diff --git a/.github/assets/revive-dev-node-polkavm-resolc.json b/.github/assets/revive-dev-node-polkavm-resolc.json index e9206a6b2..795be15ae 100644 --- a/.github/assets/revive-dev-node-polkavm-resolc.json +++ b/.github/assets/revive-dev-node-polkavm-resolc.json @@ -12,6 +12,12 @@ "fixtures/solidity/simple/try_catch/revert_long_data.sol::0::Y Ms S-": "Failed", "fixtures/solidity/simple/try_catch/revert_long_data.sol::0::Y Mz S+": "Failed", "fixtures/solidity/simple/try_catch/revert_long_data.sol::0::Y Mz S-": "Failed", + "fixtures/solidity/simple/yul_instructions/blockhash.sol::9::Y M0 S-": "Failed", + "fixtures/solidity/simple/yul_instructions/blockhash.sol::9::Y M1 S-": "Failed", + "fixtures/solidity/simple/yul_instructions/blockhash.sol::9::Y M2 S-": "Failed", + "fixtures/solidity/simple/yul_instructions/blockhash.sol::9::Y M3 S-": "Failed", + "fixtures/solidity/simple/yul_instructions/blockhash.sol::9::Y Ms S-": "Failed", + "fixtures/solidity/simple/yul_instructions/blockhash.sol::9::Y Mz S-": "Failed", "fixtures/solidity/simple/yul_instructions/revert.sol::5::Y M0 S+": "Failed", "fixtures/solidity/simple/yul_instructions/revert.sol::5::Y M0 S-": "Failed", "fixtures/solidity/simple/yul_instructions/revert.sol::5::Y Mz S+": "Failed", diff --git a/.gitignore b/.gitignore index 5f7c0a260..040ca8ef1 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ playwright-report .cache emsdk docs-tmp +workdir diff --git a/CLAUDE.md b/CLAUDE.md index f13358c57..b1f5391b6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -33,11 +33,22 @@ make test-yul # Yul parser tests make format # Check formatting (cargo fmt --all --check) make clippy # Run clippy with --deny warnings -# Run single test -cargo test --package -cargo test --package revive-integration ``` +**For verifying work, claiming a task done, or pre-commit checks: only ever run +`make test*` targets — never raw `cargo test`.** Integration and resolc tests +invoke the installed `resolc` binary as a subprocess. Each `make test*` target +already declares `install-bin` (or `install`) as a dependency, so it always +rebuilds and installs a fresh binary before running tests. Raw `cargo test` +does not — it builds the test binary but leaves system `resolc` stale, so it +passes against code the test isn't actually exercising. That mismatch is +exactly why raw `cargo test` is an anti-pattern for validation. + +The one legitimate exception is **actively debugging a single test** for fast +iteration: run `make install-bin` first to refresh the binary, then iterate with +`cargo test --package `, re-running `make install-bin` +between code changes. Never use this exception for validation. + ## Crate Architecture All crates live in `crates/`. Key crates: diff --git a/Cargo.lock b/Cargo.lock index 4d537c151..ff350333b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9363,6 +9363,7 @@ dependencies = [ "rayon", "revive-common", "revive-llvm-context", + "revive-newyork", "revive-solc-json-interface", "revive-yul", "semver 1.0.28", @@ -9492,6 +9493,20 @@ dependencies = [ "serde", ] +[[package]] +name = "revive-newyork" +version = "1.0.0" +dependencies = [ + "anyhow", + "inkwell", + "log", + "num", + "revive-common", + "revive-llvm-context", + "revive-yul", + "thiserror 2.0.18", +] + [[package]] name = "revive-runner" version = "1.2.0" diff --git a/Cargo.toml b/Cargo.toml index cb1f527d0..89ec700ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ revive-differential = { version = "1.0.0", path = "crates/differential" } revive-integration = { version = "1.2.0", path = "crates/integration" } revive-linker = { version = "1.0.0", path = "crates/linker" } revive-llvm-context = { version = "1.2.0", path = "crates/llvm-context" } +revive-newyork = { version = "1.0.0", path = "crates/newyork" } revive-runner = { version = "1.1.0", path = "crates/runner" } revive-runtime-api = { version = "1.2.0", path = "crates/runtime-api" } revive-solc-json-interface = { version = "1.0.0", path = "crates/solc-json-interface", default-features = false } diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index b4ade8bc3..7d5382542 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -13,6 +13,8 @@ - [Developer Guide](./developer_guide.md) - [Contributor guide](./developer_guide/contributing.md) - [Compiler architecture](./developer_guide/architecture.md) + - [The newyork optimizer](./developer_guide/newyork_optimizer.md) + - [IR reference](./developer_guide/newyork_ir.md) - [PVM and the pallet-revive runtime target](./developer_guide/target.md) - [Testing strategy](./developer_guide/testing.md) - [Cross compilation](./developer_guide/cross_compilation.md) diff --git a/book/src/developer_guide/architecture.md b/book/src/developer_guide/architecture.md index 6f3586f77..e773e65f4 100644 --- a/book/src/developer_guide/architecture.md +++ b/book/src/developer_guide/architecture.md @@ -52,4 +52,4 @@ We also maintain the [lld-sys crate](https://crates.io/crates/lld-sys) for inter ## Custom optimizations -At the moment, no significant custom optimizations are implemented. Thus, we are missing some optimization opportunities that neither `solc` nor LLVM can realize (due to their lack of domain specific knowledge about the semantics of our target environment). Furthermore, `solc` optimizes for EVM gas and a target machine orthogonal to our target (BE 256-bit stack machine EVM vs. 64-bit LE RISC architecture PVM). We have started working on an additional IR layer between Yul and LLVM to capture missed optimization opportunities, though. +An experimental [`newyork` optimizer](./newyork_optimizer.md) introduces a custom IR layer between Yul and LLVM IR to capture optimization opportunities that neither `solc` nor LLVM can realize on their own. `solc` optimizes for EVM gas on a 256-bit big-endian stack machine, while LLVM lacks the domain knowledge to understand EVM memory semantics or Solidity patterns. The newyork IR bridges this gap with passes for type narrowing, memory optimization, function deduplication, and more. diff --git a/book/src/developer_guide/newyork_ir.md b/book/src/developer_guide/newyork_ir.md new file mode 100644 index 000000000..7d242a884 --- /dev/null +++ b/book/src/developer_guide/newyork_ir.md @@ -0,0 +1,4119 @@ +# newyork IR reference + +A per-operation reference for the newyork IR: textual syntax, operand and result types, purity, region and static-slot annotations, and examples. + +## How to read this reference + +This appendix enumerates every operation the newyork IR supports. It is a lookup, not a walkthrough: each entry is self-contained and intended to be reachable by anchor. + +Operations are grouped by function (memory and storage writes, pure expressions, control flow, and so on) rather than alphabetically. Jump to a specific operation from the [operation index](#operation-index) below, or use the sidebar. + +Every operation appears in two places in the codebase. The canonical Rust definition is a variant of either `Expression` or `Statement` in `ir.rs`. The textual rendering used by debug dumps and by this appendix is produced by the printer in `printer.rs`. Treat the printed syntax as a debug surface, not a stable input language: there is no parser for it, and printer details change when passes add new annotations. + +### Entry format + +Each operation entry has the same shape: + +| Field | What it shows | +|---|---| +| **Heading** | The printed operation name (e.g. `mstore`) followed by the `Expression` or `Statement` variant it corresponds to in `ir.rs`. | +| **Description** | A short prose summary of what the operation does and any semantic notes worth knowing before reading the rest of the entry. | +| **Syntax** | The literal printer output, including any optional debug annotations (region tags, static-slot comments). Anything inside `/* ... */` is a debug-only annotation and is not part of the operation itself. | +| **Example** | A minimal printed snippet, using the printer's actual `v0`/`v1`/… naming. | +| **Operands** | One row per input or structural participant in the printed syntax. Value operands list the narrowest type the operation guarantees (default `i256`; narrower widths only appear when type inference has narrowed an upstream definition). Vector-of-operands fields show `Vec<…>` as the type. Non-value participants such as nested regions are listed with an em-dash type to mark them as structural rather than as operands. | +| **Result and purity** | The type the operation produces (or *none* for statements that bind no value), followed by a purity label, either *Pure* or *Effectful*. Pure operations may be reordered, deduplicated, or eliminated by the simplifier; effectful ones may not. Effectful entries may carry a parenthetical describing the nature of the side effect when informative (e.g. "control flow", "terminator", or a note about revert/trap behavior). | +| **Annotations** | Operation-specific fields the printer surfaces as `/* ... */` comments in the dump (region tag for memory ops, static-slot hint for storage ops, type suffix for non-default widths). Listed here as a table of *source field* → *printed form*. | + +### Syntax notation + +Syntax templates in each entry use the following conventions: + +| Notation | Meaning | +|---|---| +| `add`, `mload`, `if`, `else`, `case`, `let`, `yield`, … | Literal printer tokens: bare lowercase identifiers and keywords that the printer emits verbatim. | +| `$offset`, `$value`, `$key`, `$lhs`, `$rhs`, … | Role names (`$`-prefixed): placeholders for SSA value references the printer renders as `v` followed by a decimal id (`v0`, `v1`, …). | +| ``, ``, ``, ``, ``, ``, ``, ``, … | Metavariables: stand for compile-time fields (type tags, hex values, identifier strings, integer counts), not SSA values. The concrete values they take are enumerated in the Annotations section of each entry or in the type system reference. | +| `[…]` | Optional parts. Anything inside the brackets may or may not appear in any given dump, depending on the conditions described in the operation's Annotations section. | +| `[: ]` | Optional type suffix on a value reference. Suppressed when the value's type is the default `i256` integer; present otherwise (`: i32`, `: ptr`, …). | +| `/* … */` | Debug-only annotations the printer attaches to certain operations (memory region tag, static-slot hint, etc.). | +| `…` | Repetition: "more entries of the same shape." Used in vector operand lists (`$arg_0, $arg_1, …`) and in multi-line block bodies (`{ … }`). | + +### Operation index + +#### Pure expressions + +##### Constants and variables + +- [`0x`](#0xhex) +- [`v`](#vid) + +##### Arithmetic + +- [`add`](#add) +- [`sub`](#sub) +- [`mul`](#mul) +- [`div`](#div) +- [`sdiv`](#sdiv) +- [`mod`](#mod) +- [`smod`](#smod) +- [`exp`](#exp) +- [`and`](#and) +- [`or`](#or) +- [`xor`](#xor) +- [`shl`](#shl) +- [`shr`](#shr) +- [`sar`](#sar) +- [`lt`](#lt) +- [`gt`](#gt) +- [`slt`](#slt) +- [`sgt`](#sgt) +- [`eq`](#eq) +- [`byte`](#byte) +- [`signextend`](#signextend) +- [`addmod`](#addmod) +- [`mulmod`](#mulmod) +- [`iszero`](#iszero) +- [`not`](#not) +- [`clz`](#clz) + +##### Bit-width conversions + +- [`truncate>`](#truncateibits) +- [`zext>`](#zextibits) +- [`sext>`](#sextibits) + +##### Hashing + +- [`keccak256`](#keccak256) +- [`keccak256_pair`](#keccak256_pair) +- [`keccak256_single`](#keccak256_single) + +##### Environment reads + +- [`caller`](#caller) +- [`callvalue`](#callvalue) +- [`origin`](#origin) +- [`address`](#address) +- [`chainid`](#chainid) +- [`gas`](#gas) +- [`msize`](#msize) +- [`coinbase`](#coinbase) +- [`timestamp`](#timestamp) +- [`number`](#number) +- [`difficulty`](#difficulty) +- [`gaslimit`](#gaslimit) +- [`basefee`](#basefee) +- [`blobbasefee`](#blobbasefee) +- [`blobhash`](#blobhash) +- [`blockhash`](#blockhash) +- [`selfbalance`](#selfbalance) +- [`gasprice`](#gasprice) + +##### Calldata, returndata, and code + +- [`calldataload`](#calldataload) +- [`calldatasize`](#calldatasize) +- [`returndatasize`](#returndatasize) +- [`codesize`](#codesize) +- [`extcodesize`](#extcodesize) +- [`extcodehash`](#extcodehash) +- [`balance`](#balance) + +##### Memory and storage loads + +- [`mload`](#mload) +- [`sload`](#sload) +- [`tload`](#tload) +- [`mapping_sload`](#mapping_sload) + +##### Linker + +- [`dataoffset`](#dataoffset) +- [`datasize`](#datasize) +- [`loadimmutable`](#loadimmutable) +- [`linkersymbol`](#linkersymbol) + +##### Function call + +- [``](#func_name) + +#### Memory and storage writes + +- [`mstore`](#mstore) +- [`mstore8`](#mstore8) +- [`mcopy`](#mcopy) +- [`sstore`](#sstore) +- [`tstore`](#tstore) +- [`mapping_sstore`](#mapping_sstore) + +#### Bulk copies + +- [`codecopy`](#codecopy) +- [`extcodecopy`](#extcodecopy) +- [`returndatacopy`](#returndatacopy) +- [`datacopy`](#datacopy) +- [`calldatacopy`](#calldatacopy) + +#### Bindings and wrappers + +- [`let`](#let) +- [expression statement](#expression-statement) +- [`setimmutable`](#setimmutable) + +#### Structured control flow + +- [`if`](#if) +- [`switch`](#switch) +- [`for`](#for) +- [`break`](#break) +- [`continue`](#continue) +- [`leave`](#leave) +- [nested block](#nested-block) + +#### External interaction + +- [`call`](#call) +- [`callcode`](#callcode) +- [`delegatecall`](#delegatecall) +- [`staticcall`](#staticcall) +- [`create`](#create) +- [`create2`](#create2) +- [`log`](#logn) + +#### Termination + +- [`return`](#return) +- [`revert`](#revert) +- [`stop`](#stop) +- [`invalid`](#invalid) +- [`selfdestruct`](#selfdestruct) +- [`panic_revert`](#panic_revert) +- [`error_string_revert`](#error_string_revert) +- [`custom_error_revert`](#custom_error_revert) + +## Type system + +Every value in the IR carries a `Type`. The operation entries below refer to widths (`i1`…`i256`), address spaces (`ptr`, etc.), and memory regions (`scratch`, etc.) by their printed form; this section is the reference for those names. + +### `Type` + +The umbrella enum. Three variants: + +| Variant | Printed as | Description | +|---|---|---| +| `Int(BitWidth)` | `i1`, `i8`, …, `i256` | An integer at one of seven widths; see [BitWidth](#bitwidth). | +| `Ptr(AddressSpace)` | `ptr`, `ptr`, `ptr`, `ptr` | A pointer tagged with its address space; see [AddressSpace](#addressspace). | +| `Void` | `void` | Unit type. Used for statements that produce no value and for `void`-returning functions. | + +### `BitWidth` + +The seven rungs of integer width. Newly minted values default to `I256`; type inference narrows them down to one of the lower rungs when it can prove the upper bits are zero or unused. + +| Variant | Printed as | Typical use | +|---|---|---| +| `I1` | `i1` | Boolean. Result type of every comparison and `iszero`. | +| `I8` | `i8` | Byte values. The narrowest meaningful integer. | +| `I32` | `i32` | PolkaVM pointer width (XLEN); minimum width for function parameters under the rv64e ABI. | +| `I64` | `i64` | PolkaVM native register width; most narrowed values land here. | +| `I128` | `i128` | Two registers; arithmetic that overflows `i64` but doesn't need full 256-bit emulation. | +| `I160` | `i160` | Ethereum addresses; result of `caller`, `origin`, mapping keys. | +| `I256` | `i256` | EVM word width. The default and conservative ceiling. | + +### `AddressSpace` + +The address space a pointer points into. Carried on every `Ptr` value so the codegen can lower loads and stores without a separate alias-analysis pass. + +| Variant | Printed as | Points into | Endianness | +|---|---|---|---| +| `Heap` | `ptr` | Emulated EVM linear memory (the simulated `mload`/`mstore` region). | Big-endian (by EVM contract). | +| `Stack` | `ptr` | Native PolkaVM stack allocations. | Little-endian (no swap). | +| `Storage` | `ptr` | Contract storage; key/value with 256-bit slots. | Big-endian on the wire. | +| `Code` | `ptr` | Read-only code/data segment. | Big-endian. | + +### `MemoryRegion` + +A refinement carried by every memory load and store on top of `AddressSpace::Heap`. The tag tells later passes what kind of heap address an offset is hitting, which drives both free-memory-pointer propagation and byte-swap elimination. + +| Variant | Address range | Printed as | Meaning | +|---|---|---|---| +| `Scratch` | `0x00`–`0x3f` | `/* scratch */` | EVM scratch space; safe to touch without consulting the free memory pointer. | +| `FreePointerSlot` | exactly `0x40` | `/* free_ptr */` | Slot that stores the free memory pointer itself. | +| `Dynamic` | `0x80` and above | `/* dynamic */` | Real heap allocations. | +| `Unknown` | everything else (constants in `0x41`–`0x7f`, plus all non-constant offsets) | (suppressed) | Conservative fallback used when the offset isn't a constant or doesn't slot cleanly. | + +## Pure expressions + +Pure expressions produce values without side effects. The simplifier may freely reorder, deduplicate, and eliminate them. They appear on the right-hand side of a `let` binding, or as operands of other expressions and effectful statements; the operand positions accept SSA value references only, so any pure expression that is consumed elsewhere is first bound by a `let`. Examples in this section wrap each expression in a `let v := …` to give it somewhere to land. + +### `0x` + +(`Expression::Literal`) + +#### Description + +A compile-time constant value with a declared type. New literals minted by the translator default to `Int(I256)`; passes that synthesize constants at narrower widths (e.g. a one-bit boolean from a constant comparison) attach the narrower type directly. + +#### Syntax + +```text +0x[: ] +``` + +#### Example + +```text +let v0 := 0x2a // 42 at the default i256 +let v1 := 0x1: i1 // boolean true +let v2 := 0x80: i64 // narrowed by type inference +``` + +#### Operands + +None — literals are leaves. + +#### Result and purity + +| Result | Purity | +|---|---| +| Same as the literal's `value_type` | Pure | + +#### Annotations + +| Source field | Printed as | +|---|---| +| `value: BigUint` | `0x` in the syntax position (not a comment annotation; it is the expression itself) | +| `value_type:` [`Type`](#type) | `: ` suffix when `value_type` is not the default `Int(I256)`; suppressed otherwise | + +### `v` + +(`Expression::Var`) + +#### Description + +A reference to an existing SSA value, used as the entire right-hand side of a `let`. In a typical dump this is rare because the simplifier collapses `let v := v` into the consumers of `v` via copy propagation; expect to see it only in dumps taken before simplification has run. + +#### Syntax + +```text +v +``` + +#### Example + +```text +let v5 := v3 // copy; usually eliminated by simplify +``` + +#### Operands + +None — the expression is the value reference itself. + +#### Result and purity + +| Result | Purity | +|---|---| +| Same as the referenced value's type | Pure | + +#### Annotations + +None. + +### `add` + +(`Expression::Binary` with `BinaryOperation::Add`) + +#### Description + +Modular addition. Wraps on overflow; per EVM, the result is `(lhs + rhs) mod 2^N` where `N` is the operand width. + +#### Syntax + +```text +add($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := add(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | — | +| `rhs` | `i256` | — | + +#### Result and purity + +| Result | Purity | +|---|---| +| `widen_by_one(max(width(lhs), width(rhs)))` — one tier above the wider operand to account for the carry bit | Pure | + +#### Annotations + +None. + +### `sub` + +(`Expression::Binary` with `BinaryOperation::Sub`) + +#### Description + +Modular subtraction. Wraps on underflow; the result is `(lhs - rhs) mod 2^256` regardless of operand widths. + +#### Syntax + +```text +sub($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := sub(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | — | +| `rhs` | `i256` | — | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` — conservative; underflow on narrower operands could borrow into upper bits | Pure | + +#### Annotations + +None. + +### `mul` + +(`Expression::Binary` with `BinaryOperation::Mul`) + +#### Description + +Modular multiplication. The result is `(lhs * rhs) mod 2^256`. + +#### Syntax + +```text +mul($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := mul(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | — | +| `rhs` | `i256` | — | + +#### Result and purity + +| Result | Purity | +|---|---| +| `double_width(max(width(lhs), width(rhs)))` — the tier holding twice the wider operand's bits (skipping `i160` at the `i128` → `i256` transition) | Pure | + +#### Annotations + +None. + +### `div` + +(`Expression::Binary` with `BinaryOperation::Div`) + +#### Description + +Unsigned integer division. Per EVM, `div(x, 0) = 0` (no trap on division by zero). + +#### Syntax + +```text +div($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := div(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | Dividend. | +| `rhs` | `i256` | Divisor; `0` yields a result of `0`, not a trap. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `width(lhs)` — the quotient cannot exceed the dividend | Pure | + +#### Annotations + +None. + +### `sdiv` + +(`Expression::Binary` with `BinaryOperation::SDiv`) + +#### Description + +Signed two's-complement integer division. Per EVM, `sdiv(x, 0) = 0`; quotient is truncated toward zero. + +#### Syntax + +```text +sdiv($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := sdiv(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | Dividend, treated as signed. | +| `rhs` | `i256` | Divisor, treated as signed; `0` yields `0`. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `width(lhs)` | Pure | + +#### Annotations + +None. + +### `mod` + +(`Expression::Binary` with `BinaryOperation::Mod`) + +#### Description + +Unsigned modulo. Per EVM, `mod(x, 0) = 0`. + +#### Syntax + +```text +mod($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := mod(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | Dividend. | +| `rhs` | `i256` | Divisor; `0` yields `0`. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `width(lhs)` | Pure | + +#### Annotations + +None. + +### `smod` + +(`Expression::Binary` with `BinaryOperation::SMod`) + +#### Description + +Signed modulo. Per EVM, `smod(x, 0) = 0`; the result takes the sign of the dividend. + +#### Syntax + +```text +smod($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := smod(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | Dividend, treated as signed. | +| `rhs` | `i256` | Divisor, treated as signed; `0` yields `0`. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `width(lhs)` | Pure | + +#### Annotations + +None. + +### `exp` + +(`Expression::Binary` with `BinaryOperation::Exp`) + +#### Description + +Modular exponentiation: `(lhs ^ rhs) mod 2^256`. The most expensive arithmetic opcode in EVM (variable gas cost proportional to the byte length of `rhs`). + +#### Syntax + +```text +exp($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := exp(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | Base. | +| `rhs` | `i256` | Exponent. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` — conservative; exponentiation can fill any width | Pure | + +#### Annotations + +None. + +### `and` + +(`Expression::Binary` with `BinaryOperation::And`) + +#### Description + +Bitwise AND. The common idiom for type narrowing: a constant mask on the right lets forward analysis pick up a tight result width. + +#### Syntax + +```text +and($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := and(v0, v1) +let v3 := and(v0, 0xff) // type inference narrows result to i8 +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | — | +| `rhs` | `i256` | — | + +#### Result and purity + +| Result | Purity | +|---|---| +| `min(width(lhs), width(rhs))` — AND can only clear bits, so the result fits in the narrower operand | Pure | + +#### Annotations + +None. + +### `or` + +(`Expression::Binary` with `BinaryOperation::Or`) + +#### Description + +Bitwise OR. + +#### Syntax + +```text +or($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := or(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | — | +| `rhs` | `i256` | — | + +#### Result and purity + +| Result | Purity | +|---|---| +| `max(width(lhs), width(rhs))` | Pure | + +#### Annotations + +None. + +### `xor` + +(`Expression::Binary` with `BinaryOperation::Xor`) + +#### Description + +Bitwise XOR. + +#### Syntax + +```text +xor($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := xor(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | — | +| `rhs` | `i256` | — | + +#### Result and purity + +| Result | Purity | +|---|---| +| `max(width(lhs), width(rhs))` | Pure | + +#### Annotations + +None. + +### `shl` + +(`Expression::Binary` with `BinaryOperation::Shl`) + +#### Description + +Logical left shift. Operand order follows EVM: `shl(shift, value)` computes `value << shift`. Shifts ≥ 256 produce `0`. + +#### Syntax + +```text +shl($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := shl(v0, v1) // v1 shifted left by v0 bits +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | Shift amount in bits. | +| `rhs` | `i256` | Value to shift. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` — conservative; bits may shift into any width | Pure | + +#### Annotations + +None. + +### `shr` + +(`Expression::Binary` with `BinaryOperation::Shr`) + +#### Description + +Logical right shift. Operand order follows EVM: `shr(shift, value)` computes `value >> shift` with zero-fill from the left. Shifts ≥ 256 produce `0`. + +#### Syntax + +```text +shr($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := shr(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | Shift amount in bits. | +| `rhs` | `i256` | Value to shift. | + +#### Result and purity + +| Result | Purity | +|---|---| +| If `lhs` is a known constant `k`: tier holding `256 - k` bits (or `i1` for `k ≥ 256`). Otherwise: `width(rhs)`. | Pure | + +#### Annotations + +None. + +### `sar` + +(`Expression::Binary` with `BinaryOperation::Sar`) + +#### Description + +Arithmetic (signed) right shift. Operand order follows EVM: `sar(shift, value)` shifts `value` right by `shift` bits, preserving the sign bit. Shifts ≥ 256 saturate to `0` for non-negative values and to `-1` (all-ones) for negative values. + +#### Syntax + +```text +sar($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := sar(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | Shift amount in bits. | +| `rhs` | `i256` | Value to shift, treated as signed. | + +#### Result and purity + +| Result | Purity | +|---|---| +| Same shape as [`shr`](#shr) forward inference (constant shift narrows the result; non-constant falls back to `width(rhs)`). | Pure | + +#### Annotations + +None. + +### `lt` + +(`Expression::Binary` with `BinaryOperation::Lt`) + +#### Description + +Unsigned less-than comparison. Returns `1` if `lhs < rhs`, else `0`. + +#### Syntax + +```text +lt($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := lt(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | Compared unsigned. | +| `rhs` | `i256` | Compared unsigned. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i1` | Pure | + +#### Annotations + +None. + +### `gt` + +(`Expression::Binary` with `BinaryOperation::Gt`) + +#### Description + +Unsigned greater-than comparison. Returns `1` if `lhs > rhs`, else `0`. + +#### Syntax + +```text +gt($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := gt(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | Compared unsigned. | +| `rhs` | `i256` | Compared unsigned. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i1` | Pure | + +#### Annotations + +None. + +### `slt` + +(`Expression::Binary` with `BinaryOperation::Slt`) + +#### Description + +Signed less-than comparison. Operands are treated as two's complement. + +#### Syntax + +```text +slt($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := slt(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | Compared signed. | +| `rhs` | `i256` | Compared signed. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i1` | Pure | + +#### Annotations + +None. + +### `sgt` + +(`Expression::Binary` with `BinaryOperation::Sgt`) + +#### Description + +Signed greater-than comparison. Operands are treated as two's complement. + +#### Syntax + +```text +sgt($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := sgt(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | Compared signed. | +| `rhs` | `i256` | Compared signed. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i1` | Pure | + +#### Annotations + +None. + +### `eq` + +(`Expression::Binary` with `BinaryOperation::Eq`) + +#### Description + +Equality comparison. Returns `1` if `lhs == rhs`, else `0`. Signedness is irrelevant. + +#### Syntax + +```text +eq($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := eq(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | — | +| `rhs` | `i256` | — | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i1` | Pure | + +#### Annotations + +None. + +### `byte` + +(`Expression::Binary` with `BinaryOperation::Byte`) + +#### Description + +Extract a single byte from a 256-bit word. `byte(i, x)` returns the *i*-th byte of `x` with byte 0 being the most significant. If `i ≥ 32`, the result is `0`. + +#### Syntax + +```text +byte($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := byte(v0, v1) // v0 = byte index, v1 = word +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | Byte position; `0` = most significant byte. Values `≥ 32` yield `0`. | +| `rhs` | `i256` | Source word. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i8` | Pure | + +#### Annotations + +None. + +### `signextend` + +(`Expression::Binary` with `BinaryOperation::SignExtend`) + +#### Description + +Sign-extend an integer from a byte position. Per EVM, `signextend(b, x)` treats byte `b` of `x` as the most significant byte of a smaller signed integer and extends its sign through the upper bytes. + +#### Syntax + +```text +signextend($lhs[: ], $rhs[: ]) +``` + +#### Example + +```text +let v2 := signextend(v0, v1) // v0 = byte position, v1 = value +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `lhs` | `i256` | Byte position of the sign byte (0–31). | +| `rhs` | `i256` | Source value. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` — the extended value occupies the full word | Pure | + +#### Annotations + +The width-targeted sign-extension primitive [`sext>`](#sextibits) (`Expression::SignExtendTo`) is a separate operation; see the bit-width conversions section. + +### `addmod` + +(`Expression::Ternary` with `BinaryOperation::AddMod`) + +#### Description + +Ternary modular addition: `(a + b) mod n`, computed without intermediate overflow. Per EVM, `n = 0` yields `0`. + +#### Syntax + +```text +addmod($a[: ], $b[: ], $n[: ]) +``` + +#### Example + +```text +let v3 := addmod(v0, v1, v2) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `a` | `i256` | First addend. | +| `b` | `i256` | Second addend. | +| `n` | `i256` | Modulus; `0` yields `0`. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` — conservative | Pure | + +#### Annotations + +None. + +### `mulmod` + +(`Expression::Ternary` with `BinaryOperation::MulMod`) + +#### Description + +Ternary modular multiplication: `(a * b) mod n`, computed without intermediate overflow. Per EVM, `n = 0` yields `0`. + +#### Syntax + +```text +mulmod($a[: ], $b[: ], $n[: ]) +``` + +#### Example + +```text +let v3 := mulmod(v0, v1, v2) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `a` | `i256` | First factor. | +| `b` | `i256` | Second factor. | +| `n` | `i256` | Modulus; `0` yields `0`. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` — conservative | Pure | + +#### Annotations + +None. + +### `iszero` + +(`Expression::Unary` with `UnaryOperation::IsZero`) + +#### Description + +Returns `1` if the operand is `0`, else `0`. Also serves as the logical NOT for boolean values. + +#### Syntax + +```text +iszero($operand[: ]) +``` + +#### Example + +```text +let v1 := iszero(v0) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `operand` | `i256` | — | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i1` | Pure | + +#### Annotations + +None. + +### `not` + +(`Expression::Unary` with `UnaryOperation::Not`) + +#### Description + +Bitwise complement. Inverts every bit; equivalent to `xor(operand, 2^256 - 1)`. + +#### Syntax + +```text +not($operand[: ]) +``` + +#### Example + +```text +let v1 := not(v0) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `operand` | `i256` | — | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` — the complement fills the full word regardless of operand width | Pure | + +#### Annotations + +None. + +### `clz` + +(`Expression::Unary` with `UnaryOperation::Clz`) + +#### Description + +Count leading zeros. Returns the number of leading zero bits in the operand, where a value of `0` returns `256` (the full width). Not an EVM opcode; reaches newyork as a Yul builtin (`FunctionName::Clz`) and is translated directly by the Yul-to-newyork translator. + +#### Syntax + +```text +clz($operand[: ]) +``` + +#### Example + +```text +let v1 := clz(v0) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `operand` | `i256` | — | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` — in practice the value fits in nine bits (max `256`), so type inference often narrows further | Pure | + +#### Annotations + +None. + +### `truncate>` + +(`Expression::Truncate`) + +#### Description + +Reinterpret a wider integer as a narrower one by discarding the upper bits. The destination width is carried in the IR's `to: BitWidth` field and is rendered inside the angle brackets of the printer mnemonic. Narrowing-only; the source width must be greater than or equal to the destination width. + +#### Syntax + +```text +truncate>($value[: ]) +``` + +#### Example + +```text +let v1 := truncate(v0) +let v2 := truncate(v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `value` | `i256` | Source value; must be at least as wide as the destination. | + +#### Result and purity + +| Result | Purity | +|---|---| +| The destination width from the `to` field | Pure | + +#### Annotations + +None. The destination width is part of the operation name, not a debug annotation. + +### `zext>` + +(`Expression::ZeroExtend`) + +#### Description + +Reinterpret a narrower integer as a wider one by zero-filling the upper bits. The destination width is carried in the IR's `to: BitWidth` field. Widening-only. + +#### Syntax + +```text +zext>($value[: ]) +``` + +#### Example + +```text +let v1 := zext(v0: i8) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `value` | `i256` | Source value; must be no wider than the destination. | + +#### Result and purity + +| Result | Purity | +|---|---| +| The destination width from the `to` field | Pure | + +#### Annotations + +None. + +### `sext>` + +(`Expression::SignExtendTo`) + +#### Description + +Reinterpret a narrower signed integer as a wider one by sign-extending the high bit. The destination width is carried in the IR's `to: BitWidth` field. Distinct from [`signextend`](#signextend) (`Expression::Binary`), which is the EVM byte-position primitive; this one specifies the destination width directly and is introduced by passes that produce a sign-extended value at a known target width. + +#### Syntax + +```text +sext>($value[: ]) +``` + +#### Example + +```text +let v1 := sext(v0: i64) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `value` | `i256` | Source value; must be no wider than the destination. | + +#### Result and purity + +| Result | Purity | +|---|---| +| The destination width from the `to` field | Pure | + +#### Annotations + +None. + +### `keccak256` + +(`Expression::Keccak256`) + +#### Description + +Compute the Keccak-256 hash of `length` bytes of emulated EVM linear memory starting at `offset`. The general-purpose hashing primitive; the two specialized variants below cover the common scratch-space patterns more compactly. + +#### Syntax + +```text +keccak256($offset[: ], $length[: ]) +``` + +#### Example + +```text +let v2 := keccak256(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `offset` | `i256` | Byte offset into linear memory; forward analysis widens to at least `i64`. | +| `length` | `i256` | Length of the region to hash, in bytes; forward analysis widens to at least `i64`. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure — the hash is a deterministic function of the memory contents at evaluation time. Passes that hoist or dedupe must respect intervening memory writes. | + +#### Annotations + +None. + +### `keccak256_pair` + +(`Expression::Keccak256Pair`) + +#### Description + +Compound hash of two 256-bit words. Equivalent to `mstore(0, word0); mstore(32, word1); keccak256(0, 64)` but emitted as a single outlined call after the keccak-fusion pass recognizes the pattern. The mapping-key idiom; see also [`mapping_sload`](#mapping_sload). + +#### Syntax + +```text +keccak256_pair($word0[: ], $word1[: ]) +``` + +#### Example + +```text +let v2 := keccak256_pair(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `word0` | `i256` | First word; the high 32 bytes of the hash input. | +| `word1` | `i256` | Second word; the low 32 bytes of the hash input. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +None. + +### `keccak256_single` + +(`Expression::Keccak256Single`) + +#### Description + +Compound hash of a single 256-bit word. Equivalent to `mstore(0, word0); keccak256(0, 32)` but emitted as a single outlined call after the keccak-fusion pass. + +#### Syntax + +```text +keccak256_single($word0[: ]) +``` + +#### Example + +```text +let v1 := keccak256_single(v0) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `word0` | `i256` | The word to hash. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +None. + +### `caller` + +(`Expression::Caller`) + +#### Description + +Address of the immediate caller of the current call frame. + +#### Syntax + +```text +caller() +``` + +#### Example + +```text +let v0 := caller() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i160` | Pure | + +#### Annotations + +None. + +### `callvalue` + +(`Expression::CallValue`) + +#### Description + +Value (wei) attached to the current call. + +#### Syntax + +```text +callvalue() +``` + +#### Example + +```text +let v0 := callvalue() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +None. + +### `origin` + +(`Expression::Origin`) + +#### Description + +Address of the original externally owned account that initiated the transaction. + +#### Syntax + +```text +origin() +``` + +#### Example + +```text +let v0 := origin() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i160` | Pure | + +#### Annotations + +None. + +### `address` + +(`Expression::Address`) + +#### Description + +Address of the contract executing the current call frame. + +#### Syntax + +```text +address() +``` + +#### Example + +```text +let v0 := address() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i160` | Pure | + +#### Annotations + +None. + +### `chainid` + +(`Expression::ChainId`) + +#### Description + +Chain identifier of the network the contract is executing on. + +#### Syntax + +```text +chainid() +``` + +#### Example + +```text +let v0 := chainid() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +None. + +### `gas` + +(`Expression::Gas`) + +#### Description + +Remaining gas at the point of evaluation. Modelled as a pure expression for IR purposes; in practice it changes between evaluations, so any simplifier that deduplicates pure expressions must respect `gas` as a barrier. + +#### Syntax + +```text +gas() +``` + +#### Example + +```text +let v0 := gas() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i64` | Pure (per IR; see Description) | + +#### Annotations + +None. + +### `msize` + +(`Expression::MSize`) + +#### Description + +Highest byte offset of emulated EVM linear memory that has been touched, rounded up to the next 32-byte boundary. Unlike [`gas`](#gas), classified as side-effectful by the simplifier: unused `msize()` bindings are not eliminated, because the result depends on the program's memory-access history and would change if the surrounding statements were reordered. + +#### Syntax + +```text +msize() +``` + +#### Example + +```text +let v0 := msize() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i64` | Effectful (see Description) | + +#### Annotations + +None. + +### `coinbase` + +(`Expression::Coinbase`) + +#### Description + +Address of the block's coinbase (block author). + +#### Syntax + +```text +coinbase() +``` + +#### Example + +```text +let v0 := coinbase() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i160` | Pure | + +#### Annotations + +None. + +### `timestamp` + +(`Expression::Timestamp`) + +#### Description + +Block timestamp, as a Unix epoch second. + +#### Syntax + +```text +timestamp() +``` + +#### Example + +```text +let v0 := timestamp() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i64` | Pure | + +#### Annotations + +None. + +### `number` + +(`Expression::Number`) + +#### Description + +Current block number. + +#### Syntax + +```text +number() +``` + +#### Example + +```text +let v0 := number() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i64` | Pure | + +#### Annotations + +None. + +### `difficulty` + +(`Expression::Difficulty`) + +#### Description + +Pre-merge block difficulty. On post-merge chains this is the block's `prevrandao` value. + +#### Syntax + +```text +difficulty() +``` + +#### Example + +```text +let v0 := difficulty() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +None. + +### `gaslimit` + +(`Expression::GasLimit`) + +#### Description + +Block gas limit. + +#### Syntax + +```text +gaslimit() +``` + +#### Example + +```text +let v0 := gaslimit() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i64` | Pure | + +#### Annotations + +None. + +### `basefee` + +(`Expression::BaseFee`) + +#### Description + +Current block's EIP-1559 base fee per gas. + +#### Syntax + +```text +basefee() +``` + +#### Example + +```text +let v0 := basefee() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +None. + +### `blobbasefee` + +(`Expression::BlobBaseFee`) + +#### Description + +Current block's EIP-4844 blob base fee per gas. + +#### Syntax + +```text +blobbasefee() +``` + +#### Example + +```text +let v0 := blobbasefee() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +None. + +### `blobhash` + +(`Expression::BlobHash`) + +#### Description + +Versioned hash of the blob at the given index in the current transaction's blob list. + +#### Syntax + +```text +blobhash($index[: ]) +``` + +#### Example + +```text +let v1 := blobhash(v0) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `index` | `i256` | Blob index; forward analysis widens to at least `i64`. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +None. + +### `blockhash` + +(`Expression::BlockHash`) + +#### Description + +Hash of the block with the given number. Per EVM, valid only for the most recent 256 blocks; outside that range the result is `0`. + +#### Syntax + +```text +blockhash($number[: ]) +``` + +#### Example + +```text +let v1 := blockhash(v0) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `number` | `i256` | Block number; forward analysis widens to at least `i64`. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +None. + +### `selfbalance` + +(`Expression::SelfBalance`) + +#### Description + +Balance (in wei) of the contract executing the current call frame. Cheaper than `balance(address())`. + +#### Syntax + +```text +selfbalance() +``` + +#### Example + +```text +let v0 := selfbalance() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +None. + +### `gasprice` + +(`Expression::GasPrice`) + +#### Description + +Effective gas price of the current transaction. + +#### Syntax + +```text +gasprice() +``` + +#### Example + +```text +let v0 := gasprice() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +None. + +### `calldataload` + +(`Expression::CallDataLoad`) + +#### Description + +Read 32 bytes from the current call's calldata at the given offset. Reads past the end of calldata return zero bytes. + +#### Syntax + +```text +calldataload($offset[: ]) +``` + +#### Example + +```text +let v1 := calldataload(v0) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `offset` | `i256` | Byte offset into calldata. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +None. + +### `calldatasize` + +(`Expression::CallDataSize`) + +#### Description + +Length of the current call's calldata, in bytes. + +#### Syntax + +```text +calldatasize() +``` + +#### Example + +```text +let v0 := calldatasize() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i64` | Pure | + +#### Annotations + +None. + +### `returndatasize` + +(`Expression::ReturnDataSize`) + +#### Description + +Length of the most recently returned data buffer from a sub-call, in bytes. Modelled as pure per IR but reflects the last `ExternalCall` / `Create` result; consumers must respect that ordering. + +#### Syntax + +```text +returndatasize() +``` + +#### Example + +```text +let v0 := returndatasize() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i64` | Pure (per IR; see Description) | + +#### Annotations + +None. + +### `codesize` + +(`Expression::CodeSize`) + +#### Description + +Size of the currently executing code, in bytes. + +#### Syntax + +```text +codesize() +``` + +#### Example + +```text +let v0 := codesize() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i64` | Pure | + +#### Annotations + +None. + +### `extcodesize` + +(`Expression::ExtCodeSize`) + +#### Description + +Size of the code deployed at the given address, in bytes. Returns `0` for accounts with no deployed code. + +#### Syntax + +```text +extcodesize($address[: ]) +``` + +#### Example + +```text +let v1 := extcodesize(v0: i160) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `address` | `i256` | Account address; forward analysis widens to at least `i160`. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i64` | Pure | + +#### Annotations + +None. + +### `extcodehash` + +(`Expression::ExtCodeHash`) + +#### Description + +Keccak-256 hash of the code deployed at the given address. Returns `0` for non-existent accounts. + +#### Syntax + +```text +extcodehash($address[: ]) +``` + +#### Example + +```text +let v1 := extcodehash(v0: i160) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `address` | `i256` | Account address; forward analysis widens to at least `i160`. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +None. + +### `balance` + +(`Expression::Balance`) + +#### Description + +Balance (in wei) of the given account address. Use [`selfbalance`](#selfbalance) for the contract executing the current call frame (cheaper). + +#### Syntax + +```text +balance($address[: ]) +``` + +#### Example + +```text +let v1 := balance(v0: i160) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `address` | `i256` | Account address; forward analysis widens to at least `i160`. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +None. + +### `mload` + +(`Expression::MLoad`) + +#### Description + +Read a 32-byte word from emulated EVM linear memory at `offset`. The word is read big-endian per EVM semantics. Pure per IR, but reads after writes return the new value; the memory passes track read/write dependencies separately. + +#### Syntax + +```text +mload($offset[: ]) [/* */] +``` + +#### Example + +```text +let v1 := mload(v0) +let v2 := mload(v3) /* free_ptr */ +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `offset` | `i256` | Byte offset into linear memory; forward analysis widens to at least `i64`. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i32` when region is `FreePointerSlot`; `i256` otherwise | Pure (per IR; see Description) | + +#### Annotations + +| Source field | Printed as | +|---|---| +| `region:` [`MemoryRegion`](#memoryregion) | `/* scratch */` · `/* free_ptr */` · `/* dynamic */` (`Unknown` is suppressed) | + +Same tagging rules as [`mstore`](#mstore). The region also determines the result width: a load from `FreePointerSlot` produces an `i32` since the FMP fits in a pointer-sized word. + +### `sload` + +(`Expression::SLoad`) + +#### Description + +Read a 32-byte word from persistent contract storage at the given key. Pure per IR; reads after writes to the same slot return the new value. + +#### Syntax + +```text +sload($key[: ]) [/* slot: 0x */] +``` + +#### Example + +```text +let v1 := sload(v0) +let v2 := sload(v3) /* slot: 0x0 */ +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `key` | `i256` | Storage slot. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure (per IR; see Description) | + +#### Annotations + +| Source field | Printed as | +|---|---| +| `static_slot: Option` | `/* slot: 0x */` when set; suppressed otherwise | + +Same tagging rules as [`sstore`](#sstore). The printer renders the annotation whenever the field is `Some` and the deduplicator's canonicalizer partitions signatures by slot; no pass currently writes `Some(...)`, however, so in present-day dumps the annotation is dormant. + +### `tload` + +(`Expression::TLoad`) + +#### Description + +Read a 32-byte word from transient storage at the given key. Transient storage is wiped at the end of the transaction; pair with [`tstore`](#tstore). + +#### Syntax + +```text +tload($key[: ]) +``` + +#### Example + +```text +let v1 := tload(v0) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `key` | `i256` | Transient storage slot. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure (per IR; see Description) | + +#### Annotations + +None. The IR does not track a static slot for `tload`. + +### `mapping_sload` + +(`Expression::MappingSLoad`) + +#### Description + +Compound load for a Solidity mapping element. Equivalent to `mstore(0, key); mstore(32, slot); sload(keccak256(0, 64))` but emitted as a single outlined call after the `compound_outlining` pass recognizes the pattern (it fuses a `keccak256_pair` — itself produced by `mem_opt`'s keccak fusion — followed by an `sload` whose key has a single consumer). Only valid when the intermediate hash is used exclusively by this load. + +#### Syntax + +```text +mapping_sload($key[: ], $slot[: ]) +``` + +#### Example + +```text +let v2 := mapping_sload(v0: i160, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `key` | `i256` | Mapping key; often narrowed to `i160` for address keys. | +| `slot` | `i256` | The mapping's declared storage slot. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure (per IR; see Description) | + +#### Annotations + +None. The fused statement's effective storage slot is the keccak hash of the key and the declared slot, which is never a compile-time constant; no `static_slot` hint is surfaced. + +### `dataoffset` + +(`Expression::DataOffset`) + +#### Description + +Offset of a named data segment within the deployed code. The identifier is a string carried in the IR's `id: String` field; the linker resolves it to a concrete offset. + +#### Syntax + +```text +dataoffset("") +``` + +#### Example + +```text +let v0 := dataoffset("MyContract_deployed") +``` + +#### Operands + +None — the identifier is a quoted string literal in the syntax position, not an operand. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +| Source field | Printed as | +|---|---| +| `id: String` | The quoted identifier in the syntax position (not a comment annotation; it is the expression itself). | + +### `datasize` + +(`Expression::DataSize`) + +#### Description + +Size of a named data segment within the deployed code, in bytes. The identifier is resolved by the linker. + +#### Syntax + +```text +datasize("") +``` + +#### Example + +```text +let v0 := datasize("MyContract_deployed") +``` + +#### Operands + +None — the identifier is a quoted string literal in the syntax position, not an operand. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i64` | Pure | + +#### Annotations + +| Source field | Printed as | +|---|---| +| `id: String` | The quoted identifier in the syntax position. | + +### `loadimmutable` + +(`Expression::LoadImmutable`) + +#### Description + +Read the value of a named immutable variable. Immutables are written once during contract construction by `SetImmutable` and read afterwards via this expression. + +#### Syntax + +```text +loadimmutable("") +``` + +#### Example + +```text +let v0 := loadimmutable("MyContract.owner") +``` + +#### Operands + +None — the key is a quoted string literal in the syntax position. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` | Pure | + +#### Annotations + +| Source field | Printed as | +|---|---| +| `key: String` | The quoted identifier in the syntax position. | + +### `linkersymbol` + +(`Expression::LinkerSymbol`) + +#### Description + +Address of an external library, resolved by the linker. The path encodes the library's source location and identifier. + +#### Syntax + +```text +linkersymbol("") +``` + +#### Example + +```text +let v0 := linkersymbol("contracts/Library.sol:L") +``` + +#### Operands + +None — the path is a quoted string literal in the syntax position. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i160` | Pure | + +#### Annotations + +| Source field | Printed as | +|---|---| +| `path: String` | The quoted path in the syntax position. | + +### `` + +(`Expression::Call`; the printer emits `func_` when no function name is registered) + +#### Description + +Internal function call. Invokes a user-defined function declared earlier in the same object; the mnemonic is the function's Yul-level name, or `func_` if the printer has no name registered for the `FunctionId`. Distinct from [`call`](#call) and the other EVM call-opcode statements, which cross the contract boundary. + +#### Syntax + +```text +([$argument_0[: ], $argument_1[: ], …]) +``` + +#### Example + +```text +let v3 := abi_decode_uint256(v0, v1, v2) +let v4, v5 := returns_two(v0) // multi-return via let multi-binding +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `arguments` | `Vec` | Zero or more argument values, in declaration order; each operand may carry a `: ` suffix. | + +#### Result and purity + +| Result | Purity | +|---|---| +| One or more values, widths taken from the callee's declared return types (or the inferred return widths, narrowed via the interprocedural pass). Falls back to `i256` when the callee's returns are unknown to type inference. | Effectful — the simplifier treats every call as side-effectful regardless of callee body, so unused call bindings are not DCE'd. The transitive purity of the callee is not tracked at the IR level. | + +#### Annotations + +| Source field | Printed as | +|---|---| +| `function: FunctionId` | The callee's name in the syntax position (or `func_` if the printer has no name registered). | + +## Memory and storage writes + +The six operations in this section all modify external state: emulated EVM linear memory, persistent storage, or transient storage. They are statements (not expressions) and they are never pure. Simplification and deduplication never reorder them with respect to each other or with respect to reverts; the memory passes treat them as the side-effect boundary for their analyses. + +### `mstore` + +(`Statement::MStore`) + +#### Description + +Write a 32-byte word to emulated EVM linear memory at `offset`. The word is stored big-endian, matching EVM semantics; the codegen handles the byte swap on PolkaVM's little-endian RISC-V target. + +#### Syntax + +```text +mstore($offset[: ], $value[: ]) [/* */] +``` + +#### Example + +```text +mstore(v0, v1) // Unknown region; no annotation printed +mstore(v2, v3) /* scratch */ // offset proven to land in 0x00..0x3f +mstore(v4, v5) /* free_ptr */ // offset is exactly 0x40 +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `offset` | `i256` | Byte offset into linear memory; forward analysis widens to at least `i64`. | +| `value` | `i256` | The 32-byte word to store. Narrower values are zero-extended at codegen time. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful | + +#### Annotations + +| Source field | Printed as | +|---|---| +| `region:` [`MemoryRegion`](#memoryregion) | `/* scratch */` · `/* free_ptr */` · `/* dynamic */` (`Unknown` is suppressed) | + +Assigned at translation time from the constant offset (if any); consumed by mem_opt, FMP propagation, and byte-swap mode selection. + +### `mstore8` + +(`Statement::MStore8`) + +#### Description + +Write a single byte to emulated EVM linear memory at `offset`. The low 8 bits of `value` are stored; the upper bits are ignored. The operation is otherwise identical to `mstore`: same operand shape, same region tag, same side-effect classification. + +#### Syntax + +```text +mstore8($offset[: ], $value[: ]) [/* */] +``` + +#### Example + +```text +mstore8(v0, v1: i8) // value narrowed to i8 by type inference +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `offset` | `i256` | Byte offset into linear memory; forward analysis widens to at least `i64`. | +| `value` | `i256` | Only the low 8 bits are stored. Often narrowed to `i8` by type inference. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful | + +#### Annotations + +| Source field | Printed as | +|---|---| +| `region:` [`MemoryRegion`](#memoryregion) | `/* scratch */` · `/* free_ptr */` · `/* dynamic */` (`Unknown` is suppressed) | + +Same tagging rules as [`mstore`](#mstore). Most `mstore8`s carry an `Unknown` region in practice because single-byte writes typically target offsets the translator cannot prove constant. + +### `mcopy` + +(`Statement::MCopy`) + +#### Description + +Copy `length` bytes from `src` to `dest` within emulated EVM linear memory. The Yul builtin `mcopy` maps directly onto this statement; unlike `mstore`, it does not carry a region tag because the source and destination ranges may straddle multiple regions. + +#### Syntax + +```text +mcopy($dest[: ], $src[: ], $length[: ]) +``` + +#### Example + +```text +mcopy(v0, v1, v2) // dest, src, length +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `dest` | `i256` | Destination byte offset in linear memory. | +| `src` | `i256` | Source byte offset in linear memory. | +| `length` | `i256` | Number of bytes to copy. Overlapping ranges follow EVM-defined memmove semantics. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful | + +#### Annotations + +None. `mcopy` carries no region tag because the source and destination ranges may straddle multiple regions, and no static-slot hint because the copy is not storage-bound. + +### `sstore` + +(`Statement::SStore`) + +#### Description + +Write a 32-byte word to persistent contract storage at `key`. The operation is the durable counterpart of `mstore`: the value survives across transactions and is observable to subsequent calls to the contract. + +#### Syntax + +```text +sstore($key[: ], $value[: ]) [/* slot: 0x */] +``` + +#### Example + +```text +sstore(v0, v1) +sstore(v2, v3) /* slot: 0x0 */ +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `key` | `i256` | Storage slot. May be a constant slot, a keccak-derived slot for mappings or dynamic arrays, or an arbitrary expression. | +| `value` | `i256` | The 256-bit word to store. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful | + +#### Annotations + +| Source field | Printed as | +|---|---| +| `static_slot: Option` | `/* slot: 0x */` when set; suppressed otherwise | + +The printer renders the annotation whenever the field is `Some`, and the deduplicator's canonicalizer and mapping-fusion analyses consume it as part of the signature. No pass currently writes `Some(...)`, so the annotation is dormant in present-day dumps; when absent, alias and dedup analyses fall back to the conservative "may alias any slot" assumption. + +### `tstore` + +(`Statement::TStore`) + +#### Description + +Write a 32-byte word to transient storage at `key`. Transient storage is wiped at the end of the transaction, so `tstore` is the right primitive for per-transaction bookkeeping (reentrancy guards, cached results) without the gas cost of `sstore` on EVM. On PolkaVM the transient backing store is provided by pallet-revive. + +#### Syntax + +```text +tstore($key[: ], $value[: ]) +``` + +#### Example + +```text +tstore(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `key` | `i256` | Transient storage slot. | +| `value` | `i256` | The 256-bit word to store. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful | + +#### Annotations + +None. Unlike `sstore`, the IR does not track a static slot for `tstore`: transient storage's short-lived lifetime makes the slot-aware optimizations less valuable, and the translator does not produce the annotation. + +### `mapping_sstore` + +(`Statement::MappingSStore`) + +#### Description + +Compound store for a Solidity mapping element. Equivalent to the three-operation sequence `mstore(0, key); mstore(32, slot); sstore(keccak256(0, 64), value)` but emitted as a single outlined statement after the `compound_outlining` pass recognizes the pattern (it fuses a `keccak256_pair` followed by an `sstore` whose key has a single consumer). Only valid when the intermediate hash is not observed by any other statement. + +#### Syntax + +```text +mapping_sstore($key[: ], $slot[: ], $value[: ]) +``` + +#### Example + +```text +mapping_sstore(v0: i160, v1, v2) // address key, declared slot, value +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `key` | `i256` | Mapping key. Often narrowed to `i160` for address keys. | +| `slot` | `i256` | The mapping's declared storage slot. Typically a small constant. | +| `value` | `i256` | The value to store at the computed storage location. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful | + +#### Annotations + +None. `mapping_sstore` deliberately drops the `static_slot` annotation that the original `sstore` may have carried, because the fused statement's effective slot is the keccak hash of the key and the declared slot, which is never a compile-time constant. + +## Bulk copies + +Multi-byte memory copies from the five EVM-accessible byte sources (code, external code, returndata, embedded data, and calldata) into emulated EVM linear memory. All five take the same shape: a destination memory offset, a source offset, and a length. They are effectful and act as opaque barriers to the memory passes. + +### `codecopy` + +(`Statement::CodeCopy`) + +#### Description + +Copy `length` bytes from the currently executing code at `offset` into emulated EVM linear memory at `dest`. Reads past the end of code yield zero bytes. + +#### Syntax + +```text +codecopy($dest[: ], $offset[: ], $length[: ]) +``` + +#### Example + +```text +codecopy(v0, v1, v2) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `dest` | `i256` | Destination byte offset in linear memory. | +| `offset` | `i256` | Source byte offset in the executing code. | +| `length` | `i256` | Number of bytes to copy. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful | + +#### Annotations + +None. + +### `extcodecopy` + +(`Statement::ExtCodeCopy`) + +#### Description + +Copy `length` bytes from the code at `address` starting at `offset` into emulated EVM linear memory at `dest`. Reads beyond the code yield zero bytes; non-existent accounts yield all zeros. + +#### Syntax + +```text +extcodecopy($address[: ], $dest[: ], $offset[: ], $length[: ]) +``` + +#### Example + +```text +extcodecopy(v0: i160, v1, v2, v3) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `address` | `i256` | Account whose code to read; narrows to `i160`. | +| `dest` | `i256` | Destination byte offset in linear memory. | +| `offset` | `i256` | Source byte offset in the external code. | +| `length` | `i256` | Number of bytes to copy. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful | + +#### Annotations + +None. + +### `returndatacopy` + +(`Statement::ReturnDataCopy`) + +#### Description + +Copy `length` bytes from the most recent sub-call's return data starting at `offset` into emulated EVM linear memory at `dest`. Per EVM, reads past the return data's end revert; the memory passes treat this as a potential trap site. + +#### Syntax + +```text +returndatacopy($dest[: ], $offset[: ], $length[: ]) +``` + +#### Example + +```text +returndatacopy(v0, v1, v2) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `dest` | `i256` | Destination byte offset in linear memory. | +| `offset` | `i256` | Source byte offset in the return-data buffer. | +| `length` | `i256` | Number of bytes to copy. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful (may revert on out-of-range reads, per EVM) | + +#### Annotations + +None. + +### `datacopy` + +(`Statement::DataCopy`) + +#### Description + +Copy `length` bytes from an embedded data segment starting at `offset` into emulated EVM linear memory at `dest`. The source segment is resolved by the linker, typically used to pull constants compiled into the bytecode into runtime memory. + +#### Syntax + +```text +datacopy($dest[: ], $offset[: ], $length[: ]) +``` + +#### Example + +```text +datacopy(v0, v1, v2) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `dest` | `i256` | Destination byte offset in linear memory. | +| `offset` | `i256` | Source byte offset in the data segment. | +| `length` | `i256` | Number of bytes to copy. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful | + +#### Annotations + +None. + +### `calldatacopy` + +(`Statement::CallDataCopy`) + +#### Description + +Copy `length` bytes from the current call's calldata starting at `offset` into emulated EVM linear memory at `dest`. Reads past the end of calldata yield zero bytes. + +#### Syntax + +```text +calldatacopy($dest[: ], $offset[: ], $length[: ]) +``` + +#### Example + +```text +calldatacopy(v0, v1, v2) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `dest` | `i256` | Destination byte offset in linear memory. | +| `offset` | `i256` | Source byte offset in calldata. | +| `length` | `i256` | Number of bytes to copy. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful | + +#### Annotations + +None. + +## Bindings and wrappers + +The statements that bind SSA values, hold loose expressions evaluated for their side effects, and write to immutable storage. Every pure expression in the appendix's earlier sections appears on the right-hand side of one of these statements (almost always `let`). + +### `let` + +(`Statement::Let`) + +#### Description + +SSA binding: evaluate an expression and bind its result(s) to a list of fresh value ids. The `let` statement is the only mechanism by which pure expressions enter the value namespace; every `v` in a dump was produced by a `let` (or by a value-yielding control-flow statement or by a parameter at function entry). + +#### Syntax + +```text +let $binding_0[, $binding_1, …] := $expression +``` + +#### Example + +```text +let v3 := add(v0, v1) +let v4, v5 := if v2 [v0, v1] { … } else { … } // multi-binding from a value-yielding If +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `bindings` | `Vec` | One or more fresh SSA ids to bind. Most expressions produce one value; control-flow statements may produce several. | +| `value` | `Expression` | The right-hand side; see any of the Pure expression entries. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None directly — the bound ids carry the expression's result(s) | Effectful (binding establishment); the right-hand side's purity is independent | + +#### Annotations + +None. + +### Expression statement + +(`Statement::Expression`) + +#### Description + +Wraps an expression evaluated for its observable consequences but whose value is not bound. Typically a user-defined function call (`Expression::Call`) whose return values the source code discarded, or another Yul expression statement that does not have a dedicated `Statement::` variant. EVM external calls (`call`, `delegatecall`, etc.) and contract creation (`create`, `create2`) translate to dedicated `Statement::ExternalCall` and `Statement::Create` variants, not through this wrapper. + +#### Syntax + +```text +$expression +``` + +#### Example + +```text +keccak256(v0, v1) // hash computed but not bound to a value +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `expression` | `Expression` | Any expression; result is discarded. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful (per its statement position) | + +#### Annotations + +None. + +### `setimmutable` + +(`Statement::SetImmutable`) + +#### Description + +Write an immutable variable during contract construction. Immutables are written once in the constructor and read later via [`loadimmutable`](#loadimmutable). The key is a string identifier resolved by the linker. + +#### Syntax + +```text +setimmutable("", $value[: ]) +``` + +#### Example + +```text +setimmutable("MyContract.owner", v0: i160) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `value` | `i256` | The value to store; the key is a quoted string literal in the syntax position. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful | + +#### Annotations + +| Source field | Printed as | +|---|---| +| `key: String` | The quoted identifier in the syntax position. | + +## Structured control flow + +The IR's control flow is structured: `if`, `switch`, and `for` are statements with explicit nested regions, each carrying input values and yielding output values. The three jump-like statements (`break`, `continue`, `leave`) are scoped to their nearest enclosing construct. Nested blocks create lexical scope without otherwise changing control flow. + +### `if` + +(`Statement::If`) + +#### Description + +Conditional execution with optional value yields. The `then` region runs when `condition` is non-zero; the `else` region runs otherwise. If `outputs` is non-empty, both regions must yield the same number of values and the statement is bound by a `let`. + +#### Syntax + +```text +if $condition[: ] [[$input_0, $input_1, …]] { … } [else { … }] +``` + +#### Example + +```text +if v0 { + sstore(v1, v2) +} + +let v5, v6 := if v3 [v1, v2] { + let v7 := add(v2, 0x1) + yield v1, v7 +} else { + yield v1, v2 +} +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `condition` | `i256` | Branch selector; non-zero takes the `then` region. Often narrowed to `i1`. | +| `inputs` | `Vec` | Values threaded into both regions, printed in square brackets after the condition. | +| (regions) | — | The `then_region` is mandatory; the `else_region` is optional and, when absent, implicitly yields the inputs unchanged. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None for the statement form; for the value-yielding form, one value per `outputs` binding, types taken from the yielded values | Effectful (control flow) | + +#### Annotations + +None. + +### `switch` + +(`Statement::Switch`) + +#### Description + +Multi-way dispatch on a scrutinee value. Each case matches a specific constant and runs its region; an optional `default` region catches non-matching values. Like `if`, switch may yield values via `outputs` and accept thread-through values via `inputs`. + +#### Syntax + +```text +switch $scrutinee[: ] [[$input_0, …]] +case 0x { + … +} +[case 0x { + … +} …] +[default { + … +}] +``` + +#### Example + +```text +switch v0 +case 0x0 { + sstore(v1, v2) +} +case 0x1 { + sstore(v1, v3) +} +default { + invalid() +} +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `scrutinee` | `i256` | The value to compare against each case. | +| `inputs` | `Vec` | Values threaded into every case and default region. | +| `cases` | `Vec` | Each case carries a constant `value: BigUint` and a region. | +| (default) | — | Optional fall-through region. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None for the statement form; one value per `outputs` binding for the value-yielding form | Effectful (control flow) | + +#### Annotations + +None. + +### `for` + +(`Statement::For`) + +#### Description + +Structured loop with explicit loop-carried variables. Each iteration evaluates `condition_statements` followed by `condition`; if the condition is non-zero, the `body` region runs, then the `post` region runs, and the loop iterates. Loop-carried variables are passed as SSA values through each region. `break` exits the loop and `continue` jumps to the post region. + +#### Syntax + +```text +for { $variable_0 := $initial_0[, …] } + [// condition_statements: + …] + $condition + { // post + … + } +{ + … body … +} +``` + +#### Example + +```text +for { v1 := 0x0 } + lt(v1, 0xa) + { // post + let v3 := add(v1, 0x1) + yield v3 + } +{ + sstore(v1, v2) + yield v1 +} +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `initial_values` | `Vec` | Starting values for the loop-carried variables. | +| `loop_variables` | `Vec` | SSA ids visible inside condition, body, and post. | +| `condition_statements` | `Vec` | Statements evaluated each iteration *before* the condition expression; emitted into the loop header block. Printed only when non-empty, behind a `// condition_statements:` comment. | +| `condition` | `Expression` | Re-evaluated each iteration; non-zero continues, zero exits. | +| `body` | `Region` | Loop body; yields current loop-carried values. | +| `post_input_variables` | `Vec` | Input SSA ids for the post region (one per loop-carried variable); receive the body's yielded values merged with continue-site values via phi nodes in the LLVM codegen. | +| `post` | `Region` | Runs after each body iteration (and after `continue`); yields updated loop-carried values. | +| `outputs` | `Vec` | Final loop-carried values after exit. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None for the statement form; one value per `outputs` binding for the value-yielding form | Effectful (control flow) | + +#### Annotations + +None. + +### `break` + +(`Statement::Break`) + +#### Description + +Exit the innermost enclosing `for` loop. Carries the current values of loop-carried variables at the break point; these become the loop's outputs. + +#### Syntax + +```text +break +``` + +#### Example + +```text +if v0 { break } +``` + +#### Operands + +None in the printed form; the IR's `values: Vec` field carries the loop-carried values internally. + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful (control flow) | + +#### Annotations + +None. + +### `continue` + +(`Statement::Continue`) + +#### Description + +Skip to the post region of the innermost enclosing `for` loop. Like `break`, carries the current values of loop-carried variables internally. + +#### Syntax + +```text +continue +``` + +#### Example + +```text +if v0 { continue } +``` + +#### Operands + +None in the printed form; the IR's `values` field carries the loop-carried values internally. + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful (control flow) | + +#### Annotations + +None. + +### `leave` + +(`Statement::Leave`) + +#### Description + +Exit the current function, returning the listed values as the function's return values. The Yul-level `leave` keyword translates directly to this statement; the inlining pass eliminates intra-function `leave`s where possible via the exit-flag transformation. + +#### Syntax + +```text +leave [[$value_0[: ], $value_1[: ], …]] +``` + +#### Example + +```text +leave [v0, v1] // returns v0 and v1 from the function +leave // returns nothing (void function) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `return_values` | `Vec` | Empty for void functions; otherwise one entry per declared return. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful (control flow) | + +#### Annotations + +None. + +### Nested block + +(`Statement::Block`) + +#### Description + +A lexical scope without conditional or iterative behavior. The body is a region; control falls through after the region's statements complete. Used to bound the visibility of inner bindings. + +#### Syntax + +```text +{ + … +} +``` + +#### Example + +```text +{ + let v0 := add(v1, v2) + sstore(v3, v0) +} // v0 is no longer in scope here +``` + +#### Operands + +None — the body is a region, not an operand. + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful (per the body's contents) | + +#### Annotations + +None. + +## External interaction + +Statements that cross the contract boundary: external calls (four kinds), contract creation (two kinds), and event log emission. All produce or rely on external state and act as barriers to memory and storage analyses. + +### `call` + +(`Statement::ExternalCall` with `CallKind::Call`) + +#### Description + +Standard external call that may transfer value. Reads `args_length` bytes from emulated EVM linear memory at `args_offset` as calldata, executes the target, and writes up to `ret_length` bytes of return data into linear memory at `ret_offset`. The boolean result indicates success. + +#### Syntax + +```text +let $result := call($gas[: ], $address[: ], $value[: ], $args_offset[: ], $args_length[: ], $ret_offset[: ], $ret_length[: ]) +``` + +#### Example + +```text +let v8 := call(v0, v1: i160, v2, v3, v4, v5, v6) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `gas` | `i256` | Gas to forward to the target. | +| `address` | `i256` | Callee address; narrows to `i160`. | +| `value` | `i256` | Wei to transfer with the call. | +| `args_offset` | `i256` | Calldata source offset in linear memory. | +| `args_length` | `i256` | Calldata length in bytes. | +| `ret_offset` | `i256` | Return-data destination offset in linear memory. | +| `ret_length` | `i256` | Maximum return-data length. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` (success flag: `1` on success, `0` on revert/error; narrowable to `i1`) | Effectful | + +#### Annotations + +None. + +### `callcode` + +(`Statement::ExternalCall` with `CallKind::CallCode`) + +#### Description + +Deprecated EVM opcode that executes the callee's code in the caller's context but with the callee's storage. Preserved for Solidity compatibility; new code should use [`delegatecall`](#delegatecall). + +#### Syntax + +```text +let $result := callcode($gas[: ], $address[: ], $value[: ], $args_offset[: ], $args_length[: ], $ret_offset[: ], $ret_length[: ]) +``` + +#### Example + +```text +let v8 := callcode(v0, v1: i160, v2, v3, v4, v5, v6) +``` + +#### Operands + +Same shape as [`call`](#call). + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` (success flag; narrowable to `i1`) | Effectful | + +#### Annotations + +None. + +### `delegatecall` + +(`Statement::ExternalCall` with `CallKind::DelegateCall`) + +#### Description + +Execute the callee's code in the caller's context: same storage, same sender, same call value. The standard mechanism for library calls and proxy patterns. No `value` operand (the caller's call value is inherited). + +#### Syntax + +```text +let $result := delegatecall($gas[: ], $address[: ], $args_offset[: ], $args_length[: ], $ret_offset[: ], $ret_length[: ]) +``` + +#### Example + +```text +let v7 := delegatecall(v0, v1: i160, v2, v3, v4, v5) +``` + +#### Operands + +Same shape as [`call`](#call) minus the `value` operand. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` (success flag; narrowable to `i1`) | Effectful | + +#### Annotations + +None. + +### `staticcall` + +(`Statement::ExternalCall` with `CallKind::StaticCall`) + +#### Description + +Read-only external call. Any state modification in the callee (including nested calls) causes the call to revert. No `value` operand. + +#### Syntax + +```text +let $result := staticcall($gas[: ], $address[: ], $args_offset[: ], $args_length[: ], $ret_offset[: ], $ret_length[: ]) +``` + +#### Example + +```text +let v7 := staticcall(v0, v1: i160, v2, v3, v4, v5) +``` + +#### Operands + +Same shape as [`call`](#call) minus the `value` operand. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` (success flag; narrowable to `i1`) | Effectful (no state writes, but still an external boundary and may revert) | + +#### Annotations + +None. + +### `create` + +(`Statement::Create` with `CreateKind::Create`) + +#### Description + +Deploy a new contract with the given init-code bytes, transferring `value` wei from the caller. The new contract's address is derived from the caller's address and nonce; on failure the result is `0`. + +#### Syntax + +```text +let $result := create($value[: ], $offset[: ], $length[: ]) +``` + +#### Example + +```text +let v4 := create(v0, v1, v2) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `value` | `i256` | Wei to transfer to the new contract. | +| `offset` | `i256` | Linear-memory offset of the init code. | +| `length` | `i256` | Length of the init code in bytes. | + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` (created address; narrowable to `i160` on success, `0` on failure) | Effectful | + +#### Annotations + +None. + +### `create2` + +(`Statement::Create` with `CreateKind::Create2`) + +#### Description + +Deploy a new contract with a deterministic address derived from the caller's address, the salt, and the init-code hash. Same operand shape as [`create`](#create) plus an additional `salt`. + +#### Syntax + +```text +let $result := create2($value[: ], $offset[: ], $length[: ], $salt[: ]) +``` + +#### Example + +```text +let v5 := create2(v0, v1, v2, v3) +``` + +#### Operands + +Same as [`create`](#create) plus `salt: i256`. + +#### Result and purity + +| Result | Purity | +|---|---| +| `i256` (created address; narrowable to `i160` on success, `0` on failure) | Effectful | + +#### Annotations + +None. + +### `log` + +(`Statement::Log`) + +#### Description + +Emit an event log entry. The mnemonic suffix `` is the number of indexed topics (`0` through `4`), determined by the length of the IR's `topics` field. The data portion is read from `length` bytes of emulated EVM linear memory at `offset`. + +#### Syntax + +```text +log($offset[: ], $length[: ][, $topic_0[: ], …]) +``` + +#### Example + +```text +log0(v0, v1) +log2(v0, v1, v2, v3) // two topics +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `offset` | `i256` | Data source offset in linear memory. | +| `length` | `i256` | Data length in bytes. | +| `topics` | `Vec` | Zero to four indexed topic values; the length determines the mnemonic suffix. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None | Effectful | + +#### Annotations + +None. + +## Termination + +Statements that end the current call frame. Three plain forms (`return`, `revert`, `stop`), two unconditional traps (`invalid`, `selfdestruct`), and three outlined revert variants that encode common Solidity error patterns into single nodes that can be deduplicated across call sites. + +### `return` + +(`Statement::Return`) + +#### Description + +End the current call frame successfully, returning `length` bytes from emulated EVM linear memory at `offset` as the return data. + +#### Syntax + +```text +return($offset[: ], $length[: ]) +``` + +#### Example + +```text +return(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `offset` | `i256` | Return-data source offset. | +| `length` | `i256` | Return-data length. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None — terminates the call frame | Effectful (terminator) | + +#### Annotations + +None. + +### `revert` + +(`Statement::Revert`) + +#### Description + +End the current call frame with a revert, undoing all state changes made during the call, and returning `length` bytes of revert data from emulated EVM linear memory at `offset`. + +#### Syntax + +```text +revert($offset[: ], $length[: ]) +``` + +#### Example + +```text +revert(v0, v1) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `offset` | `i256` | Revert-data source offset. | +| `length` | `i256` | Revert-data length. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None — terminates the call frame | Effectful (terminator) | + +#### Annotations + +None. + +### `stop` + +(`Statement::Stop`) + +#### Description + +End the current call frame successfully with empty return data. + +#### Syntax + +```text +stop() +``` + +#### Example + +```text +stop() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| None — terminates the call frame | Effectful (terminator) | + +#### Annotations + +None. + +### `invalid` + +(`Statement::Invalid`) + +#### Description + +Unconditional invalid-opcode trap. Consumes all remaining gas and reverts. Used for unreachable branches and assertion failures. + +#### Syntax + +```text +invalid() +``` + +#### Example + +```text +invalid() +``` + +#### Operands + +None. + +#### Result and purity + +| Result | Purity | +|---|---| +| None — terminates the call frame | Effectful (terminator) | + +#### Annotations + +None. + +### `selfdestruct` + +(`Statement::SelfDestruct`) + +#### Description + +End the current call frame and transfer the contract's remaining balance to `address`. Post-Cancun, the contract storage is not deleted (selfdestruct is effectively deprecated; the opcode still exists for legacy compatibility). + +#### Syntax + +```text +selfdestruct($address[: ]) +``` + +#### Example + +```text +selfdestruct(v0: i160) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `address` | `i256` | Recipient of the contract's balance; narrows to `i160`. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None — terminates the call frame | Effectful (terminator) | + +#### Annotations + +None. + +### `panic_revert` + +(`Statement::PanicRevert`) + +#### Description + +Outlined Solidity panic revert. Equivalent to writing the `Panic(uint256)` ABI encoding (selector `0x4e487b71` plus the panic code) into emulated EVM linear memory and reverting, but emitted as a single statement that lowers to one outlined helper call. Common panic codes: `0x01` assertion failure, `0x11` arithmetic overflow, `0x12` division by zero, `0x32` array-out-of-bounds, `0x41` memory overflow. + +#### Syntax + +```text +panic_revert(0x) +``` + +#### Example + +```text +panic_revert(0x11) // arithmetic overflow +``` + +#### Operands + +None — the panic code is stored as a `u8` field on the IR, not an SSA operand. + +#### Result and purity + +| Result | Purity | +|---|---| +| None — terminates the call frame | Effectful (terminator) | + +#### Annotations + +| Source field | Printed as | +|---|---| +| `code: u8` | The panic code in `0x` form (two hex digits, zero-padded). | + +### `error_string_revert` + +(`Statement::ErrorStringRevert`) + +#### Description + +Outlined Solidity `Error(string)` revert. Equivalent to writing the `Error` selector (`0x08c379a0`), the string offset and length, and up to four 32-byte data words into emulated EVM linear memory and reverting. The string length and the data words are stored as compile-time fields; no SSA operands. + +#### Syntax + +```text +error_string_revert(, _words) +``` + +#### Example + +```text +error_string_revert(12, 1_words) // 12-byte string in one 32-byte word +``` + +#### Operands + +None — the string length and data are compile-time fields, not SSA operands. + +#### Result and purity + +| Result | Purity | +|---|---| +| None — terminates the call frame | Effectful (terminator) | + +#### Annotations + +| Source field | Printed as | +|---|---| +| `length: u8` | The string length in bytes, in the first syntax position. | +| `data: Vec` | The number of 32-byte data words (1–4), printed as `_words` in the second syntax position. The actual data is stored separately and not shown in the printed form. | + +### `custom_error_revert` + +(`Statement::CustomErrorRevert`) + +#### Description + +Outlined Solidity custom-error revert. Encodes the error selector (left-shifted by 224 bits) and zero to three argument values into scratch memory and reverts. No FMP load is needed; the encoding uses the scratch region at offset `0`. + +#### Syntax + +```text +custom_error_revert(0x, [$arg_0, $arg_1, …]) +``` + +#### Example + +```text +custom_error_revert(0xa28c4c1100000000000000000000000000000000000000000000000000000000, [v0, v1]) +``` + +#### Operands + +| Name | Type | Notes | +|---|---|---| +| `arguments` | `Vec` | 0–3 argument values; the selector is a compile-time field. | + +#### Result and purity + +| Result | Purity | +|---|---| +| None — terminates the call frame | Effectful (terminator) | + +#### Annotations + +| Source field | Printed as | +|---|---| +| `selector: BigUint` | The 4-byte error selector shifted left by 224 bits, printed in hex in the first syntax position. | diff --git a/book/src/developer_guide/newyork_optimizer.md b/book/src/developer_guide/newyork_optimizer.md new file mode 100644 index 000000000..75b0f94dd --- /dev/null +++ b/book/src/developer_guide/newyork_optimizer.md @@ -0,0 +1,286 @@ +# The newyork optimizer + +The `newyork` crate (`crates/newyork/`) introduces an additional intermediate representation (IR) layer between Yul and LLVM IR. It enables domain-specific optimizations that neither `solc` nor LLVM can perform on their own, because they lack semantic knowledge about the cross-domain compilation from EVM to PolkaVM. + +> [!NOTE] +> The newyork optimizer is experimental. It is gated behind the `RESOLC_USE_NEWYORK=1` environment variable (for standard JSON mode) or the `--newyork` CLI flag, and not yet enabled by default. + +## Motivation + +The EVM and PolkaVM are fundamentally different machines: + +| Property | EVM | PolkaVM (RISC-V) | +|---|---|---| +| Word size | 256-bit | 64-bit | +| Endianness | Big-endian | Little-endian | +| Architecture | Stack machine | Register-based | +| Memory model | Linear with free pointer convention | Flat address space | + +`solc` optimizes Yul IR for EVM gas costs on a 256-bit big-endian stack machine. LLVM, on the other hand, operates at too low a level to understand EVM memory semantics or Solidity patterns. By the time Yul reaches LLVM IR, the high-level intent is lost. + +The newyork IR sits between these two worlds and recovers enough semantic information to make optimization decisions that neither compiler can make alone. + +## Pipeline overview + +```text + ┌──────────────────────────────────────────────────┐ +Yul AST ──────────► │ newyork IR │ ──► LLVM IR ──► RISC-V + from_yul│ │ to_llvm + │ 1. inline │ + │ 2. simplify (pass 1) │ + │ 3. dedup (exact + fuzzy) │ + │ 4. mem_opt + fmp_prop + keccak_fold │ + │ 5. simplify (pass 2) │ + │ 6. compound_outlining + guard_narrow │ + │ 7. simplify (pass 3) │ + │ 8. dedup (exact + fuzzy, pass 2) │ + │ ── recursive on subobjects ── │ + │ 9. heap_opt (analysis) │ + │ 10. type_inference (4 iterative rounds) │ + │ 11. validate │ + └──────────────────────────────────────────────────┘ +``` + +The optimizer runs the following passes in order: + +1. **Inlining** -- custom heuristics tuned for PolkaVM call overhead, with Tarjan SCC-based recursion detection and quadratic leave-overhead modeling. +2. **Simplify** (pass 1) -- constant folding, algebraic identities, strength reduction (`mul` by power-of-2 to `shl`), copy propagation, dead code elimination, environment read CSE (`callvalue`, `caller`, `origin`, etc.), and revert pattern outlining (panic selectors, custom error selectors). +3. **Function deduplication** -- exact structural match, then fuzzy dedup (functions differing only in literal constants are parameterized and merged, up to 4 differing positions). +4. **Memory optimization** -- load-after-store elimination, keccak256 fusion (`mstore` + `keccak256` sequences into `Keccak256Single`/`Keccak256Pair` nodes), free memory pointer propagation (replaces `mload(0x40)` with a known constant), and constant keccak256 folding (precomputes hashes of compile-time-constant inputs). +5. **Simplify** (pass 2) -- cleans up dead code and new constant expressions exposed by memory optimization and keccak folding. +6. **Compound outlining** -- detects `keccak256_pair` + `sload`/`sstore` sequences and fuses them into `MappingSLoad`/`MappingSStore` IR nodes, eliminating intermediate hash values. **Guard narrowing** -- detects `if gt(val, MASK) { revert }` and `iszero(eq(val, and(val, MASK)))` patterns and inserts AND-mask narrowing, giving type inference proof that values fit in fewer bits. +7. **Simplify** (pass 3) -- propagates opportunities created by compound outlining and guard narrowing. +8. **Function deduplication** (pass 2) -- catches new duplicates exposed by guard narrowing and compound outlining canonicalization. +9. **Heap analysis** -- analyzes memory access patterns (alignment, static offsets, taintedness, escaping regions) to determine which accesses can use native little-endian layout, skipping byte-swap operations. Uses GCD-based alignment propagation and per-region taint tracking. +10. **Type inference** -- narrows 256-bit values to smaller widths (`I1`, `I8`, `I32`, `I64`, `I128`, `I160`) where provable. Runs iteratively for up to 4 cascading refinement rounds, combining forward min-width propagation, backward use-context demands, transparent-operation demand propagation, and interprocedural parameter/return narrowing. +11. **Validation** -- checks SSA well-formedness (use-before-def, multiple definitions), yield count consistency, and function reference correctness. + +Steps 1-8 run recursively on subobjects (deployed contract code), where optimization impact is greatest. Steps 9-11 run on the full object tree. + +## IR design + +The newyork IR is an SSA form with structured control flow, inspired by MLIR's SCF dialect. Key design choices: + +- **Explicit types with address spaces**: Every value carries a bit-width (`I1`, `I8`, `I32`, `I64`, `I128`, `I160`, `I256`) and pointers carry address space information (`Heap`, `Stack`, `Storage`, `Code`). All values start as `I256` and are narrowed by type inference. +- **Pure expressions vs. effectful statements**: Expressions compute values without side effects; statements perform memory, storage, or control flow effects. This separation simplifies analysis and rewriting. +- **Semantic annotations**: Memory operations are tagged with region information (`Scratch`, `FreePointerSlot`, `Dynamic`). Storage operations carry static slot values when known at compile time. +- **Structured control flow**: `If`, `Switch`, and `For` nodes preserve the high-level structure from Yul, with explicit region arguments and yields for value flow across control edges. + +For per-operation detail — printed syntax, operand and result types, and more — see the [newyork IR reference](./newyork_ir.md). + +## Key optimizations explained + +### Type narrowing + +EVM operates on 256-bit words, but most values in practice fit in 32 or 64 bits. The type inference pass performs bidirectional analysis: + +- **Forward**: computes minimum width from literal values and operation semantics (e.g., `add(I64, I8)` produces `I65`, rounded up to `I128`). +- **Backward use tracking**: classifies each value's uses into 9 context categories (`MemoryOffset`, `MemoryValue`, `StorageAccess`, `Comparison`, `Arithmetic`, `FunctionArg`, `FunctionReturn`, `ExternalCall`, `General`). All categories conservatively demand the full `I256` width by default; the categorisation is what enables the interprocedural phase to selectively relax the demand for narrowed function arguments. Earlier versions narrowed directly from the use category, but that was unsound for memory offsets — `mload(2^128)` aliased to `mload(0)` because the bounds check ran on an already-truncated value (commit `ccca38df`). +- **Transparent demand propagation**: for modular-arithmetic operations (`Add`, `Sub`, `Mul`, `And`, `Or`, `Xor`), propagates narrow demands backward through operands, exploiting the property that `trunc(op(a,b), N) == op(trunc(a,N), trunc(b,N))`. +- **Interprocedural**: iteratively narrows function parameter and return types in up to four rounds, combining four narrowing strategies — body-driven parameter narrowing, caller-driven parameter narrowing, forward-based return narrowing, and demand-based return narrowing — and re-running full inference between rounds. Parameters are clamped to at least `I32` (XLEN on PolkaVM). + +This allows LLVM to emit native 32/64-bit instructions instead of software-emulated 256-bit arithmetic, and eliminates expensive multi-instruction comparison sequences (16-20 RISC-V instructions for i256 comparisons reduced to 1-2 for i64). + +### Guard narrowing + +Solidity emits runtime guards that prove values fit in narrow ranges (e.g., address validation via `if gt(val, 2^160-1) { revert }`). The guard narrowing pass detects these patterns and inserts explicit AND-mask narrowing after the guard. This gives downstream type inference proof that the value fits in fewer bits, enabling cascading narrowing of comparisons, arithmetic, and memory operations that use the guarded value. + +Two pattern families are recognized: + +- **GT-based guards**: `if gt(val, MASK) { }` where MASK is a boundary value like `2^N - 1` +- **EQ-based guards**: `iszero(eq(val, and(val, MASK)))` patterns common in Solidity's address validation + +### Heap optimization + +PVM doesn't provide EVM-compatible linear memory, so the compiler emulates it using a byte buffer with byte-swap operations for big-endian compatibility. The heap analysis pass determines which memory accesses can use native little-endian layout by analyzing access patterns: + +- Tracks alignment and static offset information for all memory accesses using GCD-based propagation +- Propagates taintedness when addresses escape to external calls, are written by external sources (`codecopy`, `calldatacopy`), or use unaligned access patterns +- Tracks variable-accessed offsets to prevent mode mismatches between native and byte-swap accesses to the same location +- Handles loop-carried variables conservatively (marked as non-literal to prevent false constant propagation) + +The codegen backend supports four memory access modes: `AllNative` (all accesses skip byte-swap), `InlineNative` (constant-offset accesses use native layout), `InlineByteSwap` (constant-offset accesses use inline byte-swap), and `ByteSwap` (standard byte-swap through helper functions). + +### Free memory pointer range proof + +The Solidity free memory pointer (`mload(0x40)`) always fits in 32 bits — sbrk enforces `FMP < heap_size` on every store, regardless of which memory mode the contract uses. After every literal `mload(0x40)`, codegen emits a `trunc N → zext 256` chain (where N is `bits(heap_size - 1)`, e.g. 17 for the 131,072-byte default heap). The trunc-extend round-trip is a no-op semantically, but exposes the bound to LLVM's IPSCCP range analysis, which then propagates it through every `add(fmp, K)` and eliminates the trailing `safe_truncate_int_to_xlen` overflow checks at every FMP-derived offset use. Despite only affecting a single codegen site, this is the single largest contributor to the optimizer's code-size reduction. + +A subtle gating issue: the byte-order mode (`InlineNative` / `ByteSwap`) and the value bound on FMP are *independent* invariants. `fmp_native_safe()` and `can_use_native(0x40)` protect against mixing little-endian writers with big-endian readers on the FMP slot, which would corrupt the stored offset; the value bound is unrelated and holds in every mode. Earlier versions of the codegen gated the load-side range proof on the byte-order checks, which suppressed the optimization for any contract with dynamic memory accesses. Decoupling the two reasonings — keeping the byte-order gate on the *store* side, dropping it from the load-side range proof — is what makes the multiplicative IPSCCP effect available to OZ-class contracts. + +### Soundness traps for FMP optimizations + +The FMP slot is small but easy to mis-optimize. The codebase carries several +regression tests for previously-found soundness bugs; new FMP-related changes +should be verified against them: + +- **`mload_at_fmp_slot`** (`crates/integration/src/tests.rs`, fixed in + `1fd6063c`): tests `mload(0x40)` and offsets near it (`0x21`, `0x3f`, `0x42`) + on a contract that also performs dynamic mloads. Catches byte-order mismatches + when one access goes native (LE) and another goes byte-swap (BE). The fix + blocks native mode for FMP whenever `has_dynamic_accesses` is true. +- **`mload_huge_offset_traps`** (fixed in `ccca38df`): tests that + `mload(2^128)` and `mload(2^255)` correctly trap via the gas-exhaustion + path. Catches `UseContext::MemoryOffset` narrowing bypassing the + `safe_truncate_int_to_xlen` overflow check at the use site — + `mload(2^128)` aliasing to `mload(0)` and returning the zero-initialized + scratch slot. The fix classifies `MemoryOffset` as `I256` so it doesn't + drive narrowing; the bounds check at the use site catches out-of-range. +- **FMP i32 shortcut removal** (`dbcfc921`): an earlier optimization stored + only 4 bytes at offset 0x40 instead of the full 32-byte EVM word, breaking + any inline assembly using `mstore(0x40, ...)` for non-FMP purposes. + Caused a cascade of 249/251 retester failures via allocator corruption. + No dedicated regression test was added — the retester corpus was sufficient + coverage — but the lesson generalizes: writes to 0x40 must store the full + word, even when the high bits are provably zero, because the slot is part + of the same 32-byte memory region read by other code. + +When adding an optimization that touches FMP, distinguish carefully between: +the **byte-order encoding** at the slot (must be consistent between writers +and readers), the **value bound** (FMP < heap_size, always true), and the +**stored width** (must be 32 bytes for `mstore(0x40, ...)`, even though only +the low N bits are non-zero). + +### Keccak256 fusion and folding + +Two complementary optimizations target the common Solidity pattern of hashing values for storage slot computation: + +- **Fusion**: Recognizes `mstore` + `keccak256` sequences and fuses them into dedicated IR nodes (`Keccak256Single`, `Keccak256Pair`), eliminating intermediate memory traffic. +- **Constant folding**: When all keccak256 inputs are compile-time constants, the hash is computed at compile time and replaced with a literal. + +### Compound outlining (mapping access) + +Solidity mapping accesses follow a predictable pattern: hash a key with a storage slot, then load/store the result. The compound outlining pass detects `keccak256_pair(key, slot)` followed by `sload`/`sstore` and fuses them into `MappingSLoad`/`MappingSStore` IR nodes. These are lowered to outlined helper functions (`__revive_mapping_sload`, `__revive_mapping_sstore`) that combine the hash computation with the storage operation, eliminating intermediate values and redundant byte-swaps. + +### Fuzzy function deduplication + +Solidity generates many near-identical functions that differ only in literal constants (e.g., error selectors, storage slot offsets). Fuzzy deduplication identifies such groups, parameterizes the differing literals (up to 4 positions), and replaces all copies with calls to a single shared implementation. + +### Revert pattern outlining + +The simplify pass detects common revert patterns and replaces them with compact IR nodes: + +- **Panic reverts**: Solidity `Panic(uint256)` sequences (selector `0x4e487b71` + encoded panic code) are collapsed into `PanicRevert { code }` nodes, which are lowered to shared helper functions. +- **Custom error reverts**: ABI-encoded custom error reverts with known selectors are collapsed into `CustomErrorRevert { selector, args }` nodes. + +These patterns appear dozens of times in typical contracts, and outlining them into shared blocks eliminates significant code duplication. + +### Outlined helper functions + +The LLVM codegen backend generates approximately 15 types of outlined helper functions for common operations: + +- **Storage**: `__revive_sload_word`, `__revive_sstore_word` (handle byte-swap internally) +- **Mapping**: `__revive_mapping_sload`, `__revive_mapping_sstore` (keccak256 + storage in one call) +- **Callvalue**: `__revive_callvalue`, `__revive_callvalue_nonzero` (boolean optimization for non-payable checks) +- **Calldataload**: `__revive_calldataload` (outlined when >= 20 call sites) +- **Memory**: `__revive_store_bswap`, `__revive_exit_checked`, `__revive_return_word` +- **Errors**: `__revive_error_string_revert_N`, `__revive_custom_error_N` (per data-word count) +- **Keccak wrappers**: `__keccak256_slot_N` (one `noinline` wrapper per constant slot, internally dispatching to `__revive_keccak256_two_words`) + +Additionally, common exit patterns (revert with constant length, zero-value returns) are deduplicated into shared LLVM basic blocks, saving hundreds of instruction copies in large contracts. + +## Codesize results + +### Integration test contracts + +Reproducible with `cargo test --package revive-integration -- codesize`. The `main` column is the value committed to `crates/integration/codesize.json` on `main`; the `newyork` column is the value produced by the same test with `RESOLC_USE_NEWYORK=1` set, currently committed on this branch. + +| Contract | main (bytes) | newyork (bytes) | Reduction | +|---|---|---|---| +| Baseline | 870 | 479 | −44.9% | +| Computation | 2,418 | 1,376 | −43.1% | +| DivisionArithmetics | 9,327 | 7,192 | −22.9% | +| ERC20 | 17,160 | 10,138 | −40.9% | +| Events | 1,662 | 1,279 | −23.0% | +| FibonacciIterative | 1,427 | 949 | −33.5% | +| Flipper | 2,240 | 1,123 | −49.9% | +| SHA1 | 8,009 | 6,286 | −21.5% | + +### OpenZeppelin contracts + +Measured by running `oz-tests/oz.sh` against real-world contracts generated with the OpenZeppelin Wizard. The numbers below are a development snapshot — there is no committed measurement file in the repo, so these may drift as the optimizer evolves; rerun the script for fresh figures. + +| Contract | newyork (bytes) | +|---|---| +| oz_gov | 81,840 | +| erc721 | 52,634 | +| erc20 | 45,703 | +| oz_stable | 45,052 | +| oz_rwa | 41,581 | +| erc1155 | 33,087 | +| oz_simple_erc20 | 17,024 | +| proxy | 3,748 | +| **Total** | **320,669** | + +For comparison, building the same contracts without the newyork optimizer at the equivalent snapshot produced **563,526** bytes total — a reduction of about **−43%** across the corpus. + +Per-contract reductions in the integration suite range from roughly **−21%** (SHA1, where the bulk of the work is the SHA-1 inner loop and offers little to optimise) to nearly **−50%** (Flipper, where the optimiser strips away most of Solidity's dispatch and storage-access scaffolding). + +## Development history and challenges + +The newyork optimizer was developed over roughly three months — from early February 2026 through early May 2026 — largely through AI-assisted pair programming with Claude. The development progressed through several distinct phases: + +**Phase 1 -- Initial scaffolding**: The first draft established the core IR data structures, Yul-to-IR translation, and LLVM codegen. Early commits focused on getting a correct round-trip through the new pipeline. + +**Phase 2 -- Optimization passes**: Once the baseline was stable, optimization passes were added iteratively: inlining, simplification, memory optimization, function deduplication, keccak256 fusion, and type inference. Each pass was validated against differential tests comparing EVM and PVM execution. + +**Phase 3 -- Soundness hardening**: Several type inference and narrowing approaches turned out to be unsound and had to be reworked: +- An early type inference approach caused namespace collisions across subobjects and was scoped per-object. +- Caller-based parameter narrowing was polluted by overly aggressive inference and replaced with body-based structural analysis. +- Backward demand-driven narrowing required multiple iterations to become provably safe. + +**Phase 4 -- Measuring and tuning**: Systematic measurement of OpenZeppelin contracts revealed which optimizations had the most impact and which approaches regressed performance. + +### Approaches that did not work + +| Approach | Outcome | +|---|---| +| Storage bswap decomposition (4x bswap.i64) | Regressed: LLVM handles bswap.i256 better natively | +| NoInline on `__revive_int_truncate` | +62% regression: PolkaVM call overhead exceeds inline cost | +| Native FMP memory (inline sbrk) | Mixed: small contracts improved, large ones regressed from sbrk bloat | +| Shared overflow trap block | Mixed: prevented LLVM from eliminating individual dead overflow checks | + +These results highlight a recurring theme: interacting well with LLVM's own optimization passes is critical. Optimizations at the IR level can inadvertently inhibit LLVM's downstream passes, sometimes causing surprising regressions. + +## Known limitations and future work + +The following opportunities have been identified but are not yet implemented: + +- **Bitwise algebraic simplifications**: `BitAnd`, `BitOr`, `BitXor` identity patterns fall through without simplification. +- **Cross-control-flow memory optimization**: Memory state is conservatively cleared at `if`/`switch`/`for` boundaries. Preserving state across simple branches would enable more load-after-store eliminations. +- **Adaptive inlining thresholds**: Current thresholds are static constants. Profile-guided or contract-size-aware heuristics could improve decisions for diverse contract sizes. +- **Extended fuzzy deduplication**: The current pass only compares functions by structure of `Let` bindings. Extending to consider literals inside `MStore`, `Return`, `Revert`, and `Log` statements would find more deduplication opportunities. +- **Type checking in validation**: The validator checks SSA well-formedness and structural correctness, but does not yet verify type consistency of operations (the `TypeMismatch` error variant exists but is not yet wired). +- **Loop variable narrowing**: Loop-carried variables are conservatively widened to `I256`. Reaching a fixed-point across loop iterations could allow narrower types for simple counters. + +## Environment variables + +A small set of environment variables controls or inspects the newyork pipeline. Only `RESOLC_USE_NEWYORK` affects generated bytecode; the others are read-only inspection knobs used while debugging the optimizer. + +| Variable | Effect | +|---|---| +| `RESOLC_USE_NEWYORK=1` | Routes Yul lowering through the newyork pipeline. Equivalent to passing `--newyork` on the command line; the CLI flag and this variable are OR-ed by `resolve_use_newyork` (`crates/resolc/src/lib.rs`). | +| `RESOLC_DEBUG_IR` | When set, prints the translated newyork IR for every object to stderr. Additionally writes `/.newyork.txt` whenever the debug config carries an output directory. | +| `RESOLC_DEBUG_HEAP` | When set, appends per-object heap-analysis details — native regions/offsets, taintedness, dynamic escapes, escaping ranges — to `/resolc_heap_debug.log`. Requires the debug config to carry an output directory. | +| `NEWYORK_DUMP_IR` | When set, writes the IR for every translated object to `/tmp/newyork_ir_.txt` from inside `translate_yul_object` (`crates/newyork/src/lib.rs`). Independent of `RESOLC_DEBUG_IR` — fires before codegen and needs no output directory. | +| `RESOLC_DEBUG_BLOB` | Test harness only. Dumps the compiled PVM blob to `/tmp/debug_blob_.pvm` and the LLVM IR debug directory to `/tmp/debug_llvm_newyork` or `/tmp/debug_llvm_yul`. Used by `crates/resolc/src/test_utils.rs` when comparing newyork against the Yul path. | + +All of these gate on presence/value at the start of compilation; flipping them mid-run has no effect. + +## Module reference + +| Module | Purpose | +|---|---| +| `lib.rs` | Pipeline orchestration and pass sequencing | +| `ir.rs` | Core IR data structures (types, expressions, statements, functions, objects) | +| `from_yul.rs` | Yul AST to newyork IR translation (two-pass with forward reference support) | +| `to_llvm.rs` | newyork IR to LLVM IR codegen with outlined helpers and narrowing | +| `simplify.rs` | Constant folding, algebraic identities, strength reduction, copy propagation, DCE, environment read CSE, revert outlining, callvalue hoisting, function deduplication (exact and fuzzy), constant keccak folding | +| `inline.rs` | Function inlining with PolkaVM-tuned heuristics (Tarjan SCC, leave elimination) | +| `type_inference.rs` | Bidirectional integer width narrowing with transparent demand propagation | +| `mem_opt.rs` | Load-after-store elimination, keccak256 fusion, FMP propagation | +| `heap_opt.rs` | Heap access pattern analysis, alignment tracking, byte-swap elimination | +| `compound_outlining.rs` | Mapping access pattern detection and fusion (`keccak256_pair` + `sload`/`sstore`) | +| `guard_narrow.rs` | Guard pattern detection and AND-mask narrowing insertion | +| `validate.rs` | IR well-formedness checks (SSA, yields, function references) | +| `printer.rs` | Human-readable IR pretty printer with configurable output | +| `ssa.rs` | SSA construction helpers (scope management, phi-node merging) | diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs index 3081632de..2943e9323 100644 --- a/crates/common/src/lib.rs +++ b/crates/common/src/lib.rs @@ -10,6 +10,7 @@ pub(crate) mod extension; pub(crate) mod keccak256; pub(crate) mod metadata; pub(crate) mod object; +pub(crate) mod solidity_selector; pub(crate) mod utils; pub use self::base::*; @@ -21,5 +22,6 @@ pub use self::extension::*; pub use self::keccak256::*; pub use self::metadata::*; pub use self::object::*; +pub use self::solidity_selector::*; pub use self::utils::*; pub use contract_identifier::*; diff --git a/crates/common/src/solidity_selector.rs b/crates/common/src/solidity_selector.rs new file mode 100644 index 000000000..d04c67c07 --- /dev/null +++ b/crates/common/src/solidity_selector.rs @@ -0,0 +1,22 @@ +//! Solidity ABI selector words used when emitting reverts. +//! +//! Each constant is the 32-byte EVM memory word that stores the corresponding +//! Solidity selector at memory offset 0. The 4-byte selector occupies the +//! high-order bytes (memory addresses 0..4) and the remaining 28 bytes are +//! zero. The hex strings are consumed verbatim by 256-bit integer constructors +//! such as `Context::word_const_str_hex`, so the selector ends up in the most +//! significant bits of the resulting `i256`. + +/// 32-byte EVM word holding the Solidity `Panic(uint256)` ABI selector. +/// +/// `keccak256("Panic(uint256)")[..4] == 0x4e487b71`, placed in the high-order +/// bytes of a 32-byte word followed by 28 zero bytes. +pub const PANIC_UINT256_SELECTOR_WORD_HEX: &str = + "4e487b7100000000000000000000000000000000000000000000000000000000"; + +/// 32-byte EVM word holding the Solidity `Error(string)` ABI selector. +/// +/// `keccak256("Error(string)")[..4] == 0x08c379a0`, placed in the high-order +/// bytes of a 32-byte word followed by 28 zero bytes. +pub const ERROR_STRING_SELECTOR_WORD_HEX: &str = + "08c379a000000000000000000000000000000000000000000000000000000000"; diff --git a/crates/integration/codesize.json b/crates/integration/codesize.json index 878d2fcea..9c3c57e0c 100644 --- a/crates/integration/codesize.json +++ b/crates/integration/codesize.json @@ -1,10 +1,10 @@ { - "Baseline": 870, - "Computation": 2418, - "DivisionArithmetics": 9368, - "ERC20": 17090, - "Events": 1662, - "FibonacciIterative": 1427, - "Flipper": 2240, - "SHA1": 8056 + "Baseline": 493, + "Computation": 1313, + "DivisionArithmetics": 7288, + "ERC20": 8895, + "Events": 909, + "FibonacciIterative": 969, + "Flipper": 1058, + "SHA1": 5209 } \ No newline at end of file diff --git a/crates/integration/codesize_newyork.json b/crates/integration/codesize_newyork.json new file mode 100644 index 000000000..a9eba0f5b --- /dev/null +++ b/crates/integration/codesize_newyork.json @@ -0,0 +1,10 @@ +{ + "Baseline": 479, + "Computation": 1376, + "DivisionArithmetics": 7192, + "ERC20": 10138, + "Events": 1279, + "FibonacciIterative": 949, + "Flipper": 1123, + "SHA1": 6286 +} \ No newline at end of file diff --git a/crates/integration/contracts/CallerOriginAliasing.sol b/crates/integration/contracts/CallerOriginAliasing.sol new file mode 100644 index 000000000..888938845 --- /dev/null +++ b/crates/integration/contracts/CallerOriginAliasing.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +// Differential guard against a latent soundness footgun in the codegen for +// __revive_caller: before the fix the helper wrote its result through the +// shared @__address_spill_buffer LLVM global while declaring +// memory(inaccessiblemem: read). The same global is also written by the +// inlined tx.origin and address(this) patterns, so the function attribute +// was a contract violation from LLVM's point of view (globals are Other +// memory, not inaccessiblemem). Any optimizer pass that exploited the wrong +// attribute to CSE / hoist a load of the spill buffer across a +// __revive_caller() call would have miscompiled the surrounding tx.origin / +// address(this) read. +// +// The fix moves __revive_caller's output to a function-local alloca so the +// attribute matches the body. This contract exercises every shape that +// previously shared the spill buffer. +contract CallerOriginAliasing { + function caller_then_origin() external view returns (address, address) { + return (msg.sender, tx.origin); + } + + function origin_then_caller() external view returns (address, address) { + return (tx.origin, msg.sender); + } + + function caller_address_origin() external view returns (address, address, address) { + return (msg.sender, address(this), tx.origin); + } + + function repeated_caller() external view returns (address, address, address) { + return (msg.sender, msg.sender, msg.sender); + } +} diff --git a/crates/integration/contracts/ConstReturnOverflowBug.sol b/crates/integration/contracts/ConstReturnOverflowBug.sol new file mode 100644 index 000000000..ade52e8fd --- /dev/null +++ b/crates/integration/contracts/ConstReturnOverflowBug.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +/// Soundness PoC: `to_llvm.rs::get_or_create_return_block` (and the +/// emit-revert sibling) call `context.xlen_type().const_int(const_offset, +/// false)` to build the constant offset/length for the +/// `emit_exit_unchecked` path. `const_int` takes a `u64` and truncates +/// silently to `xlen_type`'s width (`i32`), so any constant +/// offset/length above `u32::MAX` (but still within `u64::MAX` so +/// `try_extract_const_u64` returns `Some`) is wrapped mod `2^32` and the +/// resulting return/revert reads from / aliases the truncated heap +/// offset. EVM expands memory and OOGs. +contract ConstReturnOverflowBug { + function bug() external pure returns (uint256 r) { + assembly { + // Constant offset 2^56 — fits in u64, doesn't fit in u32. With + // the current codegen, the shared `return_shared_…` block + // truncates to i32 (=0) and reads/writes at heap[0..32] + // instead of trapping. + mstore(0x100000000000000, mload(0x100000000000000)) + return(0x100000000000000, 32) + // `r` is just to satisfy the signature; control flow exits + // via the inline-assembly `return` above. + r := 0 + } + } +} diff --git a/crates/integration/contracts/CopyOverlapBug.sol b/crates/integration/contracts/CopyOverlapBug.sol new file mode 100644 index 000000000..26d8dcdb0 --- /dev/null +++ b/crates/integration/contracts/CopyOverlapBug.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +/// Soundness PoC: `mem_opt::optimize_statements` `*Copy` handler +/// (CodeCopy / ExtCodeCopy / ReturnDataCopy / DataCopy / +/// CallDataCopy) only invalidates `memory_state[word(dest)]` when +/// `dest` is statically known. It ignores the *length* entirely, so +/// additional words inside `[dest, dest + length)` keep their stale +/// tracked entries. A subsequent `mload` at the exact tracked offset +/// is forwarded to the pre-overwrite value while EVM reads the +/// actually-overwritten bytes from the copy. +/// +/// The dynamic `length` parameter defeats solc's dead-store +/// elimination of the sentinel — solc can't prove that +/// `calldatacopy(0xc0, 0, length)` overwrites bytes `0xe0..0x100` +/// without knowing `length >= 0x40`. +contract CopyOverlapBug { + function bug(uint256 length) external pure returns (bytes32 r) { + assembly { + mstore(0xe0, 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) + calldatacopy(0xc0, 0, length) + r := mload(0xe0) + } + } +} diff --git a/crates/integration/contracts/DivisionArithmetics.sol b/crates/integration/contracts/DivisionArithmetics.sol index 2657abfc6..87d799c52 100644 --- a/crates/integration/contracts/DivisionArithmetics.sol +++ b/crates/integration/contracts/DivisionArithmetics.sol @@ -26,4 +26,20 @@ contract DivisionArithmetics { r := smod(n, d) } } + + /// Regression / soundness PoC: newyork simplifier folds `div(x, x) → 1` + /// and `sdiv(x, x) → 1` for any runtime value `x`, but EVM defines + /// division by zero to return 0, so `div(0, 0) = 0`. The fold is + /// unsound when `x == 0`. + /// + /// `mod(x, x) → 0` is sound because EVM also returns 0 for mod by zero. + function divSelf(uint x) external pure returns (uint r) { + assembly { r := div(x, x) } + } + function sdivSelf(int x) external pure returns (int r) { + assembly { r := sdiv(x, x) } + } + function modSelf(uint x) external pure returns (uint r) { + assembly { r := mod(x, x) } + } } diff --git a/crates/integration/contracts/Factorial.sol b/crates/integration/contracts/Factorial.sol new file mode 100644 index 000000000..f3750db9a --- /dev/null +++ b/crates/integration/contracts/Factorial.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8; + +// Regression test: factorial with uint8 parameter and uint64 result. +// Bug: newyork pipeline doesn't revert for out-of-range uint8 parameter, +// causing the function to return 1 (factorial of truncated 0) instead of +// reverting. + +/* runner.json +{ + "differential": true, + "actions": [ + { + "Instantiate": { + "code": { "Solidity": { "contract": "Factorial", "solc_optimizer": false } } + } + }, + { + "Call": { + "dest": { "Instantiated": 0 }, + "data": "ebbee3910000000000000000000000000000000000000000000000000000000000000005" + } + }, + { + "Call": { + "dest": { "Instantiated": 0 }, + "data": "ebbee3910000000000000000000000000000000000000000000000000000000100000000" + } + } + ] +} +*/ + +contract Factorial { + function main(uint8 n) public pure returns (uint64) { + uint64 fact = 1; + for (uint8 i = 1; i <= n; i++) { + fact *= i; + } + return fact; + } +} diff --git a/crates/integration/contracts/FmpCrossObjectBug.sol b/crates/integration/contracts/FmpCrossObjectBug.sol new file mode 100644 index 000000000..68c03be94 --- /dev/null +++ b/crates/integration/contracts/FmpCrossObjectBug.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +contract FmpCrossObjectBug { + // Recursive so solc can't inline; the function survives to + // newyork IR as `fun_rec` with parameter ValueIds starting at 0, + // colliding with the deploy (parent) object's `v0 := 0x80`. + function rec(uint256 value, uint256 depth) internal view returns (uint256 r) { + if (depth == 0) { + assembly { + mstore(0x40, value) + // Force the same byte-swap-mode path as FmpRangeProofBug + // so the range proof is the only optimization controlling + // the loaded value. + let _success := staticcall(gas(), origin(), 0, 0x80, 0, 0) + r := mload(0x40) + } + return r; + } + return rec(value, depth - 1); + } + + fallback() external { + uint256 value; + uint256 depth; + assembly { + value := calldataload(0) + depth := calldataload(0x20) + } + uint256 result = rec(value, depth); + assembly { + mstore(0x100, result) + return(0x100, 32) + } + } +} diff --git a/crates/integration/contracts/FmpDynRevertBug.sol b/crates/integration/contracts/FmpDynRevertBug.sol new file mode 100644 index 000000000..c1eae48de --- /dev/null +++ b/crates/integration/contracts/FmpDynRevertBug.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +/// Soundness PoC: same shape as `FmpRevertBug` but with *dynamic* +/// offset and length on the revert. The original `mark_escaping_range` +/// only sets `has_dynamic_escapes` for fully-dynamic escapes +/// (`(None, _)` arm) — it does not lower `min_dynamic_escape_start`, +/// so `fmp_native_safe()` doesn't reject and `mstore(0x40, …)` still +/// encodes as a 4-byte i32 LE native store. With the caller passing +/// `offset = 0` and `length = 96`, the revert covers the FMP slot +/// and the BE/LE encoding mismatch is observed. +contract FmpDynRevertBug { + fallback() external { + uint256 offset; + uint256 length; + assembly { + mstore(0x40, 0xdeadbeef) + offset := calldataload(0) + length := calldataload(32) + revert(offset, length) + } + } +} diff --git a/crates/integration/contracts/FmpDynStoreBug.sol b/crates/integration/contracts/FmpDynStoreBug.sol new file mode 100644 index 000000000..a449defbd --- /dev/null +++ b/crates/integration/contracts/FmpDynStoreBug.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +/// Soundness PoC: `mem_opt::FmpPropagation::propagate_statements` +/// tracks the known FMP value across statements. Its MStore handler +/// detects FMP writes by `region == FreePointerSlot || +/// resolved_offset == Some(0x40)`. For an mstore with a *dynamic* +/// offset whose runtime value happens to be 0x40 (but the simplifier +/// can't see that — e.g. `calldataload(...)`), neither condition +/// fires: the simplifier leaves `region == Unknown` because the +/// offset isn't a literal, and `resolve_offset` returns None because +/// the value isn't tracked in the local constants map. The +/// `fmp_value` stays stale. +/// +/// A subsequent `mload(0x40)` IS recognized as an FMP load (because +/// 0x40 is a literal). FmpPropagation folds it to the stale literal +/// `fmp_value` at IR level — diverging from EVM which reads the +/// overwritten memory. +/// +/// Both values (`0x100`, `0x200`) fit in the heap-size range so the +/// FMP-load range proof (`to_llvm.rs::apply_range_proof`) doesn't +/// affect this test. +contract FmpDynStoreBug { + fallback() external { + uint256 offset; + assembly { + // Set FMP via a recognized FMP-slot mstore. + mstore(0x40, 0x100) + // Caller passes 0x40 as calldata so offset = 0x40 at + // runtime, but the simplifier sees an opaque calldataload. + offset := calldataload(0) + // Dynamic-offset mstore. FmpPropagation can't tell this + // hits 0x40, so it doesn't invalidate the known fmp_value. + mstore(offset, 0x200) + let v := mload(0x40) + mstore(0x100, v) + return(0x100, 32) + } + } +} diff --git a/crates/integration/contracts/FmpNativeStoreBug.sol b/crates/integration/contracts/FmpNativeStoreBug.sol new file mode 100644 index 000000000..175eee6d9 --- /dev/null +++ b/crates/integration/contracts/FmpNativeStoreBug.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +contract FmpNativeStoreBug { + // Recursive — solc can't inline. + function loop(uint depth) internal pure returns (uint) { + if (depth == 0) return 0; + return loop(depth - 1) + depth; + } + + fallback() external { + uint256 v; + uint256 depth; + assembly { + v := calldataload(0) + depth := calldataload(0x20) + mstore(0x40, v) + } + // Recursive call: mem_opt clears memory_state, no escape so + // fmp_word_escapes stays false, fmp_native_safe stays true. + uint256 unused = loop(depth); + uint256 r; + assembly { + r := mload(0x40) + // use unused so solc doesn't DCE the call + r := add(r, mul(unused, 0)) + mstore(0x100, r) + return(0x100, 32) + } + } +} diff --git a/crates/integration/contracts/FmpRangeProofBug.sol b/crates/integration/contracts/FmpRangeProofBug.sol new file mode 100644 index 000000000..9b815fce2 --- /dev/null +++ b/crates/integration/contracts/FmpRangeProofBug.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +contract FmpRangeProofBug { + fallback() external { + assembly { + let v := calldataload(0) + mstore(0x40, v) + // Force fmp_word_escapes via a staticcall whose args cover + // memory[0..0x80] (so 0x40 is in the escape range). That + // disables FMP-native-mode storage and forces ByteSwap mode + // where the range-proof bug lives. + let _success := staticcall(gas(), origin(), 0, 0x80, 0, 0) + let r := mload(0x40) + mstore(0x100, r) + return(0x100, 32) + } + } +} diff --git a/crates/integration/contracts/FmpRevertBug.sol b/crates/integration/contracts/FmpRevertBug.sol new file mode 100644 index 000000000..33c5b4ebd --- /dev/null +++ b/crates/integration/contracts/FmpRevertBug.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +/// Soundness PoC: `heap_opt.rs::fmp_native_safe()` does NOT check +/// `tainted_regions` or `escaping_regions`. A `revert(0, 96)` that +/// covers the FMP slot (0x40) only calls `mark_escaping_range` +/// (line 241-243), which adds the FMP word to `escaping_regions` / +/// `tainted_regions` — but `fmp_native_safe()` only looks at four flags +/// (variable_accessed_offsets, has_dynamic_accesses, +/// has_return_covering_fmp, min_dynamic_escape_start) and returns +/// true when the static `revert(0, 96)` set none of them. +/// +/// `Statement::Return` correctly sets `has_return_covering_fmp` in this +/// case (line 252-254). `Statement::Revert` does not, so a contract +/// that reverts with data covering the FMP gets the FMP slot stored +/// as native i32 little-endian (4 bytes at heap[0x40..0x44]) instead +/// of the big-endian 32-byte word EVM produces. +/// +/// EVM revert data [0x40..0x60) = 32-byte BE encoding of FMP value. +/// PVM revert data [0x40..0x60) = 4 bytes LE i32, then 28 bytes +/// of uninitialized/zero heap memory. +contract FmpRevertBug { + fallback() external { + assembly { + // Set FMP to 0xdeadbeef. With newyork's InlineNative mode, + // this becomes a 4-byte i32 LE store at heap[0x40..0x44]. + mstore(0x40, 0xdeadbeef) + // Revert with 96 bytes covering [0x00..0x60). EVM caller + // sees 32-byte BE encoding of FMP at bytes [0x40..0x60). + // PVM caller sees the 4-byte LE encoding at [0x40..0x44) + // followed by 28 uninitialized bytes — different bytes. + revert(0, 96) + } + } +} diff --git a/crates/integration/contracts/InternalFn.sol b/crates/integration/contracts/InternalFn.sol new file mode 100644 index 000000000..7c37d2b3f --- /dev/null +++ b/crates/integration/contracts/InternalFn.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +// Regression test: contracts whose Yul IR generates internal helper functions +// (e.g. abi_encode_string, extract_byte_array_length) that survive the newyork +// inliner require a function scope in the LLVM context during code generation. +// Without it, declaring frontend functions in generate_object triggers an ICE: +// "function scope must be pushed before declaring frontend functions". + +/* runner.json +{ + "differential": false, + "actions": [ + { + "Instantiate": {} + }, + { + "Call": { + "dest": { "Instantiated": 0 }, + "data": "e942b51600000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000568656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000" + } + }, + { + "VerifyCall": { + "success": true + } + }, + { + "Call": { + "dest": { "Instantiated": 0 }, + "data": "6d4ce63c" + } + }, + { + "VerifyCall": { + "success": true, + "output": "00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000568656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000" + } + } + ] +} +*/ + +contract InternalFn { + string public a; + string public b; + + function set(string calldata _a, string calldata _b) external { + a = _a; + b = _b; + } + + function get() external view returns (string memory, string memory) { + return (a, b); + } +} diff --git a/crates/integration/contracts/KeccakFuseBug.sol b/crates/integration/contracts/KeccakFuseBug.sol new file mode 100644 index 000000000..948432244 --- /dev/null +++ b/crates/integration/contracts/KeccakFuseBug.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +contract KeccakFuseBug { + address public target; + + constructor() { + target = address(this); + } + + function probe(uint256[8] calldata seeds) + external view returns (uint256 r, bytes32 sink_out) + { + bytes32 sink; + uint256 s0 = seeds[0]; uint256 s1 = seeds[1]; uint256 s2 = seeds[2]; + uint256 s3 = seeds[3]; uint256 s4 = seeds[4]; uint256 s5 = seeds[5]; + uint256 s6 = seeds[6]; uint256 s7 = seeds[7]; + assembly { + mstore(0, s0) sink := xor(sink, keccak256(0, 32)) + mstore(0, s1) sink := xor(sink, keccak256(0, 32)) + mstore(0, s2) sink := xor(sink, keccak256(0, 32)) + mstore(0, s3) sink := xor(sink, keccak256(0, 32)) + mstore(0, s4) sink := xor(sink, keccak256(0, 32)) + mstore(0, s5) sink := xor(sink, keccak256(0, 32)) + mstore(0, s6) sink := xor(sink, keccak256(0, 32)) + mstore(0, s7) sink := xor(sink, keccak256(0, 32)) + } + (bool ok,) = target.staticcall(""); + ok; + assembly { + r := mload(0) + } + sink_out = sink; + } +} diff --git a/crates/integration/contracts/MSize.sol b/crates/integration/contracts/MSize.sol index 5fb241597..cfe34226c 100644 --- a/crates/integration/contracts/MSize.sol +++ b/crates/integration/contracts/MSize.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8; /* runner.json { - "differential": true, + "differential": false, "actions": [ { "Instantiate": { @@ -24,6 +24,11 @@ pragma solidity ^0.8; "data": "f016832c" } }, + { + "VerifyCall": { + "success": true + } + }, { "Call": { "dest": { @@ -31,6 +36,11 @@ pragma solidity ^0.8; }, "data": "f4a63aa5" } + }, + { + "VerifyCall": { + "success": true + } } ] } diff --git a/crates/integration/contracts/PanicCodeBug.sol b/crates/integration/contracts/PanicCodeBug.sol new file mode 100644 index 000000000..0538429c3 --- /dev/null +++ b/crates/integration/contracts/PanicCodeBug.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +/// Soundness PoC: the panic-pattern outliner in +/// `simplify.rs::find_panic_pattern_backwards` extracts the panic code +/// from `mstore(4, code)` via `code_val.to_u64_digits().first()` and a +/// `<= 0xFF` check. That returns the LEAST-significant u64 digit, so any +/// 256-bit `code` value whose low byte is in `[0, 0xFF]` is mis-classified +/// as a small canonical Solidity panic code regardless of its higher bits. +/// +/// Codegen for `Statement::PanicRevert { code }` emits the canonical +/// 36-byte Solidity panic format (selector + zero-padded `code`), so the +/// high bits of the original mstored value are silently dropped from the +/// revert data observed by the caller. EVM emits the original bytes. +contract PanicCodeBug { + fallback() external { + assembly { + // canonical panic selector at offset 0 + mstore(0, 0x4e487b7100000000000000000000000000000000000000000000000000000000) + // "code" value 0x10_00000000_00000000_00000000_00000042 — its low + // byte (0x42) passes the simplifier's `<= 0xFF` check, but byte + // position 20 of the revert encoding holds the 0x10 nibble. + mstore(4, 0x10000000000000000000000000000042) + revert(0, 0x24) + } + } +} diff --git a/crates/integration/contracts/PanicInterveneBug.sol b/crates/integration/contracts/PanicInterveneBug.sol new file mode 100644 index 000000000..f5ee92266 --- /dev/null +++ b/crates/integration/contracts/PanicInterveneBug.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +/// Soundness PoC: `simplify.rs::find_panic_pattern_backwards` walks +/// backward from `revert(0, 0x24)` skipping every mstore whose offset +/// is not exactly 0 or 4, and the final `only_safe` gate only checks +/// that intermediate statements are `Let`/`MStore`/`Expression`. An +/// `mstore(p, …)` with `p ∈ (0, 4) ∪ (4, 0x24)` partially overwrites +/// the panic-encoded revert data EVM emits, but the simplifier still +/// matches the canonical panic shape and replaces the whole sequence +/// with `Statement::PanicRevert { code }` — dropping the corrupting +/// mstore from the revert data observed by the caller. +contract PanicInterveneBug { + fallback() external { + assembly { + // Canonical panic selector + code prelude. + mstore(0, 0x4e487b7100000000000000000000000000000000000000000000000000000000) + mstore(4, 0x01) + // Unaligned mstore overwriting bytes 7..38 — bytes 7..35 of + // this end up in the revert(0, 0x24) data on EVM. PVM emits + // canonical PanicRevert(0x01) instead, dropping these bytes. + mstore(7, 0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef) + revert(0, 0x24) + } + } +} diff --git a/crates/integration/contracts/ParamMload.sol b/crates/integration/contracts/ParamMload.sol new file mode 100644 index 000000000..7f84f01f8 --- /dev/null +++ b/crates/integration/contracts/ParamMload.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +/// Soundness PoC: function parameter used only as `mload` offset gets +/// silently narrowed from i256 to i64 by `narrow_function_params`. The +/// call-site bare truncate drops the upper 192 bits BEFORE the use-site +/// `safe_truncate_int_to_xlen` can observe them, so `mload(2^64)` aliases +/// to `mload(0)` and returns the zero-initialised scratch slot instead of +/// OOGing on memory expansion the way EVM does. +/// +/// `fetch` is intentionally recursive so the early newyork inliner refuses +/// to inline it, preserving the narrowable `mload(x)`-only parameter shape. +contract ParamMload { + function fetch(uint depth, uint x) internal pure returns (uint r) { + if (depth == 0) { + assembly { r := mload(x) } + return r; + } + return fetch(depth - 1, x); + } + + function tryFetch(uint x) external pure returns (uint) { + return fetch(1, x); + } +} diff --git a/crates/integration/contracts/SDivNarrowBug.sol b/crates/integration/contracts/SDivNarrowBug.sol new file mode 100644 index 000000000..834ccb220 --- /dev/null +++ b/crates/integration/contracts/SDivNarrowBug.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +contract SDivNarrowBug { + /// Forces LLVM IR of the form + /// sdiv i256 (and i256 %a, 0xff..ff_u64), (and i256 %b, 0xff..ff_u64) + /// + /// `provable_bit_width` accepts the AND-mask proof and lets revive's + /// `narrow_divrem_instructions` rewrite this to `sdiv i64 (trunc..), (trunc..)` + /// followed by `sext` back to i256. The truncated low-64 view of an i256 + /// whose bit 63 is set looks negative under i64, but the i256 value is + /// non-negative (high 192 bits are zero by the AND), so the narrowed + /// signed division returns the wrong sign. + function sdiv_masked(uint256 a, uint256 b) external pure returns (int256 q) { + assembly { + let am := and(a, 0xffffffffffffffff) + let bm := and(b, 0xffffffffffffffff) + q := sdiv(am, bm) + } + } +} diff --git a/crates/integration/contracts/SubTypeValidation.sol b/crates/integration/contracts/SubTypeValidation.sol new file mode 100644 index 000000000..415e872f3 --- /dev/null +++ b/crates/integration/contracts/SubTypeValidation.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8; + +// Regression test: ABI parameter validation for sub-256-bit types. +// Solidity 0.8+ reverts when a calldataload value exceeds the range of its +// declared type (e.g., passing 256 to a uint8 parameter). +// Bug: the newyork pipeline silently truncates instead of reverting. + +/* runner.json +{ + "differential": true, + "actions": [ + { + "Instantiate": { + "code": { "Solidity": { "contract": "SubTypeValidation", "solc_optimizer": false } } + } + }, + { + "Call": { + "dest": { "Instantiated": 0 }, + "data": "d552145b0000000000000000000000000000000000000000000000000000000100000000" + } + }, + { + "Call": { + "dest": { "Instantiated": 0 }, + "data": "7440c86b0000000000000000000000000000000000000000000000010000000000000000" + } + }, + { + "Call": { + "dest": { "Instantiated": 0 }, + "data": "0850cee20000000000000000000000000000000100000000000000000000000000000000" + } + }, + { + "Call": { + "dest": { "Instantiated": 0 }, + "data": "d552145b0000000000000000000000000000000000000000000000000000000000000005" + } + }, + { + "Call": { + "dest": { "Instantiated": 0 }, + "data": "7440c86b0000000000000000000000000000000000000000000000000000000000000005" + } + }, + { + "Call": { + "dest": { "Instantiated": 0 }, + "data": "0850cee20000000000000000000000000000000000000000000000000000000000000005" + } + } + ] +} +*/ + +contract SubTypeValidation { + // Should revert when called with value > 0xFF + function narrow_uint8(uint8 x) public pure returns (uint8) { + return x; + } + + // Should revert when called with value > 0xFFFFFFFFFFFFFFFF + function narrow_uint64(uint64 x) public pure returns (uint64) { + return x; + } + + // Should revert when called with value > 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + function narrow_uint128(uint128 x) public pure returns (uint128) { + return x; + } +} diff --git a/crates/integration/contracts/SubUnderflowZext.sol b/crates/integration/contracts/SubUnderflowZext.sol new file mode 100644 index 000000000..175a894a1 --- /dev/null +++ b/crates/integration/contracts/SubUnderflowZext.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8; + +// Regression test: sub-underflow result widened to uint256 must preserve EVM +// modular semantics. +// +// Bug (crates/newyork/src/to_llvm.rs ~5977-5999): when `BinaryOperation::Sub` +// is codegen'd with both operands LLVM-narrowed to <= 64 bits (via +// `try_narrow_let_binding` Strategy 1 — structural proof from `and value, mask`) +// and the consumer's demand for the let binding holding the sub result is None +// (here: the result is mstored as a uint256), codegen takes the i128 fast-path: +// sub at i128 of (0, 1) → 2^128 - 1 (high bit set) +// Later widening via ensure_word_type → build_int_z_extend produces +// 0x...0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF instead of 2^256 - 1. +// +// Inline assembly is used so the masks land as IR constants (Solidity's +// non-asm path wraps integer literals through a `convert_rational_*` function, +// which defeats the structural narrowness proof). + +/* runner.json +{ + "differential": true, + "actions": [ + { + "Instantiate": { + "code": { "Solidity": { "contract": "SubUnderflowZext", "solc_optimizer": false } } + } + }, + { + "Call": { + "dest": { "Instantiated": 0 }, + "data": "0aa7a67700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + } + } + ] +} +*/ + +contract SubUnderflowZext { + function sub_underflow(uint256 a, uint256 b) external pure returns (uint256 r) { + assembly { + let x := and(a, 0xff) + let y := and(b, 0xff) + r := sub(x, y) + } + } +} diff --git a/crates/integration/contracts/Uint128Arithmetic.sol b/crates/integration/contracts/Uint128Arithmetic.sol new file mode 100644 index 000000000..81bec77af --- /dev/null +++ b/crates/integration/contracts/Uint128Arithmetic.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8; + +// Regression test: arithmetic with uint128 types. +// Bug: newyork pipeline produces wrong results for uint128 arithmetic with +// values that trigger overflow checking in Solidity 0.8+. + +/* runner.json +{ + "differential": true, + "actions": [ + { + "Instantiate": { + "code": { "Solidity": { "contract": "Uint128Arithmetic", "solc_optimizer": false } } + } + }, + { + "Call": { + "dest": { "Instantiated": 0 }, + "data": "ba517410000000000000000000000000000000000000000000000000000000000000002100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000100000000000000000000000000000000" + } + }, + { + "Call": { + "dest": { "Instantiated": 0 }, + "data": "ba51741000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001f" + } + } + ] +} +*/ + +contract Uint128Arithmetic { + uint128 constant EPS = 1E10; + uint128 constant PRECISION = 100; + uint128 constant MAX_U128_SQRT = 18446744073709551615; + + function entry(uint128 a, uint128 mb, uint128 c) public pure returns (bool, uint128, uint128) { + (bool p, uint128 x1, uint128 x2) = main(a, mb, c); + x1 *= PRECISION; + x1 /= EPS; + x2 *= PRECISION; + x2 /= EPS; + return (p, x1, x2); + } + + function sqrt(uint128 n) private pure returns (uint128) { + uint128 l = 0; + uint128 r = MAX_U128_SQRT; + while (l < r) { + uint128 m = (l + r + 1) / 2; + if (m * m <= n) { + l = m; + } else { + r = m - 1; + } + } + if (n - l * l < (l + 1) * (l + 1) - n) { + return l; + } else { + return l + 1; + } + } + + function main(uint128 a, uint128 mb, uint128 c) private pure returns (bool, uint128, uint128) { + if (mb * mb < 4 * a * c) { + return (false, 0, 0); + } + uint128 d = (mb * mb - 4 * a * c) * EPS * EPS; + uint128 sd = sqrt(d); + uint128 x1 = (mb * EPS + sd) / 2 / a; + uint128 x2 = (mb * EPS - sd) / 2 / a; + return (true, x1, x2); + } +} diff --git a/crates/integration/contracts/UnalignedMStore8Bug.sol b/crates/integration/contracts/UnalignedMStore8Bug.sol new file mode 100644 index 000000000..472f55abe --- /dev/null +++ b/crates/integration/contracts/UnalignedMStore8Bug.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +/// Soundness PoC: `mem_opt::optimize_statements` MStore8 handler only +/// invalidates `memory_state[word_offset(offset)]`. An unaligned +/// `mstore(0x70, AA…)` leaves a tracked entry at word 0x60 with +/// `tracked.offset = 0x70`, whose 32-byte write range covers byte +/// 0x80. A later `mstore8(0x80, 0xCC)` overwrites that byte but only +/// removes `memory_state[0x80]`, not the overlapping entry at +/// `memory_state[0x60]`. A subsequent `mload(0x70)` matches the +/// stale tracked entry by exact-offset comparison and is forwarded +/// to the pre-overwrite value, dropping the single-byte overwrite. +/// EVM observes byte 0x80 = `0xCC` in the actual memory read. +contract UnalignedMStore8Bug { + function bug() external pure returns (bytes32 r) { + assembly { + mstore(0x70, 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) + mstore8(0x80, 0xcc) + r := mload(0x70) + } + } +} diff --git a/crates/integration/contracts/UnalignedMStoreBug.sol b/crates/integration/contracts/UnalignedMStoreBug.sol new file mode 100644 index 000000000..192a8d894 --- /dev/null +++ b/crates/integration/contracts/UnalignedMStoreBug.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +/// Soundness PoC: `mem_opt.rs` only updates `memory_state[word_offset]` when +/// recording an mstore, where `word_offset = static_offset / 32 * 32`. An +/// *unaligned* `mstore(0x70, v)` writes 32 bytes from byte 0x70 to 0x90, so +/// it overwrites the lower half of the word starting at 0x80. mem_opt only +/// touches `memory_state[0x60]` and leaves `memory_state[0x80]` intact. +/// +/// A subsequent `mload(0x80)` finds the still-cached tracked entry at 0x80 +/// (offset == 0x80, no aliasing check across overlap with 0x70) and is +/// forwarded to the *pre-overwrite* stored value. EVM reads the actual +/// memory which contains the lower half of the unaligned store plus the +/// untouched upper half of the original. +contract UnalignedMStoreBug { + function bug() external pure returns (bytes32 r) { + assembly { + // 32 byte sentinel at the aligned word 0x80. + mstore(0x80, 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) + // Unaligned write: 16 bytes of 0xbb at 0x70..0x80 and 16 bytes of + // 0xcc at 0x80..0x90 (overwriting the lower half of the sentinel). + mstore(0x70, 0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccc) + // mem_opt forwards the stale sentinel, missing the partial overwrite. + r := mload(0x80) + } + } +} diff --git a/crates/integration/src/cases.rs b/crates/integration/src/cases.rs index 93bd1dd01..0bf1e3f64 100644 --- a/crates/integration/src/cases.rs +++ b/crates/integration/src/cases.rs @@ -179,12 +179,222 @@ sol!( function mod(uint n, uint d) public pure returns (uint r); function smod(int n, int d) public pure returns (int r); + + function divSelf(uint256 x) external pure returns (uint256 r); + function sdivSelf(int256 x) external pure returns (int256 r); + function modSelf(uint256 x) external pure returns (uint256 r); } ); case!("DivisionArithmetics.sol", DivisionArithmetics, divCall, division_arithmetics_div, n: U256, d: U256); case!("DivisionArithmetics.sol", DivisionArithmetics, sdivCall, division_arithmetics_sdiv, n: I256, d: I256); case!("DivisionArithmetics.sol", DivisionArithmetics, modCall, division_arithmetics_mod, n: U256, d: U256); case!("DivisionArithmetics.sol", DivisionArithmetics, smodCall, division_arithmetics_smod, n: I256, d: I256); +case!("DivisionArithmetics.sol", DivisionArithmetics, divSelfCall, division_arithmetics_div_self, x: U256); +case!("DivisionArithmetics.sol", DivisionArithmetics, sdivSelfCall, division_arithmetics_sdiv_self, x: I256); +case!("DivisionArithmetics.sol", DivisionArithmetics, modSelfCall, division_arithmetics_mod_self, x: U256); + +sol!( + contract SDivNarrowBug { + function sdiv_masked(uint256 a, uint256 b) external pure returns (int256 q); + } +); +case!("SDivNarrowBug.sol", SDivNarrowBug, sdiv_maskedCall, sdiv_narrow_bug_masked, a: U256, b: U256); + +sol!( + contract KeccakFuseBug { + function probe(uint256[8] calldata seeds) external view returns (uint256 r, bytes32 sink_out); + } +); +case!( + "KeccakFuseBug.sol", + KeccakFuseBug, + probeCall, + keccak_fuse_bug_probe, + seeds: [U256; 8] +); + +sol!( + contract ParamMload { + function tryFetch(uint256 x) external pure returns (uint256); + } +); +case!("ParamMload.sol", ParamMload, tryFetchCall, param_mload_try_fetch, x: U256); + +// `PanicCodeBug` has only a `fallback()` — invoked by sending raw +// calldata that doesn't match any function selector. Empty calldata +// suffices. +case!( + "PanicCodeBug.sol", + "PanicCodeBug", + vec![], + panic_code_bug_trigger +); + +// `FmpDynStoreBug` is invoked via empty fallback, passing 0x40 as the +// only calldata word so the inline-asm `calldataload(0)` resolves to +// 0x40 at runtime but stays opaque to the simplifier. +case!( + "FmpDynStoreBug.sol", + "FmpDynStoreBug", + { + let mut bytes = vec![0u8; 32]; + bytes[31] = 0x40; + bytes + }, + fmp_dyn_store_bug +); + +// `FmpRangeProofBug` reads the 32-byte calldata as the value to put +// into the FMP slot. Use `0x100000007 = 2^32 + 7` (well beyond the +// 17-bit heap-size range) to make the range-proof truncation visible. +case!( + "FmpRangeProofBug.sol", + "FmpRangeProofBug", + { + let mut bytes = vec![0u8; 32]; + bytes[31] = 0x07; + bytes[27] = 0x01; + bytes + }, + fmp_range_proof_bug +); + +// `FmpNativeStoreBug` calldata: first word = FMP value `0x100000007`, +// second word = non-zero condition to force the if-branch. +case!( + "FmpNativeStoreBug.sol", + "FmpNativeStoreBug", + { + let mut bytes = vec![0u8; 64]; + bytes[31] = 0x07; + bytes[27] = 0x01; + bytes[63] = 0x01; + bytes + }, + fmp_native_store_bug +); + +// `FmpCrossObjectBug` calldata: first word = FMP value `0x100000007`, +// second word = recursion depth (0 to hit the inner inline-asm branch). +case!( + "FmpCrossObjectBug.sol", + "FmpCrossObjectBug", + { + let mut bytes = vec![0u8; 64]; + bytes[31] = 0x07; + bytes[27] = 0x01; + bytes + }, + fmp_cross_object_bug +); + +// `FmpRevertBug` is invoked via empty calldata into its `fallback()`. +case!("FmpRevertBug.sol", "FmpRevertBug", vec![], fmp_revert_bug); + +// `FmpDynRevertBug` reads `offset` and `length` from calldata: pass +// 64 bytes encoding `offset=0`, `length=96` so the dynamic revert +// covers the FMP slot. +case!( + "FmpDynRevertBug.sol", + "FmpDynRevertBug", + { + let mut bytes = vec![0u8; 64]; + bytes[63] = 96; + bytes + }, + fmp_dyn_revert_bug +); + +sol!( + contract UnalignedMStoreBug { + function bug() external pure returns (bytes32); + } +); +case!( + "UnalignedMStoreBug.sol", + UnalignedMStoreBug, + bugCall, + unaligned_mstore_bug, +); + +sol!( + contract ConstReturnOverflowBug { + function bug() external pure returns (uint256); + } +); +case!( + "ConstReturnOverflowBug.sol", + ConstReturnOverflowBug, + bugCall, + const_return_overflow_bug, +); + +// `PanicInterveneBug` has only a `fallback()` — invoked by sending +// raw calldata that doesn't match any selector. Empty calldata works. +case!( + "PanicInterveneBug.sol", + "PanicInterveneBug", + vec![], + panic_intervene_bug +); + +sol!( + contract UnalignedMStore8Bug { + function bug() external pure returns (bytes32); + } +); +case!( + "UnalignedMStore8Bug.sol", + UnalignedMStore8Bug, + bugCall, + unaligned_mstore8_bug, +); + +sol!( + contract CopyOverlapBug { + function bug(uint256 length) external pure returns (bytes32); + } +); +case!( + "CopyOverlapBug.sol", + CopyOverlapBug, + bugCall, + copy_overlap_bug, + length: U256 +); + +sol!( + contract CallerOriginAliasing { + function caller_then_origin() external view returns (address, address); + function origin_then_caller() external view returns (address, address); + function caller_address_origin() external view returns (address, address, address); + function repeated_caller() external view returns (address, address, address); + } +); +case!( + "CallerOriginAliasing.sol", + CallerOriginAliasing, + caller_then_originCall, + caller_origin_aliasing_caller_then_origin, +); +case!( + "CallerOriginAliasing.sol", + CallerOriginAliasing, + origin_then_callerCall, + caller_origin_aliasing_origin_then_caller, +); +case!( + "CallerOriginAliasing.sol", + CallerOriginAliasing, + caller_address_originCall, + caller_origin_aliasing_caller_address_origin, +); +case!( + "CallerOriginAliasing.sol", + CallerOriginAliasing, + repeated_callerCall, + caller_origin_aliasing_repeated_caller, +); sol!( contract DivConst { diff --git a/crates/integration/src/tests.rs b/crates/integration/src/tests.rs index 945042a48..d28446fb4 100644 --- a/crates/integration/src/tests.rs +++ b/crates/integration/src/tests.rs @@ -78,6 +78,23 @@ test_spec!( "StructDeleteStorage", "StructDeleteStorage.sol" ); +test_spec!(internal_fn, "InternalFn", "InternalFn.sol"); +test_spec!( + sub_type_validation, + "SubTypeValidation", + "SubTypeValidation.sol" +); +test_spec!(factorial, "Factorial", "Factorial.sol"); +test_spec!( + uint128_arithmetic, + "Uint128Arithmetic", + "Uint128Arithmetic.sol" +); +test_spec!( + sub_underflow_zext, + "SubUnderflowZext", + "SubUnderflowZext.sol" +); fn instantiate(path: &str, contract: &str) -> Vec { vec![Instantiate { @@ -307,6 +324,402 @@ fn signed_remainder() { run_differential(actions); } +/// Regression: `div(x, x)` (and `sdiv(x, x)`) must return 0 when `x == 0`. +/// +/// EVM defines `DIV` / `SDIV` to return 0 when the denominator is zero, so +/// `div(0, 0) == 0`. The newyork simplifier in `simplify.rs` previously +/// folded `div(x, x) → 1` and `sdiv(x, x) → 1` based on operand-identity +/// alone, which is only correct when `x != 0`. For `x == 0`, EVM returns 0 +/// but PVM returned 1 — a semantic divergence visible to any contract that +/// passes 0 (intentionally or via uninitialised state) to such an +/// expression in inline assembly. +/// +/// `mod(x, x)` is sound (mod by zero in EVM is also 0). +#[test] +fn div_self_zero_returns_zero() { + let mut actions = instantiate("contracts/DivisionArithmetics.sol", "DivisionArithmetics"); + for x in [U256::ZERO, U256::from(1u64), U256::from(5u64), U256::MAX] { + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::division_arithmetics_div_self(x).calldata, + }); + } + run_differential(actions); +} + +#[test] +fn sdiv_self_zero_returns_zero() { + let mut actions = instantiate("contracts/DivisionArithmetics.sol", "DivisionArithmetics"); + for x in [ + I256::ZERO, + I256::try_from(1).unwrap(), + I256::MINUS_ONE, + I256::MIN, + I256::MAX, + ] { + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::division_arithmetics_sdiv_self(x).calldata, + }); + } + run_differential(actions); +} + +#[test] +fn mod_self_zero_returns_zero() { + let mut actions = instantiate("contracts/DivisionArithmetics.sol", "DivisionArithmetics"); + for x in [U256::ZERO, U256::from(7u64), U256::MAX] { + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::division_arithmetics_mod_self(x).calldata, + }); + } + run_differential(actions); +} + +/// Regression: `narrow_function_params` narrows a function parameter that is +/// only used as a `MemoryOffset` (e.g. as `mload` offset) from `i256` to +/// `i64`. The call site emits a bare `trunc i256 → i64`, so an i256 +/// argument with bits above 64 (e.g. `2^64`) silently aliases to `0`. The +/// use-site `safe_truncate_int_to_xlen` (i64 → i32) only sees the already- +/// truncated value and can't observe the discarded high bits. +/// +/// Commit ccca38df fixed the same class of issue for `try_narrow_let_binding` +/// (let-binding demand narrowing) but parameter narrowing still uses +/// `constraint.max_width` directly, which `narrow_from_use(offset.id, I64)` +/// pulls down to I64. Differential mode catches the mismatch: EVM OOGs on +/// memory expansion, PVM returns 0 from the zero-initialised scratch slot. +#[test] +fn param_mload_huge_offset_traps() { + for shift in [64u32, 128, 200] { + let huge = U256::from(1u64) << shift; + let mut actions = instantiate("contracts/ParamMload.sol", "ParamMload"); + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::param_mload_try_fetch(huge).calldata, + }); + Specs { + actions, + differential: true, + ..Default::default() + } + .run(); + } +} + +/// Regression: the panic-pattern outliner in `simplify.rs` extracts a +/// panic code via `to_u64_digits().first()` (lowest u64 digit), then +/// gates on `<= 0xFF`. A 256-bit code value with non-zero high bits but a +/// low byte `<= 0xFF` passes the check; codegen for the synthesised +/// `Statement::PanicRevert { code }` emits Solidity's canonical 36-byte +/// panic encoding with `code` zero-padded — the original high bits of the +/// mstored value are silently dropped from the revert data. EVM emits the +/// original bytes. +#[test] +fn panic_code_high_bits_preserved() { + let mut actions = instantiate("contracts/PanicCodeBug.sol", "PanicCodeBug"); + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::panic_code_bug_trigger().calldata, + }); + run_differential(actions); +} + +/// Regression: `mem_opt::optimize_statements` records each `mstore` at the +/// *aligned* word offset (`static_offset / 32 * 32`) but doesn't invalidate +/// adjacent words that an *unaligned* store partially overwrites. An +/// `mstore(0x70, v)` writes bytes [0x70, 0x90) — the lower half of the +/// word at 0x80 — yet the entry tracked at `memory_state[0x80]` (from a +/// previous aligned `mstore(0x80, …)`) survives untouched. A later +/// `mload(0x80)` matches that stale entry by exact-offset comparison and +/// is forwarded to the pre-overwrite value, dropping the bytes from the +/// unaligned write. EVM reads the actual mixed memory. +#[test] +fn unaligned_mstore_forwarding() { + let mut actions = instantiate("contracts/UnalignedMStoreBug.sol", "UnalignedMStoreBug"); + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::unaligned_mstore_bug().calldata, + }); + run_differential(actions); +} + +/// Regression: `to_llvm.rs::get_or_create_return_block` (and revert / Stop +/// siblings) build the constant offset/length via +/// `context.xlen_type().const_int(const_offset, false)`, which silently +/// truncates a `u64` to `i32`. A constant offset like `0x100000000000000` +/// (`2^56`) fits in `u64` so `try_extract_const_u64` returns `Some`, the +/// shared block path is taken, and the truncated offset (`0`) is fed to +/// `emit_exit_unchecked` — the return reads from `heap[0]` instead of +/// trapping on the out-of-bounds offset. EVM OOGs on memory expansion. +#[test] +fn const_return_offset_overflow_traps() { + let mut actions = instantiate( + "contracts/ConstReturnOverflowBug.sol", + "ConstReturnOverflowBug", + ); + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::const_return_overflow_bug().calldata, + }); + run_differential(actions); +} + +/// Regression: `simplify.rs::find_panic_pattern_backwards` walks the +/// statement list backwards from `revert(0, 0x24)` and accepts an +/// `mstore` at offsets ≠ 0 / 4 as "safe filler" — it skips it in the +/// backward search and the `only_safe` gate only restricts statement +/// kinds, not memory regions touched. An intermediate `mstore(p, v)` +/// with `p` inside the panic encoding region (e.g. `p = 7`) partially +/// overwrites the EVM revert bytes EVM caller sees, but the +/// simplifier still matches the canonical panic shape and replaces +/// the whole sequence with `Statement::PanicRevert { code }` — +/// codegen then emits Solidity's canonical panic encoding without +/// the corrupting mstore. The caller observes different revert data +/// on PVM vs EVM. +#[test] +fn panic_pattern_intervening_mstore_preserved() { + let mut actions = instantiate("contracts/PanicInterveneBug.sol", "PanicInterveneBug"); + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::panic_intervene_bug().calldata, + }); + run_differential(actions); +} + +/// Regression: `heap_opt::fmp_native_safe()` does not check +/// `tainted_regions` or `escaping_regions`. A static `revert(0, 96)` +/// marks the FMP word (0x40) as escaping via `mark_escaping_range`, +/// but `Statement::Revert` (unlike `Statement::Return`) doesn't set +/// `has_return_covering_fmp`. The four flags `fmp_native_safe()` reads +/// stay false, so it returns true and `mstore(0x40, …)` is encoded as +/// a 4-byte i32 LE native store. The revert data bytes [0x40..0x60) +/// then carry the LE-encoded i32 followed by 28 stale bytes instead +/// of the BE 32-byte word EVM emits. +#[test] +fn fmp_revert_native_mode_corrupts_revert_data() { + let mut actions = instantiate("contracts/FmpRevertBug.sol", "FmpRevertBug"); + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::fmp_revert_bug().calldata, + }); + run_differential(actions); +} + +/// Bug #15a regression test: `to_llvm.rs::Expression::MLoad` applies +/// a range-proof truncation on any FMP-slot mload, assuming +/// `FMP < heap_size`. Sound for Solidity-convention FMP updates via +/// sbrk-style allocations but unsound for inline asm that puts an +/// arbitrary i256 at memory[0x40..0x60]. Fixed by gating on +/// `!heap_opt.fmp_could_be_unbounded()`, a precise static detector +/// that only trips when an `mstore(0x40, _)` writes from a source +/// `is_trusted_fmp_source` cannot prove sbrk-bounded. See +/// `project_round3_fmp_native_bugs.md` Bug #15a. +#[test] +fn fmp_load_range_proof_corrupts_non_bounded_value() { + let mut actions = instantiate("contracts/FmpRangeProofBug.sol", "FmpRangeProofBug"); + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::fmp_range_proof_bug().calldata, + }); + run_differential(actions); +} + +/// Bug #15b regression test: when `fmp_native_safe()` returns true, +/// the InlineNative-mode MStore at `to_llvm.rs` previously truncated +/// any `mstore(0x40, _)` value to i32 unconditionally. Fixed by +/// gating the i32 truncation on `!heap_opt.fmp_could_be_unbounded()`, +/// the same precise static gate used for Bug #15a's range proof. See +/// `project_round3_fmp_native_bugs.md` Bug #15b. +#[test] +fn fmp_native_store_truncates_non_bounded_value() { + let mut actions = instantiate("contracts/FmpNativeStoreBug.sol", "FmpNativeStoreBug"); + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::fmp_native_store_bug().calldata, + }); + run_differential(actions); +} + +/// Cross-subobject ValueId collision regression test: `HeapAnalysis` +/// shares its `value_expressions` map across deploy and deployed +/// objects, but `from_yul.rs` constructs a fresh `SsaBuilder` per +/// subobject so ValueIds restart at 0 inside each subobject. Before +/// the fix, the deploy code's `Let v0 := 0x80` (trusted Literal) +/// poisoned `value_expressions[0]`; the deployed object's recursive +/// `fun_rec(v0, v1)` then reused id 0 for its first parameter, and +/// `is_trusted_fmp_source(0)` returned the parent's trusted entry — +/// silently disabling the `fmp_could_be_unbounded` flag for the +/// `mstore(0x40, param)` inside the function. Fixed by clearing +/// `value_expressions` alongside `offset_values` when recursing into +/// subobjects in `HeapAnalysis::analyze_object`. +#[test] +fn fmp_cross_object_value_id_collision_corrupts_fmp() { + let mut actions = instantiate("contracts/FmpCrossObjectBug.sol", "FmpCrossObjectBug"); + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::fmp_cross_object_bug().calldata, + }); + run_differential(actions); +} + +#[test] +fn fmp_propagation_misses_dynamic_offset_mstore() { + let mut actions = instantiate("contracts/FmpDynStoreBug.sol", "FmpDynStoreBug"); + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::fmp_dyn_store_bug().calldata, + }); + run_differential(actions); +} + +#[test] +fn keccak_fuse_preserves_scratch_observable_via_mload() { + let mut actions = instantiate("contracts/KeccakFuseBug.sol", "KeccakFuseBug"); + let seeds = [ + U256::from(0xaa01u64), + U256::from(0xaa02u64), + U256::from(0xaa03u64), + U256::from(0xaa04u64), + U256::from(0xaa05u64), + U256::from(0xaa06u64), + U256::from(0xaa07u64), + U256::from(0xaa08u64), + ]; + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::keccak_fuse_bug_probe(seeds).calldata, + }); + run_differential(actions); +} + +/// Regression: same FMP-native-mode mismatch as +/// `fmp_revert_native_mode_corrupts_revert_data`, but the revert +/// uses *dynamic* offset and length read from calldata. The +/// `(None, _)` arm of `mark_escaping_range` only flips +/// `has_dynamic_escapes`; without lowering `min_dynamic_escape_start` +/// the FMP-native guard misses this case too. Fixed by +/// `note_fmp_coverage` lowering `min_dynamic_escape_start` to 0 +/// for fully-dynamic escapes. +#[test] +fn fmp_dyn_revert_native_mode_corrupts_revert_data() { + let mut actions = instantiate("contracts/FmpDynRevertBug.sol", "FmpDynRevertBug"); + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::fmp_dyn_revert_bug().calldata, + }); + run_differential(actions); +} + +/// Regression: same shape as `unaligned_mstore_forwarding` (Bug #6), +/// but the second store is `mstore8` instead of `mstore`. mem_opt's +/// MStore8 handler removes only `memory_state[word(offset)]` and +/// doesn't invalidate the overlapping tracked entry from an earlier +/// *unaligned* `mstore` whose 32-byte write range covers the single +/// byte. A later `mload` matching the stale tracked offset gets +/// forwarded to the pre-overwrite value, dropping the byte overwrite. +#[test] +fn unaligned_mstore8_forwarding() { + let mut actions = instantiate("contracts/UnalignedMStore8Bug.sol", "UnalignedMStore8Bug"); + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::unaligned_mstore8_bug().calldata, + }); + run_differential(actions); +} + +/// Regression: `mem_opt::optimize_statements` `*Copy` handler +/// (CodeCopy / ExtCodeCopy / ReturnDataCopy / DataCopy / CallDataCopy) +/// removes only `memory_state[word(dest)]` when `dest` is statically +/// known. It ignores the copy's *length*, so additional words inside +/// `[dest, dest + length)` keep their stale tracked entries. A +/// subsequent `mload` matching the stale tracked offset is forwarded +/// to the pre-overwrite value while EVM reads the bytes that the copy +/// actually wrote. +/// +/// The dynamic `length` argument defeats solc's dead-store +/// elimination of the sentinel mstore — solc can't prove that +/// `calldatacopy(0xc0, 0, length)` overwrites the sentinel at +/// `mstore(0xe0, …)` without knowing `length >= 0x40`. +#[test] +fn copy_length_invalidates_tracked_overlap() { + use alloy_primitives::U256; + let mut actions = instantiate("contracts/CopyOverlapBug.sol", "CopyOverlapBug"); + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::copy_overlap_bug(U256::from(64u64)).calldata, + }); + run_differential(actions); +} + /// Build calldata for the both-const Yul fixtures. Each fixture reads the case /// index from `calldataload(0)` and a 32-byte "tag" from `calldataload(32)` /// that gets XORed into the returned result. A non-zero tag turns silent @@ -1237,6 +1650,145 @@ fn invalid_opcode_works() { assert_eq!(result.weight_consumed, GAS_LIMIT); } +/// Guard: `sdiv` of AND-masked i256 operands must agree with EVM. Today this +/// works only because LLVM gets there first — `__revive_signed_division` +/// holds the only `sdiv i256` we emit, and InstCombine rewrites it to +/// `udiv i256` (then to `udiv i64`) once it sees the AND-masks prove the +/// operands non-negative. The latent risk: revive's +/// `narrow_divrem_instructions` (crates/llvm-context/src/polkavm/context/mod.rs) +/// would, given a surviving `sdiv i256 (and a, M), (and b, M)`, rewrite it +/// to `sext (sdiv i64 (trunc..), (trunc..))`, which flips sign for any +/// operand whose bit (n-1) is set. If LLVM ever stops folding sdiv → udiv +/// before that pass, this differential test fails on `(high_bit, 1)` etc. +#[test] +fn sdiv_narrow_masked() { + let mut actions = instantiate("contracts/SDivNarrowBug.sol", "SDivNarrowBug"); + + let u64_max = U256::from(u64::MAX); + let one = U256::from(1u64); + let two = U256::from(2u64); + let high_bit = U256::from(1u64) << 63; + + for (a, b) in [ + (u64_max, one), + (high_bit, one), + (high_bit + one, one), + (u64_max, two), + ] { + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: Contract::sdiv_narrow_bug_masked(a, b).calldata, + }); + } + + run_differential(actions); +} + +/// Regression: `__revive_caller` must not share `@__address_spill_buffer` +/// with `tx.origin` / `address(this)`. The helper carries +/// `memory(inaccessiblemem: read)` so LLVM treats a `__revive_caller()` call +/// as having no `Other` (heap/global) effect. The previous body wrote the +/// caller into the shared spill buffer global — which `origin()` and +/// `build_address` also write — making the attribute a contract violation +/// from LLVM's point of view. No current Solidity emission pattern triggers +/// a miscompile, but any optimizer pass that hoisted a load of the spill +/// buffer past a `__revive_caller()` call would have corrupted the +/// surrounding `tx.origin` / `address(this)` result. Running the four +/// interleaved patterns through the differential harness asserts the +/// PVM-side values match EVM, guarding against future pipeline changes that +/// could expose the wrong attribute. +#[test] +fn caller_origin_aliasing() { + let mut actions = instantiate("contracts/CallerOriginAliasing.sol", "CallerOriginAliasing"); + + for calldata in [ + Contract::caller_origin_aliasing_caller_then_origin().calldata, + Contract::caller_origin_aliasing_origin_then_caller().calldata, + Contract::caller_origin_aliasing_caller_address_origin().calldata, + Contract::caller_origin_aliasing_repeated_caller().calldata, + ] { + actions.push(Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data: calldata, + }); + } + + run_differential(actions); +} + +/// Regression: `mload(huge_offset)` must trap, not silently return zero. +/// +/// With the newyork backend, the calldata-loaded `_offset` was demand-narrowed +/// to i64 because its only use is a memory-offset (max-width I64). The +/// narrowing was a bare i256→i64 truncate with no overflow check, so values +/// like 2^128 (high bit in the upper i128 half) and 2^255 (high bit in the +/// top word) silently aliased to 0 and `mload(0)` returned the zero-initialized +/// scratch slot successfully. EVM correctly OOGs on the memory expansion. +/// Differential mode catches the mismatch. +#[test] +fn mload_huge_offset_traps() { + for shift in [128u32, 255] { + let huge = U256::from(1u64) << shift; + let data = Contract::load_at(huge).calldata; + let mut actions = instantiate("contracts/MLoad.sol", "MLoad"); + actions.append(&mut vec![ + Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data, + }, + VerifyCall(VerifyCallExpectation { + success: false, + ..Default::default() + }), + ]); + + Specs { + actions, + differential: true, + ..Default::default() + } + .run(); + } +} + +/// Regression: `mload(0x40)` on a contract that only does inline-assembly +/// `mload(dynamic)` must return Solidity's free-memory pointer (0x80). +/// Fuzzer found divergence on offsets near 0x40 under newyork; suspected +/// heap-optimization native-mode / byteswap mismatch. +#[test] +fn mload_at_fmp_slot() { + for &offset in &[0x40u64, 0x21, 0x3f, 0x42] { + let data = Contract::load_at(Uint::from(offset)).calldata; + let mut actions = instantiate("contracts/MLoad.sol", "MLoad"); + actions.append(&mut vec![Call { + origin: TestAddress::Alice, + dest: TestAddress::Instantiated(0), + value: 0, + gas_limit: None, + storage_deposit_limit: None, + data, + }]); + Specs { + actions, + differential: true, + ..Default::default() + } + .run(); + } +} + /// Load from heap memory using an out of bounds offset and expect the /// contract to hit the `invalid` syscall to use all gas (like on EVM). /// diff --git a/crates/llvm-context/src/lib.rs b/crates/llvm-context/src/lib.rs index db83d44d2..0cf1ec8e6 100644 --- a/crates/llvm-context/src/lib.rs +++ b/crates/llvm-context/src/lib.rs @@ -14,6 +14,7 @@ pub use self::polkavm::build as polkavm_build; pub use self::polkavm::context::address_space::AddressSpace as PolkaVMAddressSpace; pub use self::polkavm::context::argument::Argument as PolkaVMArgument; pub use self::polkavm::context::attribute::Attribute as PolkaVMAttribute; +pub use self::polkavm::context::attribute::MemoryEffect as PolkaVMMemoryEffect; pub use self::polkavm::context::build::Build as PolkaVMBuild; pub use self::polkavm::context::code_type::CodeType as PolkaVMCodeType; pub use self::polkavm::context::debug_info::DebugInfo; @@ -27,7 +28,14 @@ pub use self::polkavm::context::function::runtime::arithmetics::SignedDivision a pub use self::polkavm::context::function::runtime::arithmetics::SignedRemainder as PolkaVMSignedRemainderFunction; pub use self::polkavm::context::function::runtime::deploy_code::DeployCode as PolkaVMDeployCodeFunction; pub use self::polkavm::context::function::runtime::entry::Entry as PolkaVMEntryFunction; +pub use self::polkavm::context::function::runtime::revive::CallDataLoad as PolkaVMCallDataLoadFunction; +pub use self::polkavm::context::function::runtime::revive::CallValue as PolkaVMCallValueFunction; +pub use self::polkavm::context::function::runtime::revive::CallValueNonzero as PolkaVMCallValueNonzeroFunction; +pub use self::polkavm::context::function::runtime::revive::Caller as PolkaVMCallerFunction; pub use self::polkavm::context::function::runtime::revive::Exit as PolkaVMExitFunction; +pub use self::polkavm::context::function::runtime::revive::Revert as PolkaVMRevertFunction; +pub use self::polkavm::context::function::runtime::revive::RevertEmpty as PolkaVMRevertEmptyFunction; +pub use self::polkavm::context::function::runtime::revive::RevertPanic as PolkaVMRevertPanicFunction; pub use self::polkavm::context::function::runtime::revive::WordToPointer as PolkaVMWordToPointerFunction; pub use self::polkavm::context::function::runtime::runtime_code::RuntimeCode as PolkaVMRuntimeCodeFunction; pub use self::polkavm::context::function::runtime::sbrk::Sbrk as PolkaVMSbrkFunction; @@ -37,8 +45,12 @@ pub use self::polkavm::context::function::runtime::FUNCTION_RUNTIME_CODE as Polk pub use self::polkavm::context::function::yul_data::YulData as PolkaVMFunctionYulData; pub use self::polkavm::context::function::Function as PolkaVMFunction; pub use self::polkavm::context::global::Global as PolkaVMGlobal; +pub use self::polkavm::context::pointer::heap::Keccak256OneWord as PolkaVMKeccak256OneWordFunction; +pub use self::polkavm::context::pointer::heap::Keccak256TwoWords as PolkaVMKeccak256TwoWordsFunction; pub use self::polkavm::context::pointer::heap::LoadWord as PolkaVMLoadHeapWordFunction; +pub use self::polkavm::context::pointer::heap::LoadWordNative as PolkaVMLoadHeapWordNativeFunction; pub use self::polkavm::context::pointer::heap::StoreWord as PolkaVMStoreHeapWordFunction; +pub use self::polkavm::context::pointer::heap::StoreWordNative as PolkaVMStoreHeapWordNativeFunction; pub use self::polkavm::context::pointer::storage::LoadTransientWord as PolkaVMLoadTransientStorageWordFunction; pub use self::polkavm::context::pointer::storage::LoadWord as PolkaVMLoadStorageWordFunction; pub use self::polkavm::context::pointer::storage::StoreTransientWord as PolkaVMStoreTransientStorageWordFunction; @@ -94,8 +106,22 @@ pub fn initialize_llvm(target: PolkaVMTarget, name: &str, llvm_arguments: &[Stri return; // Tests don't go through a recursive process }; + // Disable LICM promotion and machine LICM: on the PVM target (rv64e), + // LICM hoists i256 operations out of loops, increasing register pressure + // and causing excessive stack spills that outweigh the loop optimization. + let default_args = [ + "--disable-licm-promotion".to_string(), + "--disable-machine-licm".to_string(), + "--enable-machine-outliner".to_string(), + "--machine-outliner-reruns=2".to_string(), + "--disable-early-taildup=true".to_string(), + "--apply-ext-tsp-for-size=true".to_string(), + "--attributor-allow-deep-wrappers=true".to_string(), + "--hoist-common-insts=true".to_string(), + ]; let argv = [name.to_string()] .iter() + .chain(default_args.iter()) .chain(llvm_arguments) .map(|arg| CString::new(arg.as_bytes()).unwrap()) .collect::>(); diff --git a/crates/llvm-context/src/optimizer/mod.rs b/crates/llvm-context/src/optimizer/mod.rs index b02aaacce..95d9f7d0c 100644 --- a/crates/llvm-context/src/optimizer/mod.rs +++ b/crates/llvm-context/src/optimizer/mod.rs @@ -22,16 +22,39 @@ impl Optimizer { Self { settings } } - /// Runs the new pass manager. + /// Runs the new pass manager with a three-stage pipeline: + /// + /// 1. `default`: initial optimization at the configured size level. + /// 2. `ipsccp,deadargelim`: propagate inter-function constants through outlined helpers and + /// remove now-constant arguments. + /// 3. `default`: re-optimize with newly discovered constants. + /// + /// The second pass is hard-coded to `O1` for empirical reasons. An earlier rationale claimed + /// `O1` avoids aggressive LICM of i256, but that is circular: LICM promotion and machine LICM + /// are already disabled at the LLVM driver level via `--disable-licm-promotion` and + /// `--disable-machine-licm` in `initialize_llvm`, so neither preset can re-introduce them. + /// + /// The actual reason `O1` is retained is a differential-test regression: matching the second + /// pass to the configured level (running `default` after IPSCCP at default size + /// optimization) changes the post-link PVM blob for two contracts under solc M0 + /// + /// * `complex/defi/UniswapV2Router01/UniswapV2Pair` (Y M0 S+) + /// * `complex/solidity_by_example/applications/iterable_mapping` (Y M0 S- >=0.8.1) + /// + /// and the changed blobs reproducibly hit a "Code upload failed: Timeout when retrying + /// request" error on pallet-revive deployment (verified across two retester runs at each + /// commit). The exact pass that produces the regression has not been isolated; until it is, + /// keeping the second pass at `O1` is the safe choice. pub fn run( &self, target_machine: &TargetMachine, module: &inkwell::module::Module, ) -> Result<(), inkwell::support::LLVMString> { - target_machine.run_optimization_passes( - module, - format!("default", self.settings.middle_end_as_string()).as_str(), - ) + let optimization_level = self.settings.middle_end_as_string(); + let pass_pipeline = format!( + "mergefunc,default,mergefunc,ipsccp,deadargelim,attributor,default,mergefunc" + ); + target_machine.run_optimization_passes(module, &pass_pipeline) } /// Returns the optimizer settings reference. diff --git a/crates/llvm-context/src/polkavm/context/argument.rs b/crates/llvm-context/src/polkavm/context/argument.rs index 5f63254db..69145fed7 100644 --- a/crates/llvm-context/src/polkavm/context/argument.rs +++ b/crates/llvm-context/src/polkavm/context/argument.rs @@ -53,6 +53,11 @@ impl<'ctx> Argument<'ctx> { self } + /// Returns true if the argument holds an LLVM register value (not a pointer). + pub fn is_register(&self) -> bool { + matches!(&self.value, Value::Register(_)) + } + /// Returns the inner LLVM value. /// /// Panics if `self` is a pointer argument. diff --git a/crates/llvm-context/src/polkavm/context/attribute.rs b/crates/llvm-context/src/polkavm/context/attribute.rs index 6f9a472ed..4086dc216 100644 --- a/crates/llvm-context/src/polkavm/context/attribute.rs +++ b/crates/llvm-context/src/polkavm/context/attribute.rs @@ -121,6 +121,147 @@ pub enum Attribute { //LastConstantRangeListAttr = 101, } +/// Rust mirror of LLVM's `llvm::ModRefInfo`. +/// +/// Discriminants are the C++ enum values verbatim from +/// `llvm/include/llvm/Support/ModRef.h` lines 28-38 of the LLVM 21.1.8 +/// source tree (`LLVM_SYS_211_PREFIX`): +/// +/// ```text +/// enum class ModRefInfo : uint8_t { +/// NoModRef = 0, +/// Ref = 1, +/// Mod = 2, +/// ModRef = Ref | Mod, +/// }; +/// ``` +#[allow(dead_code)] // ModRef mirror — every variant kept for completeness. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +enum ModRefInfo { + NoModRef = 0, + Ref = 1, + Mod = 2, + ModRef = 3, +} + +/// Rust mirror of LLVM's `llvm::IRMemLocation`. +/// +/// Discriminants are the C++ enum values verbatim from +/// `llvm/include/llvm/Support/ModRef.h` lines 60-73 of the LLVM 21.1.8 +/// source tree: +/// +/// ```text +/// enum class IRMemLocation { +/// ArgMem = 0, +/// InaccessibleMem = 1, +/// ErrnoMem = 2, +/// Other = 3, +/// ... +/// }; +/// ``` +/// +/// The discriminant also serves as the location's index into the packed +/// `memory(...)` payload — see the `memory_location_pos` helper. +#[allow(dead_code)] // LLVM location mirror — every variant kept for completeness. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +enum MemoryLocation { + ArgMem = 0, + InaccessibleMem = 1, + ErrnoMem = 2, + Other = 3, +} + +/// Mirror of `llvm::MemoryEffectsBase::BitsPerLoc` — see +/// `llvm/include/llvm/Support/ModRef.h:82` of LLVM 21.1.8: +/// +/// ```text +/// static constexpr uint32_t BitsPerLoc = 2; +/// ``` +const MEMORY_EFFECT_BITS_PER_LOCATION: u64 = 2; + +/// Mirror of `llvm::MemoryEffectsBase::getLocationPos` — see +/// `llvm/include/llvm/Support/ModRef.h:85-87` of LLVM 21.1.8: +/// +/// ```text +/// static uint32_t getLocationPos(Location Loc) { +/// return (uint32_t)Loc * BitsPerLoc; +/// } +/// ``` +const fn memory_location_pos(location: MemoryLocation) -> u64 { + (location as u64) * MEMORY_EFFECT_BITS_PER_LOCATION +} + +/// Mirror of `llvm::MemoryEffectsBase::setModRef` for a single location on +/// an initially-zero payload — see `llvm/include/llvm/Support/ModRef.h:91-94` +/// of LLVM 21.1.8: +/// +/// ```text +/// void setModRef(Location Loc, ModRefInfo MR) { +/// Data &= ~(LocMask << getLocationPos(Loc)); +/// Data |= static_cast(MR) << getLocationPos(Loc); +/// } +/// ``` +const fn pack_memory_effect(location: MemoryLocation, mod_ref: ModRefInfo) -> u64 { + (mod_ref as u64) << memory_location_pos(location) +} + +/// Per-location memory effect packed into the integer payload of +/// [`Attribute::Memory`]. Every variant's encoding is derived through the +/// crate-private `pack_memory_effect` helper from `MemoryLocation` / +/// `ModRefInfo`, which are Rust mirrors of LLVM 21 enums with discriminants +/// matching C++. No raw integer literals appear in [`MemoryEffect::encoding`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum MemoryEffect { + /// Do not attach a `memory(...)` attribute to the function. + Unrestricted, + /// `memory(none)` — function has no observable memory effect. + None, + /// `memory(inaccessiblemem: read)` — the function only reads pallet-revive + /// runtime state (storage, call context, etc.) reached via host syscalls. + /// LLVM sees no pointer effects from the caller's perspective. + ReadInaccessible, + /// `memory(argmem: read, inaccessiblemem: read)` — the function reads from + /// a pointer argument **and** from pallet-revive runtime state. Used by + /// helpers that dereference a key buffer and forward into a host syscall. + ReadArgAndInaccessible, + /// `memory(inaccessiblemem: write)` — the only externally visible effect + /// is a write into pallet-revive runtime state. Heap loads remain CSE-able + /// across calls to such a helper. + WriteInaccessible, + /// `memory(other: read)` — function reads from regular heap memory only. + /// Pointer arguments, runtime state and errno are all untouched, so the + /// helper is invalidated by any heap store rather than by sstore wrappers. + ReadOther, +} + +impl MemoryEffect { + /// LLVM's packed integer encoding of this effect, or `None` when no + /// `memory(...)` attribute should be applied. See the crate-private + /// `pack_memory_effect` helper above for the LLVM 21 source the + /// encoding mirrors. + pub const fn encoding(self) -> Option { + match self { + Self::Unrestricted => None, + Self::None => Some(0), + Self::ReadInaccessible => Some(pack_memory_effect( + MemoryLocation::InaccessibleMem, + ModRefInfo::Ref, + )), + Self::ReadArgAndInaccessible => Some( + pack_memory_effect(MemoryLocation::ArgMem, ModRefInfo::Ref) + | pack_memory_effect(MemoryLocation::InaccessibleMem, ModRefInfo::Ref), + ), + Self::WriteInaccessible => Some(pack_memory_effect( + MemoryLocation::InaccessibleMem, + ModRefInfo::Mod, + )), + Self::ReadOther => Some(pack_memory_effect(MemoryLocation::Other, ModRefInfo::Ref)), + } + } +} + impl TryFrom<&str> for Attribute { type Error = String; @@ -139,3 +280,27 @@ impl TryFrom<&str> for Attribute { } } } + +#[cfg(test)] +mod memory_effect_tests { + use super::*; + + /// Locks the encoding against LLVM 21.1.8's `MemoryEffectsBase` layout. + /// Expected integers were cross-checked by compiling probe contracts and + /// reading the `memory(...)` strings off the emitted LLVM IR — every + /// helper using one of these variants printed the matching attribute + /// (e.g. `memory(inaccessiblemem: read)` for `ReadInaccessible`, + /// `memory(read, argmem: none, inaccessiblemem: none, errnomem: none)` — + /// LLVM 21's verbose form of `memory(other: read)` — for `ReadOther`). + /// If LLVM ever reorders `IRMemLocation` (as happened between LLVM 18 and + /// 21 when `ErrnoMem` was added), this test fires before codegen does. + #[test] + fn encoding_matches_llvm_21_layout() { + assert_eq!(MemoryEffect::Unrestricted.encoding(), None); + assert_eq!(MemoryEffect::None.encoding(), Some(0)); + assert_eq!(MemoryEffect::ReadInaccessible.encoding(), Some(4)); + assert_eq!(MemoryEffect::ReadArgAndInaccessible.encoding(), Some(5)); + assert_eq!(MemoryEffect::WriteInaccessible.encoding(), Some(8)); + assert_eq!(MemoryEffect::ReadOther.encoding(), Some(64)); + } +} diff --git a/crates/llvm-context/src/polkavm/context/function/mod.rs b/crates/llvm-context/src/polkavm/context/function/mod.rs index 9c59104f6..a499d59cc 100644 --- a/crates/llvm-context/src/polkavm/context/function/mod.rs +++ b/crates/llvm-context/src/polkavm/context/function/mod.rs @@ -97,6 +97,12 @@ impl<'ctx> Function<'ctx> { } /// Sets the memory writer function attributes. + /// + /// `Attribute::Memory` is **not** valid here — it carries a payload that + /// this enum-only API cannot express. Use the `MEMORY_EFFECT` associated + /// constant on the `RuntimeFunction` trait (or + /// `inkwell::attributes::Context::create_enum_attribute` directly when + /// not declaring through the trait) instead. pub fn set_attributes( llvm: &'ctx inkwell::context::Context, declaration: Declaration<'ctx>, @@ -104,8 +110,13 @@ impl<'ctx> Function<'ctx> { force: bool, ) { for attribute_kind in attributes { + assert_ne!( + *attribute_kind, + Attribute::Memory, + "Attribute::Memory cannot be set through set_attributes; \ + use RuntimeFunction::MEMORY_EFFECT to express the encoding", + ); match attribute_kind { - Attribute::Memory => unimplemented!("`memory` attributes are not implemented"), attribute_kind @ Attribute::AlwaysInline if force => { declaration.value.remove_enum_attribute( inkwell::attributes::AttributeLoc::Function, @@ -172,16 +183,19 @@ impl<'ctx> Function<'ctx> { ); } - if !optimizer.settings().is_middle_end_enabled() { - Self::set_attributes( - llvm, - declaration, - &[Attribute::NoInline, Attribute::OptimizeNone], - true, - ); - } - - Self::set_attributes(llvm, declaration, &[Attribute::NoFree], false); + // `NoFree` and `NoUnwind` are facts about the PVM target, not optimization heuristics: + // * PVM has no `free` (the heap is bump-allocated via `sbrk`), so no Solidity-emitted + // function can ever release memory. + // * PVM has no stack unwinding: Solidity errors leave a frame via `revert` + // (`seal_return(1, ..)` + `unreachable`), never via an unwind edge. Marking every + // function `nounwind` lets LLVM elide CFI directives, lower `invoke` to `call`, and + // skip exception frame setup. + Self::set_attributes( + llvm, + declaration, + &[Attribute::NoFree, Attribute::NoUnwind], + false, + ); } /// Sets the front-end runtime attributes. diff --git a/crates/llvm-context/src/polkavm/context/function/runtime/arithmetics.rs b/crates/llvm-context/src/polkavm/context/function/runtime/arithmetics.rs index 7e097fff1..a9a3c4d6d 100644 --- a/crates/llvm-context/src/polkavm/context/function/runtime/arithmetics.rs +++ b/crates/llvm-context/src/polkavm/context/function/runtime/arithmetics.rs @@ -3,16 +3,33 @@ use inkwell::values::BasicValue; use revive_common::BIT_LENGTH_WORD; +use crate::polkavm::context::attribute::Attribute; +use crate::polkavm::context::attribute::MemoryEffect; use crate::polkavm::context::runtime::RuntimeFunction; use crate::polkavm::context::Context; use crate::polkavm::WriteLLVM; +/// Standard attribute set for the pure arithmetic helpers. Each helper pairs +/// this list with [`PURE_MEMORY_EFFECT`] so that LLVM GVN/CSE can merge +/// repeated calls and hoist invariant divisions out of loops. +const PURE_ATTRIBUTES: &[Attribute] = &[ + Attribute::NoFree, + Attribute::NoRecurse, + Attribute::WillReturn, +]; + +/// The arithmetic helpers are pure (only depend on their integer arguments). +const PURE_MEMORY_EFFECT: MemoryEffect = MemoryEffect::None; + /// Implements the division operator according to the EVM specification. pub struct Division; impl RuntimeFunction for Division { const NAME: &'static str = "__revive_division"; + const ATTRIBUTES: &'static [Attribute] = PURE_ATTRIBUTES; + const MEMORY_EFFECT: MemoryEffect = PURE_MEMORY_EFFECT; + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { context.word_type().fn_type( &[context.word_type().into(), context.word_type().into()], @@ -52,6 +69,9 @@ pub struct SignedDivision; impl RuntimeFunction for SignedDivision { const NAME: &'static str = "__revive_signed_division"; + const ATTRIBUTES: &'static [Attribute] = PURE_ATTRIBUTES; + const MEMORY_EFFECT: MemoryEffect = PURE_MEMORY_EFFECT; + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { context.word_type().fn_type( &[context.word_type().into(), context.word_type().into()], @@ -126,6 +146,9 @@ pub struct Remainder; impl RuntimeFunction for Remainder { const NAME: &'static str = "__revive_remainder"; + const ATTRIBUTES: &'static [Attribute] = PURE_ATTRIBUTES; + const MEMORY_EFFECT: MemoryEffect = PURE_MEMORY_EFFECT; + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { context.word_type().fn_type( &[context.word_type().into(), context.word_type().into()], @@ -174,6 +197,9 @@ pub struct SignedRemainder; impl RuntimeFunction for SignedRemainder { const NAME: &'static str = "__revive_signed_remainder"; + const ATTRIBUTES: &'static [Attribute] = PURE_ATTRIBUTES; + const MEMORY_EFFECT: MemoryEffect = PURE_MEMORY_EFFECT; + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { context.word_type().fn_type( &[context.word_type().into(), context.word_type().into()], diff --git a/crates/llvm-context/src/polkavm/context/function/runtime/revive.rs b/crates/llvm-context/src/polkavm/context/function/runtime/revive.rs index 345a18045..ea2323288 100644 --- a/crates/llvm-context/src/polkavm/context/function/runtime/revive.rs +++ b/crates/llvm-context/src/polkavm/context/function/runtime/revive.rs @@ -2,6 +2,7 @@ use inkwell::values::BasicValue; +use crate::polkavm::context::attribute::MemoryEffect; use crate::polkavm::context::function::Attribute; use crate::polkavm::context::runtime::RuntimeFunction; use crate::polkavm::context::Context; @@ -132,3 +133,386 @@ impl WriteLLVM for Exit { ::emit(&self, context) } } + +/// Outlined `callvalue()` function that reads the value transferred with the call. +/// +/// The `value_transferred` runtime API writes a 256-bit value to a buffer. +/// Each inline call site generates: alloca i256 + store 0 + ptrtoint + call + load. +/// By outlining into a shared function, all call sites reduce to a single `call`. +/// Contracts with many non-payable checks (OpenZeppelin ERC20: 37 sites) save +/// significant code size through this deduplication. +pub struct CallValue; + +impl RuntimeFunction for CallValue { + const NAME: &'static str = "__revive_callvalue"; + + const ATTRIBUTES: &'static [Attribute] = &[ + Attribute::NoFree, + Attribute::NoRecurse, + Attribute::WillReturn, + ]; + + /// The call value is constant for the duration of a contract invocation, + /// so this helper is effectively pure: LLVM can DCE redundant calls and + /// CSE duplicate calls. + const MEMORY_EFFECT: MemoryEffect = MemoryEffect::None; + + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { + context.word_type().fn_type(&[], false) + } + + fn emit_body<'ctx>( + &self, + context: &mut Context<'ctx>, + ) -> anyhow::Result>> { + let output_pointer = + context.build_alloca_at_entry(context.value_type(), "value_transferred"); + context.build_store(output_pointer, context.word_const(0))?; + context.build_runtime_call( + revive_runtime_api::polkavm_imports::VALUE_TRANSFERRED, + &[output_pointer.to_int(context).into()], + ); + let value = context.build_load(output_pointer, "value_transferred")?; + Ok(Some(value)) + } +} + +impl WriteLLVM for CallValue { + fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> { + ::declare(self, context) + } + + fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { + ::emit(&self, context) + } +} + +/// Outlined `callvalue() != 0` function that returns a boolean flag. +/// +/// In ERC20 and similar contracts, callvalue is ONLY used for non-payable +/// checks: `if (callvalue()) { revert(0, 0) }`. Each such check compares +/// a 256-bit value against zero, generating 4 limb comparisons in PVM. +/// By outlining the check into a function returning `i1`, each call site +/// saves ~15 bytes (4 comparisons + OR vs. a single branch on i1). +/// OpenZeppelin ERC20 has ~20 such checks, saving ~300 bytes. +pub struct CallValueNonzero; + +impl RuntimeFunction for CallValueNonzero { + const NAME: &'static str = "__revive_callvalue_nonzero"; + + const ATTRIBUTES: &'static [Attribute] = &[ + Attribute::NoFree, + Attribute::NoRecurse, + Attribute::WillReturn, + ]; + + /// Same `memory(none)` rationale as [`CallValue`]. + const MEMORY_EFFECT: MemoryEffect = MemoryEffect::None; + + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { + context.llvm().bool_type().fn_type(&[], false) + } + + fn emit_body<'ctx>( + &self, + context: &mut Context<'ctx>, + ) -> anyhow::Result>> { + let output_pointer = + context.build_alloca_at_entry(context.value_type(), "value_transferred"); + context.build_store(output_pointer, context.word_const(0))?; + context.build_runtime_call( + revive_runtime_api::polkavm_imports::VALUE_TRANSFERRED, + &[output_pointer.to_int(context).into()], + ); + let value = context + .build_load(output_pointer, "value_transferred")? + .into_int_value(); + let zero = context.word_type().const_zero(); + let is_nonzero = context.builder().build_int_compare( + inkwell::IntPredicate::NE, + value, + zero, + "callvalue_nonzero", + )?; + Ok(Some(is_nonzero.into())) + } +} + +impl WriteLLVM for CallValueNonzero { + fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> { + ::declare(self, context) + } + + fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { + ::emit(&self, context) + } +} + +/// Outlined `calldataload(offset)` function that reads 32 bytes from call data. +/// +/// The `call_data_load` runtime API writes a 256-bit value to a buffer. +/// Each inline call site generates: alloca i256 + ptrtoint + call + load. +/// By outlining into a shared function, all call sites reduce to `clip_to_xlen + call`. +/// Contracts with many ABI parameters (OpenZeppelin ERC20: 51 sites) save +/// significant code size through this deduplication. +pub struct CallDataLoad; + +impl RuntimeFunction for CallDataLoad { + const NAME: &'static str = "__revive_calldataload"; + + /// Calldata is immutable for the duration of execution and only + /// reachable through the host syscall. The helper's alloca write is + /// invisible to callers, so the externally observable effect is a read + /// of pallet-revive runtime state — letting LLVM GVN fold repeated + /// `__revive_calldataload(offset)` calls even across heap mstores. + const MEMORY_EFFECT: MemoryEffect = MemoryEffect::ReadInaccessible; + + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { + context + .word_type() + .fn_type(&[context.xlen_type().into()], false) + } + + fn emit_body<'ctx>( + &self, + context: &mut Context<'ctx>, + ) -> anyhow::Result>> { + let offset = Self::paramater(context, 0).into_int_value(); + let output_pointer = context.build_alloca_at_entry(context.word_type(), "call_data_output"); + context.build_runtime_call( + revive_runtime_api::polkavm_imports::CALL_DATA_LOAD, + &[output_pointer.to_int(context).into(), offset.into()], + ); + let value = context.build_load(output_pointer, "call_data_load_value")?; + Ok(Some(value)) + } +} + +impl WriteLLVM for CallDataLoad { + fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> { + ::declare(self, context) + } + + fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { + ::emit(&self, context) + } +} + +/// Outlined `caller()` function that reads the calling account address. +/// +/// The `caller` runtime API writes a 20-byte address to a buffer. +/// Each inline call site generates: get_global + ptrtoint + call + load + bswap + zext. +/// By outlining into a shared function, all call sites reduce to a single `call`. +/// Contracts with many msg.sender checks (OpenZeppelin ERC20: 10+ sites) save +/// significant code size through this deduplication. +pub struct Caller; + +impl RuntimeFunction for Caller { + const NAME: &'static str = "__revive_caller"; + + /// The caller is immutable within an execution and the syscall reads it + /// from pallet-revive runtime state. The body writes the result into a + /// function-local alloca (not the shared `@GLOBAL_ADDRESS_SPILL_BUFFER`, + /// which `origin()` and `build_address` also touch — see the + /// `caller_origin_aliasing` regression test), so from the caller's view + /// only pallet-revive runtime state is read and `ReadInaccessible` is + /// sound. This lets GVN deduplicate repeated `__revive_caller()` calls + /// across heap mstores. + const MEMORY_EFFECT: MemoryEffect = MemoryEffect::ReadInaccessible; + + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { + context.word_type().fn_type(&[], false) + } + + fn emit_body<'ctx>( + &self, + context: &mut Context<'ctx>, + ) -> anyhow::Result>> { + let address_type = context.integer_type(revive_common::BIT_LENGTH_ETH_ADDRESS); + let output_pointer = context.build_alloca_at_entry(address_type, "caller_output"); + context.build_runtime_call( + revive_runtime_api::polkavm_imports::CALLER, + &[output_pointer.to_int(context).into()], + ); + let value = context.build_load_address(output_pointer)?; + Ok(Some(value)) + } +} + +impl WriteLLVM for Caller { + fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> { + ::declare(self, context) + } + + fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { + ::emit(&self, context) + } +} + +/// Outlined `revert(0, 0)` function (empty revert / panic). +/// +/// This is the most common revert pattern in Solidity contracts (20+ sites in ERC20). +/// Each inlined site generates sbrk(0, 0) + ptrtoint + seal_return (~8 PVM instructions). +/// By outlining into a zero-argument noreturn function, each call site becomes a single +/// `call @__revive_revert_0` (~2 PVM instructions). +pub struct RevertEmpty; + +impl RuntimeFunction for RevertEmpty { + const NAME: &'static str = "__revive_revert_0"; + + const ATTRIBUTES: &'static [Attribute] = &[Attribute::NoReturn, Attribute::NoFree]; + + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { + context.void_type().fn_type(&[], false) + } + + fn emit_body<'ctx>( + &self, + context: &mut Context<'ctx>, + ) -> anyhow::Result>> { + let zero = context.xlen_type().const_zero(); + // Use unchecked GEP: revert data at offset 0 is always within the + // static heap. The sbrk overhead is unnecessary since the data was + // already written to memory before this function is called. + let heap_pointer = context.build_heap_gep_unchecked(zero)?; + let offset_pointer = context.builder().build_ptr_to_int( + heap_pointer.value, + context.xlen_type(), + "return_data_ptr_to_int", + )?; + let flags = context.integer_const(crate::polkavm::XLEN, 1); + + context.build_runtime_call( + revive_runtime_api::polkavm_imports::RETURN, + &[flags.into(), offset_pointer.into(), zero.into()], + ); + context.build_unreachable(); + + Ok(None) + } +} + +impl WriteLLVM for RevertEmpty { + fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> { + ::declare(self, context) + } + + fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { + ::emit(&self, context) + } +} + +/// Outlined `revert(0, length)` function for non-zero constant lengths. +/// +/// After error data has been stored to heap memory at offset 0, this function +/// calls seal_return(1, heap_base, length). Used for revert(0, 4), revert(0, 36), +/// revert(0, 68), revert(0, 100) patterns. ERC20 has 34+ such sites. +pub struct Revert; + +impl RuntimeFunction for Revert { + const NAME: &'static str = "__revive_revert"; + + const ATTRIBUTES: &'static [Attribute] = &[Attribute::NoReturn, Attribute::NoFree]; + + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { + context + .void_type() + .fn_type(&[context.xlen_type().into()], false) + } + + fn emit_body<'ctx>( + &self, + context: &mut Context<'ctx>, + ) -> anyhow::Result>> { + let length = Self::paramater(context, 0).into_int_value(); + + let zero = context.xlen_type().const_zero(); + let heap_pointer = context.build_heap_gep(zero, length)?; + let offset_pointer = context.builder().build_ptr_to_int( + heap_pointer.value, + context.xlen_type(), + "return_data_ptr_to_int", + )?; + let flags = context.integer_const(crate::polkavm::XLEN, 1); + + context.build_runtime_call( + revive_runtime_api::polkavm_imports::RETURN, + &[flags.into(), offset_pointer.into(), length.into()], + ); + context.build_unreachable(); + + Ok(None) + } +} + +impl WriteLLVM for Revert { + fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> { + ::declare(self, context) + } + + fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { + ::emit(&self, context) + } +} + +/// Outlined `Panic(uint256)` revert helper: writes the Panic ABI encoding to +/// scratch memory (selector at offset 0, code at offset 4) and reverts with +/// length 36. The code is passed as an `i256` argument so a single helper +/// covers every panic code (0x01, 0x11, 0x12, 0x21, 0x22, 0x31, 0x32, 0x41). +/// Replaces the inline two-mstore + revert pattern at every panic site, which +/// otherwise duplicates ~30+ instructions across every function that traps. +pub struct RevertPanic; + +impl RuntimeFunction for RevertPanic { + const NAME: &'static str = "__revive_panic"; + + const ATTRIBUTES: &'static [Attribute] = &[Attribute::NoReturn, Attribute::NoFree]; + + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { + context + .void_type() + .fn_type(&[context.word_type().into()], false) + } + + fn emit_body<'ctx>( + &self, + context: &mut Context<'ctx>, + ) -> anyhow::Result>> { + let code = Self::paramater(context, 0).into_int_value(); + + let zero_xlen = context.xlen_type().const_zero(); + let four_xlen = context.xlen_type().const_int(4, false); + let panic_selector = + context.word_const_str_hex(revive_common::PANIC_UINT256_SELECTOR_WORD_HEX); + + crate::polkavm::evm::memory::store_bswap_unchecked(context, zero_xlen, panic_selector)?; + crate::polkavm::evm::memory::store_bswap_unchecked(context, four_xlen, code)?; + + let length = context.xlen_type().const_int(0x24, false); + let heap_pointer = context.build_heap_gep_unchecked(zero_xlen)?; + let offset_pointer = context.builder().build_ptr_to_int( + heap_pointer.value, + context.xlen_type(), + "panic_data_ptr_to_int", + )?; + let flags = context.integer_const(crate::polkavm::XLEN, 1); + + context.build_runtime_call( + revive_runtime_api::polkavm_imports::RETURN, + &[flags.into(), offset_pointer.into(), length.into()], + ); + context.build_unreachable(); + + Ok(None) + } +} + +impl WriteLLVM for RevertPanic { + fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> { + ::declare(self, context) + } + + fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { + ::emit(&self, context) + } +} diff --git a/crates/llvm-context/src/polkavm/context/mod.rs b/crates/llvm-context/src/polkavm/context/mod.rs index e02db6062..bc6608bc3 100644 --- a/crates/llvm-context/src/polkavm/context/mod.rs +++ b/crates/llvm-context/src/polkavm/context/mod.rs @@ -10,6 +10,7 @@ use inkwell::debug_info::AsDIScope; use inkwell::debug_info::DIScope; use inkwell::types::BasicType; use inkwell::values::BasicValue; +use inkwell::values::InstructionOpcode; use revive_solc_json_interface::PolkaVMDefaultHeapMemorySize; use revive_solc_json_interface::PolkaVMDefaultStackMemorySize; use revive_solc_json_interface::SolcStandardJsonInputSettingsPolkaVMMemory; @@ -20,11 +21,14 @@ use crate::polkavm::DebugConfig; use crate::target_machine::target::Target; use crate::target_machine::TargetMachine; use crate::PolkaVMLoadHeapWordFunction; +use crate::PolkaVMLoadHeapWordNativeFunction; use crate::PolkaVMSbrkFunction; use crate::PolkaVMStoreHeapWordFunction; +use crate::PolkaVMStoreHeapWordNativeFunction; use self::address_space::AddressSpace; use self::attribute::Attribute; +use self::attribute::MemoryEffect; use self::build::Build; use self::code_type::CodeType; use self::debug_info::DebugInfo; @@ -59,6 +63,18 @@ pub mod yul_data; #[cfg(test)] mod tests; +/// Imported host syscalls whose only externally visible effect is a read of +/// pallet-revive runtime state. Each returns a scalar — no output buffer +/// argument and no heap traffic from the caller's view — so we can attach +/// [`MemoryEffect::ReadInaccessible`] and let LLVM GVN dedupe repeated calls +/// across heap mstores. +const MEMORY_READ_IMPORTS: &[&str] = &[ + revive_runtime_api::polkavm_imports::CALL_DATA_SIZE, + revive_runtime_api::polkavm_imports::CODE_SIZE, + revive_runtime_api::polkavm_imports::GAS_LIMIT, + revive_runtime_api::polkavm_imports::RETURNDATASIZE, +]; + /// The LLVM IR generator context. /// It is a not-so-big god-like object glueing all the compilers' complexity and act as an adapter /// and a superstructure over the inner `inkwell` LLVM context. @@ -123,8 +139,10 @@ impl<'ctx> Context<'ctx> { .expect("the stdlib module should be linkable"); } - /// Link in the PolkaVM imports module, containing imported functions, - /// and marking them as external (they need to be relocatable as too). + /// Link in the PolkaVM imports module, mark host syscall imports as + /// `Internal` linkage (they need to be relocatable too), and attach a + /// [`MemoryEffect::ReadInaccessible`] attribute to every entry of + /// [`MEMORY_READ_IMPORTS`]. fn link_polkavm_imports( llvm: &'ctx inkwell::context::Context, module: &inkwell::module::Module<'ctx>, @@ -141,6 +159,20 @@ impl<'ctx> Context<'ctx> { .unwrap_or_else(|| panic!("{import} import should be declared")) .set_linkage(inkwell::module::Linkage::Internal); } + + let read_inaccessible_encoding = MemoryEffect::ReadInaccessible + .encoding() + .expect("ICE: ReadInaccessible always encodes to an integer"); + let memory_read_attr = + llvm.create_enum_attribute(Attribute::Memory as u32, read_inaccessible_encoding); + for import in MEMORY_READ_IMPORTS { + if let Some(function) = module.get_function(import) { + function.add_attribute( + inkwell::attributes::AttributeLoc::Function, + memory_read_attr, + ); + } + } } fn link_polkavm_exports(&self, contract_path: &str) -> anyhow::Result<()> { @@ -311,6 +343,12 @@ impl<'ctx> Context<'ctx> { ) })?; + // Narrow large integer div/rem where operands provably fit in a smaller + // type. LLVM's i256 div/rem backend expansion produces enormous basic + // blocks that pallet-revive rejects as `BasicBlockTooLarge`; narrowing + // here keeps the expansion compact. + self.narrow_divrem_instructions(); + self.debug_config .dump_llvm_ir_optimized(contract_path, self.module())?; @@ -441,12 +479,35 @@ impl<'ctx> Context<'ctx> { &self.llvm_runtime } + /// Returns the topmost frontend function-name → mangled-name scope. + /// + /// Panics if no scope has been pushed; callers must invoke this from inside a region + /// that has already set up its function scope. pub fn get_current_scope(&mut self) -> &mut BTreeMap { self.function_scope .last_mut() .expect("ICE: function scope must be pushed before declaring frontend functions") } + /// Returns the mangled symbol name for a frontend (Solidity-emitted) function. + /// + /// Frontend names collide across compilation units: separate Yul objects can both define + /// `fun_main` for example. The mangling appends a code-section tag (deploy / runtime) and a + /// per-context counter so each definition gets a globally unique LLVM symbol, while the + /// original name remains the lookup key in `function_scope`. + fn mangle_frontend_function_name(&mut self, name: &str) -> String { + assert!( + !self.get_current_scope().contains_key(name), + "ICE: function '{name}' declared subsequently in the same scope" + ); + let counter = self.function_counter; + self.function_counter += 1; + let mangled = format!("{name}_{}__{counter}", self.code_type().unwrap()); + self.get_current_scope() + .insert(name.to_string(), mangled.clone()); + mangled + } + /// Appends a function to the current module. pub fn add_function( &mut self, @@ -458,16 +519,7 @@ impl<'ctx> Context<'ctx> { is_frontend: bool, ) -> anyhow::Result>>> { let name = if is_frontend { - assert!( - !self.get_current_scope().contains_key(name), - "ICE: function '{name}' declared subsequently in the same scope" - ); - let counter = self.function_counter; - self.function_counter += 1; - let mangled = format!("{name}_{}__{counter}", self.code_type().unwrap()); - self.get_current_scope() - .insert(name.to_string(), mangled.clone()); - mangled + self.mangle_frontend_function_name(name) } else { name.to_string() }; @@ -492,21 +544,28 @@ impl<'ctx> Context<'ctx> { let entry_block = self.llvm.append_basic_block(value, "entry"); let return_block = self.llvm.append_basic_block(value, "return"); + // Allocate return slots using the actual return type from the function signature. + // Narrowed return types (e.g. i64 instead of i256) flow through unchanged, reducing + // register pressure and spills. let r#return = match return_values_length { 0 => FunctionReturn::none(), 1 => { self.set_basic_block(entry_block); - let pointer = self.build_alloca(self.word_type(), "return_pointer"); + let alloca_type = r#type + .get_return_type() + .unwrap_or_else(|| self.word_type().as_basic_type_enum()); + let pointer = self.build_alloca(alloca_type, "return_pointer"); FunctionReturn::primitive(pointer) } size => { self.set_basic_block(entry_block); - let pointer = self.build_alloca( + let alloca_type = r#type.get_return_type().unwrap_or_else(|| { self.structure_type( vec![self.word_type().as_basic_type_enum(); size].as_slice(), - ), - "return_pointer", - ); + ) + .as_basic_type_enum() + }); + let pointer = self.build_alloca(alloca_type, "return_pointer"); FunctionReturn::compound(pointer, size) } }; @@ -709,28 +768,35 @@ impl<'ctx> Context<'ctx> { } /// Builds an aligned stack allocation at the function entry. + /// + /// Allocas placed at the entry block coalesce into a single stack-frame allocation, + /// eliminating per-alloca dynamic stack adjustment. LLVM's stack coloring pass handles + /// lifetime-based slot reuse regardless of alloca placement. pub fn build_alloca_at_entry + Clone + Copy>( &self, r#type: T, name: &str, ) -> Pointer<'ctx> { - // TODO: Revisit. While at entry should be preferred in theory: - // - It has negligible code size impact on real word contracts. - // - Sometimes has negative impact on code size. - // - Messes up debug information used to analyze code size issues. - self.build_alloca(r#type, name) + let current_block = self.builder.get_insert_block().unwrap(); + let function = current_block.get_parent().unwrap(); + let entry_block = function.get_first_basic_block().unwrap(); - // let current_block = self.basic_block(); - // let entry_block = self.current_function().borrow().entry_block(); + if let Some(terminator) = entry_block.get_terminator() { + self.builder.position_before(&terminator); + } else { + self.builder.position_at_end(entry_block); + } - // match entry_block.get_first_instruction() { - // Some(instruction) => self.builder().position_before(&instruction), - // None => self.builder().position_at_end(entry_block), - // } + let pointer = self.builder.build_alloca(r#type, name).unwrap(); + pointer + .as_instruction() + .unwrap() + .set_alignment(revive_common::BYTE_LENGTH_STACK_ALIGN as u32) + .expect("ICE: alignment is valid"); - // let pointer = self.build_alloca(r#type, name); - // self.set_basic_block(current_block); - // pointer + self.builder.position_at_end(current_block); + + Pointer::new(r#type, AddressSpace::Stack, pointer) } /// Builds an aligned stack allocation at the current position. @@ -848,6 +914,34 @@ impl<'ctx> Context<'ctx> { Ok(()) } + /// Builds a heap load instruction without byte-swapping. + /// Used for internal memory operations that don't escape to external code. + pub fn build_load_native( + &self, + offset: inkwell::values::IntValue<'ctx>, + ) -> anyhow::Result> { + let name = ::NAME; + let declaration = ::declaration(self); + let arguments = [offset.as_basic_value_enum()]; + Ok(self + .build_call(declaration, &arguments, "heap_load_native") + .unwrap_or_else(|| panic!("revive runtime function {name} should return a value"))) + } + + /// Builds a heap store instruction without byte-swapping. + /// Used for internal memory operations that don't escape to external code. + pub fn build_store_native( + &self, + offset: inkwell::values::IntValue<'ctx>, + value: inkwell::values::IntValue<'ctx>, + ) -> anyhow::Result<()> { + let declaration = + ::declaration(self); + let arguments = [offset.as_basic_value_enum(), value.as_basic_value_enum()]; + self.build_call(declaration, &arguments, "heap_store_native"); + Ok(()) + } + /// Swap the endianness of an intvalue pub fn build_byte_swap( &self, @@ -1053,45 +1147,111 @@ impl<'ctx> Context<'ctx> { } /// Truncate a memory offset to register size, trapping if it doesn't fit. + /// + /// Handles all integer widths: at xlen the value is returned unchanged, narrower types are + /// zero-extended (no overflow possible), word-typed values delegate to the + /// `WordToPointer` runtime function (which returns the truncated value or jumps to invalid), + /// and intermediate widths inline a truncate-extend-compare at the source width because that + /// is much cheaper on 32-bit PVM than extending to i256 first (i64 compare is 2 register + /// pairs vs i256's 8 words — roughly 10 fewer instructions per check). pub fn safe_truncate_int_to_xlen( &self, value: inkwell::values::IntValue<'ctx>, ) -> anyhow::Result> { - if value.get_type() == self.xlen_type() { + let value_width = value.get_type().get_bit_width(); + let xlen_width = self.xlen_type().get_bit_width(); + let word_width = self.word_type().get_bit_width(); + + if value_width == xlen_width { return Ok(value); } - assert_eq!( - value.get_type(), - self.word_type(), - "expected XLEN or WORD sized int type for memory offset", - ); - Ok(self - .build_call( - ::declaration(self), - &[value.into()], - "word_to_pointer", - ) - .unwrap_or_else(|| { - panic!( - "revive runtime function {} should return a value", - ::NAME, + if value_width < xlen_width { + return Ok(self.builder().build_int_z_extend( + value, + self.xlen_type(), + "narrow_to_xlen", + )?); + } + + if value_width == word_width { + return Ok(self + .build_call( + ::declaration(self), + &[value.into()], + "word_to_pointer", ) - }) - .into_int_value()) + .unwrap_or_else(|| { + panic!( + "ICE: revive runtime function {} should return a value", + ::NAME, + ) + }) + .into_int_value()); + } + + let truncated = + self.builder() + .build_int_truncate(value, self.xlen_type(), "offset_truncated")?; + let extended = + self.builder() + .build_int_z_extend(truncated, value.get_type(), "offset_extended")?; + let is_overflow = self.builder().build_int_compare( + inkwell::IntPredicate::NE, + value, + extended, + "compare_truncated_extended", + )?; + + let block_continue = self.append_basic_block("offset_pointer_ok"); + let block_invalid = self.append_basic_block("offset_pointer_overflow"); + self.build_conditional_branch(is_overflow, block_invalid, block_continue)?; + + self.set_basic_block(block_invalid); + self.build_runtime_call(revive_runtime_api::polkavm_imports::INVALID, &[]); + self.build_unreachable(); + + self.set_basic_block(block_continue); + Ok(truncated) } /// Clip a memory offset to the maximum value that fits into a register. + /// + /// Behaves like [`Self::safe_truncate_int_to_xlen`] up to xlen-and-narrower widths, but for + /// wider types it saturates to `xlen::MAX` rather than trapping. The wider-type branch + /// keeps the original-width comparison so the codegen stays compact (word-type values + /// remain at word_type; intermediate widths use the value's own type). pub fn clip_to_xlen( &self, value: inkwell::values::IntValue<'ctx>, ) -> anyhow::Result> { + let value_width = value.get_type().get_bit_width(); + let xlen_width = self.xlen_type().get_bit_width(); + let word_width = self.word_type().get_bit_width(); + + if value_width == xlen_width { + return Ok(value); + } + + if value_width < xlen_width { + return Ok(self.builder().build_int_z_extend( + value, + self.xlen_type(), + "narrow_to_xlen", + )?); + } + let clipped = self.xlen_type().const_all_ones(); + let comparison_type = if value_width == word_width { + self.word_type() + } else { + value.get_type() + }; let is_overflow = self.builder().build_int_compare( inkwell::IntPredicate::UGT, value, self.builder() - .build_int_z_extend(clipped, self.word_type(), "value_clipped")?, + .build_int_z_extend(clipped, comparison_type, "value_clipped")?, "is_value_overflow", )?; let truncated = @@ -1158,6 +1318,64 @@ impl<'ctx> Context<'ctx> { Ok(Pointer::new(self.byte_type(), AddressSpace::Stack, pointer)) } + /// Returns a pointer to `offset` into the heap WITHOUT calling sbrk. + /// + /// The heap global is a fixed-size byte array (the static heap) that is always live for the + /// full duration of contract execution. sbrk only updates the *high-water mark* tracked in + /// `GLOBAL_HEAP_SIZE`; the underlying memory backing offsets up to `HEAP_SIZE` is always + /// addressable. Skipping sbrk is therefore safe whenever the *byte-order semantics* of the + /// access do not depend on a previously published high-water mark — i.e., for offsets known + /// to live inside the statically reserved scratch area (0x00-0x7f, including the free + /// memory pointer slot at 0x40), and for compiler-internal native-mode I/O whose offset + /// bound is proven by the type system. + /// + /// # Panics + /// Assumes `offset` to be a register sized value. + pub fn build_heap_gep_unchecked( + &self, + offset: inkwell::values::IntValue<'ctx>, + ) -> anyhow::Result> { + assert_eq!(offset.get_type(), self.xlen_type()); + let heap_global: Pointer<'ctx> = + self.get_global(crate::polkavm::GLOBAL_HEAP_MEMORY)?.into(); + let pointer = self.build_gep( + heap_global, + &[self.xlen_type().const_zero(), offset], + self.byte_type(), + "heap_unchecked_ptr", + ); + Ok(Pointer::new( + self.byte_type(), + AddressSpace::Stack, + pointer.value, + )) + } + + /// Ensures the heap size (msize) is at least `min_size`. + /// This emits a branchless max(current_msize, min_size) update. + /// Used after native stores that bypass sbrk to keep msize consistent. + pub fn ensure_heap_size( + &self, + min_size: inkwell::values::IntValue<'ctx>, + ) -> anyhow::Result<()> { + let current = self + .get_global_value(crate::polkavm::GLOBAL_HEAP_SIZE)? + .into_int_value(); + let needs_update = self.builder().build_int_compare( + inkwell::IntPredicate::UGT, + min_size, + current, + "msize_needs_update", + )?; + let new_size = self + .builder() + .build_select(needs_update, min_size, current, "msize_new")? + .into_int_value(); + let heap_size_global = self.get_global(crate::polkavm::GLOBAL_HEAP_SIZE)?; + self.build_store(heap_size_global.into(), new_size)?; + Ok(()) + } + /// Returns a boolean type constant. pub fn bool_const(&self, value: bool) -> inkwell::values::IntValue<'ctx> { self.bool_type().const_int(u64::from(value), false) @@ -1292,6 +1510,8 @@ impl<'ctx> Context<'ctx> { } /// Returns a Yul function type with the specified arguments and number of return values. + /// All return values use word_type (i256). For narrowed return types, use + /// `function_type_with_returns`. pub fn function_type( &self, argument_types: Vec, @@ -1318,6 +1538,39 @@ impl<'ctx> Context<'ctx> { } } + /// Returns a function type with explicit return types instead of word_type. + /// Used by the newyork codegen for functions with narrowed return types. + pub fn function_type_with_returns( + &self, + argument_types: Vec, + return_types: &[inkwell::types::IntType<'ctx>], + ) -> inkwell::types::FunctionType<'ctx> + where + T: BasicType<'ctx>, + { + let argument_types: Vec = argument_types + .as_slice() + .iter() + .map(T::as_basic_type_enum) + .map(inkwell::types::BasicMetadataTypeEnum::from) + .collect(); + match return_types.len() { + 0 => self + .llvm + .void_type() + .fn_type(argument_types.as_slice(), false), + 1 => return_types[0].fn_type(argument_types.as_slice(), false), + _ => { + let field_types: Vec = return_types + .iter() + .map(|t| t.as_basic_type_enum()) + .collect(); + self.structure_type(&field_types) + .fn_type(argument_types.as_slice(), false) + } + } + } + /// Modifies the call site value, setting the default attributes. /// The attributes only affect the LLVM optimizations. pub fn modify_call_site_value( @@ -1476,4 +1729,214 @@ impl<'ctx> Context<'ctx> { false, ) } + + /// Narrows large integer div/rem instructions whose operands provably fit + /// in a smaller type. + /// + /// LLVM's i256 div/rem backend expansion produces enormous basic blocks + /// that pallet-revive rejects as `BasicBlockTooLarge`. LLVM's own + /// `DivRemNarrowing` pass also sometimes fails to narrow div/rem in large + /// functions after inlining. This runs as a safety net after the full + /// LLVM optimization pipeline so we operate on the final form where the + /// proof sources we accept (LLVM constants, `and` masks, `zext`) are + /// observable across function boundaries after IPSCCP and inlining. + fn narrow_divrem_instructions(&self) { + let builder = self.llvm.create_builder(); + + for function in self.module().get_functions() { + let mut to_narrow = Vec::new(); + + for basic_block in function.get_basic_blocks() { + for instruction in basic_block.get_instructions() { + let is_divrem = matches!( + instruction.get_opcode(), + InstructionOpcode::UDiv + | InstructionOpcode::SDiv + | InstructionOpcode::URem + | InstructionOpcode::SRem + ); + if !is_divrem { + continue; + } + if instruction.get_type().into_int_type().get_bit_width() < 256 { + continue; + } + + let lhs = instruction.get_operand(0).and_then(|op| op.value()); + let rhs = instruction.get_operand(1).and_then(|op| op.value()); + + if let (Some(lhs), Some(rhs)) = (lhs, rhs) { + let lhs_width = Self::provable_bit_width(lhs); + let rhs_width = Self::provable_bit_width(rhs); + + if let (Some(lw), Some(rw)) = (lhs_width, rhs_width) { + let max_operand_width = lw.max(rw); + let narrow_width = Self::round_up_bit_width(max_operand_width); + // Signed div/rem narrowing is sound only when bit (narrow_width - 1) of every operand is provably zero — otherwise the + // narrow signed division treats a non-negative i256 operand as negative and the sign-extended result diverges from the + // i256 sdiv. The proof sources accepted here (constants, AND-masks, ZExt) all pin the upper bits to zero strictly above + // the operand width, so this holds iff the operand fits with at least one bit of headroom in the narrow type. + let is_signed = matches!( + instruction.get_opcode(), + InstructionOpcode::SDiv | InstructionOpcode::SRem + ); + let signed_sign_bit_safe = + !is_signed || narrow_width > max_operand_width; + if narrow_width < 256 && signed_sign_bit_safe { + to_narrow.push((instruction, narrow_width)); + } + } + } + } + } + + for (instruction, narrow_width) in to_narrow { + let lhs = instruction + .get_operand(0) + .unwrap() + .value() + .unwrap() + .into_int_value(); + let rhs = instruction + .get_operand(1) + .unwrap() + .value() + .unwrap() + .into_int_value(); + let wide_type = instruction.get_type().into_int_type(); + let narrow_type = self + .llvm + .custom_width_int_type( + std::num::NonZeroU32::new(narrow_width).expect("narrow width is non-zero"), + ) + .expect("valid integer width"); + + builder.position_before(&instruction); + + let lhs_truncated = builder.build_int_truncate(lhs, narrow_type, "").unwrap(); + let rhs_truncated = builder.build_int_truncate(rhs, narrow_type, "").unwrap(); + + let narrow_result = match instruction.get_opcode() { + InstructionOpcode::UDiv => builder + .build_int_unsigned_div(lhs_truncated, rhs_truncated, "") + .unwrap(), + InstructionOpcode::SDiv => builder + .build_int_signed_div(lhs_truncated, rhs_truncated, "") + .unwrap(), + InstructionOpcode::URem => builder + .build_int_unsigned_rem(lhs_truncated, rhs_truncated, "") + .unwrap(), + InstructionOpcode::SRem => builder + .build_int_signed_rem(lhs_truncated, rhs_truncated, "") + .unwrap(), + _ => unreachable!(), + }; + + let wide_result = if matches!( + instruction.get_opcode(), + InstructionOpcode::SDiv | InstructionOpcode::SRem + ) { + builder + .build_int_s_extend(narrow_result, wide_type, "") + .unwrap() + } else { + builder + .build_int_z_extend(narrow_result, wide_type, "") + .unwrap() + }; + + let wide_instruction = wide_result.as_instruction().unwrap(); + instruction.replace_all_uses_with(&wide_instruction); + instruction.erase_from_basic_block(); + } + } + } + + /// Returns the provable bit width of a value, if it can be determined. + /// + /// Checks for: + /// - Constants: bit width needed to represent the value. + /// - `and %x, mask`: bit width of the mask. + /// - `zext from smaller_type`: bit width of the source type. + /// - `trunc to smaller_type`: bit width of the result type. + fn provable_bit_width(value: inkwell::values::BasicValueEnum) -> Option { + let integer_value = value.into_int_value(); + if integer_value.is_const() { + return Self::constant_bit_width(integer_value); + } + + let instruction = integer_value.as_instruction()?; + match instruction.get_opcode() { + InstructionOpcode::And => { + let operand_0 = instruction.get_operand(0)?.value()?.into_int_value(); + let operand_1 = instruction.get_operand(1)?.value()?.into_int_value(); + if operand_1.is_const() { + Self::constant_bit_width(operand_1) + } else if operand_0.is_const() { + Self::constant_bit_width(operand_0) + } else { + None + } + } + InstructionOpcode::ZExt => { + let source = instruction.get_operand(0)?.value()?.into_int_value(); + Some(source.get_type().get_bit_width()) + } + InstructionOpcode::Trunc => { + Some(instruction.get_type().into_int_type().get_bit_width()) + } + _ => None, + } + } + + /// Returns the minimum number of bits needed to represent a constant integer. + /// + /// For types up to 64 bits the direct LLVM API suffices. For wider types (e.g. i256) we + /// truncate to i64 and verify the round-trip: if the reconstructed wide constant equals the + /// original (LLVM constants are interned, so pointer equality is correct), the value fits + /// in u64 and we report `64 - leading_zeros`. + fn constant_bit_width(integer_value: inkwell::values::IntValue) -> Option { + if let Some(value) = integer_value.get_zero_extended_constant() { + return Some(if value == 0 { + 1 + } else { + 64 - value.leading_zeros() + }); + } + + let wide_type = integer_value.get_type(); + if wide_type.get_bit_width() > 64 { + let i64_type = wide_type.get_context().i64_type(); + let truncated = integer_value.const_truncate(i64_type); + if let Some(value) = truncated.get_zero_extended_constant() { + let reconstructed = wide_type.const_int(value, false); + if reconstructed == integer_value { + return Some(if value == 0 { + 1 + } else { + 64 - value.leading_zeros() + }); + } + } + } + + None + } + + /// Rounds a bit width up to the next standard integer type width. + fn round_up_bit_width(bits: u32) -> u32 { + if bits <= 8 { + 8 + } else if bits <= 16 { + 16 + } else if bits <= 32 { + 32 + } else if bits <= 64 { + 64 + } else if bits <= 128 { + 128 + } else { + 256 + } + } } diff --git a/crates/llvm-context/src/polkavm/context/pointer/heap.rs b/crates/llvm-context/src/polkavm/context/pointer/heap.rs index 80549516d..1b72c8781 100644 --- a/crates/llvm-context/src/polkavm/context/pointer/heap.rs +++ b/crates/llvm-context/src/polkavm/context/pointer/heap.rs @@ -1,15 +1,20 @@ //! The revive simulated EVM linear memory pointer functions. +use std::num::NonZeroU32; + use inkwell::values::BasicValueEnum; use revive_common::BYTE_LENGTH_BYTE; use revive_common::BYTE_LENGTH_WORD; +use revive_common::BYTE_LENGTH_X64; +use crate::polkavm::context::attribute::MemoryEffect; use crate::polkavm::context::runtime::RuntimeFunction; use crate::polkavm::context::Context; use crate::polkavm::WriteLLVM; /// Load a word size value from a heap pointer. +/// Uses 4x 64-bit loads with bswap for efficient byte-order conversion. pub struct LoadWord; impl RuntimeFunction for LoadWord { @@ -21,6 +26,251 @@ impl RuntimeFunction for LoadWord { .fn_type(&[context.xlen_type().into()], false) } + fn emit_body<'ctx>( + &self, + context: &mut Context<'ctx>, + ) -> anyhow::Result>> { + let offset = Self::paramater(context, 0).into_int_value(); + let length = context + .xlen_type() + .const_int(BYTE_LENGTH_WORD as u64, false); + let pointer = context.build_heap_gep(offset, length)?; + let result = build_efficient_load_swap(context, pointer.value)?; + Ok(Some(result)) + } +} + +impl WriteLLVM for LoadWord { + fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> { + ::declare(self, context) + } + + fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { + ::emit(&self, context) + } +} + +/// Store a word size value through a heap pointer. +/// Uses 4x 64-bit stores with bswap for efficient byte-order conversion. +pub struct StoreWord; + +impl RuntimeFunction for StoreWord { + const NAME: &'static str = "__revive_store_heap_word"; + + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { + context.void_type().fn_type( + &[context.xlen_type().into(), context.word_type().into()], + false, + ) + } + + fn emit_body<'ctx>( + &self, + context: &mut Context<'ctx>, + ) -> anyhow::Result>> { + let offset = Self::paramater(context, 0).into_int_value(); + let length = context + .xlen_type() + .const_int(BYTE_LENGTH_WORD as u64, false); + let pointer = context.build_heap_gep(offset, length)?; + let value = Self::paramater(context, 1).into_int_value(); + build_efficient_store_swap(context, pointer.value, value)?; + Ok(None) + } +} + +/// Builds an efficient 256-bit load with byte-swap using 4x 64-bit operations. +/// +/// This is much more efficient than LLVM's default lowering of llvm.bswap.i256 +/// which generates byte-by-byte loads. We instead: +/// 1. Load 4x 64-bit values +/// 2. Byte-swap each 64-bit value using llvm.bswap.i64 +/// 3. Combine them in reversed word order to form the 256-bit result +pub(crate) fn build_efficient_load_swap<'ctx>( + context: &Context<'ctx>, + pointer: inkwell::values::PointerValue<'ctx>, +) -> anyhow::Result> { + let i64_type = context + .llvm() + .custom_width_int_type(NonZeroU32::new(64).expect("const is non-zero")) + .expect("valid integer width"); + let i8_type = context + .llvm() + .custom_width_int_type(NonZeroU32::new(8).expect("const is non-zero")) + .expect("valid integer width"); + let word_type = context.word_type(); + + let bswap64 = inkwell::intrinsics::Intrinsic::find("llvm.bswap.i64") + .expect("ICE: llvm.bswap.i64 intrinsic exists"); + let bswap64_function = bswap64 + .get_declaration(context.module(), &[i64_type.into()]) + .expect("ICE: bswap.i64 declaration"); + + let mut swapped_x64_values = Vec::with_capacity(4); + for index in 0..4 { + let gep_offset = context + .xlen_type() + .const_int(index * BYTE_LENGTH_X64 as u64, false); + let byte_pointer = unsafe { + context.builder().build_gep( + i8_type, + pointer, + &[gep_offset], + &format!("byte_pointer_{index}"), + )? + }; + let x64_value = context + .builder() + .build_load(i64_type, byte_pointer, &format!("x64_value_{index}"))? + .into_int_value(); + context + .basic_block() + .get_last_instruction() + .expect("ICE: load instruction always exists") + .set_alignment(BYTE_LENGTH_X64 as u32) + .expect("ICE: alignment is valid"); + + let swapped_x64_value = context + .builder() + .build_call( + bswap64_function, + &[x64_value.into()], + &format!("swapped_x64_value_{index}"), + )? + .try_as_basic_value() + .unwrap_basic() + .into_int_value(); + swapped_x64_values.push(swapped_x64_value); + } + + // Combine in reversed register order: chunks 3, 2, 1, 0 from most to + // least significant. This achieves the full big-endian to little-endian + // conversion of the 256-bit word. + let mut result = + context + .builder() + .build_int_z_extend(swapped_x64_values[3], word_type, "ext_0")?; + for (index, &x64_value) in swapped_x64_values.iter().rev().skip(1).enumerate() { + let extended = context.builder().build_int_z_extend( + x64_value, + word_type, + &format!("ext_{}", index + 1), + )?; + let shift_amount = word_type.const_int(64 * (index + 1) as u64, false); + let shifted = context.builder().build_left_shift( + extended, + shift_amount, + &format!("shift_{}", index + 1), + )?; + result = context + .builder() + .build_or(result, shifted, &format!("or_{}", index + 1))?; + } + + Ok(result.into()) +} + +/// Builds an efficient 256-bit store with byte-swap using 4x 64-bit operations. +/// +/// This is much more efficient than LLVM's default lowering of llvm.bswap.i256 +/// which generates byte-by-byte stores. We instead: +/// 1. Extract 4x 64-bit values from the 256-bit word +/// 2. Byte-swap each 64-bit value using llvm.bswap.i64 +/// 3. Store them in reversed word order +pub(crate) fn build_efficient_store_swap<'ctx>( + context: &Context<'ctx>, + pointer: inkwell::values::PointerValue<'ctx>, + value: inkwell::values::IntValue<'ctx>, +) -> anyhow::Result<()> { + let i64_type = context + .llvm() + .custom_width_int_type(NonZeroU32::new(64).expect("const is non-zero")) + .expect("valid integer width"); + let i8_type = context + .llvm() + .custom_width_int_type(NonZeroU32::new(8).expect("const is non-zero")) + .expect("valid integer width"); + let word_type = context.word_type(); + + let bswap64 = inkwell::intrinsics::Intrinsic::find("llvm.bswap.i64") + .expect("ICE: llvm.bswap.i64 intrinsic exists"); + let bswap64_function = bswap64 + .get_declaration(context.module(), &[i64_type.into()]) + .expect("ICE: bswap.i64 declaration"); + + for index in 0..4 { + let shift_amount = word_type.const_int(64 * index as u64, false); + let shifted = context.builder().build_right_shift( + value, + shift_amount, + false, + &format!("shift_{index}"), + )?; + let x64_value = + context + .builder() + .build_int_truncate(shifted, i64_type, &format!("trunc_{index}"))?; + + let swapped_x64_value = context + .builder() + .build_call( + bswap64_function, + &[x64_value.into()], + &format!("swap_x64_value_{index}"), + )? + .try_as_basic_value() + .unwrap_basic() + .into_int_value(); + + // Reverse the position so the least-significant chunk lands at the + // highest byte offset; this performs the big-endian byte order on + // the 256-bit word as a whole. + let store_byte_offset = (3 - index) * BYTE_LENGTH_X64; + let gep_offset = context + .xlen_type() + .const_int(store_byte_offset as u64, false); + let byte_pointer = unsafe { + context.builder().build_gep( + i8_type, + pointer, + &[gep_offset], + &format!("store_pointer_{index}"), + )? + }; + let store_instruction = context + .builder() + .build_store(byte_pointer, swapped_x64_value)?; + store_instruction + .set_alignment(BYTE_LENGTH_X64 as u32) + .expect("ICE: alignment is valid"); + } + + Ok(()) +} + +impl WriteLLVM for StoreWord { + fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> { + ::declare(self, context) + } + + fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { + ::emit(&self, context) + } +} + +/// Load a word size value from a heap pointer without byte-swapping. +/// Used for internal memory operations that don't escape to external code. +pub struct LoadWordNative; + +impl RuntimeFunction for LoadWordNative { + const NAME: &'static str = "__revive_load_heap_word_native"; + + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { + context + .word_type() + .fn_type(&[context.xlen_type().into()], false) + } + fn emit_body<'ctx>( &self, context: &mut Context<'ctx>, @@ -36,16 +286,14 @@ impl RuntimeFunction for LoadWord { context .basic_block() .get_last_instruction() - .expect("Always exists") + .expect("ICE: load instruction always exists") .set_alignment(BYTE_LENGTH_BYTE as u32) - .expect("Alignment is valid"); - - let swapped_value = context.build_byte_swap(value)?; - Ok(Some(swapped_value)) + .expect("ICE: alignment is valid"); + Ok(Some(value)) } } -impl WriteLLVM for LoadWord { +impl WriteLLVM for LoadWordNative { fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> { ::declare(self, context) } @@ -55,11 +303,12 @@ impl WriteLLVM for LoadWord { } } -/// Store a word size value through a heap pointer. -pub struct StoreWord; +/// Store a word size value through a heap pointer without byte-swapping. +/// Used for internal memory operations that don't escape to external code. +pub struct StoreWordNative; -impl RuntimeFunction for StoreWord { - const NAME: &'static str = "__revive_store_heap_word"; +impl RuntimeFunction for StoreWordNative { + const NAME: &'static str = "__revive_store_heap_word_native"; fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { context.void_type().fn_type( @@ -77,19 +326,178 @@ impl RuntimeFunction for StoreWord { .xlen_type() .const_int(BYTE_LENGTH_WORD as u64, false); let pointer = context.build_heap_gep(offset, length)?; - - let value = context.build_byte_swap(Self::paramater(context, 1))?; + let value = Self::paramater(context, 1); context .builder() .build_store(pointer.value, value)? .set_alignment(BYTE_LENGTH_BYTE as u32) - .expect("Alignment is valid"); + .expect("ICE: alignment is valid"); Ok(None) } } -impl WriteLLVM for StoreWord { +impl WriteLLVM for StoreWordNative { + fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> { + ::declare(self, context) + } + + fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { + ::emit(&self, context) + } +} + +/// Keccak256 hash of one 256-bit word from scratch memory. +/// Equivalent to: mstore(0, word0); sha3(0, 32) +/// Deduplicated into a single function to reduce code size for storage slot lookups. +pub struct Keccak256OneWord; + +impl Keccak256OneWord { + /// The function name. + pub const NAME: &'static str = "__revive_keccak256_one_word"; +} + +impl RuntimeFunction for Keccak256OneWord { + const NAME: &'static str = "__revive_keccak256_one_word"; + + const ATTRIBUTES: &'static [crate::polkavm::context::Attribute] = &[ + crate::polkavm::context::Attribute::NoFree, + crate::polkavm::context::Attribute::NoRecurse, + crate::polkavm::context::Attribute::WillReturn, + crate::polkavm::context::Attribute::NoInline, + ]; + + /// Writes the input back to heap[0..32] (matching EVM's + /// `mstore(0, word0); keccak256(0, 32)`), then hashes from there. + /// This lets `mem_opt`'s keccak fusion safely dead-eliminate the + /// preceding `mstore(0, k)` — a later `mload(0)` whose mem_opt + /// forwarding has been invalidated (e.g., by an intervening + /// external call) reads the helper's heap write and gets the + /// same value EVM would. The helper is no longer + /// `MemoryEffect::None`; `Unrestricted` gives LLVM accurate + /// information about its memory effects. + const MEMORY_EFFECT: MemoryEffect = MemoryEffect::Unrestricted; + + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { + context + .word_type() + .fn_type(&[context.word_type().into()], false) + } + + fn emit_body<'ctx>( + &self, + context: &mut Context<'ctx>, + ) -> anyhow::Result>> { + let word0 = Self::paramater(context, 0).into_int_value(); + + // Mirror EVM's `mstore(0, word0)`: byte-swap and store to heap[0..32]. + let zero_xlen = context.xlen_type().const_zero(); + crate::polkavm::evm::memory::store_bswap_unchecked(context, zero_xlen, word0)?; + + let length = context + .xlen_type() + .const_int(BYTE_LENGTH_WORD as u64, false); + + let output_pointer = context.build_alloca_at_entry(context.word_type(), "output_pointer"); + let input_pointer = context.build_heap_gep_unchecked(zero_xlen)?; + + context.build_runtime_call( + revive_runtime_api::polkavm_imports::HASH_KECCAK_256, + &[ + input_pointer.to_int(context).into(), + length.into(), + output_pointer.to_int(context).into(), + ], + ); + + let result = context.build_byte_swap(context.build_load(output_pointer, "sha3_output")?)?; + Ok(Some(result)) + } +} + +impl WriteLLVM for Keccak256OneWord { + fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> { + ::declare(self, context) + } + + fn into_llvm(self, context: &mut Context) -> anyhow::Result<()> { + ::emit(&self, context) + } +} + +/// Keccak256 hash of two 256-bit words from scratch memory. +/// Equivalent to: mstore(0, word0); mstore(32, word1); sha3(0, 64) +/// Deduplicated into a single function to reduce code size for mapping lookups. +pub struct Keccak256TwoWords; + +impl Keccak256TwoWords { + /// The function name. + pub const NAME: &'static str = "__revive_keccak256_two_words"; +} + +impl RuntimeFunction for Keccak256TwoWords { + const NAME: &'static str = "__revive_keccak256_two_words"; + + const ATTRIBUTES: &'static [crate::polkavm::context::Attribute] = &[ + crate::polkavm::context::Attribute::NoFree, + crate::polkavm::context::Attribute::NoRecurse, + crate::polkavm::context::Attribute::WillReturn, + crate::polkavm::context::Attribute::NoInline, + ]; + + /// Writes the inputs back to heap[0..64] (matching EVM's + /// `mstore(0, word0); mstore(32, word1); keccak256(0, 64)`), then + /// hashes from there. This lets `mem_opt`'s keccak fusion safely + /// dead-eliminate the preceding mstores — a later `mload` at offset + /// 0 or 32 whose mem_opt forwarding has been invalidated reads the + /// helper's heap writes and gets the same value EVM would. + const MEMORY_EFFECT: MemoryEffect = MemoryEffect::Unrestricted; + + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { + context.word_type().fn_type( + &[context.word_type().into(), context.word_type().into()], + false, + ) + } + + fn emit_body<'ctx>( + &self, + context: &mut Context<'ctx>, + ) -> anyhow::Result>> { + let word0 = Self::paramater(context, 0).into_int_value(); + let word1 = Self::paramater(context, 1).into_int_value(); + + // Mirror EVM's `mstore(0, word0); mstore(32, word1)`: byte-swap + // and store both words to heap[0..64]. + let zero_xlen = context.xlen_type().const_zero(); + let word_xlen = context + .xlen_type() + .const_int(BYTE_LENGTH_WORD as u64, false); + crate::polkavm::evm::memory::store_bswap_unchecked(context, zero_xlen, word0)?; + crate::polkavm::evm::memory::store_bswap_unchecked(context, word_xlen, word1)?; + + let length = context + .xlen_type() + .const_int(2 * BYTE_LENGTH_WORD as u64, false); + + let output_pointer = context.build_alloca_at_entry(context.word_type(), "output_pointer"); + let input_pointer = context.build_heap_gep_unchecked(zero_xlen)?; + + context.build_runtime_call( + revive_runtime_api::polkavm_imports::HASH_KECCAK_256, + &[ + input_pointer.to_int(context).into(), + length.into(), + output_pointer.to_int(context).into(), + ], + ); + + let result = context.build_byte_swap(context.build_load(output_pointer, "sha3_output")?)?; + Ok(Some(result)) + } +} + +impl WriteLLVM for Keccak256TwoWords { fn declare(&mut self, context: &mut Context) -> anyhow::Result<()> { ::declare(self, context) } diff --git a/crates/llvm-context/src/polkavm/context/pointer/storage.rs b/crates/llvm-context/src/polkavm/context/pointer/storage.rs index c7293c5ea..427789771 100644 --- a/crates/llvm-context/src/polkavm/context/pointer/storage.rs +++ b/crates/llvm-context/src/polkavm/context/pointer/storage.rs @@ -2,6 +2,7 @@ use inkwell::values::BasicValueEnum; +use crate::polkavm::context::attribute::MemoryEffect; use crate::polkavm::context::runtime::RuntimeFunction; use crate::polkavm::context::Context; use crate::polkavm::WriteLLVM; @@ -12,6 +13,13 @@ pub struct LoadWord; impl RuntimeFunction for LoadWord { const NAME: &'static str = "__revive_load_storage_word"; + /// The helper dereferences its key pointer (a read through `argmem`) and + /// reads storage (pallet-revive runtime state, invisible to LLVM). Heap + /// is not touched. Intervening `__revive_store_storage_word` carries the + /// default attributes and still acts as a barrier, so this lets GVN + /// dedupe `__revive_load_storage_word` calls across heap mstores. + const MEMORY_EFFECT: MemoryEffect = MemoryEffect::ReadArgAndInaccessible; + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { context .word_type() @@ -46,6 +54,11 @@ pub struct LoadTransientWord; impl RuntimeFunction for LoadTransientWord { const NAME: &'static str = "__revive_load_transient_storage_word"; + /// Same shape as [`LoadWord`]: argmem read (key pointer) plus a read of + /// pallet-revive runtime state. Transient-store wrappers retain unknown + /// memory effects and act as a barrier preventing incorrect CSE. + const MEMORY_EFFECT: MemoryEffect = MemoryEffect::ReadArgAndInaccessible; + fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx> { context .word_type() diff --git a/crates/llvm-context/src/polkavm/context/runtime.rs b/crates/llvm-context/src/polkavm/context/runtime.rs index 566e9d10c..1b65be2ac 100644 --- a/crates/llvm-context/src/polkavm/context/runtime.rs +++ b/crates/llvm-context/src/polkavm/context/runtime.rs @@ -4,6 +4,7 @@ //! This benefits contract code size. use crate::optimizer::settings::size_level::SizeLevel; +use crate::polkavm::context::attribute::MemoryEffect; use crate::polkavm::context::function::declaration::Declaration; use crate::polkavm::context::function::Function; use crate::polkavm::context::Attribute; @@ -21,10 +22,19 @@ pub trait RuntimeFunction { Attribute::WillReturn, ]; + /// The `memory(...)` effect to attach to the function declaration. + /// + /// Helpers that interact only with their own allocas or with pallet-revive + /// runtime state (via host syscalls) can advertise a tighter effect than + /// the conservative LLVM default. The trait wires the encoding through + /// [`Self::declare`] so concrete impls don't have to call the raw inkwell + /// API. Default: do not attach the attribute. + const MEMORY_EFFECT: MemoryEffect = MemoryEffect::Unrestricted; + /// The function type. fn r#type<'ctx>(context: &Context<'ctx>) -> inkwell::types::FunctionType<'ctx>; - /// Declare the function. + /// Declare the function with standard attributes. fn declare(&self, context: &mut Context) -> anyhow::Result<()> { let function = context.add_function( Self::NAME, @@ -46,6 +56,14 @@ pub trait RuntimeFunction { &attributes, true, ); + if let Some(encoding) = Self::MEMORY_EFFECT.encoding() { + function.borrow().declaration().value.add_attribute( + inkwell::attributes::AttributeLoc::Function, + context + .llvm() + .create_enum_attribute(Attribute::Memory as u32, encoding), + ); + } let function = function.borrow().declaration().function_value(); let comdat = context .module() diff --git a/crates/llvm-context/src/polkavm/evm/calldata.rs b/crates/llvm-context/src/polkavm/evm/calldata.rs index c3bef985c..cf136b594 100644 --- a/crates/llvm-context/src/polkavm/evm/calldata.rs +++ b/crates/llvm-context/src/polkavm/evm/calldata.rs @@ -18,6 +18,30 @@ pub fn load<'ctx>( context.build_load(output_pointer, "call_data_load_value") } +/// Calls the outlined `__revive_calldataload(xlen) -> i256` runtime function. +/// +/// Functionally identical to [`load`] but calls a shared outlined function +/// instead of inlining the alloca+call+load sequence at every call site. +pub fn load_outlined<'ctx>( + context: &mut Context<'ctx>, + offset: inkwell::values::IntValue<'ctx>, +) -> anyhow::Result> { + use crate::polkavm::context::function::runtime::revive::CallDataLoad; + use crate::polkavm::context::runtime::RuntimeFunction; + let offset = context.clip_to_xlen(offset)?; + let function = context + .get_function(CallDataLoad::NAME, false) + .expect("ICE: __revive_calldataload should be declared"); + let result = context + .build_call( + function.borrow().declaration(), + &[offset.into()], + "calldataload_result", + ) + .expect("ICE: __revive_calldataload should return a value"); + Ok(result) +} + /// Translates the calldata size. pub fn size<'ctx>( context: &mut Context<'ctx>, diff --git a/crates/llvm-context/src/polkavm/evm/context.rs b/crates/llvm-context/src/polkavm/evm/context.rs index f1f057ae2..e50b88199 100644 --- a/crates/llvm-context/src/polkavm/evm/context.rs +++ b/crates/llvm-context/src/polkavm/evm/context.rs @@ -148,3 +148,23 @@ pub fn caller<'ctx>( ); context.build_load_address(pointer) } + +/// Calls the outlined `__revive_caller() -> i256` runtime function. +/// +/// This is functionally identical to [`caller`] but calls a shared outlined function +/// instead of inlining the get_global+call+load+bswap+zext sequence at every call site. +/// For contracts with many msg.sender checks (e.g. OpenZeppelin ERC20: 10+ sites), +/// this significantly reduces code size. +pub fn caller_outlined<'ctx>( + context: &mut Context<'ctx>, +) -> anyhow::Result> { + use crate::polkavm::context::function::runtime::revive::Caller; + use crate::polkavm::context::runtime::RuntimeFunction; + let function = context + .get_function(Caller::NAME, false) + .expect("ICE: __revive_caller should be declared"); + let result = context + .build_call(function.borrow().declaration(), &[], "caller_result") + .expect("ICE: __revive_caller should return a value"); + Ok(result) +} diff --git a/crates/llvm-context/src/polkavm/evm/crypto.rs b/crates/llvm-context/src/polkavm/evm/crypto.rs index 3f2876238..bdcf1706c 100644 --- a/crates/llvm-context/src/polkavm/evm/crypto.rs +++ b/crates/llvm-context/src/polkavm/evm/crypto.rs @@ -11,7 +11,7 @@ pub fn sha3<'ctx>( let offset_casted = context.safe_truncate_int_to_xlen(offset)?; let length_casted = context.safe_truncate_int_to_xlen(length)?; let input_pointer = context.build_heap_gep(offset_casted, length_casted)?; - let output_pointer = context.build_alloca(context.word_type(), "output_pointer"); + let output_pointer = context.build_alloca_at_entry(context.word_type(), "output_pointer"); context.build_runtime_call( revive_runtime_api::polkavm_imports::HASH_KECCAK_256, @@ -24,3 +24,52 @@ pub fn sha3<'ctx>( context.build_byte_swap(context.build_load(output_pointer, "sha3_output")?) } + +/// Translates keccak256 of one 256-bit word via a deduplicated helper function. +/// Equivalent to: mstore(0, word0); sha3(0, 32) +/// but emitted as a single function call to reduce code size. +/// +/// Falls back to inline code if the helper function is not declared +/// (e.g. when there are too few call sites to justify the function body cost). +pub fn sha3_one_word<'ctx>( + context: &mut Context<'ctx>, + word0: inkwell::values::IntValue<'ctx>, +) -> anyhow::Result> { + use crate::polkavm::context::pointer::heap::Keccak256OneWord; + let Some(function) = context.get_function(Keccak256OneWord::NAME, false) else { + let offset = context.word_const(0); + let length = context.word_const(32); + crate::polkavm::evm::memory::store(context, offset, word0)?; + return sha3(context, offset, length); + }; + let result = context + .build_call( + function.borrow().declaration(), + &[word0.into()], + "keccak256_single_result", + ) + .expect("ICE: keccak256_one_word should return a value"); + Ok(result) +} + +/// Translates keccak256 of two 256-bit words via a deduplicated helper function. +/// Equivalent to: mstore(0, word0); mstore(32, word1); sha3(0, 64) +/// but emitted as a single function call to reduce code size. +pub fn sha3_two_words<'ctx>( + context: &mut Context<'ctx>, + word0: inkwell::values::IntValue<'ctx>, + word1: inkwell::values::IntValue<'ctx>, +) -> anyhow::Result> { + use crate::polkavm::context::pointer::heap::Keccak256TwoWords; + let function = context + .get_function(Keccak256TwoWords::NAME, false) + .expect("ICE: __revive_keccak256_two_words should be declared"); + let result = context + .build_call( + function.borrow().declaration(), + &[word0.into(), word1.into()], + "keccak256_pair_result", + ) + .expect("ICE: keccak256_two_words should return a value"); + Ok(result) +} diff --git a/crates/llvm-context/src/polkavm/evm/ether_gas.rs b/crates/llvm-context/src/polkavm/evm/ether_gas.rs index ab152644b..cfbeef808 100644 --- a/crates/llvm-context/src/polkavm/evm/ether_gas.rs +++ b/crates/llvm-context/src/polkavm/evm/ether_gas.rs @@ -30,6 +30,46 @@ pub fn value<'ctx>( context.build_load(output_pointer, "value_transferred") } +/// Calls the outlined `__revive_callvalue() -> i256` runtime function. +/// +/// This is functionally identical to [`value`] but calls a shared outlined function +/// instead of inlining the alloca+store+call+load sequence at every call site. +/// For contracts with many non-payable checks (e.g. OpenZeppelin ERC20: 37 sites), +/// this significantly reduces code size. +pub fn value_outlined<'ctx>( + context: &mut Context<'ctx>, +) -> anyhow::Result> { + use crate::polkavm::context::function::runtime::revive::CallValue; + use crate::polkavm::context::runtime::RuntimeFunction; + let function = context + .get_function(CallValue::NAME, false) + .expect("ICE: __revive_callvalue should be declared"); + let result = context + .build_call(function.borrow().declaration(), &[], "callvalue_result") + .expect("ICE: __revive_callvalue should return a value"); + Ok(result) +} + +/// Calls the outlined `__revive_callvalue_nonzero() -> i1` runtime function. +/// +/// Returns true (i1) if callvalue is nonzero. This is more efficient than +/// `value_outlined()` followed by `icmp ne i256 %cv, 0` because the +/// 256-bit comparison is done once inside the outlined function body, +/// and each call site only receives a single boolean flag. +pub fn value_nonzero_outlined<'ctx>( + context: &mut Context<'ctx>, +) -> anyhow::Result> { + use crate::polkavm::context::function::runtime::revive::CallValueNonzero; + use crate::polkavm::context::runtime::RuntimeFunction; + let function = context + .get_function(CallValueNonzero::NAME, false) + .expect("ICE: __revive_callvalue_nonzero should be declared"); + let result = context + .build_call(function.borrow().declaration(), &[], "callvalue_nonzero") + .expect("ICE: __revive_callvalue_nonzero should return a value"); + Ok(result) +} + /// Translates the `balance` instructions. pub fn balance<'ctx>( context: &mut Context<'ctx>, diff --git a/crates/llvm-context/src/polkavm/evm/memory.rs b/crates/llvm-context/src/polkavm/evm/memory.rs index f21eaf729..a5115fd47 100644 --- a/crates/llvm-context/src/polkavm/evm/memory.rs +++ b/crates/llvm-context/src/polkavm/evm/memory.rs @@ -1,9 +1,13 @@ //! Translates the heap memory operations. use inkwell::values::BasicValue; +use inkwell::values::BasicValueEnum; use revive_common::BYTE_LENGTH_BYTE; use crate::polkavm::context::address_space::AddressSpace; +use crate::polkavm::context::pointer::heap::{ + build_efficient_load_swap, build_efficient_store_swap, +}; use crate::polkavm::context::pointer::Pointer; use crate::polkavm::context::Context; @@ -81,6 +85,74 @@ pub fn store_byte<'ctx>( .builder() .build_store(pointer, value)? .set_alignment(BYTE_LENGTH_BYTE as u32) - .expect("Alignment is valid"); + .expect("ICE: alignment is valid"); + Ok(()) +} + +/// Builds an efficient 256-bit store with byte-swap at a pointer obtained via unchecked GEP +/// (no sbrk bounds check). For use by the newyork InlineByteSwap mode on constant offsets +/// within the static heap. +pub fn store_bswap_unchecked<'ctx>( + context: &Context<'ctx>, + offset: inkwell::values::IntValue<'ctx>, + value: inkwell::values::IntValue<'ctx>, +) -> anyhow::Result<()> { + let pointer = context.build_heap_gep_unchecked(offset)?; + build_efficient_store_swap(context, pointer.value, value) +} + +/// Builds an efficient 256-bit load with byte-swap at a pointer obtained via unchecked GEP +/// (no sbrk bounds check). For use by the newyork InlineByteSwap mode on constant offsets +/// within the static heap. +pub fn load_bswap_unchecked<'ctx>( + context: &Context<'ctx>, + offset: inkwell::values::IntValue<'ctx>, +) -> anyhow::Result> { + let pointer = context.build_heap_gep_unchecked(offset)?; + build_efficient_load_swap(context, pointer.value) +} + +/// Translates the `mload` instruction without byte-swapping, inlined. +/// This version inlines the load directly without a function call, +/// saving both call overhead and function body size when not all +/// memory accesses need native mode. +pub fn load_native_inline<'ctx>( + context: &mut Context<'ctx>, + offset: inkwell::values::IntValue<'ctx>, +) -> anyhow::Result> { + let length = context + .xlen_type() + .const_int(revive_common::BYTE_LENGTH_WORD as u64, false); + let pointer = context.build_heap_gep(offset, length)?; + let value = context + .builder() + .build_load(context.word_type(), pointer.value, "native_load")?; + context + .basic_block() + .get_last_instruction() + .expect("ICE: load instruction always exists") + .set_alignment(BYTE_LENGTH_BYTE as u32) + .expect("ICE: alignment is valid"); + Ok(value) +} + +/// Translates the `mstore` instruction without byte-swapping, inlined. +/// This version inlines the store directly without a function call, +/// saving both call overhead and function body size when not all +/// memory accesses need native mode. +pub fn store_native_inline<'ctx>( + context: &mut Context<'ctx>, + offset: inkwell::values::IntValue<'ctx>, + value: inkwell::values::IntValue<'ctx>, +) -> anyhow::Result<()> { + let length = context + .xlen_type() + .const_int(revive_common::BYTE_LENGTH_WORD as u64, false); + let pointer = context.build_heap_gep(offset, length)?; + context + .builder() + .build_store(pointer.value, value)? + .set_alignment(BYTE_LENGTH_BYTE as u32) + .expect("ICE: alignment is valid"); Ok(()) } diff --git a/crates/llvm-context/src/polkavm/evm/return.rs b/crates/llvm-context/src/polkavm/evm/return.rs index 84a7bd952..a6b7503a2 100644 --- a/crates/llvm-context/src/polkavm/evm/return.rs +++ b/crates/llvm-context/src/polkavm/evm/return.rs @@ -43,6 +43,37 @@ pub fn revert<'ctx>( ) } +/// Calls the outlined `__revive_revert_0()` function for empty reverts. +pub fn revert_empty_outlined(context: &mut Context) -> anyhow::Result<()> { + use crate::polkavm::context::function::runtime::revive::RevertEmpty; + use crate::polkavm::context::runtime::RuntimeFunction; + let function = context + .get_function(RevertEmpty::NAME, false) + .expect("ICE: __revive_revert_0 should be declared"); + context.build_call(function.borrow().declaration(), &[], "revert_empty"); + Ok(()) +} + +/// Calls the outlined `__revive_revert(length)` function for constant-length reverts. +/// +/// The length parameter is xlen-sized (already truncated from i256). +pub fn revert_outlined<'ctx>( + context: &mut Context<'ctx>, + length: inkwell::values::IntValue<'ctx>, +) -> anyhow::Result<()> { + use crate::polkavm::context::function::runtime::revive::Revert; + use crate::polkavm::context::runtime::RuntimeFunction; + let function = context + .get_function(Revert::NAME, false) + .expect("ICE: __revive_revert should be declared"); + context.build_call( + function.borrow().declaration(), + &[length.into()], + "revert_outlined", + ); + Ok(()) +} + /// Translates the `stop` instruction. /// Is the same as `return(0, 0)`. pub fn stop(context: &mut Context) -> anyhow::Result<()> { diff --git a/crates/llvm-context/src/target_machine/mod.rs b/crates/llvm-context/src/target_machine/mod.rs index f6f859288..73c83d4bc 100644 --- a/crates/llvm-context/src/target_machine/mod.rs +++ b/crates/llvm-context/src/target_machine/mod.rs @@ -29,7 +29,7 @@ impl TargetMachine { /// LLVM target features. pub const VM_FEATURES: &'static str = - "+e,+m,+a,+c,+zbb,+auipc-addi-fusion,+ld-add-fusion,+lui-addi-fusion,+xtheadcondmov,+relax"; + "+e,+m,+a,+c,+zbb,+auipc-addi-fusion,+ld-add-fusion,+lui-addi-fusion,+xtheadcondmov,+relax,+unaligned-scalar-mem"; /// A shortcut constructor. /// A separate instance for every optimization level is created. @@ -71,6 +71,15 @@ impl TargetMachine { } /// Runs the optimization passes on `module`. + /// + /// `MergeFunctions` is disabled because it can collapse `@deploy` and `@call` into a single + /// function body when their lowered control flow becomes equivalent (e.g. a bare `invalid()` + /// in both code sections). The resulting ELF has two exports pointing at the same block, + /// which triggers a non-determinism bug in polkavm-linker's reachability consistency check + /// (the exports are stored as `Vec` and compared by order, so equal-but-differently- + /// ordered vectors are rejected as inconsistent). Disabling the pass keeps the export + /// targets distinct and sidesteps the issue. The size cost is negligible for production + /// contracts — their `@deploy`/`@call` bodies diverge well before any merging opportunity. pub fn run_optimization_passes( &self, module: &inkwell::module::Module, @@ -79,11 +88,10 @@ impl TargetMachine { let pass_builder_options = inkwell::passes::PassBuilderOptions::create(); pass_builder_options.set_verify_each(self.optimizer_settings.is_verify_each_enabled); pass_builder_options.set_debug_logging(self.optimizer_settings.is_debug_logging_enabled); - pass_builder_options.set_loop_unrolling( self.optimizer_settings.level_middle_end_size == OptimizerSettingsSizeLevel::Zero, ); - pass_builder_options.set_merge_functions(true); + pass_builder_options.set_merge_functions(false); module.run_passes(passes, &self.target_machine, pass_builder_options) } diff --git a/crates/newyork/Cargo.toml b/crates/newyork/Cargo.toml new file mode 100644 index 000000000..1a753c882 --- /dev/null +++ b/crates/newyork/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "revive-newyork" +description = "NEW Yul OptimziR Kit - Custom IR layer for domain-specific optimizations" +version = "1.0.0" +authors.workspace = true +license.workspace = true +edition.workspace = true +repository.workspace = true +rust-version.workspace = true + +[lib] +doctest = false + +[dependencies] +anyhow = { workspace = true } +log = { workspace = true } +num = { workspace = true } +thiserror = { workspace = true } +inkwell = { workspace = true } + +revive-yul = { workspace = true } +revive-llvm-context = { workspace = true } +revive-common = { workspace = true } + +[dev-dependencies] diff --git a/crates/newyork/src/compound_outlining.rs b/crates/newyork/src/compound_outlining.rs new file mode 100644 index 000000000..4e78133cf --- /dev/null +++ b/crates/newyork/src/compound_outlining.rs @@ -0,0 +1,215 @@ +//! Compound outlining pass for newyork IR. +//! +//! This pass detects multi-statement patterns in the IR and replaces them +//! with compound IR nodes that get lowered to single outlined function calls. +//! Runs after simplification and before LLVM codegen. +//! +//! Detected patterns: +//! - Mapping SLoad: `let hash = keccak256_pair(key, slot); let value = sload(hash)` +//! → `let value = mapping_sload(key, slot)` +//! - Mapping SStore: `let hash = keccak256_pair(key, slot); sstore(hash, value)` +//! → `mapping_sstore(key, slot, value)` +use std::collections::BTreeMap; + +use crate::ir::{Block, Expression, Object, Region, Statement, Value}; + +/// Statistics from the compound outlining pass. +#[derive(Default, Debug)] +pub struct CompoundOutliningStatistics { + /// Number of mapping sload patterns replaced. + pub mapping_sloads: usize, + /// Number of mapping sstore patterns replaced. + pub mapping_sstores: usize, +} + +/// Run compound outlining on an entire object tree (including subobjects). +pub fn outline_compounds_in_object(object: &mut Object) -> CompoundOutliningStatistics { + let mut statistics = CompoundOutliningStatistics::default(); + + outline_block(&mut object.code, &mut statistics); + for function in object.functions.values_mut() { + outline_block(&mut function.body, &mut statistics); + } + + for sub_object in &mut object.subobjects { + let sub_object_statistics = outline_compounds_in_object(sub_object); + statistics.mapping_sloads += sub_object_statistics.mapping_sloads; + statistics.mapping_sstores += sub_object_statistics.mapping_sstores; + } + + statistics +} + +/// Process a block: detect and replace compound patterns. +fn outline_block(block: &mut Block, statistics: &mut CompoundOutliningStatistics) { + for statement in &mut block.statements { + outline_nested_regions(statement, statistics); + } + outline_statements(&mut block.statements, statistics); +} + +/// Recurse into nested regions within a statement. +fn outline_nested_regions(statement: &mut Statement, statistics: &mut CompoundOutliningStatistics) { + match statement { + Statement::If { + then_region, + else_region, + .. + } => { + outline_region(then_region, statistics); + if let Some(region) = else_region { + outline_region(region, statistics); + } + } + Statement::Switch { cases, default, .. } => { + for case in cases { + outline_region(&mut case.body, statistics); + } + if let Some(default_region) = default { + outline_region(default_region, statistics); + } + } + Statement::For { + condition_statements, + body, + post, + .. + } => { + for statement in condition_statements.iter_mut() { + outline_nested_regions(statement, statistics); + } + outline_region(body, statistics); + outline_region(post, statistics); + } + Statement::Block(region) => { + outline_region(region, statistics); + } + _ => {} + } +} + +/// Process a region. +fn outline_region(region: &mut Region, statistics: &mut CompoundOutliningStatistics) { + for statement in &mut region.statements { + outline_nested_regions(statement, statistics); + } + outline_statements(&mut region.statements, statistics); +} + +/// Count how many times each ValueId is referenced (used) in a statement list, +/// recursing through nested regions and counting yields. +fn count_value_uses(statements: &[Statement]) -> BTreeMap { + let mut counts = BTreeMap::new(); + for statement in statements { + statement.for_each_value_id(&mut |id| { + *counts.entry(id.0).or_insert(0) += 1; + }); + } + counts +} + +/// Core transformation: scan a statement list for compound patterns and replace them. +/// +/// Detects two patterns: +/// 1. MappingSLoad: `let hash = keccak256_pair(key, slot); ... let value = sload(hash)` +/// where hash has exactly one use (the sload). +/// 2. MappingSStore: `let hash = keccak256_pair(key, slot); ... sstore(hash, value)` +/// where hash has exactly one use (the sstore). +fn outline_statements( + statements: &mut Vec, + statistics: &mut CompoundOutliningStatistics, +) { + let use_counts = count_value_uses(statements); + + let mut keccak_definitions: BTreeMap = BTreeMap::new(); + for (index, statement) in statements.iter().enumerate() { + if let Statement::Let { + bindings, + value: Expression::Keccak256Pair { word0, word1 }, + } = statement + { + if bindings.len() == 1 { + keccak_definitions.insert(bindings[0].0, (index, *word0, *word1)); + } + } + } + + if keccak_definitions.is_empty() { + return; + } + + let mut transformations: Vec<(usize, Statement, usize)> = Vec::new(); + + for (index, statement) in statements.iter().enumerate() { + match statement { + Statement::Let { + bindings, + value: Expression::SLoad { key, .. }, + } if bindings.len() == 1 => { + if let Some((definition_index, word0, word1)) = keccak_definitions.get(&key.id.0) { + if use_counts.get(&key.id.0).copied().unwrap_or(0) == 1 { + transformations.push(( + index, + Statement::Let { + bindings: bindings.clone(), + value: Expression::MappingSLoad { + key: *word0, + slot: *word1, + }, + }, + *definition_index, + )); + } + } + } + Statement::SStore { key, value, .. } => { + if let Some((definition_index, word0, word1)) = keccak_definitions.get(&key.id.0) { + if use_counts.get(&key.id.0).copied().unwrap_or(0) == 1 { + transformations.push(( + index, + Statement::MappingSStore { + key: *word0, + slot: *word1, + value: *value, + }, + *definition_index, + )); + } + } + } + _ => {} + } + } + + if transformations.is_empty() { + return; + } + + let mut indices_to_remove = std::collections::BTreeSet::new(); + let mut replacements: BTreeMap = BTreeMap::new(); + + for (statement_index, new_statement, definition_index) in transformations { + if !indices_to_remove.contains(&definition_index) + && !indices_to_remove.contains(&statement_index) + { + indices_to_remove.insert(definition_index); + replacements.insert(statement_index, new_statement); + match &replacements[&statement_index] { + Statement::Let { + value: Expression::MappingSLoad { .. }, + .. + } => statistics.mapping_sloads += 1, + Statement::MappingSStore { .. } => statistics.mapping_sstores += 1, + _ => {} + } + } + } + + for (index, new_statement) in &replacements { + statements[*index] = new_statement.clone(); + } + + for index in indices_to_remove.into_iter().rev() { + statements.remove(index); + } +} diff --git a/crates/newyork/src/from_yul.rs b/crates/newyork/src/from_yul.rs new file mode 100644 index 000000000..86e0fb527 --- /dev/null +++ b/crates/newyork/src/from_yul.rs @@ -0,0 +1,1526 @@ +//! Translation from Yul AST to newyork IR. +//! +//! This module implements the visitor that translates Yul AST into SSA form IR. + +use std::collections::BTreeMap; + +use num::BigUint; + +use revive_yul::lexer::token::lexeme::literal::boolean::Boolean as BooleanLiteral; +use revive_yul::lexer::token::lexeme::literal::integer::Integer as IntegerLiteral; +use revive_yul::lexer::token::lexeme::literal::Literal as LexicalLiteral; +use revive_yul::parser::statement::assignment::Assignment; +use revive_yul::parser::statement::block::Block as YulBlock; +use revive_yul::parser::statement::expression::function_call::name::Name as FunctionName; +use revive_yul::parser::statement::expression::function_call::FunctionCall; +use revive_yul::parser::statement::expression::literal::Literal as YulLiteral; +use revive_yul::parser::statement::expression::Expression as YulExpression; +use revive_yul::parser::statement::for_loop::ForLoop; +use revive_yul::parser::statement::function_definition::FunctionDefinition; +use revive_yul::parser::statement::if_conditional::IfConditional; +use revive_yul::parser::statement::object::Object as YulObject; +use revive_yul::parser::statement::switch::Switch; +use revive_yul::parser::statement::variable_declaration::VariableDeclaration; +use revive_yul::parser::statement::Statement as YulStatement; + +use crate::ir::{ + BinaryOperation, BitWidth, Block, CallKind, CreateKind, Expression, Function, FunctionId, + MemoryRegion, Object, Region, Statement, SwitchCase, Type, UnaryOperation, Value, +}; +use crate::ssa::SsaBuilder; + +/// Error type for Yul to IR translation. +#[derive(Debug, thiserror::Error)] +pub enum TranslationError { + /// A variable name was referenced before being declared. + #[error("Undefined variable: {0}")] + UndefinedVariable(String), + + /// A function name was referenced before any matching definition was discovered. + #[error("Undefined function: {0}")] + UndefinedFunction(String), + + /// A literal could not be parsed (malformed integer, hex, or escape sequence). + #[error("Invalid literal: {0}")] + InvalidLiteral(String), + + /// A Yul construct was encountered that this translator does not lower. + #[error("Unsupported construct: {0}")] + Unsupported(String), +} + +/// Translator from Yul AST to newyork IR. +pub struct YulTranslator { + /// SSA builder for tracking variables. + ssa: SsaBuilder, + /// Function name to ID mapping. + function_ids: BTreeMap, + /// Next function ID to allocate. + next_function_id: u32, + /// Collected functions. + functions: BTreeMap, + /// Return variable names for the current function being translated. + /// Used to look up current SSA values when translating `leave` statements. + current_return_variable_names: Vec, + /// Stack of loop-carried variable names for the enclosing for loops. + /// Used to collect current values when translating `break` and `continue`. + loop_variable_names_stack: Vec>, +} + +impl Default for YulTranslator { + fn default() -> Self { + Self::new() + } +} + +impl YulTranslator { + /// Creates a new translator. + pub fn new() -> Self { + YulTranslator { + ssa: SsaBuilder::new(), + function_ids: BTreeMap::new(), + next_function_id: 0, + functions: BTreeMap::new(), + current_return_variable_names: Vec::new(), + loop_variable_names_stack: Vec::new(), + } + } + + /// Translates a Yul object to IR. + pub fn translate_object( + &mut self, + yul_object: &YulObject, + ) -> std::result::Result { + self.collect_functions(&yul_object.code.block)?; + let code = self.translate_block(&yul_object.code.block)?; + let functions = std::mem::take(&mut self.functions); + + let mut subobjects = Vec::new(); + if let Some(inner_object) = &yul_object.inner_object { + let mut inner_translator = YulTranslator::new(); + subobjects.push(inner_translator.translate_object(inner_object)?); + } + + Ok(Object { + name: yul_object.identifier.clone(), + code, + functions, + subobjects, + data: BTreeMap::new(), + }) + } + + /// First pass: walk the AST and pre-allocate `FunctionId`s and parameter `ValueId`s for + /// every Yul function definition (including those nested inside blocks, if/for/switch). + /// This lets later passes resolve forward references and reuse parameter IDs across + /// recursive translation calls. + fn collect_functions(&mut self, block: &YulBlock) -> std::result::Result<(), TranslationError> { + for statement in &block.statements { + if let YulStatement::FunctionDefinition(function_definition) = statement { + let id = self.allocate_function_id(&function_definition.identifier); + let mut function = Function::new(id, function_definition.identifier.clone()); + + for _parameter in &function_definition.arguments { + let parameter_id = self.ssa.fresh_id(); + function + .parameters + .push((parameter_id, Type::Int(BitWidth::I256))); + } + for _ in &function_definition.result { + function.returns.push(Type::Int(BitWidth::I256)); + } + + self.functions.insert(id, function); + } + + match statement { + YulStatement::Block(inner) => self.collect_functions(inner)?, + YulStatement::IfConditional(if_conditional) => { + self.collect_functions(&if_conditional.block)? + } + YulStatement::ForLoop(for_loop) => { + self.collect_functions(&for_loop.initializer)?; + self.collect_functions(&for_loop.body)?; + self.collect_functions(&for_loop.finalizer)?; + } + YulStatement::Switch(switch) => { + for case in &switch.cases { + self.collect_functions(&case.block)?; + } + if let Some(default) = &switch.default { + self.collect_functions(default)?; + } + } + _ => {} + } + } + Ok(()) + } + + /// Allocates a function ID for a name. + fn allocate_function_id(&mut self, name: &str) -> FunctionId { + if let Some(&id) = self.function_ids.get(name) { + return id; + } + let id = FunctionId::new(self.next_function_id); + self.next_function_id += 1; + self.function_ids.insert(name.to_string(), id); + id + } + + /// Looks up a function ID by name. + fn lookup_function(&self, name: &str) -> Option { + self.function_ids.get(name).copied() + } + + /// Translates a Yul block to an IR block. + fn translate_block( + &mut self, + block: &YulBlock, + ) -> std::result::Result { + let mut ir_block = Block::new(); + + for statement in &block.statements { + let ir_statements = self.translate_statement(statement)?; + for ir_statement in ir_statements { + ir_block.push(ir_statement); + } + } + + Ok(ir_block) + } + + /// Translates a Yul block to an IR region. + fn translate_region( + &mut self, + block: &YulBlock, + ) -> std::result::Result { + let mut region = Region::new(); + + for statement in &block.statements { + let ir_statements = self.translate_statement(statement)?; + for ir_statement in ir_statements { + region.push(ir_statement); + } + } + + Ok(region) + } + + /// Translates a Yul statement to IR statements. + fn translate_statement( + &mut self, + statement: &YulStatement, + ) -> std::result::Result, TranslationError> { + match statement { + YulStatement::VariableDeclaration(variable_declaration) => { + self.translate_variable_declaration(variable_declaration) + } + YulStatement::Assignment(assignment) => self.translate_assignment(assignment), + YulStatement::Expression(expression) => self.translate_expression_statement(expression), + YulStatement::Block(block) => { + let parent_scope = self.ssa.current_scope().clone(); + self.ssa.enter_scope(); + let region = self.translate_region(block)?; + let block_scope = self.ssa.exit_scope(); + + for (name, value) in &block_scope { + if parent_scope.contains_key(name) { + self.ssa.assign(name, *value); + } + } + + Ok(vec![Statement::Block(region)]) + } + YulStatement::IfConditional(if_conditional) => self.translate_if(if_conditional), + YulStatement::Switch(switch) => self.translate_switch(switch), + YulStatement::ForLoop(for_loop) => self.translate_for_loop(for_loop), + YulStatement::FunctionDefinition(function_definition) => { + self.translate_function_definition(function_definition) + } + YulStatement::Continue(_) => { + let values = self.collect_loop_variable_values(); + Ok(vec![Statement::Continue { values }]) + } + YulStatement::Break(_) => { + let values = self.collect_loop_variable_values(); + Ok(vec![Statement::Break { values }]) + } + YulStatement::Leave(_) => { + let mut return_values = Vec::new(); + for name in &self.current_return_variable_names { + if let Some(value) = self.ssa.lookup(name) { + return_values.push(value); + } + } + Ok(vec![Statement::Leave { return_values }]) + } + YulStatement::Object(_) | YulStatement::Code(_) => Ok(vec![]), + } + } + + /// Translates a variable declaration. Tuple destructuring (multiple bindings) requires the + /// initializer to be a function call that returns the matching number of values; the absence + /// of an initializer yields zero-initialized i256 bindings. + fn translate_variable_declaration( + &mut self, + variable_declaration: &VariableDeclaration, + ) -> std::result::Result, TranslationError> { + let mut statements = Vec::new(); + + if let Some(expression) = &variable_declaration.expression { + let (initializer_statements, initializer_value) = + self.translate_expression(expression)?; + statements.extend(initializer_statements); + + if variable_declaration.bindings.len() == 1 { + let binding = &variable_declaration.bindings[0]; + let value_id = self.ssa.fresh_id(); + let value = Value::new(value_id, Type::Int(BitWidth::I256)); + self.ssa.declare(&binding.inner, value); + + statements.push(Statement::Let { + bindings: vec![value_id], + value: initializer_value, + }); + } else { + let mut bindings = Vec::new(); + for binding in &variable_declaration.bindings { + let value_id = self.ssa.fresh_id(); + let value = Value::new(value_id, Type::Int(BitWidth::I256)); + self.ssa.declare(&binding.inner, value); + bindings.push(value_id); + } + + statements.push(Statement::Let { + bindings, + value: initializer_value, + }); + } + } else { + for binding in &variable_declaration.bindings { + let value_id = self.ssa.fresh_id(); + let value = Value::new(value_id, Type::Int(BitWidth::I256)); + self.ssa.declare(&binding.inner, value); + + statements.push(Statement::Let { + bindings: vec![value_id], + value: Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Int(BitWidth::I256), + }, + }); + } + } + + Ok(statements) + } + + /// Translates an assignment. Multiple bindings imply tuple destructuring of a function call. + fn translate_assignment( + &mut self, + assignment: &Assignment, + ) -> std::result::Result, TranslationError> { + let mut statements = Vec::new(); + + let (initializer_statements, initializer_value) = + self.translate_expression(&assignment.initializer)?; + statements.extend(initializer_statements); + + if assignment.bindings.len() == 1 { + let binding = &assignment.bindings[0]; + let value_id = self.ssa.fresh_id(); + let value = Value::new(value_id, Type::Int(BitWidth::I256)); + self.ssa.assign(&binding.inner, value); + + statements.push(Statement::Let { + bindings: vec![value_id], + value: initializer_value, + }); + } else { + let mut bindings = Vec::new(); + for binding in &assignment.bindings { + let value_id = self.ssa.fresh_id(); + let value = Value::new(value_id, Type::Int(BitWidth::I256)); + self.ssa.assign(&binding.inner, value); + bindings.push(value_id); + } + + statements.push(Statement::Let { + bindings, + value: initializer_value, + }); + } + + Ok(statements) + } + + /// Translates an expression used as a statement; the expression result is discarded. + fn translate_expression_statement( + &mut self, + expression: &YulExpression, + ) -> std::result::Result, TranslationError> { + let (mut statements, ir_expression) = self.translate_expression(expression)?; + statements.push(Statement::Expression(ir_expression)); + Ok(statements) + } + + /// Translates an expression, returning any required setup statements and the expression. + fn translate_expression( + &mut self, + expression: &YulExpression, + ) -> std::result::Result<(Vec, Expression), TranslationError> { + match expression { + YulExpression::Literal(literal) => { + let value = self.parse_literal(literal)?; + Ok(( + vec![], + Expression::Literal { + value, + value_type: Type::Int(BitWidth::I256), + }, + )) + } + YulExpression::Identifier(identifier) => { + let value = self + .ssa + .lookup(&identifier.inner) + .ok_or_else(|| TranslationError::UndefinedVariable(identifier.inner.clone()))?; + Ok((vec![], Expression::Var(value.id))) + } + YulExpression::FunctionCall(call) => self.translate_function_call(call), + } + } + + /// Translates a function call. The `DataSize`, `DataOffset`, `LoadImmutable`, `SetImmutable`, + /// and `LinkerSymbol` builtins receive a string literal argument that cannot be evaluated as + /// an expression, so they are extracted before the generic argument-translation loop runs. + fn translate_function_call( + &mut self, + call: &FunctionCall, + ) -> std::result::Result<(Vec, Expression), TranslationError> { + match &call.name { + FunctionName::DataSize => { + let id = self.extract_string_literal(&call.arguments)?; + return Ok((vec![], Expression::DataSize { id })); + } + FunctionName::DataOffset => { + let id = self.extract_string_literal(&call.arguments)?; + return Ok((vec![], Expression::DataOffset { id })); + } + FunctionName::LoadImmutable => { + let key = self.extract_string_literal(&call.arguments)?; + return Ok((vec![], Expression::LoadImmutable { key })); + } + FunctionName::SetImmutable => { + let key = self.extract_string_literal_at(&call.arguments, 1)?; + let (mut statements, value_expression) = + self.translate_expression(&call.arguments[2])?; + let value = match value_expression { + Expression::Var(id) => Value::new(id, Type::Int(BitWidth::I256)), + _ => { + let temporary_id = self.ssa.fresh_id(); + statements.push(Statement::Let { + bindings: vec![temporary_id], + value: value_expression, + }); + Value::new(temporary_id, Type::Int(BitWidth::I256)) + } + }; + statements.push(Statement::SetImmutable { key, value }); + return Ok(( + statements, + Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }, + )); + } + FunctionName::LinkerSymbol => { + let path = self.extract_string_literal(&call.arguments)?; + return Ok((vec![], Expression::LinkerSymbol { path })); + } + _ => {} + } + + let mut statements = Vec::new(); + let mut arguments = Vec::new(); + + for outer_argument_expression in call.arguments.iter().rev() { + let (argument_statements, argument_expression) = + self.translate_expression(outer_argument_expression)?; + statements.extend(argument_statements); + + let argument_value = match argument_expression { + Expression::Var(id) => Value::new(id, Type::Int(BitWidth::I256)), + _ => { + let temporary_id = self.ssa.fresh_id(); + statements.push(Statement::Let { + bindings: vec![temporary_id], + value: argument_expression, + }); + Value::new(temporary_id, Type::Int(BitWidth::I256)) + } + }; + arguments.push(argument_value); + } + arguments.reverse(); + + let expression = self.translate_builtin_or_call(&call.name, arguments, &mut statements)?; + Ok((statements, expression)) + } + + /// Extracts a string literal from the first argument. + fn extract_string_literal( + &self, + arguments: &[YulExpression], + ) -> std::result::Result { + self.extract_string_literal_at(arguments, 0) + } + + /// Extracts a string literal from an argument at a specific index. + fn extract_string_literal_at( + &self, + arguments: &[YulExpression], + index: usize, + ) -> std::result::Result { + if arguments.len() <= index { + return Err(TranslationError::Unsupported( + "Missing string literal argument".to_string(), + )); + } + + match &arguments[index] { + YulExpression::Literal(literal) => match &literal.inner { + LexicalLiteral::String(string) => Ok(string.inner.clone()), + _ => Ok(self.parse_literal(literal)?.to_string()), + }, + _ => Err(TranslationError::Unsupported( + "Expected literal argument".to_string(), + )), + } + } + + /// Translates a builtin function or user-defined call. + fn translate_builtin_or_call( + &mut self, + name: &FunctionName, + arguments: Vec, + statements: &mut Vec, + ) -> std::result::Result { + match name { + FunctionName::Add => Ok(binary_op(BinaryOperation::Add, &arguments)), + FunctionName::Sub => Ok(binary_op(BinaryOperation::Sub, &arguments)), + FunctionName::Mul => Ok(binary_op(BinaryOperation::Mul, &arguments)), + FunctionName::Div => Ok(binary_op(BinaryOperation::Div, &arguments)), + FunctionName::Sdiv => Ok(binary_op(BinaryOperation::SDiv, &arguments)), + FunctionName::Mod => Ok(binary_op(BinaryOperation::Mod, &arguments)), + FunctionName::Smod => Ok(binary_op(BinaryOperation::SMod, &arguments)), + FunctionName::Exp => Ok(binary_op(BinaryOperation::Exp, &arguments)), + FunctionName::AddMod => Ok(ternary_op(BinaryOperation::AddMod, &arguments)), + FunctionName::MulMod => Ok(ternary_op(BinaryOperation::MulMod, &arguments)), + + FunctionName::Lt => Ok(binary_op(BinaryOperation::Lt, &arguments)), + FunctionName::Gt => Ok(binary_op(BinaryOperation::Gt, &arguments)), + FunctionName::Slt => Ok(binary_op(BinaryOperation::Slt, &arguments)), + FunctionName::Sgt => Ok(binary_op(BinaryOperation::Sgt, &arguments)), + FunctionName::Eq => Ok(binary_op(BinaryOperation::Eq, &arguments)), + FunctionName::IsZero => Ok(unary_op(UnaryOperation::IsZero, &arguments)), + + FunctionName::And => Ok(binary_op(BinaryOperation::And, &arguments)), + FunctionName::Or => Ok(binary_op(BinaryOperation::Or, &arguments)), + FunctionName::Xor => Ok(binary_op(BinaryOperation::Xor, &arguments)), + FunctionName::Not => Ok(unary_op(UnaryOperation::Not, &arguments)), + FunctionName::Shl => Ok(binary_op(BinaryOperation::Shl, &arguments)), + FunctionName::Shr => Ok(binary_op(BinaryOperation::Shr, &arguments)), + FunctionName::Sar => Ok(binary_op(BinaryOperation::Sar, &arguments)), + FunctionName::Byte => Ok(binary_op(BinaryOperation::Byte, &arguments)), + FunctionName::SignExtend => Ok(binary_op(BinaryOperation::SignExtend, &arguments)), + + FunctionName::MLoad => Ok(Expression::MLoad { + offset: arguments[0], + region: MemoryRegion::Unknown, + }), + FunctionName::MStore => { + statements.push(Statement::MStore { + offset: arguments[0], + value: arguments[1], + region: MemoryRegion::Unknown, + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + FunctionName::MStore8 => { + statements.push(Statement::MStore8 { + offset: arguments[0], + value: arguments[1], + region: MemoryRegion::Unknown, + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + FunctionName::MCopy => { + statements.push(Statement::MCopy { + dest: arguments[0], + src: arguments[1], + length: arguments[2], + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + + FunctionName::SLoad => Ok(Expression::SLoad { + key: arguments[0], + static_slot: None, + }), + FunctionName::SStore => { + statements.push(Statement::SStore { + key: arguments[0], + value: arguments[1], + static_slot: None, + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + FunctionName::TLoad => Ok(Expression::TLoad { key: arguments[0] }), + FunctionName::TStore => { + statements.push(Statement::TStore { + key: arguments[0], + value: arguments[1], + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + + FunctionName::CallDataLoad => Ok(Expression::CallDataLoad { + offset: arguments[0], + }), + FunctionName::CallDataSize => Ok(Expression::CallDataSize), + FunctionName::CallValue => Ok(Expression::CallValue), + FunctionName::Caller => Ok(Expression::Caller), + FunctionName::Origin => Ok(Expression::Origin), + FunctionName::Address => Ok(Expression::Address), + FunctionName::Balance => Ok(Expression::Balance { + address: arguments[0], + }), + FunctionName::SelfBalance => Ok(Expression::SelfBalance), + FunctionName::Gas => Ok(Expression::Gas), + FunctionName::GasLimit => Ok(Expression::GasLimit), + FunctionName::GasPrice => Ok(Expression::GasPrice), + FunctionName::ChainId => Ok(Expression::ChainId), + FunctionName::Number => Ok(Expression::Number), + FunctionName::Timestamp => Ok(Expression::Timestamp), + FunctionName::BlockHash => Ok(Expression::BlockHash { + number: arguments[0], + }), + FunctionName::CoinBase => Ok(Expression::Coinbase), + FunctionName::Difficulty | FunctionName::Prevrandao => Ok(Expression::Difficulty), + FunctionName::BaseFee => Ok(Expression::BaseFee), + FunctionName::BlobBaseFee => Ok(Expression::BlobBaseFee), + FunctionName::BlobHash => Ok(Expression::BlobHash { + index: arguments[0], + }), + FunctionName::MSize => Ok(Expression::MSize), + FunctionName::CodeSize => Ok(Expression::CodeSize), + FunctionName::ExtCodeSize => Ok(Expression::ExtCodeSize { + address: arguments[0], + }), + FunctionName::ExtCodeHash => Ok(Expression::ExtCodeHash { + address: arguments[0], + }), + FunctionName::ReturnDataSize => Ok(Expression::ReturnDataSize), + + FunctionName::Return => { + statements.push(Statement::Return { + offset: arguments[0], + length: arguments[1], + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + FunctionName::Revert => { + statements.push(Statement::Revert { + offset: arguments[0], + length: arguments[1], + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + FunctionName::Stop => { + statements.push(Statement::Stop); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + FunctionName::Invalid => { + statements.push(Statement::Invalid); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + FunctionName::SelfDestruct => { + statements.push(Statement::SelfDestruct { + address: arguments[0], + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + + FunctionName::Keccak256 => Ok(Expression::Keccak256 { + offset: arguments[0], + length: arguments[1], + }), + + FunctionName::Call => { + let result_id = self.ssa.fresh_id(); + statements.push(Statement::ExternalCall { + kind: CallKind::Call, + gas: arguments[0], + address: arguments[1], + value: Some(arguments[2]), + args_offset: arguments[3], + args_length: arguments[4], + ret_offset: arguments[5], + ret_length: arguments[6], + result: result_id, + }); + Ok(Expression::Var(result_id)) + } + FunctionName::CallCode => { + let result_id = self.ssa.fresh_id(); + statements.push(Statement::ExternalCall { + kind: CallKind::CallCode, + gas: arguments[0], + address: arguments[1], + value: Some(arguments[2]), + args_offset: arguments[3], + args_length: arguments[4], + ret_offset: arguments[5], + ret_length: arguments[6], + result: result_id, + }); + Ok(Expression::Var(result_id)) + } + FunctionName::DelegateCall => { + let result_id = self.ssa.fresh_id(); + statements.push(Statement::ExternalCall { + kind: CallKind::DelegateCall, + gas: arguments[0], + address: arguments[1], + value: None, + args_offset: arguments[2], + args_length: arguments[3], + ret_offset: arguments[4], + ret_length: arguments[5], + result: result_id, + }); + Ok(Expression::Var(result_id)) + } + FunctionName::StaticCall => { + let result_id = self.ssa.fresh_id(); + statements.push(Statement::ExternalCall { + kind: CallKind::StaticCall, + gas: arguments[0], + address: arguments[1], + value: None, + args_offset: arguments[2], + args_length: arguments[3], + ret_offset: arguments[4], + ret_length: arguments[5], + result: result_id, + }); + Ok(Expression::Var(result_id)) + } + + FunctionName::Create => { + let result_id = self.ssa.fresh_id(); + statements.push(Statement::Create { + kind: CreateKind::Create, + value: arguments[0], + offset: arguments[1], + length: arguments[2], + salt: None, + result: result_id, + }); + Ok(Expression::Var(result_id)) + } + FunctionName::Create2 => { + let result_id = self.ssa.fresh_id(); + statements.push(Statement::Create { + kind: CreateKind::Create2, + value: arguments[0], + offset: arguments[1], + length: arguments[2], + salt: Some(arguments[3]), + result: result_id, + }); + Ok(Expression::Var(result_id)) + } + + FunctionName::Log0 => { + statements.push(Statement::Log { + offset: arguments[0], + length: arguments[1], + topics: vec![], + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + FunctionName::Log1 => { + statements.push(Statement::Log { + offset: arguments[0], + length: arguments[1], + topics: vec![arguments[2]], + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + FunctionName::Log2 => { + statements.push(Statement::Log { + offset: arguments[0], + length: arguments[1], + topics: vec![arguments[2], arguments[3]], + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + FunctionName::Log3 => { + statements.push(Statement::Log { + offset: arguments[0], + length: arguments[1], + topics: vec![arguments[2], arguments[3], arguments[4]], + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + FunctionName::Log4 => { + statements.push(Statement::Log { + offset: arguments[0], + length: arguments[1], + topics: vec![arguments[2], arguments[3], arguments[4], arguments[5]], + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + + FunctionName::CodeCopy => { + statements.push(Statement::CodeCopy { + dest: arguments[0], + offset: arguments[1], + length: arguments[2], + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + FunctionName::ExtCodeCopy => { + statements.push(Statement::ExtCodeCopy { + address: arguments[0], + dest: arguments[1], + offset: arguments[2], + length: arguments[3], + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + FunctionName::ReturnDataCopy => { + statements.push(Statement::ReturnDataCopy { + dest: arguments[0], + offset: arguments[1], + length: arguments[2], + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + FunctionName::CallDataCopy => { + statements.push(Statement::CallDataCopy { + dest: arguments[0], + offset: arguments[1], + length: arguments[2], + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + FunctionName::DataCopy => { + statements.push(Statement::DataCopy { + dest: arguments[0], + offset: arguments[1], + length: arguments[2], + }); + Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }) + } + + FunctionName::DataSize | FunctionName::DataOffset => { + unreachable!("ICE: DataSize/DataOffset handled in translate_function_call") + } + + FunctionName::Pop => Ok(Expression::Literal { + value: BigUint::from(0u32), + value_type: Type::Void, + }), + FunctionName::MemoryGuard => { + if !arguments.is_empty() { + Ok(Expression::Var(arguments[0].id)) + } else { + Ok(Expression::Literal { + value: BigUint::from(0x80u32), + value_type: Type::Int(BitWidth::I256), + }) + } + } + FunctionName::LinkerSymbol => { + unreachable!("ICE: LinkerSymbol handled in translate_function_call") + } + + FunctionName::Pc => Err(TranslationError::Unsupported("pc".to_string())), + + FunctionName::Clz => Ok(unary_op(UnaryOperation::Clz, &arguments)), + + FunctionName::LoadImmutable | FunctionName::SetImmutable => { + unreachable!("LoadImmutable/SetImmutable handled in translate_function_call") + } + + FunctionName::Verbatim { .. } => { + Err(TranslationError::Unsupported("verbatim".to_string())) + } + + FunctionName::UserDefined(name) => { + let function_id = self + .lookup_function(name) + .ok_or_else(|| TranslationError::UndefinedFunction(name.clone()))?; + Ok(Expression::Call { + function: function_id, + arguments, + }) + } + } + } + + /// Translates an if statement. + fn translate_if( + &mut self, + if_conditional: &IfConditional, + ) -> std::result::Result, TranslationError> { + let mut statements = Vec::new(); + + let (condition_statements, condition_expression) = + self.translate_expression(&if_conditional.condition)?; + statements.extend(condition_statements); + + let condition_value = match condition_expression { + Expression::Var(id) => Value::new(id, Type::Int(BitWidth::I256)), + _ => { + let temporary_id = self.ssa.fresh_id(); + statements.push(Statement::Let { + bindings: vec![temporary_id], + value: condition_expression, + }); + Value::new(temporary_id, Type::Int(BitWidth::I256)) + } + }; + + let scope_before = self.ssa.current_scope().clone(); + + self.ssa.enter_scope(); + let then_region = self.translate_region(&if_conditional.block)?; + let then_scope = self.ssa.exit_scope(); + + let mut inputs = Vec::new(); + let mut outputs = Vec::new(); + let mut modified_vars = Vec::new(); + + for (name, &then_value) in &then_scope { + if let Some(&before_value) = scope_before.get(name) { + if then_value.id != before_value.id { + modified_vars.push((name.clone(), before_value, then_value)); + inputs.push(before_value); + } + } + } + + for (name, before_value, _then_value) in &modified_vars { + let output_id = self.ssa.fresh_id(); + outputs.push(output_id); + self.ssa + .assign(name, Value::new(output_id, before_value.value_type)); + } + + let mut then_with_yields = then_region; + for (_, _, then_value) in &modified_vars { + then_with_yields.yields.push(*then_value); + } + + let else_region = if modified_vars.is_empty() { + None + } else { + let mut else_region = Region::new(); + for (_, before_value, _) in &modified_vars { + else_region.yields.push(*before_value); + } + Some(else_region) + }; + + statements.push(Statement::If { + condition: condition_value, + inputs, + then_region: then_with_yields, + else_region, + outputs, + }); + + Ok(statements) + } + + /// Translates a switch statement. + fn translate_switch( + &mut self, + switch: &Switch, + ) -> std::result::Result, TranslationError> { + let mut statements = Vec::new(); + + let (scrutinee_statements, scrutinee_expression) = + self.translate_expression(&switch.expression)?; + statements.extend(scrutinee_statements); + + let scrutinee_value = match scrutinee_expression { + Expression::Var(id) => Value::new(id, Type::Int(BitWidth::I256)), + _ => { + let temporary_id = self.ssa.fresh_id(); + statements.push(Statement::Let { + bindings: vec![temporary_id], + value: scrutinee_expression, + }); + Value::new(temporary_id, Type::Int(BitWidth::I256)) + } + }; + + let scope_before = self.ssa.current_scope().clone(); + + let mut cases = Vec::new(); + let mut all_scopes = Vec::new(); + + for case in &switch.cases { + self.ssa.restore_scope(scope_before.clone()); + self.ssa.enter_scope(); + let case_region = self.translate_region(&case.block)?; + let case_scope = self.ssa.exit_scope(); + all_scopes.push(case_scope); + + let case_value = self.parse_literal(&case.literal)?; + cases.push((case_value, case_region)); + } + + let (default_scope, default_region) = if let Some(default_block) = &switch.default { + self.ssa.restore_scope(scope_before.clone()); + self.ssa.enter_scope(); + let region = self.translate_region(default_block)?; + let scope = self.ssa.exit_scope(); + (Some(scope), Some(region)) + } else { + (None, None) + }; + + let mut modified_vars: BTreeMap = BTreeMap::new(); + + for case_scope in &all_scopes { + for (name, &value) in case_scope { + if let Some(&before_value) = scope_before.get(name) { + if value.id != before_value.id { + modified_vars.entry(name.clone()).or_insert(before_value); + } + } + } + } + + if let Some(ref default_scope) = default_scope { + for (name, &value) in default_scope { + if let Some(&before_value) = scope_before.get(name) { + if value.id != before_value.id { + modified_vars.entry(name.clone()).or_insert(before_value); + } + } + } + } + + let modified_names: Vec = modified_vars.keys().cloned().collect(); + + let mut inputs = Vec::new(); + let mut outputs = Vec::new(); + let mut output_names = Vec::new(); + + for name in &modified_names { + if let Some(&before_value) = modified_vars.get(name) { + inputs.push(before_value); + let output_id = self.ssa.fresh_id(); + outputs.push(output_id); + output_names.push((name.clone(), Value::new(output_id, before_value.value_type))); + } + } + + let mut cases_with_yields = Vec::new(); + for (index, (case_value, mut case_region)) in cases.into_iter().enumerate() { + let case_scope = &all_scopes[index]; + for name in &modified_names { + let before_value = modified_vars.get(name).copied().unwrap(); + let value = case_scope.get(name).copied().unwrap_or(before_value); + case_region.yields.push(value); + } + cases_with_yields.push(SwitchCase { + value: case_value, + body: case_region, + }); + } + + let default_with_yields = if let Some(mut region) = default_region { + let default_scope = default_scope.as_ref().unwrap(); + for name in &modified_names { + let before_value = modified_vars.get(name).copied().unwrap(); + let value = default_scope.get(name).copied().unwrap_or(before_value); + region.yields.push(value); + } + Some(region) + } else if !modified_names.is_empty() { + let mut region = Region::new(); + for name in &modified_names { + let before_value = modified_vars.get(name).copied().unwrap(); + region.yields.push(before_value); + } + Some(region) + } else { + None + }; + + self.ssa.restore_scope(scope_before); + for (name, value) in output_names { + self.ssa.assign(&name, value); + } + + statements.push(Statement::Switch { + scrutinee: scrutinee_value, + inputs, + cases: cases_with_yields, + default: default_with_yields, + outputs, + }); + + Ok(statements) + } + + /// Translates a for loop. + fn translate_for_loop( + &mut self, + for_loop: &ForLoop, + ) -> std::result::Result, TranslationError> { + let mut statements = Vec::new(); + + self.ssa.enter_scope(); + for statement in &for_loop.initializer.statements { + let initializer_statements = self.translate_statement(statement)?; + statements.extend(initializer_statements); + } + + let initializer_scope = self.ssa.current_scope().clone(); + let mut loop_variables = Vec::new(); + let mut initializer_values = Vec::new(); + + for (name, &value) in &initializer_scope { + loop_variables.push((name.clone(), self.ssa.fresh_id())); + initializer_values.push(value); + } + + for (name, var_id) in &loop_variables { + let value_type = initializer_scope + .get(name) + .map(|v| v.value_type) + .unwrap_or_default(); + self.ssa.assign(name, Value::new(*var_id, value_type)); + } + + let (condition_statements, condition_expression) = + self.translate_expression(&for_loop.condition)?; + + let loop_variable_names: Vec = + loop_variables.iter().map(|(n, _)| n.clone()).collect(); + self.loop_variable_names_stack.push(loop_variable_names); + + self.ssa.enter_scope(); + let mut body_region = self.translate_region(&for_loop.body)?; + let body_scope = self.ssa.exit_scope(); + + self.loop_variable_names_stack.pop(); + + for (name, loop_variable_id) in &loop_variables { + if let Some(&value) = body_scope.get(name) { + body_region.yields.push(value); + } else { + let value_type = initializer_scope + .get(name) + .map(|v| v.value_type) + .unwrap_or_default(); + body_region + .yields + .push(Value::new(*loop_variable_id, value_type)); + } + } + + self.ssa.enter_scope(); + let mut post_input_var_ids = Vec::new(); + for (name, _) in loop_variables.iter() { + let post_var_id = self.ssa.fresh_id(); + post_input_var_ids.push(post_var_id); + let value_type = initializer_scope + .get(name) + .map(|v| v.value_type) + .unwrap_or_default(); + self.ssa.assign(name, Value::new(post_var_id, value_type)); + } + + let mut post_region = self.translate_region(&for_loop.finalizer)?; + let post_scope = self.ssa.exit_scope(); + + for (name, _) in &loop_variables { + if let Some(&value) = post_scope.get(name) { + post_region.yields.push(value); + } + } + + let mut outputs = Vec::new(); + let mut output_values = Vec::new(); + for (name, _) in &loop_variables { + let output_id = self.ssa.fresh_id(); + outputs.push(output_id); + let value_type = initializer_scope + .get(name) + .map(|v| v.value_type) + .unwrap_or_default(); + output_values.push((name.clone(), Value::new(output_id, value_type))); + } + + self.ssa.exit_scope(); + + for (name, value) in output_values { + self.ssa.assign(&name, value); + } + + statements.push(Statement::For { + initial_values: initializer_values, + loop_variables: loop_variables.into_iter().map(|(_, id)| id).collect(), + condition_statements, + condition: condition_expression, + body: body_region, + post_input_variables: post_input_var_ids, + post: post_region, + outputs, + }); + + Ok(statements) + } + + /// Translates a function definition. The function definition does not produce statements in + /// the containing block — its body is attached to the pre-allocated `Function` entry. + /// + /// We save the current scope but keep the SSA counter advanced to ensure globally unique + /// `ValueId`s. Creating a fresh `SsaBuilder` would restart at ID 0 and collide with the + /// parameter IDs already allocated by [`Self::collect_functions`]. + fn translate_function_definition( + &mut self, + function_definition: &FunctionDefinition, + ) -> std::result::Result, TranslationError> { + let function_id = self + .lookup_function(&function_definition.identifier) + .ok_or_else(|| { + TranslationError::UndefinedFunction(function_definition.identifier.clone()) + })?; + + let saved_scope = self.ssa.current_scope().clone(); + self.ssa.restore_scope(BTreeMap::new()); + + let function = self.functions.get(&function_id).cloned(); + if let Some(function) = &function { + for ((parameter_id, _), parameter_identifier) in function + .parameters + .iter() + .zip(&function_definition.arguments) + { + self.ssa.declare( + ¶meter_identifier.inner, + Value::new(*parameter_id, Type::Int(BitWidth::I256)), + ); + } + } + + let mut return_value_ids = Vec::new(); + let saved_return_variable_names = std::mem::take(&mut self.current_return_variable_names); + for return_identifier in &function_definition.result { + let return_id = self.ssa.fresh_id(); + self.ssa.declare( + &return_identifier.inner, + Value::new(return_id, Type::Int(BitWidth::I256)), + ); + return_value_ids.push(return_id); + self.current_return_variable_names + .push(return_identifier.inner.clone()); + } + + let body = self.translate_block(&function_definition.body)?; + + self.current_return_variable_names = saved_return_variable_names; + + let mut final_return_values = Vec::new(); + for return_identifier in &function_definition.result { + if let Some(value) = self.ssa.lookup(&return_identifier.inner) { + final_return_values.push(value.id); + } + } + + if let Some(function) = self.functions.get_mut(&function_id) { + function.body = body; + function.return_values_initial = return_value_ids; + function.return_values = final_return_values; + function.size_estimate = estimate_function_size(&function.body); + } + + self.ssa.restore_scope(saved_scope); + + Ok(vec![]) + } + + /// Collects the current SSA values of the innermost loop's carried variables. + /// Used by break/continue to carry the right values to the loop's join/post blocks. + fn collect_loop_variable_values(&self) -> Vec { + let Some(variable_names) = self.loop_variable_names_stack.last() else { + return Vec::new(); + }; + variable_names + .iter() + .map(|name| { + self.ssa + .lookup(name) + .unwrap_or(Value::new(crate::ir::ValueId::new(0), Type::default())) + }) + .collect() + } + + /// Parses a Yul literal to a BigUint. + fn parse_literal( + &self, + literal: &YulLiteral, + ) -> std::result::Result { + let inner = &literal.inner; + + match inner { + LexicalLiteral::Boolean(boolean) => Ok(match boolean { + BooleanLiteral::True => BigUint::from(1u32), + BooleanLiteral::False => BigUint::from(0u32), + }), + LexicalLiteral::Integer(integer_literal) => match integer_literal { + IntegerLiteral::Decimal { inner } => BigUint::parse_bytes(inner.as_bytes(), 10) + .ok_or_else(|| TranslationError::InvalidLiteral(inner.clone())), + IntegerLiteral::Hexadecimal { inner } => { + let hex = inner + .strip_prefix("0x") + .or_else(|| inner.strip_prefix("0X")) + .unwrap_or(inner); + BigUint::parse_bytes(hex.as_bytes(), 16) + .ok_or_else(|| TranslationError::InvalidLiteral(inner.clone())) + } + }, + LexicalLiteral::String(string_literal) => { + let string = &string_literal.inner; + let mut hex_string = if string_literal.is_hexadecimal { + string.clone() + } else { + let mut hex = std::string::String::with_capacity(64); + let mut index = 0; + let bytes = string.as_bytes(); + while index < bytes.len() { + if bytes[index] == b'\\' { + index += 1; + if index >= bytes.len() { + break; + } + match bytes[index] { + b'x' => { + if index + 2 < bytes.len() { + hex.push(bytes[index + 1] as char); + hex.push(bytes[index + 2] as char); + } + index += 3; + } + b'u' => { + if index + 4 < bytes.len() { + let code_point_string = &string[index + 1..index + 5]; + if let Ok(codepoint) = + u32::from_str_radix(code_point_string, 16) + { + if let Some(ch) = char::from_u32(codepoint) { + let mut buf = [0u8; 4]; + let encoded = ch.encode_utf8(&mut buf); + for byte in encoded.bytes() { + hex.push_str(&format!("{byte:02x}")); + } + } + } + } + index += 5; + } + b't' => { + hex.push_str("09"); + index += 1; + } + b'n' => { + hex.push_str("0a"); + index += 1; + } + b'r' => { + hex.push_str("0d"); + index += 1; + } + b'\n' => { + index += 1; + } + other => { + hex.push_str(&format!("{other:02x}")); + index += 1; + } + } + } else { + hex.push_str(&format!("{:02x}", bytes[index])); + index += 1; + } + } + hex + }; + + if hex_string.len() > 64 { + hex_string.truncate(64); + } + while hex_string.len() < 64 { + hex_string.push('0'); + } + + BigUint::parse_bytes(hex_string.as_bytes(), 16) + .ok_or_else(|| TranslationError::InvalidLiteral(string.clone())) + } + } + } +} + +/// Creates a binary operation expression. +fn binary_op(operation: BinaryOperation, arguments: &[Value]) -> Expression { + Expression::Binary { + operation, + lhs: arguments[0], + rhs: arguments[1], + } +} + +/// Creates a ternary operation expression. +fn ternary_op(operation: BinaryOperation, arguments: &[Value]) -> Expression { + Expression::Ternary { + operation, + a: arguments[0], + b: arguments[1], + n: arguments[2], + } +} + +/// Creates a unary operation expression. +fn unary_op(operation: UnaryOperation, arguments: &[Value]) -> Expression { + Expression::Unary { + operation, + operand: arguments[0], + } +} + +/// Estimates the size of a function body for inlining decisions. +fn estimate_function_size(block: &Block) -> usize { + let mut size = 0; + for statement in &block.statements { + size += estimate_statement_size(statement); + } + size +} + +/// Estimates the size of a statement. +fn estimate_statement_size(statement: &Statement) -> usize { + match statement { + Statement::Let { .. } => 1, + Statement::MStore { .. } | Statement::MStore8 { .. } | Statement::MCopy { .. } => 1, + Statement::SStore { .. } | Statement::TStore { .. } => 1, + Statement::If { + then_region, + else_region, + .. + } => { + 1 + estimate_region_size(then_region) + + else_region.as_ref().map_or(0, estimate_region_size) + } + Statement::Switch { cases, default, .. } => { + 1 + cases + .iter() + .map(|c| estimate_region_size(&c.body)) + .sum::() + + default.as_ref().map_or(0, estimate_region_size) + } + Statement::For { body, post, .. } => { + 1 + estimate_region_size(body) + estimate_region_size(post) + } + Statement::Block(region) => estimate_region_size(region), + Statement::Expression(_) => 1, + _ => 1, + } +} + +/// Estimates the size of a region. +fn estimate_region_size(region: &Region) -> usize { + region.statements.iter().map(estimate_statement_size).sum() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_decimal_literal() { + let _translator = YulTranslator::new(); + } +} diff --git a/crates/newyork/src/guard_narrow.rs b/crates/newyork/src/guard_narrow.rs new file mode 100644 index 000000000..50e4f4c95 --- /dev/null +++ b/crates/newyork/src/guard_narrow.rs @@ -0,0 +1,1032 @@ +//! Guard-based value narrowing pass. +//! +//! Detects patterns like `if gt(value, MASK) { }` and inserts +//! `let val_narrow = and(value, MASK)` after the guard, replacing all subsequent +//! uses of `value` with `val_narrow`. This gives type inference proof that the +//! value fits in fewer bits, enabling downstream narrowing of comparisons, +//! arithmetic, and memory operations. +//! +//! Common pattern in Solidity ABI decoding and checked arithmetic: +//! ```text +//! let check = gt(calldataload_value, 0xFFFFFFFFFFFFFFFF) +//! if check { revert(0, 0) } +//! // After here, calldataload_value <= UINT64_MAX +//! let offset = add(calldataload_value, 4) // can be i64 arithmetic +//! ``` + +use crate::ir::*; +use num::{BigUint, Zero}; +use std::collections::BTreeMap; + +/// Statistics from guard narrowing. +#[derive(Default, Debug)] +pub struct GuardNarrowStats { + /// Number of guard patterns detected and narrowed. + pub guards_narrowed: usize, + /// Number of value uses replaced with narrowed versions. + pub uses_replaced: usize, +} + +/// Runs guard narrowing on an entire object tree (including subobjects). +pub fn narrow_guards_in_object(object: &mut Object) -> GuardNarrowStats { + let mut next_id = object.find_max_value_id() + 1; + let mut statistics = GuardNarrowStats::default(); + + let noreturn = detect_noreturn_functions(object); + + let validators = detect_validator_functions(object, &noreturn); + + let _ = narrow_block( + &mut object.code, + &mut next_id, + &mut statistics, + &validators, + &noreturn, + ); + for function in object.functions.values_mut() { + let replacements = narrow_block( + &mut function.body, + &mut next_id, + &mut statistics, + &validators, + &noreturn, + ); + if !replacements.is_empty() { + for return_value in &mut function.return_values { + if let Some(&new_id) = replacements.get(&return_value.0) { + *return_value = new_id; + } + } + } + } + + rewrite_allocator_p1_with_early_check(object, &mut next_id, &noreturn); + + narrow_allocator_param_types(object, &noreturn); + + for subobject in &mut object.subobjects { + let subobject_statistics = narrow_guards_in_object(subobject); + statistics.guards_narrowed += subobject_statistics.guards_narrowed; + statistics.uses_replaced += subobject_statistics.uses_replaced; + } + + statistics +} + +/// Narrows function parameters that are provably bounded by UINT64_MAX +/// at every reachable path in the function body. Two patterns matter +/// for OZ contracts: +/// +/// 1. `(i256, i256) -> ()` with the `finalize_allocation` shape — an +/// add overflow check followed by `mstore(0x40, sum)`. +/// 2. Any param whose first reachable use path is `if gt(p, UINT64_MAX) +/// { }` (Solidity's `array_allocation_size_bytes`-shape +/// validator at function entry). +/// +/// In both cases, plain truncation at the call site is sound because the +/// function's own guard would have trapped a wide value before the +/// param's first non-validation use. +/// Inserts an explicit `if gt(p1, UINT64_MAX) { panic_0x41 }` early +/// guard plus a downstream `and(p1, UINT64_MAX)` rewrite at the top of +/// each `finalize_allocation`-shaped function. Subsequent uses of `p1` +/// in the body are redirected to the AND-masked value. +/// +/// Soundness: the inserted gt/panic pair is *redundant* with the body's +/// existing `or(gt(sum, UINT64_MAX), lt(sum, p0)) { panic_0x41 }` check +/// — any caller that would have failed the early check would also have +/// failed the existing late check, so semantics are preserved. The +/// purpose is to expose the `p1 <= UINT64_MAX` invariant at the *top* +/// of the function so type-inference / LLVM IPSCCP can fold the rest of +/// the body's i256 arithmetic to i64. +/// +/// Why this avoids the iter34 regression: the function signature is +/// untouched, so caller-side IR sees the exact same `(i64, i256)` +/// declaration as iter33. Only the *body* changes, and only by adding +/// an early check that any compliant caller already satisfies. +fn rewrite_allocator_p1_with_early_check( + object: &mut Object, + next_id: &mut u32, + _noreturn: &std::collections::BTreeSet, +) { + let mut to_rewrite: Vec = Vec::new(); + for (function_id, function) in &object.functions { + if function.parameters.len() != 2 || !function.returns.is_empty() { + continue; + } + if !function + .parameters + .iter() + .all(|(_, value_type)| matches!(value_type, Type::Int(BitWidth::I256))) + { + continue; + } + let p0 = function.parameters[0].0; + let p1 = function.parameters[1].0; + if has_allocator_shape(&function.body, p0, p1) { + to_rewrite.push(function_id.0); + } + } + + let uint64_max: BigUint = (BigUint::from(1u32) << 64) - BigUint::from(1u32); + for function_id in to_rewrite { + let Some(function) = object.functions.get_mut(&FunctionId(function_id)) else { + continue; + }; + let p1 = function.parameters[1].0; + let max_const = ValueId(*next_id); + *next_id += 1; + let gt_check = ValueId(*next_id); + *next_id += 1; + let p1_narrow = ValueId(*next_id); + *next_id += 1; + + let original_stmts = std::mem::take(&mut function.body.statements); + + let mut new_stmts: Vec = Vec::with_capacity(original_stmts.len() + 4); + new_stmts.push(Statement::Let { + bindings: vec![max_const], + value: Expression::Literal { + value: uint64_max.clone(), + value_type: Type::Int(BitWidth::I256), + }, + }); + new_stmts.push(Statement::Let { + bindings: vec![gt_check], + value: Expression::Binary { + operation: BinaryOperation::Gt, + lhs: Value::int(p1), + rhs: Value::int(max_const), + }, + }); + new_stmts.push(Statement::If { + condition: Value::new(gt_check, Type::Int(BitWidth::I1)), + inputs: Vec::new(), + then_region: Region { + statements: vec![Statement::PanicRevert { code: 0x41 }], + yields: Vec::new(), + }, + else_region: None, + outputs: Vec::new(), + }); + new_stmts.push(Statement::Let { + bindings: vec![p1_narrow], + value: Expression::Binary { + operation: BinaryOperation::And, + lhs: Value::int(p1), + rhs: Value::int(max_const), + }, + }); + + let mut replacements: BTreeMap = BTreeMap::new(); + replacements.insert(p1.0, p1_narrow); + for statement in original_stmts { + new_stmts.push(replace_value_ids_in_statement(statement, &replacements)); + } + function.body.statements = new_stmts; + } +} + +fn narrow_allocator_param_types(object: &mut Object, _noreturn: &std::collections::BTreeSet) { + let mut narrow_params: BTreeMap> = BTreeMap::new(); + + for (function_id, function) in &object.functions { + if function.parameters.is_empty() { + continue; + } + + if function.parameters.len() == 2 + && function.returns.is_empty() + && function + .parameters + .iter() + .all(|(_, value_type)| matches!(value_type, Type::Int(BitWidth::I256))) + { + let p0 = function.parameters[0].0; + let p1 = function.parameters[1].0; + if has_allocator_shape(&function.body, p0, p1) { + narrow_params.insert(function_id.0, vec![0]); + continue; + } + } + } + + for (function_id, indices) in narrow_params { + if let Some(function) = object.functions.get_mut(&FunctionId(function_id)) { + for i in indices { + if let Some((_, value_type)) = function.parameters.get_mut(i) { + *value_type = Type::Int(BitWidth::I64); + } + } + } + } +} + +/// Detects the canonical allocator pattern in a block: +/// * `mstore(0x40, sum)` (FMP store) +/// * `sum = add(p0, x)` somewhere upstream +/// * `if or(gt(sum, UINT64_MAX), lt(sum, p0)) { }` overflow check +/// * `x` is derived from `p1` (we don't constrain the alignment computation +/// precisely; the FMP store + add(p0, _) + overflow check is enough). +fn has_allocator_shape(block: &Block, p0: ValueId, _p1: ValueId) -> bool { + use num::Zero; + + let mut add_results: BTreeMap = BTreeMap::new(); + let mut and_results: BTreeMap = BTreeMap::new(); + let mut gt_const_checks: BTreeMap = BTreeMap::new(); + let mut lt_against_addend: BTreeMap = BTreeMap::new(); + let mut or_results: BTreeMap = BTreeMap::new(); + let mut constants: BTreeMap = BTreeMap::new(); + let mut fmp_store_value: Option = None; + + for statement in &block.statements { + if let Statement::Let { bindings, value } = statement { + if bindings.len() == 1 { + let bid = bindings[0].0; + if let Expression::Literal { value: lit_val, .. } = value { + constants.insert(bid, lit_val.clone()); + } + if let Expression::Binary { + operation, + lhs, + rhs, + } = value + { + match operation { + BinaryOperation::Add => { + add_results.insert(bid, (lhs.id.0, rhs.id.0)); + } + BinaryOperation::And => { + if let Some(mask) = constants.get(&rhs.id.0) { + and_results.insert(bid, (lhs.id.0, mask.clone())); + } else if let Some(mask) = constants.get(&lhs.id.0) { + and_results.insert(bid, (rhs.id.0, mask.clone())); + } + } + BinaryOperation::Gt => { + if let Some(c) = constants.get(&rhs.id.0) { + gt_const_checks.insert(bid, (lhs.id.0, c.clone())); + } + } + BinaryOperation::Lt => { + lt_against_addend.insert(bid, (lhs.id.0, rhs.id.0)); + } + BinaryOperation::Or => { + or_results.insert(bid, (lhs.id.0, rhs.id.0)); + } + _ => {} + } + } + } + } + if let Statement::MStore { offset, value, .. } = statement { + if let Some(off) = constants.get(&offset.id.0) { + if !off.is_zero() && *off == BigUint::from(0x40u32) { + fmp_store_value = Some(value.id.0); + } + } + } + } + + let Some(fmp_val) = fmp_store_value else { + return false; + }; + + let sum_id = match and_results.get(&fmp_val) { + Some((orig, _mask)) => *orig, + None => fmp_val, + }; + + let Some(&(add_lhs, add_rhs)) = add_results.get(&sum_id) else { + return false; + }; + let p0_used = add_lhs == p0.0 || add_rhs == p0.0; + if !p0_used { + return false; + } + + let uint64_max: BigUint = (BigUint::from(1u32) << 64) - 1u32; + let mut visit: Vec = Vec::new(); + let mut have_gt_sum_max = false; + let mut have_lt_sum_p0 = false; + + for (or_id, (l, r)) in &or_results { + let _ = or_id; + visit.push(*l); + visit.push(*r); + } + for id in &visit { + if let Some((value, c)) = gt_const_checks.get(id) { + if *value == sum_id && *c == uint64_max { + have_gt_sum_max = true; + } + } + if let Some((sum, addend)) = lt_against_addend.get(id) { + if *sum == sum_id && *addend == p0.0 { + have_lt_sum_p0 = true; + } + } + } + for (id, (value, c)) in >_const_checks { + let _ = id; + if *value == sum_id && *c == uint64_max { + have_gt_sum_max = true; + } + } + for (id, (sum, addend)) in <_against_addend { + let _ = id; + if *sum == sum_id && *addend == p0.0 { + have_lt_sum_p0 = true; + } + } + + have_gt_sum_max && have_lt_sum_p0 +} + +/// Detects functions that always terminate (no fall-through). A function +/// is noreturn if its body has a single statement that is a known terminator +/// (Revert, PanicRevert, etc.) — the typical compiler-generated panic helper +/// like `function panic_error_0x41() { panic_revert(0x41) }`. +/// +/// Calls to noreturn functions are equivalent to inlining the terminator at +/// the call site; `region_terminates` accepts them so guard narrowing can +/// recognize patterns like `if check { panic_error_0x41() }`. +/// +/// The set is conservative: only single-statement direct terminators count, +/// not nested or conditional terminators. This rules out functions whose +/// termination depends on dynamic checks the analysis can't prove always +/// fire. +/// +/// The body iterates to a fixed point so transitive helpers like +/// `function trampoline() { panic_error_0x41() }` are recognised once the +/// leaf `panic_error_0x41` is itself in the set. +fn detect_noreturn_functions(object: &Object) -> std::collections::BTreeSet { + let mut noreturn = std::collections::BTreeSet::new(); + loop { + let before = noreturn.len(); + for (function_id, function) in &object.functions { + if noreturn.contains(&function_id.0) || function.body.statements.len() != 1 { + continue; + } + let terminates = match &function.body.statements[0] { + Statement::Revert { .. } + | Statement::Return { .. } + | Statement::Invalid + | Statement::Stop + | Statement::SelfDestruct { .. } + | Statement::PanicRevert { .. } + | Statement::ErrorStringRevert { .. } + | Statement::CustomErrorRevert { .. } => true, + Statement::Expression(Expression::Call { + function: callee, .. + }) => noreturn.contains(&callee.0), + _ => false, + }; + if terminates { + noreturn.insert(function_id.0); + } + } + if noreturn.len() == before { + break; + } + } + noreturn +} + +/// Detects "validator" functions that prove their parameter fits in a mask. +/// +/// Pattern: void function with one parameter whose body contains: +/// ```text +/// let masked = and(param, MASK) +/// let eq_check = eq(param, masked) +/// let not_check = iszero(eq_check) +/// if not_check { } +/// ``` +/// +/// Returns a map from FunctionId to the boundary mask (BigUint). +fn detect_validator_functions( + object: &Object, + noreturn: &std::collections::BTreeSet, +) -> BTreeMap { + let mut validators = BTreeMap::new(); + + for (function_id, function) in &object.functions { + if !function.returns.is_empty() || function.parameters.len() != 1 { + continue; + } + + let parameter_id = function.parameters[0].0; + if let Some(mask) = detect_validator_mask(&function.body, parameter_id, noreturn) { + validators.insert(function_id.0, mask); + } + } + + validators +} + +/// Checks if a block contains the eq-based validator pattern for the given param. +/// Returns the boundary mask if found. +fn detect_validator_mask( + block: &Block, + parameter_id: ValueId, + noreturn: &std::collections::BTreeSet, +) -> Option { + let statements = &block.statements; + + let mut constants: BTreeMap = BTreeMap::new(); + let mut and_defs: BTreeMap = BTreeMap::new(); + let mut eq_mask_defs: BTreeMap = BTreeMap::new(); + let mut iszero_eq_defs: BTreeMap = BTreeMap::new(); + + for statement in statements { + if let Statement::Let { + ref bindings, + ref value, + } = statement + { + if bindings.len() != 1 { + continue; + } + let bid = bindings[0].0; + + if let Expression::Literal { + value: ref lit_val, .. + } = value + { + constants.insert(bid, lit_val.clone()); + } + + if let Expression::Binary { + operation: BinaryOperation::And, + ref lhs, + ref rhs, + } = value + { + let (val_id, mask_id) = (lhs.id.0, rhs.id.0); + if val_id == parameter_id.0 { + if let Some(mask) = constants.get(&mask_id) { + if is_wide_boundary_mask(mask) { + and_defs.insert(bid, (val_id, mask.clone())); + } + } + } else if mask_id == parameter_id.0 { + if let Some(mask) = constants.get(&val_id) { + if is_wide_boundary_mask(mask) { + and_defs.insert(bid, (mask_id, mask.clone())); + } + } + } + } + + if let Expression::Binary { + operation: BinaryOperation::Eq, + ref lhs, + ref rhs, + } = value + { + if let Some((orig_id, ref mask)) = and_defs.get(&rhs.id.0) { + if *orig_id == lhs.id.0 { + eq_mask_defs.insert(bid, mask.clone()); + } + } else if let Some((orig_id, ref mask)) = and_defs.get(&lhs.id.0) { + if *orig_id == rhs.id.0 { + eq_mask_defs.insert(bid, mask.clone()); + } + } + } + + if let Expression::Unary { + operation: UnaryOperation::IsZero, + ref operand, + } = value + { + if let Some(mask) = eq_mask_defs.get(&operand.id.0) { + iszero_eq_defs.insert(bid, mask.clone()); + } + } + } + + if let Statement::If { + ref condition, + ref then_region, + ref else_region, + ref outputs, + .. + } = statement + { + if else_region.is_none() + && outputs.is_empty() + && region_terminates(then_region, noreturn) + { + if let Some(mask) = iszero_eq_defs.get(&condition.id.0) { + return Some(mask.clone()); + } + } + } + } + + None +} + +/// Process a block: find guard patterns and insert AND masks. +/// Returns the accumulated replacements map so callers can apply it to +/// function return values and other metadata outside the block. +fn narrow_block( + block: &mut Block, + next_id: &mut u32, + statistics: &mut GuardNarrowStats, + validators: &BTreeMap, + noreturn: &std::collections::BTreeSet, +) -> BTreeMap { + for statement in &mut block.statements { + narrow_stmt_regions(statement, next_id, statistics, validators, noreturn); + } + + let statements = std::mem::take(&mut block.statements); + let mut new_stmts = Vec::with_capacity(statements.len() + 16); + + let mut constants: BTreeMap = BTreeMap::new(); + let mut gt_defs: BTreeMap = BTreeMap::new(); + let mut and_defs: BTreeMap = BTreeMap::new(); + let mut eq_mask_defs: BTreeMap = BTreeMap::new(); + let mut iszero_eq_defs: BTreeMap = BTreeMap::new(); + let mut or_defs: BTreeMap = BTreeMap::new(); + let mut add_defs: BTreeMap = BTreeMap::new(); + let mut lt_defs: BTreeMap = BTreeMap::new(); + let mut lt_const_defs: BTreeMap = BTreeMap::new(); + let mut iszero_lt_defs: BTreeMap = BTreeMap::new(); + let mut replacements: BTreeMap = BTreeMap::new(); + + for statement in statements { + let statement = if replacements.is_empty() { + statement + } else { + replace_value_ids_in_statement(statement, &replacements) + }; + + if let Statement::Let { + ref bindings, + ref value, + } = statement + { + if bindings.len() == 1 { + let bid = bindings[0].0; + + if let Expression::Literal { + value: ref lit_val, .. + } = value + { + constants.insert(bid, lit_val.clone()); + } + + if let Expression::Binary { + operation: BinaryOperation::Gt, + ref lhs, + ref rhs, + } = value + { + let rhs_id = resolve_id(rhs.id, &replacements); + if let Some(mask) = constants.get(&rhs_id.0) { + if is_boundary_mask(mask) { + let guarded = Value { + id: resolve_id(lhs.id, &replacements), + value_type: lhs.value_type, + }; + gt_defs.insert(bid, (guarded, mask.clone())); + } + } + } + + if let Expression::Binary { + operation: BinaryOperation::And, + ref lhs, + ref rhs, + } = value + { + let lhs_id = resolve_id(lhs.id, &replacements); + let rhs_id = resolve_id(rhs.id, &replacements); + if let Some(mask) = constants.get(&rhs_id.0) { + if is_wide_boundary_mask(mask) { + and_defs.insert(bid, (lhs_id.0, ValueId(bid))); + } + } else if let Some(mask) = constants.get(&lhs_id.0) { + if is_wide_boundary_mask(mask) { + and_defs.insert(bid, (rhs_id.0, ValueId(bid))); + } + } + } + + if let Expression::Binary { + operation: BinaryOperation::Eq, + ref lhs, + ref rhs, + } = value + { + let lhs_id = resolve_id(lhs.id, &replacements); + let rhs_id = resolve_id(rhs.id, &replacements); + if let Some(&(orig_id, and_val_id)) = and_defs.get(&rhs_id.0) { + if orig_id == lhs_id.0 { + eq_mask_defs.insert(bid, (orig_id, and_val_id)); + } + } else if let Some(&(orig_id, and_val_id)) = and_defs.get(&lhs_id.0) { + if orig_id == rhs_id.0 { + eq_mask_defs.insert(bid, (orig_id, and_val_id)); + } + } + } + + if let Expression::Unary { + operation: UnaryOperation::IsZero, + ref operand, + } = value + { + let op_id = resolve_id(operand.id, &replacements); + if let Some(&(orig_id, and_val_id)) = eq_mask_defs.get(&op_id.0) { + iszero_eq_defs.insert(bid, (orig_id, and_val_id)); + } + } + + if let Expression::Binary { + operation: BinaryOperation::Or, + ref lhs, + ref rhs, + } = value + { + let lhs_id = resolve_id(lhs.id, &replacements); + let rhs_id = resolve_id(rhs.id, &replacements); + or_defs.insert(bid, (lhs_id.0, rhs_id.0)); + } + + if let Expression::Binary { + operation: BinaryOperation::Add, + ref lhs, + ref rhs, + } = value + { + let lhs_id = resolve_id(lhs.id, &replacements); + let rhs_id = resolve_id(rhs.id, &replacements); + add_defs.insert(bid, (lhs_id.0, rhs_id.0)); + } + + if let Expression::Binary { + operation: BinaryOperation::Lt, + ref lhs, + ref rhs, + } = value + { + let lhs_id = resolve_id(lhs.id, &replacements); + let rhs_id = resolve_id(rhs.id, &replacements); + lt_defs.insert(bid, (lhs_id.0, rhs_id.0)); + + if let Some(k) = constants.get(&rhs_id.0) { + let k_minus_one = if k.is_zero() { BigUint::ZERO } else { k - 1u32 }; + if !k.is_zero() && (k & &k_minus_one) == BigUint::ZERO { + lt_const_defs.insert( + bid, + ( + Value { + id: lhs_id, + value_type: lhs.value_type, + }, + k_minus_one, + ), + ); + } + } + } + } + + if let Statement::Let { + ref bindings, + value: + Expression::Unary { + operation: UnaryOperation::IsZero, + ref operand, + }, + } = statement + { + if bindings.len() == 1 { + let bid = bindings[0].0; + let op_id = resolve_id(operand.id, &replacements); + if let Some((value, mask)) = lt_const_defs.get(&op_id.0) { + iszero_lt_defs.insert(bid, (*value, mask.clone())); + } + } + } + } + + if let Statement::If { + ref condition, + ref then_region, + ref else_region, + ref outputs, + .. + } = statement + { + let cond_id = resolve_id(condition.id, &replacements); + if else_region.is_none() + && outputs.is_empty() + && region_terminates(then_region, noreturn) + { + let mut gt_guards: Vec<(Value, BigUint)> = Vec::new(); + let mut iszero_eq_guards: Vec<(u32, ValueId)> = Vec::new(); + let mut lt_overflows: Vec<(u32, u32)> = Vec::new(); + let mut visit = vec![cond_id.0]; + let mut seen: std::collections::BTreeSet = std::collections::BTreeSet::new(); + while let Some(id) = visit.pop() { + if !seen.insert(id) { + continue; + } + if let Some((guarded, mask)) = gt_defs.get(&id) { + gt_guards.push((*guarded, mask.clone())); + } else if let Some(&(orig_id, and_val_id)) = iszero_eq_defs.get(&id) { + iszero_eq_guards.push((orig_id, and_val_id)); + } else if let Some(&(sum_id, addend_id)) = lt_defs.get(&id) { + lt_overflows.push((sum_id, addend_id)); + } else if let Some((value, mask)) = iszero_lt_defs.get(&id) { + gt_guards.push((*value, mask.clone())); + } else if let Some(&(lhs_id, rhs_id)) = or_defs.get(&id) { + visit.push(lhs_id); + visit.push(rhs_id); + } + } + + let mut extra_gt_guards: Vec<(Value, BigUint)> = Vec::new(); + for (sum_id, addend_id) in <_overflows { + let Some(&(add_lhs, add_rhs)) = add_defs.get(sum_id) else { + continue; + }; + let Some((_, mask)) = gt_guards.iter().find(|(g, _)| g.id.0 == *sum_id) else { + continue; + }; + if *addend_id != add_lhs && *addend_id != add_rhs { + continue; + } + let i256_ty = Type::Int(BitWidth::I256); + extra_gt_guards.push(( + Value { + id: ValueId(add_lhs), + value_type: i256_ty, + }, + mask.clone(), + )); + extra_gt_guards.push(( + Value { + id: ValueId(add_rhs), + value_type: i256_ty, + }, + mask.clone(), + )); + } + gt_guards.extend(extra_gt_guards); + + if !gt_guards.is_empty() || !iszero_eq_guards.is_empty() { + new_stmts.push(statement); + + for (guarded_val, mask) in gt_guards { + if replacements.contains_key(&guarded_val.id.0) { + continue; + } + let mask_id = ValueId(*next_id); + *next_id += 1; + let narrow_id = ValueId(*next_id); + *next_id += 1; + + new_stmts.push(Statement::Let { + bindings: vec![mask_id], + value: Expression::Literal { + value: mask, + value_type: Type::Int(BitWidth::I256), + }, + }); + new_stmts.push(Statement::Let { + bindings: vec![narrow_id], + value: Expression::Binary { + operation: BinaryOperation::And, + lhs: guarded_val, + rhs: Value::int(mask_id), + }, + }); + + replacements.insert(guarded_val.id.0, narrow_id); + statistics.guards_narrowed += 1; + } + + for (orig_id, and_val_id) in iszero_eq_guards { + replacements.entry(orig_id).or_insert(and_val_id); + statistics.guards_narrowed += 1; + } + + continue; + } + } + } + + if let Statement::Expression(Expression::Call { + ref function, + ref arguments, + }) = statement + { + if arguments.len() == 1 { + if let Some(mask) = validators.get(&function.0) { + let arg_id = resolve_id(arguments[0].id, &replacements); + if let std::collections::btree_map::Entry::Vacant(e) = + replacements.entry(arg_id.0) + { + let mask_id = ValueId(*next_id); + *next_id += 1; + let narrow_id = ValueId(*next_id); + *next_id += 1; + + new_stmts.push(statement); + + new_stmts.push(Statement::Let { + bindings: vec![mask_id], + value: Expression::Literal { + value: mask.clone(), + value_type: Type::Int(BitWidth::I256), + }, + }); + + new_stmts.push(Statement::Let { + bindings: vec![narrow_id], + value: Expression::Binary { + operation: BinaryOperation::And, + lhs: Value { + id: arg_id, + value_type: Type::Int(BitWidth::I256), + }, + rhs: Value::int(mask_id), + }, + }); + + e.insert(narrow_id); + statistics.guards_narrowed += 1; + continue; + } + } + } + } + + new_stmts.push(statement); + } + + block.statements = new_stmts; + replacements +} + +/// Recurse into nested regions within a statement. +fn narrow_stmt_regions( + statement: &mut Statement, + next_id: &mut u32, + statistics: &mut GuardNarrowStats, + validators: &BTreeMap, + noreturn: &std::collections::BTreeSet, +) { + match statement { + Statement::If { + then_region, + else_region, + .. + } => { + narrow_region(then_region, next_id, statistics, validators, noreturn); + if let Some(r) = else_region { + narrow_region(r, next_id, statistics, validators, noreturn); + } + } + Statement::Switch { cases, default, .. } => { + for case in cases { + narrow_region(&mut case.body, next_id, statistics, validators, noreturn); + } + if let Some(d) = default { + narrow_region(d, next_id, statistics, validators, noreturn); + } + } + Statement::For { + condition_statements, + body, + post, + .. + } => { + let mut cond_block = Block { + statements: std::mem::take(condition_statements), + }; + narrow_block(&mut cond_block, next_id, statistics, validators, noreturn); + *condition_statements = cond_block.statements; + + narrow_region(body, next_id, statistics, validators, noreturn); + narrow_region(post, next_id, statistics, validators, noreturn); + } + Statement::Block(region) => { + narrow_region(region, next_id, statistics, validators, noreturn); + } + _ => {} + } +} + +/// Process a region as a block. +fn narrow_region( + region: &mut Region, + next_id: &mut u32, + statistics: &mut GuardNarrowStats, + validators: &BTreeMap, + noreturn: &std::collections::BTreeSet, +) { + let mut block = Block { + statements: std::mem::take(&mut region.statements), + }; + narrow_block(&mut block, next_id, statistics, validators, noreturn); + region.statements = block.statements; +} + +/// Returns true if `value` is a useful boundary mask for gt-based guard narrowing. +/// Only masks that fit in a native register width (≤64 bits) are useful for +/// the gt pattern, since we need to insert a new AND instruction. +fn is_boundary_mask(value: &BigUint) -> bool { + if value.is_zero() { + return false; + } + let plus_one = value + 1u32; + if (plus_one.clone() & value) != BigUint::ZERO { + return false; + } + *value <= BigUint::from(u64::MAX) +} + +/// Returns true if `value` is a boundary mask useful for eq-based guard narrowing. +/// For eq-based patterns (iszero(eq(value, and(value, MASK)))), we accept wider +/// masks up to 160 bits (address width). The AND already exists in the IR, +/// so we just redirect uses — no new instruction is emitted. +/// +/// Narrowing from i256 to i160 is significant on a 32-bit target: 5 words +/// instead of 8, saving 37.5% register pressure per address value. +fn is_wide_boundary_mask(value: &BigUint) -> bool { + if value.is_zero() { + return false; + } + let plus_one = value + 1u32; + if (plus_one.clone() & value) != BigUint::ZERO { + return false; + } + let bits = value.bits(); + bits <= 160 +} + +/// Returns true if a region terminates (doesn't fall through). +/// Checks for direct terminators (revert, return, etc.) and also for +/// regions that end with a function call with no subsequent statements, +/// which indicates a call to a never-returning function (like panic helpers). +/// After the simplifier's DCE pass, dead code after unreachable calls has +/// been eliminated, so a trailing call with no yields is a reliable indicator. +fn region_terminates(region: &Region, noreturn: &std::collections::BTreeSet) -> bool { + region.statements.iter().any(|s| { + if matches!( + s, + Statement::Revert { .. } + | Statement::Return { .. } + | Statement::Invalid + | Statement::Stop + | Statement::SelfDestruct { .. } + | Statement::Leave { .. } + | Statement::PanicRevert { .. } + | Statement::ErrorStringRevert { .. } + | Statement::CustomErrorRevert { .. } + ) { + return true; + } + if let Statement::Expression(Expression::Call { function, .. }) = s { + if noreturn.contains(&function.0) { + return true; + } + } + false + }) +} + +/// Resolve a ValueId through the replacement chain. +fn resolve_id(id: ValueId, replacements: &BTreeMap) -> ValueId { + let mut current = id; + for _ in 0..8 { + if let Some(&replacement) = replacements.get(¤t.0) { + current = replacement; + } else { + break; + } + } + current +} + +/// Replaces every used ValueId in the statement using the `replacements` map. +/// One-step lookup: if A→B is in the map, A becomes B; does not chase B→C. +/// Definitions (Let bindings, If/Switch/For outputs, loop_variables, ExternalCall/Create +/// result) are left untouched — only use sites are rewritten. +fn replace_value_ids_in_statement( + mut statement: Statement, + replacements: &BTreeMap, +) -> Statement { + statement.for_each_value_id_mut(&mut |id| { + if let Some(&new_id) = replacements.get(&id.0) { + *id = new_id; + } + }); + statement +} diff --git a/crates/newyork/src/heap_opt.rs b/crates/newyork/src/heap_opt.rs new file mode 100644 index 000000000..8fa96a113 --- /dev/null +++ b/crates/newyork/src/heap_opt.rs @@ -0,0 +1,1112 @@ +//! Heap optimization pass for partial heap emulation. +//! +//! This module implements an optimization strategy for handling big-endian EVM +//! memory operations on the little-endian PolkaVM/RISC-V target. The approach: +//! +//! 1. Start with a fully little-endian heap +//! 2. At compile time, analyze memory access patterns to determine alignment +//! 3. Mark regions that require big-endian emulation ("tainted" regions) +//! 4. Generate optimized code that avoids byte-swapping when possible +//! +//! # Memory Access Analysis +//! +//! Memory accesses are classified into: +//! - **Aligned accesses**: Offset is known at compile time and word-aligned (multiple of 32) +//! - **Potentially unaligned**: Offset is computed dynamically or not word-aligned +//! +//! For aligned accesses, we can often eliminate byte-swapping by keeping values +//! in native little-endian format when they don't escape to external calls. + +use std::collections::{BTreeMap, BTreeSet}; + +use crate::ir::{ + for_each_statement, word_align, Block, Expression, MemoryRegion, Object, Statement, Value, +}; +use revive_common::BYTE_LENGTH_WORD; + +/// Maximum number of words to iterate when marking escaping/tainted ranges. +/// Contracts with `return(0, 320000000000)` or similar huge constants would +/// cause billions of loop iterations without this cap. Any range exceeding +/// this is treated as a dynamic escape instead. +const MAX_RANGE_WORDS: u64 = 4096; + +/// Classification of a memory access pattern. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum AccessPattern { + /// Offset is known at compile time and word-aligned (multiple of 32). + AlignedStatic(u64), + /// Offset is known at compile time but not word-aligned. + UnalignedStatic(u64), + /// Offset is computed dynamically but provably aligned. + AlignedDynamic, + /// Offset is computed dynamically and may be unaligned. + Unknown, +} + +impl AccessPattern { + /// Returns true if this access is known to be aligned. + pub fn is_aligned(&self) -> bool { + matches!( + self, + AccessPattern::AlignedStatic(_) | AccessPattern::AlignedDynamic + ) + } + + /// Returns true if this access pattern is fully known at compile time. + pub fn is_static(&self) -> bool { + matches!( + self, + AccessPattern::AlignedStatic(_) | AccessPattern::UnalignedStatic(_) + ) + } +} + +/// Memory slot tracking for heap analysis. +#[derive(Clone, Debug)] +pub struct MemorySlot { + /// The memory region this slot belongs to. + pub region: MemoryRegion, + /// Whether this slot has been written with potentially unaligned data. + pub tainted: bool, + /// Whether this slot escapes (used in external calls, returns, etc.). + pub escapes: bool, +} + +impl Default for MemorySlot { + fn default() -> Self { + MemorySlot { + region: MemoryRegion::Unknown, + tainted: false, + escapes: false, + } + } +} + +/// Heap optimization analysis context. +pub struct HeapAnalysis { + /// Known static memory offsets and their access patterns. + memory_accesses: BTreeMap, + /// Values known to be memory offsets (for tracking alignment). + offset_values: BTreeMap, + /// Memory regions that are known to be tainted (require big-endian emulation). + tainted_regions: BTreeSet, + /// Memory regions that escape to external code. + escaping_regions: BTreeSet, + /// Whether any memory escaping statement (return, revert, external call, log, create) + /// has a dynamic (non-static) offset. When true, we cannot determine which regions + /// escape and must conservatively disable native-only mode. + has_dynamic_escapes: bool, + /// The minimum static start offset of any dynamic-length escape. + /// When a return/revert/call has a known start but unknown length, all memory + /// from this offset onwards could potentially escape. + /// `None` means no such escape exists, or the start offset is also dynamic. + min_dynamic_escape_start: Option, + /// Whether any memory access (mstore, mstore8, mcopy, mload) has a dynamic + /// (non-static) offset that we cannot track. When true, some accesses are invisible + /// to the analysis. + has_dynamic_accesses: bool, + /// Whether any statement sends memory to external code over a static range + /// that covers the FMP word at 0x40 (`return`, `revert`, `log*`, external + /// calls, `create*`, `keccak256`). When true, user data stored at 0x40 + /// would be observed by the caller in BE format, so the FMP native-mode + /// optimization is unsafe. Normal Solidity returns and reverts from + /// `free_ptr (>= 0x80)` so this fires only for inline-assembly patterns + /// like `return(0, 96)` / `revert(0, 96)`. + fmp_word_escapes: bool, + /// Static offsets that are accessed via non-literal (variable) expressions. + /// When the solc M3 optimizer turns literal offsets into variables + /// (e.g., `let size := 64; mload(size)`), the LLVM IR value won't be a constant. + /// Native mode requires LLVM constant detection, so these offsets must use + /// byte-swap mode to avoid store/load mode mismatches. + variable_accessed_offsets: BTreeSet, + /// Whether the FMP slot at 0x40 is written from a value that is not + /// provably sbrk-bounded. Solidity's allocator only ever writes + /// either a literal initial value (`0x80` from `memoryguard`) or + /// `add(mload(0x40), bounded_size)` — both keep the FMP < heap_size + /// in practice. Inline asm such as `mstore(0x40, calldataload(0))` + /// can put any 256-bit value at 0x40. When true, downstream + /// optimizations that assume `FMP < heap_size` (e.g. the post-MLoad + /// range proof) must skip the optimization to preserve EVM + /// semantics. Conservatively starts false; set by inspecting every + /// `MStore` whose target is the FMP slot. + fmp_could_be_unbounded: bool, + /// Per-`Let`-binding source expression, used by + /// `is_trusted_fmp_source` to decide whether an mstore's value + /// comes from a sbrk-style allocator pattern. Only populated for + /// bindings of size 1. + value_expressions: BTreeMap, +} + +/// Information about a value used as a memory offset. +#[derive(Clone, Debug)] +pub struct OffsetInfo { + /// Known static value, if any. + pub static_value: Option, + /// Known alignment (in bytes). 32 means word-aligned. + pub alignment: u32, + /// Whether this value originates from a literal expression (not a variable). + /// When false, the LLVM IR value may not be a constant even though the + /// newyork analysis can resolve it statically. + pub from_literal: bool, +} + +impl Default for OffsetInfo { + fn default() -> Self { + OffsetInfo { + static_value: None, + alignment: 1, + from_literal: false, + } + } +} + +impl HeapAnalysis { + /// Creates a new heap analysis context. + pub fn new() -> Self { + HeapAnalysis { + memory_accesses: BTreeMap::new(), + offset_values: BTreeMap::new(), + tainted_regions: BTreeSet::new(), + escaping_regions: BTreeSet::new(), + has_dynamic_escapes: false, + min_dynamic_escape_start: None, + has_dynamic_accesses: false, + fmp_word_escapes: false, + variable_accessed_offsets: BTreeSet::new(), + fmp_could_be_unbounded: false, + value_expressions: BTreeMap::new(), + } + } + + /// Runs heap analysis on an object. + pub fn analyze_object(&mut self, object: &Object) { + self.analyze_block(&object.code, false); + + for function in object.functions.values() { + self.analyze_block(&function.body, true); + } + + for subobject in &object.subobjects { + self.offset_values.clear(); + self.value_expressions.clear(); + self.analyze_object(subobject); + } + + self.compute_tainted_regions(); + } + + /// Analyzes a block for memory access patterns. Recursion through nested + /// regions is handled by `for_each_statement`; `analyze_statement` only handles + /// the per-statement analysis (no longer recursing internally). + fn analyze_block(&mut self, block: &Block, in_function: bool) { + for_each_statement(&block.statements, &mut |statement| { + self.analyze_statement(statement, in_function); + }); + } + + /// Analyzes a single statement for memory access patterns. The caller is + /// responsible for walking nested regions (use `for_each_statement`). + fn analyze_statement(&mut self, statement: &Statement, in_function: bool) { + match statement { + Statement::Let { bindings, value } => { + if let Some(offset_info) = self.analyze_expression_offset(value) { + for binding in bindings { + self.offset_values.insert(binding.0, offset_info.clone()); + } + } + if bindings.len() == 1 { + self.value_expressions.insert(bindings[0].0, value.clone()); + } + self.analyze_expression_side_effects(value); + } + + Statement::MStore { + offset, + value, + region, + } => { + let pattern = self.classify_access(offset); + self.track_variable_access(offset); + let static_offset = self.extract_static_offset(offset); + if let Some(addr) = static_offset { + self.memory_accesses.insert(addr, pattern); + } else { + self.has_dynamic_accesses = true; + } + if *region == MemoryRegion::Unknown && !pattern.is_aligned() { + if let Some(addr) = static_offset { + if addr % BYTE_LENGTH_WORD as u64 != 0 { + self.tainted_regions.insert(word_align(addr)); + } + } + } + // FMP unboundedness tracking: any `mstore(0x40, value)` + // whose value isn't a recognized sbrk-allocator pattern + // means the FMP could hold a non-Solidity-convention + // value at runtime. Downstream `mload(0x40)` range + // proofs / native-mode truncations assume `FMP < + // heap_size`; those assumptions break here. + let is_fmp_store = region.is_free_pointer_slot(static_offset); + if is_fmp_store && !self.is_trusted_fmp_source(value.id.0) { + self.fmp_could_be_unbounded = true; + } + } + + Statement::MStore8 { offset, .. } => { + let pattern = AccessPattern::Unknown; + if let Some(addr) = self.extract_static_offset(offset) { + self.memory_accesses.insert(addr, pattern); + self.tainted_regions.insert(word_align(addr)); + } else { + self.has_dynamic_accesses = true; + } + } + + Statement::MCopy { dest, src, length } => { + let dest_start = self.extract_static_offset(dest); + let src_start = self.extract_static_offset(src); + let len = self.extract_static_offset(length); + self.taint_range(dest_start, len); + self.taint_range(src_start, len); + } + + Statement::ExternalCall { + args_offset, + args_length, + ret_offset, + ret_length, + .. + } => { + self.mark_escaping_range(args_offset, args_length); + self.note_fmp_coverage(args_offset, args_length); + self.mark_escaping_and_tainted_range(ret_offset, ret_length); + self.note_fmp_coverage(ret_offset, ret_length); + } + + Statement::Revert { offset, length } => { + self.mark_escaping_range(offset, length); + self.note_fmp_coverage(offset, length); + } + + Statement::Return { offset, length } => { + self.mark_escaping_range(offset, length); + if in_function { + self.note_fmp_coverage(offset, length); + } + } + + Statement::Log { offset, length, .. } => { + self.mark_escaping_range(offset, length); + self.note_fmp_coverage(offset, length); + } + + Statement::Create { offset, length, .. } => { + self.mark_escaping_range(offset, length); + self.note_fmp_coverage(offset, length); + } + + Statement::If { .. } | Statement::Switch { .. } | Statement::Block(_) => {} + + Statement::For { + initial_values, + loop_variables, + outputs, + .. + } => { + for (initial_value, loop_var) in initial_values.iter().zip(loop_variables.iter()) { + if let Some(mut info) = self.offset_values.get(&initial_value.id.0).cloned() { + info.from_literal = false; + self.offset_values.insert(loop_var.0, info); + } + } + for (initial_value, output) in initial_values.iter().zip(outputs.iter()) { + if let Some(mut info) = self.offset_values.get(&initial_value.id.0).cloned() { + info.from_literal = false; + self.offset_values.insert(output.0, info); + } + } + } + + Statement::Expression(expression) => { + self.analyze_expression_side_effects(expression); + } + + Statement::ReturnDataCopy { dest, .. } => { + if let Some(addr) = self.extract_static_offset(dest) { + self.tainted_regions.insert(word_align(addr)); + } else { + self.has_dynamic_accesses = true; + } + } + + Statement::CodeCopy { dest, .. } + | Statement::ExtCodeCopy { dest, .. } + | Statement::DataCopy { dest, .. } + | Statement::CallDataCopy { dest, .. } => { + if let Some(addr) = self.extract_static_offset(dest) { + self.memory_accesses + .entry(addr) + .or_insert(AccessPattern::AlignedStatic(addr)); + self.tainted_regions.insert(word_align(addr)); + } else { + self.has_dynamic_accesses = true; + } + } + + Statement::SStore { .. } + | Statement::TStore { .. } + | Statement::MappingSStore { .. } + | Statement::SelfDestruct { .. } + | Statement::Break { .. } + | Statement::Continue { .. } + | Statement::Leave { .. } + | Statement::Stop + | Statement::Invalid + | Statement::PanicRevert { .. } + | Statement::ErrorStringRevert { .. } + | Statement::CustomErrorRevert { .. } + | Statement::SetImmutable { .. } => {} + } + } + + /// Classifies a memory access based on the offset value. + fn classify_access(&self, offset: &Value) -> AccessPattern { + if let Some(info) = self.offset_values.get(&offset.id.0) { + if let Some(static_val) = info.static_value { + if static_val % BYTE_LENGTH_WORD as u64 == 0 { + return AccessPattern::AlignedStatic(static_val); + } else { + return AccessPattern::UnalignedStatic(static_val); + } + } + if info.alignment >= 32 { + return AccessPattern::AlignedDynamic; + } + } + AccessPattern::Unknown + } + + /// Extracts a static offset value if known. + fn extract_static_offset(&self, offset: &Value) -> Option { + self.offset_values + .get(&offset.id.0) + .and_then(|info| info.static_value) + } + + /// Records that a static offset was accessed via a non-literal expression. + /// This means LLVM may not see it as a constant, causing a mode mismatch + /// if we use native mode for literal accesses to the same offset. + fn track_variable_access(&mut self, offset: &Value) { + if let Some(info) = self.offset_values.get(&offset.id.0) { + if let Some(static_val) = info.static_value { + if !info.from_literal { + self.variable_accessed_offsets.insert(static_val); + } + } + } + } + + /// Marks all word-aligned memory regions in [offset, offset+length) as escaping. + /// Notes a static escape range that may cover the FMP word at 0x40. + /// Each external escape statement (`revert`, `return` in a function, + /// `log*`, external `call`, `create*`, `keccak256`) must call this so + /// `fmp_native_safe()` can disable the FMP native-mode encoding when + /// the FMP value would be observed externally in BE format. + /// + /// - `(static_start, static_len)` covering `[0x40, 0x60)` → set + /// `fmp_word_escapes`. + /// - `(static_start, dynamic_len)` with `start <= 0x40` → could cover + /// FMP, set `min_dynamic_escape_start` to that word. + /// - `(dynamic, _)` → offset is unknown so the escape could start + /// anywhere including at/below 0x40; lower `min_dynamic_escape_start` + /// to 0 so `fmp_native_safe()` rejects. + fn note_fmp_coverage(&mut self, offset: &Value, length: &Value) { + let start = self.extract_static_offset(offset); + let len = self.extract_static_offset(length); + match (start, len) { + (Some(s), Some(l)) => { + if s <= 0x40 && s.saturating_add(l) >= 0x60 { + self.fmp_word_escapes = true; + } + } + (Some(s), None) => { + let word_start = word_align(s); + self.min_dynamic_escape_start = Some( + self.min_dynamic_escape_start + .map_or(word_start, |prev| prev.min(word_start)), + ); + } + (None, _) => { + self.min_dynamic_escape_start = Some(0); + } + } + } + + fn mark_escaping_range(&mut self, offset: &Value, length: &Value) { + let start = self.extract_static_offset(offset); + let len = self.extract_static_offset(length); + match (start, len) { + (Some(_), Some(0)) => {} + (Some(addr), Some(size)) => { + let end = addr.saturating_add(size); + let first_word = word_align(addr); + let range = end.saturating_sub(first_word); + let num_words = + range.saturating_add(BYTE_LENGTH_WORD as u64 - 1) / BYTE_LENGTH_WORD as u64; + if num_words > MAX_RANGE_WORDS { + self.escaping_regions.insert(first_word); + self.has_dynamic_escapes = true; + } else { + let mut word = first_word; + while word < end { + self.escaping_regions.insert(word); + word += BYTE_LENGTH_WORD as u64; + } + } + } + (Some(addr), None) => { + self.escaping_regions.insert(word_align(addr)); + self.has_dynamic_escapes = true; + } + (None, _) => { + self.has_dynamic_escapes = true; + } + } + } + + /// Taints all word-aligned memory regions in a range. + /// If the range is too large, treats it as a dynamic access instead. + fn taint_range(&mut self, start: Option, len: Option) { + match (start, len) { + (Some(addr), Some(size)) if size > 0 => { + let end = addr.saturating_add(size); + let first_word = word_align(addr); + let num_words = end + .saturating_sub(first_word) + .saturating_add(BYTE_LENGTH_WORD as u64 - 1) + / BYTE_LENGTH_WORD as u64; + if num_words > MAX_RANGE_WORDS { + self.tainted_regions.insert(first_word); + self.has_dynamic_accesses = true; + } else { + let mut word = first_word; + while word < end { + self.tainted_regions.insert(word); + word += BYTE_LENGTH_WORD as u64; + } + } + } + (Some(addr), _) => { + self.tainted_regions.insert(word_align(addr)); + self.has_dynamic_accesses = true; + } + (None, _) => { + self.has_dynamic_accesses = true; + } + } + } + + /// Marks all word-aligned memory regions in a range as both escaping and tainted. + fn mark_escaping_and_tainted_range(&mut self, offset: &Value, length: &Value) { + let start = self.extract_static_offset(offset); + let len = self.extract_static_offset(length); + match (start, len) { + (Some(addr), Some(size)) if size > 0 => { + let end = addr.saturating_add(size); + let first_word = word_align(addr); + let num_words = end + .saturating_sub(first_word) + .saturating_add(BYTE_LENGTH_WORD as u64 - 1) + / BYTE_LENGTH_WORD as u64; + if num_words > MAX_RANGE_WORDS { + self.escaping_regions.insert(first_word); + self.tainted_regions.insert(first_word); + self.has_dynamic_escapes = true; + } else { + let mut word = first_word; + while word < end { + self.escaping_regions.insert(word); + self.tainted_regions.insert(word); + word += BYTE_LENGTH_WORD as u64; + } + } + } + (Some(addr), None) => { + self.escaping_regions.insert(word_align(addr)); + self.tainted_regions.insert(word_align(addr)); + self.has_dynamic_escapes = true; + } + _ => { + self.has_dynamic_escapes = true; + } + } + } + + /// Analyzes an expression to extract offset information. + fn analyze_expression_offset(&self, expression: &Expression) -> Option { + match expression { + Expression::Literal { value, .. } => { + let digits = value.to_u64_digits(); + let static_val = if digits.is_empty() { + 0 + } else if digits.len() == 1 { + digits[0] + } else { + return None; + }; + Some(OffsetInfo { + static_value: Some(static_val), + alignment: compute_alignment(static_val), + from_literal: true, + }) + } + + Expression::Var(id) => self.offset_values.get(&id.0).cloned().map(|mut info| { + info.from_literal = false; + info + }), + + Expression::Binary { + operation, + lhs, + rhs, + } => { + let lhs_info = self.offset_values.get(&lhs.id.0); + let rhs_info = self.offset_values.get(&rhs.id.0); + + match operation { + crate::ir::BinaryOperation::Add => { + let lhs_align = lhs_info.map(|i| i.alignment).unwrap_or(1); + let rhs_align = rhs_info.map(|i| i.alignment).unwrap_or(1); + let result_align = gcd(lhs_align, rhs_align); + + let static_val = match ( + lhs_info.and_then(|i| i.static_value), + rhs_info.and_then(|i| i.static_value), + ) { + (Some(l), Some(r)) => Some(l.wrapping_add(r)), + _ => None, + }; + + Some(OffsetInfo { + static_value: static_val, + alignment: result_align, + from_literal: false, + }) + } + + crate::ir::BinaryOperation::Mul => { + let static_val = match ( + lhs_info.and_then(|i| i.static_value), + rhs_info.and_then(|i| i.static_value), + ) { + (Some(l), Some(r)) => Some(l.wrapping_mul(r)), + _ => None, + }; + + let mult_align = match ( + rhs_info.and_then(|i| i.static_value), + lhs_info.and_then(|i| i.static_value), + ) { + (Some(32), _) | (_, Some(32)) => 32, + (Some(n), _) | (_, Some(n)) if n % 32 == 0 => 32, + _ => 1, + }; + + Some(OffsetInfo { + static_value: static_val, + alignment: mult_align, + from_literal: false, + }) + } + + crate::ir::BinaryOperation::And => { + if let Some(mask) = rhs_info.and_then(|i| i.static_value) { + let align = compute_alignment((!mask).wrapping_add(1)); + Some(OffsetInfo { + static_value: None, + alignment: align.max(1), + from_literal: false, + }) + } else { + None + } + } + + crate::ir::BinaryOperation::Shl => { + if let Some(shift) = rhs_info.and_then(|i| i.static_value) { + if shift < 32 { + let base_align = lhs_info.map(|i| i.alignment).unwrap_or(1); + Some(OffsetInfo { + static_value: None, + alignment: base_align.saturating_mul(1 << shift), + from_literal: false, + }) + } else { + None + } + } else { + None + } + } + + _ => None, + } + } + + Expression::MLoad { .. } => None, + + Expression::CallDataLoad { .. } => None, + + _ => None, + } + } + + /// Analyzes expression side effects on memory. + fn analyze_expression_side_effects(&mut self, expression: &Expression) { + match expression { + Expression::MLoad { offset, .. } => { + let _ = self.classify_access(offset); + self.track_variable_access(offset); + if self.extract_static_offset(offset).is_none() { + self.has_dynamic_accesses = true; + } + } + Expression::Keccak256 { offset, length } => { + let _ = self.classify_access(offset); + if self.extract_static_offset(offset).is_none() { + self.has_dynamic_accesses = true; + } + self.mark_escaping_range(offset, length); + self.note_fmp_coverage(offset, length); + } + Expression::Keccak256Pair { .. } | Expression::Keccak256Single { .. } => {} + Expression::MappingSLoad { .. } => {} + _ => {} + } + } + + /// Computes which regions need big-endian emulation. + fn compute_tainted_regions(&mut self) { + for ®ion in &self.escaping_regions { + self.tainted_regions.insert(region); + } + } + + /// Returns whether a memory region requires big-endian emulation. + pub fn requires_big_endian(&self, addr: u64) -> bool { + let word_addr = word_align(addr); + self.tainted_regions.contains(&word_addr) || self.escaping_regions.contains(&word_addr) + } + + /// Returns whether a memory region escapes to external code. + pub fn region_escapes(&self, addr: u64) -> bool { + let word_addr = word_align(addr); + self.escaping_regions.contains(&word_addr) + } + + /// Returns the set of tainted memory regions (word-aligned addresses). + pub fn tainted_regions(&self) -> &BTreeSet { + &self.tainted_regions + } + + /// Returns the set of escaping memory regions. + pub fn escaping_regions(&self) -> &BTreeSet { + &self.escaping_regions + } + + /// Returns whether any escaping statement has a dynamic (non-static) offset. + pub fn has_dynamic_escapes(&self) -> bool { + self.has_dynamic_escapes + } + + /// Returns the minimum start offset of any dynamic-length escape. + pub fn min_dynamic_escape_start(&self) -> Option { + self.min_dynamic_escape_start + } + + /// Returns whether any memory access has a dynamic (non-static) offset. + pub fn has_dynamic_accesses(&self) -> bool { + self.has_dynamic_accesses + } + + /// Returns whether any `return` statement covers the FMP slot at 0x40. + pub fn fmp_word_escapes(&self) -> bool { + self.fmp_word_escapes + } + + /// Returns whether any FMP write uses a value that is not provably + /// sbrk-bounded. See `fmp_could_be_unbounded` field doc. + pub fn fmp_could_be_unbounded(&self) -> bool { + self.fmp_could_be_unbounded + } + + /// Walks the (possibly transitive) `Let` chain for `value_id` and + /// returns true iff its source expression matches a Solidity-allocator + /// pattern that keeps the FMP < heap_size at runtime. Recognized + /// patterns: + /// - Literal (`memoryguard(0x80)` collapses to this; any literal + /// small enough that `mstore(0x40, )` would have to + /// have been written by the contract author with the allocator + /// invariant in mind — we trust them). + /// - `Var(x)` where `x` itself is trusted (forwarding chain). + /// - `Binary { Add, ... }` where at least one operand is trusted + /// (the canonical `add(mload(0x40), bounded_size)` pattern, or + /// its variants with both operands derived from FMP arithmetic). + /// - `MLoad { offset: 0x40, .. }` — reads the current FMP, which + /// sbrk-style code uses as the base for new allocations. + /// - `Keccak256Single` / `Keccak256Pair` — solc never writes a + /// hash to FMP, but the simplifier does fuse mload(0x40) + + /// keccak in mapping lookups; we don't actually expect this + /// to flow to mstore(0x40), so flagging it would be a false + /// negative. Out of caution we say "not trusted". + /// + /// Anything else (e.g. `CallDataLoad`, `SLoad`, opaque function + /// returns, arithmetic involving untrusted values) is treated as + /// potentially-non-bounded. + /// + /// Walks at most `MAX_FMP_TRUST_DEPTH` `Var` links to avoid loops. + fn is_trusted_fmp_source(&self, value_id: u32) -> bool { + const MAX_FMP_TRUST_DEPTH: u32 = 32; + let mut current = value_id; + for _ in 0..MAX_FMP_TRUST_DEPTH { + let Some(expression) = self.value_expressions.get(¤t) else { + // No known Let binding for `current`: it's either a + // function parameter or a result whose Let we haven't + // visited yet. Either way, we can't prove it's + // sbrk-bounded. + return false; + }; + match expression { + Expression::Literal { .. } => return true, + Expression::MLoad { offset, .. } => { + return self.extract_static_offset(offset) == Some(0x40); + } + Expression::Var(inner) => { + current = inner.0; + continue; + } + Expression::Binary { + operation: crate::ir::BinaryOperation::Add, + lhs, + rhs, + } => { + // `add(trusted, _)` is trusted iff at least one + // operand is trusted. Solidity's allocator emits + // `add(mload(0x40), bounded_size)` which fits this. + return self.is_trusted_fmp_source(lhs.id.0) + || self.is_trusted_fmp_source(rhs.id.0); + } + Expression::Binary { + operation: crate::ir::BinaryOperation::And, + lhs, + rhs, + } => { + // `and(trusted, _)` is trusted. `guard_narrow.rs`'s + // body-rewrite synthesizes `mstore(0x40, and(sum, + // max_const))` for any allocator that matches + // `has_allocator_shape`. The `sum` chain leads back + // through `add(mload(0x40), aligned_size)`, which + // recurses to trusted via the `Add` arm above. + return self.is_trusted_fmp_source(lhs.id.0) + || self.is_trusted_fmp_source(rhs.id.0); + } + _ => return false, + } + } + false + } + + /// Returns the set of static offsets accessed via non-literal expressions. + pub fn variable_accessed_offsets(&self) -> &BTreeSet { + &self.variable_accessed_offsets + } + + /// Returns statistics about the analysis. + pub fn statistics(&self) -> HeapAnalysisStats { + let total_accesses = self.memory_accesses.len(); + let aligned_accesses = self + .memory_accesses + .values() + .filter(|p| p.is_aligned()) + .count(); + let static_accesses = self + .memory_accesses + .values() + .filter(|p| p.is_static()) + .count(); + + HeapAnalysisStats { + total_accesses, + aligned_accesses, + static_accesses, + tainted_regions: self.tainted_regions.len(), + escaping_regions: self.escaping_regions.len(), + } + } +} + +impl Default for HeapAnalysis { + fn default() -> Self { + Self::new() + } +} + +/// Statistics from heap analysis. +#[derive(Clone, Debug)] +pub struct HeapAnalysisStats { + /// Total number of memory accesses analyzed. + pub total_accesses: usize, + /// Number of accesses that are known to be aligned. + pub aligned_accesses: usize, + /// Number of accesses with statically known offsets. + pub static_accesses: usize, + /// Number of tainted regions requiring big-endian emulation. + pub tainted_regions: usize, + /// Number of regions that escape to external code. + pub escaping_regions: usize, +} + +/// Results of heap analysis that can be used during code generation. +/// +/// This struct captures which memory addresses can use native byte order +/// (skip byte-swapping) because they are: +/// 1. Word-aligned (offset is multiple of 32) +/// 2. Not escaping to external code +/// 3. Not tainted by unaligned writes +#[derive(Clone, Debug, Default)] +pub struct HeapOptResults { + /// Memory addresses (word-aligned) that can use native byte order. + /// These are addresses that are NOT in tainted_regions and NOT in escaping_regions. + pub native_safe_regions: BTreeSet, + /// Static offsets that are known to be safe for native access. + pub native_safe_offsets: BTreeSet, + /// Total number of memory accesses analyzed. + pub total_accesses: usize, + /// Number of accesses that have unknown/dynamic offsets. + pub unknown_accesses: usize, + /// Number of tainted regions (require big-endian). + pub tainted_count: usize, + /// Number of escaping regions (external interfaces). + pub escaping_count: usize, + /// Whether any escaping statement has a dynamic offset we cannot track. + pub has_dynamic_escapes: bool, + /// The minimum start offset of any dynamic-length escape. + min_dynamic_escape_start: Option, + /// Whether any memory access has a dynamic offset we cannot track. + pub has_dynamic_accesses: bool, + /// Whether any `return` statement covers the FMP slot at 0x40. + /// When true, the FMP native-mode optimization is unsafe. + fmp_word_escapes: bool, + /// Static offsets that are accessed via non-literal (variable) expressions. + /// These offsets may not be LLVM constants, so native mode would cause + /// a store/load mode mismatch with literal accesses to the same offset. + variable_accessed_offsets: BTreeSet, + /// Whether some `mstore(0x40, value)` in the program writes a value + /// that isn't provably sbrk-bounded. See HeapAnalysis docs. + fmp_could_be_unbounded: bool, +} + +impl HeapOptResults { + /// Creates results from a completed heap analysis. + pub fn from_analysis(analysis: &HeapAnalysis) -> Self { + let mut native_safe_regions = BTreeSet::new(); + let mut native_safe_offsets = BTreeSet::new(); + let mut unknown_accesses = 0; + + for (&addr, pattern) in &analysis.memory_accesses { + if matches!(pattern, AccessPattern::Unknown) { + unknown_accesses += 1; + } else if pattern.is_aligned() { + let word_addr = word_align(addr); + if !analysis.requires_big_endian(addr) { + native_safe_regions.insert(word_addr); + native_safe_offsets.insert(addr); + } + } + } + + HeapOptResults { + native_safe_regions, + native_safe_offsets, + total_accesses: analysis.memory_accesses.len(), + unknown_accesses, + tainted_count: analysis.tainted_regions().len(), + escaping_count: analysis.escaping_regions().len(), + has_dynamic_escapes: analysis.has_dynamic_escapes(), + min_dynamic_escape_start: analysis.min_dynamic_escape_start(), + has_dynamic_accesses: analysis.has_dynamic_accesses(), + fmp_word_escapes: analysis.fmp_word_escapes(), + variable_accessed_offsets: analysis.variable_accessed_offsets().clone(), + fmp_could_be_unbounded: analysis.fmp_could_be_unbounded(), + } + } + + /// Returns whether any FMP write writes a value not provably bounded + /// by heap_size. When true, codegen optimizations that rely on + /// `FMP < heap_size` (the post-MLoad range proof, InlineNative + /// truncations on the FMP slot) must be skipped — those + /// assumptions hold only for the Solidity allocator pattern. + pub fn fmp_could_be_unbounded(&self) -> bool { + self.fmp_could_be_unbounded + } + + /// Checks if a static offset can use native byte order. + pub fn can_use_native(&self, offset: u64) -> bool { + if self.has_dynamic_accesses { + return false; + } + if self.variable_accessed_offsets.contains(&offset) { + return false; + } + if let Some(min_start) = self.min_dynamic_escape_start { + let word_offset = word_align(offset); + if word_offset >= min_start { + return false; + } + } + if self.has_dynamic_escapes && offset >= 0x60 { + return false; + } + if self.native_safe_offsets.contains(&offset) { + return true; + } + let word_addr = word_align(offset); + self.native_safe_regions.contains(&word_addr) + } + + /// Returns true if any optimization opportunities were found. + pub fn has_optimizations(&self) -> bool { + !self.native_safe_regions.is_empty() + } + + /// Returns true if the FMP slot at 0x40 is safe for native-mode optimization. + /// This is false when: + /// - A static escape covers offset 0x40 (e.g., `return(0, 96)`, + /// `revert(0, 96)`, `log0(0, 96)`, `call(.., 0, 96, ..)`, `keccak256(0, 96)`) + /// - A dynamic-length escape starts at or before 0x40 (e.g., `return(0, dynamic)`) + /// - Offset 0x40 is accessed via a non-literal expression (LLVM won't see a constant) + /// - Any memory access uses a fully dynamic offset (could touch 0x40) + pub fn fmp_native_safe(&self) -> bool { + if self.variable_accessed_offsets.contains(&0x40) { + return false; + } + if self.has_dynamic_accesses { + return false; + } + if self.fmp_word_escapes { + return false; + } + if let Some(min_start) = self.min_dynamic_escape_start { + if min_start <= 0x40 { + return false; + } + } + true + } + + /// Returns true if ALL memory accesses can use native byte order. + /// + /// This is used to enable the native-only heap mode, where we only emit + /// native heap functions and skip byte-swapping entirely. This is beneficial + /// only when ALL accesses are native-safe; otherwise, emitting both native + /// and non-native functions increases code size. + /// + /// Native-only mode is enabled when: + /// 1. There are memory accesses that were analyzed + /// 2. No unknown/dynamic accesses exist + /// 3. No memory escapes to external code (calls, returns, logs) + /// 4. No tainted regions (unaligned writes) + pub fn all_native(&self) -> bool { + self.total_accesses > 0 + && self.unknown_accesses == 0 + && self.tainted_count == 0 + && self.escaping_count == 0 + && !self.has_dynamic_escapes + && !self.has_dynamic_accesses + } + + /// Checks if ANY native optimizations are available. + /// This is a weaker condition than `all_native()` - it means at least some + /// accesses can use native byte order, but we may need mixed mode. + pub fn has_any_native(&self) -> bool { + !self.native_safe_regions.is_empty() + } +} + +/// Computes the alignment of a value (highest power of 2 that divides it). +fn compute_alignment(value: u64) -> u32 { + if value == 0 { + return 32; + } + value.trailing_zeros().min(5) +} + +/// Computes GCD of two numbers. +fn gcd(a: u32, b: u32) -> u32 { + if b == 0 { + a + } else { + gcd(b, a % b) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use num::BigUint; + + #[test] + fn test_alignment_computation() { + assert_eq!(compute_alignment(0), 32); + assert_eq!(compute_alignment(1), 0); + assert_eq!(compute_alignment(2), 1); + assert_eq!(compute_alignment(4), 2); + assert_eq!(compute_alignment(32), 5); + assert_eq!(compute_alignment(64), 5); + assert_eq!(compute_alignment(33), 0); + } + + #[test] + fn test_access_pattern_classification() { + assert!(AccessPattern::AlignedStatic(0).is_aligned()); + assert!(AccessPattern::AlignedStatic(32).is_aligned()); + assert!(AccessPattern::AlignedDynamic.is_aligned()); + assert!(!AccessPattern::UnalignedStatic(1).is_aligned()); + assert!(!AccessPattern::Unknown.is_aligned()); + + assert!(AccessPattern::AlignedStatic(0).is_static()); + assert!(AccessPattern::UnalignedStatic(1).is_static()); + assert!(!AccessPattern::AlignedDynamic.is_static()); + assert!(!AccessPattern::Unknown.is_static()); + } + + #[test] + fn test_gcd() { + assert_eq!(gcd(32, 64), 32); + assert_eq!(gcd(12, 18), 6); + assert_eq!(gcd(17, 13), 1); + assert_eq!(gcd(0, 5), 5); + } + + #[test] + fn test_offset_info_from_literal() { + let analysis = HeapAnalysis::new(); + + let expression = Expression::Literal { + value: BigUint::from(0u32), + value_type: crate::ir::Type::default(), + }; + let info = analysis.analyze_expression_offset(&expression).unwrap(); + assert_eq!(info.static_value, Some(0)); + assert_eq!(info.alignment, 32); + + let expression = Expression::Literal { + value: BigUint::from(64u32), + value_type: crate::ir::Type::default(), + }; + let info = analysis.analyze_expression_offset(&expression).unwrap(); + assert_eq!(info.static_value, Some(64)); + assert_eq!(info.alignment, 5); + } +} diff --git a/crates/newyork/src/inline.rs b/crates/newyork/src/inline.rs new file mode 100644 index 000000000..ffedfd357 --- /dev/null +++ b/crates/newyork/src/inline.rs @@ -0,0 +1,1665 @@ +//! Function inlining pass for the newyork IR. +//! +//! This module implements custom inlining heuristics tailored for PolkaVM. +//! LLVM's generic inliner lacks domain knowledge about EVM/Solidity patterns, +//! so we make inlining decisions at the IR level where we have more context. +//! +//! # Approach +//! +//! 1. **Call graph analysis**: Count call sites, detect recursion +//! 2. **Heuristic decisions**: Decide which functions to inline based on +//! call count, function size, and optimization opportunity +//! 3. **IR transformation**: Inline by substituting function bodies at call sites +//! 4. **Dead function removal**: Remove functions that were fully inlined +//! +//! # Inlining Policy +//! +//! - **Always inline**: Functions called exactly once with size below +//! `SINGLE_CALL_INLINE_SIZE_THRESHOLD`, or any function with size below +//! `ALWAYS_INLINE_SIZE_THRESHOLD` and no `Leave` statements +//! - **Never inline**: Recursive functions, functions with size at or above +//! `NEVER_INLINE_SIZE_THRESHOLD`, or functions called from +//! `NEVER_INLINE_CALL_COUNT_THRESHOLD`+ sites +//! - **Cost-benefit**: For everything else, inline if benefit > cost +//! +//! # Pipeline position +//! +//! `inline_functions` is invoked twice: +//! +//! 1. **Early** — at the start of `optimize_object_tree`, before simplify / +//! mem_opt / compound_outlining / guard_narrow. The IR is full of redundant +//! `Let` bindings and unfolded arithmetic; the thresholds above were +//! empirically calibrated to that shape (see `INLINER.md`). +//! 2. **Late** — after the parameter narrowing fixed point, via +//! `run_late_inline_loop` in `lib.rs`. By then every other pass has +//! canonicalized the IR; many helper functions have collapsed to a handful +//! of statements. Refreshing `size_estimate` with [`estimate_function_sizes`] +//! before the call lets the cost model see the post-simplify shape, so the +//! same thresholds catch newly tiny wrappers that the early pass left +//! behind. + +use std::collections::{BTreeMap, BTreeSet}; + +use crate::ir::{ + for_each_statement, for_each_statement_mut, BitWidth, Block, Expression, Function, FunctionId, + Object, Region, Statement, SwitchCase, Type, UnaryOperation, Value, ValueId, +}; + +/// Maximum function size (in IR nodes) that is always inlined regardless of call count. +const ALWAYS_INLINE_SIZE_THRESHOLD: usize = 6; + +/// Maximum function size (in IR nodes) beyond which a function is never inlined. +const NEVER_INLINE_SIZE_THRESHOLD: usize = 100; + +/// Maximum function size for single-call inlining at IR level. +/// Since single-call functions are eliminated entirely (zero code duplication), +/// a higher threshold is justified. The interprocedural optimizations from +/// inlining (constant propagation, dead code elimination, type narrowing) +/// usually outweigh the register pressure increase for moderate-sized functions. +const SINGLE_CALL_INLINE_SIZE_THRESHOLD: usize = 48; + +/// Maximum number of call sites beyond which a function is never inlined. +const NEVER_INLINE_CALL_COUNT_THRESHOLD: usize = 100; + +/// Bonus for inlining a small function (enables further optimization). +const SMALL_FUNCTION_BONUS: usize = 28; + +/// Size threshold for receiving the small-function bonus in the cost-benefit +/// branch. Tightened from 15 to 10 in iter40 after measurement: at size 11–15 +/// the bonus pushes marginal functions over the cost line and the resulting +/// inlines add more lowered bytes than they save (`+1,296` regression on the +/// OZ corpus at threshold 15 vs. 10). +const SMALL_FUNCTION_BONUS_SIZE_THRESHOLD: usize = 10; + +/// Maximum call count for which the few-callsites bonus applies. The cost term +/// `(call_count - 1) * size` grows linearly with callers, so 2–3 is the regime +/// where the bonus can plausibly offset it. Calibrated alongside the rest of +/// the cost model in commit 6ea5672c ("Improve the inliner") — see INLINER.md. +const FEW_CALLS_BONUS_CALL_THRESHOLD: usize = 3; + +/// Maximum Leave count for the few-callsites bonus to apply. Each Leave becomes +/// an exit-flag + phi chain in the inlined body (see [`eliminate_leaves`]); the +/// `leaves² * 6 * call_count` term in `cost` already discourages many-Leave +/// inlines, so this threshold just keeps single-Leave functions in play. +const FEW_CALLS_BONUS_LEAVE_THRESHOLD: usize = 1; + +/// Cost-benefit bonus when a function has both few call sites +/// ([`FEW_CALLS_BONUS_CALL_THRESHOLD`]) and few Leaves +/// ([`FEW_CALLS_BONUS_LEAVE_THRESHOLD`]). Retuned from 10 to 15 in commit +/// 6ea5672c as part of an end-to-end cost-model retune that landed −8.95% on +/// the OZ corpus. INLINER.md records that the model is at a local optimum on +/// this axis, so don't perturb in isolation without re-running the corpus. +const FEW_CALLS_BONUS: usize = 15; + +/// Results of the call graph analysis. +#[derive(Debug, Clone)] +pub struct CallGraphAnalysis { + /// Number of call sites per function. + pub call_counts: BTreeMap, + /// Set of functions that are (mutually) recursive. + pub recursive_functions: BTreeSet, + /// Call graph edges: caller -> set of callees. + pub call_edges: BTreeMap>, + /// Calls from top-level code (not inside any function). + pub top_level_calls: BTreeSet, +} + +/// Results of the inlining pass. +#[derive(Debug, Clone, Default)] +pub struct InlineResults { + /// Number of call sites that were inlined. + pub inlined_call_sites: usize, + /// Functions that were fully inlined and removed. + pub removed_functions: BTreeSet, + /// Inlining decisions made per function. + pub decisions: BTreeMap, +} + +/// The inlining decision for a function. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum InlineDecision { + /// Always inline this function at every call site. + AlwaysInline, + /// Never inline this function — emitted as a standalone callable. + NeverInline, + /// The cost-benefit heuristic could not justify inlining. The IR-level pass + /// leaves the function intact; downstream codegen also marks multi-call + /// `CostBenefit` functions with LLVM `NoInline` so the LLVM inliner does + /// not undo the decision by inlining at every call site (a behavior that + /// regressed code size on the PolkaVM target — see iter38 in + /// `RALPH_TASK.md`). + CostBenefit, +} + +/// Analyzes the call graph of an IR object. +/// +/// Walks all functions and the top-level code block to: +/// - Count how many times each function is called +/// - Build caller->callee edges +/// - Detect recursive functions via Tarjan's SCC +pub fn analyze_call_graph(object: &Object) -> CallGraphAnalysis { + let mut call_counts: BTreeMap = BTreeMap::new(); + let mut call_edges: BTreeMap> = BTreeMap::new(); + let mut top_level_calls: BTreeSet = BTreeSet::new(); + + for &func_id in object.functions.keys() { + call_counts.insert(func_id, 0); + call_edges.insert(func_id, BTreeSet::new()); + } + + count_calls_in_block(&object.code, &mut call_counts, &mut top_level_calls); + + for (&func_id, function) in &object.functions { + let mut callee_set = BTreeSet::new(); + count_calls_in_block(&function.body, &mut call_counts, &mut callee_set); + call_edges.insert(func_id, callee_set); + } + + let recursive_functions = find_recursive_functions(&call_edges); + + CallGraphAnalysis { + call_counts, + recursive_functions, + call_edges, + top_level_calls, + } +} + +/// Counts call sites in a block, incrementing call_counts and recording callees. +fn count_calls_in_block( + block: &Block, + call_counts: &mut BTreeMap, + callees: &mut BTreeSet, +) { + for_each_statement(&block.statements, &mut |statement| { + statement.for_each_expression(&mut |expression| { + if let Expression::Call { function, .. } = expression { + *call_counts.entry(*function).or_insert(0) += 1; + callees.insert(*function); + } + }); + }); +} + +/// Finds recursive functions using iterative SCC detection. +/// +/// A function is recursive if it belongs to an SCC of size > 1, +/// or if it has a self-edge (direct recursion). +fn find_recursive_functions( + call_edges: &BTreeMap>, +) -> BTreeSet { + let mut recursive = BTreeSet::new(); + + for (&func_id, callees) in call_edges { + if callees.contains(&func_id) { + recursive.insert(func_id); + } + } + + let all_functions: Vec = call_edges.keys().copied().collect(); + for &start in &all_functions { + if recursive.contains(&start) { + continue; + } + let mut visited = BTreeSet::new(); + let mut stack: Vec = call_edges + .get(&start) + .map(|s| s.iter().copied().collect()) + .unwrap_or_default(); + + while let Some(current) = stack.pop() { + if current == start { + recursive.insert(start); + break; + } + if !visited.insert(current) { + continue; + } + if let Some(next_callees) = call_edges.get(¤t) { + for &next in next_callees { + if !visited.contains(&next) { + stack.push(next); + } + } + } + } + } + + recursive +} + +/// Estimated IR node overhead per Leave statement during inline expansion. +/// Each Leave adds: accum assignment(s) + done flag + IsZero + If guard (~6 nodes). +/// Additionally, each Leave wraps all subsequent statements in a nested guard, +/// so the overhead grows quadratically with the number of Leaves (N Leaves +/// produce O(N^2) nesting as each guard re-wraps the remaining guarded code). +const LEAVE_OVERHEAD_PER_SITE: usize = 6; + +/// Counts the number of Leave statements in a block (recursing into nested +/// regions and `For::condition_statements`, but not into other functions). +fn count_leaves(block: &Block) -> usize { + let mut count = 0; + for_each_statement(&block.statements, &mut |statement| { + if matches!(statement, Statement::Leave { .. }) { + count += 1; + } + }); + count +} + +/// Recomputes the `size_estimate` field on every function from its current body. +/// +/// The initial size estimates are recorded by the Yul translator before any simplification has +/// occurred. After simplify/narrow passes change the IR, re-estimation is required so the inliner +/// makes decisions on the post-simplify shape rather than the original pre-simplify shape. +pub fn estimate_function_sizes(object: &mut Object) { + for function in object.functions.values_mut() { + function.size_estimate = estimate_block_size(&function.body); + } +} + +/// Decides which functions should be inlined. +pub fn make_inline_decisions( + object: &Object, + analysis: &CallGraphAnalysis, +) -> BTreeMap { + let mut decisions = BTreeMap::new(); + + for (&func_id, function) in &object.functions { + let call_count = analysis.call_counts.get(&func_id).copied().unwrap_or(0); + let size = function.size_estimate; + let is_recursive = analysis.recursive_functions.contains(&func_id); + let leave_count = count_leaves(&function.body); + + let decision = if is_recursive || call_count == 0 || size >= NEVER_INLINE_SIZE_THRESHOLD { + InlineDecision::NeverInline + } else if call_count == 1 && size <= SINGLE_CALL_INLINE_SIZE_THRESHOLD { + InlineDecision::AlwaysInline + } else if call_count == 1 { + InlineDecision::CostBenefit + } else if size <= ALWAYS_INLINE_SIZE_THRESHOLD && leave_count == 0 { + InlineDecision::AlwaysInline + } else if call_count >= NEVER_INLINE_CALL_COUNT_THRESHOLD { + InlineDecision::NeverInline + } else { + let leave_overhead = leave_count * leave_count * LEAVE_OVERHEAD_PER_SITE * call_count; + let cost = (call_count - 1) * size + leave_overhead; + let mut benefit = 0; + + if size <= SMALL_FUNCTION_BONUS_SIZE_THRESHOLD && leave_count == 0 { + benefit += SMALL_FUNCTION_BONUS; + } + + if call_count <= FEW_CALLS_BONUS_CALL_THRESHOLD + && leave_count <= FEW_CALLS_BONUS_LEAVE_THRESHOLD + { + benefit += FEW_CALLS_BONUS; + } + + if benefit > cost { + InlineDecision::AlwaysInline + } else { + InlineDecision::CostBenefit + } + }; + + decisions.insert(func_id, decision); + } + + decisions +} + +/// State for SSA value remapping during inlining. +struct InlineRemapper { + /// Maps old ValueId -> new ValueId. + value_map: BTreeMap, + /// Next fresh value ID to allocate. + next_value_id: ValueId, +} + +impl InlineRemapper { + /// Creates a new remapper starting from the given next ID. + fn new(next_value_id: ValueId) -> Self { + InlineRemapper { + value_map: BTreeMap::new(), + next_value_id, + } + } + + /// Gets or creates a fresh ID for the given old ID. + fn remap_value_id(&mut self, old: ValueId) -> ValueId { + if let Some(&new_id) = self.value_map.get(&old) { + new_id + } else { + let new_id = self.next_value_id.fresh(); + self.value_map.insert(old, new_id); + new_id + } + } + + /// Clones the source statements and rewrites every `ValueId` (definitions and + /// uses) through `remap_value_id`. Used to inline a function body at a + /// call site with a fresh SSA namespace. + fn remap_statements(&mut self, source: &[Statement]) -> Vec { + let mut statements = source.to_vec(); + for_each_statement_mut(&mut statements, &mut |statement| { + statement.for_each_value_id_def_mut(&mut |id| *id = self.remap_value_id(*id)); + }); + for statement in &mut statements { + statement.for_each_value_id_mut(&mut |id| *id = self.remap_value_id(*id)); + } + statements + } +} + +/// Checks whether a function can be inlined. +/// +/// A function can be inlined if it doesn't have top-level Break/Continue +/// statements (those would conflict with an outer loop context). +/// Leave statements are handled during inlining by wrapping the body +/// in a single-iteration For loop and converting Leave to Break. +fn can_inline(function: &Function) -> bool { + fn has_top_level_break_continue(block: &Block) -> bool { + block.statements.iter().any(check_stmt_for_break_continue) + } + + fn check_stmt_for_break_continue(statement: &Statement) -> bool { + match statement { + Statement::Break { .. } | Statement::Continue { .. } => true, + Statement::If { + then_region, + else_region, + .. + } => { + region_has_break_continue(then_region) + || else_region.as_ref().is_some_and(region_has_break_continue) + } + Statement::Switch { cases, default, .. } => { + cases.iter().any(|c| region_has_break_continue(&c.body)) + || default.as_ref().is_some_and(region_has_break_continue) + } + Statement::For { .. } => false, + Statement::Block(region) => region_has_break_continue(region), + _ => false, + } + } + + fn region_has_break_continue(region: &Region) -> bool { + region.statements.iter().any(check_stmt_for_break_continue) + } + + !has_top_level_break_continue(&function.body) +} + +/// Checks if a function has Leave statements inside any For loop (at any +/// nesting level). Leave inside For is not handled by our IR-level inliner. +fn has_leave_in_for(block: &Block) -> bool { + let mut found = false; + for_each_statement(&block.statements, &mut |statement| { + if let Statement::For { + body, + post, + condition_statements, + .. + } = statement + { + if statements_have_leave(&body.statements) + || statements_have_leave(&post.statements) + || statements_have_leave(condition_statements) + { + found = true; + } + } + }); + found +} + +/// Checks if a slice of statements contains any Leave at any nesting level. +fn statements_have_leave(statements: &[Statement]) -> bool { + let mut found = false; + for_each_statement(statements, &mut |s| { + if matches!(s, Statement::Leave { .. }) { + found = true; + } + }); + found +} + +fn statement_has_leave_recursive(statement: &Statement) -> bool { + statements_have_leave(std::slice::from_ref(statement)) +} + +/// Allocates a fresh ValueId. +fn fresh_id(next_id: &mut ValueId) -> ValueId { + next_id.fresh() +} + +/// Result of Leave elimination on a statement list. +struct LeaveElimResult { + statements: Vec, + accum_ids: Vec, + done_id: Option, +} + +/// Eliminates Leave statements from a list of (already remapped) statements. +/// +/// Uses the "exit flag" pattern: when Leave is encountered, return values are +/// stored in accumulator variables and a "done" flag is set. Subsequent statements +/// are guarded by `if !done`, using the If statement's inputs/outputs as phi nodes. +fn eliminate_leaves( + statements: &[Statement], + accum_ids: &[ValueId], + next_id: &mut ValueId, +) -> LeaveElimResult { + let mut result_statements = Vec::new(); + let mut current_accums = accum_ids.to_vec(); + let mut done_id: Option = None; + + for (index, statement) in statements.iter().enumerate() { + if let Some(done) = done_id { + let remaining = &statements[index..]; + if !remaining.is_empty() { + let guarded = wrap_remaining_in_guard(remaining, ¤t_accums, done, next_id); + result_statements.extend(guarded.statements); + return LeaveElimResult { + statements: result_statements, + accum_ids: guarded.accum_ids, + done_id: guarded.done_id, + }; + } + break; + } + + match statement { + Statement::Leave { return_values } => { + let new_accums: Vec = return_values + .iter() + .map(|v| { + let id = fresh_id(next_id); + result_statements.push(Statement::Let { + bindings: vec![id], + value: Expression::Var(v.id), + }); + id + }) + .collect(); + let done = fresh_id(next_id); + result_statements.push(Statement::Let { + bindings: vec![done], + value: Expression::Literal { + value: num::BigUint::from(1u32), + value_type: Type::Int(BitWidth::I256), + }, + }); + current_accums = new_accums; + done_id = Some(done); + continue; + } + + _ if statement_has_leave_recursive(statement) => { + let transformed = transform_leave_statement(statement, ¤t_accums, next_id); + result_statements.extend(transformed.statements); + current_accums = transformed.accum_ids; + done_id = transformed.done_id; + } + + _ => { + result_statements.push(statement.clone()); + } + } + } + + LeaveElimResult { + statements: result_statements, + accum_ids: current_accums, + done_id, + } +} + +/// Wraps remaining statements in `if !done { ... }` guard. +/// When done=true (Leave was taken), inputs flow to outputs unchanged. +/// When done=false, the then_region executes and its yields flow to outputs. +fn wrap_remaining_in_guard( + statements: &[Statement], + accum_ids: &[ValueId], + done_id: ValueId, + next_id: &mut ValueId, +) -> LeaveElimResult { + let mut pre_stmts = Vec::new(); + + let not_done = fresh_id(next_id); + pre_stmts.push(Statement::Let { + bindings: vec![not_done], + value: Expression::Unary { + operation: UnaryOperation::IsZero, + operand: Value { + id: done_id, + value_type: Type::Int(BitWidth::I256), + }, + }, + }); + + let inner = eliminate_leaves(statements, accum_ids, next_id); + + let new_accums: Vec = accum_ids.iter().map(|_| fresh_id(next_id)).collect(); + + let then_yields: Vec = inner + .accum_ids + .iter() + .map(|&id| Value { + id, + value_type: Type::Int(BitWidth::I256), + }) + .collect(); + let inputs: Vec = accum_ids + .iter() + .map(|&id| Value { + id, + value_type: Type::Int(BitWidth::I256), + }) + .collect(); + + pre_stmts.push(Statement::If { + condition: Value { + id: not_done, + value_type: Type::Int(BitWidth::I256), + }, + inputs, + then_region: Region { + statements: inner.statements, + yields: then_yields, + }, + else_region: None, + outputs: new_accums.clone(), + }); + + LeaveElimResult { + statements: pre_stmts, + accum_ids: new_accums, + done_id: Some(done_id), + } +} + +/// Collects all ValueIds defined at the top scope of a statement list. +/// This includes Let bindings, If/Switch outputs, but NOT values inside nested regions. +fn collect_top_scope_defs(statements: &[Statement]) -> Vec { + let mut definitions = Vec::new(); + for statement in statements { + match statement { + Statement::Let { bindings, .. } => { + definitions.extend_from_slice(bindings); + } + Statement::If { outputs, .. } | Statement::Switch { outputs, .. } => { + definitions.extend_from_slice(outputs); + } + Statement::For { outputs, .. } => { + definitions.extend_from_slice(outputs); + } + _ => {} + } + } + definitions +} + +/// Checks if a ValueId is defined anywhere within a region (recursively). +fn region_defines_value(region: &Region, target: ValueId) -> bool { + for statement in ®ion.statements { + match statement { + Statement::Let { bindings, .. } if bindings.contains(&target) => { + return true; + } + Statement::If { + outputs, + then_region, + else_region, + .. + } => { + if outputs.contains(&target) { + return true; + } + if region_defines_value(then_region, target) { + return true; + } + if let Some(r) = else_region { + if region_defines_value(r, target) { + return true; + } + } + } + Statement::Switch { + outputs, + cases, + default, + .. + } => { + if outputs.contains(&target) { + return true; + } + for c in cases { + if region_defines_value(&c.body, target) { + return true; + } + } + if let Some(d) = default { + if region_defines_value(d, target) { + return true; + } + } + } + Statement::For { + outputs, + condition_statements, + body, + post, + .. + } => { + if outputs.contains(&target) { + return true; + } + for s in condition_statements { + if let Statement::Let { bindings, .. } = s { + if bindings.contains(&target) { + return true; + } + } + } + if region_defines_value(body, target) { + return true; + } + if region_defines_value(post, target) { + return true; + } + } + Statement::Block(r) if region_defines_value(r, target) => { + return true; + } + _ => {} + } + } + false +} + +/// After leave elimination, some original yield values may be inside guard Ifs +/// (created by `wrap_remaining_in_guard`). This function promotes those values +/// to be additional outputs of the guard If, so they're accessible at the outer scope. +fn promote_yields_from_guards( + statements: &mut [Statement], + yields: &mut [Value], + top_defs: &[ValueId], + next_id: &mut ValueId, +) { + for yield_val in yields.iter_mut() { + if top_defs.contains(&yield_val.id) { + continue; + } + for statement in statements.iter_mut() { + if let Statement::If { + ref mut then_region, + ref mut inputs, + ref mut outputs, + .. + } = statement + { + if region_defines_value(then_region, yield_val.id) { + then_region.yields.push(*yield_val); + let new_out = fresh_id(next_id); + outputs.push(new_out); + let placeholder = inputs.first().copied().unwrap_or(*yield_val); + inputs.push(placeholder); + yield_val.id = new_out; + break; + } + } + } + } +} + +/// Transforms a statement that contains Leave in its sub-structure. +fn transform_leave_statement( + statement: &Statement, + accum_ids: &[ValueId], + next_id: &mut ValueId, +) -> LeaveElimResult { + match statement { + Statement::If { + condition, + inputs: orig_inputs, + then_region, + else_region, + outputs: orig_outputs, + } => { + let mut pre_stmts = Vec::new(); + + let done_false_id = fresh_id(next_id); + pre_stmts.push(Statement::Let { + bindings: vec![done_false_id], + value: Expression::Literal { + value: num::BigUint::from(0u32), + value_type: Type::Int(BitWidth::I256), + }, + }); + + let then_result = if statements_have_leave(&then_region.statements) { + eliminate_leaves(&then_region.statements, accum_ids, next_id) + } else { + LeaveElimResult { + statements: then_region.statements.clone(), + accum_ids: accum_ids.to_vec(), + done_id: None, + } + }; + let then_done = then_result.done_id.unwrap_or(done_false_id); + + let mut then_stmts = then_result.statements; + let mut then_yields: Vec = then_region.yields.clone(); + + let then_top_defs = collect_top_scope_defs(&then_stmts); + promote_yields_from_guards(&mut then_stmts, &mut then_yields, &then_top_defs, next_id); + + then_yields.extend(then_result.accum_ids.iter().map(|&id| Value { + id, + value_type: Type::Int(BitWidth::I256), + })); + then_yields.push(Value { + id: then_done, + value_type: Type::Int(BitWidth::I256), + }); + + let new_accums: Vec = accum_ids.iter().map(|_| fresh_id(next_id)).collect(); + let new_done = fresh_id(next_id); + let mut all_outputs: Vec = orig_outputs.clone(); + all_outputs.extend(new_accums.iter()); + all_outputs.push(new_done); + + if let Some(else_r) = else_region { + let else_result = if statements_have_leave(&else_r.statements) { + eliminate_leaves(&else_r.statements, accum_ids, next_id) + } else { + LeaveElimResult { + statements: else_r.statements.clone(), + accum_ids: accum_ids.to_vec(), + done_id: None, + } + }; + let else_done = else_result.done_id.unwrap_or(done_false_id); + + let mut else_stmts = else_result.statements; + let mut else_yields: Vec = else_r.yields.clone(); + + let else_top_defs = collect_top_scope_defs(&else_stmts); + promote_yields_from_guards( + &mut else_stmts, + &mut else_yields, + &else_top_defs, + next_id, + ); + + else_yields.extend(else_result.accum_ids.iter().map(|&id| Value { + id, + value_type: Type::Int(BitWidth::I256), + })); + else_yields.push(Value { + id: else_done, + value_type: Type::Int(BitWidth::I256), + }); + + let mut inputs: Vec = orig_inputs.clone(); + inputs.extend(accum_ids.iter().map(|&id| Value { + id, + value_type: Type::Int(BitWidth::I256), + })); + inputs.push(Value { + id: done_false_id, + value_type: Type::Int(BitWidth::I256), + }); + + pre_stmts.push(Statement::If { + condition: *condition, + inputs, + then_region: Region { + statements: then_stmts, + yields: then_yields, + }, + else_region: Some(Region { + statements: else_stmts, + yields: else_yields, + }), + outputs: all_outputs, + }); + } else { + let mut inputs: Vec = orig_inputs.clone(); + inputs.extend(accum_ids.iter().map(|&id| Value { + id, + value_type: Type::Int(BitWidth::I256), + })); + inputs.push(Value { + id: done_false_id, + value_type: Type::Int(BitWidth::I256), + }); + + pre_stmts.push(Statement::If { + condition: *condition, + inputs, + then_region: Region { + statements: then_stmts, + yields: then_yields, + }, + else_region: None, + outputs: all_outputs, + }); + } + + LeaveElimResult { + statements: pre_stmts, + accum_ids: new_accums, + done_id: Some(new_done), + } + } + + Statement::Switch { + scrutinee, + inputs: orig_inputs, + cases, + default, + outputs: orig_outputs, + } => { + let mut pre_stmts = Vec::new(); + + let done_false_id = fresh_id(next_id); + pre_stmts.push(Statement::Let { + bindings: vec![done_false_id], + value: Expression::Literal { + value: num::BigUint::from(0u32), + value_type: Type::Int(BitWidth::I256), + }, + }); + + let new_cases: Vec = cases + .iter() + .map(|c| { + let case_result = if statements_have_leave(&c.body.statements) { + eliminate_leaves(&c.body.statements, accum_ids, next_id) + } else { + LeaveElimResult { + statements: c.body.statements.clone(), + accum_ids: accum_ids.to_vec(), + done_id: None, + } + }; + let case_done = case_result.done_id.unwrap_or(done_false_id); + + let mut statements = case_result.statements; + let mut yields: Vec = c.body.yields.clone(); + + let top_defs = collect_top_scope_defs(&statements); + promote_yields_from_guards(&mut statements, &mut yields, &top_defs, next_id); + + yields.extend(case_result.accum_ids.iter().map(|&id| Value { + id, + value_type: Type::Int(BitWidth::I256), + })); + yields.push(Value { + id: case_done, + value_type: Type::Int(BitWidth::I256), + }); + SwitchCase { + value: c.value.clone(), + body: Region { statements, yields }, + } + }) + .collect(); + + let new_default = default.as_ref().map(|d| { + let def_result = if statements_have_leave(&d.statements) { + eliminate_leaves(&d.statements, accum_ids, next_id) + } else { + LeaveElimResult { + statements: d.statements.clone(), + accum_ids: accum_ids.to_vec(), + done_id: None, + } + }; + let def_done = def_result.done_id.unwrap_or(done_false_id); + + let mut statements = def_result.statements; + let mut yields: Vec = d.yields.clone(); + + let top_defs = collect_top_scope_defs(&statements); + promote_yields_from_guards(&mut statements, &mut yields, &top_defs, next_id); + + yields.extend(def_result.accum_ids.iter().map(|&id| Value { + id, + value_type: Type::Int(BitWidth::I256), + })); + yields.push(Value { + id: def_done, + value_type: Type::Int(BitWidth::I256), + }); + Region { statements, yields } + }); + + let new_accums: Vec = accum_ids.iter().map(|_| fresh_id(next_id)).collect(); + let new_done = fresh_id(next_id); + let mut all_outputs: Vec = orig_outputs.clone(); + all_outputs.extend(new_accums.iter()); + all_outputs.push(new_done); + + let mut inputs: Vec = orig_inputs.clone(); + inputs.extend(accum_ids.iter().map(|&id| Value { + id, + value_type: Type::Int(BitWidth::I256), + })); + inputs.push(Value { + id: done_false_id, + value_type: Type::Int(BitWidth::I256), + }); + + pre_stmts.push(Statement::Switch { + scrutinee: *scrutinee, + inputs, + cases: new_cases, + default: new_default, + outputs: all_outputs, + }); + + LeaveElimResult { + statements: pre_stmts, + accum_ids: new_accums, + done_id: Some(new_done), + } + } + + Statement::Block(region) => eliminate_leaves(®ion.statements, accum_ids, next_id), + + _ => LeaveElimResult { + statements: vec![statement.clone()], + accum_ids: accum_ids.to_vec(), + done_id: None, + }, + } +} + +/// Performs inlining on an IR object. +/// +/// This is the main entry point for the inlining pass. It: +/// 1. Analyzes the call graph +/// 2. Makes inlining decisions +/// 3. Performs the actual inlining transformations +/// 4. Removes fully-inlined dead functions +/// 5. Updates call counts and size estimates +pub fn inline_functions(object: &mut Object) -> InlineResults { + let mut results = InlineResults::default(); + + let analysis = analyze_call_graph(object); + + for (&func_id, function) in object.functions.iter_mut() { + function.call_count = analysis.call_counts.get(&func_id).copied().unwrap_or(0); + } + + let decisions = make_inline_decisions(object, &analysis); + results.decisions = decisions.clone(); + + let mut next_value_id = ValueId(object.find_max_value_id() + 1); + + let functions_snapshot: BTreeMap = object.functions.clone(); + + let inlineable: BTreeSet = decisions + .iter() + .filter_map(|(&func_id, &decision)| { + if decision == InlineDecision::AlwaysInline { + if let Some(function) = functions_snapshot.get(&func_id) { + if can_inline(function) && !has_leave_in_for(&function.body) { + return Some(func_id); + } + } + } + None + }) + .collect(); + + if inlineable.is_empty() { + return results; + } + + let new_code_stmts = inline_in_statements( + &object.code.statements, + &inlineable, + &functions_snapshot, + &mut next_value_id, + &mut results.inlined_call_sites, + ); + object.code.statements = new_code_stmts; + + let func_ids: Vec = object.functions.keys().copied().collect(); + for func_id in func_ids { + let function = object.functions.get(&func_id).unwrap().clone(); + let new_body_stmts = inline_in_statements( + &function.body.statements, + &inlineable, + &functions_snapshot, + &mut next_value_id, + &mut results.inlined_call_sites, + ); + if let Some(f) = object.functions.get_mut(&func_id) { + f.body.statements = new_body_stmts; + } + } + + let new_analysis = analyze_call_graph(object); + let mut to_remove = Vec::new(); + for (&func_id, &count) in &new_analysis.call_counts { + if count == 0 { + to_remove.push(func_id); + results.removed_functions.insert(func_id); + } + } + for func_id in &to_remove { + object.functions.remove(func_id); + } + + for (&func_id, function) in object.functions.iter_mut() { + function.call_count = new_analysis.call_counts.get(&func_id).copied().unwrap_or(0); + function.size_estimate = estimate_block_size(&function.body); + } + + results +} + +/// Performs inlining within a list of statements. +/// Returns the new list of statements with call sites replaced by inlined bodies. +fn inline_in_statements( + statements: &[Statement], + inlineable: &BTreeSet, + functions: &BTreeMap, + next_value_id: &mut ValueId, + inlined_count: &mut usize, +) -> Vec { + let mut result = Vec::new(); + + for statement in statements { + match statement { + Statement::Let { + bindings, + value: + Expression::Call { + function, + arguments, + }, + } if inlineable.contains(function) => { + if let Some(func_def) = functions.get(function) { + let inlined = + inline_call_with_results(func_def, arguments, bindings, next_value_id); + result.extend(inlined); + *inlined_count += 1; + } else { + result.push(statement.clone()); + } + } + + Statement::Expression(Expression::Call { + function, + arguments, + }) if inlineable.contains(function) => { + if let Some(func_def) = functions.get(function) { + let inlined = inline_call_void(func_def, arguments, next_value_id); + result.extend(inlined); + *inlined_count += 1; + } else { + result.push(statement.clone()); + } + } + + Statement::If { + condition, + inputs, + then_region, + else_region, + outputs, + } => { + result.push(Statement::If { + condition: *condition, + inputs: inputs.clone(), + then_region: inline_in_region( + then_region, + inlineable, + functions, + next_value_id, + inlined_count, + ), + else_region: else_region.as_ref().map(|r| { + inline_in_region(r, inlineable, functions, next_value_id, inlined_count) + }), + outputs: outputs.clone(), + }); + } + + Statement::Switch { + scrutinee, + inputs, + cases, + default, + outputs, + } => { + result.push(Statement::Switch { + scrutinee: *scrutinee, + inputs: inputs.clone(), + cases: cases + .iter() + .map(|c| SwitchCase { + value: c.value.clone(), + body: inline_in_region( + &c.body, + inlineable, + functions, + next_value_id, + inlined_count, + ), + }) + .collect(), + default: default.as_ref().map(|r| { + inline_in_region(r, inlineable, functions, next_value_id, inlined_count) + }), + outputs: outputs.clone(), + }); + } + + Statement::For { + initial_values, + loop_variables, + condition_statements, + condition, + body, + post_input_variables, + post, + outputs, + } => { + let new_cond_stmts = inline_in_statements( + condition_statements, + inlineable, + functions, + next_value_id, + inlined_count, + ); + result.push(Statement::For { + initial_values: initial_values.clone(), + loop_variables: loop_variables.clone(), + condition_statements: new_cond_stmts, + condition: condition.clone(), + body: inline_in_region( + body, + inlineable, + functions, + next_value_id, + inlined_count, + ), + post_input_variables: post_input_variables.clone(), + post: inline_in_region( + post, + inlineable, + functions, + next_value_id, + inlined_count, + ), + outputs: outputs.clone(), + }); + } + + Statement::Block(region) => { + result.push(Statement::Block(inline_in_region( + region, + inlineable, + functions, + next_value_id, + inlined_count, + ))); + } + + other => result.push(other.clone()), + } + } + + result +} + +/// Performs inlining within a region. +fn inline_in_region( + region: &Region, + inlineable: &BTreeSet, + functions: &BTreeMap, + next_value_id: &mut ValueId, + inlined_count: &mut usize, +) -> Region { + Region { + statements: inline_in_statements( + ®ion.statements, + inlineable, + functions, + next_value_id, + inlined_count, + ), + yields: region.yields.clone(), + } +} + +/// Inlines a function call that produces results (used in Let bindings). +/// +/// Handles functions with Leave statements by eliminating them using the +/// "exit flag" pattern with If outputs as phi nodes. +fn inline_call_with_results( + function: &Function, + arguments: &[Value], + result_bindings: &[ValueId], + next_value_id: &mut ValueId, +) -> Vec { + let mut remapper = InlineRemapper::new(*next_value_id); + let mut statements = Vec::new(); + + debug_assert_eq!( + function.parameters.len(), + arguments.len(), + "inliner: argument count mismatch for function (expected {}, got {})", + function.parameters.len(), + arguments.len() + ); + for ((parameter_id, _param_ty), argument) in function.parameters.iter().zip(arguments.iter()) { + let new_parameter_id = remapper.remap_value_id(*parameter_id); + statements.push(Statement::Let { + bindings: vec![new_parameter_id], + value: Expression::Var(argument.id), + }); + } + + for &ret_init_id in &function.return_values_initial { + let new_ret_id = remapper.remap_value_id(ret_init_id); + statements.push(Statement::Let { + bindings: vec![new_ret_id], + value: Expression::Literal { + value: num::BigUint::from(0u32), + value_type: Type::Int(BitWidth::I256), + }, + }); + } + + let remapped_body = remapper.remap_statements(&function.body.statements); + *next_value_id = remapper.next_value_id; + + let initial_accums: Vec = function + .return_values_initial + .iter() + .filter_map(|id| remapper.value_map.get(id).copied()) + .collect(); + let fallthrough_ids: Vec = function + .return_values + .iter() + .filter_map(|id| remapper.value_map.get(id).copied()) + .collect(); + + let mut body_with_leave = remapped_body; + body_with_leave.push(Statement::Leave { + return_values: fallthrough_ids + .iter() + .map(|&id| Value { + id, + value_type: Type::Int(BitWidth::I256), + }) + .collect(), + }); + + let elim = eliminate_leaves(&body_with_leave, &initial_accums, next_value_id); + statements.extend(elim.statements); + + for (result_binding, final_ret) in result_bindings.iter().zip(elim.accum_ids.iter()) { + statements.push(Statement::Let { + bindings: vec![*result_binding], + value: Expression::Var(*final_ret), + }); + } + + statements +} + +/// Inlines a function call whose result is discarded. +fn inline_call_void( + function: &Function, + arguments: &[Value], + next_value_id: &mut ValueId, +) -> Vec { + let mut remapper = InlineRemapper::new(*next_value_id); + let mut statements = Vec::new(); + + for ((parameter_id, _), argument) in function.parameters.iter().zip(arguments.iter()) { + let new_parameter_id = remapper.remap_value_id(*parameter_id); + statements.push(Statement::Let { + bindings: vec![new_parameter_id], + value: Expression::Var(argument.id), + }); + } + + for &ret_init_id in &function.return_values_initial { + let new_ret_id = remapper.remap_value_id(ret_init_id); + statements.push(Statement::Let { + bindings: vec![new_ret_id], + value: Expression::Literal { + value: num::BigUint::from(0u32), + value_type: Type::Int(BitWidth::I256), + }, + }); + } + + let remapped_body = remapper.remap_statements(&function.body.statements); + *next_value_id = remapper.next_value_id; + + if statements_have_leave(&remapped_body) { + let initial_accums: Vec = function + .return_values_initial + .iter() + .filter_map(|id| remapper.value_map.get(id).copied()) + .collect(); + + let elim = eliminate_leaves(&remapped_body, &initial_accums, next_value_id); + statements.extend(elim.statements); + } else { + statements.extend(remapped_body); + } + + statements +} + +/// Estimates the size of a block (same metric used by from_yul.rs). +pub(crate) fn estimate_block_size(block: &Block) -> usize { + block.statements.iter().map(estimate_statement_size).sum() +} + +/// Estimates the size of a statement. +fn estimate_statement_size(statement: &Statement) -> usize { + match statement { + Statement::Let { .. } => 1, + Statement::MStore { .. } | Statement::MStore8 { .. } | Statement::MCopy { .. } => 1, + Statement::SStore { .. } | Statement::TStore { .. } => 1, + Statement::If { + then_region, + else_region, + .. + } => { + 1 + estimate_region_size(then_region) + + else_region.as_ref().map_or(0, estimate_region_size) + } + Statement::Switch { cases, default, .. } => { + 1 + cases + .iter() + .map(|c| estimate_region_size(&c.body)) + .sum::() + + default.as_ref().map_or(0, estimate_region_size) + } + Statement::For { body, post, .. } => { + 1 + estimate_region_size(body) + estimate_region_size(post) + } + Statement::Block(region) => estimate_region_size(region), + Statement::Expression(_) => 1, + _ => 1, + } +} + +/// Estimates the size of a region. +fn estimate_region_size(region: &Region) -> usize { + region.statements.iter().map(estimate_statement_size).sum() +} + +#[cfg(test)] +mod tests { + use super::*; + use num::BigUint; + + /// Helper to create a simple function with the given number of statements. + fn make_simple_function( + id: u32, + name: &str, + num_stmts: usize, + num_params: usize, + num_returns: usize, + ) -> Function { + let mut function = Function::new(FunctionId::new(id), name.to_string()); + + let mut next_id = id * 1000; + for _ in 0..num_params { + function + .parameters + .push((ValueId::new(next_id), Type::Int(BitWidth::I256))); + next_id += 1; + } + + for _ in 0..num_returns { + function.returns.push(Type::Int(BitWidth::I256)); + function.return_values_initial.push(ValueId::new(next_id)); + next_id += 1; + } + + for i in 0..num_stmts { + function.body.push(Statement::Let { + bindings: vec![ValueId::new(next_id)], + value: Expression::Literal { + value: BigUint::from(i as u32), + value_type: Type::Int(BitWidth::I256), + }, + }); + next_id += 1; + } + + if num_returns > 0 { + let first_ret = next_id - num_stmts as u32; + for i in 0..num_returns { + function + .return_values + .push(ValueId::new(first_ret + i as u32)); + } + } + + function.size_estimate = num_stmts; + function + } + + #[test] + fn test_call_count_analysis() { + let mut object = Object::new("test".to_string()); + + let g = make_simple_function(1, "g", 3, 0, 1); + let g_id = g.id; + + let mut f = Function::new(FunctionId::new(0), "f".to_string()); + f.body.push(Statement::Let { + bindings: vec![ValueId::new(100)], + value: Expression::Call { + function: g_id, + arguments: vec![], + }, + }); + f.body.push(Statement::Let { + bindings: vec![ValueId::new(101)], + value: Expression::Call { + function: g_id, + arguments: vec![], + }, + }); + f.size_estimate = 2; + let f_id = f.id; + + object.functions.insert(f_id, f); + object.functions.insert(g_id, g); + + object.code.push(Statement::Expression(Expression::Call { + function: f_id, + arguments: vec![], + })); + + let analysis = analyze_call_graph(&object); + + assert_eq!(analysis.call_counts.get(&f_id), Some(&1)); + assert_eq!(analysis.call_counts.get(&g_id), Some(&2)); + assert!(analysis.recursive_functions.is_empty()); + assert!(analysis.top_level_calls.contains(&f_id)); + } + + #[test] + fn test_recursion_detection() { + let mut object = Object::new("test".to_string()); + + let mut f = Function::new(FunctionId::new(0), "f".to_string()); + f.body.push(Statement::Expression(Expression::Call { + function: FunctionId::new(0), + arguments: vec![], + })); + f.size_estimate = 1; + object.functions.insert(f.id, f); + + let analysis = analyze_call_graph(&object); + assert!(analysis.recursive_functions.contains(&FunctionId::new(0))); + } + + #[test] + fn test_mutual_recursion_detection() { + let mut object = Object::new("test".to_string()); + + let mut f = Function::new(FunctionId::new(0), "f".to_string()); + f.body.push(Statement::Expression(Expression::Call { + function: FunctionId::new(1), + arguments: vec![], + })); + f.size_estimate = 1; + + let mut g = Function::new(FunctionId::new(1), "g".to_string()); + g.body.push(Statement::Expression(Expression::Call { + function: FunctionId::new(0), + arguments: vec![], + })); + g.size_estimate = 1; + + object.functions.insert(f.id, f); + object.functions.insert(g.id, g); + + let analysis = analyze_call_graph(&object); + assert!(analysis.recursive_functions.contains(&FunctionId::new(0))); + assert!(analysis.recursive_functions.contains(&FunctionId::new(1))); + } + + #[test] + fn test_inline_single_call_function() { + let mut object = Object::new("test".to_string()); + + let mut g = Function::new(FunctionId::new(1), "g".to_string()); + let g_ret_init = ValueId::new(1000); + let g_ret_final = ValueId::new(1001); + g.returns.push(Type::Int(BitWidth::I256)); + g.return_values_initial.push(g_ret_init); + g.body.push(Statement::Let { + bindings: vec![g_ret_final], + value: Expression::Literal { + value: BigUint::from(42u32), + value_type: Type::Int(BitWidth::I256), + }, + }); + g.return_values.push(g_ret_final); + g.size_estimate = 1; + g.call_count = 0; + + object.functions.insert(g.id, g); + + object.code.push(Statement::Let { + bindings: vec![ValueId::new(99)], + value: Expression::Call { + function: FunctionId::new(1), + arguments: vec![], + }, + }); + + let results = inline_functions(&mut object); + + assert_eq!(results.inlined_call_sites, 1); + assert!(results.removed_functions.contains(&FunctionId::new(1))); + assert!(!object.functions.contains_key(&FunctionId::new(1))); + + assert!(object.code.statements.len() > 1); + let has_call = object.code.statements.iter().any(|s| { + matches!( + s, + Statement::Let { + value: Expression::Call { .. }, + .. + } + ) + }); + assert!(!has_call, "Call should have been inlined"); + } + + #[test] + fn test_never_inline_recursive() { + let mut object = Object::new("test".to_string()); + + let mut f = Function::new(FunctionId::new(0), "f".to_string()); + f.body.push(Statement::Expression(Expression::Call { + function: FunctionId::new(0), + arguments: vec![], + })); + f.size_estimate = 1; + object.functions.insert(f.id, f); + + object.code.push(Statement::Expression(Expression::Call { + function: FunctionId::new(0), + arguments: vec![], + })); + + let results = inline_functions(&mut object); + + assert_eq!(results.inlined_call_sites, 0); + assert!(object.functions.contains_key(&FunctionId::new(0))); + } + + #[test] + fn test_inline_decisions() { + let mut object = Object::new("test".to_string()); + + let small = make_simple_function(0, "small", 3, 0, 0); + object.functions.insert(small.id, small); + + let medium = make_simple_function(1, "medium", 50, 0, 0); + object.functions.insert(medium.id, medium); + + let large = make_simple_function(2, "large", 150, 0, 0); + object.functions.insert(large.id, large); + + object.code.push(Statement::Expression(Expression::Call { + function: FunctionId::new(0), + arguments: vec![], + })); + for _ in 0..15 { + object.code.push(Statement::Expression(Expression::Call { + function: FunctionId::new(1), + arguments: vec![], + })); + } + object.code.push(Statement::Expression(Expression::Call { + function: FunctionId::new(2), + arguments: vec![], + })); + + let analysis = analyze_call_graph(&object); + let decisions = make_inline_decisions(&object, &analysis); + + assert_eq!( + decisions.get(&FunctionId::new(0)), + Some(&InlineDecision::AlwaysInline) + ); + // medium (size 50, 15 callers): with NEVER_INLINE_CALL_COUNT_THRESHOLD + // now at 100, this drops to the cost-benefit branch which rejects it + // (cost 700, benefit 0) so it ends up CostBenefit rather than + // NeverInline. Both effectively keep the body intact and tell LLVM + // not to inline; the distinction matters only for trace dumps. + assert_eq!( + decisions.get(&FunctionId::new(1)), + Some(&InlineDecision::CostBenefit) + ); + assert_eq!( + decisions.get(&FunctionId::new(2)), + Some(&InlineDecision::NeverInline) + ); + } +} diff --git a/crates/newyork/src/ir.rs b/crates/newyork/src/ir.rs new file mode 100644 index 000000000..6f0ed538a --- /dev/null +++ b/crates/newyork/src/ir.rs @@ -0,0 +1,1747 @@ +//! IR data structures for the newyork intermediate representation. +//! +//! This module defines the core IR types based on an SSA form with structured +//! control flow, similar to MLIR's SCF dialect. The design preserves high-level +//! structure from Yul while enabling domain-specific optimizations. + +use num::BigUint; +use revive_common::BYTE_LENGTH_WORD; +use std::collections::BTreeMap; + +/// Bit width for integer types. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum BitWidth { + I1 = 1, + I8 = 8, + I32 = 32, + I64 = 64, + I128 = 128, + I160 = 160, + I256 = 256, +} + +impl BitWidth { + /// Returns the bit width as a u32 for LLVM type construction. + pub fn bits(self) -> u32 { + self as u32 + } + + /// Returns the smallest BitWidth variant that has at least `bits` bits. + pub fn from_bits(bits: u32) -> Self { + if bits <= 1 { + BitWidth::I1 + } else if bits <= 8 { + BitWidth::I8 + } else if bits <= 32 { + BitWidth::I32 + } else if bits <= 64 { + BitWidth::I64 + } else if bits <= 128 { + BitWidth::I128 + } else if bits <= 160 { + BitWidth::I160 + } else { + BitWidth::I256 + } + } + + /// Determines the minimum bit width that can hold the given value. + pub fn from_max_value(value: &BigUint) -> Self { + if *value <= BigUint::from(1u8) { + BitWidth::I1 + } else if *value <= BigUint::from(u8::MAX) { + BitWidth::I8 + } else if *value <= BigUint::from(u32::MAX) { + BitWidth::I32 + } else if *value <= BigUint::from(u64::MAX) { + BitWidth::I64 + } else if *value <= BigUint::from(u128::MAX) { + BitWidth::I128 + } else if *value < BigUint::from(2u8).pow(160) { + BitWidth::I160 + } else { + BitWidth::I256 + } + } +} + +/// Address space for pointers - distinguishes memory regions. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum AddressSpace { + /// EVM heap memory (linear, big-endian). + Heap, + /// Native stack allocations (little-endian, optimizable). + Stack, + /// Contract storage (key-value, 256-bit slots). + Storage, + /// Code/data segment (read-only). + Code, +} + +/// Type of a value in the IR. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum Type { + /// Integer with specific bit width. + Int(BitWidth), + /// Pointer with address space. + Ptr(AddressSpace), + /// No value (for statements/void returns). + Void, +} + +impl Default for Type { + fn default() -> Self { + Type::Int(BitWidth::I256) + } +} + +/// Memory region annotation for heap operations. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default)] +pub enum MemoryRegion { + /// Scratch space: addresses 0x00-0x3f (64 bytes). + Scratch, + /// Free memory pointer location: address 0x40. + FreePointerSlot, + /// Dynamic allocation region: 0x80+. + Dynamic, + /// Unknown region (conservative). + #[default] + Unknown, +} + +impl MemoryRegion { + /// Determines the memory region from a statically known address. + pub fn from_address(addr: &BigUint) -> Self { + let addr_u64 = addr.to_u64_digits(); + if addr_u64.is_empty() || (addr_u64.len() == 1 && addr_u64[0] < 0x40) { + MemoryRegion::Scratch + } else if addr_u64.len() == 1 && addr_u64[0] == 0x40 { + MemoryRegion::FreePointerSlot + } else if addr_u64.len() == 1 && addr_u64[0] >= 0x80 { + MemoryRegion::Dynamic + } else { + MemoryRegion::Unknown + } + } + + /// Returns whether a memory access targets the free memory pointer slot (`0x40`). + /// + /// Two independent signals identify an FMP access and neither subsumes the + /// other, so both must be checked: + /// - `self == FreePointerSlot`: the region tag assigned by [`MemoryRegion::from_address`] + /// at translation time from a literal `0x40` offset. This catches accesses + /// whose offset value a later pass cannot fold back to a constant (offset + /// resolution only tracks locally visible literal bindings). + /// - `resolved_offset == Some(0x40)`: a *computed* offset (e.g. `add(0x20, 0x20)`) + /// that a constant-folding pass resolves to `0x40` but that was tagged + /// `Unknown` at translation time because no literal was visible then. + /// + /// `resolved_offset` is the caller's best constant resolution of the access + /// offset, or `None` when it could not be resolved. + pub fn is_free_pointer_slot(self, resolved_offset: Option) -> bool { + self == MemoryRegion::FreePointerSlot || resolved_offset == Some(0x40) + } +} + +/// Rounds a byte address down to the start of its EVM word. +pub fn word_align(address: u64) -> u64 { + address / BYTE_LENGTH_WORD as u64 * BYTE_LENGTH_WORD as u64 +} + +/// An SSA value reference (index into value table). +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct ValueId(pub u32); + +impl ValueId { + /// Creates a new value ID. + pub fn new(id: u32) -> Self { + ValueId(id) + } + + /// Returns the current value ID and advances `self` to the next one. + /// Used by counter fields and locals that allocate fresh IDs. + pub fn fresh(&mut self) -> ValueId { + let id = *self; + self.0 += 1; + id + } +} + +/// A typed SSA value. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct Value { + /// SSA identity of the value. + pub id: ValueId, + /// Static type of the value (bit width and integer/pointer kind). + pub value_type: Type, +} + +impl Value { + /// Creates a new typed value. + pub fn new(id: ValueId, value_type: Type) -> Self { + Value { id, value_type } + } + + /// Creates an integer value with default I256 type. + pub fn int(id: ValueId) -> Self { + Value::new(id, Type::Int(BitWidth::I256)) + } +} + +/// Binary operation kinds. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum BinaryOperation { + Add, + Sub, + Mul, + Div, + SDiv, + Mod, + SMod, + Exp, + AddMod, + MulMod, + And, + Or, + Xor, + Shl, + Shr, + Sar, + Lt, + Gt, + Slt, + Sgt, + Eq, + Byte, + SignExtend, +} + +/// Unary operation kinds. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum UnaryOperation { + /// Zero check - result is I1. + IsZero, + /// Bitwise NOT. + Not, + /// Count leading zeros. + Clz, +} + +/// External call kinds. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum CallKind { + Call, + CallCode, + DelegateCall, + StaticCall, +} + +/// Contract creation kinds. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum CreateKind { + Create, + Create2, +} + +/// Function identifier, unique within a single [`Object`] but **not** across objects. +/// +/// Each [`Object`] (top-level and every subobject) owns its own `functions` map +/// and issues IDs starting from `0`, so the same `FunctionId(N)` in two different +/// objects refers to two unrelated functions. Passes that walk an object tree +/// must look up names/bodies in the *current* object's table — never the parent's. +/// +/// Cross-object references go through the [`Object`] `subobjects` field and +/// contract-creation expressions, not through `FunctionId`. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct FunctionId(pub u32); + +impl FunctionId { + /// Creates a new function ID. + pub fn new(id: u32) -> Self { + FunctionId(id) + } +} + +/// Pure expressions that produce values without side effects. +#[derive(Clone, Debug)] +pub enum Expression { + /// Literal constant. + Literal { + value: BigUint, + value_type: Type, + }, + + /// Reference to an SSA value. + Var(ValueId), + + /// Binary operation. + Binary { + operation: BinaryOperation, + lhs: Value, + rhs: Value, + }, + + /// Ternary operation (addmod, mulmod). + Ternary { + operation: BinaryOperation, + a: Value, + b: Value, + n: Value, + }, + + /// Unary operation. + Unary { + operation: UnaryOperation, + operand: Value, + }, + + CallDataLoad { + offset: Value, + }, + CallValue, + Caller, + Origin, + CallDataSize, + CodeSize, + GasPrice, + ExtCodeSize { + address: Value, + }, + ReturnDataSize, + ExtCodeHash { + address: Value, + }, + BlockHash { + number: Value, + }, + Coinbase, + Timestamp, + Number, + Difficulty, + GasLimit, + ChainId, + SelfBalance, + BaseFee, + BlobHash { + index: Value, + }, + BlobBaseFee, + Gas, + MSize, + Address, + Balance { + address: Value, + }, + + /// Memory load with region annotation. + MLoad { + offset: Value, + region: MemoryRegion, + }, + + /// Storage load with optional static slot. + SLoad { + key: Value, + /// If key is a compile-time constant, store it here for analysis. + static_slot: Option, + }, + + /// Transient storage load. + TLoad { + key: Value, + }, + + /// Function call. + Call { + function: FunctionId, + arguments: Vec, + }, + + Truncate { + value: Value, + to: BitWidth, + }, + ZeroExtend { + value: Value, + to: BitWidth, + }, + SignExtendTo { + value: Value, + to: BitWidth, + }, + + /// Keccak256 hash (pure but expensive). + Keccak256 { + offset: Value, + length: Value, + }, + + /// Keccak256 hash of two 256-bit words stored at scratch memory. + /// Equivalent to: mstore(0, word0); mstore(32, word1); keccak256(0, 64) + /// but lowered to a single function call to avoid code duplication. + Keccak256Pair { + word0: Value, + word1: Value, + }, + + /// Keccak256 hash of one 256-bit word stored at scratch memory. + /// Equivalent to: mstore(0, word0); keccak256(0, 32) + /// but lowered to a single function call to avoid code duplication. + Keccak256Single { + word0: Value, + }, + + /// Compound mapping load: keccak256(key, slot) → sload. + /// Combines a Keccak256Pair hash with a storage load into one outlined call. + /// Only valid when the hash intermediate is used exclusively by this load. + MappingSLoad { + /// The mapping key (first word of keccak256 input). + key: Value, + /// The storage slot (second word of keccak256 input). + slot: Value, + }, + + /// Data offset (for deployed bytecode). + DataOffset { + id: String, + }, + + /// Data size (for deployed bytecode). + DataSize { + id: String, + }, + + /// Load immutable variable. + LoadImmutable { + /// The immutable variable identifier. + key: String, + }, + + /// Linker symbol - returns the address of an external library. + LinkerSymbol { + /// The library path (e.g., "contracts/Library.sol:L"). + path: String, + }, +} + +/// Switch case. +#[derive(Clone, Debug)] +pub struct SwitchCase { + /// Selector value that triggers this case. + pub value: BigUint, + /// Statements executed when the selector matches. + pub body: Region, +} + +/// A region is a block that can yield values. +#[derive(Clone, Debug, Default)] +pub struct Region { + /// Statements in this region. + pub statements: Vec, + /// Values yielded by this region (for structured control flow). + pub yields: Vec, +} + +impl Region { + /// Creates a new empty region. + pub fn new() -> Self { + Region::default() + } + + /// Adds a statement to this region. + pub fn push(&mut self, statement: Statement) { + self.statements.push(statement); + } +} + +/// A basic block of statements (no yields - for function bodies). +#[derive(Clone, Debug, Default)] +pub struct Block { + pub statements: Vec, +} + +impl Block { + /// Creates a new empty block. + pub fn new() -> Self { + Block::default() + } + + /// Adds a statement to this block. + pub fn push(&mut self, statement: Statement) { + self.statements.push(statement); + } +} + +/// Statements with effects and structured control flow. +#[derive(Clone, Debug)] +pub enum Statement { + /// SSA binding: let x, y, z = expression + Let { + bindings: Vec, + value: Expression, + }, + + /// Memory store with region annotation. + MStore { + offset: Value, + value: Value, + region: MemoryRegion, + }, + + /// Memory store (single byte). + MStore8 { + offset: Value, + value: Value, + region: MemoryRegion, + }, + + /// Memory copy. + MCopy { + dest: Value, + src: Value, + length: Value, + }, + + /// Storage store with optional static slot. + SStore { + key: Value, + value: Value, + /// If key is a compile-time constant, store it here for analysis. + static_slot: Option, + }, + + /// Transient storage store. + TStore { + key: Value, + value: Value, + }, + + /// Structured if with explicit yields. + If { + condition: Value, + /// Input values passed into regions (for SSA). + inputs: Vec, + /// Then region. + then_region: Region, + /// Optional else region (defaults to yielding inputs unchanged). + else_region: Option, + /// Output value bindings (SSA values defined by this If). + outputs: Vec, + }, + + /// Switch statement with explicit yields. + Switch { + scrutinee: Value, + inputs: Vec, + cases: Vec, + default: Option, + outputs: Vec, + }, + + /// For loop with structured regions and explicit loop-carried values. + For { + /// Initial values for loop-carried variables. + initial_values: Vec, + /// Loop-carried variable bindings (visible in condition, body, post). + loop_variables: Vec, + /// Statements to execute before evaluating condition (evaluated each iteration). + /// These are generated inside the loop header block. + condition_statements: Vec, + /// Condition expression (evaluated each iteration after condition_statements). + condition: Expression, + /// Loop body (yields current values of loop-carried variables). + body: Region, + /// Input ValueIds for the post region, one per loop-carried variable. + /// These receive the body's yielded values (merged with continue-site values + /// via phi nodes in the LLVM codegen). + post_input_variables: Vec, + /// Post-iteration block (yields updated loop variables). + post: Region, + /// Final values after loop exits. + outputs: Vec, + }, + + /// Loop control - break out of the innermost for loop. + /// Carries the current values of loop-carried variables at the point of break. + Break { + /// Current values of loop-carried variables at the break point. + values: Vec, + }, + /// Loop control - continue to the next iteration of the innermost for loop. + /// Carries the current values of loop-carried variables at the continue point. + Continue { + /// Current values of loop-carried variables at the continue point. + values: Vec, + }, + /// Leave the current function, returning the given values. + Leave { + /// The current values of the return variables to return. + return_values: Vec, + }, + + Revert { + offset: Value, + length: Value, + }, + Return { + offset: Value, + length: Value, + }, + Stop, + Invalid, + SelfDestruct { + address: Value, + }, + + /// Solidity panic revert: emits `Panic(uint256)` ABI encoding and reverts. + /// Equivalent to: mstore(0, 0x4e487b71...), mstore(4, code), revert(0, 0x24). + /// Outlined to a shared helper function to avoid duplicating the pattern. + PanicRevert { + /// The panic error code (e.g., 0x11 = overflow, 0x22 = encoding, 0x41 = memory). + code: u8, + }, + + /// Error string revert: emits `Error(string)` ABI encoding and reverts. + /// Equivalent to: mload(0x40) → mstore(fmp, selector) → mstore(fmp+4, 0x20) → + /// mstore(fmp+0x24, length) → mstore(fmp+0x44, word0) → [...] → revert(fmp, total). + /// Outlined to a shared helper function parameterized by string length and data words. + ErrorStringRevert { + /// The string length in bytes. + length: u8, + /// The string data words (1-4 words of 32 bytes each). + data: Vec, + }, + + /// Custom error revert: emits a custom error revert using scratch space. + /// Pattern: mstore(0, selector) + [mstore(4, arg0) + mstore(0x24, arg1) + ...] + revert(0, 4+32*N). + /// Uses scratch space (offset 0), so no FMP load needed. + CustomErrorRevert { + /// The 4-byte error selector, left-shifted by 224 bits (as stored in scratch). + selector: BigUint, + /// The arguments to the custom error (0-3 values). + arguments: Vec, + }, + + /// Compound mapping store: keccak256(key, slot) → sstore(hash, value). + /// Combines a Keccak256Pair hash with a storage store into one outlined call. + /// Only valid when the hash intermediate is used exclusively by this store. + MappingSStore { + /// The mapping key (first word of keccak256 input). + key: Value, + /// The storage slot (second word of keccak256 input). + slot: Value, + /// The value to store. + value: Value, + }, + + ExternalCall { + kind: CallKind, + gas: Value, + address: Value, + value: Option, + args_offset: Value, + args_length: Value, + ret_offset: Value, + ret_length: Value, + result: ValueId, + }, + + Create { + kind: CreateKind, + value: Value, + offset: Value, + length: Value, + salt: Option, + result: ValueId, + }, + + Log { + offset: Value, + length: Value, + topics: Vec, + }, + + CodeCopy { + dest: Value, + offset: Value, + length: Value, + }, + ExtCodeCopy { + address: Value, + dest: Value, + offset: Value, + length: Value, + }, + ReturnDataCopy { + dest: Value, + offset: Value, + length: Value, + }, + DataCopy { + dest: Value, + offset: Value, + length: Value, + }, + CallDataCopy { + dest: Value, + offset: Value, + length: Value, + }, + + /// Nested block scope. + Block(Region), + + /// Expression evaluated for side effects only (result discarded). + Expression(Expression), + + /// Set immutable variable. + SetImmutable { + /// The immutable variable identifier. + key: String, + /// The value to store. + value: Value, + }, +} + +/// Function definition. +#[derive(Clone, Debug)] +pub struct Function { + /// Unique identifier within the enclosing object. + pub id: FunctionId, + /// Source-level function name as it appears in Yul. + pub name: String, + /// Formal parameter list as (SSA value id, type) pairs. + pub parameters: Vec<(ValueId, Type)>, + /// Return value types, in declaration order. + pub returns: Vec, + /// Initial SSA value IDs for return variables (allocated at function entry). + /// These are the IDs that the function body's If statements will reference + /// as "before" values. + pub return_values_initial: Vec, + /// Final SSA value IDs for return variables (after body execution). + /// These are the values that should be stored to the return pointer. + pub return_values: Vec, + /// Function body. + pub body: Block, + /// Number of call sites (for inlining decisions). + pub call_count: usize, + /// Instruction count estimate (for inlining decisions). + pub size_estimate: usize, +} + +impl Function { + /// Creates a new function. + pub fn new(id: FunctionId, name: String) -> Self { + Function { + id, + name, + parameters: Vec::new(), + returns: Vec::new(), + return_values_initial: Vec::new(), + return_values: Vec::new(), + body: Block::new(), + call_count: 0, + size_estimate: 0, + } + } +} + +/// Top-level object (contract). +#[derive(Clone, Debug)] +pub struct Object { + /// Yul-level object name (used as the LLVM module identifier). + pub name: String, + /// Top-level code block executed when this object is invoked. + pub code: Block, + /// Functions defined at object scope. + pub functions: BTreeMap, + /// Nested objects (e.g. the deployed-code object for a contract). + pub subobjects: Vec, + /// Embedded data sections keyed by Yul `datasize`/`dataoffset` identifier. + pub data: BTreeMap>, +} + +impl Object { + /// Creates a new object. + pub fn new(name: String) -> Self { + Object { + name, + code: Block::new(), + functions: BTreeMap::new(), + subobjects: Vec::new(), + data: BTreeMap::new(), + } + } + + /// Counts the total number of heap memory operations (MLoad, MStore, MStore8, MCopy) + /// in this object including all functions and subobjects. + /// This is used to estimate the number of `__sbrk_internal` call sites after LLVM codegen. + pub fn count_heap_operations(&self) -> usize { + let mut count = count_heap_ops_in_block(&self.code); + for function in self.functions.values() { + count += count_heap_ops_in_block(&function.body); + } + for subobject in &self.subobjects { + count += subobject.count_heap_operations(); + } + count + } + + /// Counts the total number of exit operations (Return, Revert, Stop) in this object + /// including all functions and subobjects. + /// This is used to estimate the number of `__revive_exit` call sites after LLVM codegen. + pub fn count_exit_operations(&self) -> usize { + let mut count = count_exit_ops_in_block(&self.code); + for function in self.functions.values() { + count += count_exit_ops_in_block(&function.body); + } + for subobject in &self.subobjects { + count += subobject.count_exit_operations(); + } + count + } + + /// Counts the total number of `Keccak256Single` expression nodes in this object + /// (including functions and subobjects). + /// Used to conditionally emit the `__revive_keccak256_one_word` helper function + /// only when enough call sites exist to justify the function body cost. + pub fn count_keccak256_single(&self) -> usize { + let mut count = count_keccak_single_in_block(&self.code); + for function in self.functions.values() { + count += count_keccak_single_in_block(&function.body); + } + for subobject in &self.subobjects { + count += subobject.count_keccak256_single(); + } + count + } + + /// Counts the total number of `ErrorStringRevert` statements grouped by + /// number of data words. Returns a map from num_words → count. + /// Used to conditionally outline: only profitable with >= 2 call sites. + pub fn count_error_string_reverts(&self) -> BTreeMap { + let mut counts = BTreeMap::new(); + count_error_string_reverts_in_block(&self.code, &mut counts); + for function in self.functions.values() { + count_error_string_reverts_in_block(&function.body, &mut counts); + } + counts + } + + /// Counts the total number of `CustomErrorRevert` statements grouped by + /// num_args. Returns a map from num_args → count. + /// Used to conditionally outline: only profitable with >= 3 call sites. + pub fn count_custom_error_reverts(&self) -> BTreeMap { + let mut counts = BTreeMap::new(); + count_custom_error_reverts_in_block(&self.code, &mut counts); + for function in self.functions.values() { + count_custom_error_reverts_in_block(&function.body, &mut counts); + } + counts + } + + /// Returns true if any code in this object uses the `msize()` expression. + /// When false, the msize watermark (`GLOBAL_HEAP_SIZE`) doesn't need updating, + /// allowing InlineNative stores to skip the `ensure_heap_size` call. + pub fn has_msize(&self) -> bool { + has_msize_in_block(&self.code) + || self.functions.values().any(|f| has_msize_in_block(&f.body)) + || self.subobjects.iter().any(|s| s.has_msize()) + } + + /// Finds the maximum ValueId used anywhere in this object (code + functions). + /// Does NOT recurse into subobjects. + pub fn find_max_value_id(&self) -> u32 { + fn scan_block(block: &Block, max_id: &mut u32) { + for statement in &block.statements { + statement.for_each_value_id(&mut |id| *max_id = (*max_id).max(id.0)); + } + for_each_statement(&block.statements, &mut |statement| { + statement.for_each_value_id_def(&mut |id| *max_id = (*max_id).max(id.0)); + }); + } + + let mut max_id: u32 = 0; + scan_block(&self.code, &mut max_id); + for function in self.functions.values() { + for (parameter_id, _) in &function.parameters { + max_id = max_id.max(parameter_id.0); + } + for id in &function.return_values_initial { + max_id = max_id.max(id.0); + } + for id in &function.return_values { + max_id = max_id.max(id.0); + } + scan_block(&function.body, &mut max_id); + } + for sub in &self.subobjects { + max_id = max_id.max(sub.find_max_value_id()); + } + max_id + } +} + +/// Counts the occurrences of callvalue and calldataload expressions. +/// +/// Returns `(callvalue_count, calldataload_count)`. +/// Used to decide whether outlining these into shared functions saves code. +#[derive(Debug, Default, Clone, Copy)] +pub struct SyscallCounts { + /// Number of `callvalue()` expression sites. + pub callvalue: usize, + /// Number of `calldataload(offset)` expression sites. + pub calldataload: usize, + /// Number of `caller()` expression sites. + pub caller: usize, + /// Number of heap memory operations (MStore, MLoad, MStore8, MCopy, etc.) + /// that translate to sbrk calls at the LLVM level. + pub heap_operations: usize, +} + +impl std::ops::AddAssign for SyscallCounts { + fn add_assign(&mut self, rhs: Self) { + self.callvalue += rhs.callvalue; + self.calldataload += rhs.calldataload; + self.caller += rhs.caller; + self.heap_operations += rhs.heap_operations; + } +} + +impl Object { + /// Counts the total number of callvalue and calldataload expression sites + /// in this object including all functions and subobjects. + pub fn count_syscall_sites(&self) -> SyscallCounts { + let mut counts = count_syscalls_in_block(&self.code); + for function in self.functions.values() { + counts += count_syscalls_in_block(&function.body); + } + for subobject in &self.subobjects { + counts += subobject.count_syscall_sites(); + } + counts + } +} + +impl Statement { + /// Visits every immediate `Expression` in this statement (NOT recursing into + /// nested regions, and NOT into `For::condition_statements`). Pair with + /// [`for_each_statement`] to walk all `Expression`s reachable from a statement list: + /// + /// ```ignore + /// for_each_statement(&block.statements, &mut |statement| { + /// statement.for_each_expression(&mut |expression| { /* ... */ }); + /// }); + /// ``` + pub fn for_each_expression(&self, f: &mut dyn FnMut(&Expression)) { + match self { + Statement::Let { value, .. } | Statement::Expression(value) => f(value), + Statement::For { condition, .. } => f(condition), + _ => {} + } + } + + /// Mutating variant of [`Statement::for_each_expression`]. + pub fn for_each_expression_mut(&mut self, f: &mut dyn FnMut(&mut Expression)) { + match self { + Statement::Let { value, .. } | Statement::Expression(value) => f(value), + Statement::For { condition, .. } => f(condition), + _ => {} + } + } + + /// Visits every `ValueId` *used* by this statement, recursing through + /// nested regions, `For::condition_statements`, and region yields. Does NOT + /// visit defining `ValueId`s (Let bindings, If/Switch/For outputs, + /// loop_variables, post_input_variables, ExternalCall/Create result). Use + /// [`Statement::for_each_value_id_def`] for those. + pub fn for_each_value_id(&self, f: &mut dyn FnMut(ValueId)) { + match self { + Statement::Let { value, .. } | Statement::Expression(value) => { + value.for_each_value_id(f) + } + Statement::MStore { offset, value, .. } | Statement::MStore8 { offset, value, .. } => { + f(offset.id); + f(value.id); + } + Statement::MCopy { dest, src, length } => { + f(dest.id); + f(src.id); + f(length.id); + } + Statement::SStore { key, value, .. } | Statement::TStore { key, value } => { + f(key.id); + f(value.id); + } + Statement::MappingSStore { key, slot, value } => { + f(key.id); + f(slot.id); + f(value.id); + } + Statement::If { + condition, + inputs, + then_region, + else_region, + .. + } => { + f(condition.id); + for v in inputs { + f(v.id); + } + walk_region_uses(then_region, f); + if let Some(r) = else_region { + walk_region_uses(r, f); + } + } + Statement::Switch { + scrutinee, + inputs, + cases, + default, + .. + } => { + f(scrutinee.id); + for v in inputs { + f(v.id); + } + for c in cases { + walk_region_uses(&c.body, f); + } + if let Some(r) = default { + walk_region_uses(r, f); + } + } + Statement::For { + initial_values, + condition_statements, + condition, + body, + post, + .. + } => { + for v in initial_values { + f(v.id); + } + for s in condition_statements { + s.for_each_value_id(f); + } + condition.for_each_value_id(f); + walk_region_uses(body, f); + walk_region_uses(post, f); + } + Statement::Block(region) => walk_region_uses(region, f), + Statement::Revert { offset, length } | Statement::Return { offset, length } => { + f(offset.id); + f(length.id); + } + Statement::SelfDestruct { address } => f(address.id), + Statement::ExternalCall { + gas, + address, + value, + args_offset, + args_length, + ret_offset, + ret_length, + .. + } => { + f(gas.id); + f(address.id); + if let Some(v) = value { + f(v.id); + } + f(args_offset.id); + f(args_length.id); + f(ret_offset.id); + f(ret_length.id); + } + Statement::Create { + value, + offset, + length, + salt, + .. + } => { + f(value.id); + f(offset.id); + f(length.id); + if let Some(s) = salt { + f(s.id); + } + } + Statement::Log { + offset, + length, + topics, + } => { + f(offset.id); + f(length.id); + for t in topics { + f(t.id); + } + } + Statement::CodeCopy { + dest, + offset, + length, + } + | Statement::ReturnDataCopy { + dest, + offset, + length, + } + | Statement::DataCopy { + dest, + offset, + length, + } + | Statement::CallDataCopy { + dest, + offset, + length, + } => { + f(dest.id); + f(offset.id); + f(length.id); + } + Statement::ExtCodeCopy { + address, + dest, + offset, + length, + } => { + f(address.id); + f(dest.id); + f(offset.id); + f(length.id); + } + Statement::SetImmutable { value, .. } => f(value.id), + Statement::Leave { return_values } + | Statement::Break { + values: return_values, + } + | Statement::Continue { + values: return_values, + } => { + for v in return_values { + f(v.id); + } + } + Statement::CustomErrorRevert { arguments, .. } => { + for a in arguments { + f(a.id); + } + } + Statement::Stop + | Statement::Invalid + | Statement::PanicRevert { .. } + | Statement::ErrorStringRevert { .. } => {} + } + } + + /// Mutating variant of [`Statement::for_each_value_id`]. Same traversal + /// rules — visits use sites, recurses into nested regions, skips definitions. + pub fn for_each_value_id_mut(&mut self, f: &mut dyn FnMut(&mut ValueId)) { + match self { + Statement::Let { value, .. } | Statement::Expression(value) => { + value.for_each_value_id_mut(f) + } + Statement::MStore { offset, value, .. } | Statement::MStore8 { offset, value, .. } => { + f(&mut offset.id); + f(&mut value.id); + } + Statement::MCopy { dest, src, length } => { + f(&mut dest.id); + f(&mut src.id); + f(&mut length.id); + } + Statement::SStore { key, value, .. } | Statement::TStore { key, value } => { + f(&mut key.id); + f(&mut value.id); + } + Statement::MappingSStore { key, slot, value } => { + f(&mut key.id); + f(&mut slot.id); + f(&mut value.id); + } + Statement::If { + condition, + inputs, + then_region, + else_region, + .. + } => { + f(&mut condition.id); + for v in inputs { + f(&mut v.id); + } + walk_region_uses_mut(then_region, f); + if let Some(r) = else_region { + walk_region_uses_mut(r, f); + } + } + Statement::Switch { + scrutinee, + inputs, + cases, + default, + .. + } => { + f(&mut scrutinee.id); + for v in inputs { + f(&mut v.id); + } + for c in cases { + walk_region_uses_mut(&mut c.body, f); + } + if let Some(r) = default { + walk_region_uses_mut(r, f); + } + } + Statement::For { + initial_values, + condition_statements, + condition, + body, + post, + .. + } => { + for v in initial_values { + f(&mut v.id); + } + for s in condition_statements { + s.for_each_value_id_mut(f); + } + condition.for_each_value_id_mut(f); + walk_region_uses_mut(body, f); + walk_region_uses_mut(post, f); + } + Statement::Block(region) => walk_region_uses_mut(region, f), + Statement::Revert { offset, length } | Statement::Return { offset, length } => { + f(&mut offset.id); + f(&mut length.id); + } + Statement::SelfDestruct { address } => f(&mut address.id), + Statement::ExternalCall { + gas, + address, + value, + args_offset, + args_length, + ret_offset, + ret_length, + .. + } => { + f(&mut gas.id); + f(&mut address.id); + if let Some(v) = value { + f(&mut v.id); + } + f(&mut args_offset.id); + f(&mut args_length.id); + f(&mut ret_offset.id); + f(&mut ret_length.id); + } + Statement::Create { + value, + offset, + length, + salt, + .. + } => { + f(&mut value.id); + f(&mut offset.id); + f(&mut length.id); + if let Some(s) = salt { + f(&mut s.id); + } + } + Statement::Log { + offset, + length, + topics, + } => { + f(&mut offset.id); + f(&mut length.id); + for t in topics { + f(&mut t.id); + } + } + Statement::CodeCopy { + dest, + offset, + length, + } + | Statement::ReturnDataCopy { + dest, + offset, + length, + } + | Statement::DataCopy { + dest, + offset, + length, + } + | Statement::CallDataCopy { + dest, + offset, + length, + } => { + f(&mut dest.id); + f(&mut offset.id); + f(&mut length.id); + } + Statement::ExtCodeCopy { + address, + dest, + offset, + length, + } => { + f(&mut address.id); + f(&mut dest.id); + f(&mut offset.id); + f(&mut length.id); + } + Statement::SetImmutable { value, .. } => f(&mut value.id), + Statement::Leave { return_values } + | Statement::Break { + values: return_values, + } + | Statement::Continue { + values: return_values, + } => { + for v in return_values { + f(&mut v.id); + } + } + Statement::CustomErrorRevert { arguments, .. } => { + for a in arguments { + f(&mut a.id); + } + } + Statement::Stop + | Statement::Invalid + | Statement::PanicRevert { .. } + | Statement::ErrorStringRevert { .. } => {} + } + } + + /// Visits every `ValueId` *defined* by this statement (NOT used by it). + /// This is the dual of [`Statement::for_each_value_id`]. Does not recurse + /// into nested regions — for that, use [`for_each_statement`] to walk and call + /// this on each statement. + pub fn for_each_value_id_def(&self, f: &mut dyn FnMut(ValueId)) { + match self { + Statement::Let { bindings, .. } => { + for b in bindings { + f(*b); + } + } + Statement::If { outputs, .. } | Statement::Switch { outputs, .. } => { + for o in outputs { + f(*o); + } + } + Statement::For { + loop_variables, + post_input_variables, + outputs, + .. + } => { + for v in loop_variables { + f(*v); + } + for v in post_input_variables { + f(*v); + } + for o in outputs { + f(*o); + } + } + Statement::ExternalCall { result, .. } | Statement::Create { result, .. } => f(*result), + _ => {} + } + } + + /// Mutating variant of [`Statement::for_each_value_id_def`]. Same per-statement + /// scope (no recursion into nested regions). Used by the inliner to + /// allocate fresh IDs for definitions in a cloned function body. + pub fn for_each_value_id_def_mut(&mut self, f: &mut dyn FnMut(&mut ValueId)) { + match self { + Statement::Let { bindings, .. } => { + for b in bindings { + f(b); + } + } + Statement::If { outputs, .. } | Statement::Switch { outputs, .. } => { + for o in outputs { + f(o); + } + } + Statement::For { + loop_variables, + post_input_variables, + outputs, + .. + } => { + for v in loop_variables { + f(v); + } + for v in post_input_variables { + f(v); + } + for o in outputs { + f(o); + } + } + Statement::ExternalCall { result, .. } | Statement::Create { result, .. } => f(result), + _ => {} + } + } +} + +fn walk_region_uses(region: &Region, f: &mut dyn FnMut(ValueId)) { + for s in ®ion.statements { + s.for_each_value_id(f); + } + for v in ®ion.yields { + f(v.id); + } +} + +fn walk_region_uses_mut(region: &mut Region, f: &mut dyn FnMut(&mut ValueId)) { + for s in &mut region.statements { + s.for_each_value_id_mut(f); + } + for v in &mut region.yields { + f(&mut v.id); + } +} + +impl Expression { + /// Visits every `ValueId` *used* by this expression. Includes the + /// `ValueId` of `Expression::Var` and the `id` of every `Value` operand. + pub fn for_each_value_id(&self, f: &mut dyn FnMut(ValueId)) { + match self { + Expression::Var(id) => f(*id), + Expression::Binary { lhs, rhs, .. } => { + f(lhs.id); + f(rhs.id); + } + Expression::Ternary { a, b, n, .. } => { + f(a.id); + f(b.id); + f(n.id); + } + Expression::Unary { operand, .. } => f(operand.id), + Expression::CallDataLoad { offset } | Expression::MLoad { offset, .. } => f(offset.id), + Expression::ExtCodeSize { address } + | Expression::ExtCodeHash { address } + | Expression::Balance { address } => f(address.id), + Expression::BlockHash { number } => f(number.id), + Expression::BlobHash { index } => f(index.id), + Expression::SLoad { key, .. } | Expression::TLoad { key } => f(key.id), + Expression::Call { arguments, .. } => { + for a in arguments { + f(a.id); + } + } + Expression::Truncate { value, .. } + | Expression::ZeroExtend { value, .. } + | Expression::SignExtendTo { value, .. } => f(value.id), + Expression::Keccak256 { offset, length } => { + f(offset.id); + f(length.id); + } + Expression::Keccak256Pair { word0, word1 } => { + f(word0.id); + f(word1.id); + } + Expression::MappingSLoad { key, slot } => { + f(key.id); + f(slot.id); + } + Expression::Keccak256Single { word0 } => f(word0.id), + Expression::Literal { .. } + | Expression::CallValue + | Expression::Caller + | Expression::Origin + | Expression::CallDataSize + | Expression::CodeSize + | Expression::GasPrice + | Expression::ReturnDataSize + | Expression::Coinbase + | Expression::Timestamp + | Expression::Number + | Expression::Difficulty + | Expression::GasLimit + | Expression::ChainId + | Expression::SelfBalance + | Expression::BaseFee + | Expression::BlobBaseFee + | Expression::Gas + | Expression::MSize + | Expression::Address + | Expression::DataOffset { .. } + | Expression::DataSize { .. } + | Expression::LoadImmutable { .. } + | Expression::LinkerSymbol { .. } => {} + } + } + + /// Mutating variant of [`Expression::for_each_value_id`]. + pub fn for_each_value_id_mut(&mut self, f: &mut dyn FnMut(&mut ValueId)) { + match self { + Expression::Var(id) => f(id), + Expression::Binary { lhs, rhs, .. } => { + f(&mut lhs.id); + f(&mut rhs.id); + } + Expression::Ternary { a, b, n, .. } => { + f(&mut a.id); + f(&mut b.id); + f(&mut n.id); + } + Expression::Unary { operand, .. } => f(&mut operand.id), + Expression::CallDataLoad { offset } | Expression::MLoad { offset, .. } => { + f(&mut offset.id) + } + Expression::ExtCodeSize { address } + | Expression::ExtCodeHash { address } + | Expression::Balance { address } => f(&mut address.id), + Expression::BlockHash { number } => f(&mut number.id), + Expression::BlobHash { index } => f(&mut index.id), + Expression::SLoad { key, .. } | Expression::TLoad { key } => f(&mut key.id), + Expression::Call { arguments, .. } => { + for a in arguments { + f(&mut a.id); + } + } + Expression::Truncate { value, .. } + | Expression::ZeroExtend { value, .. } + | Expression::SignExtendTo { value, .. } => f(&mut value.id), + Expression::Keccak256 { offset, length } => { + f(&mut offset.id); + f(&mut length.id); + } + Expression::Keccak256Pair { word0, word1 } => { + f(&mut word0.id); + f(&mut word1.id); + } + Expression::MappingSLoad { key, slot } => { + f(&mut key.id); + f(&mut slot.id); + } + Expression::Keccak256Single { word0 } => f(&mut word0.id), + Expression::Literal { .. } + | Expression::CallValue + | Expression::Caller + | Expression::Origin + | Expression::CallDataSize + | Expression::CodeSize + | Expression::GasPrice + | Expression::ReturnDataSize + | Expression::Coinbase + | Expression::Timestamp + | Expression::Number + | Expression::Difficulty + | Expression::GasLimit + | Expression::ChainId + | Expression::SelfBalance + | Expression::BaseFee + | Expression::BlobBaseFee + | Expression::Gas + | Expression::MSize + | Expression::Address + | Expression::DataOffset { .. } + | Expression::DataSize { .. } + | Expression::LoadImmutable { .. } + | Expression::LinkerSymbol { .. } => {} + } + } +} + +/// Mutating variant of [`for_each_statement`]. Visits every statement in a slice +/// recursively. `f` is called on each statement *before* recursion into its +/// nested regions, so a callback that swaps a statement's variant will not +/// have its new nested regions re-visited. For our use cases the callback +/// only mutates inner fields, never changes the variant. +pub fn for_each_statement_mut(statements: &mut [Statement], f: &mut dyn FnMut(&mut Statement)) { + for statement in statements.iter_mut() { + f(statement); + match statement { + Statement::If { + then_region, + else_region, + .. + } => { + for_each_statement_mut(&mut then_region.statements, f); + if let Some(r) = else_region { + for_each_statement_mut(&mut r.statements, f); + } + } + Statement::Switch { cases, default, .. } => { + for case in cases { + for_each_statement_mut(&mut case.body.statements, f); + } + if let Some(r) = default { + for_each_statement_mut(&mut r.statements, f); + } + } + Statement::For { + condition_statements, + body, + post, + .. + } => { + for_each_statement_mut(condition_statements, f); + for_each_statement_mut(&mut body.statements, f); + for_each_statement_mut(&mut post.statements, f); + } + Statement::Block(region) => for_each_statement_mut(&mut region.statements, f), + _ => {} + } + } +} + +/// Visits every statement in a slice recursively, calling `f` on each one. +/// Handles structural recursion into If/Switch/For/Block regions. +pub fn for_each_statement(statements: &[Statement], f: &mut dyn FnMut(&Statement)) { + for statement in statements { + f(statement); + match statement { + Statement::If { + then_region, + else_region, + .. + } => { + for_each_statement(&then_region.statements, f); + if let Some(r) = else_region { + for_each_statement(&r.statements, f); + } + } + Statement::Switch { cases, default, .. } => { + for case in cases { + for_each_statement(&case.body.statements, f); + } + if let Some(r) = default { + for_each_statement(&r.statements, f); + } + } + Statement::For { + condition_statements, + body, + post, + .. + } => { + for_each_statement(condition_statements, f); + for_each_statement(&body.statements, f); + for_each_statement(&post.statements, f); + } + Statement::Block(region) => for_each_statement(®ion.statements, f), + _ => {} + } + } +} + +fn count_syscalls_in_block(block: &Block) -> SyscallCounts { + let mut counts = SyscallCounts::default(); + for_each_statement(&block.statements, &mut |statement| match statement { + Statement::Let { value, .. } | Statement::Expression(value) => match value { + Expression::CallValue => counts.callvalue += 1, + Expression::CallDataLoad { .. } => counts.calldataload += 1, + Expression::Caller => counts.caller += 1, + Expression::MLoad { .. } | Expression::Keccak256 { .. } => counts.heap_operations += 1, + _ => {} + }, + Statement::MStore { .. } | Statement::MStore8 { .. } | Statement::MCopy { .. } => { + counts.heap_operations += 1; + } + Statement::Revert { .. } + | Statement::Return { .. } + | Statement::CodeCopy { .. } + | Statement::ExtCodeCopy { .. } + | Statement::ReturnDataCopy { .. } + | Statement::DataCopy { .. } + | Statement::CallDataCopy { .. } => { + counts.heap_operations += 1; + } + Statement::ExternalCall { .. } | Statement::Create { .. } => { + counts.heap_operations += 2; + } + Statement::Log { topics, .. } => { + counts.heap_operations += 1 + topics.len(); + } + _ => {} + }); + counts +} + +fn count_heap_ops_in_block(block: &Block) -> usize { + let mut count = 0usize; + for_each_statement(&block.statements, &mut |statement| match statement { + Statement::MStore { .. } | Statement::MStore8 { .. } | Statement::MCopy { .. } => { + count += 1; + } + Statement::Let { + value: Expression::MLoad { .. }, + .. + } => count += 1, + _ => {} + }); + count +} + +fn count_exit_ops_in_block(block: &Block) -> usize { + let mut count = 0usize; + for_each_statement(&block.statements, &mut |statement| { + if matches!( + statement, + Statement::Return { .. } | Statement::Revert { .. } | Statement::Stop + ) { + count += 1; + } + }); + count +} + +fn count_keccak_single_in_block(block: &Block) -> usize { + let mut count = 0usize; + for_each_statement(&block.statements, &mut |statement| { + if let Statement::Let { value, .. } | Statement::Expression(value) = statement { + if matches!(value, Expression::Keccak256Single { .. }) { + count += 1; + } + } + }); + count +} + +fn count_error_string_reverts_in_block(block: &Block, counts: &mut BTreeMap) { + for_each_statement(&block.statements, &mut |statement| { + if let Statement::ErrorStringRevert { data, .. } = statement { + *counts.entry(data.len()).or_insert(0) += 1; + } + }); +} + +fn count_custom_error_reverts_in_block(block: &Block, counts: &mut BTreeMap) { + for_each_statement(&block.statements, &mut |statement| { + if let Statement::CustomErrorRevert { arguments, .. } = statement { + *counts.entry(arguments.len()).or_insert(0) += 1; + } + }); +} + +fn has_msize_in_block(block: &Block) -> bool { + let mut found = false; + for_each_statement(&block.statements, &mut |statement| { + if let Statement::Let { value, .. } | Statement::Expression(value) = statement { + if matches!(value, Expression::MSize) { + found = true; + } + } + }); + found +} diff --git a/crates/newyork/src/lib.rs b/crates/newyork/src/lib.rs new file mode 100644 index 000000000..e0f0a948b --- /dev/null +++ b/crates/newyork/src/lib.rs @@ -0,0 +1,846 @@ +//! NEW Yul OptimziR Kit (newyork) +//! +//! This crate provides a custom intermediate representation (IR) for the Revive +//! compiler, positioned between Yul and LLVM IR. It enables domain-specific +//! optimizations that LLVM cannot perform because it lacks semantic knowledge +//! of the PolkaVM target and EVM/Solidity source domains. +//! +//! # Architecture +//! +//! ```text +//! Yul AST ──► newyork IR ──► [Optimizations] ──► LLVM IR ──► RISC-V +//! (from_yul) (passes) (to_llvm) +//! ``` +//! +//! # Design Principles +//! +//! 1. **SSA with Structured Control Flow** - Preserves high-level structure from Yul +//! 2. **Explicit Types with Address Spaces** - Every value has a known bit-width +//! 3. **Pure Expressions vs Effectful Statements** - Enables easier reasoning +//! 4. **Semantic Annotations** - Storage/memory operations tagged with region info +//! +//! # Modules +//! +//! - [`ir`] - Core IR data structures (types, values, statements, expressions) +//! - [`ssa`] - SSA builder for variable tracking and phi-node insertion +//! - [`from_yul`] - Translation from Yul AST to newyork IR +//! - [`to_llvm`] - LLVM code generation from newyork IR +//! - [`type_inference`] - Type inference pass for narrowing integer widths +//! - [`heap_opt`] - Heap optimization for partial big-endian emulation +//! - [`mem_opt`] - Memory optimization (load-after-store, dead store elimination) +//! - [`inline`] - Function inlining with custom heuristics for PolkaVM +//! +//! For now, allow missing docs while the crate is in development. +#![allow(missing_docs)] +#![deny(clippy::all)] + +/// Environment variable: when set, dumps the newyork IR for every translated object to +/// `newyork_ir_.txt` inside the caller-provided debug output directory +/// (`--debug-output-dir`), after the intra-object optimization passes have run. When the variable +/// is set but no debug output directory was configured, the dump is skipped. +pub const NEWYORK_DUMP_IR_ENV: &str = "NEWYORK_DUMP_IR"; + +pub mod compound_outlining; +pub mod from_yul; +pub mod guard_narrow; +pub mod heap_opt; +pub mod inline; +pub mod ir; +pub mod mem_opt; +pub mod printer; +pub mod simplify; +pub mod ssa; +pub mod to_llvm; +pub mod type_inference; +pub mod validate; + +pub use from_yul::{TranslationError, YulTranslator}; +pub use heap_opt::{ + AccessPattern, HeapAnalysis, HeapAnalysisStats, HeapOptResults, MemorySlot, OffsetInfo, +}; +pub use inline::{ + analyze_call_graph, inline_functions, CallGraphAnalysis, InlineDecision, InlineResults, +}; +pub use ir::{ + AddressSpace, BinaryOperation, BitWidth, Block, CallKind, CreateKind, Expression, Function, + FunctionId, MemoryRegion, Object, Region, Statement, SwitchCase, Type, UnaryOperation, Value, + ValueId, +}; +pub use mem_opt::{MemOptResults, MemoryOptimizer}; +pub use printer::{ + print_expression, print_function, print_object, print_object_with_types, print_statement, + Printer, PrinterConfig, +}; +pub use simplify::{ + deduplicate_functions, deduplicate_functions_fuzzy, fold_constant_keccak, Simplifier, + SimplifyResults, +}; +pub use ssa::SsaBuilder; +pub use to_llvm::{CodegenError, LlvmCodegen}; +pub use type_inference::{TypeConstraint, TypeInference}; +pub use validate::{validate_function, validate_object, ValidationError, ValidationResult}; +/// Maximum number of param/return narrowing iterations. +/// +/// Each iteration narrows function signatures, re-runs full type inference with the new widths so +/// narrowed parameters cascade through `add`/`and`/etc. forward, and then refines call-site +/// demands. Four iterations is enough to reach a fixed point on the OZ corpus; any further work is +/// bounded by an explicit `changed` check. +const PARAM_NARROW_ITERATIONS: u32 = 4; + +/// Per-call-site overhead in IR units used by [`inline_by_shrink_prediction`]. Roughly maps to the +/// LLVM cost of a `tail call` + per-arg setup. `make_inline_decisions` treats `1 IR unit ≈ 1 LLVM +/// byte` empirically, so a small constant here is correct. +const SHRINK_PREDICTION_CALL_OVERHEAD: usize = 2; + +/// Minimum body size considered by [`inline_by_shrink_prediction`]. Below the always-inline +/// threshold the existing inliner already inlines, so shrink-prediction adds no information. +const SHRINK_PREDICTION_MIN_CANDIDATE_SIZE: usize = 7; + +/// Maximum body size considered by [`inline_by_shrink_prediction`]. Beyond this, body-side +/// simplifier folding cannot realistically halve a 70+ statement function via a handful of literal +/// args, so prediction is fragile and disabled. +const SHRINK_PREDICTION_MAX_CANDIDATE_SIZE: usize = 60; + +/// Result of translating a Yul object to newyork IR. +pub struct TranslationResult { + /// The translated IR object. + pub object: Object, + /// Heap optimization results (identifies where byte-swapping can be skipped). + pub heap_opt: HeapOptResults, + /// Type inference results (narrower types for values). + pub type_info: TypeInference, + /// Memory optimization results (load-after-store, dead store elimination). + pub mem_opt: MemOptResults, + /// Inlining results (which functions were inlined and removed). + pub inline_results: InlineResults, +} + +/// Translates a Yul object to newyork IR. +/// +/// This is the main entry point for converting Yul AST to the new IR format. +/// Returns the IR object along with heap optimization analysis results. +/// +/// # Example +/// +/// ```ignore +/// use revive_newyork::translate_yul_object; +/// use revive_yul::parser::statement::object::Object; +/// +/// let yul_object: Object = /* parse yul */; +/// let result = translate_yul_object(&yul_object, None)?; +/// let ir_object = result.object; +/// let heap_opt = result.heap_opt; +/// ``` +pub fn translate_yul_object( + yul_object: &revive_yul::parser::statement::object::Object, + debug_output_directory: Option<&std::path::Path>, +) -> Result { + let mut translator = YulTranslator::new(); + let mut ir_object = translator.translate_object(yul_object)?; + + let (mut inline_results, mem_opt_results) = optimize_object_tree(&mut ir_object); + + // When `NEWYORK_DUMP_IR` is set, dump this post-`optimize_object_tree` IR snapshot into the + // caller-provided debug output directory. If the variable is set but no debug output directory + // was configured, skip the dump rather than writing to a hardcoded path. + if std::env::var(NEWYORK_DUMP_IR_ENV).is_ok() { + if let Some(directory) = debug_output_directory { + use std::io::Write; + let mut dump_path = directory.to_owned(); + dump_path.push(format!( + "newyork_ir_{}.txt", + ir_object.name.replace('/', "_") + )); + if let Ok(mut file) = std::fs::File::create(&dump_path) { + let _ = write!(file, "{}", print_object(&ir_object)); + } + } + } + + let mut heap_analysis = HeapAnalysis::new(); + heap_analysis.analyze_object(&ir_object); + let heap_opt = HeapOptResults::from_analysis(&heap_analysis); + + let mut type_info = TypeInference::new(); + type_info.infer_object_tree(&ir_object); + + let type_info = narrow_signatures_to_fixed_point(&mut ir_object, type_info); + + // Late inline pass: now that parameter narrowing has propagated through the IR and + // simplification has folded any newly exposed constants, some wrapper functions have shrunk + // below the inline thresholds. Re-estimate function sizes and run the inliner again to catch + // these, followed by simplify + dedup to clean up the inlined bodies. This is intentionally + // separate from the early inliner: the early pass exposes intra-procedural opportunities that + // drive the rest of the pipeline; the late pass collects the per-function shrinkage produced + // by every subsequent optimization (mem_opt, compound_outlining, guard_narrow, full type + // narrowing). + let type_info = run_late_inline_loop(&mut ir_object, &mut inline_results, type_info); + + if let Err(errors) = validate::validate_object(&ir_object) { + let details = errors + .iter() + .map(|error| format!(" - {error}")) + .collect::>() + .join("\n"); + panic!( + "ICE: IR validation failed for object `{}` after optimization pipeline:\n{}", + ir_object.name, details, + ); + } + + Ok(TranslationResult { + object: ir_object, + heap_opt, + type_info, + mem_opt: mem_opt_results, + inline_results, + }) +} + +/// Maximum number of late inline + simplify + narrow iterations. +/// +/// One round captures every additional inline the cost model can make once the pipeline's other +/// passes have settled (measured on the OZ corpus — two or more rounds produce identical output). +/// The bound is kept as a constant so future cost-model work that depends on cascading shrinkage +/// across iterations doesn't have to re-introduce the scaffolding. +const LATE_INLINE_ITERATIONS: u32 = 1; + +/// Runs a fixed-point loop of late inline + simplify + dedup + type narrow. +/// +/// After the early inline + heap + mem_opt + compound_outlining + guard_narrow + first round of +/// param narrowing has completed, many wrapper helpers have collapsed to a handful of statements. +/// The early inliner couldn't act on them because they were still wrapped in pre-simplify noise; +/// running the inliner again at this point — with re-estimated function sizes and on top of the +/// narrowed signatures — picks up the residue. +/// +/// The function takes ownership of `type_info` so we can reseed it after the inlined IR is in +/// place; the returned `TypeInference` reflects the final state used for downstream codegen. +fn run_late_inline_loop( + ir_object: &mut ir::Object, + inline_results: &mut InlineResults, + mut type_info: TypeInference, +) -> TypeInference { + for _ in 0..LATE_INLINE_ITERATIONS { + inline::estimate_function_sizes(ir_object); + let late_results = inline_functions(ir_object); + inline_results.inlined_call_sites += late_results.inlined_call_sites; + inline_results + .removed_functions + .extend(late_results.removed_functions); + inline_results.decisions.extend(late_results.decisions); + + let mut simplifier = Simplifier::new(); + simplifier.simplify_object(ir_object); + + // Re-run compound outlining + guard narrowing after inlining: the + // inlined bodies expose new keccak256_pair+sload pairs and overflow + // checks that the early pass couldn't see across the call boundary. + compound_outlining::outline_compounds_in_object(ir_object); + guard_narrow::narrow_guards_in_object(ir_object); + let mut simplifier_post = Simplifier::new(); + simplifier_post.simplify_object(ir_object); + + let _ = deduplicate_functions(ir_object); + let _ = simplify::deduplicate_functions_fuzzy(ir_object); + + type_info = TypeInference::new(); + type_info.infer_object_tree(ir_object); + type_info = narrow_signatures_to_fixed_point(ir_object, type_info); + } + // Final size refresh so LLVM-level inline hints (set during codegen) see + // the post-simplify, post-narrow shape rather than the larger pre-cleanup + // estimates that `inline_functions` last set internally. + inline::estimate_function_sizes(ir_object); + type_info +} + +/// Iteratively narrows function parameter and return types until no change. +/// +/// Each iteration applies four narrowing strategies — forward param, caller-driven +/// param, forward return, demand-driven return — and re-runs full type inference +/// so the new signature widths cascade through every function body before the next +/// iteration. Bounded by [`PARAM_NARROW_ITERATIONS`] but exits early on a fixed point. +fn narrow_signatures_to_fixed_point( + ir_object: &mut ir::Object, + mut type_info: TypeInference, +) -> TypeInference { + for _ in 0..PARAM_NARROW_ITERATIONS { + let mut changed = type_info.narrow_function_params(ir_object); + changed |= type_info.narrow_function_params_from_callers(ir_object); + changed |= type_info.narrow_function_returns(ir_object); + changed |= type_info.narrow_function_returns_from_demand(ir_object); + if !changed { + break; + } + type_info = TypeInference::new(); + type_info.infer_object_tree(ir_object); + type_info.refine_demands_from_params(ir_object); + } + type_info +} + +/// Runs the full newyork optimization pipeline on an object and its subobjects. +/// +/// Pass order matters: inlining runs first to expose intra-procedural opportunities, +/// then simplify+dedup clean up the IR, then mem_opt + FMP propagation expose +/// constant keccak inputs, and finally compound outlining and guard narrowing +/// rewrite specialized patterns. Each of those rewriting passes can produce new +/// constants and dead code, so a simplify pass follows each cluster; a second dedup +/// catches near-duplicates that only emerge after canonicalization. +/// +/// Subobjects are processed recursively and their inline/memory results are merged +/// into the returned aggregates. +fn optimize_object_tree(object: &mut ir::Object) -> (InlineResults, MemOptResults) { + let mut inline_results = inline_functions(object); + + let mut simplifier = Simplifier::new(); + let _simplify_stats = simplifier.simplify_object(object); + + let _dedup_count = deduplicate_functions(object); + let _fuzzy_dedup_count = simplify::deduplicate_functions_fuzzy(object); + + let mut mem_optimizer = MemoryOptimizer::new(); + let mut mem_opt_results = mem_optimizer.optimize_object(object); + let mut fmp_prop = mem_opt::FmpPropagation::new(0); + fmp_prop.propagate_object(object); + mem_opt_results.fmp_loads_eliminated += fmp_prop.loads_eliminated; + + simplify::fold_constant_keccak(object); + + let mut simplifier2 = Simplifier::new(); + simplifier2.simplify_object(object); + + compound_outlining::outline_compounds_in_object(object); + guard_narrow::narrow_guards_in_object(object); + + let mut simplifier3 = Simplifier::new(); + simplifier3.simplify_object(object); + + let _eliminated = eliminate_constant_parameters(object); + if _eliminated > 0 { + let mut simplifier_post_const = Simplifier::new(); + simplifier_post_const.simplify_object(object); + } + + let _predicted = inline_by_shrink_prediction(object); + if _predicted > 0 { + let mut simplifier_post_predict = Simplifier::new(); + simplifier_post_predict.simplify_object(object); + } + + let _dedup_count2 = deduplicate_functions(object); + let _fuzzy_dedup_count2 = simplify::deduplicate_functions_fuzzy(object); + + for subobject in &mut object.subobjects { + let (sub_inline, sub_mem_opt) = optimize_object_tree(subobject); + inline_results.inlined_call_sites += sub_inline.inlined_call_sites; + inline_results + .removed_functions + .extend(sub_inline.removed_functions); + inline_results.decisions.extend(sub_inline.decisions); + mem_opt_results.loads_eliminated += sub_mem_opt.loads_eliminated; + mem_opt_results.stores_eliminated += sub_mem_opt.stores_eliminated; + mem_opt_results.values_tracked += sub_mem_opt.values_tracked; + mem_opt_results.keccak_pairs_fused += sub_mem_opt.keccak_pairs_fused; + mem_opt_results.keccak_singles_fused += sub_mem_opt.keccak_singles_fused; + mem_opt_results.fmp_loads_eliminated += sub_mem_opt.fmp_loads_eliminated; + } + + (inline_results, mem_opt_results) +} + +/// Eliminate parameters whose argument is the same compile-time literal at +/// every call site. The parameter is removed from the function signature, an +/// equivalent `Let` binding is prepended to the body so existing uses of the +/// parameter's `ValueId` keep working, and the matching argument is dropped +/// from every call expression. +/// +/// Returns the total number of `(function, parameter)` pairs eliminated +/// (including those inside subobjects). +/// +/// This is an IR-level analogue of LLVM's `deadargelim` + `ipsccp` constant +/// propagation through call boundaries — necessary because most newyork +/// helpers carry `noinline` for code-size reasons, which blocks LLVM's IPO +/// from baking constants into the function bodies. +fn eliminate_constant_parameters(object: &mut ir::Object) -> usize { + use std::collections::BTreeMap; + + let mut total = 0; + for subobject in &mut object.subobjects { + total += eliminate_constant_parameters(subobject); + } + + let mut block_literals: BTreeMap = BTreeMap::new(); + collect_top_level_literals(&object.code.statements, &mut block_literals); + + #[derive(Clone)] + enum ArgState { + Initial, + Constant(num::BigUint, Type), + Variable, + } + + let mut arg_states: BTreeMap<(FunctionId, usize), ArgState> = BTreeMap::new(); + let mut call_counts: BTreeMap = BTreeMap::new(); + for &function_id in object.functions.keys() { + call_counts.insert(function_id, 0); + } + + let mut record_call = + |function_id: FunctionId, + arguments: &[Value], + extra_literals: &BTreeMap| { + *call_counts.entry(function_id).or_insert(0) += 1; + for (parameter_index, argument) in arguments.iter().enumerate() { + let new_state = match extra_literals + .get(&argument.id.0) + .or_else(|| block_literals.get(&argument.id.0)) + { + Some((value, value_type)) => ArgState::Constant(value.clone(), *value_type), + None => ArgState::Variable, + }; + let entry = arg_states + .entry((function_id, parameter_index)) + .or_insert(ArgState::Initial); + let merged = match (entry.clone(), new_state) { + (ArgState::Initial, fresh) => fresh, + (ArgState::Variable, _) | (_, ArgState::Variable) => ArgState::Variable, + (ArgState::Constant(value_a, type_a), ArgState::Constant(value_b, type_b)) + if value_a == value_b && type_a == type_b => + { + ArgState::Constant(value_a, type_a) + } + _ => ArgState::Variable, + }; + *entry = merged; + } + }; + + visit_calls(&object.code.statements, &mut record_call); + for function in object.functions.values() { + visit_calls(&function.body.statements, &mut record_call); + } + + let mut by_function: BTreeMap> = BTreeMap::new(); + for ((function_id, parameter_index), state) in arg_states { + if call_counts.get(&function_id).copied().unwrap_or(0) < 1 { + continue; + } + if let ArgState::Constant(value, value_type) = state { + by_function + .entry(function_id) + .or_default() + .push((parameter_index, value, value_type)); + } + } + + if by_function.is_empty() { + return total; + } + + let mut drop_indices: BTreeMap> = BTreeMap::new(); + + for (function_id, mut entries) in by_function { + let Some(function) = object.functions.get_mut(&function_id) else { + continue; + }; + + // Don't eliminate every parameter — leave the function with at least + // one input slot so the call-site arity matches non-zero. (Yul allows + // zero-arg functions, so this isn't strictly necessary, but it keeps + // the change conservative and the diff smaller.) + if entries.len() >= function.parameters.len() { + entries.truncate(function.parameters.len().saturating_sub(1)); + if entries.is_empty() { + continue; + } + } + + entries.sort_by_key(|entry| entry.0); + let mut prologue: Vec = Vec::with_capacity(entries.len()); + for (parameter_index, value, value_type) in &entries { + let (parameter_id, _) = function.parameters[*parameter_index]; + prologue.push(Statement::Let { + bindings: vec![parameter_id], + value: Expression::Literal { + value: value.clone(), + value_type: *value_type, + }, + }); + } + + let dropped: Vec = entries.iter().map(|(index, _, _)| *index).collect(); + let mut dropped_descending = dropped.clone(); + dropped_descending.sort_by(|a, b| b.cmp(a)); + for parameter_index in dropped_descending { + function.parameters.remove(parameter_index); + } + + let mut new_body = prologue; + new_body.extend(std::mem::take(&mut function.body.statements)); + function.body.statements = new_body; + function.size_estimate = inline::estimate_block_size(&function.body); + + total += entries.len(); + drop_indices.insert(function_id, dropped); + } + + if drop_indices.is_empty() { + return total; + } + + trim_call_arguments(&mut object.code.statements, &drop_indices); + for function in object.functions.values_mut() { + trim_call_arguments(&mut function.body.statements, &drop_indices); + } + + total +} + +/// Inlines functions whose predicted post-substitution size (with +/// callsite literal arguments propagated through the body and a fresh +/// simplifier pass run on the result) beats the cost of keeping them. +/// +/// For each function in the cost-benefit range: +/// 1. Walk every call site, build the literal-arg map for that site. +/// 2. Clone the function body, prepend `Let p_i = Literal(value)` for each +/// literal arg, drop those params from the signature. +/// 3. Run the full simplifier on the cloned function in isolation. +/// 4. Measure the resulting `size_estimate`. +/// 5. Sum the predicted sizes over all call sites. +/// 6. If the sum (no body, no call overhead) beats the keep-cost +/// (body + N × call-overhead), force-inline by lowering +/// `size_estimate` so the next `inline_functions` pass picks the +/// function as `AlwaysInline`. +/// +/// Returns the number of functions force-inlined. +fn inline_by_shrink_prediction(object: &mut ir::Object) -> usize { + use std::collections::BTreeMap; + + let mut total = 0; + for subobject in &mut object.subobjects { + total += inline_by_shrink_prediction(subobject); + } + + let mut block_literals: BTreeMap = BTreeMap::new(); + collect_top_level_literals(&object.code.statements, &mut block_literals); + + // For each (function, callsite) → ordered list of (param_idx → literal) + // for the args known at the call site. + type LiteralArgs = BTreeMap; + let mut sites_per_callee: BTreeMap> = BTreeMap::new(); + + let mut record_call = + |function_id: FunctionId, + arguments: &[Value], + extra_literals: &BTreeMap| { + let mut site_literals: LiteralArgs = BTreeMap::new(); + for (parameter_index, argument) in arguments.iter().enumerate() { + if let Some((value, value_type)) = extra_literals + .get(&argument.id.0) + .or_else(|| block_literals.get(&argument.id.0)) + { + site_literals.insert(parameter_index, (value.clone(), *value_type)); + } + } + sites_per_callee + .entry(function_id) + .or_default() + .push(site_literals); + }; + + visit_calls(&object.code.statements, &mut record_call); + for function in object.functions.values() { + visit_calls(&function.body.statements, &mut record_call); + } + + let mut force_inline: Vec = Vec::new(); + for (function_id, sites) in &sites_per_callee { + if sites.len() < 2 { + continue; + } + let Some(function) = object.functions.get(function_id) else { + continue; + }; + if function.size_estimate < SHRINK_PREDICTION_MIN_CANDIDATE_SIZE { + continue; + } + if function.size_estimate > SHRINK_PREDICTION_MAX_CANDIDATE_SIZE { + continue; + } + if !sites.iter().any(|literals| !literals.is_empty()) { + continue; + } + + let mut total_predicted = 0; + for site_literals in sites { + total_predicted += predict_simplified_size(function, site_literals); + } + let keep_cost = function.size_estimate + sites.len() * SHRINK_PREDICTION_CALL_OVERHEAD; + // Require predicted <= 75% of keep cost. Empirically the + // 1-IR-unit-≈-1-LLVM-byte assumption is tight, so small predicted + // wins are noise; 60% changes nothing on the OZ corpus, 80% admits + // +868 bytes of regression. + if total_predicted * 4 < keep_cost * 3 { + force_inline.push(*function_id); + } + } + + if force_inline.is_empty() { + return total; + } + + // Lower size_estimate below ALWAYS_INLINE_SIZE_THRESHOLD so the next + // `inline_functions` pass picks these as AlwaysInline, reusing the + // canonical inliner rather than duplicating its logic. + for function_id in &force_inline { + if let Some(function) = object.functions.get_mut(function_id) { + function.size_estimate = 1; + } + } + let _ = inline_functions(object); + total += force_inline.len(); + + total +} + +/// Clones `function`, prepends `Let p_i = Literal(value)` for every +/// `(param_idx, value)` in `literal_args`, drops those parameters from +/// the signature, then runs the full simplifier on the clone in +/// isolation. Returns the post-simplify size estimate. +fn predict_simplified_size( + function: &ir::Function, + literal_args: &std::collections::BTreeMap, +) -> usize { + let mut temp = function.clone(); + let mut sorted_args: Vec<(usize, num::BigUint, Type)> = literal_args + .iter() + .map(|(&idx, (value, value_type))| (idx, value.clone(), *value_type)) + .collect(); + sorted_args.sort_by_key(|entry| entry.0); + + let mut prologue: Vec = Vec::with_capacity(sorted_args.len()); + for (idx, value, value_type) in &sorted_args { + if *idx >= temp.parameters.len() { + continue; + } + let (param_id, _) = temp.parameters[*idx]; + prologue.push(Statement::Let { + bindings: vec![param_id], + value: Expression::Literal { + value: value.clone(), + value_type: *value_type, + }, + }); + } + let mut dropped: Vec = sorted_args + .iter() + .filter(|(idx, _, _)| *idx < temp.parameters.len()) + .map(|(idx, _, _)| *idx) + .collect(); + dropped.sort_by(|a, b| b.cmp(a)); + for idx in dropped { + temp.parameters.remove(idx); + } + + let mut new_body = prologue; + new_body.extend(std::mem::take(&mut temp.body.statements)); + temp.body.statements = new_body; + + let original_id = temp.id; + let mut tmp_object = ir::Object::new("tmp_shrink_prediction".to_string()); + tmp_object.functions.insert(original_id, temp); + let mut simplifier = Simplifier::new(); + simplifier.simplify_object(&mut tmp_object); + + let simplified_function = match tmp_object.functions.get(&original_id) { + Some(function) => function, + None => return function.size_estimate, + }; + inline::estimate_block_size(&simplified_function.body) +} + +/// Records `Let id = Literal v` bindings that occur at the top level of a +/// statement list (not inside any nested branch). +fn collect_top_level_literals( + statements: &[Statement], + literals: &mut std::collections::BTreeMap, +) { + for statement in statements { + if let Statement::Let { + bindings, + value: Expression::Literal { value, value_type }, + } = statement + { + if bindings.len() == 1 { + literals.insert(bindings[0].0, (value.clone(), *value_type)); + } + } + } +} + +/// Visits every Call expression in a statement list (recursing into nested +/// regions) and invokes `record(function_id, arguments, branch_literals)`. +/// `branch_literals` covers `Let id = Literal v` bindings encountered earlier +/// in the same statement list — branches inherit the literals from the +/// containing block but their own literals stay local to that branch. +fn visit_calls(statements: &[Statement], record: &mut F) +where + F: FnMut(FunctionId, &[Value], &std::collections::BTreeMap), +{ + use std::collections::BTreeMap; + let mut literals: BTreeMap = BTreeMap::new(); + visit_calls_inner(statements, &mut literals, record); +} + +fn visit_calls_inner( + statements: &[Statement], + literals: &mut std::collections::BTreeMap, + record: &mut F, +) where + F: FnMut(FunctionId, &[Value], &std::collections::BTreeMap), +{ + for statement in statements { + match statement { + Statement::Let { bindings, value } => { + if let Expression::Literal { value, value_type } = value { + if bindings.len() == 1 { + literals.insert(bindings[0].0, (value.clone(), *value_type)); + } + } + if let Expression::Call { + function, + arguments, + } = value + { + record(*function, arguments, literals); + } + } + Statement::Expression(Expression::Call { + function, + arguments, + }) => { + record(*function, arguments, literals); + } + Statement::If { + then_region, + else_region, + .. + } => { + let saved = literals.clone(); + visit_calls_inner(&then_region.statements, literals, record); + if let Some(region) = else_region { + *literals = saved.clone(); + visit_calls_inner(®ion.statements, literals, record); + } + *literals = saved; + } + Statement::Switch { cases, default, .. } => { + let saved = literals.clone(); + for case in cases { + visit_calls_inner(&case.body.statements, literals, record); + *literals = saved.clone(); + } + if let Some(region) = default { + visit_calls_inner(®ion.statements, literals, record); + } + *literals = saved; + } + Statement::For { + condition_statements, + body, + post, + .. + } => { + let saved = literals.clone(); + visit_calls_inner(condition_statements, literals, record); + visit_calls_inner(&body.statements, literals, record); + visit_calls_inner(&post.statements, literals, record); + *literals = saved; + } + Statement::Block(region) => { + let saved = literals.clone(); + visit_calls_inner(®ion.statements, literals, record); + *literals = saved; + } + _ => {} + } + } +} + +/// Trim arguments from every Call expression in the statement list whose +/// callee appears in `drops`. `drops[fid]` is the ascending list of argument +/// indices to remove. +fn trim_call_arguments( + statements: &mut [Statement], + drops: &std::collections::BTreeMap>, +) { + for statement in statements.iter_mut() { + match statement { + Statement::Let { + value: + Expression::Call { + function, + arguments, + }, + .. + } => { + if let Some(indices) = drops.get(function) { + trim_indices(arguments, indices); + } + } + Statement::Expression(Expression::Call { + function, + arguments, + }) => { + if let Some(indices) = drops.get(function) { + trim_indices(arguments, indices); + } + } + Statement::If { + then_region, + else_region, + .. + } => { + trim_call_arguments(&mut then_region.statements, drops); + if let Some(region) = else_region { + trim_call_arguments(&mut region.statements, drops); + } + } + Statement::Switch { cases, default, .. } => { + for case in cases { + trim_call_arguments(&mut case.body.statements, drops); + } + if let Some(region) = default { + trim_call_arguments(&mut region.statements, drops); + } + } + Statement::For { + condition_statements, + body, + post, + .. + } => { + trim_call_arguments(condition_statements, drops); + trim_call_arguments(&mut body.statements, drops); + trim_call_arguments(&mut post.statements, drops); + } + Statement::Block(region) => { + trim_call_arguments(&mut region.statements, drops); + } + _ => {} + } + } +} + +fn trim_indices(values: &mut Vec, indices_ascending: &[usize]) { + let mut keep: Vec = + Vec::with_capacity(values.len() - indices_ascending.len().min(values.len())); + let drop_set: std::collections::BTreeSet = indices_ascending.iter().copied().collect(); + for (i, v) in values.iter().enumerate() { + if !drop_set.contains(&i) { + keep.push(v.clone()); + } + } + *values = keep; +} diff --git a/crates/newyork/src/mem_opt.rs b/crates/newyork/src/mem_opt.rs new file mode 100644 index 000000000..88a2aee83 --- /dev/null +++ b/crates/newyork/src/mem_opt.rs @@ -0,0 +1,1763 @@ +//! Memory optimization pass for load-after-store elimination and dead store elimination. +//! +//! This module provides the infrastructure for two key optimizations: +//! +//! 1. **Load-after-store elimination**: If we just stored a value to a memory location +//! and then load from that same location, we can reuse the stored value directly +//! without accessing memory. +//! +//! 2. **Dead store elimination**: If we store a value to a memory location and that +//! value is never read before being overwritten or the function returns, we can +//! eliminate the store. +//! +//! # Current Status +//! +//! The infrastructure for tracking memory state and constant values is in place. The pass +//! correctly traverses the IR and maintains state, but currently applies **conservative** +//! state clearing at control flow boundaries. This ensures correctness while we build +//! confidence in the implementation. +//! +//! The optimization will fire when: +//! - A load immediately follows a store to the same static offset +//! - Both offsets can be resolved to compile-time constants +//! +//! # Memory Model +//! +//! We track memory state at the granularity of 32-byte words (matching EVM semantics). +//! A store to a known static offset records the stored value at that offset. +//! A store to an unknown (dynamic) offset conservatively invalidates all tracked state. +//! +//! # Value Tracking +//! +//! We track constant values through `Let` bindings to determine static memory offsets: +//! - `Let { x, Literal(42) }` - x is known to be 42 +//! - `Let { y, Binary(Add, x, z) }` where x=10, z=5 - y is known to be 15 +//! +//! This enables us to identify when memory operations use constant offsets even when +//! the offset is computed through intermediate variables. +//! +//! # Safety +//! +//! The pass is conservative at control flow joins - we clear all state when entering +//! or exiting control flow constructs (if, switch, for, block). This ensures correctness +//! but limits optimization opportunities. Future work can implement proper state merging +//! for branches. +//! +//! # Limitations +//! +//! - Only static offsets (compile-time constants) are tracked +//! - Cross-function optimization is not implemented +//! - Control flow joins clear all state (conservative but correct) +//! - Dead store elimination is tracked but not applied yet + +use std::collections::{BTreeMap, BTreeSet}; + +use num::{BigUint, Zero}; + +use crate::ir::{ + for_each_statement, word_align, BinaryOperation, BitWidth, Block, Expression, FunctionId, + MemoryRegion, Object, Region, Statement, Type, Value, ValueId, +}; +use revive_common::BYTE_LENGTH_WORD; + +/// Results of memory optimization. +#[derive(Clone, Debug, Default)] +pub struct MemOptResults { + /// Number of loads eliminated (replaced with stored value). + pub loads_eliminated: usize, + /// Number of stores eliminated (dead stores). + pub stores_eliminated: usize, + /// Number of values tracked. + pub values_tracked: usize, + /// Number of keccak256 calls fused into keccak256_pair. + pub keccak_pairs_fused: usize, + /// Number of keccak256 calls fused into keccak256_single. + pub keccak_singles_fused: usize, + /// Number of FMP (`mload(0x40)`) loads eliminated by [`FmpPropagation`]. + pub fmp_loads_eliminated: usize, +} + +/// Memory optimization pass. +pub struct MemoryOptimizer { + /// Tracks the most recently stored value at each static memory offset. + /// Key is the word-aligned offset. + memory_state: BTreeMap, + /// Tracks constant values for ValueIds. + /// When a Let binds a literal, we record the constant value here. + constant_values: BTreeMap, + /// Counter for fresh value IDs when creating new bindings. + next_value_id: u32, + /// Statistics about optimizations performed. + statistics: MemOptResults, + /// Indices of dead stores that should be removed in the current statement list. + /// A store is dead if it's overwritten before being read. + dead_store_indices: BTreeSet, + /// Pending stores that haven't been read yet. + /// Maps word-aligned offset to the index in the current statement list. + pending_stores: BTreeMap, +} + +/// A tracked value in memory. +#[derive(Clone, Debug)] +struct TrackedValue { + /// The value that was stored. + stored_value: Value, + /// The exact offset where it was stored. + offset: u64, + /// Whether this store has been read (for dead store elimination). + was_read: bool, +} + +impl MemoryOptimizer { + /// Creates a new memory optimizer. + pub fn new() -> Self { + MemoryOptimizer { + memory_state: BTreeMap::new(), + constant_values: BTreeMap::new(), + next_value_id: 0, + statistics: MemOptResults::default(), + dead_store_indices: BTreeSet::new(), + pending_stores: BTreeMap::new(), + } + } + + /// Optimizes an object in place. + pub fn optimize_object(&mut self, object: &mut Object) -> MemOptResults { + self.next_value_id = object.find_max_value_id() + 1; + + self.optimize_block(&mut object.code); + + for function in object.functions.values_mut() { + self.memory_state.clear(); + self.constant_values.clear(); + self.optimize_block(&mut function.body); + } + + std::mem::take(&mut self.statistics) + } + + /// Optimizes a block in place. + fn optimize_block(&mut self, block: &mut Block) { + let statements = std::mem::take(&mut block.statements); + block.statements = self.optimize_statements(statements); + } + + /// Optimizes a region in place. + fn optimize_region(&mut self, region: &mut Region) { + let statements = std::mem::take(&mut region.statements); + region.statements = self.optimize_statements(statements); + } + + /// Optimizes a list of statements. + fn optimize_statements(&mut self, statements: Vec) -> Vec { + let outer_dead_stores = std::mem::take(&mut self.dead_store_indices); + let outer_pending = std::mem::take(&mut self.pending_stores); + + let mut processed = Vec::with_capacity(statements.len()); + + for (index, statement) in statements.into_iter().enumerate() { + match statement { + Statement::MStore { + offset, + value, + region, + } => { + if let Some(static_offset) = self.try_get_static_offset(&offset) { + let word_offset = word_align(static_offset); + + // Dead-store elimination: an unread mstore to the + // exact same offset is fully overwritten by this + // one. Check this FIRST, before the overlap-retain + // below drops the matching `pending_stores` entry. + if let Some(&prev_idx) = self.pending_stores.get(&static_offset) { + self.dead_store_indices.insert(prev_idx); + self.statistics.stores_eliminated += 1; + log::trace!( + "Dead store at index {} (offset {}) - overwritten at index {}", + prev_idx, + static_offset, + index + ); + } + + // Soundness: an `mstore(p, v)` writes 32 bytes at + // `[p, p + 32)`. Forwarding compares the *exact* + // `tracked.offset` against the load's static + // offset, so any tracked entry whose own 32-byte + // write range overlaps `[p, p + 32)` must be + // invalidated — otherwise a later `mload` at the + // stale tracked offset would forward the + // pre-overwrite value while the actual memory has + // been partially overwritten by the new store. + let new_end = static_offset.saturating_add(BYTE_LENGTH_WORD as u64); + self.memory_state.retain(|_, tracked| { + let tracked_end = + tracked.offset.saturating_add(BYTE_LENGTH_WORD as u64); + tracked_end <= static_offset || tracked.offset >= new_end + }); + // Same for pending_stores: a partial-overwrite + // doesn't make the prior store dead (its bytes are + // only *partially* covered), but a later `mload` + // won't match the original offset either, so the + // pending entry can never be matched and should + // not be kept. + self.pending_stores.retain(|&k, _| { + let prev_end = k.saturating_add(BYTE_LENGTH_WORD as u64); + prev_end <= static_offset || k >= new_end + }); + + self.pending_stores.insert(static_offset, index); + + self.memory_state.insert( + word_offset, + TrackedValue { + stored_value: value, + offset: static_offset, + was_read: false, + }, + ); + self.statistics.values_tracked += 1; + } else { + self.memory_state.clear(); + self.pending_stores.clear(); + } + processed.push(Statement::MStore { + offset, + value, + region, + }); + } + + Statement::MStore8 { + offset, + value, + region, + } => { + if let Some(static_offset) = self.try_get_static_offset(&offset) { + // Soundness: `mstore8(p, _)` overwrites the single + // byte at `p`. Any tracked entry from an earlier + // `mstore` whose 32-byte write range + // `[tracked.offset, tracked.offset + 32)` covers + // `p` becomes stale — `mload` at the still-cached + // exact tracked offset would forward the + // pre-overwrite value. Invalidate every such + // entry and the matching `pending_stores` key. + self.memory_state.retain(|_, tracked| { + let tracked_end = + tracked.offset.saturating_add(BYTE_LENGTH_WORD as u64); + tracked.offset > static_offset || tracked_end <= static_offset + }); + self.pending_stores.retain(|&k, _| { + let prev_end = k.saturating_add(BYTE_LENGTH_WORD as u64); + k > static_offset || prev_end <= static_offset + }); + } else { + self.memory_state.clear(); + self.pending_stores.clear(); + } + processed.push(Statement::MStore8 { + offset, + value, + region, + }); + } + + Statement::MCopy { dest, src, length } => { + self.memory_state.clear(); + self.pending_stores.clear(); + processed.push(Statement::MCopy { dest, src, length }); + } + + Statement::Let { bindings, value } => { + let is_call = matches!(&value, Expression::Call { .. }); + + let optimized_value = self.optimize_expr_with_read_tracking(value); + + if is_call { + self.memory_state.clear(); + self.pending_stores.clear(); + } + + if bindings.len() == 1 { + self.record_constant(bindings[0], &optimized_value); + } + + processed.push(Statement::Let { + bindings, + value: optimized_value, + }); + } + + Statement::If { + condition, + inputs, + mut then_region, + else_region, + outputs, + } => { + self.pending_stores.clear(); + + let pre_branch_memory = self.memory_state.clone(); + let pre_branch_constants = self.constant_values.clone(); + + self.optimize_region(&mut then_region); + let then_memory = self.memory_state.clone(); + let then_constants = self.constant_values.clone(); + + let else_region = if let Some(mut er) = else_region { + self.memory_state = pre_branch_memory; + self.constant_values = pre_branch_constants; + self.optimize_region(&mut er); + + self.memory_state = + Self::intersect_memory_state(&then_memory, &self.memory_state); + self.constant_values = + Self::intersect_constants(&then_constants, &self.constant_values); + Some(er) + } else { + self.memory_state = + Self::intersect_memory_state(&then_memory, &pre_branch_memory); + self.constant_values = + Self::intersect_constants(&then_constants, &pre_branch_constants); + None + }; + + processed.push(Statement::If { + condition, + inputs, + then_region, + else_region, + outputs, + }); + } + + Statement::Switch { + scrutinee, + inputs, + mut cases, + default, + outputs, + } => { + self.pending_stores.clear(); + + let pre_branch_memory = self.memory_state.clone(); + let pre_branch_constants = self.constant_values.clone(); + + let mut exit_memories = Vec::new(); + let mut exit_constants = Vec::new(); + for case in &mut cases { + self.memory_state = pre_branch_memory.clone(); + self.constant_values = pre_branch_constants.clone(); + self.optimize_region(&mut case.body); + exit_memories.push(self.memory_state.clone()); + exit_constants.push(self.constant_values.clone()); + } + + let default = if let Some(mut d) = default { + self.memory_state = pre_branch_memory; + self.constant_values = pre_branch_constants; + self.optimize_region(&mut d); + exit_memories.push(self.memory_state.clone()); + exit_constants.push(self.constant_values.clone()); + Some(d) + } else { + exit_memories.push(pre_branch_memory); + exit_constants.push(pre_branch_constants); + None + }; + + self.memory_state = Self::intersect_memory_states(&exit_memories); + self.constant_values = Self::intersect_all_constants(&exit_constants); + + processed.push(Statement::Switch { + scrutinee, + inputs, + cases, + default, + outputs, + }); + } + + Statement::For { + initial_values, + loop_variables, + mut condition_statements, + condition, + mut body, + post_input_variables, + mut post, + outputs, + } => { + self.memory_state.clear(); + self.constant_values.clear(); + self.pending_stores.clear(); + + condition_statements = self.optimize_statements(condition_statements); + self.memory_state.clear(); + self.constant_values.clear(); + self.optimize_region(&mut body); + self.memory_state.clear(); + self.constant_values.clear(); + self.optimize_region(&mut post); + + self.memory_state.clear(); + self.constant_values.clear(); + + processed.push(Statement::For { + initial_values, + loop_variables, + condition_statements, + condition, + body, + post_input_variables, + post, + outputs, + }); + } + + Statement::Block(mut region) => { + self.pending_stores.clear(); + self.optimize_region(&mut region); + processed.push(Statement::Block(region)); + } + + Statement::Expression(expression) => { + let is_call = matches!(&expression, Expression::Call { .. }); + + let optimized = self.optimize_expr_with_read_tracking(expression); + + if is_call { + self.memory_state.clear(); + self.pending_stores.clear(); + } + + processed.push(Statement::Expression(optimized)); + } + + Statement::ExternalCall { .. } => { + self.memory_state.clear(); + self.pending_stores.clear(); + processed.push(statement); + } + + Statement::Create { .. } => { + self.memory_state.clear(); + self.pending_stores.clear(); + processed.push(statement); + } + + Statement::CodeCopy { + ref dest, + ref length, + .. + } + | Statement::ExtCodeCopy { + ref dest, + ref length, + .. + } + | Statement::ReturnDataCopy { + ref dest, + ref length, + .. + } + | Statement::DataCopy { + ref dest, + ref length, + .. + } + | Statement::CallDataCopy { + ref dest, + ref length, + .. + } => { + // Soundness: a `*copy(dest, _, length)` writes + // `length` bytes at `[dest, dest + length)`. Any + // tracked entry whose own 32-byte write range + // overlaps that range must be invalidated — + // otherwise a later `mload` at the still-cached + // exact tracked offset would forward the + // pre-overwrite value while actual memory has been + // overwritten by the copy. + // + // Three cases, in priority order: + // + // 1. `length == Some(0)`: zero-byte copy is a + // no-op regardless of whether `dest` is known — + // nothing to invalidate. + // 2. `dest == Some(start)` and `length == Some(size)` + // with `size > 0`: known write range, retain + // only entries that don't overlap. + // 3. anything else (dynamic dest with nonzero or + // unknown length, dynamic length with known + // dest): conservatively clear all tracking. + let copy_length = self.try_get_static_offset(length); + let copy_dest = self.try_get_static_offset(dest); + if matches!(copy_length, Some(0)) { + // case 1: no bytes written + } else if let (Some(start), Some(size)) = (copy_dest, copy_length) { + // case 2: known [start, start + size) range + let end = start.saturating_add(size); + self.memory_state.retain(|_, tracked| { + let tracked_end = + tracked.offset.saturating_add(BYTE_LENGTH_WORD as u64); + tracked_end <= start || tracked.offset >= end + }); + self.pending_stores.retain(|&k, _| { + let prev_end = k.saturating_add(BYTE_LENGTH_WORD as u64); + prev_end <= start || k >= end + }); + } else { + // case 3: dynamic — pessimistic clear + self.memory_state.clear(); + self.pending_stores.clear(); + } + processed.push(statement); + } + + Statement::Log { + offset, + length, + topics, + } => { + self.pending_stores.clear(); + processed.push(Statement::Log { + offset, + length, + topics, + }); + } + + Statement::Return { .. } | Statement::Revert { .. } => { + self.pending_stores.clear(); + processed.push(statement); + } + + Statement::SStore { .. } + | Statement::TStore { .. } + | Statement::MappingSStore { .. } + | Statement::SetImmutable { .. } + | Statement::SelfDestruct { .. } + | Statement::Stop + | Statement::Invalid + | Statement::PanicRevert { .. } + | Statement::ErrorStringRevert { .. } + | Statement::CustomErrorRevert { .. } + | Statement::Break { .. } + | Statement::Continue { .. } + | Statement::Leave { .. } => { + processed.push(statement); + } + } + } + + let result = if self.dead_store_indices.is_empty() { + processed + } else { + processed + .into_iter() + .enumerate() + .filter(|(index, _)| !self.dead_store_indices.contains(index)) + .map(|(_, statement)| statement) + .collect() + }; + + self.dead_store_indices = outer_dead_stores; + self.pending_stores = outer_pending; + + result + } + + /// Tracks memory reads for dead store elimination and load-after-store forwarding. + /// + /// When a load follows a store to the same static offset, the stored value is + /// forwarded directly, eliminating the redundant memory round-trip. If the stored + /// value has a narrower type than I256 (what MLoad produces), a ZeroExtend is + /// inserted to maintain type correctness. + fn optimize_expr_with_read_tracking(&mut self, expression: Expression) -> Expression { + match expression { + Expression::MLoad { offset, region } => { + if let Some(static_offset) = self.try_get_static_offset(&offset) { + let word_offset = word_align(static_offset); + + self.pending_stores.remove(&word_offset); + + if let Some(tracked) = self.memory_state.get_mut(&word_offset) { + if tracked.offset == static_offset { + tracked.was_read = true; + + let stored = tracked.stored_value; + self.statistics.loads_eliminated += 1; + log::trace!("Load-after-store forwarding at offset {}", static_offset); + + return match stored.value_type { + Type::Int(BitWidth::I256) => Expression::Var(stored.id), + Type::Int(width) if width < BitWidth::I256 => { + Expression::ZeroExtend { + value: stored, + to: BitWidth::I256, + } + } + _ => Expression::Var(stored.id), + }; + } + } + } else { + self.pending_stores.clear(); + } + Expression::MLoad { offset, region } + } + + Expression::Keccak256 { offset, length } => { + let static_offset = self.try_get_static_offset(&offset); + let static_length = self.try_get_static_offset(&length); + + // Fusion soundness: the `Keccak256Pair` / `Keccak256Single` + // helper functions write their input back to heap[0..N] + // (see `Keccak256OneWord::emit_body` / + // `Keccak256TwoWords::emit_body`), so the post-call heap + // state matches what EVM's `mstore(...); keccak256(...)` + // would have produced. That lets us safely dead-eliminate + // the prior mstores — a later `mload` (even one that + // mem_opt's forwarding can't reach because of an + // intervening clearing event) reads the helper's heap + // write and gets the same value EVM would. + if static_offset == Some(0) && static_length == Some(2 * BYTE_LENGTH_WORD as u64) { + if let (Some(tracked0), Some(tracked32)) = ( + self.memory_state.get(&0), + self.memory_state.get(&(BYTE_LENGTH_WORD as u64)), + ) { + if tracked0.offset == 0 && tracked32.offset == BYTE_LENGTH_WORD as u64 { + let word0 = tracked0.stored_value; + let word1 = tracked32.stored_value; + if let Some(&idx0) = self.pending_stores.get(&0) { + self.dead_store_indices.insert(idx0); + self.statistics.stores_eliminated += 1; + } + if let Some(&idx32) = + self.pending_stores.get(&(BYTE_LENGTH_WORD as u64)) + { + self.dead_store_indices.insert(idx32); + self.statistics.stores_eliminated += 1; + } + self.statistics.keccak_pairs_fused += 1; + self.pending_stores.clear(); + log::trace!("Fused keccak256(0, 64) into keccak256_pair"); + return Expression::Keccak256Pair { word0, word1 }; + } + } + } + + if static_offset == Some(0) && static_length == Some(BYTE_LENGTH_WORD as u64) { + if let Some(tracked0) = self.memory_state.get(&0) { + if tracked0.offset == 0 { + let word0 = tracked0.stored_value; + if let Some(&idx0) = self.pending_stores.get(&0) { + self.dead_store_indices.insert(idx0); + self.statistics.stores_eliminated += 1; + } + self.statistics.keccak_singles_fused += 1; + self.pending_stores.clear(); + log::trace!("Fused keccak256(0, 32) into keccak256_single"); + return Expression::Keccak256Single { word0 }; + } + } + } + + self.pending_stores.clear(); + Expression::Keccak256 { offset, length } + } + + Expression::Keccak256Pair { word0, word1 } => { + self.pending_stores.clear(); + Expression::Keccak256Pair { word0, word1 } + } + + Expression::Keccak256Single { word0 } => { + self.pending_stores.clear(); + Expression::Keccak256Single { word0 } + } + + Expression::MappingSLoad { key, slot } => { + self.pending_stores.clear(); + Expression::MappingSLoad { key, slot } + } + + other => other, + } + } + + /// Intersects two memory states: keeps entries present in both with the same stored value ID. + fn intersect_memory_state( + a: &BTreeMap, + b: &BTreeMap, + ) -> BTreeMap { + let mut result = BTreeMap::new(); + for (offset, val_a) in a { + if let Some(val_b) = b.get(offset) { + if val_a.stored_value.id == val_b.stored_value.id && val_a.offset == val_b.offset { + result.insert(*offset, val_a.clone()); + } + } + } + result + } + + /// Intersects two constant value maps: keeps entries present in both with the same value. + fn intersect_constants( + a: &BTreeMap, + b: &BTreeMap, + ) -> BTreeMap { + let mut result = BTreeMap::new(); + for (id, val_a) in a { + if let Some(val_b) = b.get(id) { + if val_a == val_b { + result.insert(*id, val_a.clone()); + } + } + } + result + } + + /// Intersects multiple memory states (for switch with many cases). + fn intersect_memory_states( + states: &[BTreeMap], + ) -> BTreeMap { + if states.is_empty() { + return BTreeMap::new(); + } + let mut result = states[0].clone(); + for state in &states[1..] { + result = Self::intersect_memory_state(&result, state); + } + result + } + + /// Intersects multiple constant maps (for switch with many cases). + fn intersect_all_constants(constants: &[BTreeMap]) -> BTreeMap { + if constants.is_empty() { + return BTreeMap::new(); + } + let mut result = constants[0].clone(); + for c in &constants[1..] { + result = Self::intersect_constants(&result, c); + } + result + } + + /// Tries to extract a static offset from a Value. + /// Looks up the value ID in the constant_values map. + fn try_get_static_offset(&self, value: &Value) -> Option { + self.constant_values.get(&value.id.0).and_then(|big| { + let digits = big.to_u64_digits(); + if digits.is_empty() { + Some(0) + } else if digits.len() == 1 { + Some(digits[0]) + } else { + None + } + }) + } + + /// Tries to evaluate an expression to a constant value. + fn try_eval_const(&self, expression: &Expression) -> Option { + match expression { + Expression::Literal { value, .. } => Some(value.clone()), + Expression::Var(id) => self.constant_values.get(&id.0).cloned(), + Expression::Binary { + operation, + lhs, + rhs, + } => { + let l = self.constant_values.get(&lhs.id.0)?; + let r = self.constant_values.get(&rhs.id.0)?; + match operation { + BinaryOperation::Add => Some(l + r), + BinaryOperation::Sub => { + if l >= r { + Some(l - r) + } else { + None + } + } + BinaryOperation::Mul => Some(l * r), + BinaryOperation::Div => { + if r.is_zero() { + None + } else { + Some(l / r) + } + } + BinaryOperation::And => Some(l & r), + BinaryOperation::Or => Some(l | r), + BinaryOperation::Xor => Some(l ^ r), + BinaryOperation::Shl => { + let shift = r.to_u32_digits().first().copied().unwrap_or(0); + if shift < 256 { + Some(l << shift as usize) + } else { + Some(BigUint::from(0u32)) + } + } + BinaryOperation::Shr => { + let shift = r.to_u32_digits().first().copied().unwrap_or(0); + if shift < 256 { + Some(l >> shift as usize) + } else { + Some(BigUint::from(0u32)) + } + } + _ => None, + } + } + _ => None, + } + } + + /// Records a constant binding if the expression is constant. + fn record_constant(&mut self, binding_id: ValueId, expression: &Expression) { + if let Some(value) = self.try_eval_const(expression) { + self.constant_values.insert(binding_id.0, value); + } + } +} + +impl Default for MemoryOptimizer { + fn default() -> Self { + Self::new() + } +} + +/// Free memory pointer (FMP) propagation pass. +/// +/// Replaces `mload(0x40)` with the known FMP value when provably unchanged. +/// This eliminates expensive heap loads (`__revive_load_heap_word(64)` with sbrk + bswap) +/// in favor of cheap constant materialization. +/// +/// In Solidity-generated Yul, the runtime code starts with `mstore(0x40, 0x80)` and +/// most switch cases never update FMP. This pass detects those cases and propagates +/// the constant 0x80 through them. +pub struct FmpPropagation { + /// Number of FMP loads eliminated. + pub loads_eliminated: usize, + /// Set of function IDs that may write to FMP (directly or transitively). + fmp_writers: BTreeSet, +} + +impl FmpPropagation { + /// Creates a new FMP propagation pass. + pub fn new(_next_value_id: u32) -> Self { + FmpPropagation { + loads_eliminated: 0, + fmp_writers: BTreeSet::new(), + } + } + + /// Runs FMP propagation on an object. + pub fn propagate_object(&mut self, object: &mut Object) { + self.fmp_writers = Self::find_fmp_writers(object); + + self.propagate_block(&mut object.code); + for function in object.functions.values_mut() { + self.propagate_block(&mut function.body); + } + } + + /// Finds all functions that may write to FMP, including transitive callers. + fn find_fmp_writers(object: &Object) -> BTreeSet { + let mut direct_writers = BTreeSet::new(); + let mut callers: BTreeMap> = BTreeMap::new(); + + for (fid, function) in &object.functions { + if Self::statements_write_fmp(&function.body.statements) { + direct_writers.insert(*fid); + } + Self::collect_callees(&function.body.statements, &mut |callee| { + callers.entry(callee).or_default().push(*fid); + }); + } + + Self::collect_callees(&object.code.statements, &mut |_callee| {}); + + let mut writers = direct_writers.clone(); + let mut worklist: Vec = direct_writers.into_iter().collect(); + while let Some(fid) = worklist.pop() { + if let Some(caller_list) = callers.get(&fid) { + for caller in caller_list { + if writers.insert(*caller) { + worklist.push(*caller); + } + } + } + } + + writers + } + + /// Collects all function IDs called in a statement list, recursing through + /// nested regions and `For::condition_statements`. + fn collect_callees(statements: &[Statement], cb: &mut dyn FnMut(FunctionId)) { + for_each_statement(statements, &mut |statement| { + if let Statement::Let { value, .. } | Statement::Expression(value) = statement { + if let Expression::Call { function, .. } = value { + cb(*function); + } + } + }); + } + + /// Propagates FMP through a block. + fn propagate_block(&mut self, block: &mut Block) { + let statements = std::mem::take(&mut block.statements); + block.statements = self.propagate_statements(statements, None); + } + + /// Propagates FMP through a region. + fn propagate_region(&mut self, region: &mut Region, fmp_value: Option) { + let statements = std::mem::take(&mut region.statements); + region.statements = self.propagate_statements(statements, fmp_value); + } + + /// Propagates FMP value through a statement list. + /// + /// Tracks constant values to resolve MStore/MLoad offsets, and maintains the + /// known FMP value across control flow when provably safe. + fn propagate_statements( + &mut self, + statements: Vec, + initial_fmp: Option, + ) -> Vec { + let mut fmp_value = initial_fmp; + let mut constants: BTreeMap = BTreeMap::new(); + let mut result = Vec::with_capacity(statements.len()); + + for statement in statements { + match statement { + Statement::MStore { + offset, + value, + region, + } => { + let resolved_offset = Self::resolve_offset(&constants, &offset); + let is_fmp_store = region.is_free_pointer_slot(resolved_offset); + + if is_fmp_store { + let new_fmp = Self::resolve_value(&constants, &value); + fmp_value = new_fmp; + } else if resolved_offset.is_none() + && region != MemoryRegion::Dynamic + && region != MemoryRegion::Scratch + { + // Soundness: a dynamic-offset mstore whose offset we + // can't resolve statically could land on 0x40 at + // runtime (e.g. `mstore(calldataload(p), v)`). The + // simplifier leaves `region == Unknown` for any + // non-literal offset, so the only safe move is to + // invalidate the tracked FMP. `Dynamic` (offset + // proven `>= 0x80`) and `Scratch` (`< 0x40`) regions + // can't reach 0x40 even at runtime, so we keep them. + fmp_value = None; + } + + result.push(Statement::MStore { + offset, + value, + region, + }); + } + + Statement::Let { bindings, value } => { + let new_value = if let Expression::MLoad { + ref offset, + ref region, + } = value + { + let resolved_offset = Self::resolve_offset(&constants, offset); + let is_fmp_load = region.is_free_pointer_slot(resolved_offset); + + if is_fmp_load { + if let Some(ref known_fmp) = fmp_value { + self.loads_eliminated += 1; + Some(Expression::Literal { + value: known_fmp.clone(), + value_type: Type::Int(BitWidth::I256), + }) + } else { + None + } + } else { + None + } + } else { + None + }; + + let final_value = new_value.unwrap_or(value); + + if bindings.len() == 1 { + if let Some(c) = Self::eval_const(&constants, &final_value) { + constants.insert(bindings[0].0, c); + } + } + + if let Expression::Call { function, .. } = &final_value { + if self.fmp_writers.contains(function) { + fmp_value = None; + } + } + + result.push(Statement::Let { + bindings, + value: final_value, + }); + } + + Statement::If { + condition, + inputs, + mut then_region, + else_region, + outputs, + } => { + self.propagate_region(&mut then_region, fmp_value.clone()); + let then_writes = Self::region_writes_fmp(&then_region); + + let else_region = if let Some(mut er) = else_region { + self.propagate_region(&mut er, fmp_value.clone()); + let else_writes = Self::region_writes_fmp(&er); + if then_writes || else_writes { + fmp_value = None; + } + Some(er) + } else { + if then_writes { + fmp_value = None; + } + None + }; + + result.push(Statement::If { + condition, + inputs, + then_region, + else_region, + outputs, + }); + } + + Statement::Switch { + scrutinee, + inputs, + mut cases, + default, + outputs, + } => { + let mut any_writes = false; + + for case in &mut cases { + self.propagate_region(&mut case.body, fmp_value.clone()); + if Self::region_writes_fmp(&case.body) { + any_writes = true; + } + } + + let default = if let Some(mut d) = default { + self.propagate_region(&mut d, fmp_value.clone()); + if Self::region_writes_fmp(&d) { + any_writes = true; + } + Some(d) + } else { + None + }; + + if any_writes { + fmp_value = None; + } + + result.push(Statement::Switch { + scrutinee, + inputs, + cases, + default, + outputs, + }); + } + + Statement::For { + initial_values, + loop_variables, + mut condition_statements, + condition, + mut body, + post_input_variables, + mut post, + outputs, + } => { + self.propagate_region(&mut body, fmp_value.clone()); + condition_statements = + self.propagate_statements(condition_statements, fmp_value.clone()); + self.propagate_region(&mut post, fmp_value.clone()); + + if Self::statements_write_fmp(&body.statements) + || Self::statements_write_fmp(&condition_statements) + || Self::statements_write_fmp(&post.statements) + { + fmp_value = None; + } + + result.push(Statement::For { + initial_values, + loop_variables, + condition_statements, + condition, + body, + post_input_variables, + post, + outputs, + }); + } + + Statement::MCopy { dest, src, length } => { + if Self::resolve_offset(&constants, &dest) == Some(0x40) { + fmp_value = None; + } + result.push(Statement::MCopy { dest, src, length }); + } + + Statement::Block(mut region) => { + self.propagate_region(&mut region, fmp_value.clone()); + if Self::region_writes_fmp(®ion) { + fmp_value = None; + } + result.push(Statement::Block(region)); + } + + Statement::Expression(ref expression) => { + if let Expression::Call { function, .. } = expression { + if self.fmp_writers.contains(function) { + fmp_value = None; + } + } + result.push(statement); + } + + Statement::ExternalCall { .. } | Statement::Create { .. } => { + fmp_value = None; + result.push(statement); + } + + other => { + result.push(other); + } + } + } + + result + } + + /// Checks if a region writes to offset 0x40 (the FMP slot). + fn region_writes_fmp(region: &Region) -> bool { + Self::statements_write_fmp(®ion.statements) + } + + /// Checks if any statement (recursively) writes to offset 0x40 or otherwise + /// invalidates the FMP. The IR translator marks FMP stores explicitly via + /// `MemoryRegion::FreePointerSlot`; `ExternalCall`/`Create` are conservative + /// invalidators because they can mutate arbitrary memory. `MCopy` to 0x40 + /// is theoretically possible but is not generated by Solidity in practice + /// and would defeat the optimization for everyone. + fn statements_write_fmp(statements: &[Statement]) -> bool { + let mut found = false; + for_each_statement(statements, &mut |statement| { + if matches!( + statement, + Statement::MStore { + region: MemoryRegion::FreePointerSlot, + .. + } | Statement::ExternalCall { .. } + | Statement::Create { .. } + ) { + found = true; + } + }); + found + } + + /// Resolves a Value to a constant offset if known. + fn resolve_offset(constants: &BTreeMap, value: &Value) -> Option { + constants.get(&value.id.0).and_then(|big| { + let digits = big.to_u64_digits(); + if digits.is_empty() { + Some(0) + } else if digits.len() == 1 { + Some(digits[0]) + } else { + None + } + }) + } + + /// Resolves a Value to a constant BigUint if known. + fn resolve_value(constants: &BTreeMap, value: &Value) -> Option { + constants.get(&value.id.0).cloned() + } + + /// Evaluates an expression to a constant if possible. + fn eval_const(constants: &BTreeMap, expression: &Expression) -> Option { + match expression { + Expression::Literal { value, .. } => Some(value.clone()), + Expression::Var(id) => constants.get(&id.0).cloned(), + Expression::Binary { + operation, + lhs, + rhs, + } => { + let l = constants.get(&lhs.id.0)?; + let r = constants.get(&rhs.id.0)?; + match operation { + BinaryOperation::Add => Some(l + r), + BinaryOperation::Sub => { + if l >= r { + Some(l - r) + } else { + None + } + } + BinaryOperation::And => Some(l & r), + BinaryOperation::Or => Some(l | r), + _ => None, + } + } + _ => None, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::ir::{BitWidth, Type}; + + fn make_value(id: u32) -> Value { + Value { + id: ValueId(id), + value_type: Type::Int(BitWidth::I256), + } + } + + #[test] + fn test_load_after_store_elimination() { + use crate::ir::{MemoryRegion, Object}; + + let mut opt = MemoryOptimizer::new(); + + let offset_id = ValueId(1); + let value_id = ValueId(2); + let result_id = ValueId(3); + + let statements = vec![ + Statement::Let { + bindings: vec![offset_id], + value: Expression::Literal { + value: BigUint::from(64u32), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::Let { + bindings: vec![value_id], + value: Expression::Literal { + value: BigUint::from(42u32), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::MStore { + offset: Value { + id: offset_id, + value_type: Type::Int(BitWidth::I256), + }, + value: Value { + id: value_id, + value_type: Type::Int(BitWidth::I256), + }, + region: MemoryRegion::Unknown, + }, + Statement::Let { + bindings: vec![result_id], + value: Expression::MLoad { + offset: Value { + id: offset_id, + value_type: Type::Int(BitWidth::I256), + }, + region: MemoryRegion::Unknown, + }, + }, + ]; + + let mut object = Object { + name: "test".to_string(), + code: Block { statements }, + functions: BTreeMap::new(), + subobjects: vec![], + data: BTreeMap::new(), + }; + + let statistics = opt.optimize_object(&mut object); + + assert_eq!(statistics.loads_eliminated, 1); + + if let Statement::Let { value, .. } = &object.code.statements[3] { + assert!( + matches!(value, Expression::Var(_)), + "Expected Var (forwarded value), got {:?}", + value + ); + } else { + panic!("Expected Let statement"); + } + } + + #[test] + fn test_constant_propagation_through_add() { + use crate::ir::{MemoryRegion, Object}; + + let mut opt = MemoryOptimizer::new(); + + let base_id = ValueId(1); + let offset_id = ValueId(2); + let value_id = ValueId(3); + let result_id = ValueId(4); + + let statements = vec![ + Statement::Let { + bindings: vec![base_id], + value: Expression::Literal { + value: BigUint::from(32u32), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::Let { + bindings: vec![offset_id], + value: Expression::Binary { + operation: BinaryOperation::Add, + lhs: Value { + id: base_id, + value_type: Type::Int(BitWidth::I256), + }, + rhs: Value { + id: ValueId(100), + value_type: Type::Int(BitWidth::I256), + }, + }, + }, + Statement::Let { + bindings: vec![value_id], + value: Expression::Literal { + value: BigUint::from(1u32), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::MStore { + offset: Value { + id: offset_id, + value_type: Type::Int(BitWidth::I256), + }, + value: Value { + id: value_id, + value_type: Type::Int(BitWidth::I256), + }, + region: MemoryRegion::Unknown, + }, + Statement::Let { + bindings: vec![result_id], + value: Expression::MLoad { + offset: Value { + id: offset_id, + value_type: Type::Int(BitWidth::I256), + }, + region: MemoryRegion::Unknown, + }, + }, + ]; + + let mut object = Object { + name: "test".to_string(), + code: Block { statements }, + functions: BTreeMap::new(), + subobjects: vec![], + data: BTreeMap::new(), + }; + + let _stats = opt.optimize_object(&mut object); + } + + #[test] + fn test_zero_offset_handling() { + let mut opt = MemoryOptimizer::new(); + + let zero_id = ValueId(1); + opt.constant_values.insert(zero_id.0, BigUint::from(0u32)); + + let value = Value { + id: zero_id, + value_type: Type::Int(BitWidth::I256), + }; + + let offset = opt.try_get_static_offset(&value); + assert_eq!(offset, Some(0)); + } + + #[test] + fn test_dead_store_elimination() { + use crate::ir::{MemoryRegion, Object}; + + let mut opt = MemoryOptimizer::new(); + + let offset_id = ValueId(1); + let value1_id = ValueId(2); + let value2_id = ValueId(3); + + let statements = vec![ + Statement::Let { + bindings: vec![offset_id], + value: Expression::Literal { + value: BigUint::from(64u32), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::Let { + bindings: vec![value1_id], + value: Expression::Literal { + value: BigUint::from(1u32), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::Let { + bindings: vec![value2_id], + value: Expression::Literal { + value: BigUint::from(2u32), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::MStore { + offset: Value { + id: offset_id, + value_type: Type::Int(BitWidth::I256), + }, + value: Value { + id: value1_id, + value_type: Type::Int(BitWidth::I256), + }, + region: MemoryRegion::Unknown, + }, + Statement::MStore { + offset: Value { + id: offset_id, + value_type: Type::Int(BitWidth::I256), + }, + value: Value { + id: value2_id, + value_type: Type::Int(BitWidth::I256), + }, + region: MemoryRegion::Unknown, + }, + ]; + + let mut object = Object { + name: "test".to_string(), + code: Block { statements }, + functions: BTreeMap::new(), + subobjects: vec![], + data: BTreeMap::new(), + }; + + let statistics = opt.optimize_object(&mut object); + + assert_eq!(statistics.stores_eliminated, 1); + + assert_eq!(object.code.statements.len(), 4); + + if let Statement::MStore { value, .. } = &object.code.statements[3] { + assert_eq!(value.id, value2_id); + } else { + panic!("Expected MStore statement"); + } + } + + #[test] + fn test_no_dead_store_when_read() { + use crate::ir::{MemoryRegion, Object}; + + let mut opt = MemoryOptimizer::new(); + + let offset_id = ValueId(1); + let value1_id = ValueId(2); + let value2_id = ValueId(3); + let result_id = ValueId(4); + + let statements = vec![ + Statement::Let { + bindings: vec![offset_id], + value: Expression::Literal { + value: BigUint::from(64u32), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::Let { + bindings: vec![value1_id], + value: Expression::Literal { + value: BigUint::from(1u32), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::Let { + bindings: vec![value2_id], + value: Expression::Literal { + value: BigUint::from(2u32), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::MStore { + offset: Value { + id: offset_id, + value_type: Type::Int(BitWidth::I256), + }, + value: Value { + id: value1_id, + value_type: Type::Int(BitWidth::I256), + }, + region: MemoryRegion::Unknown, + }, + Statement::Let { + bindings: vec![result_id], + value: Expression::MLoad { + offset: Value { + id: offset_id, + value_type: Type::Int(BitWidth::I256), + }, + region: MemoryRegion::Unknown, + }, + }, + Statement::MStore { + offset: Value { + id: offset_id, + value_type: Type::Int(BitWidth::I256), + }, + value: Value { + id: value2_id, + value_type: Type::Int(BitWidth::I256), + }, + region: MemoryRegion::Unknown, + }, + ]; + + let mut object = Object { + name: "test".to_string(), + code: Block { statements }, + functions: BTreeMap::new(), + subobjects: vec![], + data: BTreeMap::new(), + }; + + let statistics = opt.optimize_object(&mut object); + + assert_eq!(statistics.stores_eliminated, 0); + + assert_eq!(statistics.loads_eliminated, 1); + + assert_eq!(object.code.statements.len(), 6); + } + + #[test] + fn test_fmp_propagation_basic() { + use crate::ir::{MemoryRegion, Object}; + use num::BigUint; + + let v1 = make_value(1); + let v2 = make_value(2); + let v3_id = ValueId(3); + + let statements = vec![ + Statement::Let { + bindings: vec![ValueId(1)], + value: Expression::Literal { + value: BigUint::from(0x80u64), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::Let { + bindings: vec![ValueId(2)], + value: Expression::Literal { + value: BigUint::from(0x40u64), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::MStore { + offset: v2, + value: v1, + region: MemoryRegion::FreePointerSlot, + }, + Statement::Let { + bindings: vec![v3_id], + value: Expression::MLoad { + offset: v2, + region: MemoryRegion::FreePointerSlot, + }, + }, + ]; + + let mut object = Object { + name: "test".to_string(), + code: Block { statements }, + functions: std::collections::BTreeMap::new(), + subobjects: vec![], + data: std::collections::BTreeMap::new(), + }; + + let mut fmp = FmpPropagation::new(0); + fmp.propagate_object(&mut object); + + assert_eq!(fmp.loads_eliminated, 1, "Should eliminate 1 FMP load"); + + if let Statement::Let { value, .. } = &object.code.statements[3] { + match value { + Expression::Literal { value: v, .. } => { + assert_eq!(*v, BigUint::from(0x80u64), "FMP should be 0x80"); + } + other => panic!("Expected Literal, got {:?}", other), + } + } else { + panic!("Expected Let statement"); + } + } + + /// `is_free_pointer_slot` must keep both detection signals: the + /// `FreePointerSlot` region tag is the only thing that identifies an FMP + /// access whose offset a pass cannot fold back to a constant. + /// + /// Here the offset value (id 9) is never bound to a literal, so + /// `resolve_offset` returns `None`. Detection relies solely on the region + /// tag. If that signal were dropped, the unresolved-offset store would + /// invalidate the tracked FMP and the load would not be eliminated. + #[test] + fn test_fmp_eliminated_via_region_tag_with_unresolvable_offset() { + use crate::ir::{MemoryRegion, Object}; + use num::BigUint; + + let stored_value = make_value(1); + let unresolvable_offset = make_value(9); + let load_result = ValueId(3); + + let statements = vec![ + Statement::Let { + bindings: vec![ValueId(1)], + value: Expression::Literal { + value: BigUint::from(0x80u64), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::MStore { + offset: unresolvable_offset, + value: stored_value, + region: MemoryRegion::FreePointerSlot, + }, + Statement::Let { + bindings: vec![load_result], + value: Expression::MLoad { + offset: unresolvable_offset, + region: MemoryRegion::FreePointerSlot, + }, + }, + ]; + + let mut object = Object { + name: "test".to_string(), + code: Block { statements }, + functions: std::collections::BTreeMap::new(), + subobjects: vec![], + data: std::collections::BTreeMap::new(), + }; + + let mut fmp = FmpPropagation::new(0); + fmp.propagate_object(&mut object); + + assert_eq!( + fmp.loads_eliminated, 1, + "region tag must detect the FMP load when the offset cannot be resolved" + ); + } + + /// `is_free_pointer_slot` must keep both detection signals: the + /// resolved-offset check is the only thing that identifies an FMP access + /// whose offset was computed (and so could not be classified by + /// `MemoryRegion::from_address` at translation time). + /// + /// Here the offset is computed as `0x20 + 0x20`, folds to `0x40`, and is + /// tagged `Unknown`. Detection relies solely on the resolved offset. If + /// that signal were dropped, neither the store nor the load would be + /// recognised as FMP accesses. + #[test] + fn test_fmp_eliminated_via_resolved_offset_when_region_untagged() { + use crate::ir::{BinaryOperation, MemoryRegion, Object}; + use num::BigUint; + + let stored_value = make_value(1); + let half_offset = make_value(2); + let computed_offset = make_value(3); + let load_result = ValueId(4); + + let statements = vec![ + Statement::Let { + bindings: vec![ValueId(1)], + value: Expression::Literal { + value: BigUint::from(0x80u64), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::Let { + bindings: vec![ValueId(2)], + value: Expression::Literal { + value: BigUint::from(0x20u64), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::Let { + bindings: vec![ValueId(3)], + value: Expression::Binary { + operation: BinaryOperation::Add, + lhs: half_offset, + rhs: half_offset, + }, + }, + Statement::MStore { + offset: computed_offset, + value: stored_value, + region: MemoryRegion::Unknown, + }, + Statement::Let { + bindings: vec![load_result], + value: Expression::MLoad { + offset: computed_offset, + region: MemoryRegion::Unknown, + }, + }, + ]; + + let mut object = Object { + name: "test".to_string(), + code: Block { statements }, + functions: std::collections::BTreeMap::new(), + subobjects: vec![], + data: std::collections::BTreeMap::new(), + }; + + let mut fmp = FmpPropagation::new(0); + fmp.propagate_object(&mut object); + + assert_eq!( + fmp.loads_eliminated, 1, + "resolved offset must detect the FMP load when the region is untagged" + ); + } +} diff --git a/crates/newyork/src/printer.rs b/crates/newyork/src/printer.rs new file mode 100644 index 000000000..60e2668b6 --- /dev/null +++ b/crates/newyork/src/printer.rs @@ -0,0 +1,1654 @@ +//! Pretty printer for the newyork IR. +//! +//! Outputs Yul-like syntax for debugging and inspection. The output is not +//! valid Yul but is designed to be human-readable and clearly show the SSA +//! structure with explicit value IDs. +//! +//! # Example Output +//! +//! ```text +//! object "Test" { +//! code { +//! let v0 := 0x00 +//! let v1 := calldataload(v0) +//! mstore(v0, v1) +//! } +//! +//! function add_one(v2: i256) -> (v3: i256) { +//! let v4 := 0x01 +//! let v3 := add(v2, v4) +//! } +//! } +//! ``` +//! +//! When type-inference results are attached via [`Printer::set_type_info`], +//! value ids whose inferred width is narrower than the i256 default are +//! annotated with that width, e.g. `let v4: i64 := 0x01`. Without inference, +//! bindings carry no annotation because they store no type of their own. + +use crate::ir::{ + AddressSpace, BinaryOperation, BitWidth, Block, CallKind, CreateKind, Expression, Function, + FunctionId, MemoryRegion, Object, Region, Statement, SwitchCase, Type, UnaryOperation, Value, + ValueId, +}; +use crate::type_inference::TypeInference; +use std::collections::BTreeMap; +use std::fmt::{self, Write}; + +/// Configuration for the IR printer. +#[derive(Clone, Debug)] +pub struct PrinterConfig { + /// Number of spaces per indentation level. + pub indent_size: usize, + /// Whether to print type annotations. + pub show_types: bool, + /// Whether to print memory region annotations. + pub show_regions: bool, + /// Whether to print static slot annotations for storage operations. + pub show_static_slots: bool, +} + +impl Default for PrinterConfig { + fn default() -> Self { + PrinterConfig { + indent_size: 4, + show_types: true, + show_regions: true, + show_static_slots: true, + } + } +} + +/// Pretty printer for newyork IR. +pub struct Printer<'a> { + config: PrinterConfig, + /// Output buffer. + output: String, + /// Current indentation level. + indent: usize, + /// Function name lookup for printing calls. + function_names: BTreeMap, + /// Optional type-inference results. When present, value ids are annotated + /// with their post-narrow effective width instead of the statically + /// assigned i256 default stored in the IR. + inferred_types: Option<&'a TypeInference>, +} + +impl<'a> Printer<'a> { + /// Creates a new printer with default configuration. + pub fn new() -> Self { + Printer { + config: PrinterConfig::default(), + output: String::new(), + indent: 0, + function_names: BTreeMap::new(), + inferred_types: None, + } + } + + /// Creates a new printer with the given configuration. + pub fn with_config(config: PrinterConfig) -> Self { + Printer { + config, + output: String::new(), + indent: 0, + function_names: BTreeMap::new(), + inferred_types: None, + } + } + + /// Attaches type-inference results so value annotations reflect the + /// post-narrow effective widths computed by the type-inference pass rather + /// than the statically assigned i256 defaults stored in the IR. + pub fn set_type_info(&mut self, type_info: &'a TypeInference) { + self.inferred_types = Some(type_info); + } + + /// Prints an IR object and returns the formatted string. + pub fn print_object(&mut self, object: &'a Object) -> String { + self.output.clear(); + self.indent = 0; + self.function_names.clear(); + self.write_object(object); + std::mem::take(&mut self.output) + } + + /// Prints an IR function and returns the formatted string. + pub fn print_function(&mut self, function: &'a Function) -> String { + self.output.clear(); + self.indent = 0; + self.write_function(function); + std::mem::take(&mut self.output) + } + + /// Prints an IR statement and returns the formatted string. + pub fn print_statement(&mut self, statement: &Statement) -> String { + self.output.clear(); + self.indent = 0; + self.write_statement(statement); + std::mem::take(&mut self.output) + } + + /// Prints an IR expression and returns the formatted string. + pub fn print_expression(&mut self, expression: &Expression) -> String { + self.output.clear(); + self.write_expression(expression); + std::mem::take(&mut self.output) + } + + fn write_indent(&mut self) { + for _ in 0..self.indent * self.config.indent_size { + self.output.push(' '); + } + } + + fn write_newline(&mut self) { + self.output.push('\n'); + } + + fn write_object(&mut self, object: &'a Object) { + // FunctionIds are per-object (see ir::FunctionId docs); swap in this + // object's name table for the duration of the walk and restore on exit + // so subobjects don't print the parent's names or fall through to + // `func_` on collisions. + let saved_function_names = std::mem::take(&mut self.function_names); + for (id, function) in &object.functions { + self.function_names.insert(*id, &function.name); + } + + self.write_indent(); + let _ = write!(self.output, "object \"{}\" {{", object.name); + self.write_newline(); + + self.indent += 1; + + self.write_indent(); + self.output.push_str("code {"); + self.write_newline(); + + self.indent += 1; + self.write_block(&object.code); + self.indent -= 1; + + self.write_indent(); + self.output.push('}'); + self.write_newline(); + + for function in object.functions.values() { + self.write_newline(); + self.write_function(function); + } + + for (name, data) in &object.data { + self.write_newline(); + self.write_indent(); + let _ = write!(self.output, "data \"{}\" hex\"", name); + for byte in data { + let _ = write!(self.output, "{:02x}", byte); + } + self.output.push('"'); + self.write_newline(); + } + + for (index, subobject) in object.subobjects.iter().enumerate() { + self.write_newline(); + // Subobjects have their own ValueId namespace and a matching + // `TypeInference` in `sub_inferences` (same order as `subobjects`, + // mirroring codegen). Swap to the child's inference for the duration + // of the walk so subobject value ids aren't looked up in the parent + // map — where they'd be absent and default to i1. Restore on exit. + let saved_inferred_types = self.inferred_types; + self.inferred_types = self + .inferred_types + .and_then(|inference| inference.sub_inferences.get(index)); + self.write_object(subobject); + self.inferred_types = saved_inferred_types; + } + + self.indent -= 1; + self.write_indent(); + self.output.push('}'); + self.write_newline(); + + self.function_names = saved_function_names; + } + + fn write_function(&mut self, function: &Function) { + self.write_indent(); + let _ = write!(self.output, "function {}(", function.name); + + for (i, (id, value_type)) in function.parameters.iter().enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.write_value_id(*id); + if self.config.show_types { + self.output.push_str(": "); + self.write_type(*value_type); + } + } + self.output.push(')'); + + if !function.returns.is_empty() { + self.output.push_str(" -> ("); + for (i, (id, value_type)) in function + .return_values_initial + .iter() + .zip(function.returns.iter()) + .enumerate() + { + if i > 0 { + self.output.push_str(", "); + } + self.write_value_id(*id); + if self.config.show_types { + self.output.push_str(": "); + self.write_type(*value_type); + } + } + self.output.push(')'); + } + + if function.call_count > 0 || function.size_estimate > 0 { + let _ = write!( + self.output, + " /* calls: {}, size: {} */", + function.call_count, function.size_estimate + ); + } + + self.output.push_str(" {"); + self.write_newline(); + + self.indent += 1; + self.write_block(&function.body); + + if function.return_values != function.return_values_initial { + self.write_indent(); + self.output.push_str("// final return values: "); + for (i, id) in function.return_values.iter().enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.write_value_id(*id); + } + self.write_newline(); + } + self.indent -= 1; + + self.write_indent(); + self.output.push('}'); + self.write_newline(); + } + + fn write_block(&mut self, block: &Block) { + for statement in &block.statements { + self.write_statement(statement); + } + } + + fn write_region(&mut self, region: &Region) { + for statement in ®ion.statements { + self.write_statement(statement); + } + if !region.yields.is_empty() { + self.write_indent(); + self.output.push_str("yield "); + for (i, value) in region.yields.iter().enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.write_value(value); + } + self.write_newline(); + } + } + + fn write_statement(&mut self, statement: &Statement) { + match statement { + Statement::Let { bindings, value } => { + self.write_indent(); + self.output.push_str("let "); + for (i, id) in bindings.iter().enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.write_binding_id(*id); + } + self.output.push_str(" := "); + self.write_expression(value); + self.write_newline(); + } + + Statement::MStore { + offset, + value, + region, + } => { + self.write_indent(); + self.output.push_str("mstore("); + self.write_value(offset); + self.output.push_str(", "); + self.write_value(value); + self.output.push(')'); + if self.config.show_regions && *region != MemoryRegion::Unknown { + let _ = write!(self.output, " /* {} */", self.region_name(*region)); + } + self.write_newline(); + } + + Statement::MStore8 { + offset, + value, + region, + } => { + self.write_indent(); + self.output.push_str("mstore8("); + self.write_value(offset); + self.output.push_str(", "); + self.write_value(value); + self.output.push(')'); + if self.config.show_regions && *region != MemoryRegion::Unknown { + let _ = write!(self.output, " /* {} */", self.region_name(*region)); + } + self.write_newline(); + } + + Statement::MCopy { dest, src, length } => { + self.write_indent(); + self.output.push_str("mcopy("); + self.write_value(dest); + self.output.push_str(", "); + self.write_value(src); + self.output.push_str(", "); + self.write_value(length); + self.output.push(')'); + self.write_newline(); + } + + Statement::SStore { + key, + value, + static_slot, + } => { + self.write_indent(); + self.output.push_str("sstore("); + self.write_value(key); + self.output.push_str(", "); + self.write_value(value); + self.output.push(')'); + if self.config.show_static_slots { + if let Some(slot) = static_slot { + let _ = write!(self.output, " /* slot: 0x{:x} */", slot); + } + } + self.write_newline(); + } + + Statement::TStore { key, value } => { + self.write_indent(); + self.output.push_str("tstore("); + self.write_value(key); + self.output.push_str(", "); + self.write_value(value); + self.output.push(')'); + self.write_newline(); + } + + Statement::MappingSStore { key, slot, value } => { + self.write_indent(); + self.output.push_str("mapping_sstore("); + self.write_value(key); + self.output.push_str(", "); + self.write_value(slot); + self.output.push_str(", "); + self.write_value(value); + self.output.push(')'); + self.write_newline(); + } + + Statement::If { + condition, + inputs, + then_region, + else_region, + outputs, + } => { + self.write_indent(); + + if !outputs.is_empty() { + self.output.push_str("let "); + for (i, id) in outputs.iter().enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.write_value_id(*id); + } + self.output.push_str(" := "); + } + + self.output.push_str("if "); + self.write_value(condition); + + if !inputs.is_empty() { + self.output.push_str(" ["); + for (i, v) in inputs.iter().enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.write_value(v); + } + self.output.push(']'); + } + + self.output.push_str(" {"); + self.write_newline(); + + self.indent += 1; + self.write_region(then_region); + self.indent -= 1; + + self.write_indent(); + self.output.push('}'); + + if let Some(else_region) = else_region { + self.output.push_str(" else {"); + self.write_newline(); + + self.indent += 1; + self.write_region(else_region); + self.indent -= 1; + + self.write_indent(); + self.output.push('}'); + } + self.write_newline(); + } + + Statement::Switch { + scrutinee, + inputs, + cases, + default, + outputs, + } => { + self.write_indent(); + + if !outputs.is_empty() { + self.output.push_str("let "); + for (i, id) in outputs.iter().enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.write_value_id(*id); + } + self.output.push_str(" := "); + } + + self.output.push_str("switch "); + self.write_value(scrutinee); + + if !inputs.is_empty() { + self.output.push_str(" ["); + for (i, v) in inputs.iter().enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.write_value(v); + } + self.output.push(']'); + } + self.write_newline(); + + for case in cases { + self.write_switch_case(case); + } + + if let Some(default_region) = default { + self.write_indent(); + self.output.push_str("default {"); + self.write_newline(); + + self.indent += 1; + self.write_region(default_region); + self.indent -= 1; + + self.write_indent(); + self.output.push('}'); + self.write_newline(); + } + } + + Statement::For { + initial_values, + loop_variables, + condition_statements, + condition, + body, + post_input_variables, + post, + outputs, + } => { + self.write_indent(); + + if !outputs.is_empty() { + self.output.push_str("let "); + for (i, id) in outputs.iter().enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.write_value_id(*id); + } + self.output.push_str(" := "); + } + + self.output.push_str("for { "); + + for (i, (init, variable)) in + initial_values.iter().zip(loop_variables.iter()).enumerate() + { + if i > 0 { + self.output.push_str(", "); + } + self.write_value_id(*variable); + self.output.push_str(" := "); + self.write_value(init); + } + + self.output.push_str(" }"); + self.write_newline(); + + // Everything that makes up the loop is indented one level under + // the `for` header so the condition, post and body blocks line + // up and their braces match. + self.indent += 1; + + if !condition_statements.is_empty() { + self.write_indent(); + self.output.push_str("// condition statements:"); + self.write_newline(); + for statement in condition_statements { + self.write_statement(statement); + } + } + + self.write_indent(); + self.output.push_str("condition: "); + self.write_expression(condition); + self.write_newline(); + + self.write_indent(); + self.output.push_str("post"); + if !post_input_variables.is_empty() { + self.output.push_str(" ("); + for (i, id) in post_input_variables.iter().enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.write_value_id(*id); + } + self.output.push(')'); + } + self.output.push_str(" {"); + self.write_newline(); + self.indent += 1; + self.write_region(post); + self.indent -= 1; + self.write_indent(); + self.output.push('}'); + self.write_newline(); + + self.write_indent(); + self.output.push_str("body {"); + self.write_newline(); + self.indent += 1; + self.write_region(body); + self.indent -= 1; + self.write_indent(); + self.output.push('}'); + self.write_newline(); + + self.indent -= 1; + } + + Statement::Break { .. } => { + self.write_indent(); + self.output.push_str("break"); + self.write_newline(); + } + + Statement::Continue { .. } => { + self.write_indent(); + self.output.push_str("continue"); + self.write_newline(); + } + + Statement::Leave { return_values } => { + self.write_indent(); + self.output.push_str("leave"); + if !return_values.is_empty() { + self.output.push_str(" ["); + for (i, v) in return_values.iter().enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.write_value(v); + } + self.output.push(']'); + } + self.write_newline(); + } + + Statement::Revert { offset, length } => { + self.write_indent(); + self.output.push_str("revert("); + self.write_value(offset); + self.output.push_str(", "); + self.write_value(length); + self.output.push(')'); + self.write_newline(); + } + + Statement::Return { offset, length } => { + self.write_indent(); + self.output.push_str("return("); + self.write_value(offset); + self.output.push_str(", "); + self.write_value(length); + self.output.push(')'); + self.write_newline(); + } + + Statement::Stop => { + self.write_indent(); + self.output.push_str("stop()"); + self.write_newline(); + } + + Statement::Invalid => { + self.write_indent(); + self.output.push_str("invalid()"); + self.write_newline(); + } + + Statement::PanicRevert { code } => { + self.write_indent(); + self.output.push_str(&format!("panic_revert(0x{code:02x})")); + self.write_newline(); + } + + Statement::ErrorStringRevert { length, data } => { + self.write_indent(); + self.output.push_str(&format!( + "error_string_revert({length}, {}_words)", + data.len() + )); + self.write_newline(); + } + + Statement::CustomErrorRevert { + selector, + arguments, + } => { + self.write_indent(); + let _ = write!( + self.output, + "custom_error_revert(0x{}, [", + selector.to_str_radix(16) + ); + for (i, argument) in arguments.iter().enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.write_value(argument); + } + self.output.push_str("])"); + self.write_newline(); + } + + Statement::SelfDestruct { address } => { + self.write_indent(); + self.output.push_str("selfdestruct("); + self.write_value(address); + self.output.push(')'); + self.write_newline(); + } + + Statement::ExternalCall { + kind, + gas, + address, + value, + args_offset, + args_length, + ret_offset, + ret_length, + result, + } => { + self.write_indent(); + self.output.push_str("let "); + self.write_value_id(*result); + self.output.push_str(" := "); + + let call_name = match kind { + CallKind::Call => "call", + CallKind::CallCode => "callcode", + CallKind::DelegateCall => "delegatecall", + CallKind::StaticCall => "staticcall", + }; + self.output.push_str(call_name); + self.output.push('('); + self.write_value(gas); + self.output.push_str(", "); + self.write_value(address); + if let Some(value) = value { + self.output.push_str(", "); + self.write_value(value); + } + self.output.push_str(", "); + self.write_value(args_offset); + self.output.push_str(", "); + self.write_value(args_length); + self.output.push_str(", "); + self.write_value(ret_offset); + self.output.push_str(", "); + self.write_value(ret_length); + self.output.push(')'); + self.write_newline(); + } + + Statement::Create { + kind, + value, + offset, + length, + salt, + result, + } => { + self.write_indent(); + self.output.push_str("let "); + self.write_value_id(*result); + self.output.push_str(" := "); + + match kind { + CreateKind::Create => self.output.push_str("create("), + CreateKind::Create2 => self.output.push_str("create2("), + } + self.write_value(value); + self.output.push_str(", "); + self.write_value(offset); + self.output.push_str(", "); + self.write_value(length); + if let Some(s) = salt { + self.output.push_str(", "); + self.write_value(s); + } + self.output.push(')'); + self.write_newline(); + } + + Statement::Log { + offset, + length, + topics, + } => { + self.write_indent(); + let _ = write!(self.output, "log{}(", topics.len()); + self.write_value(offset); + self.output.push_str(", "); + self.write_value(length); + for topic in topics { + self.output.push_str(", "); + self.write_value(topic); + } + self.output.push(')'); + self.write_newline(); + } + + Statement::CodeCopy { + dest, + offset, + length, + } => { + self.write_indent(); + self.output.push_str("codecopy("); + self.write_value(dest); + self.output.push_str(", "); + self.write_value(offset); + self.output.push_str(", "); + self.write_value(length); + self.output.push(')'); + self.write_newline(); + } + + Statement::ExtCodeCopy { + address, + dest, + offset, + length, + } => { + self.write_indent(); + self.output.push_str("extcodecopy("); + self.write_value(address); + self.output.push_str(", "); + self.write_value(dest); + self.output.push_str(", "); + self.write_value(offset); + self.output.push_str(", "); + self.write_value(length); + self.output.push(')'); + self.write_newline(); + } + + Statement::ReturnDataCopy { + dest, + offset, + length, + } => { + self.write_indent(); + self.output.push_str("returndatacopy("); + self.write_value(dest); + self.output.push_str(", "); + self.write_value(offset); + self.output.push_str(", "); + self.write_value(length); + self.output.push(')'); + self.write_newline(); + } + + Statement::DataCopy { + dest, + offset, + length, + } => { + self.write_indent(); + self.output.push_str("datacopy("); + self.write_value(dest); + self.output.push_str(", "); + self.write_value(offset); + self.output.push_str(", "); + self.write_value(length); + self.output.push(')'); + self.write_newline(); + } + + Statement::CallDataCopy { + dest, + offset, + length, + } => { + self.write_indent(); + self.output.push_str("calldatacopy("); + self.write_value(dest); + self.output.push_str(", "); + self.write_value(offset); + self.output.push_str(", "); + self.write_value(length); + self.output.push(')'); + self.write_newline(); + } + + Statement::Block(region) => { + self.write_indent(); + self.output.push('{'); + self.write_newline(); + + self.indent += 1; + self.write_region(region); + self.indent -= 1; + + self.write_indent(); + self.output.push('}'); + self.write_newline(); + } + + Statement::Expression(expression) => { + self.write_indent(); + self.write_expression(expression); + self.write_newline(); + } + + Statement::SetImmutable { key, value } => { + self.write_indent(); + let _ = write!(self.output, "setimmutable(\"{}\", ", key); + self.write_value(value); + self.output.push(')'); + self.write_newline(); + } + } + } + + fn write_switch_case(&mut self, case: &SwitchCase) { + self.write_indent(); + let _ = write!(self.output, "case 0x{:x} {{", case.value); + self.write_newline(); + + self.indent += 1; + self.write_region(&case.body); + self.indent -= 1; + + self.write_indent(); + self.output.push('}'); + self.write_newline(); + } + + fn write_expression(&mut self, expression: &Expression) { + match expression { + Expression::Literal { value, value_type } => { + let _ = write!(self.output, "0x{:x}", value); + if self.config.show_types && *value_type != Type::Int(BitWidth::I256) { + self.output.push_str(": "); + self.write_type(*value_type); + } + } + + Expression::Var(id) => { + self.write_value_id(*id); + } + + Expression::Binary { + operation, + lhs, + rhs, + } => { + self.output.push_str(self.binop_name(*operation)); + self.output.push('('); + self.write_value(lhs); + self.output.push_str(", "); + self.write_value(rhs); + self.output.push(')'); + } + + Expression::Ternary { operation, a, b, n } => { + self.output.push_str(self.binop_name(*operation)); + self.output.push('('); + self.write_value(a); + self.output.push_str(", "); + self.write_value(b); + self.output.push_str(", "); + self.write_value(n); + self.output.push(')'); + } + + Expression::Unary { operation, operand } => { + let name = match operation { + UnaryOperation::IsZero => "iszero", + UnaryOperation::Not => "not", + UnaryOperation::Clz => "clz", + }; + self.output.push_str(name); + self.output.push('('); + self.write_value(operand); + self.output.push(')'); + } + + Expression::CallDataLoad { offset } => { + self.output.push_str("calldataload("); + self.write_value(offset); + self.output.push(')'); + } + + Expression::CallValue => self.output.push_str("callvalue()"), + Expression::Caller => self.output.push_str("caller()"), + Expression::Origin => self.output.push_str("origin()"), + Expression::CallDataSize => self.output.push_str("calldatasize()"), + Expression::CodeSize => self.output.push_str("codesize()"), + Expression::GasPrice => self.output.push_str("gasprice()"), + + Expression::ExtCodeSize { address } => { + self.output.push_str("extcodesize("); + self.write_value(address); + self.output.push(')'); + } + + Expression::ReturnDataSize => self.output.push_str("returndatasize()"), + + Expression::ExtCodeHash { address } => { + self.output.push_str("extcodehash("); + self.write_value(address); + self.output.push(')'); + } + + Expression::BlockHash { number } => { + self.output.push_str("blockhash("); + self.write_value(number); + self.output.push(')'); + } + + Expression::Coinbase => self.output.push_str("coinbase()"), + Expression::Timestamp => self.output.push_str("timestamp()"), + Expression::Number => self.output.push_str("number()"), + Expression::Difficulty => self.output.push_str("difficulty()"), + Expression::GasLimit => self.output.push_str("gaslimit()"), + Expression::ChainId => self.output.push_str("chainid()"), + Expression::SelfBalance => self.output.push_str("selfbalance()"), + Expression::BaseFee => self.output.push_str("basefee()"), + + Expression::BlobHash { index } => { + self.output.push_str("blobhash("); + self.write_value(index); + self.output.push(')'); + } + + Expression::BlobBaseFee => self.output.push_str("blobbasefee()"), + Expression::Gas => self.output.push_str("gas()"), + Expression::MSize => self.output.push_str("msize()"), + Expression::Address => self.output.push_str("address()"), + + Expression::Balance { address } => { + self.output.push_str("balance("); + self.write_value(address); + self.output.push(')'); + } + + Expression::MLoad { offset, region } => { + self.output.push_str("mload("); + self.write_value(offset); + self.output.push(')'); + if self.config.show_regions && *region != MemoryRegion::Unknown { + let _ = write!(self.output, " /* {} */", self.region_name(*region)); + } + } + + Expression::SLoad { key, static_slot } => { + self.output.push_str("sload("); + self.write_value(key); + self.output.push(')'); + if self.config.show_static_slots { + if let Some(slot) = static_slot { + let _ = write!(self.output, " /* slot: 0x{:x} */", slot); + } + } + } + + Expression::TLoad { key } => { + self.output.push_str("tload("); + self.write_value(key); + self.output.push(')'); + } + + Expression::Call { + function, + arguments, + } => { + if let Some(name) = self.function_names.get(function) { + self.output.push_str(name); + } else { + let _ = write!(self.output, "func_{}", function.0); + } + self.output.push('('); + for (i, argument) in arguments.iter().enumerate() { + if i > 0 { + self.output.push_str(", "); + } + self.write_value(argument); + } + self.output.push(')'); + } + + Expression::Truncate { value, to } => { + let _ = write!(self.output, "truncate", to.bits()); + self.output.push('('); + self.write_value(value); + self.output.push(')'); + } + + Expression::ZeroExtend { value, to } => { + let _ = write!(self.output, "zext", to.bits()); + self.output.push('('); + self.write_value(value); + self.output.push(')'); + } + + Expression::SignExtendTo { value, to } => { + let _ = write!(self.output, "sext", to.bits()); + self.output.push('('); + self.write_value(value); + self.output.push(')'); + } + + Expression::Keccak256 { offset, length } => { + self.output.push_str("keccak256("); + self.write_value(offset); + self.output.push_str(", "); + self.write_value(length); + self.output.push(')'); + } + + Expression::Keccak256Pair { word0, word1 } => { + self.output.push_str("keccak256_pair("); + self.write_value(word0); + self.output.push_str(", "); + self.write_value(word1); + self.output.push(')'); + } + + Expression::Keccak256Single { word0 } => { + self.output.push_str("keccak256_single("); + self.write_value(word0); + self.output.push(')'); + } + + Expression::MappingSLoad { key, slot } => { + self.output.push_str("mapping_sload("); + self.write_value(key); + self.output.push_str(", "); + self.write_value(slot); + self.output.push(')'); + } + + Expression::DataOffset { id } => { + let _ = write!(self.output, "dataoffset(\"{}\")", id); + } + + Expression::DataSize { id } => { + let _ = write!(self.output, "datasize(\"{}\")", id); + } + + Expression::LoadImmutable { key } => { + let _ = write!(self.output, "loadimmutable(\"{}\")", key); + } + + Expression::LinkerSymbol { path } => { + let _ = write!(self.output, "linkersymbol(\"{}\")", path); + } + } + } + + fn write_value(&mut self, value: &Value) { + self.write_value_id(value.id); + if !self.config.show_types { + return; + } + // Pointers and void are never narrowed by type inference, so keep the + // statically assigned type. For integers, prefer the post-narrow + // effective width when inference is attached; otherwise fall back to the + // static type. The default i256 width is suppressed to reduce noise. + let display_type = match (self.inferred_types, value.value_type) { + (Some(inference), Type::Int(_)) => Type::Int(inference.effective_width(value.id)), + _ => value.value_type, + }; + if display_type != Type::Int(BitWidth::I256) { + self.output.push_str(": "); + self.write_type(display_type); + } + } + + /// Writes a binding value id, annotating it with the inferred effective + /// width when type-inference results are attached. Bindings carry no static + /// type of their own, so without inference no annotation is printed. + fn write_binding_id(&mut self, id: ValueId) { + self.write_value_id(id); + if !self.config.show_types { + return; + } + if let Some(inference) = self.inferred_types { + let width = inference.effective_width(id); + if width != BitWidth::I256 { + self.output.push_str(": "); + self.write_type(Type::Int(width)); + } + } + } + + fn write_value_id(&mut self, id: ValueId) { + let _ = write!(self.output, "v{}", id.0); + } + + fn write_type(&mut self, value_type: Type) { + match value_type { + Type::Int(w) => { + let _ = write!(self.output, "i{}", w.bits()); + } + Type::Ptr(space) => { + let space_name = match space { + AddressSpace::Heap => "heap", + AddressSpace::Stack => "stack", + AddressSpace::Storage => "storage", + AddressSpace::Code => "code", + }; + let _ = write!(self.output, "ptr<{}>", space_name); + } + Type::Void => { + self.output.push_str("void"); + } + } + } + + fn binop_name(&self, operation: BinaryOperation) -> &'static str { + match operation { + BinaryOperation::Add => "add", + BinaryOperation::Sub => "sub", + BinaryOperation::Mul => "mul", + BinaryOperation::Div => "div", + BinaryOperation::SDiv => "sdiv", + BinaryOperation::Mod => "mod", + BinaryOperation::SMod => "smod", + BinaryOperation::Exp => "exp", + BinaryOperation::AddMod => "addmod", + BinaryOperation::MulMod => "mulmod", + BinaryOperation::And => "and", + BinaryOperation::Or => "or", + BinaryOperation::Xor => "xor", + BinaryOperation::Shl => "shl", + BinaryOperation::Shr => "shr", + BinaryOperation::Sar => "sar", + BinaryOperation::Lt => "lt", + BinaryOperation::Gt => "gt", + BinaryOperation::Slt => "slt", + BinaryOperation::Sgt => "sgt", + BinaryOperation::Eq => "eq", + BinaryOperation::Byte => "byte", + BinaryOperation::SignExtend => "signextend", + } + } + + fn region_name(&self, region: MemoryRegion) -> &'static str { + match region { + MemoryRegion::Scratch => "scratch", + MemoryRegion::FreePointerSlot => "free_ptr", + MemoryRegion::Dynamic => "dynamic", + MemoryRegion::Unknown => "unknown", + } + } +} + +impl Default for Printer<'_> { + fn default() -> Self { + Self::new() + } +} + +/// Convenience function to print an object to a string. +pub fn print_object(object: &Object) -> String { + let mut printer = Printer::new(); + printer.print_object(object) +} + +/// Convenience function to print an object annotated with inferred type widths. +/// +/// Value ids are annotated with the post-narrow effective widths from +/// `type_info`; see [`Printer::set_type_info`]. +pub fn print_object_with_types<'a>(object: &'a Object, type_info: &'a TypeInference) -> String { + let mut printer = Printer::new(); + printer.set_type_info(type_info); + printer.print_object(object) +} + +/// Convenience function to print a function to a string. +pub fn print_function(function: &Function) -> String { + let mut printer = Printer::new(); + printer.print_function(function) +} + +/// Convenience function to print a statement to a string. +pub fn print_statement(statement: &Statement) -> String { + let mut printer = Printer::new(); + printer.print_statement(statement) +} + +/// Convenience function to print an expression to a string. +pub fn print_expression(expression: &Expression) -> String { + Printer::new().print_expression(expression) +} + +/// Implement Display for Object using the printer. +impl fmt::Display for Object { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", print_object(self)) + } +} + +/// Implement Display for Function using the printer. +impl fmt::Display for Function { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", print_function(self)) + } +} + +/// Implement Display for Statement using the printer. +impl fmt::Display for Statement { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", print_statement(self)) + } +} + +/// Implement Display for Expression using the printer. +impl fmt::Display for Expression { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", print_expression(self)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use num::BigUint; + + #[test] + fn binding_shows_inferred_narrow_width() { + use crate::type_inference::TypeInference; + + let mut object = Object::new("Test".to_string()); + object.code.statements.push(Statement::Let { + bindings: vec![ValueId(0)], + value: Expression::Literal { + value: BigUint::from(0xffu64), + value_type: Type::Int(BitWidth::I256), + }, + }); + + // Without type info the binding carries no annotation: bindings store no + // type of their own. + let plain = print_object(&object); + assert!(plain.contains("let v0 := 0xff"), "got: {plain}"); + assert!(!plain.contains("v0: i"), "got: {plain}"); + + // With inference attached, the i8 literal binding is annotated with its + // post-narrow effective width. + let mut inference = TypeInference::new(); + inference.infer_object(&object); + assert_eq!(inference.effective_width(ValueId(0)), BitWidth::I8); + let typed = print_object_with_types(&object, &inference); + assert!(typed.contains("let v0: i8 := 0xff"), "got: {typed}"); + } + + #[test] + fn subobject_bindings_use_subobject_inference() { + use crate::type_inference::TypeInference; + + // Parent and subobject both bind ValueId(0), but to literals of + // different widths. Because each object has its own ValueId namespace + // and its own inference, the subobject's v0 must be annotated from the + // subobject inference (i64), not the parent's (i8). + let mut parent = Object::new("Parent".to_string()); + parent.code.statements.push(Statement::Let { + bindings: vec![ValueId(0)], + value: Expression::Literal { + value: BigUint::from(0xffu64), + value_type: Type::Int(BitWidth::I256), + }, + }); + + let mut subobject = Object::new("Parent_deployed".to_string()); + subobject.code.statements.push(Statement::Let { + bindings: vec![ValueId(0)], + value: Expression::Literal { + value: BigUint::from(0xffffffffffffffffu64), + value_type: Type::Int(BitWidth::I256), + }, + }); + parent.subobjects.push(subobject); + + let mut inference = TypeInference::new(); + inference.infer_object_tree(&parent); + + let output = print_object_with_types(&parent, &inference); + let subobject_section = output + .split_once("object \"Parent_deployed\"") + .expect("subobject section present") + .1; + + // Parent v0 is the i8 literal; subobject v0 is the i64 literal. If the + // subobject were printed against the parent inference it would wrongly + // show i8 (or default to i1 for ids the parent never saw). + assert!( + output.contains("let v0: i8 := 0xff\n"), + "parent binding should be i8:\n{output}" + ); + assert!( + subobject_section.contains("let v0: i64 := 0xffffffffffffffff"), + "subobject binding should be i64 from its own inference:\n{subobject_section}" + ); + } + + #[test] + fn for_loop_prints_post_inputs_with_aligned_braces() { + let for_statement = Statement::For { + initial_values: vec![Value::int(ValueId(0))], + loop_variables: vec![ValueId(1)], + condition_statements: Vec::new(), + condition: Expression::Var(ValueId(1)), + body: Region::default(), + post_input_variables: vec![ValueId(2)], + post: Region::default(), + outputs: Vec::new(), + }; + + let output = print_statement(&for_statement); + + // The post-region input variables must not be dropped. + assert!( + output.contains("post (v2) {"), + "post inputs should be printed:\n{output}" + ); + // Header at column 0; condition/post/body indented one level under it, + // with matching open/close braces at that level. + assert!(output.contains("for { v1 := v0 }\n"), "got:\n{output}"); + assert!(output.contains("\n condition: v1\n"), "got:\n{output}"); + assert!( + output.contains("\n post (v2) {\n }\n"), + "got:\n{output}" + ); + assert!(output.contains("\n body {\n }\n"), "got:\n{output}"); + } + + #[test] + fn custom_error_revert_args_use_write_value() { + // Arguments must go through write_value so they pick up type-width + // annotations like every other value, rather than being hand-formatted. + let statement = Statement::CustomErrorRevert { + selector: BigUint::from(0x12345678u64), + arguments: vec![ + Value::int(ValueId(7)), + Value::new(ValueId(8), Type::Int(BitWidth::I64)), + ], + }; + let output = print_statement(&statement); + assert_eq!( + output, "custom_error_revert(0x12345678, [v7, v8: i64])\n", + "got: {output}" + ); + } + + #[test] + fn test_print_literal() { + let expression = Expression::Literal { + value: BigUint::from(42u64), + value_type: Type::Int(BitWidth::I256), + }; + let output = print_expression(&expression); + assert_eq!(output, "0x2a"); + } + + #[test] + fn test_print_binary_op() { + let expression = Expression::Binary { + operation: BinaryOperation::Add, + lhs: Value::int(ValueId(0)), + rhs: Value::int(ValueId(1)), + }; + let output = print_expression(&expression); + assert_eq!(output, "add(v0, v1)"); + } + + #[test] + fn test_print_let_statement() { + let statement = Statement::Let { + bindings: vec![ValueId(2)], + value: Expression::Binary { + operation: BinaryOperation::Add, + lhs: Value::int(ValueId(0)), + rhs: Value::int(ValueId(1)), + }, + }; + let output = print_statement(&statement); + assert_eq!(output.trim(), "let v2 := add(v0, v1)"); + } + + #[test] + fn test_print_mstore_with_region() { + let statement = Statement::MStore { + offset: Value::int(ValueId(0)), + value: Value::int(ValueId(1)), + region: MemoryRegion::Scratch, + }; + let output = print_statement(&statement); + assert!(output.contains("mstore(v0, v1)")); + assert!(output.contains("/* scratch */")); + } + + #[test] + fn test_print_function() { + let function = Function { + id: FunctionId(0), + name: "add_one".to_string(), + parameters: vec![(ValueId(0), Type::Int(BitWidth::I256))], + returns: vec![Type::Int(BitWidth::I256)], + return_values_initial: vec![ValueId(1)], + return_values: vec![ValueId(2)], + body: Block { + statements: vec![Statement::Let { + bindings: vec![ValueId(2)], + value: Expression::Binary { + operation: BinaryOperation::Add, + lhs: Value::int(ValueId(0)), + rhs: Value::new(ValueId(3), Type::Int(BitWidth::I256)), + }, + }], + }, + call_count: 1, + size_estimate: 5, + }; + let output = print_function(&function); + assert!(output.contains("function add_one")); + assert!(output.contains("v0: i256")); + assert!(output.contains("-> (v1: i256)")); + assert!(output.contains("let v2 := add(v0, v3)")); + assert!(output.contains("/* calls: 1, size: 5 */")); + } + + #[test] + fn test_subobject_function_names_are_scoped() { + // Regression test for a printer bug where subobject Call expressions + // resolved against the parent's function-name map: ids missing in the + // parent printed as `func_`, and id collisions printed the parent's + // name (e.g. `extract_byte_array_length()` from a subobject). + let parent_only = Function { + id: FunctionId(0), + name: "parent_only".to_string(), + parameters: vec![], + returns: vec![], + return_values_initial: vec![], + return_values: vec![], + body: Block { statements: vec![] }, + call_count: 1, + size_estimate: 1, + }; + let sub_collides = Function { + id: FunctionId(0), + name: "sub_collides".to_string(), + parameters: vec![], + returns: vec![], + return_values_initial: vec![], + return_values: vec![], + body: Block { statements: vec![] }, + call_count: 1, + size_estimate: 1, + }; + let sub_unique = Function { + id: FunctionId(7), + name: "sub_unique".to_string(), + parameters: vec![], + returns: vec![], + return_values_initial: vec![], + return_values: vec![], + body: Block { statements: vec![] }, + call_count: 1, + size_estimate: 1, + }; + + let call = |id| { + Statement::Expression(Expression::Call { + function: FunctionId(id), + arguments: vec![], + }) + }; + + let mut parent_functions = BTreeMap::new(); + parent_functions.insert(parent_only.id, parent_only); + let mut sub_functions = BTreeMap::new(); + sub_functions.insert(sub_collides.id, sub_collides); + sub_functions.insert(sub_unique.id, sub_unique); + + let subobject = Object { + name: "Sub".to_string(), + code: Block { + statements: vec![call(0), call(7)], + }, + functions: sub_functions, + subobjects: Vec::new(), + data: BTreeMap::new(), + }; + let object = Object { + name: "Parent".to_string(), + code: Block { + statements: vec![call(0)], + }, + functions: parent_functions, + subobjects: vec![subobject], + data: BTreeMap::new(), + }; + + let output = print_object(&object); + + let parent_header = output.find("object \"Parent\"").unwrap(); + let sub_header = output.find("object \"Sub\"").unwrap(); + let (parent_section, sub_section) = output.split_at(sub_header); + let parent_section = &parent_section[parent_header..]; + + assert!( + parent_section.contains("parent_only()"), + "parent should resolve its own FunctionId(0):\n{parent_section}", + ); + assert!( + sub_section.contains("sub_collides()"), + "subobject's FunctionId(0) should print as sub_collides, not parent_only:\n{sub_section}", + ); + assert!( + sub_section.contains("sub_unique()"), + "subobject's FunctionId(7) should resolve via the subobject map, not fall through to func_7:\n{sub_section}", + ); + assert!( + !sub_section.contains("parent_only"), + "parent_only must not leak into subobject output:\n{sub_section}", + ); + assert!( + !sub_section.contains("func_7"), + "missing-id fallback must not appear:\n{sub_section}", + ); + } + + #[test] + fn test_print_simple_object() { + let object = Object { + name: "Test".to_string(), + code: Block { + statements: vec![Statement::Let { + bindings: vec![ValueId(0)], + value: Expression::Literal { + value: BigUint::from(0u64), + value_type: Type::Int(BitWidth::I256), + }, + }], + }, + functions: BTreeMap::new(), + subobjects: Vec::new(), + data: BTreeMap::new(), + }; + let output = print_object(&object); + assert!(output.contains("object \"Test\"")); + assert!(output.contains("code {")); + assert!(output.contains("let v0 := 0x0")); + } +} diff --git a/crates/newyork/src/simplify.rs b/crates/newyork/src/simplify.rs new file mode 100644 index 000000000..76c205577 --- /dev/null +++ b/crates/newyork/src/simplify.rs @@ -0,0 +1,3855 @@ +//! IR simplification pass: constant folding, algebraic identities, copy propagation, +//! and dead code elimination. +//! +//! This pass runs after inlining to clean up the IR: +//! 1. **Constant folding**: Binary/unary ops on literals → literal result +//! 2. **Algebraic identities**: `add(x, 0) → x`, `mul(x, 1) → x`, etc. +//! 3. **Copy propagation**: `let x = y` → replace all uses of x with y +//! 4. **Dead code elimination**: Remove unused Let bindings +//! +//! All arithmetic follows EVM semantics (unsigned 256-bit, wrapping). + +use std::collections::{BTreeMap, BTreeSet}; + +use num::{BigUint, One, ToPrimitive, Zero}; + +use crate::ir::{ + for_each_statement_mut, BinaryOperation, BitWidth, Block, CallKind, Expression, FunctionId, + MemoryRegion, Object, Region, Statement, SwitchCase, Type, UnaryOperation, Value, ValueId, +}; + +/// Maximum value for 256-bit unsigned integer (2^256 - 1). +fn max_u256() -> BigUint { + (BigUint::one() << 256) - BigUint::one() +} + +/// The modulus for 256-bit wrapping arithmetic (2^256). +fn modulus_u256() -> BigUint { + BigUint::one() << 256 +} + +/// Results of the simplification pass. +#[derive(Clone, Debug, Default)] +pub struct SimplifyResults { + /// Number of expressions constant-folded. + pub constants_folded: usize, + /// Number of algebraic identity simplifications. + pub identities_simplified: usize, + /// Number of copy propagations. + pub copies_propagated: usize, + /// Number of dead Let bindings removed. + pub dead_bindings_removed: usize, + /// Number of constant branches eliminated. + pub branches_eliminated: usize, + /// Number of environment reads eliminated by CSE. + pub env_reads_eliminated: usize, +} + +/// Categories of pure environment reads that can be CSE'd. +/// +/// These are nullary expressions whose value is fixed for the duration of a +/// single contract invocation, so reads of the same kind in the same dominator +/// scope can share a binding. +/// +/// Deliberately excluded — these *look* nullary but are observably variable: +/// - `Gas`: gas remaining, decreases on every opcode. +/// - `MSize`: memory size, grows when memory expands. +/// - `ReturnDataSize`: resets after each external call. +/// - `SelfBalance`: changes when the contract sends or receives value. +/// +/// Hash expressions (`Keccak256*`) take operands and so aren't `EnvRead` +/// candidates by shape; see `HASH_CSE_NOTE.md` for the separate CSE story. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +enum EnvRead { + Address, + BaseFee, + BlobBaseFee, + CallDataSize, + CallValue, + Caller, + ChainId, + CodeSize, + Coinbase, + Difficulty, + GasLimit, + GasPrice, + Number, + Origin, + Timestamp, +} + +/// Returns the `EnvRead` kind for an expression if it is a pure environment read. +fn env_read_kind(expression: &Expression) -> Option { + match expression { + Expression::Address => Some(EnvRead::Address), + Expression::BaseFee => Some(EnvRead::BaseFee), + Expression::BlobBaseFee => Some(EnvRead::BlobBaseFee), + Expression::CallDataSize => Some(EnvRead::CallDataSize), + Expression::CallValue => Some(EnvRead::CallValue), + Expression::Caller => Some(EnvRead::Caller), + Expression::ChainId => Some(EnvRead::ChainId), + Expression::CodeSize => Some(EnvRead::CodeSize), + Expression::Coinbase => Some(EnvRead::Coinbase), + Expression::Difficulty => Some(EnvRead::Difficulty), + Expression::GasLimit => Some(EnvRead::GasLimit), + Expression::GasPrice => Some(EnvRead::GasPrice), + Expression::Number => Some(EnvRead::Number), + Expression::Origin => Some(EnvRead::Origin), + Expression::Timestamp => Some(EnvRead::Timestamp), + _ => None, + } +} + +/// IR simplification pass. +pub struct Simplifier { + /// Maps ValueId → constant BigUint for known constants. + constants: BTreeMap, + /// Maps ValueId → ValueId for copy propagation (let x = y → x maps to y). + copies: BTreeMap, + /// Maps ValueId → (UnaryOperation, operand ValueId) for unary expression tracking. + /// Used to simplify patterns like not(not(x)) → x. + unary_defs: BTreeMap, + /// Maps ValueId → (BinaryOperation, lhs ValueId, rhs ValueId) for binary + /// expression tracking. Used to simplify patterns like `sub(add(x, y), x) → y`. + binary_defs: BTreeMap, + /// Counter for fresh value IDs when creating new bindings (strength reduction). + next_value_id: ValueId, + /// CSE cache for pure environment reads (calldatasize, caller, etc.). + /// Maps the read category to the first ValueId that bound this expression. + /// Saved/restored in region scopes to ensure LLVM SSA domination correctness: + /// a binding from one branch must not be referenced from a sibling branch. + env_reads: BTreeMap, + /// Statistics. + statistics: SimplifyResults, +} + +impl Default for Simplifier { + fn default() -> Self { + Self::new() + } +} + +impl Simplifier { + /// Creates a new simplifier. + pub fn new() -> Self { + Simplifier { + constants: BTreeMap::new(), + copies: BTreeMap::new(), + unary_defs: BTreeMap::new(), + binary_defs: BTreeMap::new(), + next_value_id: ValueId(0), + env_reads: BTreeMap::new(), + statistics: SimplifyResults::default(), + } + } + + /// Allocates a fresh ValueId. + fn fresh_id(&mut self) -> ValueId { + self.next_value_id.fresh() + } + + /// Resolves the memory region for a value if its offset is a known constant. + fn resolve_region(&self, value: &Value) -> MemoryRegion { + if let Some(addr) = self.constants.get(&value.id.0) { + MemoryRegion::from_address(addr) + } else { + MemoryRegion::Unknown + } + } + + /// Simplifies an entire object in place. + pub fn simplify_object(&mut self, object: &mut Object) -> SimplifyResults { + self.next_value_id = ValueId(object.find_max_value_id() + 1); + + self.simplify_block(&mut object.code); + self.statistics.dead_bindings_removed += + eliminate_dead_code_in_stmts(&mut object.code.statements, &BTreeSet::new()); + + for function in object.functions.values_mut() { + self.constants.clear(); + self.copies.clear(); + self.unary_defs.clear(); + self.env_reads.clear(); + function.body.statements = + self.simplify_statements(std::mem::take(&mut function.body.statements)); + + let mut extra_used = BTreeSet::new(); + for ret_id in &function.return_values { + extra_used.insert(ret_id.0); + } + self.statistics.dead_bindings_removed += + eliminate_dead_code_in_stmts(&mut function.body.statements, &extra_used); + } + + std::mem::take(&mut self.statistics) + } + + /// Runs only DCE (dead code elimination) on an object without the full simplification pass. + /// + /// This is useful after late-stage passes (mem_opt, keccak folding) that leave + /// Simplifies a block in place. + fn simplify_block(&mut self, block: &mut Block) { + block.statements = self.simplify_statements(std::mem::take(&mut block.statements)); + } + + /// Simplifies a list of statements, returning the simplified list. + fn simplify_statements(&mut self, statements: Vec) -> Vec { + let outer_constants = self.constants.clone(); + let outer_copies = self.copies.clone(); + + let mut result = Vec::with_capacity(statements.len()); + + for statement in statements { + let simplified = self.simplify_statement(statement); + result.extend(simplified); + } + + result = outline_panic_patterns(result, &self.constants); + + result = outline_custom_error_patterns(result, &self.constants); + + self.constants = outer_constants; + self.copies = outer_copies; + + result + } + + /// Simplifies a single statement. + /// Returns a vec of replacement statements (empty = remove, one = replace, multiple = expand). + fn simplify_statement(&mut self, statement: Statement) -> Vec { + match statement { + Statement::Let { bindings, value } => { + let simplified_expr = self.simplify_expression(value); + + if bindings.len() == 1 { + if let Some(statements) = self.try_strength_reduce(&bindings, &simplified_expr) + { + return statements; + } + } + + if bindings.len() == 1 { + if let Expression::Literal { ref value, .. } = simplified_expr { + self.constants.insert(bindings[0].0, value.clone()); + } + if let Expression::Var(src_id) = &simplified_expr { + let resolved = self.resolve_copy(*src_id); + self.copies.insert(bindings[0].0, resolved); + if let Some(c) = self.constants.get(&resolved.0).cloned() { + self.constants.insert(bindings[0].0, c); + } + } + + if let Some(kind) = env_read_kind(&simplified_expr) { + self.env_reads.entry(kind).or_insert(bindings[0]); + } + + if let Expression::Unary { operation, operand } = &simplified_expr { + self.unary_defs + .insert(bindings[0].0, (*operation, operand.id)); + } + + if let Expression::Binary { + operation, + lhs, + rhs, + } = &simplified_expr + { + self.binary_defs + .insert(bindings[0].0, (*operation, lhs.id, rhs.id)); + } + } + + vec![Statement::Let { + bindings, + value: simplified_expr, + }] + } + + Statement::MStore { + offset, + value, + region, + } => { + let offset = self.resolve_value(offset); + let region = if region == MemoryRegion::Unknown { + self.resolve_region(&offset) + } else { + region + }; + vec![Statement::MStore { + offset, + value: self.resolve_value(value), + region, + }] + } + + Statement::MStore8 { + offset, + value, + region, + } => { + let offset = self.resolve_value(offset); + let region = if region == MemoryRegion::Unknown { + self.resolve_region(&offset) + } else { + region + }; + vec![Statement::MStore8 { + offset, + value: self.resolve_value(value), + region, + }] + } + + Statement::If { + condition, + inputs, + then_region, + else_region, + outputs, + } => { + let condition = self.resolve_value(condition); + let cond_val = self.try_get_const(&condition); + + if let Some(cond_const) = cond_val { + let is_true = !cond_const.is_zero(); + self.statistics.branches_eliminated += 1; + + if is_true { + let then_region = self.simplify_region(then_region); + let mut result = Vec::new(); + result.extend(then_region.statements); + for (output_id, yield_val) in outputs.iter().zip(then_region.yields.iter()) + { + result.push(Statement::Let { + bindings: vec![*output_id], + value: Expression::Var(yield_val.id), + }); + } + return result; + } else if let Some(else_region) = else_region { + let else_region = self.simplify_region(else_region); + let mut result = Vec::new(); + result.extend(else_region.statements); + for (output_id, yield_val) in outputs.iter().zip(else_region.yields.iter()) + { + result.push(Statement::Let { + bindings: vec![*output_id], + value: Expression::Var(yield_val.id), + }); + } + return result; + } else { + let inputs: Vec = + inputs.into_iter().map(|v| self.resolve_value(v)).collect(); + let mut result = vec![]; + for (output_id, input_val) in outputs.iter().zip(inputs.iter()) { + result.push(Statement::Let { + bindings: vec![*output_id], + value: Expression::Var(input_val.id), + }); + } + return result; + } + } + + let inputs: Vec = + inputs.into_iter().map(|v| self.resolve_value(v)).collect(); + let then_region = self.simplify_region(then_region); + let else_region = else_region.map(|r| self.simplify_region(r)); + + vec![Statement::If { + condition, + inputs, + then_region, + else_region, + outputs, + }] + } + + Statement::Switch { + scrutinee, + inputs, + cases, + default, + outputs, + } => { + let scrutinee = self.resolve_value(scrutinee); + let scrut_val = self.try_get_const(&scrutinee); + + if let Some(scrut_const) = scrut_val { + let matching_case = cases.into_iter().find(|c| c.value == scrut_const); + + let taken_region = if let Some(case) = matching_case { + self.simplify_region(case.body) + } else if let Some(default_region) = default { + self.simplify_region(default_region) + } else { + let inputs: Vec = + inputs.into_iter().map(|v| self.resolve_value(v)).collect(); + let mut result = vec![]; + for (output_id, input_val) in outputs.iter().zip(inputs.iter()) { + result.push(Statement::Let { + bindings: vec![*output_id], + value: Expression::Var(input_val.id), + }); + } + self.statistics.branches_eliminated += 1; + return result; + }; + + let mut result = Vec::new(); + result.extend(taken_region.statements); + for (output_id, yield_val) in outputs.iter().zip(taken_region.yields.iter()) { + result.push(Statement::Let { + bindings: vec![*output_id], + value: Expression::Var(yield_val.id), + }); + } + self.statistics.branches_eliminated += 1; + return result; + } + + let inputs: Vec = + inputs.into_iter().map(|v| self.resolve_value(v)).collect(); + let mut cases: Vec = cases + .into_iter() + .map(|c| SwitchCase { + value: c.value, + body: self.simplify_region(c.body), + }) + .collect(); + let mut default = default.map(|r| self.simplify_region(r)); + + let mut hoisted = Vec::new(); + if !cases.is_empty() { + let all_have_callvalue_check = cases + .iter() + .all(|c| has_callvalue_revert_prefix(&c.body.statements)) + && default.as_ref().is_none_or(|d| { + d.statements.is_empty() || has_callvalue_revert_prefix(&d.statements) + }); + + if all_have_callvalue_check { + let first_stmts = &cases[0].body.statements; + if first_stmts.len() >= 2 { + hoisted.push(first_stmts[0].clone()); + hoisted.push(first_stmts[1].clone()); + } + for case in &mut cases { + if has_callvalue_revert_prefix(&case.body.statements) { + case.body.statements.drain(0..2); + } + } + if let Some(ref mut d) = default { + if has_callvalue_revert_prefix(&d.statements) { + d.statements.drain(0..2); + } + } + } else { + const PARTIAL_HOIST_THRESHOLD: usize = 3; + let callvalue_case_count = cases + .iter() + .filter(|c| starts_with_callvalue_let(&c.body.statements)) + .count(); + let default_has_cv = default + .as_ref() + .is_some_and(|d| starts_with_callvalue_let(&d.statements)); + let total_cv = callvalue_case_count + if default_has_cv { 1 } else { 0 }; + + if total_cv >= PARTIAL_HOIST_THRESHOLD { + let hoisted_cv_id = self.fresh_id(); + hoisted.push(Statement::Let { + bindings: vec![hoisted_cv_id], + value: Expression::CallValue, + }); + for case in &mut cases { + replace_leading_callvalue_with_var( + &mut case.body.statements, + hoisted_cv_id, + ); + } + if let Some(ref mut d) = default { + replace_leading_callvalue_with_var( + &mut d.statements, + hoisted_cv_id, + ); + } + } + } + } + + hoisted.push(Statement::Switch { + scrutinee, + inputs, + cases, + default, + outputs, + }); + hoisted + } + + Statement::For { + initial_values, + loop_variables, + condition_statements, + condition, + body, + post_input_variables, + post, + outputs, + } => { + let initial_values: Vec = initial_values + .into_iter() + .map(|v| self.resolve_value(v)) + .collect(); + + let saved_constants = self.constants.clone(); + let saved_copies = self.copies.clone(); + + let condition_statements = self.simplify_statements(condition_statements); + let condition = self.simplify_expression(condition); + let body = self.simplify_region(body); + let post = self.simplify_region(post); + + self.constants = saved_constants; + self.copies = saved_copies; + + vec![Statement::For { + initial_values, + loop_variables, + condition_statements, + condition, + body, + post_input_variables, + post, + outputs, + }] + } + + Statement::Block(region) => vec![Statement::Block(self.simplify_region(region))], + + Statement::Expression(expression) => { + vec![Statement::Expression(self.simplify_expression(expression))] + } + + Statement::Stop + | Statement::Invalid + | Statement::PanicRevert { .. } + | Statement::ErrorStringRevert { .. } + | Statement::CustomErrorRevert { .. } => vec![statement], + + mut other @ (Statement::MCopy { .. } + | Statement::SStore { .. } + | Statement::TStore { .. } + | Statement::MappingSStore { .. } + | Statement::Revert { .. } + | Statement::Return { .. } + | Statement::ExternalCall { .. } + | Statement::Create { .. } + | Statement::Log { .. } + | Statement::CodeCopy { .. } + | Statement::ExtCodeCopy { .. } + | Statement::ReturnDataCopy { .. } + | Statement::DataCopy { .. } + | Statement::CallDataCopy { .. } + | Statement::SetImmutable { .. } + | Statement::Leave { .. } + | Statement::Break { .. } + | Statement::Continue { .. } + | Statement::SelfDestruct { .. }) => { + other.for_each_value_id_mut(&mut |id| *id = self.resolve_copy(*id)); + vec![other] + } + } + } + + /// Simplifies a region in place. + fn simplify_region(&mut self, region: Region) -> Region { + let outer_constants = self.constants.clone(); + let outer_copies = self.copies.clone(); + let outer_env_reads = self.env_reads.clone(); + + let mut statements = Vec::with_capacity(region.statements.len()); + for statement in region.statements { + let simplified = self.simplify_statement(statement); + statements.extend(simplified); + } + + statements = outline_panic_patterns(statements, &self.constants); + + statements = outline_custom_error_patterns(statements, &self.constants); + + let yields: Vec = region + .yields + .into_iter() + .map(|v| self.resolve_value(v)) + .collect(); + + self.constants = outer_constants; + self.copies = outer_copies; + self.env_reads = outer_env_reads; + + Region { statements, yields } + } + + /// Simplifies an expression, performing constant folding, algebraic identities, + /// and copy propagation on operands. + fn simplify_expression(&mut self, expression: Expression) -> Expression { + match expression { + Expression::Binary { + operation, + lhs, + rhs, + } => { + let lhs = self.resolve_value(lhs); + let rhs = self.resolve_value(rhs); + let lhs_val = self.try_get_const(&lhs); + let rhs_val = self.try_get_const(&rhs); + + if let (Some(a), Some(b)) = (&lhs_val, &rhs_val) { + if let Some(result) = fold_binary(operation, a, b) { + self.statistics.constants_folded += 1; + return Expression::Literal { + value: result, + value_type: result_type(operation), + }; + } + } + + if let Some(simplified) = simplify_binary(operation, &lhs, &rhs, &lhs_val, &rhs_val) + { + self.statistics.identities_simplified += 1; + return simplified; + } + + // Simplify identities that recurse through a previously-recorded + // binary definition. These come up wherever a helper computes + // `tail = base + 32` and the caller takes `length = tail - base` + // (or the symmetric forms); recognising them lets the + // return_word peephole match against Solidity's inline encode + // helper output. + if operation == BinaryOperation::Sub { + if let Some(&(lhs_op, lhs_a, lhs_b)) = self.binary_defs.get(&lhs.id.0) { + if lhs_op == BinaryOperation::Add { + let resolved_a = self.resolve_copy(lhs_a); + let resolved_b = self.resolve_copy(lhs_b); + // sub(add(a, b), a) → b + if resolved_a == rhs.id { + self.statistics.identities_simplified += 1; + return Expression::Var(resolved_b); + } + // sub(add(a, b), b) → a + if resolved_b == rhs.id { + self.statistics.identities_simplified += 1; + return Expression::Var(resolved_a); + } + } + } + } + if operation == BinaryOperation::Add { + if let Some(&(lhs_op, lhs_a, lhs_b)) = self.binary_defs.get(&lhs.id.0) { + if lhs_op == BinaryOperation::Sub { + let resolved_a = self.resolve_copy(lhs_a); + let resolved_b = self.resolve_copy(lhs_b); + // add(sub(a, b), b) → a + if resolved_b == rhs.id { + self.statistics.identities_simplified += 1; + return Expression::Var(resolved_a); + } + } + } + if let Some(&(rhs_op, rhs_a, rhs_b)) = self.binary_defs.get(&rhs.id.0) { + if rhs_op == BinaryOperation::Sub { + let resolved_a = self.resolve_copy(rhs_a); + let resolved_b = self.resolve_copy(rhs_b); + // add(b, sub(a, b)) → a + if resolved_b == lhs.id { + self.statistics.identities_simplified += 1; + return Expression::Var(resolved_a); + } + } + } + } + + Expression::Binary { + operation, + lhs, + rhs, + } + } + + Expression::Unary { operation, operand } => { + let operand = self.resolve_value(operand); + let operand_val = self.try_get_const(&operand); + + if let Some(c) = &operand_val { + if let Some(result) = fold_unary(operation, c) { + self.statistics.constants_folded += 1; + return Expression::Literal { + value: result, + value_type: unary_result_type(operation), + }; + } + } + + if operation == UnaryOperation::Not { + if let Some((UnaryOperation::Not, inner)) = self.unary_defs.get(&operand.id.0) { + self.statistics.identities_simplified += 1; + return Expression::Var(*inner); + } + } + + Expression::Unary { operation, operand } + } + + Expression::Ternary { operation, a, b, n } => { + let a = self.resolve_value(a); + let b = self.resolve_value(b); + let n = self.resolve_value(n); + let a_val = self.try_get_const(&a); + let b_val = self.try_get_const(&b); + let n_val = self.try_get_const(&n); + + if let (Some(av), Some(bv), Some(nv)) = (&a_val, &b_val, &n_val) { + if let Some(result) = fold_ternary(operation, av, bv, nv) { + self.statistics.constants_folded += 1; + return Expression::Literal { + value: result, + value_type: Type::Int(BitWidth::I256), + }; + } + } + + Expression::Ternary { operation, a, b, n } + } + + Expression::Var(id) => { + let resolved = self.resolve_copy(id); + Expression::Var(resolved) + } + + Expression::MLoad { offset, region } => { + let offset = self.resolve_value(offset); + let region = if region == MemoryRegion::Unknown { + self.resolve_region(&offset) + } else { + region + }; + Expression::MLoad { offset, region } + } + + Expression::Address => self.cse_env_read(EnvRead::Address, expression), + Expression::BaseFee => self.cse_env_read(EnvRead::BaseFee, expression), + Expression::BlobBaseFee => self.cse_env_read(EnvRead::BlobBaseFee, expression), + Expression::CallDataSize => self.cse_env_read(EnvRead::CallDataSize, expression), + Expression::CallValue => self.cse_env_read(EnvRead::CallValue, expression), + Expression::Caller => self.cse_env_read(EnvRead::Caller, expression), + Expression::ChainId => self.cse_env_read(EnvRead::ChainId, expression), + Expression::CodeSize => self.cse_env_read(EnvRead::CodeSize, expression), + Expression::Coinbase => self.cse_env_read(EnvRead::Coinbase, expression), + Expression::Difficulty => self.cse_env_read(EnvRead::Difficulty, expression), + Expression::GasLimit => self.cse_env_read(EnvRead::GasLimit, expression), + Expression::GasPrice => self.cse_env_read(EnvRead::GasPrice, expression), + Expression::Number => self.cse_env_read(EnvRead::Number, expression), + Expression::Origin => self.cse_env_read(EnvRead::Origin, expression), + Expression::Timestamp => self.cse_env_read(EnvRead::Timestamp, expression), + + Expression::Keccak256Single { word0 } => { + let word0 = self.resolve_value(word0); + if let Some(c) = self.try_get_const(&word0) { + let result = fold_keccak256_single(&c); + self.statistics.constants_folded += 1; + Expression::Literal { + value: result, + value_type: Type::Int(BitWidth::I256), + } + } else { + Expression::Keccak256Single { word0 } + } + } + + Expression::Keccak256Pair { word0, word1 } => { + let word0 = self.resolve_value(word0); + let word1 = self.resolve_value(word1); + if let (Some(c0), Some(c1)) = + (self.try_get_const(&word0), self.try_get_const(&word1)) + { + let result = fold_keccak256_pair(&c0, &c1); + self.statistics.constants_folded += 1; + Expression::Literal { + value: result, + value_type: Type::Int(BitWidth::I256), + } + } else { + Expression::Keccak256Pair { word0, word1 } + } + } + + Expression::MappingSLoad { key, slot } => Expression::MappingSLoad { + key: self.resolve_value(key), + slot: self.resolve_value(slot), + }, + + other => other, + } + } + + /// Checks if an environment read has been cached and returns a Var reference + /// to the first binding if so. Otherwise returns the original expression. + fn cse_env_read(&mut self, kind: EnvRead, original: Expression) -> Expression { + if let Some(&cached_id) = self.env_reads.get(&kind) { + self.statistics.env_reads_eliminated += 1; + Expression::Var(cached_id) + } else { + original + } + } + + /// Resolves a Value through copy propagation. + fn resolve_value(&self, value: Value) -> Value { + let resolved = self.resolve_copy(value.id); + if resolved != value.id { + Value { + id: resolved, + ..value + } + } else { + value + } + } + + /// Resolves a ValueId through the copy chain. + fn resolve_copy(&self, id: ValueId) -> ValueId { + let mut current = id; + for _ in 0..32 { + if let Some(&target) = self.copies.get(¤t.0) { + if target == current { + break; + } + current = target; + } else { + break; + } + } + current + } + + /// Tries to get the constant value for a Value. + fn try_get_const(&self, value: &Value) -> Option { + let resolved = self.resolve_copy(value.id); + self.constants.get(&resolved.0).cloned() + } + + /// Emits the two-`Let` strength-reduction template: + /// `let helper = const_value; let result = target_op(, )` + /// where one operand of `target_op` is the freshly-bound `helper` and the + /// other is `other_operand` (its position controlled by `helper_on_lhs`). + fn emit_strength_reduce( + &mut self, + bindings: &[ValueId], + target_op: BinaryOperation, + const_value: BigUint, + helper_on_lhs: bool, + other_operand: Value, + ) -> Vec { + let helper_id = self.fresh_id(); + self.constants.insert(helper_id.0, const_value.clone()); + self.statistics.identities_simplified += 1; + let helper_val = Value::int(helper_id); + let (lhs, rhs) = if helper_on_lhs { + (helper_val, other_operand) + } else { + (other_operand, helper_val) + }; + vec![ + Statement::Let { + bindings: vec![helper_id], + value: Expression::Literal { + value: const_value, + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::Let { + bindings: bindings.to_vec(), + value: Expression::Binary { + operation: target_op, + lhs, + rhs, + }, + }, + ] + } + + /// Attempts strength reduction on a Let binding. Transforms: + /// - `mul(x, 2^k)` or `mul(2^k, x)` → `shl(k, x)` + /// - `div(x, 2^k)` → `shr(k, x)` (unsigned only) + /// - `mod(x, 2^k)` → `and(x, 2^k - 1)` + fn try_strength_reduce( + &mut self, + bindings: &[ValueId], + expression: &Expression, + ) -> Option> { + let (operation, lhs, rhs) = match expression { + Expression::Binary { + operation, + lhs, + rhs, + } => (*operation, *lhs, *rhs), + _ => return None, + }; + let lhs_val = self.try_get_const(&lhs); + let rhs_val = self.try_get_const(&rhs); + let in_range = |k: u32| (1..256).contains(&k); + + match operation { + BinaryOperation::Mul => { + let (k, value) = if let Some(k) = rhs_val.as_ref().and_then(log2_exact) { + (k, lhs) + } else if let Some(k) = lhs_val.as_ref().and_then(log2_exact) { + (k, rhs) + } else { + return None; + }; + in_range(k).then(|| { + self.emit_strength_reduce( + bindings, + BinaryOperation::Shl, + BigUint::from(k), + true, + value, + ) + }) + } + BinaryOperation::Div => { + let k = rhs_val.as_ref().and_then(log2_exact)?; + in_range(k).then(|| { + self.emit_strength_reduce( + bindings, + BinaryOperation::Shr, + BigUint::from(k), + true, + lhs, + ) + }) + } + BinaryOperation::Mod => { + let k = rhs_val.as_ref().and_then(log2_exact)?; + in_range(k).then(|| { + let mask = (BigUint::one() << k) - BigUint::one(); + self.emit_strength_reduce(bindings, BinaryOperation::And, mask, false, lhs) + }) + } + _ => None, + } + } +} + +/// Detects and replaces the Solidity panic revert pattern in a statement list. +/// +/// The pattern is a sequence of statements ending with: +/// let bindings for constants, mstore(0, 0x4e487b71...), more let bindings, +/// mstore(4, error_code), more let bindings, revert(0, 0x24) +/// +/// Each match is replaced with `PanicRevert { code }`, and the preceding +/// Let bindings used only by the panic are left for DCE to remove. +/// +/// This function merges the caller's constant map with local Let-literal bindings +/// to correctly resolve constants defined either in the current scope or in outer scopes +/// (after copy propagation may have replaced local definitions with outer references). +fn outline_panic_patterns( + statements: Vec, + scope_constants: &BTreeMap, +) -> Vec { + let has_revert = statements + .iter() + .any(|s| matches!(s, Statement::Revert { .. })); + if !has_revert { + return statements; + } + + let mut constants: BTreeMap = scope_constants.clone(); + for statement in &statements { + if let Statement::Let { + bindings, + value: Expression::Literal { value, .. }, + } = statement + { + if bindings.len() == 1 { + constants.insert(bindings[0].0, value.clone()); + } + } + } + + let mut result = Vec::with_capacity(statements.len()); + + for statement in statements { + if let Statement::Revert { + ref offset, + ref length, + } = statement + { + if is_const_value(offset.id, 0, &constants) + && is_const_value(length.id, 0x24, &constants) + { + if let Some((panic_start, error_code)) = + find_panic_pattern_backwards(&result, &constants) + { + result.truncate(panic_start); + result.push(Statement::PanicRevert { code: error_code }); + continue; + } + } + } + + result.push(statement); + } + + result +} + +/// Looks backwards from the end of a statement list to find the panic pattern: +/// mstore(0, panic_selector), [let bindings]*, mstore(4, code), [let bindings]* +/// +/// Returns `(start_index, error_code)` if the pattern is found. +fn find_panic_pattern_backwards( + statements: &[Statement], + constants: &BTreeMap, +) -> Option<(usize, u8)> { + let len = statements.len(); + if len < 2 { + return None; + } + + let mut mstore4_idx = None; + let mut error_code = None; + let search_limit = len.saturating_sub(10); + + for j in (search_limit..len).rev() { + match &statements[j] { + Statement::MStore { offset, value, .. } => { + if is_const_value(offset.id, 4, constants) { + if let Some(code_val) = constants.get(&value.id.0) { + // The simplifier emits `Statement::PanicRevert { code: u8 }` which + // encodes Solidity's canonical 36-byte panic revert with `code` + // zero-padded into the last byte. Only fold when the original + // mstored value actually fits in `u8` — i.e. ALL bits above the + // low byte are zero. Using `to_u64_digits().first()` here was + // unsound: it returned only the lowest u64 digit, so values like + // `2^124 + 0x42` were mis-classified as `code = 0x42` and the + // high bits (which the EVM emits literally into the revert data) + // were silently dropped. + if code_val.bits() <= 8 { + let code_u8 = + code_val.to_u64_digits().first().copied().unwrap_or(0) as u8; + mstore4_idx = Some(j); + error_code = Some(code_u8); + break; + } + } + } + } + Statement::Let { .. } | Statement::Expression(..) => continue, + _ => break, + } + } + + let mstore4_idx = mstore4_idx?; + let error_code = error_code?; + + let search_limit2 = mstore4_idx.saturating_sub(10); + for j in (search_limit2..mstore4_idx).rev() { + match &statements[j] { + Statement::MStore { offset, value, .. } => { + if is_const_value(offset.id, 0, constants) { + if let Some(sel_val) = constants.get(&value.id.0) { + let sel_hex = format!("{sel_val:064x}"); + if sel_hex == revive_common::PANIC_UINT256_SELECTOR_WORD_HEX { + // Soundness: every `mstore(p, …)` between the + // panic-selector store and the revert writes 32 + // bytes at `[p, p + 32)`. If `p < 0x24`, those + // bytes overlap the revert range `[0, 0x24)` and + // EVM will emit them in the revert data. The + // canonical Solidity panic shape has exactly + // two such mstores — `p = 0` (selector) and + // `p = 4` (code). Any other in-range mstore + // (e.g. `mstore(7, garbage)`) corrupts the + // revert payload, so we must NOT collapse the + // sequence into the canonical + // `PanicRevert { code }` form. + let only_safe = statements[j..].iter().all(|s| match s { + Statement::MStore { offset, .. } => { + is_const_value(offset.id, 0, constants) + || is_const_value(offset.id, 4, constants) + || constants + .get(&offset.id.0) + .is_some_and(|v| v.to_u64().is_some_and(|o| o >= 0x24)) + } + Statement::Let { .. } | Statement::Expression(..) => true, + _ => false, + }); + if only_safe { + return Some((j, error_code)); + } + } + } + } + } + Statement::Let { .. } | Statement::Expression(..) => continue, + _ => break, + } + } + + None +} + +/// Checks if a ValueId maps to a specific constant value. +fn is_const_value(id: ValueId, expected: u64, constants: &BTreeMap) -> bool { + constants + .get(&id.0) + .is_some_and(|v| *v == BigUint::from(expected)) +} + +/// Outlines custom error revert patterns in a statement list. +/// +/// Detects the pattern: mstore(0, selector) [+ mstore(4, arg0) + mstore(0x24, arg1) + ...] + revert(0, 4+32*N) +/// where the selector is a constant and the revert uses scratch space (offset 0). +/// Replaces matched patterns with `CustomErrorRevert { selector, arguments }`. +fn outline_custom_error_patterns( + statements: Vec, + scope_constants: &BTreeMap, +) -> Vec { + let has_revert = statements + .iter() + .any(|s| matches!(s, Statement::Revert { .. })); + if !has_revert { + return statements; + } + + let mut constants: BTreeMap = scope_constants.clone(); + for statement in &statements { + if let Statement::Let { + bindings, + value: Expression::Literal { value, .. }, + } = statement + { + if bindings.len() == 1 { + constants.insert(bindings[0].0, value.clone()); + } + } + } + + let zero = BigUint::ZERO; + let mut result = Vec::with_capacity(statements.len()); + + for statement in statements { + if let Statement::Revert { + ref offset, + ref length, + } = statement + { + if constants.get(&offset.id.0).is_some_and(|v| *v == zero) { + if let Some(total_len) = constants.get(&length.id.0).and_then(|v| v.to_u64()) { + let num_args = if total_len == 4 { + Some(0usize) + } else if total_len >= 0x24 && (total_len - 4) % 0x20 == 0 { + Some(((total_len - 4) / 0x20) as usize) + } else { + None + }; + + if let Some(num_args) = num_args { + if let Some((start_idx, selector, arguments)) = + find_custom_error_pattern_backwards(&result, &constants, num_args) + { + let mut kept = Vec::new(); + for s in result.drain(start_idx..) { + match s { + Statement::MStore { .. } => {} + _ => kept.push(s), + } + } + result.extend(kept); + result.push(Statement::CustomErrorRevert { + selector, + arguments, + }); + continue; + } + } + } + } + } + + result.push(statement); + } + + result +} + +/// Looks backwards from the end of a statement list to find the custom error pattern. +/// +/// Searches for: +/// 1. mstore(0, selector) at scratch space — selector is a constant +/// 2. mstore(4, arg0) — first argument (optional) +/// 3. mstore(0x24, arg1) — second argument (optional) +/// 4. mstore(0x44, arg2) — third argument (optional) +/// +/// Returns `(start_index, selector, arguments)` if found. +fn find_custom_error_pattern_backwards( + statements: &[Statement], + constants: &BTreeMap, + num_args: usize, +) -> Option<(usize, BigUint, Vec)> { + let len = statements.len(); + if len < 1 + num_args { + return None; + } + + let mut found_selector: Option = None; + let mut arguments: Vec> = vec![None; num_args]; + let mut earliest_idx = len; + + let zero = BigUint::ZERO; + let four = BigUint::from(4u32); + + let search_limit = len.saturating_sub(20); + for j in (search_limit..len).rev() { + match &statements[j] { + Statement::MStore { offset, value, .. } => { + if let Some(off_val) = constants.get(&offset.id.0) { + if *off_val == zero { + if let Some(sel) = constants.get(&value.id.0) { + found_selector = Some(sel.clone()); + earliest_idx = earliest_idx.min(j); + } + } else if *off_val == four && num_args >= 1 { + arguments[0] = Some(*value); + earliest_idx = earliest_idx.min(j); + } else if let Some(off_u64) = off_val.to_u64() { + if off_u64 >= 0x24 && (off_u64 - 4) % 0x20 == 0 { + let arg_idx = ((off_u64 - 4) / 0x20) as usize; + if arg_idx < num_args { + arguments[arg_idx] = Some(*value); + earliest_idx = earliest_idx.min(j); + } + } + } + } + } + Statement::Let { .. } | Statement::Expression(..) => continue, + _ => break, + } + } + + let selector = found_selector?; + let arguments: Vec = arguments.into_iter().collect::>>()?; + + // Soundness: see the analogous comment in + // `find_panic_pattern_backwards`. The revert range is + // `[0, 4 + 32 * num_args)`. The canonical Solidity custom-error + // shape writes at exactly the offsets `0`, `4`, `0x24`, … + // `4 + 32 * (num_args - 1)`. Any in-range mstore at a different + // offset corrupts the revert payload — we must NOT collapse the + // sequence into `Statement::CustomErrorRevert`. Out-of-range + // mstores (offset ≥ revert_length) are fine; they don't escape. + let revert_length = 4 + (num_args as u64) * 0x20; + let all_safe = statements[earliest_idx..].iter().all(|s| match s { + Statement::MStore { offset, .. } => constants.get(&offset.id.0).is_some_and(|off_val| { + if let Some(off_u64) = off_val.to_u64() { + if off_u64 >= revert_length { + return true; + } + if off_u64 == 0 { + return true; + } + off_u64 >= 4 && (off_u64 - 4) % 0x20 == 0 + } else { + false + } + }), + Statement::Let { .. } | Statement::Expression(..) => true, + _ => false, + }); + if !all_safe { + return None; + } + + Some((earliest_idx, selector, arguments)) +} + +/// Returns the result type for a binary operation. +fn result_type(operation: BinaryOperation) -> Type { + match operation { + BinaryOperation::Lt + | BinaryOperation::Gt + | BinaryOperation::Slt + | BinaryOperation::Sgt + | BinaryOperation::Eq => Type::Int(BitWidth::I256), + _ => Type::Int(BitWidth::I256), + } +} + +/// Returns the result type for a unary operation. +fn unary_result_type(operation: UnaryOperation) -> Type { + match operation { + UnaryOperation::IsZero => Type::Int(BitWidth::I256), + UnaryOperation::Not | UnaryOperation::Clz => Type::Int(BitWidth::I256), + } +} + +/// Folds a binary operation on two constant values. +/// Returns None if the operation cannot be folded. +fn fold_binary(operation: BinaryOperation, a: &BigUint, b: &BigUint) -> Option { + let modulus = modulus_u256(); + let max = max_u256(); + + Some(match operation { + BinaryOperation::Add => (a + b) % &modulus, + BinaryOperation::Sub => { + if a >= b { + a - b + } else { + &modulus - (b - a) + } + } + BinaryOperation::Mul => (a * b) % &modulus, + BinaryOperation::Div => { + if b.is_zero() { + BigUint::zero() + } else { + a / b + } + } + BinaryOperation::SDiv => { + if b.is_zero() { + BigUint::zero() + } else { + fold_sdiv(a, b, &modulus)? + } + } + BinaryOperation::Mod => { + if b.is_zero() { + BigUint::zero() + } else { + a % b + } + } + BinaryOperation::SMod => { + if b.is_zero() { + BigUint::zero() + } else { + fold_smod(a, b, &modulus)? + } + } + BinaryOperation::Exp => a.modpow(b, &modulus), + BinaryOperation::And => a & b, + BinaryOperation::Or => a | b, + BinaryOperation::Xor => a ^ b, + BinaryOperation::Shl => { + if *a >= BigUint::from(256u32) { + BigUint::zero() + } else { + let shift = a.to_u64_digits().first().copied().unwrap_or(0) as usize; + (b << shift) % &modulus + } + } + BinaryOperation::Shr => { + if *a >= BigUint::from(256u32) { + BigUint::zero() + } else { + let shift = a.to_u64_digits().first().copied().unwrap_or(0) as usize; + b >> shift + } + } + BinaryOperation::Sar => fold_sar(b, a, &modulus, &max)?, + BinaryOperation::Lt => bool_to_u256(a < b), + BinaryOperation::Gt => bool_to_u256(a > b), + BinaryOperation::Eq => bool_to_u256(a == b), + BinaryOperation::Slt => { + let a_signed = is_negative(a, &modulus); + let b_signed = is_negative(b, &modulus); + match (a_signed, b_signed) { + (true, false) => bool_to_u256(true), + (false, true) => bool_to_u256(false), + _ => bool_to_u256(a < b), + } + } + BinaryOperation::Sgt => { + let a_signed = is_negative(a, &modulus); + let b_signed = is_negative(b, &modulus); + match (a_signed, b_signed) { + (true, false) => bool_to_u256(false), + (false, true) => bool_to_u256(true), + _ => bool_to_u256(a > b), + } + } + BinaryOperation::Byte => { + if *a >= BigUint::from(32u32) { + BigUint::zero() + } else { + let n = a.to_u64_digits().first().copied().unwrap_or(0) as usize; + let shift = (31 - n) * 8; + (b >> shift) & BigUint::from(0xffu32) + } + } + BinaryOperation::SignExtend => fold_signextend(a, b, &max)?, + BinaryOperation::AddMod | BinaryOperation::MulMod => return None, + }) +} + +/// Folds a unary operation on a constant value. +fn fold_unary(operation: UnaryOperation, a: &BigUint) -> Option { + Some(match operation { + UnaryOperation::IsZero => bool_to_u256(a.is_zero()), + UnaryOperation::Not => &max_u256() ^ a, + UnaryOperation::Clz => { + if a.is_zero() { + BigUint::from(256u32) + } else { + let bits = a.bits(); + BigUint::from(256u64 - bits) + } + } + }) +} + +/// Folds a ternary operation (addmod, mulmod). +fn fold_ternary( + operation: BinaryOperation, + a: &BigUint, + b: &BigUint, + n: &BigUint, +) -> Option { + if n.is_zero() { + return Some(BigUint::zero()); + } + Some(match operation { + BinaryOperation::AddMod => (a + b) % n, + BinaryOperation::MulMod => (a * b) % n, + _ => return None, + }) +} + +/// Encodes a BigUint as a 32-byte big-endian buffer (left-padded with zeros). +fn biguint_to_be32(value: &BigUint) -> [u8; 32] { + let bytes = value.to_bytes_be(); + let mut buf = [0u8; 32]; + let start = 32usize.saturating_sub(bytes.len()); + buf[start..].copy_from_slice(&bytes[bytes.len().saturating_sub(32)..]); + buf +} + +/// Computes keccak256 of a single 256-bit word at compile time. +fn fold_keccak256_single(word0: &BigUint) -> BigUint { + let buf = biguint_to_be32(word0); + let hash = revive_common::Keccak256::from_slice(&buf); + BigUint::from_bytes_be(hash.as_bytes()) +} + +/// Computes keccak256 of two 256-bit words at compile time. +fn fold_keccak256_pair(word0: &BigUint, word1: &BigUint) -> BigUint { + let mut buf = [0u8; 64]; + buf[..32].copy_from_slice(&biguint_to_be32(word0)); + buf[32..].copy_from_slice(&biguint_to_be32(word1)); + let hash = revive_common::Keccak256::from_slice(&buf); + BigUint::from_bytes_be(hash.as_bytes()) +} + +/// Returns the power-of-2 exponent if the value is a power of 2. +/// E.g., 1 -> Some(0), 2 -> Some(1), 4 -> Some(2), 32 -> Some(5), 256 -> Some(8). +fn log2_exact(value: &BigUint) -> Option { + if value.is_zero() || !((value - BigUint::one()) & value).is_zero() { + return None; + } + Some((value.bits() - 1) as u32) +} + +/// Applies algebraic identity simplifications. +/// Returns Some(simplified_expr) if an identity applies, None otherwise. +fn simplify_binary( + operation: BinaryOperation, + lhs: &Value, + rhs: &Value, + lhs_val: &Option, + rhs_val: &Option, +) -> Option { + let i256 = Type::Int(BitWidth::I256); + let literal = |value: BigUint| Expression::Literal { + value, + value_type: i256, + }; + let var_l = || Expression::Var(lhs.id); + let var_r = || Expression::Var(rhs.id); + let same = lhs.id == rhs.id; + let l_is = |v: &BigUint| lhs_val.as_ref() == Some(v); + let r_is = |v: &BigUint| rhs_val.as_ref() == Some(v); + let zero = BigUint::zero(); + let one = BigUint::one(); + + match operation { + BinaryOperation::Add => { + if r_is(&zero) { + Some(var_l()) + } else if l_is(&zero) { + Some(var_r()) + } else { + None + } + } + + BinaryOperation::Sub if r_is(&zero) => Some(var_l()), + BinaryOperation::Sub if same => Some(literal(zero)), + BinaryOperation::Sub => None, + + BinaryOperation::Mul if r_is(&zero) || l_is(&zero) => Some(literal(zero)), + BinaryOperation::Mul if r_is(&one) => Some(var_l()), + BinaryOperation::Mul if l_is(&one) => Some(var_r()), + BinaryOperation::Mul => None, + + BinaryOperation::Div | BinaryOperation::SDiv if r_is(&one) => Some(var_l()), + BinaryOperation::Div | BinaryOperation::SDiv if l_is(&zero) => Some(literal(zero)), + // NOTE: `div(x, x) → 1` and `sdiv(x, x) → 1` are unsound when `x == 0`. + // EVM defines division by zero to return 0, so `div(0, 0) = 0`, not 1. + // We can only fold the same-operand case when we statically know `x != 0`. + BinaryOperation::Div | BinaryOperation::SDiv + if same && lhs_val.as_ref().is_some_and(|v| !v.is_zero()) => + { + Some(literal(one)) + } + BinaryOperation::Div | BinaryOperation::SDiv => None, + + BinaryOperation::Mod | BinaryOperation::SMod if r_is(&one) || l_is(&zero) || same => { + Some(literal(zero)) + } + BinaryOperation::Mod | BinaryOperation::SMod => None, + + BinaryOperation::And if r_is(&zero) || l_is(&zero) => Some(literal(zero)), + BinaryOperation::And if r_is(&max_u256()) || same => Some(var_l()), + BinaryOperation::And if l_is(&max_u256()) => Some(var_r()), + BinaryOperation::And => None, + + BinaryOperation::Or if r_is(&zero) || same => Some(var_l()), + BinaryOperation::Or if l_is(&zero) => Some(var_r()), + BinaryOperation::Or if r_is(&max_u256()) || l_is(&max_u256()) => Some(literal(max_u256())), + BinaryOperation::Or => None, + + BinaryOperation::Xor if r_is(&zero) => Some(var_l()), + BinaryOperation::Xor if l_is(&zero) => Some(var_r()), + BinaryOperation::Xor if same => Some(literal(zero)), + BinaryOperation::Xor => None, + + BinaryOperation::Shl | BinaryOperation::Shr | BinaryOperation::Sar if l_is(&zero) => { + Some(var_r()) + } + BinaryOperation::Shl | BinaryOperation::Shr | BinaryOperation::Sar => None, + + BinaryOperation::Eq if same => Some(literal(one)), + BinaryOperation::Eq => None, + + BinaryOperation::Lt | BinaryOperation::Gt | BinaryOperation::Slt | BinaryOperation::Sgt + if same => + { + Some(literal(zero)) + } + BinaryOperation::Lt | BinaryOperation::Gt | BinaryOperation::Slt | BinaryOperation::Sgt => { + None + } + + _ => None, + } +} + +/// Helper: checks if a 256-bit value is negative in two's complement. +fn is_negative(value: &BigUint, modulus: &BigUint) -> bool { + *value >= (modulus >> 1) +} + +/// Helper: converts a boolean to a 256-bit value (0 or 1). +fn bool_to_u256(b: bool) -> BigUint { + if b { + BigUint::one() + } else { + BigUint::zero() + } +} + +/// Helper: signed division for 256-bit values. +fn fold_sdiv(a: &BigUint, b: &BigUint, modulus: &BigUint) -> Option { + let half = modulus >> 1; + let a_neg = *a >= half; + let b_neg = *b >= half; + + let abs_a = if a_neg { modulus - a } else { a.clone() }; + let abs_b = if b_neg { modulus - b } else { b.clone() }; + + if abs_b.is_zero() { + return Some(BigUint::zero()); + } + + let result = &abs_a / &abs_b; + + if a_neg != b_neg && !result.is_zero() { + Some(modulus - &result) + } else { + Some(result) + } +} + +/// Helper: signed modulo for 256-bit values. +fn fold_smod(a: &BigUint, b: &BigUint, modulus: &BigUint) -> Option { + let half = modulus >> 1; + let a_neg = *a >= half; + let b_neg = *b >= half; + + let abs_a = if a_neg { modulus - a } else { a.clone() }; + let abs_b = if b_neg { modulus - b } else { b.clone() }; + + if abs_b.is_zero() { + return Some(BigUint::zero()); + } + + let result = &abs_a % &abs_b; + + if a_neg && !result.is_zero() { + Some(modulus - &result) + } else { + Some(result) + } +} + +/// Helper: arithmetic shift right for 256-bit values. +fn fold_sar(a: &BigUint, b: &BigUint, modulus: &BigUint, max: &BigUint) -> Option { + if *b >= BigUint::from(256u32) { + let half = modulus >> 1; + return if *a >= half { + Some(max.clone()) + } else { + Some(BigUint::zero()) + }; + } + + let shift = b.to_u64_digits().first().copied().unwrap_or(0) as usize; + let half = modulus >> 1; + + if *a >= half { + let shifted = a >> shift; + let fill = (max >> (256 - shift)) << (256 - shift); + Some((shifted | fill) % modulus) + } else { + Some(a >> shift) + } +} + +/// Helper: EVM signextend(b, x) operation. +fn fold_signextend(b: &BigUint, x: &BigUint, max: &BigUint) -> Option { + if *b >= BigUint::from(31u32) { + return Some(x.clone()); + } + + let byte_pos = b.to_u64_digits().first().copied().unwrap_or(0) as usize; + let bit_pos = byte_pos * 8 + 7; + let sign_bit = (x >> bit_pos) & BigUint::one(); + + if sign_bit.is_one() { + let mask = max << (bit_pos + 1); + Some((x | mask) & max) + } else { + let mask = (BigUint::one() << (bit_pos + 1)) - BigUint::one(); + Some(x & mask) + } +} + +/// Checks if an expression has side effects (cannot be dead-code eliminated). +fn expr_has_side_effects(expression: &Expression) -> bool { + matches!( + expression, + Expression::Call { .. } + | Expression::Keccak256 { .. } + | Expression::Keccak256Pair { .. } + | Expression::Keccak256Single { .. } + | Expression::MLoad { .. } + | Expression::SLoad { .. } + | Expression::TLoad { .. } + | Expression::MappingSLoad { .. } + | Expression::MSize + ) +} + +/// Eliminates dead Let bindings from a list of statements. +/// Uses bottom-up recursive DCE: first cleans nested regions, then this level. +/// Iterates at each level until fixpoint (no more removals). +/// +/// `extra_used` contains ValueIds that must be preserved even if not referenced +/// by the statements themselves (e.g., function return values, region yields). +fn eliminate_dead_code_in_stmts( + statements: &mut Vec, + extra_used: &BTreeSet, +) -> usize { + let mut total_removed = 0; + + if let Some(terminator_pos) = statements.iter().position(is_terminator) { + let unreachable_count = statements.len() - terminator_pos - 1; + if unreachable_count > 0 { + statements.truncate(terminator_pos + 1); + total_removed += unreachable_count; + } + } + + for statement in statements.iter_mut() { + total_removed += eliminate_dead_code_in_nested(statement, extra_used); + } + + loop { + let mut used = extra_used.clone(); + for statement in statements.iter() { + statement.for_each_value_id(&mut |id| { + used.insert(id.0); + }); + } + + let before = statements.len(); + statements.retain(|statement| { + if let Statement::Let { bindings, value } = statement { + let all_unused = bindings.iter().all(|id| !used.contains(&id.0)); + if all_unused && !expr_has_side_effects(value) { + return false; + } + } + if let Statement::Expression(expression) = statement { + if !expr_has_side_effects(expression) { + return false; + } + } + true + }); + + let removed = before - statements.len(); + total_removed += removed; + if removed == 0 { + break; + } + } + + total_removed +} + +/// Recursively DCE inside nested regions of a statement. +/// `parent_extra_used` contains ValueIds from the parent scope that must be preserved +/// (e.g., function return values). These are propagated into Block regions because +/// Blocks in Yul can define values that are referenced by the parent scope. +fn eliminate_dead_code_in_nested( + statement: &mut Statement, + parent_extra_used: &BTreeSet, +) -> usize { + match statement { + Statement::If { + then_region, + else_region, + .. + } => { + let mut removed = 0; + let extra = yields_as_used(&then_region.yields); + removed += eliminate_dead_code_in_stmts(&mut then_region.statements, &extra); + if let Some(r) = else_region { + let extra = yields_as_used(&r.yields); + removed += eliminate_dead_code_in_stmts(&mut r.statements, &extra); + } + removed + } + Statement::Switch { cases, default, .. } => { + let mut removed = 0; + for c in cases { + let extra = yields_as_used(&c.body.yields); + removed += eliminate_dead_code_in_stmts(&mut c.body.statements, &extra); + } + if let Some(d) = default { + let extra = yields_as_used(&d.yields); + removed += eliminate_dead_code_in_stmts(&mut d.statements, &extra); + } + removed + } + Statement::Block(region) => { + let mut extra = yields_as_used(®ion.yields); + extra.extend(parent_extra_used); + eliminate_dead_code_in_stmts(&mut region.statements, &extra) + } + _ => 0, + } +} + +/// Checks if a statement is a control-flow terminator (no fall-through). +fn is_terminator(statement: &Statement) -> bool { + matches!( + statement, + Statement::Revert { .. } + | Statement::Return { .. } + | Statement::Stop + | Statement::Invalid + | Statement::PanicRevert { .. } + | Statement::ErrorStringRevert { .. } + | Statement::CustomErrorRevert { .. } + | Statement::Leave { .. } + | Statement::SelfDestruct { .. } + ) +} + +/// Checks if a statement list starts with the two-statement pattern: +/// `let tmp = callvalue()` +/// `if tmp { ... revert(...) ... }` +/// This pattern is generated by Solidity for non-payable function checks. +/// The then_region must contain a Revert (possibly preceded by Let bindings +/// for the offset/length arguments and followed by an unreachable marker). +fn has_callvalue_revert_prefix(statements: &[Statement]) -> bool { + if statements.len() < 2 { + return false; + } + + let callvalue_id = match &statements[0] { + Statement::Let { + bindings, + value: Expression::CallValue, + } if bindings.len() == 1 => Some(bindings[0]), + _ => None, + }; + + let Some(cv_id) = callvalue_id else { + return false; + }; + + match &statements[1] { + Statement::If { + condition, + inputs, + then_region, + else_region, + outputs, + } => { + if condition.id != cv_id { + return false; + } + if !inputs.is_empty() || !outputs.is_empty() { + return false; + } + if else_region.is_some() { + return false; + } + then_region + .statements + .iter() + .any(|s| matches!(s, Statement::Revert { .. })) + } + _ => false, + } +} + +/// Checks if a statement list starts with `let vN = callvalue()`. +/// Used for partial callvalue read hoisting: we only need the first statement +/// to be a callvalue binding, not the full callvalue-revert pattern. +fn starts_with_callvalue_let(statements: &[Statement]) -> bool { + matches!( + statements.first(), + Some(Statement::Let { + bindings, + value: Expression::CallValue, + }) if bindings.len() == 1 + ) +} + +/// Replaces the first statement's `callvalue()` expression with `Var(replacement_id)` +/// if the first statement is `let vN = callvalue()`. This turns the syscall read +/// into a copy of the already-hoisted value. +fn replace_leading_callvalue_with_var(statements: &mut [Statement], replacement_id: ValueId) { + if let Some(Statement::Let { + bindings, + value: value @ Expression::CallValue, + }) = statements.first_mut() + { + if bindings.len() == 1 { + *value = Expression::Var(replacement_id); + } + } +} + +/// Collects ValueIds from region yields into a "used" set. +fn yields_as_used(yields: &[Value]) -> BTreeSet { + let mut used = BTreeSet::new(); + for y in yields { + used.insert(y.id.0); + } + used +} + +/// Minimum function size for exact dedup. A body this small lowers to a +/// handful of instructions — comparable to a call's own per-site overhead — +/// so collapsing duplicates into a shared callable would cost more than it +/// saves. +const MIN_DEDUP_SIZE: usize = 4; + +/// Deduplicates functions with identical bodies in an object. +/// +/// Two functions are considered duplicates if they have: +/// - Same number and types of parameters +/// - Same number and types of return values +/// - Structurally identical bodies (alpha-equivalent, ignoring ValueId numbering) +/// +/// When duplicates are found, all calls to the duplicate are redirected to the +/// canonical (first-seen) function, and the duplicate is removed. +/// +/// Returns the number of functions removed. +pub fn deduplicate_functions(object: &mut Object) -> usize { + if object.functions.len() < 2 { + return 0; + } + + let mut canonical_to_id: BTreeMap, FunctionId> = BTreeMap::new(); + let mut redirects: BTreeMap = BTreeMap::new(); + + for function in object.functions.values() { + if function.size_estimate < MIN_DEDUP_SIZE { + continue; + } + + let signature = ( + function + .parameters + .iter() + .map(|(_, value_type)| *value_type) + .collect::>(), + function.returns.clone(), + ); + + let canonical = canonicalize_function(function, &signature.0, &signature.1); + + if let Some(&canonical_id) = canonical_to_id.get(&canonical) { + redirects.insert(function.id, canonical_id); + } else { + canonical_to_id.insert(canonical, function.id); + } + } + + if redirects.is_empty() { + return 0; + } + + let removed_count = redirects.len(); + redirect_calls_in_block(&mut object.code, &redirects); + for function in object.functions.values_mut() { + redirect_calls_in_block(&mut function.body, &redirects); + } + + for dup_id in redirects.keys() { + object.functions.remove(dup_id); + } + + removed_count +} + +/// Produces a canonical byte representation of a function body for comparison. +/// ValueIds are renumbered sequentially (0, 1, 2, ...) in order of first occurrence. +/// FunctionIds are preserved (they're global references, not local SSA). +fn canonicalize_function( + function: &crate::ir::Function, + parameter_types: &[Type], + return_types: &[Type], +) -> Vec { + let mut canon = Canonicalizer::new(); + let mut buf = Vec::new(); + + buf.push(parameter_types.len() as u8); + for value_type in parameter_types { + buf.push(type_tag(value_type)); + } + buf.push(return_types.len() as u8); + for value_type in return_types { + buf.push(type_tag(value_type)); + } + + for (parameter_id, _) in &function.parameters { + canon.get_or_insert(*parameter_id); + } + for rv in &function.return_values_initial { + canon.get_or_insert(*rv); + } + + for statement in &function.body.statements { + canon.encode_statement(statement, &mut buf); + } + + buf.push(0xFE); + for rv in &function.return_values { + canon.encode_value_id(*rv, &mut buf); + } + + buf +} + +struct Canonicalizer { + id_map: BTreeMap, + next_id: u32, +} + +impl Canonicalizer { + fn new() -> Self { + Canonicalizer { + id_map: BTreeMap::new(), + next_id: 0, + } + } + + fn get_or_insert(&mut self, id: ValueId) -> u32 { + *self.id_map.entry(id.0).or_insert_with(|| { + let n = self.next_id; + self.next_id += 1; + n + }) + } + + fn encode_value_id(&mut self, id: ValueId, buf: &mut Vec) { + let canonical = self.get_or_insert(id); + buf.extend_from_slice(&canonical.to_le_bytes()); + } + + fn encode_value(&mut self, value: &Value, buf: &mut Vec) { + self.encode_value_id(value.id, buf); + buf.push(type_tag(&value.value_type)); + } + + fn encode_expression(&mut self, expression: &Expression, buf: &mut Vec) { + match expression { + Expression::Literal { value, value_type } => { + buf.push(0x01); + let bytes = value.to_bytes_le(); + buf.extend_from_slice(&(bytes.len() as u16).to_le_bytes()); + buf.extend_from_slice(&bytes); + buf.push(type_tag(value_type)); + } + Expression::Var(id) => { + buf.push(0x02); + self.encode_value_id(*id, buf); + } + Expression::Binary { + operation, + lhs, + rhs, + } => { + buf.push(0x03); + buf.push(binop_tag(*operation)); + self.encode_value(lhs, buf); + self.encode_value(rhs, buf); + } + Expression::Ternary { operation, a, b, n } => { + buf.push(0x04); + buf.push(binop_tag(*operation)); + self.encode_value(a, buf); + self.encode_value(b, buf); + self.encode_value(n, buf); + } + Expression::Unary { operation, operand } => { + buf.push(0x05); + buf.push(unaryop_tag(*operation)); + self.encode_value(operand, buf); + } + Expression::Call { + function, + arguments, + } => { + buf.push(0x06); + buf.extend_from_slice(&function.0.to_le_bytes()); + buf.push(arguments.len() as u8); + for argument in arguments { + self.encode_value(argument, buf); + } + } + Expression::CallDataLoad { offset } => { + buf.push(0x10); + self.encode_value(offset, buf); + } + Expression::MLoad { offset, region } => { + buf.push(0x11); + self.encode_value(offset, buf); + buf.push(region_tag(region)); + } + Expression::SLoad { key, static_slot } => { + buf.push(0x12); + self.encode_value(key, buf); + if let Some(slot) = static_slot { + buf.push(1); + let bytes = slot.to_bytes_le(); + buf.extend_from_slice(&(bytes.len() as u16).to_le_bytes()); + buf.extend_from_slice(&bytes); + } else { + buf.push(0); + } + } + Expression::TLoad { key } => { + buf.push(0x13); + self.encode_value(key, buf); + } + Expression::Keccak256 { offset, length } => { + buf.push(0x14); + self.encode_value(offset, buf); + self.encode_value(length, buf); + } + Expression::Keccak256Pair { word0, word1 } => { + buf.push(0x24); + self.encode_value(word0, buf); + self.encode_value(word1, buf); + } + Expression::Keccak256Single { word0 } => { + buf.push(0x25); + self.encode_value(word0, buf); + } + Expression::MappingSLoad { key, slot } => { + buf.push(0x27); + self.encode_value(key, buf); + self.encode_value(slot, buf); + } + Expression::Truncate { value, to } => { + buf.push(0x15); + self.encode_value(value, buf); + buf.push(bitwidth_tag(*to)); + } + Expression::ZeroExtend { value, to } => { + buf.push(0x16); + self.encode_value(value, buf); + buf.push(bitwidth_tag(*to)); + } + Expression::SignExtendTo { value, to } => { + buf.push(0x17); + self.encode_value(value, buf); + buf.push(bitwidth_tag(*to)); + } + Expression::ExtCodeSize { address } + | Expression::ExtCodeHash { address } + | Expression::Balance { address } => { + buf.push(match expression { + Expression::ExtCodeSize { .. } => 0x20, + Expression::ExtCodeHash { .. } => 0x21, + Expression::Balance { .. } => 0x22, + _ => unreachable!(), + }); + self.encode_value(address, buf); + } + Expression::BlockHash { number } => { + buf.push(0x23); + self.encode_value(number, buf); + } + Expression::BlobHash { index } => { + buf.push(0x26); + self.encode_value(index, buf); + } + Expression::DataOffset { id } => { + buf.push(0x30); + buf.extend_from_slice(&(id.len() as u16).to_le_bytes()); + buf.extend_from_slice(id.as_bytes()); + } + Expression::DataSize { id } => { + buf.push(0x31); + buf.extend_from_slice(&(id.len() as u16).to_le_bytes()); + buf.extend_from_slice(id.as_bytes()); + } + Expression::LoadImmutable { key } => { + buf.push(0x32); + buf.extend_from_slice(&(key.len() as u16).to_le_bytes()); + buf.extend_from_slice(key.as_bytes()); + } + Expression::LinkerSymbol { path } => { + buf.push(0x33); + buf.extend_from_slice(&(path.len() as u16).to_le_bytes()); + buf.extend_from_slice(path.as_bytes()); + } + _ => { + buf.push(nullary_expr_tag(expression)); + } + } + } + + fn encode_region(&mut self, region: &Region, buf: &mut Vec) { + buf.extend_from_slice(&(region.statements.len() as u32).to_le_bytes()); + for statement in ®ion.statements { + self.encode_statement(statement, buf); + } + buf.push(region.yields.len() as u8); + for y in ®ion.yields { + self.encode_value(y, buf); + } + } + + fn encode_statement(&mut self, statement: &Statement, buf: &mut Vec) { + match statement { + Statement::Let { bindings, value } => { + buf.push(0x80); + buf.push(bindings.len() as u8); + for b in bindings { + self.encode_value_id(*b, buf); + } + self.encode_expression(value, buf); + } + Statement::MStore { + offset, + value, + region, + } => { + buf.push(0x81); + self.encode_value(offset, buf); + self.encode_value(value, buf); + buf.push(region_tag(region)); + } + Statement::MStore8 { + offset, + value, + region, + } => { + buf.push(0x82); + self.encode_value(offset, buf); + self.encode_value(value, buf); + buf.push(region_tag(region)); + } + Statement::MCopy { dest, src, length } => { + buf.push(0x83); + self.encode_value(dest, buf); + self.encode_value(src, buf); + self.encode_value(length, buf); + } + Statement::SStore { + key, + value, + static_slot, + } => { + buf.push(0x84); + self.encode_value(key, buf); + self.encode_value(value, buf); + if let Some(slot) = static_slot { + buf.push(1); + let bytes = slot.to_bytes_le(); + buf.extend_from_slice(&(bytes.len() as u16).to_le_bytes()); + buf.extend_from_slice(&bytes); + } else { + buf.push(0); + } + } + Statement::TStore { key, value } => { + buf.push(0x85); + self.encode_value(key, buf); + self.encode_value(value, buf); + } + Statement::MappingSStore { key, slot, value } => { + buf.push(0xA5); + self.encode_value(key, buf); + self.encode_value(slot, buf); + self.encode_value(value, buf); + } + Statement::If { + condition, + inputs, + then_region, + else_region, + outputs, + } => { + buf.push(0x86); + self.encode_value(condition, buf); + buf.push(inputs.len() as u8); + for i in inputs { + self.encode_value(i, buf); + } + self.encode_region(then_region, buf); + if let Some(r) = else_region { + buf.push(1); + self.encode_region(r, buf); + } else { + buf.push(0); + } + buf.push(outputs.len() as u8); + for o in outputs { + self.encode_value_id(*o, buf); + } + } + Statement::Switch { + scrutinee, + inputs, + cases, + default, + outputs, + } => { + buf.push(0x87); + self.encode_value(scrutinee, buf); + buf.push(inputs.len() as u8); + for i in inputs { + self.encode_value(i, buf); + } + buf.extend_from_slice(&(cases.len() as u32).to_le_bytes()); + for c in cases { + let case_bytes = c.value.to_bytes_le(); + buf.extend_from_slice(&(case_bytes.len() as u16).to_le_bytes()); + buf.extend_from_slice(&case_bytes); + self.encode_region(&c.body, buf); + } + if let Some(d) = default { + buf.push(1); + self.encode_region(d, buf); + } else { + buf.push(0); + } + buf.push(outputs.len() as u8); + for o in outputs { + self.encode_value_id(*o, buf); + } + } + Statement::For { + initial_values, + loop_variables, + condition_statements, + condition, + body, + post_input_variables, + post, + outputs, + } => { + buf.push(0x88); + buf.push(initial_values.len() as u8); + for v in initial_values { + self.encode_value(v, buf); + } + buf.push(loop_variables.len() as u8); + for lv in loop_variables { + self.encode_value_id(*lv, buf); + } + buf.extend_from_slice(&(condition_statements.len() as u32).to_le_bytes()); + for s in condition_statements { + self.encode_statement(s, buf); + } + self.encode_expression(condition, buf); + self.encode_region(body, buf); + buf.push(post_input_variables.len() as u8); + for pv in post_input_variables { + self.encode_value_id(*pv, buf); + } + self.encode_region(post, buf); + buf.push(outputs.len() as u8); + for o in outputs { + self.encode_value_id(*o, buf); + } + } + Statement::Block(region) => { + buf.push(0x89); + self.encode_region(region, buf); + } + Statement::Revert { offset, length } => { + buf.push(0x90); + self.encode_value(offset, buf); + self.encode_value(length, buf); + } + Statement::Return { offset, length } => { + buf.push(0x91); + self.encode_value(offset, buf); + self.encode_value(length, buf); + } + Statement::Stop => buf.push(0x92), + Statement::Invalid => buf.push(0x93), + Statement::PanicRevert { code } => { + buf.push(0xA2); + buf.push(*code); + } + Statement::ErrorStringRevert { length, data } => { + buf.push(0xA3); + buf.push(*length); + buf.push(data.len() as u8); + for word in data { + for byte in word.to_bytes_be() { + buf.push(byte); + } + } + } + Statement::CustomErrorRevert { + selector, + arguments, + } => { + buf.push(0xA4); + buf.push(arguments.len() as u8); + for byte in selector.to_bytes_be() { + buf.push(byte); + } + for argument in arguments { + self.encode_value(argument, buf); + } + } + Statement::ExternalCall { + kind, + gas, + address, + value, + args_offset, + args_length, + ret_offset, + ret_length, + result, + } => { + buf.push(0x94); + buf.push(callkind_tag(*kind)); + self.encode_value(gas, buf); + self.encode_value(address, buf); + if let Some(v) = value { + buf.push(1); + self.encode_value(v, buf); + } else { + buf.push(0); + } + self.encode_value(args_offset, buf); + self.encode_value(args_length, buf); + self.encode_value(ret_offset, buf); + self.encode_value(ret_length, buf); + self.encode_value_id(*result, buf); + } + Statement::Create { + kind, + value, + offset, + length, + salt, + result, + } => { + buf.push(0x95); + buf.push(createkind_tag(*kind)); + self.encode_value(value, buf); + self.encode_value(offset, buf); + self.encode_value(length, buf); + if let Some(s) = salt { + buf.push(1); + self.encode_value(s, buf); + } else { + buf.push(0); + } + self.encode_value_id(*result, buf); + } + Statement::Log { + offset, + length, + topics, + } => { + buf.push(0x96); + self.encode_value(offset, buf); + self.encode_value(length, buf); + buf.push(topics.len() as u8); + for t in topics { + self.encode_value(t, buf); + } + } + Statement::CodeCopy { + dest, + offset, + length, + } => { + buf.push(0x97); + self.encode_value(dest, buf); + self.encode_value(offset, buf); + self.encode_value(length, buf); + } + Statement::ExtCodeCopy { + address, + dest, + offset, + length, + } => { + buf.push(0x98); + self.encode_value(address, buf); + self.encode_value(dest, buf); + self.encode_value(offset, buf); + self.encode_value(length, buf); + } + Statement::ReturnDataCopy { + dest, + offset, + length, + } => { + buf.push(0x99); + self.encode_value(dest, buf); + self.encode_value(offset, buf); + self.encode_value(length, buf); + } + Statement::DataCopy { + dest, + offset, + length, + } => { + buf.push(0x9A); + self.encode_value(dest, buf); + self.encode_value(offset, buf); + self.encode_value(length, buf); + } + Statement::CallDataCopy { + dest, + offset, + length, + } => { + buf.push(0x9B); + self.encode_value(dest, buf); + self.encode_value(offset, buf); + self.encode_value(length, buf); + } + Statement::SetImmutable { key, value } => { + buf.push(0x9C); + buf.extend_from_slice(&(key.len() as u16).to_le_bytes()); + buf.extend_from_slice(key.as_bytes()); + self.encode_value(value, buf); + } + Statement::Leave { return_values } => { + buf.push(0x9D); + buf.push(return_values.len() as u8); + for v in return_values { + self.encode_value(v, buf); + } + } + Statement::Expression(expression) => { + buf.push(0x9E); + self.encode_expression(expression, buf); + } + Statement::SelfDestruct { address } => { + buf.push(0x9F); + self.encode_value(address, buf); + } + Statement::Break { values } => { + buf.push(0xA0); + buf.push(values.len() as u8); + for v in values { + self.encode_value(v, buf); + } + } + Statement::Continue { values } => { + buf.push(0xA1); + buf.push(values.len() as u8); + for v in values { + self.encode_value(v, buf); + } + } + } + } +} + +fn type_tag(value_type: &Type) -> u8 { + match value_type { + Type::Int(bit_width) => bitwidth_tag(*bit_width), + Type::Ptr(addr) => match addr { + crate::ir::AddressSpace::Heap => 0xE0, + crate::ir::AddressSpace::Stack => 0xE1, + crate::ir::AddressSpace::Storage => 0xE2, + crate::ir::AddressSpace::Code => 0xE3, + }, + Type::Void => 0xFF, + } +} + +fn bitwidth_tag(bit_width: BitWidth) -> u8 { + match bit_width { + BitWidth::I1 => 1, + BitWidth::I8 => 8, + BitWidth::I32 => 32, + BitWidth::I64 => 64, + BitWidth::I128 => 128, + BitWidth::I160 => 160, + BitWidth::I256 => 0, + } +} + +fn binop_tag(operation: BinaryOperation) -> u8 { + match operation { + BinaryOperation::Add => 0, + BinaryOperation::Sub => 1, + BinaryOperation::Mul => 2, + BinaryOperation::Div => 3, + BinaryOperation::SDiv => 4, + BinaryOperation::Mod => 5, + BinaryOperation::SMod => 6, + BinaryOperation::Exp => 7, + BinaryOperation::AddMod => 8, + BinaryOperation::MulMod => 9, + BinaryOperation::And => 10, + BinaryOperation::Or => 11, + BinaryOperation::Xor => 12, + BinaryOperation::Shl => 13, + BinaryOperation::Shr => 14, + BinaryOperation::Sar => 15, + BinaryOperation::Lt => 16, + BinaryOperation::Gt => 17, + BinaryOperation::Slt => 18, + BinaryOperation::Sgt => 19, + BinaryOperation::Eq => 20, + BinaryOperation::Byte => 21, + BinaryOperation::SignExtend => 22, + } +} + +fn unaryop_tag(operation: UnaryOperation) -> u8 { + match operation { + UnaryOperation::IsZero => 0, + UnaryOperation::Not => 1, + UnaryOperation::Clz => 2, + } +} + +fn region_tag(region: &crate::ir::MemoryRegion) -> u8 { + match region { + crate::ir::MemoryRegion::Scratch => 0, + crate::ir::MemoryRegion::FreePointerSlot => 1, + crate::ir::MemoryRegion::Dynamic => 2, + crate::ir::MemoryRegion::Unknown => 3, + } +} + +fn callkind_tag(kind: CallKind) -> u8 { + match kind { + CallKind::Call => 0, + CallKind::CallCode => 1, + CallKind::DelegateCall => 2, + CallKind::StaticCall => 3, + } +} + +fn createkind_tag(kind: crate::ir::CreateKind) -> u8 { + match kind { + crate::ir::CreateKind::Create => 0, + crate::ir::CreateKind::Create2 => 1, + } +} + +fn nullary_expr_tag(expression: &Expression) -> u8 { + match expression { + Expression::CallValue => 0x40, + Expression::Caller => 0x41, + Expression::Origin => 0x42, + Expression::CallDataSize => 0x43, + Expression::CodeSize => 0x44, + Expression::GasPrice => 0x45, + Expression::ReturnDataSize => 0x46, + Expression::Coinbase => 0x47, + Expression::Timestamp => 0x48, + Expression::Number => 0x49, + Expression::Difficulty => 0x4A, + Expression::GasLimit => 0x4B, + Expression::ChainId => 0x4C, + Expression::SelfBalance => 0x4D, + Expression::BaseFee => 0x4E, + Expression::BlobBaseFee => 0x4F, + Expression::Gas => 0x50, + Expression::MSize => 0x51, + Expression::Address => 0x52, + _ => 0x00, + } +} + +/// Maximum number of differing literal positions allowed for fuzzy dedup. +/// Each differing literal becomes a new i256 parameter, so keep this small. +const MAX_FUZZY_LITERAL_DIFFS: usize = 4; + +/// Minimum function size (in IR statements) for fuzzy dedup when any +/// differing-literal parameter is wider than `i64`. Wider new parameters +/// cost more to pass at every call site, so the function body needs to be +/// large enough that the dedup savings cover that overhead. +const MIN_FUZZY_DEDUP_SIZE: usize = 20; + +/// Minimum function size for fuzzy dedup when every differing-literal +/// parameter fits in `i64`. Cheap parameters tolerate smaller bodies because +/// the per-call overhead is a single push on the PolkaVM `rv64e` target. +const MIN_FUZZY_DEDUP_SIZE_NARROW_PARAMS: usize = 10; + +/// Deduplicates functions that are structurally identical except for literal constants. +/// +/// When two functions have the same structure but differ only in literal values, +/// the duplicate is removed and its call sites are redirected to the canonical +/// function with the differing literals passed as additional arguments. +/// +/// Returns the number of functions removed. +pub fn deduplicate_functions_fuzzy(object: &mut Object) -> usize { + if object.functions.len() < 2 { + return 0; + } + + let mut fuzzy_groups: BTreeMap, Vec> = BTreeMap::new(); + + for function in object.functions.values() { + if function.size_estimate < MIN_FUZZY_DEDUP_SIZE_NARROW_PARAMS { + continue; + } + + let fuzzy_hash = fuzzy_canonicalize_function(function); + fuzzy_groups + .entry(fuzzy_hash) + .or_default() + .push(function.id); + } + + let mut total_removed = 0; + let mut next_value_id = ValueId(object.find_max_value_id() + 1); + + for group in fuzzy_groups.values() { + if group.len() < 2 { + continue; + } + + let mut group_literals: Vec<(FunctionId, Vec)> = Vec::new(); + for &fid in group { + let function = &object.functions[&fid]; + let lits = collect_literals_ordered(function); + group_literals.push((fid, lits)); + } + + let lit_count = group_literals[0].1.len(); + if group_literals + .iter() + .any(|(_, lits)| lits.len() != lit_count) + { + continue; + } + + let mut differing_positions: Vec = Vec::new(); + for pos in 0..lit_count { + let first_val = &group_literals[0].1[pos]; + if group_literals + .iter() + .any(|(_, lits)| &lits[pos] != first_val) + { + differing_positions.push(pos); + } + } + + if differing_positions.is_empty() { + continue; + } + + let mut value_sig_to_group: BTreeMap>, Vec> = BTreeMap::new(); + for &pos in &differing_positions { + let sig: Vec> = group_literals + .iter() + .map(|(_, lits)| lits[pos].to_bytes_le()) + .collect(); + value_sig_to_group.entry(sig).or_default().push(pos); + } + + let unique_param_count = value_sig_to_group.len(); + if unique_param_count > MAX_FUZZY_LITERAL_DIFFS { + continue; + } + + let mut parameter_groups: Vec> = value_sig_to_group.into_values().collect(); + parameter_groups.sort_by_key(|g| g[0]); + let mut position_to_parameter_index: BTreeMap = BTreeMap::new(); + for (parameter_index, positions) in parameter_groups.iter().enumerate() { + for &pos in positions { + position_to_parameter_index.insert(pos, parameter_index); + } + } + + let canonical_id = group[0]; + let canonical_func = object.functions.get(&canonical_id).unwrap().clone(); + + let canonical_param_count = canonical_func.parameters.len(); + let canonical_returns = &canonical_func.returns; + let all_compatible = group.iter().skip(1).all(|&fid| { + let function = &object.functions[&fid]; + function.parameters.len() == canonical_param_count + && &function.returns == canonical_returns + && function + .parameters + .iter() + .zip(canonical_func.parameters.iter()) + .all(|((_, t1), (_, t2))| t1 == t2) + }); + if !all_compatible { + continue; + } + + let mut new_parameter_ids: Vec = Vec::new(); + for _ in 0..unique_param_count { + new_parameter_ids.push(next_value_id.fresh()); + } + + let position_parameter_ids: Vec<(usize, ValueId)> = differing_positions + .iter() + .map(|&pos| (pos, new_parameter_ids[position_to_parameter_index[&pos]])) + .collect(); + + let parameter_types: Vec = parameter_groups + .iter() + .map(|positions| { + let max_val = group_literals + .iter() + .flat_map(|(_, lits)| positions.iter().map(move |&p| lits[p].clone())) + .max() + .unwrap_or_else(BigUint::zero); + Type::Int(BitWidth::from_max_value(&max_val)) + }) + .collect(); + + let all_params_narrow = parameter_types + .iter() + .all(|t| matches!(t, Type::Int(width) if *width <= BitWidth::I64)); + let effective_min_size = if all_params_narrow { + MIN_FUZZY_DEDUP_SIZE_NARROW_PARAMS + } else { + MIN_FUZZY_DEDUP_SIZE + }; + if canonical_func.size_estimate < effective_min_size { + continue; + } + + let mut parameterized = canonical_func.clone(); + for (&vid, parameter_type) in new_parameter_ids.iter().zip(parameter_types.iter()) { + parameterized.parameters.push((vid, *parameter_type)); + } + + let canonical_lits = &group_literals[0].1; + + replace_literals_with_params(&mut parameterized.body, &position_parameter_ids); + + object.functions.insert(canonical_id, parameterized); + + let canonical_extra_args: Vec = parameter_groups + .iter() + .map(|positions| canonical_lits[positions[0]].clone()) + .collect(); + + for &fid in group { + let extra_args: Vec = if fid == canonical_id { + canonical_extra_args.clone() + } else { + let lits = &group_literals.iter().find(|(id, _)| *id == fid).unwrap().1; + parameter_groups + .iter() + .map(|positions| lits[positions[0]].clone()) + .collect() + }; + + update_call_sites_with_extra_args( + &mut object.code, + fid, + canonical_id, + &extra_args, + ¶meter_types, + &mut next_value_id, + ); + for function in object.functions.values_mut() { + update_call_sites_with_extra_args( + &mut function.body, + fid, + canonical_id, + &extra_args, + ¶meter_types, + &mut next_value_id, + ); + } + } + + for &fid in group.iter().skip(1) { + object.functions.remove(&fid); + total_removed += 1; + } + } + + total_removed +} + +/// Produces a fuzzy canonical form where literal values are replaced with +/// position indices. Two functions with the same fuzzy form are structurally +/// identical except for their literal constant values. +fn fuzzy_canonicalize_function(function: &crate::ir::Function) -> Vec { + let mut canon = Canonicalizer::new(); + let mut buf = Vec::new(); + + buf.push(function.parameters.len() as u8); + for (_, value_type) in &function.parameters { + buf.push(type_tag(value_type)); + } + buf.push(function.returns.len() as u8); + for value_type in &function.returns { + buf.push(type_tag(value_type)); + } + + for (parameter_id, _) in &function.parameters { + canon.get_or_insert(*parameter_id); + } + for rv in &function.return_values_initial { + canon.get_or_insert(*rv); + } + + let mut lit_counter = 0u32; + for statement in &function.body.statements { + fuzzy_encode_statement(&mut canon, statement, &mut buf, &mut lit_counter); + } + + buf.push(0xFE); + for rv in &function.return_values { + canon.encode_value_id(*rv, &mut buf); + } + + buf +} + +fn fuzzy_encode_expressionession( + canon: &mut Canonicalizer, + expression: &Expression, + buf: &mut Vec, + lit_counter: &mut u32, +) { + match expression { + Expression::Literal { value_type, .. } => { + buf.push(0x01); + buf.push(0xFF); + buf.extend_from_slice(&lit_counter.to_le_bytes()); + *lit_counter += 1; + buf.push(type_tag(value_type)); + } + Expression::Var(id) => { + buf.push(0x02); + canon.encode_value_id(*id, buf); + } + Expression::Binary { + operation, + lhs, + rhs, + } => { + buf.push(0x03); + buf.push(binop_tag(*operation)); + canon.encode_value(lhs, buf); + canon.encode_value(rhs, buf); + } + Expression::Ternary { operation, a, b, n } => { + buf.push(0x04); + buf.push(binop_tag(*operation)); + canon.encode_value(a, buf); + canon.encode_value(b, buf); + canon.encode_value(n, buf); + } + Expression::Unary { operation, operand } => { + buf.push(0x05); + buf.push(unaryop_tag(*operation)); + canon.encode_value(operand, buf); + } + Expression::Call { + function, + arguments, + } => { + buf.push(0x06); + buf.extend_from_slice(&function.0.to_le_bytes()); + buf.push(arguments.len() as u8); + for argument in arguments { + canon.encode_value(argument, buf); + } + } + Expression::SLoad { key, static_slot } => { + buf.push(0x12); + canon.encode_value(key, buf); + if static_slot.is_some() { + buf.push(1); + buf.push(0xFF); + buf.extend_from_slice(&lit_counter.to_le_bytes()); + *lit_counter += 1; + } else { + buf.push(0); + } + } + _ => { + canon.encode_expression(expression, buf); + } + } +} + +fn fuzzy_encode_statement( + canon: &mut Canonicalizer, + statement: &Statement, + buf: &mut Vec, + lit_counter: &mut u32, +) { + match statement { + Statement::Let { bindings, value } => { + buf.push(0x80); + buf.push(bindings.len() as u8); + for b in bindings { + canon.encode_value_id(*b, buf); + } + fuzzy_encode_expressionession(canon, value, buf, lit_counter); + } + Statement::SStore { + key, + value, + static_slot, + } => { + buf.push(0x84); + canon.encode_value(key, buf); + canon.encode_value(value, buf); + if static_slot.is_some() { + buf.push(1); + buf.push(0xFF); + buf.extend_from_slice(&lit_counter.to_le_bytes()); + *lit_counter += 1; + } else { + buf.push(0); + } + } + Statement::If { + condition, + inputs, + then_region, + else_region, + outputs, + } => { + buf.push(0x85); + canon.encode_value(condition, buf); + buf.push(inputs.len() as u8); + for v in inputs { + canon.encode_value(v, buf); + } + fuzzy_encode_region(canon, then_region, buf, lit_counter); + if let Some(r) = else_region { + buf.push(1); + fuzzy_encode_region(canon, r, buf, lit_counter); + } else { + buf.push(0); + } + buf.push(outputs.len() as u8); + for o in outputs { + canon.encode_value_id(*o, buf); + } + } + Statement::Switch { + scrutinee, + inputs, + cases, + default, + outputs, + } => { + buf.push(0x86); + canon.encode_value(scrutinee, buf); + buf.push(inputs.len() as u8); + for v in inputs { + canon.encode_value(v, buf); + } + buf.push(cases.len() as u8); + for c in cases { + buf.push(0xFF); + buf.extend_from_slice(&lit_counter.to_le_bytes()); + *lit_counter += 1; + fuzzy_encode_region(canon, &c.body, buf, lit_counter); + } + if let Some(d) = default { + buf.push(1); + fuzzy_encode_region(canon, d, buf, lit_counter); + } else { + buf.push(0); + } + buf.push(outputs.len() as u8); + for o in outputs { + canon.encode_value_id(*o, buf); + } + } + Statement::For { + initial_values, + loop_variables, + condition_statements, + condition, + body, + post, + outputs, + .. + } => { + buf.push(0x87); + buf.push(initial_values.len() as u8); + for v in initial_values { + canon.encode_value(v, buf); + } + buf.push(loop_variables.len() as u8); + for v in loop_variables { + canon.encode_value_id(*v, buf); + } + buf.push(condition_statements.len() as u8); + for s in condition_statements { + fuzzy_encode_statement(canon, s, buf, lit_counter); + } + fuzzy_encode_expressionession(canon, condition, buf, lit_counter); + fuzzy_encode_region(canon, body, buf, lit_counter); + fuzzy_encode_region(canon, post, buf, lit_counter); + buf.push(outputs.len() as u8); + for o in outputs { + canon.encode_value_id(*o, buf); + } + } + Statement::Block(region) => { + buf.push(0x88); + fuzzy_encode_region(canon, region, buf, lit_counter); + } + Statement::Expression(expression) => { + buf.push(0x89); + fuzzy_encode_expressionession(canon, expression, buf, lit_counter); + } + _ => { + canon.encode_statement(statement, buf); + } + } +} + +fn fuzzy_encode_region( + canon: &mut Canonicalizer, + region: &Region, + buf: &mut Vec, + lit_counter: &mut u32, +) { + buf.extend_from_slice(&(region.statements.len() as u32).to_le_bytes()); + for statement in ®ion.statements { + fuzzy_encode_statement(canon, statement, buf, lit_counter); + } + buf.push(region.yields.len() as u8); + for y in ®ion.yields { + canon.encode_value(y, buf); + } +} + +/// Collects all literal values from a function in walk order. Both this and +/// [`replace_literals_with_params`] must use the **identical** traversal so +/// position indices align — keep them in sync if either changes. +/// +/// Counted positions: `Expression::Literal` value, `Expression::SLoad::static_slot`, +/// `Statement::SStore::static_slot`, and each `Switch` case value. +fn collect_literals_ordered(function: &crate::ir::Function) -> Vec { + fn from_expr(expression: &Expression, lits: &mut Vec) { + match expression { + Expression::Literal { value, .. } => lits.push(value.clone()), + Expression::SLoad { + static_slot: Some(slot), + .. + } => lits.push(slot.clone()), + _ => {} + } + } + fn walk(statements: &[Statement], lits: &mut Vec) { + for statement in statements { + match statement { + Statement::Let { value, .. } | Statement::Expression(value) => { + from_expr(value, lits) + } + Statement::SStore { + static_slot: Some(slot), + .. + } => lits.push(slot.clone()), + Statement::If { + then_region, + else_region, + .. + } => { + walk(&then_region.statements, lits); + if let Some(r) = else_region { + walk(&r.statements, lits); + } + } + Statement::Switch { cases, default, .. } => { + for c in cases { + lits.push(c.value.clone()); + walk(&c.body.statements, lits); + } + if let Some(d) = default { + walk(&d.statements, lits); + } + } + Statement::For { + condition_statements, + condition, + body, + post, + .. + } => { + walk(condition_statements, lits); + from_expr(condition, lits); + walk(&body.statements, lits); + walk(&post.statements, lits); + } + Statement::Block(region) => walk(®ion.statements, lits), + _ => {} + } + } + } + let mut lits = Vec::new(); + walk(&function.body.statements, &mut lits); + lits +} + +/// Replaces literal values at differing positions with `Var` references to new +/// parameters. Walk order **must** match [`collect_literals_ordered`] so the +/// position indices align. +fn replace_literals_with_params(block: &mut Block, position_parameter_ids: &[(usize, ValueId)]) { + fn from_expr( + expression: &mut Expression, + positions: &BTreeMap, + counter: &mut usize, + ) { + match expression { + Expression::Literal { .. } => { + if let Some(¶meter_value_id) = positions.get(counter) { + *expression = Expression::Var(parameter_value_id); + } + *counter += 1; + } + Expression::SLoad { + static_slot: slot @ Some(_), + .. + } => { + if positions.contains_key(counter) { + *slot = None; + } + *counter += 1; + } + _ => {} + } + } + fn walk( + statements: &mut [Statement], + positions: &BTreeMap, + counter: &mut usize, + ) { + for statement in statements { + match statement { + Statement::Let { value, .. } | Statement::Expression(value) => { + from_expr(value, positions, counter) + } + Statement::SStore { + static_slot: slot @ Some(_), + .. + } => { + if positions.contains_key(counter) { + *slot = None; + } + *counter += 1; + } + Statement::If { + then_region, + else_region, + .. + } => { + walk(&mut then_region.statements, positions, counter); + if let Some(r) = else_region { + walk(&mut r.statements, positions, counter); + } + } + Statement::Switch { cases, default, .. } => { + for c in cases { + *counter += 1; + walk(&mut c.body.statements, positions, counter); + } + if let Some(d) = default { + walk(&mut d.statements, positions, counter); + } + } + Statement::For { + condition_statements, + condition, + body, + post, + .. + } => { + walk(condition_statements, positions, counter); + from_expr(condition, positions, counter); + walk(&mut body.statements, positions, counter); + walk(&mut post.statements, positions, counter); + } + Statement::Block(region) => walk(&mut region.statements, positions, counter), + _ => {} + } + } + } + let positions: BTreeMap = position_parameter_ids.iter().copied().collect(); + let mut counter = 0usize; + walk(&mut block.statements, &positions, &mut counter); +} + +/// Updates call sites in a block, changing calls to `old_id` into calls to +/// `new_id` with extra literal arguments appended. For each matching call, +/// emits one `Let` binding per extra argument immediately before the call site +/// (allocating fresh `ValueId`s through `next_value_id`). +fn update_call_sites_with_extra_args( + block: &mut Block, + old_id: FunctionId, + new_id: FunctionId, + extra_args: &[BigUint], + parameter_types: &[Type], + next_value_id: &mut ValueId, +) { + fn rewrite( + statements: &mut Vec, + old_id: FunctionId, + new_id: FunctionId, + extra_args: &[BigUint], + parameter_types: &[Type], + next_id: &mut ValueId, + ) { + let mut i = 0; + while i < statements.len() { + match &mut statements[i] { + Statement::If { + then_region, + else_region, + .. + } => { + rewrite( + &mut then_region.statements, + old_id, + new_id, + extra_args, + parameter_types, + next_id, + ); + if let Some(r) = else_region { + rewrite( + &mut r.statements, + old_id, + new_id, + extra_args, + parameter_types, + next_id, + ); + } + } + Statement::Switch { cases, default, .. } => { + for c in cases.iter_mut() { + rewrite( + &mut c.body.statements, + old_id, + new_id, + extra_args, + parameter_types, + next_id, + ); + } + if let Some(d) = default { + rewrite( + &mut d.statements, + old_id, + new_id, + extra_args, + parameter_types, + next_id, + ); + } + } + Statement::For { + condition_statements, + body, + post, + .. + } => { + rewrite( + condition_statements, + old_id, + new_id, + extra_args, + parameter_types, + next_id, + ); + rewrite( + &mut body.statements, + old_id, + new_id, + extra_args, + parameter_types, + next_id, + ); + rewrite( + &mut post.statements, + old_id, + new_id, + extra_args, + parameter_types, + next_id, + ); + } + Statement::Block(region) => { + rewrite( + &mut region.statements, + old_id, + new_id, + extra_args, + parameter_types, + next_id, + ); + } + _ => {} + } + let is_target = matches!(&statements[i], + Statement::Let { value: Expression::Call { function, .. }, .. } + | Statement::Expression(Expression::Call { function, .. }) + if *function == old_id); + if is_target { + let mut extra_values = Vec::with_capacity(extra_args.len()); + for (arg_val, parameter_type) in extra_args.iter().zip(parameter_types.iter()) { + let vid = next_id.fresh(); + statements.insert( + i, + Statement::Let { + bindings: vec![vid], + value: Expression::Literal { + value: arg_val.clone(), + value_type: *parameter_type, + }, + }, + ); + i += 1; + extra_values.push(Value { + id: vid, + value_type: *parameter_type, + }); + } + match &mut statements[i] { + Statement::Let { + value: + Expression::Call { + function, + arguments, + }, + .. + } + | Statement::Expression(Expression::Call { + function, + arguments, + }) => { + *function = new_id; + arguments.extend(extra_values); + } + _ => unreachable!("is_target check above just matched a Call"), + } + } + i += 1; + } + } + rewrite( + &mut block.statements, + old_id, + new_id, + extra_args, + parameter_types, + next_value_id, + ); +} + +/// Redirects function calls in a block, replacing old function IDs with new ones. +fn redirect_calls_in_block(block: &mut Block, redirects: &BTreeMap) { + for_each_statement_mut(&mut block.statements, &mut |statement| { + statement.for_each_expression_mut(&mut |expression| { + if let Expression::Call { function, .. } = expression { + if let Some(&new_id) = redirects.get(function) { + *function = new_id; + } + } + }); + }); +} + +/// Folds constant `Keccak256Single` and `Keccak256Pair` expressions in an object. +/// +/// This is a targeted pass designed to run after the mem_opt pass, which creates +/// `Keccak256Single`/`Keccak256Pair` nodes from `mstore + keccak256` patterns. +/// When the argument(s) are compile-time constants, the hash is precomputed. +pub fn fold_constant_keccak(object: &mut Object) { + fold_keccak_in_block(&mut object.code); + for function in object.functions.values_mut() { + fold_keccak_in_block(&mut function.body); + } +} + +/// Walks a block's statements and folds constant keccak256 expressions. +fn fold_keccak_in_block(block: &mut Block) { + let mut constants: BTreeMap = BTreeMap::new(); + fold_keccak_in_stmts(&mut block.statements, &mut constants); +} + +/// Processes statements, tracking constants and folding keccak expressions. +fn fold_keccak_in_stmts(statements: &mut [Statement], constants: &mut BTreeMap) { + for statement in statements.iter_mut() { + match statement { + Statement::Let { + bindings, + value: expression, + } => { + if bindings.len() == 1 { + if let Expression::Literal { value, .. } = expression { + constants.insert(bindings[0].0, value.clone()); + } + } + + match expression { + Expression::Keccak256Single { word0 } => { + if let Some(c) = constants.get(&word0.id.0) { + *expression = Expression::Literal { + value: fold_keccak256_single(c), + value_type: Type::Int(BitWidth::I256), + }; + } + } + Expression::Keccak256Pair { word0, word1 } => { + if let (Some(c0), Some(c1)) = + (constants.get(&word0.id.0), constants.get(&word1.id.0)) + { + let c0 = c0.clone(); + let c1 = c1.clone(); + *expression = Expression::Literal { + value: fold_keccak256_pair(&c0, &c1), + value_type: Type::Int(BitWidth::I256), + }; + } + } + _ => {} + } + + if bindings.len() == 1 { + if let Expression::Literal { value, .. } = expression { + constants.insert(bindings[0].0, value.clone()); + } + } + } + Statement::If { + then_region, + else_region, + .. + } => { + fold_keccak_in_stmts(&mut then_region.statements, &mut constants.clone()); + if let Some(r) = else_region { + fold_keccak_in_stmts(&mut r.statements, &mut constants.clone()); + } + } + Statement::Switch { cases, default, .. } => { + for case in cases.iter_mut() { + fold_keccak_in_stmts(&mut case.body.statements, &mut constants.clone()); + } + if let Some(d) = default { + fold_keccak_in_stmts(&mut d.statements, &mut constants.clone()); + } + } + Statement::For { + condition_statements, + body, + post, + .. + } => { + fold_keccak_in_stmts(condition_statements, constants); + fold_keccak_in_stmts(&mut body.statements, &mut constants.clone()); + fold_keccak_in_stmts(&mut post.statements, &mut constants.clone()); + } + Statement::Block(region) => { + fold_keccak_in_stmts(&mut region.statements, &mut constants.clone()); + } + _ => {} + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn make_let_literal(id: u32, value: u64) -> Statement { + Statement::Let { + bindings: vec![ValueId(id)], + value: Expression::Literal { + value: BigUint::from(value), + value_type: Type::Int(BitWidth::I256), + }, + } + } + + fn make_let_binop(id: u32, operation: BinaryOperation, lhs_id: u32, rhs_id: u32) -> Statement { + Statement::Let { + bindings: vec![ValueId(id)], + value: Expression::Binary { + operation, + lhs: Value::int(ValueId(lhs_id)), + rhs: Value::int(ValueId(rhs_id)), + }, + } + } + + #[test] + fn test_constant_fold_add() { + let result = fold_binary( + BinaryOperation::Add, + &BigUint::from(100u64), + &BigUint::from(200u64), + ); + assert_eq!(result, Some(BigUint::from(300u64))); + } + + #[test] + fn test_constant_fold_sub_wrap() { + let result = fold_binary( + BinaryOperation::Sub, + &BigUint::from(0u64), + &BigUint::from(1u64), + ); + assert_eq!(result, Some(max_u256())); + } + + #[test] + fn test_constant_fold_mul() { + let result = fold_binary( + BinaryOperation::Mul, + &BigUint::from(7u64), + &BigUint::from(6u64), + ); + assert_eq!(result, Some(BigUint::from(42u64))); + } + + #[test] + fn test_constant_fold_div_by_zero() { + let result = fold_binary( + BinaryOperation::Div, + &BigUint::from(100u64), + &BigUint::zero(), + ); + assert_eq!(result, Some(BigUint::zero())); + } + + #[test] + fn test_constant_fold_comparisons() { + assert_eq!( + fold_binary( + BinaryOperation::Lt, + &BigUint::from(5u64), + &BigUint::from(10u64) + ), + Some(BigUint::one()) + ); + assert_eq!( + fold_binary( + BinaryOperation::Lt, + &BigUint::from(10u64), + &BigUint::from(5u64) + ), + Some(BigUint::zero()) + ); + assert_eq!( + fold_binary( + BinaryOperation::Eq, + &BigUint::from(42u64), + &BigUint::from(42u64) + ), + Some(BigUint::one()) + ); + } + + #[test] + fn test_constant_fold_bitwise() { + assert_eq!( + fold_binary( + BinaryOperation::And, + &BigUint::from(0xFF00u64), + &BigUint::from(0x0FF0u64) + ), + Some(BigUint::from(0x0F00u64)) + ); + assert_eq!( + fold_binary( + BinaryOperation::Or, + &BigUint::from(0xFF00u64), + &BigUint::from(0x00FFu64) + ), + Some(BigUint::from(0xFFFFu64)) + ); + } + + #[test] + fn test_constant_fold_shifts() { + assert_eq!( + fold_binary( + BinaryOperation::Shl, + &BigUint::from(8u64), + &BigUint::from(1u64) + ), + Some(BigUint::from(256u64)) + ); + assert_eq!( + fold_binary( + BinaryOperation::Shr, + &BigUint::from(4u64), + &BigUint::from(256u64) + ), + Some(BigUint::from(16u64)) + ); + } + + #[test] + fn test_unary_fold() { + assert_eq!( + fold_unary(UnaryOperation::IsZero, &BigUint::zero()), + Some(BigUint::one()) + ); + assert_eq!( + fold_unary(UnaryOperation::IsZero, &BigUint::from(42u64)), + Some(BigUint::zero()) + ); + assert_eq!( + fold_unary(UnaryOperation::Not, &BigUint::zero()), + Some(max_u256()) + ); + } + + #[test] + fn test_simplifier_constant_propagation() { + let mut simplifier = Simplifier::new(); + + let statements = vec![ + make_let_literal(1, 10), + make_let_literal(2, 20), + make_let_binop(3, BinaryOperation::Add, 1, 2), + Statement::Return { + offset: Value::int(ValueId(3)), + length: Value::int(ValueId(3)), + }, + ]; + + let block = &mut Block { statements }; + simplifier.simplify_block(block); + + let v3_let = block.statements.iter().find( + |s| matches!(s, Statement::Let { bindings, .. } if bindings.contains(&ValueId(3))), + ); + let v3_let = v3_let.expect("v3 should still exist"); + if let Statement::Let { value, .. } = v3_let { + if let Expression::Literal { value, .. } = value { + assert_eq!(*value, BigUint::from(30u64)); + } else { + panic!("Expected literal after constant folding, got: {value:?}"); + } + } + } + + #[test] + fn test_simplifier_algebraic_identity_add_zero() { + let mut simplifier = Simplifier::new(); + + let statements = vec![ + make_let_literal(1, 0), + Statement::Let { + bindings: vec![ValueId(2)], + value: Expression::Binary { + operation: BinaryOperation::Add, + lhs: Value::int(ValueId(99)), + rhs: Value::int(ValueId(1)), + }, + }, + Statement::Return { + offset: Value::int(ValueId(2)), + length: Value::int(ValueId(2)), + }, + ]; + + let block = &mut Block { statements }; + simplifier.simplify_block(block); + + let v2_let = block.statements.iter().find( + |s| matches!(s, Statement::Let { bindings, .. } if bindings.contains(&ValueId(2))), + ); + let v2_let = v2_let.expect("v2 should still exist"); + if let Statement::Let { value, .. } = v2_let { + match value { + Expression::Var(id) => assert_eq!(id.0, 99), + _ => panic!("Expected Var after algebraic simplification, got: {value:?}"), + } + } + assert!(simplifier.statistics.identities_simplified > 0); + } + + #[test] + fn test_no_crash_on_unused_bindings() { + let mut simplifier = Simplifier::new(); + + let statements = vec![ + make_let_literal(1, 42), + make_let_literal(2, 100), + Statement::Return { + offset: Value::int(ValueId(2)), + length: Value::int(ValueId(2)), + }, + ]; + + let block = &mut Block { statements }; + simplifier.simplify_block(block); + + assert_eq!(block.statements.len(), 3); + } + + #[test] + fn test_copy_propagation() { + let mut simplifier = Simplifier::new(); + + let statements = vec![ + make_let_literal(1, 42), + Statement::Let { + bindings: vec![ValueId(2)], + value: Expression::Var(ValueId(1)), + }, + Statement::Return { + offset: Value::int(ValueId(2)), + length: Value::int(ValueId(2)), + }, + ]; + + let block = &mut Block { statements }; + simplifier.simplify_block(block); + + if let Statement::Return { offset, .. } = &block.statements[block.statements.len() - 1] { + assert!( + offset.id.0 == 1 + || matches!(block.statements.last(), Some(Statement::Return { .. })) + ); + } + } + + #[test] + fn test_ternary_fold() { + let result = fold_ternary( + BinaryOperation::AddMod, + &BigUint::from(10u64), + &BigUint::from(20u64), + &BigUint::from(7u64), + ); + assert_eq!(result, Some(BigUint::from(2u64))); + + let result = fold_ternary( + BinaryOperation::MulMod, + &BigUint::from(5u64), + &BigUint::from(7u64), + &BigUint::from(6u64), + ); + assert_eq!(result, Some(BigUint::from(5u64))); + + let result = fold_ternary( + BinaryOperation::AddMod, + &BigUint::from(10u64), + &BigUint::from(20u64), + &BigUint::zero(), + ); + assert_eq!(result, Some(BigUint::zero())); + } + + #[test] + fn test_exp_fold() { + let result = fold_binary( + BinaryOperation::Exp, + &BigUint::from(2u64), + &BigUint::from(10u64), + ); + assert_eq!(result, Some(BigUint::from(1024u64))); + } + + #[test] + fn test_byte_fold() { + let result = fold_binary( + BinaryOperation::Byte, + &BigUint::from(31u64), + &BigUint::from(0xFFu64), + ); + assert_eq!(result, Some(BigUint::from(0xFFu64))); + + let result = fold_binary( + BinaryOperation::Byte, + &BigUint::from(0u64), + &BigUint::from(0xFFu64), + ); + assert_eq!(result, Some(BigUint::zero())); + } +} diff --git a/crates/newyork/src/ssa.rs b/crates/newyork/src/ssa.rs new file mode 100644 index 000000000..d44916cee --- /dev/null +++ b/crates/newyork/src/ssa.rs @@ -0,0 +1,163 @@ +//! SSA conversion utilities for the newyork IR. +//! +//! This module provides the SSA builder that tracks variable definitions +//! and handles phi-node insertion for control flow joins. + +use crate::ir::{Type, Value, ValueId}; +use std::collections::BTreeMap; + +/// SSA builder that tracks variable definitions and creates fresh value IDs. +#[derive(Debug)] +pub struct SsaBuilder { + /// Next value ID to allocate. + next_value_id: ValueId, + /// Current scope's variable bindings: variable name -> SSA value. + current_scope: BTreeMap, + /// Stack of saved scopes for nested blocks. + scope_stack: Vec>, +} + +impl Default for SsaBuilder { + fn default() -> Self { + Self::new() + } +} + +impl SsaBuilder { + /// Creates a new SSA builder. + pub fn new() -> Self { + SsaBuilder { + next_value_id: ValueId(0), + current_scope: BTreeMap::new(), + scope_stack: Vec::new(), + } + } + + /// Allocates a fresh value ID. + pub fn fresh_id(&mut self) -> ValueId { + self.next_value_id.fresh() + } + + /// Allocates a fresh typed value with the given type. + pub fn fresh_typed_value(&mut self, value_type: Type) -> Value { + Value::new(self.fresh_id(), value_type) + } + + /// Declares a new variable in the current scope. + /// + /// Panics if a binding for `name` already exists in the current scope. + pub fn declare(&mut self, name: &str, value: Value) { + assert!( + !self.current_scope.contains_key(name), + "ICE: SsaBuilder::declare called for already-declared variable `{name}`", + ); + self.current_scope.insert(name.to_string(), value); + } + + /// Assigns a new value to an existing variable in the current scope. + /// + /// Panics if no binding for `name` exists in the current scope. + pub fn assign(&mut self, name: &str, value: Value) { + assert!( + self.current_scope.contains_key(name), + "ICE: SsaBuilder::assign called for undeclared variable `{name}`", + ); + self.current_scope.insert(name.to_string(), value); + } + + /// Looks up a variable by name, returning its current SSA value. + pub fn lookup(&self, name: &str) -> Option { + self.current_scope.get(name).copied() + } + + /// Enters a new scope, saving the current scope. + pub fn enter_scope(&mut self) { + self.scope_stack.push(self.current_scope.clone()); + } + + /// Exits the current scope, restoring the previous scope. + /// Returns the scope that was exited (for computing modified variables). + pub fn exit_scope(&mut self) -> BTreeMap { + let exited = std::mem::take(&mut self.current_scope); + self.current_scope = self.scope_stack.pop().unwrap_or_else(|| { + panic!( + "ICE: SsaBuilder::exit_scope called without a matching enter_scope; \ + {} binding(s) about to be silently dropped: {:?}", + exited.len(), + exited.keys().collect::>(), + ) + }); + exited + } + + /// Gets the current scope (for computing modified variables). + pub fn current_scope(&self) -> &BTreeMap { + &self.current_scope + } + + /// Restores scope from a saved state, used after control flow constructs. + pub fn restore_scope(&mut self, scope: BTreeMap) { + self.current_scope = scope; + } + + /// Gets the next value ID that will be allocated (for planning). + pub fn peek_next_id(&self) -> ValueId { + self.next_value_id + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::ir::BitWidth; + + #[test] + fn test_fresh_values() { + let mut builder = SsaBuilder::new(); + let v0 = builder.fresh_id(); + let v1 = builder.fresh_id(); + assert_eq!(v0.0, 0); + assert_eq!(v1.0, 1); + } + + #[test] + fn test_declare_and_lookup() { + let mut builder = SsaBuilder::new(); + let v = builder.fresh_typed_value(Type::Int(BitWidth::I256)); + builder.declare("x", v); + assert_eq!(builder.lookup("x"), Some(v)); + assert_eq!(builder.lookup("y"), None); + } + + #[test] + fn test_nested_scopes() { + let mut builder = SsaBuilder::new(); + let v0 = builder.fresh_typed_value(Type::Int(BitWidth::I256)); + builder.declare("x", v0); + + builder.enter_scope(); + let v1 = builder.fresh_typed_value(Type::Int(BitWidth::I256)); + builder.assign("x", v1); + assert_eq!(builder.lookup("x"), Some(v1)); + + builder.exit_scope(); + assert_eq!(builder.lookup("x"), Some(v0)); + } + + #[test] + #[should_panic(expected = "ICE: SsaBuilder::declare called for already-declared variable")] + fn declare_twice_panics() { + let mut builder = SsaBuilder::new(); + let v = builder.fresh_typed_value(Type::Int(BitWidth::I256)); + builder.declare("x", v); + builder.declare("x", v); + } + + #[test] + #[should_panic(expected = "ICE: SsaBuilder::assign called for undeclared variable")] + fn assign_undeclared_panics() { + let mut builder = SsaBuilder::new(); + let v = builder.fresh_typed_value(Type::Int(BitWidth::I256)); + builder.assign("x", v); + } +} diff --git a/crates/newyork/src/to_llvm.rs b/crates/newyork/src/to_llvm.rs new file mode 100644 index 000000000..b0b6e2ef0 --- /dev/null +++ b/crates/newyork/src/to_llvm.rs @@ -0,0 +1,6960 @@ +//! LLVM code generation for the newyork IR. +//! +//! Translates newyork IR to LLVM IR via inkwell, reusing the PolkaVM context +//! infrastructure from revive-llvm-context. + +use std::collections::{BTreeMap, BTreeSet}; + +use inkwell::types::BasicType; +use inkwell::values::{AnyValue, BasicValue, BasicValueEnum, IntValue}; +use num::{ToPrimitive, Zero}; +use revive_llvm_context::{ + PolkaVMArgument, PolkaVMContext, PolkaVMFunctionDeployCode, PolkaVMFunctionRuntimeCode, + PolkaVMMemoryEffect, +}; + +use crate::heap_opt::HeapOptResults; +use crate::ir::{ + BinaryOperation, BitWidth, Block, CallKind, CreateKind, Expression, Function, FunctionId, + MemoryRegion, Object, Region, Statement, Type, UnaryOperation, Value, ValueId, +}; +use crate::type_inference::TypeInference; + +/// Error type for LLVM codegen. +#[derive(Debug, thiserror::Error)] +pub enum CodegenError { + #[error("LLVM error: {0}")] + Llvm(String), + + #[error("Undefined value: {0:?}")] + UndefinedValue(ValueId), + + #[error("Undefined function: {0:?}")] + UndefinedFunction(FunctionId), + + #[error("Type mismatch: expected {expected}, got {actual}")] + TypeMismatch { expected: String, actual: String }, + + #[error("{0}")] + Unsupported(String), +} + +impl From for CodegenError { + fn from(err: anyhow::Error) -> Self { + CodegenError::Llvm(err.to_string()) + } +} + +/// Result type for codegen operations. +pub type Result = std::result::Result; + +/// Attaches the standard `noinline` + `minsize` pair to an outlined helper. +fn add_noinline_minsize_attrs<'ctx>( + context: &PolkaVMContext<'ctx>, + function: inkwell::values::FunctionValue<'ctx>, +) { + let noinline_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoInline as u32, 0); + let minsize_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::MinSize as u32, 0); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, noinline_attr); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, minsize_attr); +} + +/// Attaches the named `memory(...)` effect to an outlined helper. +fn add_memory_effect_attr<'ctx>( + context: &PolkaVMContext<'ctx>, + function: inkwell::values::FunctionValue<'ctx>, + effect: PolkaVMMemoryEffect, +) { + let Some(encoding) = effect.encoding() else { + return; + }; + let attr = context.llvm().create_enum_attribute( + revive_llvm_context::PolkaVMAttribute::Memory as u32, + encoding, + ); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, attr); +} + +/// Mode for native memory operations. +/// +/// Controls how MLoad/MStore are lowered to LLVM IR: +/// - `AllNative`: All memory accesses are native-safe; use native runtime functions +/// - `InlineNative`: This specific access is native-safe; use inline native code +/// (avoids needing native runtime function declarations in subobjects) +/// - `InlineByteSwap`: Constant offset needing BE; inline byte-swap without sbrk. +/// This lets LLVM fold constant-value byte-swaps at compile time and exposes +/// store-to-load forwarding opportunities that function calls hide. +/// - `ByteSwap`: Must use byte-swapping via shared runtime function (includes sbrk). +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum NativeMemoryMode { + /// All accesses safe. Use native runtime function calls. + AllNative, + /// This access is safe but others need byte-swapping. Use inline native code. + InlineNative, + /// Constant offset; inline byte-swap with unchecked GEP (no sbrk). + InlineByteSwap, + /// Must byte-swap for EVM compatibility (dynamic offsets needing sbrk). + ByteSwap, +} + +/// Functions with size_estimate at or above this threshold get NoInline when our +/// IR-level pass decided not to inline them. This prevents LLVM from undoing the +/// decision by inlining a large body either at every call site (multi-call) or at +/// the single site (single-call, where LLVM's MinSize-aware inliner still pulls +/// in bodies that don't amortize the saved call-instruction overhead on PolkaVM). +/// Empirical sweep on the OZ corpus settled on 91 — vs. 50: +591 bytes, vs. 100: +/// +1,481 bytes. +const LARGE_FUNCTION_NOINLINE_THRESHOLD: usize = 91; + +/// Functions with size_estimate at or below this threshold get AlwaysInline when no +/// IR-level decision was made. Very small functions benefit from inlining. +const SMALL_FUNCTION_ALWAYSINLINE_THRESHOLD: usize = 8; + +/// Solidity convention: the free memory pointer is stored at this heap offset. +const FREE_MEMORY_POINTER_SLOT: u64 = 0x40; + +/// Default initial value of the free memory pointer — the start of the dynamic +/// heap region above Solidity's scratch space and the FMP slot itself. +const DYNAMIC_HEAP_BASE: u64 = 0x80; + +/// Length in bytes of an EVM ABI function selector. +const ABI_SELECTOR_LENGTH: u64 = 4; + +/// Byte offset (inside an `Error(string)` ABI-encoded revert payload, relative to +/// the start of the payload) at which the string length word is stored. +/// Equals `selector (4) + offset word (32)`. +const ERROR_STRING_LENGTH_FIELD_OFFSET: u64 = + ABI_SELECTOR_LENGTH + revive_common::BYTE_LENGTH_WORD as u64; + +/// Byte offset (inside an `Error(string)` ABI-encoded revert payload, relative to +/// the start of the payload) at which the first string-data word begins. +/// Equals `selector (4) + offset word (32) + length word (32)`. +const ERROR_STRING_FIRST_DATA_WORD_OFFSET: u64 = + ABI_SELECTOR_LENGTH + 2 * revive_common::BYTE_LENGTH_WORD as u64; + +/// LLVM code generator for newyork IR. +/// Tracks phi nodes at the continue-landing block of a for loop. +/// These phi nodes merge values from the body's normal exit and from continue sites. +struct ForLoopPostPhis<'ctx> { + /// Phi nodes at the continue-landing block, one per body yield. + /// The phi merges body-end values with continue-site values. + phis: Vec>, + /// The loop-carried variable phi values (from the cond phi nodes). + /// Used as fallback values when continue is taken before a body yield is defined. + loop_var_phi_values: Vec>, +} + +/// Tracks phi nodes at the join block of a for loop. +/// These merge values from the normal loop exit (condition false) and break sites. +struct ForLoopBreakPhis<'ctx> { + /// Phi nodes at the join block, one per loop-carried variable. + phis: Vec>, + /// The loop-carried variable phi values (from the cond phi nodes). + /// Used as fallback values when break is taken before a body yield is defined. + loop_var_phi_values: Vec>, +} + +pub struct LlvmCodegen<'ctx> { + /// Value table: maps IR ValueId to LLVM value. + values: BTreeMap>, + /// Function table: maps IR FunctionId to function name. + function_names: BTreeMap, + /// Function parameter types: maps IR FunctionId to parameter types. + /// Used by call sites to match argument types to narrowed parameter types. + function_param_types: BTreeMap>, + /// Function return types: maps IR FunctionId to return types. + /// Used by call sites to zero-extend narrow return values back to i256. + function_return_types: BTreeMap>, + /// Return types of the currently generating function. + /// Set during `generate_function` and used by `Leave` codegen. + current_return_types: Vec, + /// Set of function names that have already been generated. + /// This is used to avoid regenerating shared utility functions in multi-contract scenarios. + generated_functions: BTreeSet, + /// Heap optimization results for skipping byte-swapping on internal memory. + heap_opt: HeapOptResults, + /// Type inference results for using narrower types. + type_info: TypeInference, + /// Inline decisions from our IR-level inliner. + /// Used to guide LLVM's inliner for functions that couldn't be inlined at IR level. + inline_decisions: BTreeMap, + /// Stack of for-loop post-block phi info, for continue to contribute values. + for_loop_post_phis: Vec>, + /// Stack of for-loop join-block phi info, for break to contribute values. + for_loop_break_phis: Vec>, + /// Shared basic blocks for `revert(0, K)` patterns (keyed by constant length K). + /// Each block contains the full exit sequence for that revert pattern. + /// Created on first use within each entry point function (deploy/runtime). + revert_blocks: BTreeMap>, + /// Shared basic blocks for `return(offset, length)` patterns where both are constants. + /// Keyed by `(offset, length)` pair. Created on first use within each entry point. + return_blocks: BTreeMap<(u64, u64), inkwell::basic_block::BasicBlock<'ctx>>, + /// Shared basic blocks for Solidity panic revert patterns (keyed by error code). + /// Each block stores the Panic(uint256) ABI encoding and branches to revert(0, 0x24). + panic_blocks: BTreeMap>, + /// Whether to use the outlined `__revive_callvalue()` runtime function. + /// True when the contract has enough callvalue sites for outlining to pay off. + use_outlined_callvalue: bool, + /// Whether to use the outlined `__revive_calldataload()` runtime function. + /// True when the contract has enough calldataload sites for outlining to pay off. + use_outlined_calldataload: bool, + /// Whether to use the outlined `__revive_caller()` runtime function. + /// True when the contract has enough caller sites for outlining to pay off. + use_outlined_caller: bool, + /// Whether to use the outlined `__revive_store_low_word_checked()` + /// helper. True only when the contract has enough constant-value + /// MStore sites whose value fits in i64 to amortise the helper's + /// body overhead — the per-call savings are ~3 PVM instructions and + /// the body costs ~25 bytes, so the break-even is around 8 sites. + use_outlined_store_low_word: bool, + /// Whether to use the outlined `__revive_store_high_word_checked()` + /// helper for `shl(224, sel)` ABI selector patterns. Same break-even + /// logic as low-word. + use_outlined_store_high_word: bool, + /// Set of ValueIds that are bound to `Expression::CallValue`. + /// When these are used as If conditions, we emit `__revive_callvalue_nonzero()` + /// returning i1 instead of the full i256 value + comparison. + callvalue_value_ids: BTreeSet, + /// Set of callvalue ValueIds that are ONLY used in callvalue_check patterns. + /// These bindings can be skipped entirely during codegen because the outlined + /// __revive_callvalue_check() function handles reading callvalue internally. + dead_callvalue_ids: BTreeSet, + /// Cache of global constants for i256 storage keys. + /// Maps the string representation of the constant to the global's pointer value. + /// This avoids materializing the same 256-bit constant at every storage access site. + storage_key_globals: BTreeMap>, + /// Map from validator function id to the asserted-fits-in mask. + /// Populated at the start of `generate_object`. Used to emit + /// `llvm.assume(value u<= MASK)` after each call to a validator so + /// downstream InstCombine can fold the redundant `and(value, MASK)` + /// the Solidity emitter places at every caller's post-validator use. + validator_masks: BTreeMap, + + /// Cache of outlined keccak256 slot wrapper functions. + /// Maps the constant slot hash string to the wrapper `FunctionValue`. + /// Each wrapper is `noinline (i256) -> i256` calling `__revive_keccak256_two_words(word0, CONST)`. + keccak256_slot_wrappers: BTreeMap>, + /// Outlined `__revive_mapping_sload(i256 key, i256 slot) -> i256` function. + /// Combines keccak256_pair + sload into one function, eliminating redundant bswaps. + mapping_sload_fn: Option>, + /// Outlined `__revive_mapping_sstore(i256 key, i256 slot, i256 value)` function. + /// Combines keccak256_pair + sstore into one function, eliminating redundant bswaps. + mapping_sstore_fn: Option>, + /// Whether to use outlined mapping_sload function (enough call sites to amortize overhead). + use_outlined_mapping_sload: bool, + /// Whether to use outlined mapping_sstore function (enough call sites to amortize overhead). + use_outlined_mapping_sstore: bool, + /// Whether the contract uses `msize()`. When false, InlineNative stores + /// can skip the `ensure_heap_size` watermark update. + has_msize: bool, + /// Cache of outlined error string revert functions. + /// Keyed by number of data words (1, 2, 3, etc.). + /// Each function is `noreturn (i256 length, i256 word0, ...) -> void`. + error_string_revert_fns: BTreeMap>, + /// Number of ErrorStringRevert sites per data-word count. + /// Used to decide: outline (>= 2 sites) vs inline (1 site). + error_string_revert_counts: BTreeMap, + /// Cache of outlined custom error revert functions. + /// Keyed by num_args. The selector is passed as the first parameter. + custom_error_revert_fns: BTreeMap>, + /// Number of CustomErrorRevert sites per num_args. + custom_error_revert_counts: BTreeMap, + /// Outlined `__revive_bswap256(i256) -> i256` function. + /// Wraps llvm.bswap.i256 into a noinline function to share the byte-swap + /// Cached outlined store_bswap function: void(i32 offset, i256 value). + /// Uses unchecked GEP + 4× bswap.i64 + store. Avoids inlining the bswap + /// sequence at every call site for variable values. + store_bswap_fn: Option>, + /// Cached store_bswap with bounds check: void(i32 offset, i256 value). + /// Like store_bswap but adds `offset + 32 <= heap_size` check before unchecked GEP. + /// Used for dynamic-offset ByteSwap stores in non-msize contracts to avoid sbrk. + store_bswap_checked_fn: Option>, + /// Cached load_bswap with bounds check: i256(i32 offset). + /// Adds `offset + 32 <= heap_size` check before unchecked GEP + bswap load. + /// Used for dynamic-offset ByteSwap loads in non-msize contracts to avoid sbrk. + load_bswap_checked_fn: Option>, + /// Cached exit with bounds check: void(i32 flags, i32 offset, i32 length). + /// Checks `offset + length <= heap_size` before unchecked GEP + seal_return. + /// Used for dynamic return/revert in non-msize contracts to avoid sbrk. + exit_checked_fn: Option>, + /// Cached outlined callvalue check + revert function. + /// Checks if callvalue is nonzero and reverts with empty data if so. + callvalue_check_fn: Option>, + /// Cached outlined storage load by value: i256(i256 key). + /// Takes key as i256 value (not pointer), internally bswaps + alloca + syscall. + /// Eliminates alloca+store at each call site for runtime-computed keys. + sload_word_fn: Option>, + /// Cached outlined storage store by value: void(i256 key, i256 value). + /// Takes key and value as i256 values, internally bswaps + alloca + syscall. + /// Eliminates alloca+store at each call site for runtime-computed keys/values. + sstore_word_fn: Option>, + /// Cached outlined zero store with bounds check: void(i32 offset). + /// Stores 32 zero bytes at heap+offset. Used for constant-zero MStore + /// in ByteSwap mode to avoid passing an i256 zero parameter. + store_zero_checked_fn: Option>, + /// Cached outlined low-word store with bounds check: + /// `void(i32 offset, i64 value)`. Stores zero in the high 24 bytes of + /// the slot and `bswap(value)` in the last 8 bytes (BE encoding of a + /// value that fits in i64). Used for ByteSwap MStore with a + /// compile-time constant whose high 192 bits are zero — avoids passing + /// an i256 (4 register pairs) when an i64 (2 register pairs) suffices, + /// and shrinks the function body from 4× shift+trunc+bswap+store down + /// to 3 zero stores + one bswap+store. + store_low_word_checked_fn: Option>, + /// Cached outlined high-word store with bounds check: + /// `void(i32 offset, i32 selector)`. Used for the canonical Solidity + /// ABI mstore pattern `shl(224, sel)` — value's low 224 bits are zero, + /// only the top 4 bytes carry the selector. Body stores 32 zero bytes + /// then overwrites the first 4 bytes with the bswapped selector. + store_high_word_checked_fn: Option>, + /// Cached outlined return word: noreturn void(i32 offset, i256 value). + /// Combines store_bswap_checked + exit_checked for single-word returns. + /// Bswap-stores value at offset, then seal_returns 32 bytes. + return_word_fn: Option>, +} + +impl<'ctx> LlvmCodegen<'ctx> { + /// Creates a new code generator with optimization results. + pub fn new( + heap_opt: HeapOptResults, + type_info: TypeInference, + inline_decisions: BTreeMap, + ) -> Self { + LlvmCodegen { + values: BTreeMap::new(), + function_names: BTreeMap::new(), + function_param_types: BTreeMap::new(), + function_return_types: BTreeMap::new(), + current_return_types: Vec::new(), + generated_functions: BTreeSet::new(), + heap_opt, + type_info, + inline_decisions, + for_loop_post_phis: Vec::new(), + for_loop_break_phis: Vec::new(), + revert_blocks: BTreeMap::new(), + return_blocks: BTreeMap::new(), + panic_blocks: BTreeMap::new(), + use_outlined_callvalue: false, + use_outlined_calldataload: false, + use_outlined_caller: false, + use_outlined_store_low_word: false, + use_outlined_store_high_word: false, + callvalue_value_ids: BTreeSet::new(), + dead_callvalue_ids: BTreeSet::new(), + storage_key_globals: BTreeMap::new(), + validator_masks: BTreeMap::new(), + keccak256_slot_wrappers: BTreeMap::new(), + has_msize: false, + error_string_revert_fns: BTreeMap::new(), + error_string_revert_counts: BTreeMap::new(), + custom_error_revert_fns: BTreeMap::new(), + custom_error_revert_counts: BTreeMap::new(), + store_bswap_fn: None, + store_bswap_checked_fn: None, + load_bswap_checked_fn: None, + exit_checked_fn: None, + callvalue_check_fn: None, + sload_word_fn: None, + sstore_word_fn: None, + store_zero_checked_fn: None, + store_low_word_checked_fn: None, + store_high_word_checked_fn: None, + return_word_fn: None, + mapping_sload_fn: None, + mapping_sstore_fn: None, + use_outlined_mapping_sload: false, + use_outlined_mapping_sstore: false, + } + } + + /// Creates a new code generator that shares the generated_functions set with another. + /// This is used for subobjects to avoid regenerating shared utility functions. + pub fn new_with_shared_functions( + generated_functions: BTreeSet, + heap_opt: HeapOptResults, + type_info: TypeInference, + inline_decisions: BTreeMap, + ) -> Self { + LlvmCodegen { + values: BTreeMap::new(), + function_names: BTreeMap::new(), + function_param_types: BTreeMap::new(), + function_return_types: BTreeMap::new(), + current_return_types: Vec::new(), + generated_functions, + heap_opt, + type_info, + inline_decisions, + for_loop_post_phis: Vec::new(), + for_loop_break_phis: Vec::new(), + revert_blocks: BTreeMap::new(), + return_blocks: BTreeMap::new(), + panic_blocks: BTreeMap::new(), + use_outlined_callvalue: false, + use_outlined_calldataload: false, + use_outlined_caller: false, + use_outlined_store_low_word: false, + use_outlined_store_high_word: false, + callvalue_value_ids: BTreeSet::new(), + dead_callvalue_ids: BTreeSet::new(), + storage_key_globals: BTreeMap::new(), + validator_masks: BTreeMap::new(), + keccak256_slot_wrappers: BTreeMap::new(), + has_msize: false, + error_string_revert_fns: BTreeMap::new(), + error_string_revert_counts: BTreeMap::new(), + custom_error_revert_fns: BTreeMap::new(), + custom_error_revert_counts: BTreeMap::new(), + store_bswap_fn: None, + store_bswap_checked_fn: None, + load_bswap_checked_fn: None, + exit_checked_fn: None, + callvalue_check_fn: None, + sload_word_fn: None, + sstore_word_fn: None, + store_zero_checked_fn: None, + store_low_word_checked_fn: None, + store_high_word_checked_fn: None, + return_word_fn: None, + mapping_sload_fn: None, + mapping_sstore_fn: None, + use_outlined_mapping_sload: false, + use_outlined_mapping_sstore: false, + } + } + + /// Gets an LLVM value by IR ValueId. + fn get_value(&self, id: ValueId) -> Result> { + self.values + .get(&id.0) + .copied() + .ok_or(CodegenError::UndefinedValue(id)) + } + + /// Stores an LLVM value for an IR ValueId. + fn set_value(&mut self, id: ValueId, value: BasicValueEnum<'ctx>) { + self.values.insert(id.0, value); + } + + /// Translates an IR Value to LLVM value. + fn translate_value(&self, value: &Value) -> Result> { + self.values.get(&value.id.0).copied().ok_or_else(|| { + let mut defined_ids: Vec<_> = self.values.keys().copied().collect(); + defined_ids.sort(); + let max_id = defined_ids.iter().max().copied().unwrap_or(0); + let lower_bound = defined_ids + .iter() + .filter(|&&x| x < value.id.0) + .max() + .copied(); + let upper_bound = defined_ids + .iter() + .filter(|&&x| x > value.id.0) + .min() + .copied(); + CodegenError::Llvm(format!( + "Undefined value {:?} (nearest: {:?}..{:?}, max: {}, total: {})", + value.id, + lower_bound, + upper_bound, + max_id, + defined_ids.len() + )) + }) + } + + /// Tries to extract a constant u64 from an LLVM IntValue. + /// Returns Some(value) if the value is a constant that fits in u64. + /// Handles i256 constants correctly (where `get_zero_extended_constant()` returns None + /// even for small values because the bit-width exceeds 64). + fn try_extract_const_u64(value: IntValue<'ctx>) -> Option { + if !value.is_const() { + return None; + } + + if let Some(v) = value.get_zero_extended_constant() { + return Some(v); + } + + let s = value.print_to_string().to_string(); + if let Some(val_str) = s.strip_prefix("i256 ") { + if let Ok(v) = val_str.trim().parse::() { + return Some(v); + } + } + + None + } + + /// Checks if an LLVM IntValue is a constant zero, handling all bit widths including i256. + fn is_const_zero(value: IntValue<'ctx>) -> bool { + Self::try_extract_const_u64(value) == Some(0) + } + + /// If `value` is a compile-time constant whose representation fits in + /// u64 (i.e., the high 192 bits of an i256 are all zero), returns the + /// low 64 bits. Returns `None` for non-constant values, oversized + /// constants, or zero (zero is handled by the dedicated zero-store + /// path which avoids the i64 argument entirely). + fn value_fits_in_i64(value: IntValue<'ctx>) -> Option { + let low = Self::try_extract_const_u64(value)?; + if low == 0 { + return None; + } + Some(low) + } + + /// If `value` is a compile-time i256 constant of the form + /// `selector << 224` (low 224 bits zero, top 32 bits set), returns the + /// selector. This is the canonical Solidity ABI selector mstore + /// pattern (`mstore(p, shl(224, 0xf92ee8a9))`). + fn value_is_selector_shl_224(value: IntValue<'ctx>) -> Option { + if !value.is_const() { + return None; + } + let s = value.print_to_string().to_string(); + let val_str = s.strip_prefix("i256 ")?.trim(); + let big = val_str.parse::().ok()?; + if big.is_zero() { + return None; + } + let low_mask = (num::BigUint::from(1u32) << 224) - 1u32; + if (&big & &low_mask) != num::BigUint::ZERO { + return None; + } + let selector_big: num::BigUint = big >> 224u32; + let digits = selector_big.to_u64_digits(); + if digits.is_empty() { + return None; + } + if digits.len() > 1 || digits[0] > u32::MAX as u64 { + return None; + } + Some(digits[0] as u32) + } + + /// Checks if an MLoad is loading the free memory pointer (offset 0x40). + /// The free memory pointer is a Solidity convention where mload(64) returns + /// the next free heap address. This value is always < 2^32 on PolkaVM. + fn is_free_pointer_load(offset: IntValue<'ctx>) -> bool { + Self::try_extract_const_u64(offset) == Some(FREE_MEMORY_POINTER_SLOT) + } + + /// Applies a range proof to a value by truncating to a narrower type and zero-extending + /// back to word type. This proves to LLVM that the value fits in the narrow type, + /// enabling overflow check elimination and arithmetic simplification downstream. + fn apply_range_proof( + context: &PolkaVMContext<'ctx>, + value: BasicValueEnum<'ctx>, + narrow_bits: u32, + name: &str, + ) -> Result> { + let value_int = value.into_int_value(); + let narrow_type = context.integer_type(narrow_bits as usize); + let truncated = context + .builder() + .build_int_truncate(value_int, narrow_type, &format!("{name}_narrow")) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let extended = context + .builder() + .build_int_z_extend(truncated, context.word_type(), &format!("{name}_extend")) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + Ok(extended.as_basic_value_enum()) + } + + /// Determines native memory mode for a specific memory access. + /// + /// Returns one of four modes: + /// - `AllNative`: all accesses are safe, use native runtime function calls + /// - `InlineNative`: this specific access is native-safe; inline store/load (no bswap) + /// - `InlineByteSwap`: constant offset needing BE; inline bswap without sbrk + /// - `ByteSwap`: dynamic offset; call shared runtime function (includes sbrk) + /// + /// Uses the LLVM constant value directly (not the IR ValueId) to avoid + /// ValueId namespace collisions between outer objects and subobjects. + /// The heap analysis tracks variable-accessed offsets to prevent mode + /// mismatches when the solc M3 optimizer turns literals into variables. + fn native_memory_mode(&self, offset_llvm: IntValue<'ctx>) -> NativeMemoryMode { + if self.heap_opt.all_native() { + return NativeMemoryMode::AllNative; + } + if let Some(static_val) = Self::try_extract_const_u64(offset_llvm) { + if self.heap_opt.can_use_native(static_val) { + return NativeMemoryMode::InlineNative; + } + if static_val == FREE_MEMORY_POINTER_SLOT && self.heap_opt.fmp_native_safe() { + return NativeMemoryMode::InlineNative; + } + return NativeMemoryMode::InlineByteSwap; + } + NativeMemoryMode::ByteSwap + } + + /// Truncates a 256-bit offset to 32-bit for use with native memory operations. + /// The native load/store functions and inline native operations expect xlen_type (32-bit) offsets. + fn truncate_offset_to_xlen( + &self, + context: &PolkaVMContext<'ctx>, + offset: IntValue<'ctx>, + name: &str, + ) -> Result> { + let xlen_type = context.xlen_type(); + if offset.get_type().get_bit_width() == xlen_type.get_bit_width() { + Ok(offset) + } else { + context + .builder() + .build_int_truncate(offset, xlen_type, name) + .map_err(|e| CodegenError::Llvm(e.to_string())) + } + } + + /// Gets the inferred bit-width for a value from type inference. + /// + /// Uses the forward-propagated min_width (what the definition produces). + /// Backward demand narrowing (effective_width) is not used here because + /// truncating a wide value at the definition site can break overflow + /// detection in safe_truncate_int_to_xlen and similar safety checks. + fn inferred_width(&self, id: ValueId) -> BitWidth { + self.type_info.get(id).min_width + } + + /// Ensures a value is extended to 256-bit word type. + /// Used when a narrower value needs to be used in operations requiring full width. + fn ensure_word_type( + &self, + context: &PolkaVMContext<'ctx>, + value: IntValue<'ctx>, + name: &str, + ) -> Result> { + let value_width = value.get_type().get_bit_width(); + let word_width = context.word_type().get_bit_width(); + + if value_width == word_width { + Ok(value) + } else if value_width < word_width { + context + .builder() + .build_int_z_extend(value, context.word_type(), name) + .map_err(|e| CodegenError::Llvm(e.to_string())) + } else { + context + .builder() + .build_int_truncate(value, context.word_type(), name) + .map_err(|e| CodegenError::Llvm(e.to_string())) + } + } + + /// Ensures two values have the same type by extending the narrower one. + /// Returns both values at the wider type. + fn ensure_same_type( + &self, + context: &PolkaVMContext<'ctx>, + a: IntValue<'ctx>, + b: IntValue<'ctx>, + name: &str, + ) -> Result<(IntValue<'ctx>, IntValue<'ctx>)> { + let a_width = a.get_type().get_bit_width(); + let b_width = b.get_type().get_bit_width(); + + if a_width == b_width { + Ok((a, b)) + } else if a_width > b_width { + let b_ext = context + .builder() + .build_int_z_extend(b, a.get_type(), &format!("{}_ext_b", name)) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + Ok((a, b_ext)) + } else { + let a_ext = context + .builder() + .build_int_z_extend(a, b.get_type(), &format!("{}_ext_a", name)) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + Ok((a_ext, b)) + } + } + + /// Ensures both operands are extended to at least the given minimum width. + /// This is used for arithmetic operations where the result needs a certain + /// width to avoid modular arithmetic wrapping at the wrong boundary. + fn ensure_min_width( + &self, + context: &PolkaVMContext<'ctx>, + a: IntValue<'ctx>, + b: IntValue<'ctx>, + min_width: u32, + name: &str, + ) -> Result<(IntValue<'ctx>, IntValue<'ctx>)> { + let target_width = min_width + .max(a.get_type().get_bit_width()) + .max(b.get_type().get_bit_width()); + let target_type = context.integer_type(target_width as usize); + + let a_ext = if a.get_type().get_bit_width() < target_width { + context + .builder() + .build_int_z_extend(a, target_type, &format!("{}_ext_a", name)) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + } else { + a + }; + let b_ext = if b.get_type().get_bit_width() < target_width { + context + .builder() + .build_int_z_extend(b, target_type, &format!("{}_ext_b", name)) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + } else { + b + }; + Ok((a_ext, b_ext)) + } + + /// Adjusts a single value to an exact target width: truncates if wider, + /// zero-extends if narrower, returns unchanged if already the target width. + fn ensure_exact_width( + &self, + context: &PolkaVMContext<'ctx>, + value: IntValue<'ctx>, + target_bits: u32, + name: &str, + ) -> Result> { + let w = value.get_type().get_bit_width(); + if w == target_bits { + Ok(value) + } else if w < target_bits { + let target_type = context.integer_type(target_bits as usize); + context + .builder() + .build_int_z_extend(value, target_type, name) + .map_err(|e| CodegenError::Llvm(e.to_string())) + } else { + let target_type = context.integer_type(target_bits as usize); + context + .builder() + .build_int_truncate(value, target_type, name) + .map_err(|e| CodegenError::Llvm(e.to_string())) + } + } + + /// Tries to narrow comparison operands to a smaller type when both are + /// provably narrow. For unsigned comparisons and equality, truncating both + /// operands to their proven width is correct and avoids expensive i256 + /// comparison sequences (16-20 RISC-V instructions vs 1-2 for i64). + /// + /// Uses three complementary width sources: + /// 1. LLVM structural analysis (zext, and-mask, lshr, etc.) + /// 2. Constant width analysis + /// 3. Forward-propagated type inference min_width + fn try_narrow_comparison( + &self, + context: &PolkaVMContext<'ctx>, + a: IntValue<'ctx>, + b: IntValue<'ctx>, + a_id: ValueId, + b_id: ValueId, + ) -> Result<(IntValue<'ctx>, IntValue<'ctx>)> { + let a_width = a.get_type().get_bit_width(); + let b_width = b.get_type().get_bit_width(); + + if a_width <= 64 && b_width <= 64 { + return self.ensure_same_type(context, a, b, "cmp"); + } + + let a_proven = Self::provable_narrow_width(a).unwrap_or(a_width); + let b_proven = Self::provable_narrow_width(b).unwrap_or(b_width); + + let a_effective = if a.is_const() { + Self::constant_effective_width(a) + .unwrap_or(a_proven) + .min(a_proven) + } else { + a_proven + }; + let b_effective = if b.is_const() { + Self::constant_effective_width(b) + .unwrap_or(b_proven) + .min(b_proven) + } else { + b_proven + }; + + let a_inferred = self.inferred_width(a_id).bits(); + let b_inferred = self.inferred_width(b_id).bits(); + let a_effective = a_effective.min(a_inferred); + let b_effective = b_effective.min(b_inferred); + + let max_needed = a_effective.max(b_effective); + + let target_bits = if max_needed <= 8 { + 8 + } else if max_needed <= 32 { + 32 + } else if max_needed <= 64 { + 64 + } else if max_needed <= 128 { + 128 + } else { + return self.ensure_same_type(context, a, b, "cmp"); + }; + + let target_type = context.integer_type(target_bits as usize); + + let a_narrow = if a_width > target_bits { + context + .builder() + .build_int_truncate(a, target_type, "cmp_narrow_a") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + } else if a_width < target_bits { + context + .builder() + .build_int_z_extend(a, target_type, "cmp_ext_a") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + } else { + a + }; + + let b_narrow = if b_width > target_bits { + context + .builder() + .build_int_truncate(b, target_type, "cmp_narrow_b") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + } else if b_width < target_bits { + context + .builder() + .build_int_z_extend(b, target_type, "cmp_ext_b") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + } else { + b + }; + + Ok((a_narrow, b_narrow)) + } + + /// Narrows a Let-bound value using two complementary strategies: + /// + /// 1. **Structural LLVM proofs** (zext source, AND mask, lshr by constant): + /// Sound because the proof is based on the instruction producing the value. + /// + /// 2. **Backward demand narrowing** from type inference: + /// If ALL use sites only need narrow bits (e.g., memory offsets → I64), + /// truncate here. LLVM will fold the truncation back into the producing + /// operation, converting entire computation chains to narrow types. + /// This is sound because modular arithmetic on the lower N bits produces + /// the same lower N bits regardless of input width. + /// + /// Narrowing to standard widths (i8, i32, i64) reduces: + /// - Register spill overhead (i64 is 1/4 the spill code of i256) + /// - Comparison instruction count (i64 is 1 compare vs 4 for i256) + /// - Overall code size through compound effects on register pressure + fn try_narrow_let_binding( + &self, + context: &PolkaVMContext<'ctx>, + value: BasicValueEnum<'ctx>, + binding_id: ValueId, + ) -> Result> { + let integer_value = match value { + BasicValueEnum::IntValue(v) => v, + _ => return Ok(value), + }; + + let value_width = integer_value.get_type().get_bit_width(); + + if value_width <= 64 { + return Ok(value); + } + + if let Some(proven_width) = Self::provable_narrow_width(integer_value) { + let target_bits = if proven_width <= 8 { + 8 + } else if proven_width <= 32 { + 32 + } else if proven_width <= 64 { + 64 + } else if proven_width <= 128 { + 128 + } else { + 0 + }; + + if target_bits > 0 && target_bits < value_width { + let narrow_type = context.integer_type(target_bits as usize); + let truncated = context + .builder() + .build_int_truncate(integer_value, narrow_type, "narrow_let") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + return Ok(truncated.as_basic_value_enum()); + } + } + + let constraint = self.type_info.get(binding_id); + if !constraint.is_signed { + let demand = self.type_info.use_demand_width(binding_id); + let target_bits = match demand { + BitWidth::I1 | BitWidth::I8 => 8, + BitWidth::I32 => 32, + BitWidth::I64 => 64, + BitWidth::I128 => 128, + _ => return Ok(value), + }; + if target_bits < value_width { + let narrow_type = context.integer_type(target_bits as usize); + let truncated = context + .builder() + .build_int_truncate(integer_value, narrow_type, "demand_narrow") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + return Ok(truncated.as_basic_value_enum()); + } + } + + Ok(value) + } + + /// Returns the provable bit width of an LLVM value based on structural analysis. + /// + /// Only returns a width when the LLVM IR itself proves the value fits, + /// regardless of type inference. Patterns detected: + /// - `zext from narrow_type`: value fits in narrow_type's width + /// - `and %value, constant_mask`: value fits in mask's bit width + /// - `trunc to narrow_type`: value fits in narrow_type's width + /// - `lshr %value, constant_amount`: result fits in (input_width - amount) bits + fn provable_narrow_width(value: IntValue<'ctx>) -> Option { + use inkwell::values::InstructionOpcode; + + let instruction = value.as_instruction_value()?; + match instruction.get_opcode() { + InstructionOpcode::ZExt => { + let operand = instruction.get_operand(0)?.value()?.into_int_value(); + let type_width = operand.get_type().get_bit_width(); + let proven = Self::provable_narrow_width(operand).unwrap_or(type_width); + Some(proven.min(type_width)) + } + InstructionOpcode::And => { + let op0 = instruction.get_operand(0)?.value()?.into_int_value(); + let op1 = instruction.get_operand(1)?.value()?.into_int_value(); + let w0 = if op0.is_const() { + Self::constant_effective_width(op0) + } else { + Self::provable_narrow_width(op0) + }; + let w1 = if op1.is_const() { + Self::constant_effective_width(op1) + } else { + Self::provable_narrow_width(op1) + }; + match (w0, w1) { + (Some(a), Some(b)) => Some(a.min(b)), + (Some(a), None) => Some(a), + (None, Some(b)) => Some(b), + (None, None) => None, + } + } + InstructionOpcode::Trunc => { + let target_width = instruction.get_type().into_int_type().get_bit_width(); + let operand = instruction.get_operand(0)?.value()?.into_int_value(); + let src_narrow = Self::provable_narrow_width(operand) + .unwrap_or(operand.get_type().get_bit_width()); + Some(src_narrow.min(target_width)) + } + InstructionOpcode::LShr => { + let shift_amount = instruction.get_operand(1)?.value()?.into_int_value(); + if let Some(shift) = Self::try_get_small_constant(shift_amount) { + let input_width = instruction + .get_operand(0)? + .value()? + .into_int_value() + .get_type() + .get_bit_width(); + if shift < input_width as u64 { + Some((input_width as u64 - shift) as u32) + } else { + Some(1) + } + } else { + None + } + } + InstructionOpcode::Or => { + let op0 = instruction.get_operand(0)?.value()?.into_int_value(); + let op1 = instruction.get_operand(1)?.value()?.into_int_value(); + let w0 = Self::provable_narrow_width(op0); + let w1 = Self::provable_narrow_width(op1); + match (w0, w1) { + (Some(a), Some(b)) => Some(a.max(b)), + _ => None, + } + } + InstructionOpcode::Add => { + let op0 = instruction.get_operand(0)?.value()?.into_int_value(); + let op1 = instruction.get_operand(1)?.value()?.into_int_value(); + let w0 = Self::provable_narrow_width(op0) + .or_else(|| Self::constant_effective_width(op0)); + let w1 = Self::provable_narrow_width(op1) + .or_else(|| Self::constant_effective_width(op1)); + match (w0, w1) { + (Some(a), Some(b)) => { + let result_width = a.max(b) + 1; + if result_width <= 128 { + Some(result_width) + } else { + None + } + } + _ => None, + } + } + InstructionOpcode::Mul => { + let op0 = instruction.get_operand(0)?.value()?.into_int_value(); + let op1 = instruction.get_operand(1)?.value()?.into_int_value(); + let w0 = Self::provable_narrow_width(op0) + .or_else(|| Self::constant_effective_width(op0)); + let w1 = Self::provable_narrow_width(op1) + .or_else(|| Self::constant_effective_width(op1)); + match (w0, w1) { + (Some(a), Some(b)) => { + let result_width = a + b; + if result_width <= 128 { + Some(result_width) + } else { + None + } + } + _ => None, + } + } + _ => None, + } + } + + /// Extracts a small constant value from an IntValue, handling wide types (i256). + /// Returns None if the value is not a constant or doesn't fit in u64. + fn try_get_small_constant(integer_value: IntValue<'ctx>) -> Option { + if let Some(value) = integer_value.get_zero_extended_constant() { + return Some(value); + } + let wide_type = integer_value.get_type(); + if wide_type.get_bit_width() > 64 && integer_value.is_const() { + let i64_type = wide_type.get_context().i64_type(); + let truncated = integer_value.const_truncate(i64_type); + if let Some(value) = truncated.get_zero_extended_constant() { + let reconstructed = wide_type.const_int(value, false); + if reconstructed == integer_value { + return Some(value); + } + } + } + None + } + + /// Returns the effective bit width needed to represent a constant integer value. + /// For wide types (> 64 bits), checks progressively wider truncation targets. + fn constant_effective_width(integer_value: IntValue<'ctx>) -> Option { + if let Some(value) = integer_value.get_zero_extended_constant() { + return Some(if value == 0 { + 1 + } else { + 64 - value.leading_zeros() + }); + } + + let wide_type = integer_value.get_type(); + if wide_type.get_bit_width() > 64 && integer_value.is_const() { + let i64_type = wide_type.get_context().i64_type(); + let truncated_64 = integer_value.const_truncate(i64_type); + if let Some(value) = truncated_64.get_zero_extended_constant() { + let reconstructed = wide_type.const_int(value, false); + if reconstructed == integer_value { + return Some(if value == 0 { + 1 + } else { + 64 - value.leading_zeros() + }); + } + } + } + + None + } + + /// Returns true when forward type inference or LLVM-IR-level structural + /// analysis proves the argument fits in `target_bits`. Used by the Call + /// codegen to decide between a bare truncate (when provably narrow) and a + /// checked truncate (when the high bits might be non-zero). + fn argument_provably_fits( + &self, + integer_value: IntValue<'ctx>, + argument: Value, + target_bits: u32, + ) -> bool { + let inferred = self.inferred_width(argument.id); + if inferred.bits() <= target_bits { + return true; + } + if let Some(width) = Self::provable_narrow_width(integer_value) { + if width <= target_bits { + return true; + } + } + false + } + + /// Emits a `trunc value, target_type` guarded by a `value != zext(trunc)` + /// overflow check. If overflow is detected, traps via `consume_all_gas` + /// (the same trap path `safe_truncate_int_to_xlen` uses for the i256→i32 + /// case). LLVM's instcombine folds the check away when the value is + /// already provably narrow, so emitting it unconditionally on the + /// not-provably-fits path costs nothing on those paths. + fn checked_truncate_to( + &self, + context: &mut PolkaVMContext<'ctx>, + value: IntValue<'ctx>, + target_type: inkwell::types::IntType<'ctx>, + name: &str, + ) -> Result> { + let value_type = value.get_type(); + let truncated = context + .builder() + .build_int_truncate(value, target_type, name) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let extended = context + .builder() + .build_int_z_extend(truncated, value_type, &format!("{name}_extended")) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let is_overflow = context + .builder() + .build_int_compare( + inkwell::IntPredicate::NE, + value, + extended, + &format!("{name}_overflow"), + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let block_continue = context.append_basic_block(&format!("{name}_ok")); + let block_invalid = context.append_basic_block(&format!("{name}_overflow_trap")); + context.build_conditional_branch(is_overflow, block_invalid, block_continue)?; + + context.set_basic_block(block_invalid); + context.build_runtime_call("consume_all_gas", &[]); + context.build_unreachable(); + + context.set_basic_block(block_continue); + Ok(truncated) + } + + /// Narrows a memory offset or length value to i64 when type inference + /// proves the value fits. This eliminates the expensive 3-basic-block + /// overflow check in `safe_truncate_int_to_xlen` (which converts i256→xlen) + /// by giving it an i64 input that takes the cheap direct truncation path. + /// + /// This is only applied at memory operation USE sites (mstore, mload, + /// return, revert, etc.) — never at LET bindings — so it cannot affect + /// intermediate arithmetic which must remain at full width. + fn narrow_offset_for_pointer( + &self, + context: &PolkaVMContext<'ctx>, + value: IntValue<'ctx>, + source_id: ValueId, + name: &str, + ) -> Result> { + let value_width = value.get_type().get_bit_width(); + + if value_width <= 32 { + return Ok(value); + } + + let inferred = self.inferred_width(source_id); + + if matches!(inferred, BitWidth::I1 | BitWidth::I8 | BitWidth::I32) { + let i32_type = context.llvm().i32_type(); + return context + .builder() + .build_int_truncate(value, i32_type, name) + .map_err(|e| CodegenError::Llvm(e.to_string())); + } + + if matches!(inferred, BitWidth::I64) && value_width > 64 { + let i64_type = context.llvm().i64_type(); + return context + .builder() + .build_int_truncate(value, i64_type, name) + .map_err(|e| CodegenError::Llvm(e.to_string())); + } + + Ok(value) + } + + /// Checks if a basic block is unreachable (has no predecessors or already has a terminator). + /// This is used to determine if a region ended early due to Leave/Break/Return/etc. + fn block_is_unreachable(block: inkwell::basic_block::BasicBlock<'ctx>) -> bool { + if block.get_terminator().is_some() { + return true; + } + if block.get_first_instruction().is_none() { + if let Ok(name) = block.get_name().to_str() { + if name.contains("unreachable") { + return true; + } + } + } + false + } + + /// Gets or creates a shared basic block for `revert(0, K)` where K is a constant length. + /// + /// Many contracts (especially those generated by OpenZeppelin) have dozens or + /// even hundreds of identical revert sites. Common patterns include: + /// - `revert(0, 0)`: callvalue checks, ABI decoding checks, overflow guards (100+ sites) + /// - `revert(0, 36)`: Solidity custom error messages with string (70+ sites) + /// - `revert(0, 4)`: custom error selectors (20+ sites) + /// - `revert(0, 68)`: errors with two arguments (17+ sites) + /// + /// Each site generates the same exit sequence: safe_truncate(offset) + safe_truncate(length) + /// + seal_return(1, heap_base+offset, length) + unreachable. + /// + /// By creating a single shared block per (offset=0, length=K) pattern and branching to it, + /// we eliminate the duplication. On OZ ERC20, this saves 200+ copies of these patterns. + fn get_or_create_revert_block( + &mut self, + context: &mut PolkaVMContext<'ctx>, + const_length: u64, + ) -> Result> { + if let Some(&block) = self.revert_blocks.get(&const_length) { + return Ok(block); + } + + let current_block = context.basic_block(); + + let block_name = format!("revert_shared_{const_length}"); + let revert_block = context.append_basic_block(&block_name); + context.set_basic_block(revert_block); + + // Soundness: `xlen_type().const_int(u64_value, false)` silently + // truncates the length to xlen. A constant length above `u32::MAX` + // would wrap and the revert would carry the wrong byte count + // instead of trapping on the out-of-bounds memory expansion. Fall + // back to the i256 + safe-truncate path in that case. + let xlen_bits = context.xlen_type().get_bit_width(); + let length_fits_in_xlen = + xlen_bits >= 64 || (xlen_bits > 0 && const_length >> xlen_bits == 0); + + if const_length == 0 { + revive_llvm_context::polkavm_evm_return::revert_empty_outlined(context) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } else if length_fits_in_xlen { + let length_xlen = context.xlen_type().const_int(const_length, false); + revive_llvm_context::polkavm_evm_return::revert_outlined(context, length_xlen) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } else { + let offset_val = context.word_const(0); + let length_val = context.word_const(const_length); + revive_llvm_context::polkavm_evm_return::revert(context, offset_val, length_val) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + + context.build_unreachable(); + + context.set_basic_block(current_block); + + self.revert_blocks.insert(const_length, revert_block); + Ok(revert_block) + } + + /// Gets or creates a shared basic block for a Solidity panic revert with a given error code. + /// The block stores `Panic(uint256)` ABI encoding to scratch memory and reverts. + /// This deduplicates the common pattern: mstore(0, 0x4e487b71...), mstore(4, code), revert(0, 36). + fn get_or_create_panic_block( + &mut self, + context: &mut PolkaVMContext<'ctx>, + error_code: u8, + ) -> Result> { + if let Some(&block) = self.panic_blocks.get(&error_code) { + return Ok(block); + } + + let current_block = context.basic_block(); + + let block_name = format!("panic_0x{error_code:02x}"); + let panic_block = context.append_basic_block(&block_name); + context.set_basic_block(panic_block); + + let panic_fn = context + .get_function("__revive_panic", false) + .expect("ICE: __revive_panic should be declared"); + let code_val = context.word_const(error_code as u64); + context.build_call( + panic_fn.borrow().declaration(), + &[code_val.into()], + "panic_outlined", + ); + context.build_unreachable(); + + context.set_basic_block(current_block); + + self.panic_blocks.insert(error_code, panic_block); + Ok(panic_block) + } + + /// Gets or creates an outlined function for Error(string) reverts with a given + /// number of data words. The function signature is: + /// `void @__revive_error_string_revert_N(i256 %length, i256 %word0, ...) noreturn` + /// + /// The function body loads the free memory pointer, stores the Error(string) ABI + /// encoding (selector + offset + length + data words), and calls revert. + fn get_or_create_error_string_revert_fn( + &mut self, + num_words: usize, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if let Some(&function) = self.error_string_revert_fns.get(&num_words) { + return Ok(function); + } + + let word_type = context.word_type(); + let function_name = format!("__revive_error_string_revert_{num_words}"); + + let mut parameter_types: Vec = + vec![word_type.into()]; + for _ in 0..num_words { + parameter_types.push(word_type.into()); + } + let function_type = context.llvm().void_type().fn_type(¶meter_types, false); + + let function = context.module().add_function( + &function_name, + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + let noinline_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoInline as u32, 0); + let noreturn_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoReturn as u32, 0); + let minsize_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::MinSize as u32, 0); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, noinline_attr); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, noreturn_attr); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, minsize_attr); + + let saved_block = context.basic_block(); + + let entry_block = context.llvm().append_basic_block(function, "entry"); + context.set_basic_block(entry_block); + + let length_parameter = function.get_nth_param(0).unwrap().into_int_value(); + let word_parameters: Vec<_> = (0..num_words) + .map(|i| { + function + .get_nth_param((i + 1) as u32) + .unwrap() + .into_int_value() + }) + .collect(); + + let fmp_offset = context.word_const(FREE_MEMORY_POINTER_SLOT); + let fmp = revive_llvm_context::polkavm_evm_memory::load(context, fmp_offset) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .into_int_value(); + + let error_selector = + context.word_const_str_hex(revive_common::ERROR_STRING_SELECTOR_WORD_HEX); + revive_llvm_context::polkavm_evm_memory::store(context, fmp, error_selector) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + let fmp_plus_offset_field = context + .builder() + .build_int_add( + fmp, + context.word_const(ABI_SELECTOR_LENGTH), + "fmp_offset_field", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let string_data_offset = context.word_const(revive_common::BYTE_LENGTH_WORD as u64); + revive_llvm_context::polkavm_evm_memory::store( + context, + fmp_plus_offset_field, + string_data_offset, + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + let fmp_plus_length_field = context + .builder() + .build_int_add( + fmp, + context.word_const(ERROR_STRING_LENGTH_FIELD_OFFSET), + "fmp_length_field", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + revive_llvm_context::polkavm_evm_memory::store( + context, + fmp_plus_length_field, + length_parameter, + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + for (i, word_parameter) in word_parameters.iter().enumerate() { + let offset = ERROR_STRING_FIRST_DATA_WORD_OFFSET + + (i as u64) * revive_common::BYTE_LENGTH_WORD as u64; + let fmp_plus_offset = context + .builder() + .build_int_add(fmp, context.word_const(offset), &format!("fmp_{offset:x}")) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + revive_llvm_context::polkavm_evm_memory::store( + context, + fmp_plus_offset, + *word_parameter, + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + + let total_length = ERROR_STRING_FIRST_DATA_WORD_OFFSET + + (num_words as u64) * revive_common::BYTE_LENGTH_WORD as u64; + let total_length_val = context.word_const(total_length); + revive_llvm_context::polkavm_evm_return::revert(context, fmp, total_length_val) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context.build_unreachable(); + + context.set_basic_block(saved_block); + + self.error_string_revert_fns.insert(num_words, function); + Ok(function) + } + + /// Gets or creates an outlined function for custom error reverts with N arguments. + /// The function signature is: + /// `void @__revive_custom_error_revert_N(i256 %selector, i256 %arg0, ...) noreturn` + /// + /// The function body stores the selector at scratch\[0\], arguments at scratch\[4\], + /// scratch\[0x24\], etc., and calls revert(0, 4 + 32*N). + /// Uses store_bswap_unchecked since scratch space offsets are constant and small. + fn get_or_create_custom_error_revert_fn( + &mut self, + num_args: usize, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if let Some(&function) = self.custom_error_revert_fns.get(&num_args) { + return Ok(function); + } + + let word_type = context.word_type(); + let xlen_type = context.xlen_type(); + let function_name = format!("__revive_custom_error_{num_args}"); + + let mut parameter_types: Vec = + Vec::with_capacity(num_args + 1); + parameter_types.push(xlen_type.into()); + for _ in 0..num_args { + parameter_types.push(word_type.into()); + } + let function_type = context.llvm().void_type().fn_type(¶meter_types, false); + + let function = context.module().add_function( + &function_name, + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + let noinline_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoInline as u32, 0); + let noreturn_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoReturn as u32, 0); + let minsize_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::MinSize as u32, 0); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, noinline_attr); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, noreturn_attr); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, minsize_attr); + + let saved_block = context.basic_block(); + + let entry_block = context.llvm().append_basic_block(function, "entry"); + context.set_basic_block(entry_block); + + let selector_parameter = function.get_nth_param(0).unwrap().into_int_value(); + let argument_parameters: Vec<_> = (1..=num_args) + .map(|i| function.get_nth_param(i as u32).unwrap().into_int_value()) + .collect(); + + let offset_0 = context.xlen_type().const_int(0, false); + let selector_heap_pointer = context + .build_heap_gep_unchecked(offset_0) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context + .builder() + .build_store(selector_heap_pointer.value, selector_parameter) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .set_alignment(revive_common::BYTE_LENGTH_BYTE as u32) + .expect("ICE: alignment is valid"); + + for (i, argument_parameter) in argument_parameters.iter().enumerate() { + let byte_offset = + ABI_SELECTOR_LENGTH + (i as u64) * revive_common::BYTE_LENGTH_WORD as u64; + let offset_val = context.xlen_type().const_int(byte_offset, false); + revive_llvm_context::polkavm_evm_memory::store_bswap_unchecked( + context, + offset_val, + *argument_parameter, + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + + let const_len = + ABI_SELECTOR_LENGTH + (num_args as u64) * revive_common::BYTE_LENGTH_WORD as u64; + let length_xlen = context.xlen_type().const_int(const_len, false); + revive_llvm_context::polkavm_evm_return::revert_outlined(context, length_xlen) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context.build_unreachable(); + + context.set_basic_block(saved_block); + + self.custom_error_revert_fns.insert(num_args, function); + Ok(function) + } + + /// Gets or creates an outlined store_bswap function: void(i32 offset, i256 value). + /// Uses unchecked heap GEP + 4× bswap.i64 + store. This avoids duplicating + /// the bswap sequence at every variable-value InlineByteSwap store site. + fn get_or_create_store_bswap_fn( + &mut self, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if let Some(function) = self.store_bswap_fn { + return Ok(function); + } + + let xlen_type = context.xlen_type(); + let word_type = context.word_type(); + let function_type = context + .llvm() + .void_type() + .fn_type(&[xlen_type.into(), word_type.into()], false); + let function = context.module().add_function( + "__revive_store_bswap", + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + let noinline_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoInline as u32, 0); + let minsize_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::MinSize as u32, 0); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, noinline_attr); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, minsize_attr); + + let saved_block = context.basic_block(); + let entry_block = context.llvm().append_basic_block(function, "entry"); + context.set_basic_block(entry_block); + + let offset_param = function.get_nth_param(0).unwrap().into_int_value(); + let value_param = function.get_nth_param(1).unwrap().into_int_value(); + + revive_llvm_context::polkavm_evm_memory::store_bswap_unchecked( + context, + offset_param, + value_param, + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context + .builder() + .build_return(None) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(saved_block); + self.store_bswap_fn = Some(function); + Ok(function) + } + + /// Gets or creates an outlined store_bswap with bounds checking: + /// void(i32 offset, i256 value). + /// Checks `offset > (heap_size - 32)` and traps if out of bounds, + /// then uses unchecked GEP + 4× bswap.i64 + store. + /// This replaces sbrk-based `__revive_store_heap_word` for non-msize contracts. + fn get_or_create_store_bswap_checked_fn( + &mut self, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if let Some(function) = self.store_bswap_checked_fn { + return Ok(function); + } + + let xlen_type = context.xlen_type(); + let word_type = context.word_type(); + let function_type = context + .llvm() + .void_type() + .fn_type(&[xlen_type.into(), word_type.into()], false); + let function = context.module().add_function( + "__revive_store_bswap_checked", + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + let noinline_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoInline as u32, 0); + let minsize_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::MinSize as u32, 0); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, noinline_attr); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, minsize_attr); + + let saved_block = context.basic_block(); + let entry_block = context.llvm().append_basic_block(function, "entry"); + let trap_block = context.llvm().append_basic_block(function, "trap"); + let store_block = context.llvm().append_basic_block(function, "store"); + + context.set_basic_block(entry_block); + let offset_param = function.get_nth_param(0).unwrap().into_int_value(); + let value_param = function.get_nth_param(1).unwrap().into_int_value(); + let heap_size = context.heap_size(); + let max_offset = context + .builder() + .build_int_sub( + heap_size, + xlen_type.const_int(revive_common::BYTE_LENGTH_WORD as u64, false), + "max_offset", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let out_of_bounds = context + .builder() + .build_int_compare( + inkwell::IntPredicate::UGT, + offset_param, + max_offset, + "out_of_bounds", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context + .builder() + .build_conditional_branch(out_of_bounds, trap_block, store_block) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(trap_block); + context.build_call(context.intrinsics().trap, &[], "heap_trap"); + context.build_unreachable(); + + context.set_basic_block(store_block); + revive_llvm_context::polkavm_evm_memory::store_bswap_unchecked( + context, + offset_param, + value_param, + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context + .builder() + .build_return(None) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(saved_block); + self.store_bswap_checked_fn = Some(function); + Ok(function) + } + + /// Gets or creates an outlined zero store with bounds checking: + /// void(i32 offset). + /// Stores 32 zero bytes at heap+offset. Used for constant-zero MStore + /// in ByteSwap mode. Saves passing an i256 zero parameter and avoids the + /// bswap sequence entirely (bswap(0) = 0). + fn get_or_create_store_zero_checked_fn( + &mut self, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if let Some(function) = self.store_zero_checked_fn { + return Ok(function); + } + + let xlen_type = context.xlen_type(); + let function_type = context + .llvm() + .void_type() + .fn_type(&[xlen_type.into()], false); + let function = context.module().add_function( + "__revive_store_zero_checked", + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + let noinline_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoInline as u32, 0); + let minsize_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::MinSize as u32, 0); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, noinline_attr); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, minsize_attr); + + let saved_block = context.basic_block(); + let entry_block = context.llvm().append_basic_block(function, "entry"); + let trap_block = context.llvm().append_basic_block(function, "trap"); + let store_block = context.llvm().append_basic_block(function, "store"); + + context.set_basic_block(entry_block); + let offset_param = function.get_nth_param(0).unwrap().into_int_value(); + let heap_size = context.heap_size(); + let max_offset = context + .builder() + .build_int_sub( + heap_size, + xlen_type.const_int(revive_common::BYTE_LENGTH_WORD as u64, false), + "max_offset", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let out_of_bounds = context + .builder() + .build_int_compare( + inkwell::IntPredicate::UGT, + offset_param, + max_offset, + "out_of_bounds", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context + .builder() + .build_conditional_branch(out_of_bounds, trap_block, store_block) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(trap_block); + context.build_call(context.intrinsics().trap, &[], "heap_trap"); + context.build_unreachable(); + + context.set_basic_block(store_block); + let pointer = context.build_heap_gep_unchecked(offset_param)?; + let word_type = context.word_type(); + let zero = word_type.const_zero(); + context + .builder() + .build_store(pointer.value, zero) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .set_alignment(revive_common::BYTE_LENGTH_BYTE as u32) + .expect("Alignment is valid"); + context + .builder() + .build_return(None) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(saved_block); + self.store_zero_checked_fn = Some(function); + Ok(function) + } + + /// Gets or creates an outlined low-word store with bounds check: + /// `void(i32 offset, i64 value)`. + /// Stores 24 zero bytes at heap+offset and `bswap(value)` at the last + /// 8 bytes of the 32-byte slot. Used by `MStore` in ByteSwap mode when + /// the value is a compile-time constant whose high 192 bits are zero. + /// vs `__revive_store_bswap_checked(i32, i256)`: + /// * call site passes 1 i64 (2 register pairs) instead of 1 i256 + /// (4 register pairs) — saves ~3 PVM instructions per call site + /// * function body collapses 4× shift+trunc+bswap+store down to + /// 3 zero stores + 1 bswap+store — saves ~10 PVM instructions in + /// the shared body. + fn get_or_create_store_low_word_checked_fn( + &mut self, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if let Some(function) = self.store_low_word_checked_fn { + return Ok(function); + } + + let xlen_type = context.xlen_type(); + let i64_type = context.llvm().i64_type(); + let function_type = context + .llvm() + .void_type() + .fn_type(&[xlen_type.into(), i64_type.into()], false); + let function = context.module().add_function( + "__revive_store_low_word_checked", + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + let noinline_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoInline as u32, 0); + let minsize_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::MinSize as u32, 0); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, noinline_attr); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, minsize_attr); + + let saved_block = context.basic_block(); + let entry_block = context.llvm().append_basic_block(function, "entry"); + let trap_block = context.llvm().append_basic_block(function, "trap"); + let store_block = context.llvm().append_basic_block(function, "store"); + + context.set_basic_block(entry_block); + let offset_param = function.get_nth_param(0).unwrap().into_int_value(); + let value_param = function.get_nth_param(1).unwrap().into_int_value(); + let heap_size = context.heap_size(); + let max_offset = context + .builder() + .build_int_sub( + heap_size, + xlen_type.const_int(revive_common::BYTE_LENGTH_WORD as u64, false), + "max_offset", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let out_of_bounds = context + .builder() + .build_int_compare( + inkwell::IntPredicate::UGT, + offset_param, + max_offset, + "out_of_bounds", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context + .builder() + .build_conditional_branch(out_of_bounds, trap_block, store_block) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(trap_block); + context.build_call(context.intrinsics().trap, &[], "heap_trap"); + context.build_unreachable(); + + context.set_basic_block(store_block); + let pointer = context.build_heap_gep_unchecked(offset_param)?; + let word_type = context.word_type(); + let zero = word_type.const_zero(); + context + .builder() + .build_store(pointer.value, zero) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .set_alignment(revive_common::BYTE_LENGTH_BYTE as u32) + .expect("Alignment is valid"); + let bswap64 = inkwell::intrinsics::Intrinsic::find("llvm.bswap.i64") + .expect("llvm.bswap.i64 intrinsic exists"); + let bswap64_decl = bswap64 + .get_declaration(context.module(), &[i64_type.into()]) + .expect("bswap.i64 declaration"); + let swapped_param = context + .builder() + .build_call(bswap64_decl, &[value_param.into()], "swapped_low") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .try_as_basic_value() + .unwrap_basic() + .into_int_value(); + let last_word_offset = xlen_type.const_int( + (revive_common::BYTE_LENGTH_WORD - revive_common::BYTE_LENGTH_X64) as u64, + false, + ); + let last_word_ptr = unsafe { + context + .builder() + .build_gep( + context.llvm().i8_type(), + pointer.value, + &[last_word_offset], + "last_word_ptr", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + }; + context + .builder() + .build_store(last_word_ptr, swapped_param) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .set_alignment(revive_common::BYTE_LENGTH_BYTE as u32) + .expect("Alignment is valid"); + context + .builder() + .build_return(None) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(saved_block); + self.store_low_word_checked_fn = Some(function); + Ok(function) + } + + /// Gets or creates an outlined high-word store with bounds check: + /// `void(i32 offset, i32 selector)`. Stores 32 zero bytes at + /// heap+offset and `bswap(selector)` in the FIRST 4 bytes of the + /// slot (BE encoding of `selector << 224`). This is the canonical + /// `mstore(p, shl(224, sel))` pattern Solidity uses for ABI selectors. + fn get_or_create_store_high_word_checked_fn( + &mut self, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if let Some(function) = self.store_high_word_checked_fn { + return Ok(function); + } + + let xlen_type = context.xlen_type(); + let i32_type = context.llvm().i32_type(); + let function_type = context + .llvm() + .void_type() + .fn_type(&[xlen_type.into(), i32_type.into()], false); + let function = context.module().add_function( + "__revive_store_high_word_checked", + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + let noinline_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoInline as u32, 0); + let minsize_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::MinSize as u32, 0); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, noinline_attr); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, minsize_attr); + + let saved_block = context.basic_block(); + let entry_block = context.llvm().append_basic_block(function, "entry"); + let trap_block = context.llvm().append_basic_block(function, "trap"); + let store_block = context.llvm().append_basic_block(function, "store"); + + context.set_basic_block(entry_block); + let offset_param = function.get_nth_param(0).unwrap().into_int_value(); + let selector_parameter = function.get_nth_param(1).unwrap().into_int_value(); + let heap_size = context.heap_size(); + let max_offset = context + .builder() + .build_int_sub( + heap_size, + xlen_type.const_int(revive_common::BYTE_LENGTH_WORD as u64, false), + "max_offset", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let out_of_bounds = context + .builder() + .build_int_compare( + inkwell::IntPredicate::UGT, + offset_param, + max_offset, + "out_of_bounds", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context + .builder() + .build_conditional_branch(out_of_bounds, trap_block, store_block) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(trap_block); + context.build_call(context.intrinsics().trap, &[], "heap_trap"); + context.build_unreachable(); + + context.set_basic_block(store_block); + let pointer = context.build_heap_gep_unchecked(offset_param)?; + let word_type = context.word_type(); + let zero = word_type.const_zero(); + context + .builder() + .build_store(pointer.value, zero) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .set_alignment(revive_common::BYTE_LENGTH_BYTE as u32) + .expect("Alignment is valid"); + + let bswap32 = inkwell::intrinsics::Intrinsic::find("llvm.bswap.i32") + .expect("llvm.bswap.i32 intrinsic exists"); + let bswap32_decl = bswap32 + .get_declaration(context.module(), &[i32_type.into()]) + .expect("bswap.i32 declaration"); + let swapped_selector = context + .builder() + .build_call(bswap32_decl, &[selector_parameter.into()], "swapped_sel") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .try_as_basic_value() + .unwrap_basic() + .into_int_value(); + context + .builder() + .build_store(pointer.value, swapped_selector) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .set_alignment(revive_common::BYTE_LENGTH_BYTE as u32) + .expect("Alignment is valid"); + context + .builder() + .build_return(None) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(saved_block); + self.store_high_word_checked_fn = Some(function); + Ok(function) + } + + /// Gets or creates an outlined return_word function: + /// noreturn void(i32 offset, i256 value). + /// Combines store_bswap_checked + exit_checked for single-word returns: + /// bounds-checks offset, bswap-stores value at heap+offset, then seal_returns 32 bytes. + /// Eliminates one function call per site and one redundant bounds check. + fn get_or_create_return_word_fn( + &mut self, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if let Some(function) = self.return_word_fn { + return Ok(function); + } + + let xlen_type = context.xlen_type(); + let word_type = context.word_type(); + let function_type = context + .llvm() + .void_type() + .fn_type(&[xlen_type.into(), word_type.into()], false); + let function = context.module().add_function( + "__revive_return_word", + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + let noinline_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoInline as u32, 0); + let minsize_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::MinSize as u32, 0); + let noreturn_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoReturn as u32, 0); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, noinline_attr); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, minsize_attr); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, noreturn_attr); + + let saved_block = context.basic_block(); + let entry_block = context.llvm().append_basic_block(function, "entry"); + + context.set_basic_block(entry_block); + let offset_param = function.get_nth_param(0).unwrap().into_int_value(); + let value_param = function.get_nth_param(1).unwrap().into_int_value(); + // store_bswap_checked already performs the offset bounds check; no need + // to duplicate it in this wrapper. After the call returns we know the + // offset is in range and can use the unchecked GEP. + let store_fn = self.get_or_create_store_bswap_checked_fn(context)?; + context + .builder() + .build_call(store_fn, &[offset_param.into(), value_param.into()], "") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let heap_pointer = context + .build_heap_gep_unchecked(offset_param) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let offset_pointer = context + .builder() + .build_ptr_to_int(heap_pointer.value, xlen_type, "return_word_ptr") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let length = xlen_type.const_int(revive_common::BYTE_LENGTH_WORD as u64, false); + context.build_runtime_call( + "seal_return", + &[ + xlen_type.const_zero().into(), + offset_pointer.into(), + length.into(), + ], + ); + context.build_unreachable(); + + context.set_basic_block(saved_block); + self.return_word_fn = Some(function); + Ok(function) + } + + /// Gets or creates an outlined load_bswap with bounds checking: + /// `i256(i32 offset)`. Checks `offset > (heap_size - 32)` and traps if + /// out of bounds, then uses unchecked GEP + 4× bswap.i64 + load. Replaces + /// sbrk-based `__revive_load_heap_word` for non-msize contracts. + /// + /// The body reads heap memory exclusively (no syscalls, no globals + /// beyond `@__heap_memory`), so we attach + /// [`PolkaVMMemoryEffect::ReadOther`] — letting GVN fold repeated + /// `load_bswap_checked(off)` calls of the same offset across arithmetic + /// gaps while still being invalidated by intervening heap mstores. + fn get_or_create_load_bswap_checked_fn( + &mut self, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if let Some(function) = self.load_bswap_checked_fn { + return Ok(function); + } + + let xlen_type = context.xlen_type(); + let word_type = context.word_type(); + let function_type = word_type.fn_type(&[xlen_type.into()], false); + let function = context.module().add_function( + "__revive_load_bswap_checked", + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + add_noinline_minsize_attrs(context, function); + add_memory_effect_attr(context, function, PolkaVMMemoryEffect::ReadOther); + + let saved_block = context.basic_block(); + let entry_block = context.llvm().append_basic_block(function, "entry"); + let trap_block = context.llvm().append_basic_block(function, "trap"); + let load_block = context.llvm().append_basic_block(function, "load"); + + context.set_basic_block(entry_block); + let offset_param = function.get_nth_param(0).unwrap().into_int_value(); + let heap_size = context.heap_size(); + let max_offset = context + .builder() + .build_int_sub( + heap_size, + xlen_type.const_int(revive_common::BYTE_LENGTH_WORD as u64, false), + "max_offset", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let out_of_bounds = context + .builder() + .build_int_compare( + inkwell::IntPredicate::UGT, + offset_param, + max_offset, + "out_of_bounds", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context + .builder() + .build_conditional_branch(out_of_bounds, trap_block, load_block) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(trap_block); + context.build_call(context.intrinsics().trap, &[], "heap_trap"); + context.build_unreachable(); + + context.set_basic_block(load_block); + let result = + revive_llvm_context::polkavm_evm_memory::load_bswap_unchecked(context, offset_param) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context + .builder() + .build_return(Some(&result)) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(saved_block); + self.load_bswap_checked_fn = Some(function); + Ok(function) + } + + /// Gets or creates an outlined exit with bounds checking: + /// void(i32 flags, i32 offset, i32 length). + /// Checks `length > heap_size - offset` (catches both offset > heap_size + /// and offset + length > heap_size) and traps if out of bounds. + /// Then uses unchecked GEP + seal_return. This replaces the sbrk-based + /// `__revive_exit` for dynamic return/revert in non-msize contracts. + fn get_or_create_exit_checked_fn( + &mut self, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if let Some(function) = self.exit_checked_fn { + return Ok(function); + } + + let xlen_type = context.xlen_type(); + let function_type = context.llvm().void_type().fn_type( + &[xlen_type.into(), xlen_type.into(), xlen_type.into()], + false, + ); + let function = context.module().add_function( + "__revive_exit_checked", + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + let noinline_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoInline as u32, 0); + let minsize_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::MinSize as u32, 0); + let noreturn_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoReturn as u32, 0); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, noinline_attr); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, minsize_attr); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, noreturn_attr); + + let saved_block = context.basic_block(); + let entry_block = context.llvm().append_basic_block(function, "entry"); + let trap_block = context.llvm().append_basic_block(function, "trap"); + let exit_block = context.llvm().append_basic_block(function, "exit"); + + context.set_basic_block(entry_block); + let flags_param = function.get_nth_param(0).unwrap().into_int_value(); + let offset_param = function.get_nth_param(1).unwrap().into_int_value(); + let length_parameter = function.get_nth_param(2).unwrap().into_int_value(); + + let heap_size = context.heap_size(); + let offset_oob = context + .builder() + .build_int_compare( + inkwell::IntPredicate::UGE, + offset_param, + heap_size, + "offset_oob", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let offset_ok_block = context.llvm().append_basic_block(function, "offset_ok"); + context + .builder() + .build_conditional_branch(offset_oob, trap_block, offset_ok_block) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(offset_ok_block); + let remaining = context + .builder() + .build_int_sub(heap_size, offset_param, "remaining") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let length_oob = context + .builder() + .build_int_compare( + inkwell::IntPredicate::UGT, + length_parameter, + remaining, + "exit_oob", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context + .builder() + .build_conditional_branch(length_oob, trap_block, exit_block) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(trap_block); + context.build_call(context.intrinsics().trap, &[], "exit_trap"); + context.build_unreachable(); + + context.set_basic_block(exit_block); + let heap_pointer = context + .build_heap_gep_unchecked(offset_param) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let offset_pointer = context + .builder() + .build_ptr_to_int(heap_pointer.value, xlen_type, "exit_ptr") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context.build_runtime_call( + "seal_return", + &[ + flags_param.into(), + offset_pointer.into(), + length_parameter.into(), + ], + ); + context.build_unreachable(); + + context.set_basic_block(saved_block); + self.exit_checked_fn = Some(function); + Ok(function) + } + + /// Gets or creates the outlined `__revive_sload_word(i256 key) -> i256` + /// function. Takes the storage key as an i256 value (not pointer), + /// internally handles bswap, alloca and the GET_STORAGE syscall. + /// Eliminates alloca+store at each call site for runtime-computed keys + /// (e.g. keccak256 mapping results). + /// + /// Effect: [`PolkaVMMemoryEffect::ReadInaccessible`]. From the caller's + /// perspective the helper only reads pallet-revive storage; the alloca + /// writes inside the body are not externally observable and it touches no + /// heap or argmem. LLVM GVN can therefore fold repeated + /// `__revive_sload_word(key)` calls across heap mstores while still being + /// invalidated by sstore wrappers that mark `inaccessiblemem: write`. + fn get_or_create_sload_word_fn( + &mut self, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if let Some(function) = self.sload_word_fn { + return Ok(function); + } + + let word_type = context.word_type(); + let xlen_type = context.xlen_type(); + let function_type = word_type.fn_type(&[word_type.into()], false); + let function = context.module().add_function( + "__revive_sload_word", + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + add_noinline_minsize_attrs(context, function); + add_memory_effect_attr(context, function, PolkaVMMemoryEffect::ReadInaccessible); + + let saved_block = context.basic_block(); + let entry_block = context.llvm().append_basic_block(function, "entry"); + context.set_basic_block(entry_block); + + let key_param = function.get_nth_param(0).unwrap().into_int_value(); + + let key_bswap = context + .build_byte_swap(key_param.as_basic_value_enum()) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + let key_pointer = context.build_alloca_at_entry(word_type, "sload_key"); + let value_pointer = context.build_alloca_at_entry(word_type, "sload_value"); + + context + .builder() + .build_store(key_pointer.value, key_bswap) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + let is_transient = xlen_type.const_int(0, false); + let arguments = [ + is_transient.into(), + key_pointer.to_int(context).into(), + value_pointer.to_int(context).into(), + ]; + context.build_runtime_call("get_storage_or_zero", &arguments); + + let value = context + .build_load(value_pointer, "sload_result") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let value_bswap = context + .build_byte_swap(value) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context + .builder() + .build_return(Some(&value_bswap)) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(saved_block); + self.sload_word_fn = Some(function); + Ok(function) + } + + /// Gets or creates the outlined `__revive_sstore_word(i256 key, i256 value)` + /// function. Takes key and value as i256 values (not pointers), internally + /// handles bswap, alloca and the SET_STORAGE syscall. Eliminates + /// alloca+store at each call site for runtime-computed keys and values. + /// + /// Effect: [`PolkaVMMemoryEffect::WriteInaccessible`]. The only + /// caller-visible effect is the storage write; the key/value byte-swap + /// allocas are local, heap state is untouched, so heap loads and calldata + /// loads survive across an sstore. + fn get_or_create_sstore_word_fn( + &mut self, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if let Some(function) = self.sstore_word_fn { + return Ok(function); + } + + let word_type = context.word_type(); + let xlen_type = context.xlen_type(); + let function_type = context + .llvm() + .void_type() + .fn_type(&[word_type.into(), word_type.into()], false); + let function = context.module().add_function( + "__revive_sstore_word", + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + add_noinline_minsize_attrs(context, function); + add_memory_effect_attr(context, function, PolkaVMMemoryEffect::WriteInaccessible); + + let saved_block = context.basic_block(); + let entry_block = context.llvm().append_basic_block(function, "entry"); + context.set_basic_block(entry_block); + + let key_param = function.get_nth_param(0).unwrap().into_int_value(); + let value_param = function.get_nth_param(1).unwrap().into_int_value(); + + let key_bswap = context + .build_byte_swap(key_param.as_basic_value_enum()) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let value_bswap = context + .build_byte_swap(value_param.as_basic_value_enum()) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + let key_pointer = context.build_alloca_at_entry(word_type, "sstore_key"); + let value_pointer = context.build_alloca_at_entry(word_type, "sstore_value"); + + context + .builder() + .build_store(key_pointer.value, key_bswap) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context + .builder() + .build_store(value_pointer.value, value_bswap) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + let is_transient = xlen_type.const_int(0, false); + let arguments = [ + is_transient.into(), + key_pointer.to_int(context).into(), + value_pointer.to_int(context).into(), + ]; + context.build_runtime_call("set_storage_or_clear", &arguments); + + context + .builder() + .build_return(None) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(saved_block); + self.sstore_word_fn = Some(function); + Ok(function) + } + + /// Gets or creates `__revive_mapping_sload(i256 key, i256 slot) -> i256`. + /// Combines keccak256_pair + sload in a single function, eliminating the + /// redundant bswap pair between keccak output and sload key input. + /// Uses heap scratch memory for keccak input (same pattern as keccak256_two_words) + /// and efficient 4x64-bit bswap to minimize function body size. + fn get_or_create_mapping_sload_fn( + &mut self, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if let Some(function) = self.mapping_sload_fn { + return Ok(function); + } + + let word_type = context.word_type(); + let xlen_type = context.xlen_type(); + let function_type = word_type.fn_type(&[word_type.into(), word_type.into()], false); + let function = context.module().add_function( + "__revive_mapping_sload", + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + let noinline_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoInline as u32, 0); + let minsize_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::MinSize as u32, 0); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, noinline_attr); + function.add_attribute(inkwell::attributes::AttributeLoc::Function, minsize_attr); + + let saved_block = context.basic_block(); + let entry_block = context.llvm().append_basic_block(function, "entry"); + context.set_basic_block(entry_block); + + let key_param = function.get_nth_param(0).unwrap().into_int_value(); + let slot_param = function.get_nth_param(1).unwrap().into_int_value(); + + let offset0 = xlen_type.const_int(0, false); + revive_llvm_context::polkavm_evm_memory::store_bswap_unchecked(context, offset0, key_param) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let offset32 = xlen_type.const_int(revive_common::BYTE_LENGTH_WORD as u64, false); + revive_llvm_context::polkavm_evm_memory::store_bswap_unchecked( + context, offset32, slot_param, + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + let input_pointer = context + .build_heap_gep_unchecked(offset0) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let length = xlen_type.const_int(2 * revive_common::BYTE_LENGTH_WORD as u64, false); + + let hash_output = context.build_alloca_at_entry(word_type, "map_sload_hash"); + let value_pointer = context.build_alloca_at_entry(word_type, "map_sload_value"); + + context.build_runtime_call( + "hash_keccak_256", + &[ + input_pointer.to_int(context).into(), + length.into(), + hash_output.to_int(context).into(), + ], + ); + + let is_transient = xlen_type.const_int(0, false); + context.build_runtime_call( + "get_storage_or_zero", + &[ + is_transient.into(), + hash_output.to_int(context).into(), + value_pointer.to_int(context).into(), + ], + ); + + let value = context + .build_load(value_pointer, "map_sload_result") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let value_bswap = context + .build_byte_swap(value) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context + .builder() + .build_return(Some(&value_bswap)) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(saved_block); + self.mapping_sload_fn = Some(function); + Ok(function) + } + + /// Gets or creates `__revive_mapping_sstore(i256 key, i256 slot, i256 value)`. + /// Combines keccak256_pair + sstore in a single function, eliminating the + /// redundant bswap pair between keccak output and sstore key input. Uses + /// a local alloca for the keccak input — heap writes would block the + /// effect attribute below and prevent heap-load CSE across mapping + /// sstores. + /// + /// Effect: [`PolkaVMMemoryEffect::WriteInaccessible`]. The only + /// caller-visible effect is the storage write; heap state is untouched + /// so heap and calldata loads survive across this call. + fn get_or_create_mapping_sstore_fn( + &mut self, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if let Some(function) = self.mapping_sstore_fn { + return Ok(function); + } + + let word_type = context.word_type(); + let xlen_type = context.xlen_type(); + let function_type = context.llvm().void_type().fn_type( + &[word_type.into(), word_type.into(), word_type.into()], + false, + ); + let function = context.module().add_function( + "__revive_mapping_sstore", + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + add_noinline_minsize_attrs(context, function); + add_memory_effect_attr(context, function, PolkaVMMemoryEffect::WriteInaccessible); + + let saved_block = context.basic_block(); + let entry_block = context.llvm().append_basic_block(function, "entry"); + context.set_basic_block(entry_block); + + let key_param = function.get_nth_param(0).unwrap().into_int_value(); + let slot_param = function.get_nth_param(1).unwrap().into_int_value(); + let value_param = function.get_nth_param(2).unwrap().into_int_value(); + + let input_buffer_type = context + .byte_type() + .array_type(2 * revive_common::BYTE_LENGTH_WORD as u32); + let input_pointer = context.build_alloca_at_entry(input_buffer_type, "map_sstore_input"); + let key_pointer = revive_llvm_context::PolkaVMPointer::new( + word_type, + Default::default(), + input_pointer.value, + ); + let slot_pointer = context.build_gep( + input_pointer, + &[ + xlen_type.const_zero(), + xlen_type.const_int(revive_common::BYTE_LENGTH_WORD as u64, false), + ], + word_type, + "slot_gep", + ); + let key_swapped = context + .build_byte_swap(key_param.into()) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context + .build_store(key_pointer, key_swapped) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let slot_swapped = context + .build_byte_swap(slot_param.into()) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context + .build_store(slot_pointer, slot_swapped) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + let value_bswap = context + .build_byte_swap(value_param.as_basic_value_enum()) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .into_int_value(); + let value_pointer = context.build_alloca_at_entry(word_type, "map_sstore_value"); + context + .builder() + .build_store(value_pointer.value, value_bswap) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + let length = xlen_type.const_int(2 * revive_common::BYTE_LENGTH_WORD as u64, false); + + let hash_output = context.build_alloca_at_entry(word_type, "map_sstore_hash"); + + context.build_runtime_call( + "hash_keccak_256", + &[ + input_pointer.to_int(context).into(), + length.into(), + hash_output.to_int(context).into(), + ], + ); + + let is_transient = xlen_type.const_int(0, false); + context.build_runtime_call( + "set_storage_or_clear", + &[ + is_transient.into(), + hash_output.to_int(context).into(), + value_pointer.to_int(context).into(), + ], + ); + + context + .builder() + .build_return(None) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(saved_block); + self.mapping_sstore_fn = Some(function); + Ok(function) + } + + /// Checks if a region is a simple `revert(0, 0)` with no other side effects. + /// The region may contain Let bindings (for intermediate zero literals) + /// followed by a Revert statement. + fn is_revert_zero_region(region: &crate::ir::Region) -> bool { + let mut found_revert = false; + for statement in ®ion.statements { + match statement { + Statement::Let { + value: Expression::Literal { ref value, .. }, + .. + } => { + if !value.is_zero() { + return false; + } + } + Statement::Let { .. } => { + return false; + } + Statement::Revert { .. } => { + found_revert = true; + } + _ => return false, + } + } + found_revert + } + + /// Gets or creates the outlined callvalue check + revert function: + /// `void __revive_callvalue_check()` that checks if callvalue is nonzero + /// and reverts with empty data if so, returning normally otherwise. + /// + /// Effect: [`PolkaVMMemoryEffect::ReadInaccessible`]. Callvalue is + /// immutable for the duration of execution and reachable through + /// pallet-revive runtime state; the alloca write inside the body is + /// local, with no heap or argmem traffic. CSE is sound because the + /// helper either always returns or always reverts for a given execution + /// — the visible "effect" is just the read of the callvalue scalar. + fn get_or_create_callvalue_check_fn( + &mut self, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if let Some(function) = self.callvalue_check_fn { + return Ok(function); + } + + let void_type = context.llvm().void_type(); + let function_type = void_type.fn_type(&[], false); + let function = context.module().add_function( + "__revive_callvalue_check", + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + add_noinline_minsize_attrs(context, function); + add_memory_effect_attr(context, function, PolkaVMMemoryEffect::ReadInaccessible); + + let saved_block = context.basic_block(); + let entry_block = context.llvm().append_basic_block(function, "entry"); + context.set_basic_block(entry_block); + + let is_nonzero = + revive_llvm_context::polkavm_evm_ether_gas::value_nonzero_outlined(context) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .into_int_value(); + + let revert_block = context.llvm().append_basic_block(function, "revert"); + let ok_block = context.llvm().append_basic_block(function, "ok"); + + context.build_conditional_branch(is_nonzero, revert_block, ok_block)?; + + context.set_basic_block(revert_block); + revive_llvm_context::polkavm_evm_return::revert_empty_outlined(context) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context.build_unreachable(); + + context.set_basic_block(ok_block); + context + .builder() + .build_return(None) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.set_basic_block(saved_block); + self.callvalue_check_fn = Some(function); + Ok(function) + } + + /// Emit an exit (return or revert) using unchecked heap GEP, bypassing sbrk. + /// For non-msize contracts, the heap data was already written by preceding stores, + /// so sbrk's bounds checking is redundant. The offset/length must be xlen-typed. + /// `is_revert` controls the flags parameter (0=return, 1=revert). + fn emit_exit_unchecked( + &self, + context: &mut PolkaVMContext<'ctx>, + offset_xlen: IntValue<'ctx>, + length_xlen: IntValue<'ctx>, + is_revert: bool, + ) -> Result<()> { + let heap_pointer = context + .build_heap_gep_unchecked(offset_xlen) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let offset_pointer = context + .builder() + .build_ptr_to_int(heap_pointer.value, context.xlen_type(), "exit_data_ptr") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let flags = context.xlen_type().const_int(u64::from(is_revert), false); + context.build_runtime_call( + "seal_return", + &[flags.into(), offset_pointer.into(), length_xlen.into()], + ); + Ok(()) + } + + /// Gets or creates a shared basic block for a `return(offset, length)` pattern + /// where both offset and length are constants. This deduplicates identical return + /// sequences (e.g., `return(0x80, 0x20)` appearing 7 times in ERC20 runtime). + /// Each shared block contains the full exit sequence including `store_immutable_data` + /// for deploy code. + fn get_or_create_return_block( + &mut self, + context: &mut PolkaVMContext<'ctx>, + const_offset: u64, + const_length: u64, + ) -> Result> { + let key = (const_offset, const_length); + if let Some(&block) = self.return_blocks.get(&key) { + return Ok(block); + } + + let current_block = context.basic_block(); + + let block_name = format!("return_shared_{const_offset:x}_{const_length:x}"); + let return_block = context.append_basic_block(&block_name); + context.set_basic_block(return_block); + + let is_deploy = matches!( + context.code_type(), + Some(revive_llvm_context::PolkaVMCodeType::Deploy) + ); + + // Soundness: `xlen_type().const_int(u64_value, false)` silently + // truncates the value to xlen (i32 here). A constant offset or + // length above `u32::MAX` would wrap mod `2^32` before reaching + // `emit_exit_unchecked` and the return would access the wrong + // (in-heap) bytes instead of trapping. Fall back to the i256 + + // safe-truncate path for any constant that doesn't fit in xlen. + let xlen_bits = context.xlen_type().get_bit_width(); + let fits_in_xlen = |v: u64| xlen_bits >= 64 || (xlen_bits > 0 && v >> xlen_bits == 0); + + if !self.has_msize && !is_deploy && fits_in_xlen(const_offset) && fits_in_xlen(const_length) + { + let offset_xlen = context.xlen_type().const_int(const_offset, false); + let length_xlen = context.xlen_type().const_int(const_length, false); + self.emit_exit_unchecked(context, offset_xlen, length_xlen, false)?; + } else { + let offset_val = context.word_const(const_offset); + let length_val = context.word_const(const_length); + revive_llvm_context::polkavm_evm_return::r#return(context, offset_val, length_val) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + + context.build_unreachable(); + + context.set_basic_block(current_block); + + self.return_blocks.insert(key, return_block); + Ok(return_block) + } + + /// Detects a Solidity validator: single-param void function whose body is + /// `if iszero(eq(v, and(v, M))) { revert/panic }` where `M = 2^N - 1`. + /// Returns the mask if the body matches. + fn extract_validator_mask(function: &Function) -> Option { + use num::Zero; + + if function.parameters.len() != 1 || !function.returns.is_empty() { + return None; + } + let param_id = function.parameters[0].0 .0; + let stmts = &function.body.statements; + if stmts.len() < 5 { + return None; + } + + let mut constants: BTreeMap = BTreeMap::new(); + let mut and_results: BTreeMap = BTreeMap::new(); + let mut eq_results: BTreeMap = BTreeMap::new(); + let mut iszero_results: BTreeMap = BTreeMap::new(); + + for statement in stmts { + match statement { + Statement::Let { bindings, value } => { + if bindings.len() != 1 { + continue; + } + let bid = bindings[0].0; + match value { + Expression::Literal { value, .. } => { + constants.insert(bid, value.clone()); + } + Expression::Binary { + operation: BinaryOperation::And, + lhs, + rhs, + } => { + and_results.insert(bid, (lhs.id.0, rhs.id.0)); + } + Expression::Binary { + operation: BinaryOperation::Eq, + lhs, + rhs, + } => { + eq_results.insert(bid, (lhs.id.0, rhs.id.0)); + } + Expression::Unary { + operation: UnaryOperation::IsZero, + operand, + } => { + iszero_results.insert(bid, operand.id.0); + } + _ => {} + } + } + Statement::If { + condition, + then_region, + else_region, + .. + } => { + if else_region.is_some() { + return None; + } + if !Self::then_region_aborts(then_region) { + return None; + } + let neg_id = iszero_results.get(&condition.id.0)?; + let (eq_lhs, eq_rhs) = eq_results.get(neg_id)?; + let &(and_lhs, and_rhs) = if eq_lhs == ¶m_id { + and_results.get(eq_rhs)? + } else if eq_rhs == ¶m_id { + and_results.get(eq_lhs)? + } else { + return None; + }; + let mask = if and_lhs == param_id { + constants.get(&and_rhs)? + } else if and_rhs == param_id { + constants.get(&and_lhs)? + } else { + return None; + }; + if mask.is_zero() { + return None; + } + let next = mask + num::BigUint::from(1u32); + if (&next & mask) != num::BigUint::zero() { + return None; + } + return Some(mask.clone()); + } + _ => return None, + } + } + None + } + + /// Emits `llvm.assume(value u<= MASK)` after a validator call. This + /// gives LLVM the range constraint without inlining the validator body. + /// `value` is the LLVM value passed as the validator's single argument. + fn emit_validator_assume( + &self, + context: &mut PolkaVMContext<'ctx>, + value: BasicValueEnum<'ctx>, + mask: &num::BigUint, + ) -> Result<()> { + let integer_value = match value { + BasicValueEnum::IntValue(v) => v, + _ => return Ok(()), + }; + let value_width = integer_value.get_type().get_bit_width(); + let mask_bits = mask.bits() as u32; + if mask_bits >= value_width { + return Ok(()); + } + let mask_str = mask.to_str_radix(16); + let mask_const = integer_value + .get_type() + .const_int_from_string(&mask_str, inkwell::types::StringRadix::Hexadecimal) + .ok_or_else(|| CodegenError::Llvm(format!("invalid validator mask: {mask}")))?; + let cmp = context + .builder() + .build_int_compare( + inkwell::IntPredicate::ULE, + integer_value, + mask_const, + "validator_assume_cmp", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let assume = inkwell::intrinsics::Intrinsic::find("llvm.assume") + .expect("ICE: llvm.assume intrinsic exists"); + let assume_decl = assume + .get_declaration(context.module(), &[]) + .expect("ICE: llvm.assume declaration"); + context + .builder() + .build_call(assume_decl, &[cmp.into()], "validator_assume") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + Ok(()) + } + + fn then_region_aborts(region: &crate::ir::Region) -> bool { + for statement in ®ion.statements { + match statement { + Statement::Revert { .. } | Statement::Return { .. } => return true, + Statement::Stop | Statement::Invalid => return true, + Statement::Expression(Expression::Call { .. }) => continue, + Statement::Let { .. } => continue, + _ => return false, + } + } + matches!( + region.statements.last(), + Some(Statement::Revert { .. }) + | Some(Statement::Return { .. }) + | Some(Statement::Stop) + | Some(Statement::Invalid) + | Some(Statement::Expression(Expression::Call { .. })) + ) + } + + /// Find callvalue ValueIds that are ONLY used as conditions in + /// `if callvalue() { revert(0,0) }` or If condition patterns. + /// These can be skipped during codegen because __revive_callvalue_check() + /// and __revive_callvalue_nonzero() handle reading callvalue internally. + fn find_dead_callvalue_ids(object: &Object) -> BTreeSet { + let mut callvalue_ids = BTreeSet::new(); + let mut used_ids = BTreeSet::new(); + + Self::find_callvalue_bindings(&object.code.statements, &mut callvalue_ids); + for function in object.functions.values() { + Self::find_callvalue_bindings(&function.body.statements, &mut callvalue_ids); + } + + Self::find_value_uses(&object.code.statements, &callvalue_ids, &mut used_ids); + for function in object.functions.values() { + Self::find_value_uses(&function.body.statements, &callvalue_ids, &mut used_ids); + } + + callvalue_ids.difference(&used_ids).copied().collect() + } + + fn find_callvalue_bindings(statements: &[Statement], ids: &mut BTreeSet) { + for statement in statements { + if let Statement::Let { bindings, value } = statement { + if bindings.len() == 1 && matches!(value, Expression::CallValue) { + ids.insert(bindings[0].0); + } + } + Self::for_each_nested_region(statement, |region_stmts| { + Self::find_callvalue_bindings(region_stmts, ids); + }); + } + } + + /// Find uses of callvalue IDs in non-condition positions. + /// If conditions are OK (handled by callvalue_nonzero); everything else is "used". + fn find_value_uses( + statements: &[Statement], + callvalue_ids: &BTreeSet, + used: &mut BTreeSet, + ) { + for statement in statements { + match statement { + Statement::Let { value, .. } | Statement::Expression(value) => { + Self::collect_expr_value_refs(value, callvalue_ids, used); + } + Statement::MStore { offset, value, .. } + | Statement::MStore8 { offset, value, .. } => { + Self::mark_if_callvalue(offset.id.0, callvalue_ids, used); + Self::mark_if_callvalue(value.id.0, callvalue_ids, used); + } + Statement::SStore { key, value, .. } | Statement::TStore { key, value } => { + Self::mark_if_callvalue(key.id.0, callvalue_ids, used); + Self::mark_if_callvalue(value.id.0, callvalue_ids, used); + } + Statement::If { inputs, .. } => { + for v in inputs { + Self::mark_if_callvalue(v.id.0, callvalue_ids, used); + } + } + Statement::Switch { + scrutinee, inputs, .. + } => { + Self::mark_if_callvalue(scrutinee.id.0, callvalue_ids, used); + for v in inputs { + Self::mark_if_callvalue(v.id.0, callvalue_ids, used); + } + } + Statement::Revert { offset, length } | Statement::Return { offset, length } => { + Self::mark_if_callvalue(offset.id.0, callvalue_ids, used); + Self::mark_if_callvalue(length.id.0, callvalue_ids, used); + } + Statement::Log { + offset, + length, + topics, + } => { + Self::mark_if_callvalue(offset.id.0, callvalue_ids, used); + Self::mark_if_callvalue(length.id.0, callvalue_ids, used); + for t in topics { + Self::mark_if_callvalue(t.id.0, callvalue_ids, used); + } + } + Statement::ExternalCall { + gas, + address, + value, + args_offset, + args_length, + ret_offset, + ret_length, + .. + } => { + Self::mark_if_callvalue(gas.id.0, callvalue_ids, used); + Self::mark_if_callvalue(address.id.0, callvalue_ids, used); + if let Some(v) = value { + Self::mark_if_callvalue(v.id.0, callvalue_ids, used); + } + Self::mark_if_callvalue(args_offset.id.0, callvalue_ids, used); + Self::mark_if_callvalue(args_length.id.0, callvalue_ids, used); + Self::mark_if_callvalue(ret_offset.id.0, callvalue_ids, used); + Self::mark_if_callvalue(ret_length.id.0, callvalue_ids, used); + } + Statement::Create { + value, + offset, + length, + salt, + .. + } => { + Self::mark_if_callvalue(value.id.0, callvalue_ids, used); + Self::mark_if_callvalue(offset.id.0, callvalue_ids, used); + Self::mark_if_callvalue(length.id.0, callvalue_ids, used); + if let Some(s) = salt { + Self::mark_if_callvalue(s.id.0, callvalue_ids, used); + } + } + Statement::CustomErrorRevert { arguments, .. } => { + for a in arguments { + Self::mark_if_callvalue(a.id.0, callvalue_ids, used); + } + } + Statement::Leave { return_values } => { + for v in return_values { + Self::mark_if_callvalue(v.id.0, callvalue_ids, used); + } + } + Statement::Break { values } | Statement::Continue { values } => { + for v in values { + Self::mark_if_callvalue(v.id.0, callvalue_ids, used); + } + } + Statement::For { + initial_values, + condition, + .. + } => { + for v in initial_values { + Self::mark_if_callvalue(v.id.0, callvalue_ids, used); + } + Self::collect_expr_value_refs(condition, callvalue_ids, used); + } + Statement::MCopy { dest, src, length } => { + Self::mark_if_callvalue(dest.id.0, callvalue_ids, used); + Self::mark_if_callvalue(src.id.0, callvalue_ids, used); + Self::mark_if_callvalue(length.id.0, callvalue_ids, used); + } + Statement::SelfDestruct { address } => { + Self::mark_if_callvalue(address.id.0, callvalue_ids, used); + } + Statement::CodeCopy { + dest, + offset, + length, + } => { + Self::mark_if_callvalue(dest.id.0, callvalue_ids, used); + Self::mark_if_callvalue(offset.id.0, callvalue_ids, used); + Self::mark_if_callvalue(length.id.0, callvalue_ids, used); + } + Statement::ExtCodeCopy { + address, + dest, + offset, + length, + } => { + Self::mark_if_callvalue(address.id.0, callvalue_ids, used); + Self::mark_if_callvalue(dest.id.0, callvalue_ids, used); + Self::mark_if_callvalue(offset.id.0, callvalue_ids, used); + Self::mark_if_callvalue(length.id.0, callvalue_ids, used); + } + Statement::MappingSStore { key, slot, value } => { + Self::mark_if_callvalue(key.id.0, callvalue_ids, used); + Self::mark_if_callvalue(slot.id.0, callvalue_ids, used); + Self::mark_if_callvalue(value.id.0, callvalue_ids, used); + } + _ => {} + } + Self::for_each_nested_region(statement, |region_stmts| { + Self::find_value_uses(region_stmts, callvalue_ids, used); + }); + } + } + + fn mark_if_callvalue(id: u32, callvalue_ids: &BTreeSet, used: &mut BTreeSet) { + if callvalue_ids.contains(&id) { + used.insert(id); + } + } + + fn collect_expr_value_refs( + expression: &Expression, + callvalue_ids: &BTreeSet, + used: &mut BTreeSet, + ) { + match expression { + Expression::Var(v) => Self::mark_if_callvalue(v.0, callvalue_ids, used), + Expression::Binary { lhs, rhs, .. } => { + Self::mark_if_callvalue(lhs.id.0, callvalue_ids, used); + Self::mark_if_callvalue(rhs.id.0, callvalue_ids, used); + } + Expression::Unary { operand, .. } + | Expression::Truncate { value: operand, .. } + | Expression::ZeroExtend { value: operand, .. } + | Expression::SignExtendTo { value: operand, .. } => { + Self::mark_if_callvalue(operand.id.0, callvalue_ids, used); + } + Expression::Call { arguments, .. } => { + for a in arguments { + Self::mark_if_callvalue(a.id.0, callvalue_ids, used); + } + } + Expression::Keccak256 { offset, length } + | Expression::Keccak256Pair { + word0: offset, + word1: length, + } + | Expression::MappingSLoad { + key: offset, + slot: length, + } => { + Self::mark_if_callvalue(offset.id.0, callvalue_ids, used); + Self::mark_if_callvalue(length.id.0, callvalue_ids, used); + } + Expression::Keccak256Single { word0 } => { + Self::mark_if_callvalue(word0.id.0, callvalue_ids, used); + } + Expression::CallDataLoad { offset } => { + Self::mark_if_callvalue(offset.id.0, callvalue_ids, used); + } + Expression::MLoad { offset, .. } => { + Self::mark_if_callvalue(offset.id.0, callvalue_ids, used); + } + _ => {} + } + } + + /// Call a closure for each nested region's statements in a statement. + fn for_each_nested_region(statement: &Statement, mut f: F) { + match statement { + Statement::If { + then_region, + else_region, + .. + } => { + f(&then_region.statements); + if let Some(r) = else_region { + f(&r.statements); + } + } + Statement::Switch { cases, default, .. } => { + for case in cases { + f(&case.body.statements); + } + if let Some(d) = default { + f(&d.statements); + } + } + Statement::For { + condition_statements, + body, + post, + .. + } => { + f(condition_statements); + f(&body.statements); + f(&post.statements); + } + Statement::Block(region) => { + f(®ion.statements); + } + _ => {} + } + } + + /// Counts MappingSLoad and MappingSStore operations separately in an object. + fn count_mapping_ops(object: &Object) -> (usize, usize) { + fn count_in_stmts(statements: &[Statement]) -> (usize, usize) { + let mut sloads = 0; + let mut sstores = 0; + for statement in statements { + match statement { + Statement::Let { + value: Expression::MappingSLoad { .. }, + .. + } => sloads += 1, + Statement::MappingSStore { .. } => sstores += 1, + _ => {} + } + match statement { + Statement::If { + then_region, + else_region, + .. + } => { + let (s, w) = count_in_stmts(&then_region.statements); + sloads += s; + sstores += w; + if let Some(r) = else_region { + let (s, w) = count_in_stmts(&r.statements); + sloads += s; + sstores += w; + } + } + Statement::Switch { cases, default, .. } => { + for c in cases { + let (s, w) = count_in_stmts(&c.body.statements); + sloads += s; + sstores += w; + } + if let Some(d) = default { + let (s, w) = count_in_stmts(&d.statements); + sloads += s; + sstores += w; + } + } + Statement::For { + condition_statements, + body, + post, + .. + } => { + let (s, w) = count_in_stmts(condition_statements); + sloads += s; + sstores += w; + let (s, w) = count_in_stmts(&body.statements); + sloads += s; + sstores += w; + let (s, w) = count_in_stmts(&post.statements); + sloads += s; + sstores += w; + } + Statement::Block(region) => { + let (s, w) = count_in_stmts(®ion.statements); + sloads += s; + sstores += w; + } + _ => {} + } + } + (sloads, sstores) + } + + let (mut total_sloads, mut total_sstores) = count_in_stmts(&object.code.statements); + for function in object.functions.values() { + let (s, w) = count_in_stmts(&function.body.statements); + total_sloads += s; + total_sstores += w; + } + (total_sloads, total_sstores) + } + + /// Counts MStore sites whose value is a compile-time constant matching + /// the low-word or high-word patterns recognised by the specialised + /// store helpers. Returns `(low_word_count, high_word_count)`. Used to + /// gate the introduction of those helpers — each helper costs ~25 + /// bytes in body overhead, so we only emit it when there are enough + /// call sites to amortise that cost (per-site savings are ~3 inst). + fn count_constant_mstore_patterns(object: &Object) -> (usize, usize) { + use crate::ir::for_each_statement; + use num::Zero; + + let mut literals: BTreeMap = BTreeMap::new(); + let mut record = |s: &Statement| { + if let Statement::Let { bindings, value } = s { + if bindings.len() == 1 { + if let Expression::Literal { value: lit_val, .. } = value { + literals.insert(bindings[0].0, lit_val.clone()); + } + } + } + }; + for_each_statement(&object.code.statements, &mut record); + for function in object.functions.values() { + for_each_statement(&function.body.statements, &mut record); + } + + let classify = |value: &Value| -> Option { + let lit_val = literals.get(&value.id.0)?; + if lit_val.is_zero() { + return None; + } + if lit_val.bits() <= 64 { + return Some(true); + } + let low_mask: num::BigUint = (num::BigUint::from(1u32) << 224) - 1u32; + if (lit_val & &low_mask).is_zero() { + let top: num::BigUint = lit_val >> 224u32; + let digits = top.to_u64_digits(); + if digits.len() == 1 && digits[0] <= u32::MAX as u64 { + return Some(false); + } + } + None + }; + + let mut low_total = 0usize; + let mut high_total = 0usize; + let mut count = |s: &Statement| { + if let Statement::MStore { value, .. } = s { + match classify(value) { + Some(true) => low_total += 1, + Some(false) => high_total += 1, + None => {} + } + } + }; + for_each_statement(&object.code.statements, &mut count); + for function in object.functions.values() { + for_each_statement(&function.body.statements, &mut count); + } + (low_total, high_total) + } + + /// Generates LLVM IR for a complete object. + pub fn generate_object( + &mut self, + object: &Object, + context: &mut PolkaVMContext<'ctx>, + ) -> Result<()> { + self.revert_blocks.clear(); + self.return_blocks.clear(); + self.panic_blocks.clear(); + + let syscall_counts = object.count_syscall_sites(); + const CALLVALUE_OUTLINE_THRESHOLD: usize = 3; + const CALLER_OUTLINE_THRESHOLD: usize = 3; + self.use_outlined_callvalue = syscall_counts.callvalue >= CALLVALUE_OUTLINE_THRESHOLD; + if self.use_outlined_callvalue { + self.dead_callvalue_ids = Self::find_dead_callvalue_ids(object); + } + const CALLDATALOAD_OUTLINE_THRESHOLD: usize = 20; + self.use_outlined_calldataload = + syscall_counts.calldataload >= CALLDATALOAD_OUTLINE_THRESHOLD; + self.use_outlined_caller = syscall_counts.caller >= CALLER_OUTLINE_THRESHOLD; + const CONST_STORE_PATTERN_THRESHOLD: usize = 5; + let (low_word_sites, high_word_sites) = Self::count_constant_mstore_patterns(object); + self.use_outlined_store_low_word = low_word_sites >= CONST_STORE_PATTERN_THRESHOLD; + self.use_outlined_store_high_word = high_word_sites >= CONST_STORE_PATTERN_THRESHOLD; + const MAPPING_COMBINED_THRESHOLD: usize = 9; + let (mapping_sloads, mapping_sstores) = Self::count_mapping_ops(object); + let combined_mapping_ops = mapping_sloads + mapping_sstores; + self.use_outlined_mapping_sload = + mapping_sloads > 0 && combined_mapping_ops >= MAPPING_COMBINED_THRESHOLD; + self.use_outlined_mapping_sstore = + mapping_sstores > 0 && combined_mapping_ops >= MAPPING_COMBINED_THRESHOLD; + self.has_msize = object.has_msize(); + self.error_string_revert_counts = object.count_error_string_reverts(); + self.custom_error_revert_counts = object.count_custom_error_reverts(); + + let is_runtime = object.name.ends_with("_deployed"); + if is_runtime { + context.set_code_type(revive_llvm_context::PolkaVMCodeType::Runtime); + } else { + context.set_code_type(revive_llvm_context::PolkaVMCodeType::Deploy); + } + + context.push_function_scope(); + + self.validator_masks.clear(); + for (func_id, function) in &object.functions { + if let Some(mask) = Self::extract_validator_mask(function) { + self.validator_masks.insert(func_id.0, mask); + } + } + + for (func_id, function) in &object.functions { + self.declare_function(function, context)?; + self.function_names.insert(func_id.0, function.name.clone()); + self.function_param_types.insert( + func_id.0, + function + .parameters + .iter() + .map(|(_, value_type)| *value_type) + .collect(), + ); + self.function_return_types + .insert(func_id.0, function.returns.clone()); + } + + for function in object.functions.values() { + self.set_inline_attributes(function, context); + } + + for function in object.functions.values() { + self.generate_function(function, context)?; + } + + let function_name = if is_runtime { + PolkaVMFunctionRuntimeCode + } else { + PolkaVMFunctionDeployCode + }; + + context + .set_current_function(function_name, None, false) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context.set_basic_block(context.current_function().borrow().entry_block()); + + self.generate_block(&object.code, context)?; + + context + .set_debug_location(0, 0, None) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + match context + .basic_block() + .get_last_instruction() + .map(|i| i.get_opcode()) + { + Some(inkwell::values::InstructionOpcode::Br) => {} + Some(inkwell::values::InstructionOpcode::Switch) => {} + Some(inkwell::values::InstructionOpcode::Return) => {} + Some(inkwell::values::InstructionOpcode::Unreachable) => {} + _ => { + context + .build_unconditional_branch(context.current_function().borrow().return_block()); + } + } + + context.set_basic_block(context.current_function().borrow().return_block()); + context.build_return(None); + + context.pop_debug_scope(); + context.pop_function_scope(); + + for (i, subobject) in object.subobjects.iter().enumerate() { + let sub_type_info = self + .type_info + .sub_inferences + .get(i) + .cloned() + .unwrap_or_else(|| self.type_info.clone()); + let mut subobject_codegen = LlvmCodegen::new_with_shared_functions( + self.generated_functions.clone(), + self.heap_opt.clone(), + sub_type_info, + self.inline_decisions.clone(), + ); + subobject_codegen.generate_object(subobject, context)?; + self.generated_functions + .extend(subobject_codegen.generated_functions); + } + + Ok(()) + } + + /// Declares a function (without generating body). + /// If the function already exists (e.g., shared utility functions in multi-contract scenarios), + /// this will skip re-declaring it. + pub fn declare_function( + &mut self, + function: &Function, + context: &mut PolkaVMContext<'ctx>, + ) -> Result<()> { + if context.get_function(&function.name, true).is_some() { + return Ok(()); + } + + let argument_types: Vec<_> = function + .parameters + .iter() + .map(|(_, value_type)| self.ir_type_to_llvm(*value_type, context)) + .collect(); + + let has_narrow_returns = function.returns.iter().any( + |value_type| matches!(value_type, Type::Int(bit_width) if *bit_width < BitWidth::I256), + ); + + let function_type = if has_narrow_returns { + let return_types: Vec<_> = function + .returns + .iter() + .map(|value_type| match value_type { + Type::Int(bit_width) => context.integer_type(bit_width.bits() as usize), + _ => context.word_type(), + }) + .collect(); + context.function_type_with_returns(argument_types, &return_types) + } else { + context.function_type(argument_types, function.returns.len()) + }; + + context.add_function( + &function.name, + function_type, + function.returns.len(), + Some(inkwell::module::Linkage::Internal), + None, + true, + )?; + + Ok(()) + } + + /// Sets LLVM inline attributes on a declared function based on our custom + /// heuristics. + /// + /// This provides guidance to LLVM's inliner for functions that survived + /// our IR-level inlining pass. We use `AlwaysInline` for functions we + /// know should be inlined, and `NoInline` only for large functions or + /// those called from many sites where inlining would cause significant + /// code bloat. For the `CostBenefit` decision specifically we apply + /// `NoInline` whenever the call count is >= 3 or the body exceeds + /// [`LARGE_FUNCTION_NOINLINE_THRESHOLD`] — otherwise MinSize-aware LLVM + /// inlining can undo the IR-level decision and re-inline the body at + /// every site, costing more bytes than the saved call overhead. For + /// other functions, we let LLVM decide using its own heuristics (it + /// already has MinSize/OptimizeForSize from `set_default_attributes`). + fn set_inline_attributes(&self, function: &Function, context: &PolkaVMContext<'ctx>) { + // Library/post-link compilations run with the middle end disabled and have + // `NoInline`/`OptimizeNone` forced on every function by `set_default_attributes`. + // Stacking `AlwaysInline` on top would produce contradictory attributes and + // trip the LLVM IR verifier; the hints would be inert there anyway. + if !context.optimizer_settings().is_middle_end_enabled() { + return; + } + + let declaration = match context.get_function(&function.name, true) { + Some(func_ref) => func_ref.borrow().declaration(), + None => return, + }; + + let ir_decision = self.inline_decisions.get(&function.id.0).copied(); + + let attr = match ir_decision { + Some(crate::InlineDecision::AlwaysInline) => { + Some(revive_llvm_context::PolkaVMAttribute::AlwaysInline) + } + Some(crate::InlineDecision::NeverInline) => { + if function.size_estimate >= LARGE_FUNCTION_NOINLINE_THRESHOLD { + Some(revive_llvm_context::PolkaVMAttribute::NoInline) + } else { + None + } + } + Some(crate::InlineDecision::CostBenefit) => { + let force_noinline = function.call_count >= 3 + || function.size_estimate >= LARGE_FUNCTION_NOINLINE_THRESHOLD; + if force_noinline { + Some(revive_llvm_context::PolkaVMAttribute::NoInline) + } else { + None + } + } + None => { + if function.size_estimate <= SMALL_FUNCTION_ALWAYSINLINE_THRESHOLD { + Some(revive_llvm_context::PolkaVMAttribute::AlwaysInline) + } else { + None + } + } + }; + + if let Some(attr) = attr { + revive_llvm_context::PolkaVMFunction::set_attributes( + context.llvm(), + declaration, + &[attr], + true, + ); + } + } + + /// Generates LLVM IR for a function body. + /// If the function body has already been generated (shared utility functions in multi-contract + /// scenarios), this will skip regenerating it. + fn generate_function( + &mut self, + function: &Function, + context: &mut PolkaVMContext<'ctx>, + ) -> Result<()> { + let internal_name = format!( + "{}_{}", + function.name, + context + .code_type() + .map(|c| format!("{:?}", c)) + .unwrap_or_default() + ); + + if self.generated_functions.contains(&internal_name) { + return Ok(()); + } + self.generated_functions.insert(internal_name); + + let saved_revert_blocks = std::mem::take(&mut self.revert_blocks); + let saved_return_blocks = std::mem::take(&mut self.return_blocks); + let saved_panic_blocks = std::mem::take(&mut self.panic_blocks); + + let saved_values = std::mem::take(&mut self.values); + let saved_callvalue_ids = std::mem::take(&mut self.callvalue_value_ids); + let saved_return_types = + std::mem::replace(&mut self.current_return_types, function.returns.clone()); + + context.set_current_function(&function.name, None, true)?; + context.set_basic_block(context.current_function().borrow().entry_block()); + + for (index, (parameter_id, parameter_type)) in function.parameters.iter().enumerate() { + let parameter_value = context.current_function().borrow().get_nth_param(index); + let stored_value = match parameter_type { + Type::Int(width) if *width < BitWidth::I256 => { + let narrow_value = parameter_value.into_int_value(); + context + .builder() + .build_int_z_extend( + narrow_value, + context.word_type(), + &format!("parameter_{}_extend", index), + ) + .map_err(|e| anyhow::anyhow!("LLVM error: {e}"))? + .as_basic_value_enum() + } + _ => parameter_value, + }; + self.set_value(*parameter_id, stored_value); + } + + let zero = context.word_const(0).as_basic_value_enum(); + for ret_id in &function.return_values_initial { + self.set_value(*ret_id, zero); + } + for ret_id in &function.return_values { + self.set_value(*ret_id, zero); + } + + self.generate_block(&function.body, context)?; + + match context.current_function().borrow().r#return() { + revive_llvm_context::PolkaVMFunctionReturn::None => {} + revive_llvm_context::PolkaVMFunctionReturn::Primitive { pointer } => { + if !function.return_values.is_empty() { + if let Ok(return_value) = self.get_value(function.return_values[0]) { + let return_value = if return_value.is_int_value() { + let integer_value = return_value.into_int_value(); + match function.returns.first() { + Some(Type::Int(bit_width)) if *bit_width < BitWidth::I256 => { + let target = context.integer_type(bit_width.bits() as usize); + let val_bits = integer_value.get_type().get_bit_width(); + let tgt_bits = target.get_bit_width(); + if val_bits > tgt_bits { + context + .builder() + .build_int_truncate(integer_value, target, "ret_narrow") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum() + } else if val_bits < tgt_bits { + context + .builder() + .build_int_z_extend(integer_value, target, "ret_widen") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum() + } else { + integer_value.as_basic_value_enum() + } + } + _ => self + .ensure_word_type(context, integer_value, "return_value")? + .as_basic_value_enum(), + } + } else { + return_value + }; + context.build_store(pointer, return_value)?; + } + } + } + revive_llvm_context::PolkaVMFunctionReturn::Compound { pointer, size } => { + let field_types: Vec<_> = (0..size) + .map(|i| match function.returns.get(i) { + Some(Type::Int(bit_width)) if *bit_width < BitWidth::I256 => context + .integer_type(bit_width.bits() as usize) + .as_basic_type_enum(), + _ => context.word_type().as_basic_type_enum(), + }) + .collect(); + let struct_type = context.structure_type(&field_types); + let mut struct_val = struct_type.get_undef(); + for (i, ret_id) in function.return_values.iter().enumerate() { + if let Ok(return_value) = self.get_value(*ret_id) { + let return_value = if return_value.is_int_value() { + let integer_value = return_value.into_int_value(); + match function.returns.get(i) { + Some(Type::Int(bit_width)) if *bit_width < BitWidth::I256 => { + let target = context.integer_type(bit_width.bits() as usize); + let val_bits = integer_value.get_type().get_bit_width(); + let tgt_bits = target.get_bit_width(); + if val_bits > tgt_bits { + context + .builder() + .build_int_truncate( + integer_value, + target, + &format!("ret_narrow_{}", i), + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum() + } else if val_bits < tgt_bits { + context + .builder() + .build_int_z_extend( + integer_value, + target, + &format!("ret_widen_{}", i), + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum() + } else { + integer_value.as_basic_value_enum() + } + } + _ => self + .ensure_word_type( + context, + integer_value, + &format!("ret_val_{}", i), + )? + .as_basic_value_enum(), + } + } else { + return_value + }; + struct_val = context + .builder() + .build_insert_value(struct_val, return_value, i as u32, "ret_insert") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .into_struct_value(); + } + } + context.build_store(pointer, struct_val.as_basic_value_enum())?; + } + } + + let return_block = context.current_function().borrow().return_block(); + context.build_unconditional_branch(return_block); + context.set_basic_block(return_block); + + match context.current_function().borrow().r#return() { + revive_llvm_context::PolkaVMFunctionReturn::None => { + context.build_return(None); + } + revive_llvm_context::PolkaVMFunctionReturn::Primitive { pointer } => { + let return_value = context + .build_load(pointer, "return_value") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context.build_return(Some(&return_value)); + } + revive_llvm_context::PolkaVMFunctionReturn::Compound { pointer, .. } => { + let return_value = context + .build_load(pointer, "return_value") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context.build_return(Some(&return_value)); + } + } + + context.pop_debug_scope(); + + self.values = saved_values; + self.callvalue_value_ids = saved_callvalue_ids; + self.current_return_types = saved_return_types; + self.revert_blocks = saved_revert_blocks; + self.return_blocks = saved_return_blocks; + self.panic_blocks = saved_panic_blocks; + + Ok(()) + } + + /// Generates LLVM IR for a block. + fn generate_block(&mut self, block: &Block, context: &mut PolkaVMContext<'ctx>) -> Result<()> { + self.generate_statement_list(&block.statements, context) + } + + /// Generates LLVM IR for a region. + fn generate_region( + &mut self, + region: &Region, + context: &mut PolkaVMContext<'ctx>, + ) -> Result<()> { + self.generate_statement_list(®ion.statements, context) + } + + /// Generates LLVM IR for a list of statements, with look-ahead for compound patterns. + /// + /// Detects `MStore(off, value) [+ Let(vN, Literal(32))] + Return(off, 32)` → `return_word`: + /// combines a bswap-store and seal_return into a single noreturn function call, + /// eliminating one function call and one redundant bounds check per site. + fn generate_statement_list( + &mut self, + statements: &[Statement], + context: &mut PolkaVMContext<'ctx>, + ) -> Result<()> { + let mut i = 0; + while i < statements.len() { + if let Some(skip) = self.try_match_return_word(statements, i, context)? { + i += skip; + continue; + } + self.generate_statement(&statements[i], context)?; + i += 1; + } + Ok(()) + } + + /// Tries to match and generate a combined return_word pattern. + /// Returns `Ok(Some(skip_count))` if matched, `Ok(None)` if no match. + /// + /// Patterns: + /// - `MStore(off, value) + Return(off, 32)` (2 statements) + /// - `MStore(off, value) + Let(vN, Literal(32)) + Return(off, vN)` (3 statements) + /// + /// Requirements: same offset ValueId, length = 32, ByteSwap mode, !msize, !deploy. + fn try_match_return_word( + &mut self, + statements: &[Statement], + i: usize, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + if i >= statements.len() { + return Ok(None); + } + + let (store_offset, store_value) = match &statements[i] { + Statement::MStore { offset, value, .. } => (offset, value), + _ => return Ok(None), + }; + + if self.has_msize { + return Ok(None); + } + if matches!( + context.code_type(), + Some(revive_llvm_context::PolkaVMCodeType::Deploy) + ) { + return Ok(None); + } + + let (ret_offset, ret_length, skip) = if i + 1 < statements.len() { + if let Statement::Return { offset, length } = &statements[i + 1] { + (offset, length, 2) + } else if i + 2 < statements.len() { + if let Statement::Return { offset, length } = &statements[i + 2] { + if let Statement::Let { + bindings, + value: Expression::Literal { .. }, + } = &statements[i + 1] + { + if bindings.len() == 1 && bindings[0] == length.id { + (offset, length, 3) + } else { + return Ok(None); + } + } else { + return Ok(None); + } + } else { + return Ok(None); + } + } else { + return Ok(None); + } + } else { + return Ok(None); + }; + + if store_offset.id != ret_offset.id { + return Ok(None); + } + + let offset_val = self.translate_value(store_offset)?.into_int_value(); + if Self::try_extract_const_u64(offset_val).is_some() { + return Ok(None); + } + + if skip == 3 { + if let Statement::Let { + value: Expression::Literal { value, .. }, + .. + } = &statements[i + 1] + { + if value != &num::BigUint::from(revive_common::BYTE_LENGTH_WORD as u64) { + return Ok(None); + } + } else { + return Ok(None); + } + } else { + let length_val = self.translate_value(ret_length)?.into_int_value(); + let const_len = Self::try_extract_const_u64(length_val); + if const_len != Some(revive_common::BYTE_LENGTH_WORD as u64) { + return Ok(None); + } + } + + let offset_narrow = self.narrow_offset_for_pointer( + context, + offset_val, + store_offset.id, + "return_word_offset_narrow", + )?; + let offset_xlen = context + .safe_truncate_int_to_xlen(offset_narrow) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + let value_val = self.translate_value(store_value)?.into_int_value(); + let value_val = self.ensure_word_type(context, value_val, "return_word_val")?; + + let function = self.get_or_create_return_word_fn(context)?; + context + .builder() + .build_call(function, &[offset_xlen.into(), value_val.into()], "") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + context.build_unreachable(); + let dead_block = context.append_basic_block("return_word_dead"); + context.set_basic_block(dead_block); + + Ok(Some(skip)) + } + + /// Generates LLVM IR for a statement. + fn generate_statement( + &mut self, + statement: &Statement, + context: &mut PolkaVMContext<'ctx>, + ) -> Result<()> { + let statement_kind = match statement { + Statement::Let { .. } => "Let", + Statement::MStore { .. } => "MStore", + Statement::MStore8 { .. } => "MStore8", + Statement::MCopy { .. } => "MCopy", + Statement::SStore { .. } => "SStore", + Statement::TStore { .. } => "TStore", + Statement::If { .. } => "If", + Statement::Switch { .. } => "Switch", + Statement::For { .. } => "For", + Statement::Return { .. } => "Return", + Statement::Revert { .. } => "Revert", + Statement::Leave { .. } => "Leave", + Statement::ExternalCall { .. } => "ExternalCall", + Statement::Create { .. } => "Create", + Statement::SelfDestruct { .. } => "SelfDestruct", + Statement::Log { .. } => "Log", + Statement::CodeCopy { .. } => "CodeCopy", + Statement::ExtCodeCopy { .. } => "ExtCodeCopy", + Statement::ReturnDataCopy { .. } => "ReturnDataCopy", + Statement::CallDataCopy { .. } => "CallDataCopy", + Statement::Block(_) => "Block", + Statement::Expression(_) => "Expression", + Statement::SetImmutable { .. } => "SetImmutable", + Statement::Continue { .. } => "Continue", + Statement::Break { .. } => "Break", + Statement::Stop => "Stop", + Statement::Invalid => "Invalid", + Statement::PanicRevert { .. } => "PanicRevert", + Statement::ErrorStringRevert { .. } => "ErrorStringRevert", + Statement::CustomErrorRevert { .. } => "CustomErrorRevert", + Statement::DataCopy { .. } => "DataCopy", + Statement::MappingSStore { .. } => "MappingSStore", + }; + + if let Err(e) = self.generate_statement_inner(statement, context) { + return Err(CodegenError::Llvm(format!( + "Error in {} statement: {}", + statement_kind, e + ))); + } + Ok(()) + } + + /// Inner implementation of generate_statement. + fn generate_statement_inner( + &mut self, + statement: &Statement, + context: &mut PolkaVMContext<'ctx>, + ) -> Result<()> { + match statement { + Statement::Let { bindings, value } => { + if bindings.len() == 1 && matches!(value, Expression::CallValue) { + self.callvalue_value_ids.insert(bindings[0].0); + if self.dead_callvalue_ids.contains(&bindings[0].0) { + return Ok(()); + } + } + + let demand = if bindings.len() == 1 { + let binding_id = bindings[0]; + let constraint = self.type_info.get(binding_id); + if !constraint.is_signed { + let dw = self.type_info.use_demand_width(binding_id); + match dw { + BitWidth::I1 | BitWidth::I8 | BitWidth::I32 | BitWidth::I64 => { + Some(dw.bits()) + } + _ => None, + } + } else { + None + } + } else { + None + }; + + let llvm_value = self.generate_expression(value, context, demand)?; + if bindings.len() == 1 { + let binding_id = bindings[0]; + let llvm_value = + self.try_narrow_let_binding(context, llvm_value, binding_id)?; + self.set_value(binding_id, llvm_value); + } else { + let struct_val = llvm_value.into_struct_value(); + for (index, binding) in bindings.iter().enumerate() { + let field = context + .builder() + .build_extract_value(struct_val, index as u32, &format!("{}", index)) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let field = if field.is_int_value() { + let integer_value = field.into_int_value(); + if integer_value.get_type().get_bit_width() < 256 { + context + .builder() + .build_int_z_extend( + integer_value, + context.word_type(), + &format!("{}_extend", index), + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum() + } else { + integer_value.as_basic_value_enum() + } + } else { + field + }; + self.set_value(*binding, field); + } + } + } + + Statement::MStore { + offset, + value, + region, + } => { + let offset_val = self.translate_value(offset)?.into_int_value(); + let value_val = self.translate_value(value)?.into_int_value(); + let value_val = self.ensure_word_type(context, value_val, "mstore_val")?; + + match self.native_memory_mode(offset_val) { + NativeMemoryMode::AllNative => { + let offset_xlen = self.truncate_offset_to_xlen( + context, + offset_val, + "mstore_offset_xlen", + )?; + context.build_store_native(offset_xlen, value_val)?; + } + NativeMemoryMode::InlineNative => { + let offset_xlen = self.truncate_offset_to_xlen( + context, + offset_val, + "mstore_offset_xlen", + )?; + let pointer = context.build_heap_gep_unchecked(offset_xlen)?; + let is_fmp_store = Self::try_extract_const_u64(offset_val) + == Some(FREE_MEMORY_POINTER_SLOT) + && matches!(region, MemoryRegion::FreePointerSlot) + && !self.heap_opt.fmp_could_be_unbounded(); + let store_val: inkwell::values::BasicValueEnum = if is_fmp_store { + context + .builder() + .build_int_truncate( + value_val, + context.xlen_type(), + "fmp_store_trunc", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .into() + } else { + value_val.into() + }; + context + .builder() + .build_store(pointer.value, store_val) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .set_alignment(revive_common::BYTE_LENGTH_BYTE as u32) + .expect("Alignment is valid"); + if self.has_msize { + let static_off = Self::try_extract_const_u64(offset_val) + .unwrap_or(DYNAMIC_HEAP_BASE); + let min_size = context.xlen_type().const_int( + static_off + revive_common::BYTE_LENGTH_WORD as u64, + false, + ); + context + .ensure_heap_size(min_size) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + } + NativeMemoryMode::InlineByteSwap => { + let offset_xlen = self.truncate_offset_to_xlen( + context, + offset_val, + "mstore_offset_xlen", + )?; + if value_val.is_const() { + revive_llvm_context::polkavm_evm_memory::store_bswap_unchecked( + context, + offset_xlen, + value_val, + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } else { + let function = self.get_or_create_store_bswap_fn(context)?; + let value_word = + self.ensure_word_type(context, value_val, "store_bswap_val")?; + context + .builder() + .build_call( + function, + &[offset_xlen.into(), value_word.into()], + "store_bswap", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + if self.has_msize { + let static_off = Self::try_extract_const_u64(offset_val) + .unwrap_or(DYNAMIC_HEAP_BASE); + let min_size = context.xlen_type().const_int( + static_off + revive_common::BYTE_LENGTH_WORD as u64, + false, + ); + context + .ensure_heap_size(min_size) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + } + NativeMemoryMode::ByteSwap => { + let offset_val = self.narrow_offset_for_pointer( + context, + offset_val, + offset.id, + "mstore_offset_narrow", + )?; + if !self.has_msize { + let offset_xlen = context + .safe_truncate_int_to_xlen(offset_val) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + if value_val.is_null() { + let function = self.get_or_create_store_zero_checked_fn(context)?; + context + .builder() + .build_call(function, &[offset_xlen.into()], "") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } else if self.use_outlined_store_low_word + && Self::value_fits_in_i64(value_val).is_some() + { + let low = Self::value_fits_in_i64(value_val).unwrap(); + let function = + self.get_or_create_store_low_word_checked_fn(context)?; + let low_const = context.llvm().i64_type().const_int(low, false); + context + .builder() + .build_call( + function, + &[offset_xlen.into(), low_const.into()], + "", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } else if self.use_outlined_store_high_word + && Self::value_is_selector_shl_224(value_val).is_some() + { + let sel = Self::value_is_selector_shl_224(value_val).unwrap(); + let function = + self.get_or_create_store_high_word_checked_fn(context)?; + let sel_const = + context.llvm().i32_type().const_int(sel as u64, false); + context + .builder() + .build_call( + function, + &[offset_xlen.into(), sel_const.into()], + "", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } else { + let function = + self.get_or_create_store_bswap_checked_fn(context)?; + context + .builder() + .build_call( + function, + &[offset_xlen.into(), value_val.into()], + "", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + } else { + revive_llvm_context::polkavm_evm_memory::store( + context, offset_val, value_val, + )?; + } + } + } + } + + Statement::MStore8 { + offset, + value, + region: _, + } => { + let offset_val = self.translate_value(offset)?.into_int_value(); + let offset_val = self.narrow_offset_for_pointer( + context, + offset_val, + offset.id, + "mstore8_offset_narrow", + )?; + let value_val = self.translate_value(value)?.into_int_value(); + let value_val = self.ensure_word_type(context, value_val, "mstore8_val")?; + revive_llvm_context::polkavm_evm_memory::store_byte( + context, offset_val, value_val, + )?; + } + + Statement::MCopy { dest, src, length } => { + let dest_val = self.translate_value(dest)?.into_int_value(); + let dest_val = self.narrow_offset_for_pointer( + context, + dest_val, + dest.id, + "mcopy_dest_narrow", + )?; + let src_val = self.translate_value(src)?.into_int_value(); + let src_val = + self.narrow_offset_for_pointer(context, src_val, src.id, "mcopy_src_narrow")?; + let len_val = self.translate_value(length)?.into_int_value(); + let len_val = self.narrow_offset_for_pointer( + context, + len_val, + length.id, + "mcopy_length_narrow", + )?; + + let dest_pointer = revive_llvm_context::PolkaVMPointer::new_with_offset( + context, + revive_llvm_context::PolkaVMAddressSpace::Heap, + context.byte_type(), + dest_val, + "mcopy_destination", + ); + let src_pointer = revive_llvm_context::PolkaVMPointer::new_with_offset( + context, + revive_llvm_context::PolkaVMAddressSpace::Heap, + context.byte_type(), + src_val, + "mcopy_source", + ); + + context.build_memcpy(dest_pointer, src_pointer, len_val, "mcopy_size")?; + } + + Statement::SStore { + key, + value, + static_slot: _, + } => { + let key_arg = self.value_to_storage_key_argument(key, context)?; + if key_arg.is_register() { + let key_val = key_arg + .access(context) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let value_val = self + .value_to_argument(value, context)? + .access(context) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let sstore_fn = self.get_or_create_sstore_word_fn(context)?; + context + .builder() + .build_call( + sstore_fn, + &[key_val.into(), value_val.into()], + "sstore_word", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } else { + let value_arg = self.value_to_argument(value, context)?; + revive_llvm_context::polkavm_evm_storage::store(context, &key_arg, &value_arg)?; + } + } + + Statement::TStore { key, value } => { + let key_arg = self.value_to_argument(key, context)?; + let value_arg = self.value_to_argument(value, context)?; + revive_llvm_context::polkavm_evm_storage::transient_store( + context, &key_arg, &value_arg, + )?; + } + + Statement::If { + condition, + inputs, + then_region, + else_region, + outputs, + } => { + if self.use_outlined_callvalue + && self.callvalue_value_ids.contains(&condition.id.0) + && else_region.is_none() + && outputs.is_empty() + && Self::is_revert_zero_region(then_region) + { + let function = self.get_or_create_callvalue_check_fn(context)?; + context + .builder() + .build_call(function, &[], "callvalue_check") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + return Ok(()); + } + + let cond_bool = if self.use_outlined_callvalue + && self.callvalue_value_ids.contains(&condition.id.0) + { + revive_llvm_context::polkavm_evm_ether_gas::value_nonzero_outlined(context) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .into_int_value() + } else { + let cond_val = self.translate_value(condition)?.into_int_value(); + let cond_zero = cond_val.get_type().const_zero(); + context + .builder() + .build_int_compare( + inkwell::IntPredicate::NE, + cond_val, + cond_zero, + "cond_bool", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + }; + + let then_block = context.append_basic_block("if_then"); + let join_block = context.append_basic_block("if_join"); + + let mut phi_incoming: Vec<( + Vec>, + inkwell::basic_block::BasicBlock<'ctx>, + )> = Vec::new(); + + if let Some(else_region) = else_region { + let else_block = context.append_basic_block("if_else"); + context.build_conditional_branch(cond_bool, then_block, else_block)?; + + context.set_basic_block(then_block); + self.generate_region(then_region, context)?; + let then_end_block = context.basic_block(); + if !Self::block_is_unreachable(then_end_block) { + let mut then_yields = Vec::new(); + for (i, yield_val) in then_region.yields.iter().enumerate() { + then_yields.push(self.translate_value_as_word( + yield_val, + context, + &format!("then_yield_{}", i), + )?); + } + context.build_unconditional_branch(join_block); + phi_incoming.push((then_yields, then_end_block)); + } else if then_end_block.get_terminator().is_none() { + context + .builder() + .build_unreachable() + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + + context.set_basic_block(else_block); + self.generate_region(else_region, context)?; + let else_end_block = context.basic_block(); + if !Self::block_is_unreachable(else_end_block) { + let mut else_yields = Vec::new(); + for (i, yield_val) in else_region.yields.iter().enumerate() { + else_yields.push(self.translate_value_as_word( + yield_val, + context, + &format!("else_yield_{}", i), + )?); + } + context.build_unconditional_branch(join_block); + phi_incoming.push((else_yields, else_end_block)); + } else if else_end_block.get_terminator().is_none() { + context + .builder() + .build_unreachable() + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + } else { + let entry_block = context.basic_block(); + context.build_conditional_branch(cond_bool, then_block, join_block)?; + + let mut else_yields = Vec::new(); + for (i, input_val) in inputs.iter().enumerate() { + else_yields.push(self.translate_value_as_word( + input_val, + context, + &format!("input_yield_{}", i), + )?); + } + phi_incoming.push((else_yields, entry_block)); + + context.set_basic_block(then_block); + self.generate_region(then_region, context)?; + let then_end_block = context.basic_block(); + if !Self::block_is_unreachable(then_end_block) { + let mut then_yields = Vec::new(); + for (i, yield_val) in then_region.yields.iter().enumerate() { + then_yields.push(self.translate_value_as_word( + yield_val, + context, + &format!("then_yield_{}", i), + )?); + } + context.build_unconditional_branch(join_block); + phi_incoming.push((then_yields, then_end_block)); + } else if then_end_block.get_terminator().is_none() { + context + .builder() + .build_unreachable() + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + } + + context.set_basic_block(join_block); + + if phi_incoming.len() >= 2 { + for (yields, _) in &phi_incoming { + if yields.len() != outputs.len() { + return Err(CodegenError::Llvm(format!( + "If phi mismatch: {} yields vs {} outputs (outputs: {:?})", + yields.len(), + outputs.len(), + outputs + ))); + } + } + for (i, output_id) in outputs.iter().enumerate() { + let phi = context + .builder() + .build_phi(context.word_type(), &format!("if_phi_{}", i)) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + for (yields, block) in &phi_incoming { + phi.add_incoming(&[(&yields[i], *block)]); + } + self.set_value(*output_id, phi.as_basic_value()); + } + } else if phi_incoming.len() == 1 { + let (yields, _) = &phi_incoming[0]; + if yields.len() != outputs.len() { + return Err(CodegenError::Llvm(format!( + "If statement mismatch: {} yields vs {} outputs (outputs: {:?})", + yields.len(), + outputs.len(), + outputs + ))); + } + for (i, output_id) in outputs.iter().enumerate() { + self.set_value(*output_id, yields[i]); + } + } else { + for output_id in outputs.iter() { + self.set_value( + *output_id, + context.word_type().get_undef().as_basic_value_enum(), + ); + } + context + .builder() + .build_unreachable() + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let dead_block = context.append_basic_block("if_dead"); + context.set_basic_block(dead_block); + } + } + + Statement::Switch { + scrutinee, + inputs, + cases, + default, + outputs, + } => { + let mut scrut_val = self.translate_value(scrutinee)?.into_int_value(); + let scrut_width = scrut_val.get_type().get_bit_width(); + + if scrut_width > 32 { + let all_cases_fit_32 = cases + .iter() + .all(|c| c.value.to_u64().is_some_and(|v| v <= u32::MAX as u64)); + if all_cases_fit_32 { + let provable = + Self::provable_narrow_width(scrut_val).unwrap_or(scrut_width); + if provable <= 32 { + scrut_val = context + .builder() + .build_int_truncate( + scrut_val, + context.llvm().i32_type(), + "switch_narrow", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + } + } + + let scrut_type = scrut_val.get_type(); + let join_block = context.append_basic_block("switch_join"); + + let mut case_blocks = Vec::new(); + for (index, case) in cases.iter().enumerate() { + let case_block = context.append_basic_block(&format!("switch_case_{}", index)); + let digits = case.value.to_u64_digits(); + let case_val = if digits.is_empty() { + scrut_type.const_zero() + } else { + scrut_type.const_int_arbitrary_precision(&digits) + }; + case_blocks.push((case_val, case_block, &case.body)); + } + + let default_block = context.append_basic_block("switch_default"); + + let switch_cases: Vec<_> = case_blocks + .iter() + .map(|(value, block, _)| (*value, *block)) + .collect(); + context + .builder() + .build_switch(scrut_val, default_block, &switch_cases) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + let mut all_yields: Vec<( + Vec>, + inkwell::basic_block::BasicBlock<'ctx>, + )> = Vec::new(); + + for (index, (_, case_block, body)) in case_blocks.into_iter().enumerate() { + context.set_basic_block(case_block); + self.generate_region(body, context)?; + let end_block = context.basic_block(); + + if !Self::block_is_unreachable(end_block) { + let mut yields = Vec::new(); + for (yield_idx, yield_val) in body.yields.iter().enumerate() { + match self.translate_value_as_word( + yield_val, + context, + &format!("case_{}_yield_{}", index, yield_idx), + ) { + Ok(v) => yields.push(v), + Err(e) => { + return Err(CodegenError::Llvm(format!( + "Switch case {} yield {}: {:?} - {}", + index, yield_idx, yield_val.id, e + ))); + } + } + } + context.build_unconditional_branch(join_block); + all_yields.push((yields, end_block)); + } else if end_block.get_terminator().is_none() { + context + .builder() + .build_unreachable() + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + } + + context.set_basic_block(default_block); + if let Some(default_region) = default { + self.generate_region(default_region, context)?; + let default_end_block = context.basic_block(); + + if !Self::block_is_unreachable(default_end_block) { + let mut default_yields = Vec::new(); + for (i, yield_val) in default_region.yields.iter().enumerate() { + default_yields.push(self.translate_value_as_word( + yield_val, + context, + &format!("default_yield_{}", i), + )?); + } + context.build_unconditional_branch(join_block); + all_yields.push((default_yields, default_end_block)); + } else if default_end_block.get_terminator().is_none() { + context + .builder() + .build_unreachable() + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + } else { + let default_end_block = context.basic_block(); + let mut default_yields = Vec::new(); + for (i, input_val) in inputs.iter().enumerate() { + default_yields.push(self.translate_value_as_word( + input_val, + context, + &format!("default_input_{}", i), + )?); + } + context.build_unconditional_branch(join_block); + all_yields.push((default_yields, default_end_block)); + } + + context.set_basic_block(join_block); + + if all_yields.len() >= 2 { + for (i, output_id) in outputs.iter().enumerate() { + let phi = context + .builder() + .build_phi(context.word_type(), &format!("switch_phi_{}", i)) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + for (yields, end_block) in &all_yields { + if i < yields.len() { + phi.add_incoming(&[(&yields[i], *end_block)]); + } + } + self.set_value(*output_id, phi.as_basic_value()); + } + } else if all_yields.len() == 1 { + let (yields, _) = &all_yields[0]; + for (i, output_id) in outputs.iter().enumerate() { + if i < yields.len() { + self.set_value(*output_id, yields[i]); + } + } + } else { + for output_id in outputs.iter() { + self.set_value( + *output_id, + context.word_type().get_undef().as_basic_value_enum(), + ); + } + context + .builder() + .build_unreachable() + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let dead_block = context.append_basic_block("switch_dead"); + context.set_basic_block(dead_block); + } + } + + Statement::For { + initial_values, + loop_variables, + condition_statements, + condition, + body, + post_input_variables, + post, + outputs, + } => { + let mut init_llvm_values: Vec> = Vec::new(); + for (i, initial_value) in initial_values.iter().enumerate() { + init_llvm_values.push(self.translate_value_as_word( + initial_value, + context, + &format!("for_init_{}", i), + )?); + } + + let entry_block = context.basic_block(); + let cond_block = context.append_basic_block("for_cond"); + let body_block = context.append_basic_block("for_body"); + let continue_landing = context.append_basic_block("for_continue_landing"); + let post_block = context.append_basic_block("for_post"); + let join_block = context.append_basic_block("for_join"); + + context.build_unconditional_branch(cond_block); + context.set_basic_block(cond_block); + + let mut loop_phis: Vec> = Vec::new(); + let mut loop_phi_values: Vec> = Vec::new(); + for (i, _loop_var) in loop_variables.iter().enumerate() { + let phi = context + .builder() + .build_phi(context.word_type(), &format!("loop_var_{}", i)) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + if i < init_llvm_values.len() { + phi.add_incoming(&[(&init_llvm_values[i], entry_block)]); + } + + loop_phi_values.push(phi.as_basic_value()); + loop_phis.push(phi); + } + + for (i, loop_var) in loop_variables.iter().enumerate() { + let phi_val = loop_phis[i].as_basic_value(); + let non_comp = self.type_info.non_comparison_demand(*loop_var); + let loop_val = if !self.type_info.get(*loop_var).is_signed + && matches!(non_comp, BitWidth::I32 | BitWidth::I64) + { + let narrow_type = context.integer_type(non_comp.bits() as usize); + let truncated = context + .builder() + .build_int_truncate( + phi_val.into_int_value(), + narrow_type, + &format!("loop_narrow_{}", i), + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + truncated.as_basic_value_enum() + } else { + phi_val + }; + self.set_value(*loop_var, loop_val); + } + + for statement in condition_statements { + self.generate_statement(statement, context)?; + } + + let cond_val = self + .generate_expression(condition, context, None)? + .into_int_value(); + let cond_zero = cond_val.get_type().const_zero(); + let cond_bool = context + .builder() + .build_int_compare( + inkwell::IntPredicate::NE, + cond_val, + cond_zero, + "for_cond_bool", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + let cond_eval_block = context.basic_block(); + + context.set_basic_block(join_block); + let mut join_phis: Vec> = Vec::new(); + let has_loop_vars = !loop_variables.is_empty(); + if has_loop_vars { + for i in 0..loop_variables.len() { + let phi = context + .builder() + .build_phi(context.word_type(), &format!("join_phi_{}", i)) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + join_phis.push(phi); + } + } + + context.set_basic_block(cond_eval_block); + context.build_conditional_branch(cond_bool, body_block, join_block)?; + if has_loop_vars { + for (i, phi) in join_phis.iter().enumerate() { + phi.add_incoming(&[(&loop_phi_values[i], cond_eval_block)]); + } + } + + context.set_basic_block(continue_landing); + let mut landing_phis: Vec> = Vec::new(); + let has_body_yields = !body.yields.is_empty(); + if has_body_yields { + for i in 0..body.yields.len() { + let phi = context + .builder() + .build_phi(context.word_type(), &format!("continue_landing_{}", i)) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + landing_phis.push(phi); + } + } + context.build_unconditional_branch(post_block); + + context.push_loop(body_block, continue_landing, join_block); + + self.for_loop_post_phis.push(ForLoopPostPhis { + phis: landing_phis.clone(), + loop_var_phi_values: loop_phi_values.clone(), + }); + + self.for_loop_break_phis.push(ForLoopBreakPhis { + phis: join_phis.clone(), + loop_var_phi_values: loop_phi_values.clone(), + }); + + context.set_basic_block(body_block); + self.generate_region(body, context)?; + + let body_end_block = context.basic_block(); + let mut body_yield_vals: Vec> = Vec::new(); + if has_body_yields { + for (i, yield_ref) in body.yields.iter().enumerate() { + let yield_val = self.translate_value_as_word( + yield_ref, + context, + &format!("body_yield_{}", i), + )?; + body_yield_vals.push(yield_val.as_basic_value_enum()); + } + } + + context.build_unconditional_branch(continue_landing); + + for (phi, yield_val) in landing_phis.iter().zip(body_yield_vals.iter()) { + phi.add_incoming(&[(yield_val, body_end_block)]); + } + + self.for_loop_post_phis.pop(); + self.for_loop_break_phis.pop(); + + context.set_basic_block(post_block); + + if has_body_yields { + for (i, phi) in landing_phis.iter().enumerate() { + if i < post_input_variables.len() { + self.set_value(post_input_variables[i], phi.as_basic_value()); + } + } + } + + self.generate_region(post, context)?; + + let post_end_block = context.basic_block(); + for (i, phi) in loop_phis.iter().enumerate() { + if i < post.yields.len() { + let yield_val = self.translate_value_as_word( + &post.yields[i], + context, + &format!("for_post_yield_{}", i), + )?; + phi.add_incoming(&[(&yield_val, post_end_block)]); + } + } + + context.build_unconditional_branch(cond_block); + + context.pop_loop(); + context.set_basic_block(join_block); + + if has_loop_vars { + for (i, output_id) in outputs.iter().enumerate() { + if i < join_phis.len() { + self.set_value(*output_id, join_phis[i].as_basic_value()); + } + } + } else { + for (i, output_id) in outputs.iter().enumerate() { + if i < loop_phis.len() { + self.set_value(*output_id, loop_phis[i].as_basic_value()); + } + } + } + } + + Statement::Break { values } => { + if let Some(break_phis) = self.for_loop_break_phis.last() { + let current_block = context.basic_block(); + for (i, phi) in break_phis.phis.iter().enumerate() { + let value = if i < values.len() { + self.translate_value_as_word( + &values[i], + context, + &format!("break_val_{}", i), + )? + .as_basic_value_enum() + } else { + break_phis.loop_var_phi_values[i] + }; + phi.add_incoming(&[(&value, current_block)]); + } + } + + let join_block = context.r#loop().join_block; + context.build_unconditional_branch(join_block); + let unreachable = context.append_basic_block("break_unreachable"); + context.set_basic_block(unreachable); + } + + Statement::Continue { values } => { + if let Some(post_phis) = self.for_loop_post_phis.last() { + let current_block = context.basic_block(); + for (i, phi) in post_phis.phis.iter().enumerate() { + let value = if i < values.len() { + self.translate_value_as_word( + &values[i], + context, + &format!("continue_val_{}", i), + )? + .as_basic_value_enum() + } else { + post_phis.loop_var_phi_values[i] + }; + phi.add_incoming(&[(&value, current_block)]); + } + } + + let continue_block = context.r#loop().continue_block; + context.build_unconditional_branch(continue_block); + let unreachable = context.append_basic_block("continue_unreachable"); + context.set_basic_block(unreachable); + } + + Statement::Leave { return_values } => { + match context.current_function().borrow().r#return() { + revive_llvm_context::PolkaVMFunctionReturn::None => {} + revive_llvm_context::PolkaVMFunctionReturn::Primitive { pointer } => { + if !return_values.is_empty() { + if let Ok(return_value) = self.translate_value(&return_values[0]) { + let return_value = if return_value.is_int_value() { + let integer_value = return_value.into_int_value(); + match self.current_return_types.first() { + Some(Type::Int(bit_width)) + if *bit_width < BitWidth::I256 => + { + let target = + context.integer_type(bit_width.bits() as usize); + let val_bits = integer_value.get_type().get_bit_width(); + let tgt_bits = target.get_bit_width(); + if val_bits > tgt_bits { + context + .builder() + .build_int_truncate( + integer_value, + target, + "leave_narrow", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum() + } else if val_bits < tgt_bits { + context + .builder() + .build_int_z_extend( + integer_value, + target, + "leave_widen", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum() + } else { + integer_value.as_basic_value_enum() + } + } + _ => self + .ensure_word_type( + context, + integer_value, + "leave_ret_val", + )? + .as_basic_value_enum(), + } + } else { + return_value + }; + context.build_store(pointer, return_value)?; + } + } + } + revive_llvm_context::PolkaVMFunctionReturn::Compound { pointer, size } => { + let field_types: Vec<_> = (0..size) + .map(|i| match self.current_return_types.get(i) { + Some(Type::Int(bit_width)) if *bit_width < BitWidth::I256 => { + context + .integer_type(bit_width.bits() as usize) + .as_basic_type_enum() + } + _ => context.word_type().as_basic_type_enum(), + }) + .collect(); + let struct_type = context.structure_type(&field_types); + let mut struct_val = struct_type.get_undef(); + for (i, return_value) in return_values.iter().enumerate() { + if let Ok(value) = self.translate_value(return_value) { + let value = if value.is_int_value() { + let integer_value = value.into_int_value(); + match self.current_return_types.get(i) { + Some(Type::Int(bit_width)) + if *bit_width < BitWidth::I256 => + { + let target = + context.integer_type(bit_width.bits() as usize); + let val_bits = integer_value.get_type().get_bit_width(); + let tgt_bits = target.get_bit_width(); + if val_bits > tgt_bits { + context + .builder() + .build_int_truncate( + integer_value, + target, + &format!("leave_narrow_{}", i), + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum() + } else if val_bits < tgt_bits { + context + .builder() + .build_int_z_extend( + integer_value, + target, + &format!("leave_widen_{}", i), + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum() + } else { + integer_value.as_basic_value_enum() + } + } + _ => self + .ensure_word_type( + context, + integer_value, + &format!("leave_ret_val_{}", i), + )? + .as_basic_value_enum(), + } + } else { + value + }; + struct_val = context + .builder() + .build_insert_value(struct_val, value, i as u32, "ret_insert") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .into_struct_value(); + } + } + context.build_store(pointer, struct_val.as_basic_value_enum())?; + } + } + let return_block = context.current_function().borrow().return_block(); + context.build_unconditional_branch(return_block); + let unreachable = context.append_basic_block("leave_unreachable"); + context.set_basic_block(unreachable); + } + + Statement::Revert { offset, length } => { + let offset_val = self.translate_value(offset)?.into_int_value(); + let length_val = self.translate_value(length)?.into_int_value(); + + if Self::is_const_zero(offset_val) { + if let Some(const_len) = Self::try_extract_const_u64(length_val) { + let revert_block = self.get_or_create_revert_block(context, const_len)?; + context.build_unconditional_branch(revert_block); + let dead_block = context.append_basic_block("revert_dedup_dead"); + context.set_basic_block(dead_block); + return Ok(()); + } + } + if !self.has_msize { + let offset_xlen = context + .safe_truncate_int_to_xlen(offset_val) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let length_xlen = context + .safe_truncate_int_to_xlen(length_val) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let flags = context.xlen_type().const_int(1, false); + let function = self.get_or_create_exit_checked_fn(context)?; + context + .builder() + .build_call( + function, + &[flags.into(), offset_xlen.into(), length_xlen.into()], + "", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } else { + let offset_val = self.ensure_word_type(context, offset_val, "revert_offset")?; + let length_val = self.ensure_word_type(context, length_val, "revert_length")?; + revive_llvm_context::polkavm_evm_return::revert( + context, offset_val, length_val, + )?; + } + } + + Statement::Return { offset, length } => { + let offset_val = self.translate_value(offset)?.into_int_value(); + let length_val = self.translate_value(length)?.into_int_value(); + + if let (Some(const_off), Some(const_len)) = ( + Self::try_extract_const_u64(offset_val), + Self::try_extract_const_u64(length_val), + ) { + let return_block = + self.get_or_create_return_block(context, const_off, const_len)?; + context.build_unconditional_branch(return_block); + let dead_block = context.append_basic_block("return_dedup_dead"); + context.set_basic_block(dead_block); + return Ok(()); + } + + if !self.has_msize + && !matches!( + context.code_type(), + Some(revive_llvm_context::PolkaVMCodeType::Deploy) + ) + { + let offset_xlen = context + .safe_truncate_int_to_xlen(offset_val) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let length_xlen = context + .safe_truncate_int_to_xlen(length_val) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let flags = context.xlen_type().const_int(0, false); + let function = self.get_or_create_exit_checked_fn(context)?; + context + .builder() + .build_call( + function, + &[flags.into(), offset_xlen.into(), length_xlen.into()], + "", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } else { + let offset_val = self.ensure_word_type(context, offset_val, "return_offset")?; + let length_val = self.ensure_word_type(context, length_val, "return_length")?; + revive_llvm_context::polkavm_evm_return::r#return( + context, offset_val, length_val, + )?; + } + } + + Statement::Stop => { + let return_block = self.get_or_create_return_block(context, 0, 0)?; + context.build_unconditional_branch(return_block); + let dead_block = context.append_basic_block("stop_dedup_dead"); + context.set_basic_block(dead_block); + } + + Statement::Invalid => { + revive_llvm_context::polkavm_evm_return::invalid(context)?; + } + + Statement::PanicRevert { code } => { + let panic_block = self.get_or_create_panic_block(context, *code)?; + context.build_unconditional_branch(panic_block); + let dead_block = context.append_basic_block("panic_dedup_dead"); + context.set_basic_block(dead_block); + } + + Statement::ErrorStringRevert { length, data } => { + let num_words = data.len(); + let count = self + .error_string_revert_counts + .get(&num_words) + .copied() + .unwrap_or(0); + + if count >= 2 { + let function = self.get_or_create_error_string_revert_fn(num_words, context)?; + + let length_val = context.word_const(*length as u64); + let mut arguments: Vec = + vec![length_val.into()]; + for word in data { + let word_val = context.word_const_str_hex(&word.to_str_radix(16)); + arguments.push(word_val.into()); + } + + context + .builder() + .build_call(function, &arguments, "error_string_revert") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context.build_unreachable(); + } else { + let fmp_offset = context.word_const(FREE_MEMORY_POINTER_SLOT); + let fmp = revive_llvm_context::polkavm_evm_memory::load(context, fmp_offset) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .into_int_value(); + + let error_selector = + context.word_const_str_hex(revive_common::ERROR_STRING_SELECTOR_WORD_HEX); + revive_llvm_context::polkavm_evm_memory::store(context, fmp, error_selector) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + let fmp_plus_offset_field = context + .builder() + .build_int_add( + fmp, + context.word_const(ABI_SELECTOR_LENGTH), + "fmp_offset_field", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + revive_llvm_context::polkavm_evm_memory::store( + context, + fmp_plus_offset_field, + context.word_const(revive_common::BYTE_LENGTH_WORD as u64), + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + let fmp_plus_length_field = context + .builder() + .build_int_add( + fmp, + context.word_const(ERROR_STRING_LENGTH_FIELD_OFFSET), + "fmp_length_field", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + revive_llvm_context::polkavm_evm_memory::store( + context, + fmp_plus_length_field, + context.word_const(*length as u64), + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + for (i, word) in data.iter().enumerate() { + let offset = ERROR_STRING_FIRST_DATA_WORD_OFFSET + + (i as u64) * revive_common::BYTE_LENGTH_WORD as u64; + let fmp_plus_offset = context + .builder() + .build_int_add( + fmp, + context.word_const(offset), + &format!("fmp_{offset:x}"), + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let word_val = context.word_const_str_hex(&word.to_str_radix(16)); + revive_llvm_context::polkavm_evm_memory::store( + context, + fmp_plus_offset, + word_val, + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + + let total_length = ERROR_STRING_FIRST_DATA_WORD_OFFSET + + (num_words as u64) * revive_common::BYTE_LENGTH_WORD as u64; + revive_llvm_context::polkavm_evm_return::revert( + context, + fmp, + context.word_const(total_length), + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context.build_unreachable(); + } + + let dead_block = context.append_basic_block("error_string_dead"); + context.set_basic_block(dead_block); + } + + Statement::CustomErrorRevert { + selector, + arguments, + } => { + let num_args = arguments.len(); + let count = self + .custom_error_revert_counts + .get(&num_args) + .copied() + .unwrap_or(0); + + if count >= 3 { + let function = self.get_or_create_custom_error_revert_fn(num_args, context)?; + + let selector_high32 = (selector >> 224u32) + .iter_u32_digits() + .next() + .unwrap_or(0) + .swap_bytes(); + let selector_val = context.xlen_type().const_int(selector_high32 as u64, false); + let mut call_args: Vec = + vec![selector_val.into()]; + for argument in arguments { + let arg_val = self.translate_value(argument)?.into_int_value(); + let arg_val = + self.ensure_word_type(context, arg_val, "custom_error_arg")?; + call_args.push(arg_val.into()); + } + + context + .builder() + .build_call(function, &call_args, "custom_error_revert") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + context.build_unreachable(); + } else { + let selector_val = context.word_const_str_hex(&selector.to_str_radix(16)); + let offset_0 = context.xlen_type().const_int(0, false); + revive_llvm_context::polkavm_evm_memory::store_bswap_unchecked( + context, + offset_0, + selector_val, + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + for (i, argument) in arguments.iter().enumerate() { + let arg_val = self.translate_value(argument)?.into_int_value(); + let arg_val = + self.ensure_word_type(context, arg_val, "custom_error_arg")?; + let byte_offset = 4 + (i as u64) * 0x20; + let offset_val = context.xlen_type().const_int(byte_offset, false); + revive_llvm_context::polkavm_evm_memory::store_bswap_unchecked( + context, offset_val, arg_val, + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + + let const_len = 4 + (num_args as u64) * 0x20; + let revert_block = self.get_or_create_revert_block(context, const_len)?; + context.build_unconditional_branch(revert_block); + } + + let dead_block = context.append_basic_block("custom_error_dead"); + context.set_basic_block(dead_block); + } + + Statement::SelfDestruct { address } => { + let addr_val = self.translate_value(address)?.into_int_value(); + let addr_val = self.ensure_word_type(context, addr_val, "selfdestruct_addr")?; + revive_llvm_context::polkavm_evm_return::selfdestruct(context, addr_val)?; + } + + Statement::ExternalCall { + kind, + gas, + address, + value, + args_offset, + args_length, + ret_offset, + ret_length, + result, + } => { + if matches!(kind, CallKind::CallCode) { + return Err(CodegenError::Unsupported( + "The `CALLCODE` instruction is not supported".into(), + )); + } + + let gas_val = self.translate_value(gas)?.into_int_value(); + let gas_val = self.ensure_word_type(context, gas_val, "call_gas")?; + let address_val = self.translate_value(address)?.into_int_value(); + let address_val = self.ensure_word_type(context, address_val, "call_addr")?; + let args_offset_val = self.translate_value(args_offset)?.into_int_value(); + let args_offset_val = self.narrow_offset_for_pointer( + context, + args_offset_val, + args_offset.id, + "call_args_offset_narrow", + )?; + let args_length_val = self.translate_value(args_length)?.into_int_value(); + let args_length_val = self.narrow_offset_for_pointer( + context, + args_length_val, + args_length.id, + "call_args_length_narrow", + )?; + let ret_offset_val = self.translate_value(ret_offset)?.into_int_value(); + let ret_offset_val = self.narrow_offset_for_pointer( + context, + ret_offset_val, + ret_offset.id, + "call_ret_offset_narrow", + )?; + let ret_length_val = self.translate_value(ret_length)?.into_int_value(); + let ret_length_val = self.narrow_offset_for_pointer( + context, + ret_length_val, + ret_length.id, + "call_ret_length_narrow", + )?; + + let call_result = match kind { + CallKind::Call => { + let value_val = value + .map(|v| -> Result<_> { + let value = self.translate_value(&v)?.into_int_value(); + self.ensure_word_type(context, value, "call_value") + }) + .transpose()?; + revive_llvm_context::polkavm_evm_call::call( + context, + gas_val, + address_val, + value_val, + args_offset_val, + args_length_val, + ret_offset_val, + ret_length_val, + vec![], + false, + )? + } + CallKind::CallCode => { + unreachable!("CallCode is handled above") + } + CallKind::StaticCall => revive_llvm_context::polkavm_evm_call::call( + context, + gas_val, + address_val, + None, + args_offset_val, + args_length_val, + ret_offset_val, + ret_length_val, + vec![], + true, + )?, + CallKind::DelegateCall => revive_llvm_context::polkavm_evm_call::delegate_call( + context, + gas_val, + address_val, + args_offset_val, + args_length_val, + ret_offset_val, + ret_length_val, + vec![], + )?, + }; + self.set_value(*result, call_result); + } + + Statement::Create { + kind, + value, + offset, + length, + salt, + result, + } => { + let value_val = self.translate_value(value)?.into_int_value(); + let value_val = self.ensure_word_type(context, value_val, "create_value")?; + let offset_val = self.translate_value(offset)?.into_int_value(); + let offset_val = self.narrow_offset_for_pointer( + context, + offset_val, + offset.id, + "create_offset_narrow", + )?; + let length_val = self.translate_value(length)?.into_int_value(); + let length_val = self.narrow_offset_for_pointer( + context, + length_val, + length.id, + "create_length_narrow", + )?; + let salt_val = match (kind, salt) { + (CreateKind::Create2, Some(s)) => { + let s_val = self.translate_value(s)?.into_int_value(); + Some(self.ensure_word_type(context, s_val, "create_salt")?) + } + _ => None, + }; + + let create_result = revive_llvm_context::polkavm_evm_create::create( + context, value_val, offset_val, length_val, salt_val, + )?; + self.set_value(*result, create_result); + } + + Statement::Log { + offset, + length, + topics, + } => { + let offset_val = self.translate_value(offset)?.into_int_value(); + let offset_val = self.narrow_offset_for_pointer( + context, + offset_val, + offset.id, + "log_offset_narrow", + )?; + let length_val = self.translate_value(length)?.into_int_value(); + let length_val = self.narrow_offset_for_pointer( + context, + length_val, + length.id, + "log_length_narrow", + )?; + let topic_vals: Vec> = topics + .iter() + .enumerate() + .map(|(i, t)| { + let value = self.translate_value(t)?.into_int_value(); + let value = + self.ensure_word_type(context, value, &format!("log_topic_{}", i))?; + Ok(value.as_basic_value_enum()) + }) + .collect::>()?; + + { + match topic_vals.len() { + 0 => revive_llvm_context::polkavm_evm_event::log::<0>( + context, + offset_val, + length_val, + [], + )?, + 1 => revive_llvm_context::polkavm_evm_event::log::<1>( + context, + offset_val, + length_val, + [topic_vals[0]], + )?, + 2 => revive_llvm_context::polkavm_evm_event::log::<2>( + context, + offset_val, + length_val, + [topic_vals[0], topic_vals[1]], + )?, + 3 => revive_llvm_context::polkavm_evm_event::log::<3>( + context, + offset_val, + length_val, + [topic_vals[0], topic_vals[1], topic_vals[2]], + )?, + 4 => revive_llvm_context::polkavm_evm_event::log::<4>( + context, + offset_val, + length_val, + [topic_vals[0], topic_vals[1], topic_vals[2], topic_vals[3]], + )?, + _ => return Err(CodegenError::Unsupported("log with >4 topics".into())), + } + } + } + + Statement::CodeCopy { + dest, + offset, + length, + } => { + if matches!( + context.code_type(), + Some(revive_llvm_context::PolkaVMCodeType::Runtime) + ) { + return Err(CodegenError::Unsupported( + "The `CODECOPY` instruction is not supported in the runtime code".into(), + )); + } + let dest_val = self.translate_value(dest)?.into_int_value(); + let dest_val = self.narrow_offset_for_pointer( + context, + dest_val, + dest.id, + "codecopy_dest_narrow", + )?; + let offset_val = self.translate_value(offset)?.into_int_value(); + let offset_val = self.narrow_offset_for_pointer( + context, + offset_val, + offset.id, + "codecopy_offset_narrow", + )?; + let length_val = self.translate_value(length)?.into_int_value(); + let length_val = self.narrow_offset_for_pointer( + context, + length_val, + length.id, + "codecopy_length_narrow", + )?; + revive_llvm_context::polkavm_evm_calldata::copy( + context, dest_val, offset_val, length_val, + )?; + } + + Statement::ExtCodeCopy { .. } => { + return Err(CodegenError::Unsupported( + "The `EXTCODECOPY` instruction is not supported".into(), + )); + } + + Statement::ReturnDataCopy { + dest, + offset, + length, + } => { + let dest_val = self.translate_value(dest)?.into_int_value(); + let dest_val = self.narrow_offset_for_pointer( + context, + dest_val, + dest.id, + "returndatacopy_dest_narrow", + )?; + let offset_val = self.translate_value(offset)?.into_int_value(); + let offset_val = self.narrow_offset_for_pointer( + context, + offset_val, + offset.id, + "returndatacopy_offset_narrow", + )?; + let length_val = self.translate_value(length)?.into_int_value(); + let length_val = self.narrow_offset_for_pointer( + context, + length_val, + length.id, + "returndatacopy_length_narrow", + )?; + revive_llvm_context::polkavm_evm_return_data::copy( + context, dest_val, offset_val, length_val, + )?; + } + + Statement::DataCopy { + dest, + offset, + length: _, + } => { + let dest_val = self.translate_value(dest)?.into_int_value(); + let dest_val = self.narrow_offset_for_pointer( + context, + dest_val, + dest.id, + "datacopy_dest_narrow", + )?; + let hash_val = self.translate_value(offset)?.into_int_value(); + let hash_val = self.ensure_word_type(context, hash_val, "datacopy_hash")?; + revive_llvm_context::polkavm_evm_memory::store(context, dest_val, hash_val)?; + } + + Statement::CallDataCopy { + dest, + offset, + length, + } => { + let dest_val = self.translate_value(dest)?.into_int_value(); + let dest_val = self.narrow_offset_for_pointer( + context, + dest_val, + dest.id, + "calldatacopy_dest_narrow", + )?; + let offset_val = self.translate_value(offset)?.into_int_value(); + let offset_val = self.narrow_offset_for_pointer( + context, + offset_val, + offset.id, + "calldatacopy_offset_narrow", + )?; + let length_val = self.translate_value(length)?.into_int_value(); + let length_val = self.narrow_offset_for_pointer( + context, + length_val, + length.id, + "calldatacopy_length_narrow", + )?; + revive_llvm_context::polkavm_evm_calldata::copy( + context, dest_val, offset_val, length_val, + )?; + } + + Statement::Block(region) => { + self.generate_region(region, context)?; + } + + Statement::Expression(expression) => { + let _ = self.generate_expression(expression, context, None)?; + } + + Statement::MappingSStore { key, slot, value } => { + let key_val = self.translate_value(key)?.into_int_value(); + let key_val = self.ensure_word_type(context, key_val, "mapping_sstore_key")?; + let slot_val = self.translate_value(slot)?.into_int_value(); + let slot_val = self.ensure_word_type(context, slot_val, "mapping_sstore_slot")?; + let value_val = self.translate_value(value)?.into_int_value(); + let value_val = + self.ensure_word_type(context, value_val, "mapping_sstore_value")?; + + if self.use_outlined_mapping_sstore { + let mapping_sstore_fn = self.get_or_create_mapping_sstore_fn(context)?; + context + .builder() + .build_call( + mapping_sstore_fn, + &[key_val.into(), slot_val.into(), value_val.into()], + "mapping_sstore_call", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } else { + let hash_val = + if slot_val.is_const() && Self::try_extract_const_u64(slot_val).is_none() { + let wrapper_fn = + self.get_or_create_keccak256_slot_wrapper(slot_val, context)?; + let function_type = context + .word_type() + .fn_type(&[context.word_type().into()], false); + context + .builder() + .build_indirect_call( + function_type, + wrapper_fn.as_global_value().as_pointer_value(), + &[key_val.into()], + "keccak256_slot_call", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .try_as_basic_value() + .basic() + .expect("keccak256 slot wrapper should return a value") + .into_int_value() + } else { + revive_llvm_context::polkavm_evm_crypto::sha3_two_words( + context, key_val, slot_val, + )? + .into_int_value() + }; + let sstore_fn = self.get_or_create_sstore_word_fn(context)?; + context + .builder() + .build_call( + sstore_fn, + &[hash_val.into(), value_val.into()], + "mapping_sstore_word", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + } + } + + Statement::SetImmutable { key, value } => { + let offset = context.solidity_mut().allocate_immutable(key.as_str()) + / revive_common::BYTE_LENGTH_WORD; + let index = context.xlen_type().const_int(offset as u64, false); + let value = self.translate_value(value)?.into_int_value(); + let value = self.ensure_word_type(context, value, "immutable_val")?; + revive_llvm_context::polkavm_evm_immutable::store(context, index, value)?; + } + } + Ok(()) + } + + /// Generates LLVM IR for an expression. + /// Generates LLVM IR for an expression. + /// + /// `demand_bits` is an optional hint: when set, the caller only needs + /// the low `demand_bits` bits of the result. For modular/bitwise BinOps + /// (Add, Sub, Mul, And, Or, Xor) this allows generating narrow operations + /// directly instead of computing at i256 and truncating afterward. + fn generate_expression( + &mut self, + expression: &Expression, + context: &mut PolkaVMContext<'ctx>, + demand_bits: Option, + ) -> Result> { + match expression { + Expression::Literal { value, .. } => { + if value.bits() <= 64 { + let val_u64 = value.to_u64().unwrap_or(0); + Ok(context + .llvm() + .i64_type() + .const_int(val_u64, false) + .as_basic_value_enum()) + } else { + let val_str = value.to_string(); + Ok(context.word_const_str_dec(&val_str).as_basic_value_enum()) + } + } + + Expression::Var(id) => self.get_value(*id), + + Expression::Binary { + operation, + lhs, + rhs, + } => { + let lhs_val = self.translate_value(lhs)?.into_int_value(); + let rhs_val = self.translate_value(rhs)?.into_int_value(); + + match operation { + BinaryOperation::Lt | BinaryOperation::Gt | BinaryOperation::Eq => { + let (lhs_cmp, rhs_cmp) = + self.try_narrow_comparison(context, lhs_val, rhs_val, lhs.id, rhs.id)?; + self.generate_binop(*operation, lhs_cmp, rhs_cmp, context) + } + BinaryOperation::Slt | BinaryOperation::Sgt => { + let (lhs_val, rhs_val) = + self.ensure_same_type(context, lhs_val, rhs_val, "cmp")?; + self.generate_binop(*operation, lhs_val, rhs_val, context) + } + + BinaryOperation::And | BinaryOperation::Or | BinaryOperation::Xor => { + if let Some(db) = demand_bits { + if db <= 64 { + let lhs_val = + self.ensure_exact_width(context, lhs_val, 64, "dnbit_l")?; + let rhs_val = + self.ensure_exact_width(context, rhs_val, 64, "dnbit_r")?; + return self.generate_binop(*operation, lhs_val, rhs_val, context); + } + if db <= 128 { + let lhs_val = + self.ensure_exact_width(context, lhs_val, 128, "dnbit128_l")?; + let rhs_val = + self.ensure_exact_width(context, rhs_val, 128, "dnbit128_r")?; + return self.generate_binop(*operation, lhs_val, rhs_val, context); + } + } + let (lhs_val, rhs_val) = + self.ensure_same_type(context, lhs_val, rhs_val, "bitwise")?; + self.generate_binop(*operation, lhs_val, rhs_val, context) + } + + BinaryOperation::Add | BinaryOperation::Sub | BinaryOperation::Mul => { + if let Some(db) = demand_bits { + if db <= 64 { + let lhs_val = + self.ensure_exact_width(context, lhs_val, 64, "dnarith_l")?; + let rhs_val = + self.ensure_exact_width(context, rhs_val, 64, "dnarith_r")?; + return self.generate_binop(*operation, lhs_val, rhs_val, context); + } + if db <= 128 { + let lhs_val = + self.ensure_exact_width(context, lhs_val, 128, "dnarith128_l")?; + let rhs_val = + self.ensure_exact_width(context, rhs_val, 128, "dnarith128_r")?; + return self.generate_binop(*operation, lhs_val, rhs_val, context); + } + } + + let lhs_inferred = self.inferred_width(lhs.id); + let rhs_inferred = self.inferred_width(rhs.id); + let max_operand = lhs_inferred.max(rhs_inferred); + + let result_fits_i64 = match operation { + BinaryOperation::Add => { + crate::type_inference::widen_by_one(max_operand).bits() <= 64 + } + BinaryOperation::Sub => false, + BinaryOperation::Mul => { + crate::type_inference::double_width(max_operand).bits() <= 64 + } + _ => unreachable!(), + }; + + let result_fits_i128 = + max_operand.bits() <= 64 && !matches!(operation, BinaryOperation::Sub); + + if result_fits_i64 { + let (lhs_val, rhs_val) = + self.ensure_min_width(context, lhs_val, rhs_val, 64, "arith")?; + self.generate_binop(*operation, lhs_val, rhs_val, context) + } else if result_fits_i128 { + let (lhs_val, rhs_val) = + self.ensure_min_width(context, lhs_val, rhs_val, 128, "arith128")?; + self.generate_binop(*operation, lhs_val, rhs_val, context) + } else { + let lhs_val = self.ensure_word_type(context, lhs_val, "arith_lhs")?; + let rhs_val = self.ensure_word_type(context, rhs_val, "arith_rhs")?; + self.generate_binop(*operation, lhs_val, rhs_val, context) + } + } + + BinaryOperation::Div | BinaryOperation::Mod => { + let lhs_width = lhs_val.get_type().get_bit_width(); + let rhs_width = rhs_val.get_type().get_bit_width(); + if lhs_width <= 64 && rhs_width <= 64 { + let (lhs_val, rhs_val) = + self.ensure_same_type(context, lhs_val, rhs_val, "narrow_divmod")?; + self.generate_narrow_divmod(*operation, lhs_val, rhs_val, context) + } else { + let lhs_val = self.ensure_word_type(context, lhs_val, "binop_lhs")?; + let rhs_val = self.ensure_word_type(context, rhs_val, "binop_rhs")?; + self.generate_binop(*operation, lhs_val, rhs_val, context) + } + } + + BinaryOperation::Shl => { + if let Some(db) = demand_bits { + if db <= 64 { + if let Some(shift) = Self::try_get_small_constant(lhs_val) { + if shift >= 64 { + let i64_type = context.llvm().i64_type(); + return Ok(i64_type.const_zero().as_basic_value_enum()); + } + let rhs_narrow = + self.ensure_exact_width(context, rhs_val, 64, "dnshl_val")?; + let lhs_narrow = + self.ensure_exact_width(context, lhs_val, 64, "dnshl_amt")?; + let result = context + .builder() + .build_left_shift(rhs_narrow, lhs_narrow, "shl_dn") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + return Ok(result.as_basic_value_enum()); + } + } + } + let lhs_val = self.ensure_word_type(context, lhs_val, "binop_lhs")?; + let rhs_val = self.ensure_word_type(context, rhs_val, "binop_rhs")?; + self.generate_binop(*operation, lhs_val, rhs_val, context) + } + + BinaryOperation::Shr => { + let rhs_inferred = self.inferred_width(rhs.id); + if rhs_inferred.bits() <= 64 { + if let Some(shift) = Self::try_get_small_constant(lhs_val) { + if shift >= 64 { + let i64_type = context.llvm().i64_type(); + return Ok(i64_type.const_zero().as_basic_value_enum()); + } + let rhs_narrow = + self.ensure_exact_width(context, rhs_val, 64, "dnshr_val")?; + let lhs_narrow = + self.ensure_exact_width(context, lhs_val, 64, "dnshr_amt")?; + let result = context + .builder() + .build_right_shift(rhs_narrow, lhs_narrow, false, "shr_dn") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + return Ok(result.as_basic_value_enum()); + } + } + let lhs_val = self.ensure_word_type(context, lhs_val, "binop_lhs")?; + let rhs_val = self.ensure_word_type(context, rhs_val, "binop_rhs")?; + self.generate_binop(*operation, lhs_val, rhs_val, context) + } + + _ => { + let lhs_val = self.ensure_word_type(context, lhs_val, "binop_lhs")?; + let rhs_val = self.ensure_word_type(context, rhs_val, "binop_rhs")?; + self.generate_binop(*operation, lhs_val, rhs_val, context) + } + } + } + + Expression::Ternary { operation, a, b, n } => { + let a_val = self.translate_value(a)?.into_int_value(); + let b_val = self.translate_value(b)?.into_int_value(); + let n_val = self.translate_value(n)?.into_int_value(); + let a_val = self.ensure_word_type(context, a_val, "ternary_a")?; + let b_val = self.ensure_word_type(context, b_val, "ternary_b")?; + let n_val = self.ensure_word_type(context, n_val, "ternary_n")?; + + match operation { + BinaryOperation::AddMod => Ok(revive_llvm_context::polkavm_evm_math::add_mod( + context, a_val, b_val, n_val, + )?), + BinaryOperation::MulMod => Ok(revive_llvm_context::polkavm_evm_math::mul_mod( + context, a_val, b_val, n_val, + )?), + _ => Err(CodegenError::Unsupported(format!( + "Ternary operation {:?}", + operation + ))), + } + } + + Expression::Unary { operation, operand } => { + let operand_val = self.translate_value(operand)?.into_int_value(); + match operation { + UnaryOperation::IsZero => { + let zero = operand_val.get_type().const_zero(); + let is_zero = context + .builder() + .build_int_compare( + inkwell::IntPredicate::EQ, + operand_val, + zero, + "iszero", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + Ok(is_zero.as_basic_value_enum()) + } + UnaryOperation::Not => { + if let Some(db) = demand_bits { + if db <= 64 { + let narrow_val = + self.ensure_exact_width(context, operand_val, 64, "dnnot_op")?; + let all_ones = narrow_val.get_type().const_all_ones(); + let xor_result = context + .builder() + .build_xor(narrow_val, all_ones, "not_narrow") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + return Ok(xor_result.as_basic_value_enum()); + } + } + let operand_val = self.ensure_word_type(context, operand_val, "not_op")?; + let all_ones = context.word_type().const_all_ones(); + let xor_result = context + .builder() + .build_xor(operand_val, all_ones, "not_result") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + Ok(xor_result.as_basic_value_enum()) + } + UnaryOperation::Clz => { + let operand_val = self.ensure_word_type(context, operand_val, "clz_op")?; + Ok( + revive_llvm_context::polkavm_evm_bitwise::count_leading_zeros( + context, + operand_val, + )?, + ) + } + } + } + + Expression::CallDataLoad { offset } => { + let offset_val = self.translate_value(offset)?.into_int_value(); + if self.use_outlined_calldataload { + Ok(revive_llvm_context::polkavm_evm_calldata::load_outlined( + context, offset_val, + )?) + } else { + Ok(revive_llvm_context::polkavm_evm_calldata::load( + context, offset_val, + )?) + } + } + + Expression::CallValue => { + if self.use_outlined_callvalue { + Ok(revive_llvm_context::polkavm_evm_ether_gas::value_outlined( + context, + )?) + } else { + Ok(revive_llvm_context::polkavm_evm_ether_gas::value(context)?) + } + } + + Expression::Caller => { + let value = if self.use_outlined_caller { + revive_llvm_context::polkavm_evm_contract_context::caller_outlined(context)? + } else { + revive_llvm_context::polkavm_evm_contract_context::caller(context)? + }; + let address_max = (num::BigUint::from(1u32) << 160) - num::BigUint::from(1u32); + self.emit_validator_assume(context, value, &address_max)?; + Ok(value) + } + + Expression::Origin => { + let value = revive_llvm_context::polkavm_evm_contract_context::origin(context)?; + let address_max = (num::BigUint::from(1u32) << 160) - num::BigUint::from(1u32); + self.emit_validator_assume(context, value, &address_max)?; + Ok(value) + } + + Expression::CallDataSize => { + Ok(revive_llvm_context::polkavm_evm_calldata::size(context)?) + } + + Expression::CodeSize => match context.code_type() { + Some(revive_llvm_context::PolkaVMCodeType::Deploy) => { + Ok(revive_llvm_context::polkavm_evm_calldata::size(context)?) + } + Some(revive_llvm_context::PolkaVMCodeType::Runtime) => Ok( + revive_llvm_context::polkavm_evm_ext_code::size(context, None)?, + ), + None => Err(CodegenError::Unsupported( + "code type undefined for codesize".into(), + )), + }, + + Expression::GasPrice => { + Ok(revive_llvm_context::polkavm_evm_contract_context::gas_price(context)?) + } + + Expression::ExtCodeSize { address } => { + let addr_val = self.translate_value(address)?.into_int_value(); + let addr_val = self.ensure_word_type(context, addr_val, "extcodesize_addr")?; + Ok(revive_llvm_context::polkavm_evm_ext_code::size( + context, + Some(addr_val), + )?) + } + + Expression::ReturnDataSize => { + Ok(revive_llvm_context::polkavm_evm_return_data::size(context)?) + } + + Expression::ExtCodeHash { address } => { + let addr_val = self.translate_value(address)?.into_int_value(); + let addr_val = self.ensure_word_type(context, addr_val, "extcodehash_addr")?; + Ok(revive_llvm_context::polkavm_evm_ext_code::hash( + context, addr_val, + )?) + } + + Expression::BlockHash { number } => { + let num_val = self.translate_value(number)?.into_int_value(); + let num_val = self.ensure_word_type(context, num_val, "blockhash_num")?; + Ok( + revive_llvm_context::polkavm_evm_contract_context::block_hash( + context, num_val, + )?, + ) + } + + Expression::Coinbase => { + let value = revive_llvm_context::polkavm_evm_contract_context::coinbase(context)?; + let address_max = (num::BigUint::from(1u32) << 160) - num::BigUint::from(1u32); + self.emit_validator_assume(context, value, &address_max)?; + Ok(value) + } + + Expression::Timestamp => { + let value = + revive_llvm_context::polkavm_evm_contract_context::block_timestamp(context)?; + Self::apply_range_proof(context, value, 64, "timestamp") + } + + Expression::Number => { + let value = + revive_llvm_context::polkavm_evm_contract_context::block_number(context)?; + Self::apply_range_proof(context, value, 64, "number") + } + + Expression::Difficulty => { + Ok(revive_llvm_context::polkavm_evm_contract_context::difficulty(context)?) + } + + Expression::GasLimit => { + Ok(revive_llvm_context::polkavm_evm_contract_context::gas_limit(context)?) + } + + Expression::ChainId => { + let value = revive_llvm_context::polkavm_evm_contract_context::chain_id(context)?; + Self::apply_range_proof(context, value, 64, "chainid") + } + + Expression::SelfBalance => Ok( + revive_llvm_context::polkavm_evm_ether_gas::self_balance(context)?, + ), + + Expression::BaseFee => { + let value = revive_llvm_context::polkavm_evm_contract_context::basefee(context)?; + Self::apply_range_proof(context, value, 128, "basefee") + } + + Expression::BlobHash { .. } | Expression::BlobBaseFee => { + Ok(context.word_const(0).as_basic_value_enum()) + } + + Expression::Gas => Ok(revive_llvm_context::polkavm_evm_ether_gas::gas(context)?), + + Expression::MSize => Ok(revive_llvm_context::polkavm_evm_memory::msize(context)?), + + Expression::Address => { + let value = revive_llvm_context::polkavm_evm_contract_context::address(context)?; + let address_max = (num::BigUint::from(1u32) << 160) - num::BigUint::from(1u32); + self.emit_validator_assume(context, value, &address_max)?; + Ok(value) + } + + Expression::Balance { address } => { + let addr_val = self.translate_value(address)?.into_int_value(); + let addr_val = self.ensure_word_type(context, addr_val, "balance_addr")?; + Ok(revive_llvm_context::polkavm_evm_ether_gas::balance( + context, addr_val, + )?) + } + + Expression::MLoad { offset, region } => { + let offset_val = self.translate_value(offset)?.into_int_value(); + let is_free_pointer = matches!(region, MemoryRegion::FreePointerSlot) + || Self::is_free_pointer_load(offset_val); + + let loaded = match self.native_memory_mode(offset_val) { + NativeMemoryMode::AllNative => { + let offset_xlen = + self.truncate_offset_to_xlen(context, offset_val, "mload_offset_xlen")?; + context.build_load_native(offset_xlen)? + } + NativeMemoryMode::InlineNative => { + let offset_xlen = + self.truncate_offset_to_xlen(context, offset_val, "mload_offset_xlen")?; + let pointer = context.build_heap_gep_unchecked(offset_xlen)?; + if is_free_pointer && !self.heap_opt.fmp_could_be_unbounded() { + let narrow = context + .builder() + .build_load(context.xlen_type(), pointer.value, "fmp_load") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .into_int_value(); + context + .builder() + .build_int_z_extend(narrow, context.word_type(), "fmp_zext") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum() + } else { + context + .builder() + .build_load(context.word_type(), pointer.value, "native_load") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum() + } + } + NativeMemoryMode::InlineByteSwap => { + let offset_xlen = + self.truncate_offset_to_xlen(context, offset_val, "mload_offset_xlen")?; + revive_llvm_context::polkavm_evm_memory::load_bswap_unchecked( + context, + offset_xlen, + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + } + NativeMemoryMode::ByteSwap => { + let offset_val = self.narrow_offset_for_pointer( + context, + offset_val, + offset.id, + "mload_offset_narrow", + )?; + if !self.has_msize { + let offset_xlen = context + .safe_truncate_int_to_xlen(offset_val) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let function = self.get_or_create_load_bswap_checked_fn(context)?; + context + .builder() + .build_call(function, &[offset_xlen.into()], "checked_load") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .try_as_basic_value() + .basic() + .expect("load_bswap_checked should return a value") + } else { + revive_llvm_context::polkavm_evm_memory::load(context, offset_val)? + } + } + }; + if is_free_pointer && !self.heap_opt.fmp_could_be_unbounded() { + // Soundness gate: the post-MLoad range proof asserts + // `FMP < heap_size`. Iter36's win (-31k bytes on OZ) + // relies on this holding when Solidity's allocator + // updates the FMP via sbrk-style `mstore(0x40, + // add(mload(0x40), bounded))` or a literal initial + // value. Hand-written Yul / inline asm that writes + // a non-bounded value to 0x40 violates the + // assumption. `fmp_could_be_unbounded` is set by + // `heap_opt::analyze_statement` when any FMP store + // uses a value whose source isn't a recognized + // allocator pattern, so the proof stays sound and + // OZ contracts keep their codesize wins. + let heap_size = context + .heap_size() + .get_zero_extended_constant() + .unwrap_or(131072); + let max_fmp = heap_size.saturating_sub(1).max(1); + let raw_bits = 64 - max_fmp.leading_zeros(); + let range_bits = raw_bits.clamp(8, 31); + Self::apply_range_proof(context, loaded, range_bits, "fmp") + } else { + Ok(loaded) + } + } + + Expression::SLoad { + key, + static_slot: _, + } => { + let key_arg = self.value_to_storage_key_argument(key, context)?; + if key_arg.is_register() { + let key_val = key_arg + .access(context) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + let sload_fn = self.get_or_create_sload_word_fn(context)?; + let result = context + .builder() + .build_call(sload_fn, &[key_val.into()], "sload_word") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .try_as_basic_value() + .basic() + .expect("sload_word should return a value"); + Ok(result) + } else { + Ok(revive_llvm_context::polkavm_evm_storage::load( + context, &key_arg, + )?) + } + } + + Expression::TLoad { key } => { + let key_arg = self.value_to_argument(key, context)?; + Ok(revive_llvm_context::polkavm_evm_storage::transient_load( + context, &key_arg, + )?) + } + + Expression::Call { + function, + arguments, + } => { + let function_name = self + .function_names + .get(&function.0) + .ok_or(CodegenError::UndefinedFunction(*function))? + .clone(); + + let parameter_types = self.function_param_types.get(&function.0).cloned(); + let mut argument_values = Vec::new(); + for (i, argument) in arguments.iter().enumerate() { + let parameter_type = parameter_types + .as_ref() + .and_then(|parameter_types| parameter_types.get(i)); + let value = match parameter_type { + Some(Type::Int(width)) if *width < BitWidth::I256 => { + let llvm_val = self.translate_value(argument)?; + let integer_value = llvm_val.into_int_value(); + let target_type = context.integer_type(width.bits() as usize); + let argument_bits = integer_value.get_type().get_bit_width(); + let target_bits = target_type.get_bit_width(); + if argument_bits > target_bits { + // Soundness: `narrow_function_params` may narrow a + // parameter to I64/I32 based purely on use-site + // demand (e.g. the callee uses the value only as an + // mload offset). A bare `trunc i256 → iN` would + // silently drop bits and bypass the use-site + // `safe_truncate_int_to_xlen`. If forward type + // inference can't prove the argument fits, emit a + // checked truncate that traps on overflow. + if self.argument_provably_fits( + integer_value, + *argument, + target_bits, + ) { + context + .builder() + .build_int_truncate( + integer_value, + target_type, + &format!("call_arg_narrow_{}", i), + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum() + } else { + self.checked_truncate_to( + context, + integer_value, + target_type, + &format!("call_arg_narrow_{}", i), + )? + .as_basic_value_enum() + } + } else if argument_bits < target_bits { + context + .builder() + .build_int_z_extend( + integer_value, + target_type, + &format!("call_arg_widen_{}", i), + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum() + } else { + integer_value.as_basic_value_enum() + } + } + _ => self.translate_value_as_word( + argument, + context, + &format!("call_arg_{}", i), + )?, + }; + argument_values.push(value); + } + + context.set_debug_location(1, 0, None)?; + + let llvm_function = context + .get_function(&function_name, true) + .ok_or(CodegenError::UndefinedFunction(*function))?; + let result = context.build_call( + llvm_function.borrow().declaration(), + &argument_values, + &format!("{}_result", function_name), + ); + + if let Some(mask) = self.validator_masks.get(&function.0) { + if let Some(first_arg) = argument_values.first() { + self.emit_validator_assume(context, *first_arg, mask)?; + } + } + + let result = result.unwrap_or_else(|| context.word_const(0).as_basic_value_enum()); + + let return_types = self.function_return_types.get(&function.0); + let result = match return_types { + Some(return_types) + if return_types.len() == 1 + && matches!(return_types[0], Type::Int(bit_width) if bit_width < BitWidth::I256) => + { + if result.is_int_value() { + let integer_value = result.into_int_value(); + if integer_value.get_type().get_bit_width() < 256 { + context + .builder() + .build_int_z_extend( + integer_value, + context.word_type(), + "call_ret_extend", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum() + } else { + result + } + } else { + result + } + } + _ => result, + }; + + Ok(result) + } + + Expression::Truncate { value, to } => { + let value = self.translate_value(value)?.into_int_value(); + let target_type = context.integer_type(to.bits() as usize); + Ok(context + .builder() + .build_int_truncate(value, target_type, "truncate") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum()) + } + + Expression::ZeroExtend { value, to } => { + let value = self.translate_value(value)?.into_int_value(); + let target_type = context.integer_type(to.bits() as usize); + Ok(context + .builder() + .build_int_z_extend(value, target_type, "zext") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum()) + } + + Expression::SignExtendTo { value, to } => { + let value = self.translate_value(value)?.into_int_value(); + let target_type = context.integer_type(to.bits() as usize); + Ok(context + .builder() + .build_int_s_extend(value, target_type, "sext") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .as_basic_value_enum()) + } + + Expression::Keccak256 { offset, length } => { + let offset_val = self.translate_value(offset)?.into_int_value(); + let offset_val = self.narrow_offset_for_pointer( + context, + offset_val, + offset.id, + "keccak_offset_narrow", + )?; + let length_val = self.translate_value(length)?.into_int_value(); + let length_val = self.narrow_offset_for_pointer( + context, + length_val, + length.id, + "keccak_length_narrow", + )?; + Ok(revive_llvm_context::polkavm_evm_crypto::sha3( + context, offset_val, length_val, + )?) + } + + Expression::Keccak256Pair { word0, word1 } => { + let word0_val = self.translate_value(word0)?.into_int_value(); + let word0_val = self.ensure_word_type(context, word0_val, "keccak_word0")?; + let word1_val = self.translate_value(word1)?.into_int_value(); + let word1_val = self.ensure_word_type(context, word1_val, "keccak_word1")?; + + if word1_val.is_const() && Self::try_extract_const_u64(word1_val).is_none() { + let wrapper_fn = + self.get_or_create_keccak256_slot_wrapper(word1_val, context)?; + let function_type = context + .word_type() + .fn_type(&[context.word_type().into()], false); + let result = context + .builder() + .build_indirect_call( + function_type, + wrapper_fn.as_global_value().as_pointer_value(), + &[word0_val.into()], + "keccak256_slot_call", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + Ok(result + .try_as_basic_value() + .basic() + .expect("keccak256 slot wrapper should return a value")) + } else { + Ok(revive_llvm_context::polkavm_evm_crypto::sha3_two_words( + context, word0_val, word1_val, + )?) + } + } + + Expression::Keccak256Single { word0 } => { + let word0_val = self.translate_value(word0)?.into_int_value(); + let word0_val = self.ensure_word_type(context, word0_val, "keccak_word0")?; + Ok(revive_llvm_context::polkavm_evm_crypto::sha3_one_word( + context, word0_val, + )?) + } + + Expression::DataOffset { id } => { + let argument = + revive_llvm_context::polkavm_evm_create::contract_hash(context, id.clone())?; + argument + .access(context) + .map_err(|e| CodegenError::Llvm(e.to_string())) + } + + Expression::DataSize { id } => { + let argument = + revive_llvm_context::polkavm_evm_create::header_size(context, id.clone())?; + argument + .access(context) + .map_err(|e| CodegenError::Llvm(e.to_string())) + } + + Expression::LoadImmutable { key } => { + let offset = context + .solidity_mut() + .get_or_allocate_immutable(key.as_str()) + / revive_common::BYTE_LENGTH_WORD; + let index = context.xlen_type().const_int(offset as u64, false); + Ok(revive_llvm_context::polkavm_evm_immutable::load( + context, index, + )?) + } + + Expression::MappingSLoad { key, slot } => { + let key_val = self.translate_value(key)?.into_int_value(); + let key_val = self.ensure_word_type(context, key_val, "mapping_sload_key")?; + let slot_val = self.translate_value(slot)?.into_int_value(); + let slot_val = self.ensure_word_type(context, slot_val, "mapping_sload_slot")?; + + if self.use_outlined_mapping_sload { + let mapping_sload_fn = self.get_or_create_mapping_sload_fn(context)?; + let result = context + .builder() + .build_call( + mapping_sload_fn, + &[key_val.into(), slot_val.into()], + "mapping_sload_call", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .try_as_basic_value() + .basic() + .expect("mapping_sload should return a value"); + Ok(result) + } else { + let hash_val = + if slot_val.is_const() && Self::try_extract_const_u64(slot_val).is_none() { + let wrapper_fn = + self.get_or_create_keccak256_slot_wrapper(slot_val, context)?; + let function_type = context + .word_type() + .fn_type(&[context.word_type().into()], false); + context + .builder() + .build_indirect_call( + function_type, + wrapper_fn.as_global_value().as_pointer_value(), + &[key_val.into()], + "keccak256_slot_call", + ) + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .try_as_basic_value() + .basic() + .expect("keccak256 slot wrapper should return a value") + .into_int_value() + } else { + revive_llvm_context::polkavm_evm_crypto::sha3_two_words( + context, key_val, slot_val, + )? + .into_int_value() + }; + let sload_fn = self.get_or_create_sload_word_fn(context)?; + let result = context + .builder() + .build_call(sload_fn, &[hash_val.into()], "mapping_sload_word") + .map_err(|e| CodegenError::Llvm(e.to_string()))? + .try_as_basic_value() + .basic() + .expect("sload_word should return a value"); + Ok(result) + } + } + + Expression::LinkerSymbol { path } => Ok( + revive_llvm_context::polkavm_evm_call::linker_symbol(context, path)?, + ), + } + } + + /// Generates a narrow (64-bit or less) unsigned division or modulo. + /// Uses native LLVM udiv/urem instead of expensive 256-bit runtime calls. + /// Handles division by zero (returns 0 per EVM spec). + fn generate_narrow_divmod( + &mut self, + operation: BinaryOperation, + lhs: IntValue<'ctx>, + rhs: IntValue<'ctx>, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + let int_type = lhs.get_type(); + let zero = int_type.const_zero(); + + let is_zero = context + .builder() + .build_int_compare(inkwell::IntPredicate::EQ, rhs, zero, "divmod_iszero") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + + let non_zero_block = context.append_basic_block("divmod_nonzero"); + let join_block = context.append_basic_block("divmod_join"); + let current_block = context.basic_block(); + + context.build_conditional_branch(is_zero, join_block, non_zero_block)?; + + context.set_basic_block(non_zero_block); + let result = match operation { + BinaryOperation::Div => context + .builder() + .build_int_unsigned_div(lhs, rhs, "narrow_div") + .map_err(|e| CodegenError::Llvm(e.to_string()))?, + BinaryOperation::Mod => context + .builder() + .build_int_unsigned_rem(lhs, rhs, "narrow_mod") + .map_err(|e| CodegenError::Llvm(e.to_string()))?, + _ => unreachable!(), + }; + let non_zero_exit = context.basic_block(); + context.build_unconditional_branch(join_block); + + context.set_basic_block(join_block); + let phi = context + .builder() + .build_phi(int_type, "divmod_result") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + phi.add_incoming(&[(&zero, current_block), (&result, non_zero_exit)]); + + Ok(phi.as_basic_value().as_basic_value_enum()) + } + + /// Generates a binary operation. + fn generate_binop( + &mut self, + operation: BinaryOperation, + lhs: IntValue<'ctx>, + rhs: IntValue<'ctx>, + context: &mut PolkaVMContext<'ctx>, + ) -> Result> { + match operation { + BinaryOperation::Add => Ok(revive_llvm_context::polkavm_evm_arithmetic::addition( + context, lhs, rhs, + )?), + BinaryOperation::Sub => Ok(revive_llvm_context::polkavm_evm_arithmetic::subtraction( + context, lhs, rhs, + )?), + BinaryOperation::Mul => Ok( + revive_llvm_context::polkavm_evm_arithmetic::multiplication(context, lhs, rhs)?, + ), + BinaryOperation::Div => Ok(revive_llvm_context::polkavm_evm_arithmetic::division( + context, lhs, rhs, + )?), + BinaryOperation::SDiv => Ok( + revive_llvm_context::polkavm_evm_arithmetic::division_signed(context, lhs, rhs)?, + ), + BinaryOperation::Mod => Ok(revive_llvm_context::polkavm_evm_arithmetic::remainder( + context, lhs, rhs, + )?), + BinaryOperation::SMod => Ok( + revive_llvm_context::polkavm_evm_arithmetic::remainder_signed(context, lhs, rhs)?, + ), + BinaryOperation::Exp => Ok(revive_llvm_context::polkavm_evm_math::exponent( + context, lhs, rhs, + )?), + BinaryOperation::And => Ok(revive_llvm_context::polkavm_evm_bitwise::and( + context, lhs, rhs, + )?), + BinaryOperation::Or => Ok(revive_llvm_context::polkavm_evm_bitwise::or( + context, lhs, rhs, + )?), + BinaryOperation::Xor => Ok(revive_llvm_context::polkavm_evm_bitwise::xor( + context, lhs, rhs, + )?), + BinaryOperation::Shl => { + if let Some(shift) = Self::try_get_small_constant(lhs) { + if shift >= 256 { + return Ok(rhs.get_type().const_zero().as_basic_value_enum()); + } + let result = context + .builder() + .build_left_shift(rhs, lhs, "shl_const") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + return Ok(result.as_basic_value_enum()); + } + Ok(revive_llvm_context::polkavm_evm_bitwise::shift_left( + context, lhs, rhs, + )?) + } + BinaryOperation::Shr => { + if let Some(shift) = Self::try_get_small_constant(lhs) { + if shift >= 256 { + return Ok(rhs.get_type().const_zero().as_basic_value_enum()); + } + let result = context + .builder() + .build_right_shift(rhs, lhs, false, "shr_const") + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + return Ok(result.as_basic_value_enum()); + } + Ok(revive_llvm_context::polkavm_evm_bitwise::shift_right( + context, lhs, rhs, + )?) + } + BinaryOperation::Sar => Ok( + revive_llvm_context::polkavm_evm_bitwise::shift_right_arithmetic( + context, lhs, rhs, + )?, + ), + BinaryOperation::Lt => build_cmp(context, inkwell::IntPredicate::ULT, lhs, rhs, "lt"), + BinaryOperation::Gt => build_cmp(context, inkwell::IntPredicate::UGT, lhs, rhs, "gt"), + BinaryOperation::Slt => build_cmp(context, inkwell::IntPredicate::SLT, lhs, rhs, "slt"), + BinaryOperation::Sgt => build_cmp(context, inkwell::IntPredicate::SGT, lhs, rhs, "sgt"), + BinaryOperation::Eq => build_cmp(context, inkwell::IntPredicate::EQ, lhs, rhs, "eq"), + BinaryOperation::Byte => Ok(revive_llvm_context::polkavm_evm_bitwise::byte( + context, lhs, rhs, + )?), + BinaryOperation::SignExtend => Ok(revive_llvm_context::polkavm_evm_math::sign_extend( + context, lhs, rhs, + )?), + BinaryOperation::AddMod | BinaryOperation::MulMod => Err(CodegenError::Unsupported( + format!("Binary call for ternary operation {:?}", operation), + )), + } + } + + /// Converts an IR type to LLVM type. + fn ir_type_to_llvm( + &self, + value_type: Type, + context: &PolkaVMContext<'ctx>, + ) -> inkwell::types::BasicTypeEnum<'ctx> { + match value_type { + Type::Int(width) => context + .integer_type(width.bits() as usize) + .as_basic_type_enum(), + Type::Ptr(_) => context.word_type().as_basic_type_enum(), + Type::Void => context.word_type().as_basic_type_enum(), + } + } + + /// Translates a value and ensures it's word type. + /// Used for phi nodes and other operations requiring consistent types. + fn translate_value_as_word( + &self, + value: &Value, + context: &PolkaVMContext<'ctx>, + name: &str, + ) -> Result> { + let llvm_val = self.translate_value(value)?; + if llvm_val.is_int_value() { + let integer_value = llvm_val.into_int_value(); + Ok(self + .ensure_word_type(context, integer_value, name)? + .as_basic_value_enum()) + } else { + Ok(llvm_val) + } + } + + /// Converts a Value to a PolkaVMArgument for storage operations. + /// Storage operations require 256-bit values, so narrow values are zero-extended. + fn value_to_argument( + &self, + value: &Value, + context: &PolkaVMContext<'ctx>, + ) -> Result> { + let llvm_val = self.translate_value(value)?; + if llvm_val.is_int_value() { + let integer_value = llvm_val.into_int_value(); + let word_val = self.ensure_word_type(context, integer_value, "storage_arg")?; + Ok(PolkaVMArgument::value(word_val.as_basic_value_enum())) + } else { + Ok(PolkaVMArgument::value(llvm_val)) + } + } + + /// Gets or creates an outlined keccak256 slot wrapper function for a constant slot hash. + /// + /// Each wrapper is `noinline (i256 word0) -> i256` that calls + /// `__revive_keccak256_two_words(word0, CONSTANT_SLOT)`. + /// This avoids materializing the large i256 constant at every call site. + fn get_or_create_keccak256_slot_wrapper( + &mut self, + slot_const: IntValue<'ctx>, + context: &PolkaVMContext<'ctx>, + ) -> Result> { + let const_str = slot_const.print_to_string().to_string(); + + if let Some(&wrapper_fn) = self.keccak256_slot_wrappers.get(&const_str) { + return Ok(wrapper_fn); + } + + let wrapper_name = format!("__keccak256_slot_{}", self.keccak256_slot_wrappers.len()); + + let word_type = context.word_type(); + let function_type = word_type.fn_type(&[word_type.into()], false); + + let wrapper_fn = context.module().add_function( + &wrapper_name, + function_type, + Some(inkwell::module::Linkage::Internal), + ); + + let noinline_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::NoInline as u32, 0); + let optsize_attr = context.llvm().create_enum_attribute( + revive_llvm_context::PolkaVMAttribute::OptimizeForSize as u32, + 0, + ); + let minsize_attr = context + .llvm() + .create_enum_attribute(revive_llvm_context::PolkaVMAttribute::MinSize as u32, 0); + wrapper_fn.add_attribute(inkwell::attributes::AttributeLoc::Function, noinline_attr); + wrapper_fn.add_attribute(inkwell::attributes::AttributeLoc::Function, optsize_attr); + wrapper_fn.add_attribute(inkwell::attributes::AttributeLoc::Function, minsize_attr); + + let saved_block = context.basic_block(); + + let entry_block = context.llvm().append_basic_block(wrapper_fn, "entry"); + context.set_basic_block(entry_block); + + let word0_param = wrapper_fn.get_nth_param(0).unwrap().into_int_value(); + + let keccak_fn = context + .get_function( + revive_llvm_context::PolkaVMKeccak256TwoWordsFunction::NAME, + false, + ) + .expect("__revive_keccak256_two_words should be declared"); + + let result = context + .build_call( + keccak_fn.borrow().declaration(), + &[word0_param.into(), slot_const.into()], + "keccak256_slot_result", + ) + .expect("keccak256_two_words should return a value"); + + context.build_return(Some(&result)); + + context.set_basic_block(saved_block); + + self.keccak256_slot_wrappers.insert(const_str, wrapper_fn); + + Ok(wrapper_fn) + } + + /// Converts a storage key Value to a PolkaVMArgument, using global constants for + /// constant keys to avoid materializing the same 256-bit constant at every call site. + /// + /// When the key is a constant i256, creates a global constant (cached by value) and + /// returns a Pointer argument pointing to it. This eliminates the alloca+store pattern + /// that `as_pointer()` would otherwise emit at each storage access site. + fn value_to_storage_key_argument( + &mut self, + value: &Value, + context: &PolkaVMContext<'ctx>, + ) -> Result> { + let llvm_val = self.translate_value(value)?; + if !llvm_val.is_int_value() { + return Ok(PolkaVMArgument::value(llvm_val)); + } + + let integer_value = llvm_val.into_int_value(); + let word_val = self.ensure_word_type(context, integer_value, "storage_key")?; + + if !word_val.is_const() { + return Ok(PolkaVMArgument::value(word_val.as_basic_value_enum())); + } + + if Self::try_extract_const_u64(word_val).is_some() { + return Ok(PolkaVMArgument::value(word_val.as_basic_value_enum())); + } + + let const_str = word_val.print_to_string().to_string(); + + if let Some(&global_ptr) = self.storage_key_globals.get(&const_str) { + let pointer = revive_llvm_context::PolkaVMPointer::new( + context.word_type(), + Default::default(), + global_ptr, + ); + Ok(PolkaVMArgument::pointer( + pointer, + "storage_key_global".into(), + )) + } else { + let global_name = format!("__storage_key_{}", self.storage_key_globals.len()); + let global = context.module().add_global( + context.word_type(), + Some(inkwell::AddressSpace::default()), + &global_name, + ); + global.set_linkage(inkwell::module::Linkage::Internal); + global.set_constant(true); + global.set_initializer(&word_val); + global.set_alignment(32); + + let global_ptr = global.as_pointer_value(); + self.storage_key_globals.insert(const_str, global_ptr); + + let pointer = revive_llvm_context::PolkaVMPointer::new( + context.word_type(), + Default::default(), + global_ptr, + ); + Ok(PolkaVMArgument::pointer( + pointer, + "storage_key_global".into(), + )) + } + } +} + +/// Emits an `icmp lhs, rhs` and returns the i1 result as a `BasicValueEnum`. +fn build_cmp<'ctx>( + context: &mut PolkaVMContext<'ctx>, + pred: inkwell::IntPredicate, + lhs: IntValue<'ctx>, + rhs: IntValue<'ctx>, + name: &str, +) -> Result> { + let cmp = context + .builder() + .build_int_compare(pred, lhs, rhs, name) + .map_err(|e| CodegenError::Llvm(e.to_string()))?; + Ok(cmp.as_basic_value_enum()) +} + +impl Default for LlvmCodegen<'_> { + fn default() -> Self { + Self::new( + HeapOptResults::default(), + TypeInference::default(), + BTreeMap::new(), + ) + } +} diff --git a/crates/newyork/src/type_inference.rs b/crates/newyork/src/type_inference.rs new file mode 100644 index 000000000..ba19fa71b --- /dev/null +++ b/crates/newyork/src/type_inference.rs @@ -0,0 +1,1701 @@ +//! Type inference pass for narrowing integer widths. +//! +//! This module implements a dataflow-based type inference algorithm that +//! determines the minimum bit-width required for each SSA value. The algorithm: +//! +//! 1. **Forward pass**: Computes minimum width from literals and operation results +//! 2. **Backward pass**: Constrains width based on how values are USED +//! 3. Iterates until a fixed point is reached +//! +//! Key insight: If a value is only used in contexts needing N bits (e.g., mload offset +//! only needs 64 bits), we can constrain the value's computation to N bits. +//! +//! The result is that each value has the narrowest possible type that can +//! correctly represent all values it may hold at runtime AND satisfies all use sites. + +use std::collections::{BTreeMap, BTreeSet}; + +use num::ToPrimitive; + +use crate::ir::{ + for_each_statement, BinaryOperation, BitWidth, Block, Expression, Function, MemoryRegion, + Object, Region, Statement, Type, UnaryOperation, ValueId, +}; + +/// Type constraint representing the width bounds for a value. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct TypeConstraint { + /// Minimum bit width required (from forward propagation). + pub min_width: BitWidth, + /// Maximum bit width needed (from backward propagation / use sites). + /// If max_width < min_width, the value is truncated at use sites. + pub max_width: BitWidth, + /// Whether the value is known to be signed. + pub is_signed: bool, +} + +impl Default for TypeConstraint { + fn default() -> Self { + TypeConstraint { + min_width: BitWidth::I1, + max_width: BitWidth::I256, + is_signed: false, + } + } +} + +impl TypeConstraint { + /// Creates a constraint for a specific width. + pub fn with_width(width: BitWidth) -> Self { + TypeConstraint { + min_width: width, + max_width: BitWidth::I256, + is_signed: false, + } + } + + /// Creates a signed constraint. + pub fn signed(width: BitWidth) -> Self { + TypeConstraint { + min_width: width, + max_width: BitWidth::I256, + is_signed: true, + } + } + + /// Joins two constraints, taking the wider minimum. + pub fn join(&self, other: &TypeConstraint) -> TypeConstraint { + TypeConstraint { + min_width: self.min_width.max(other.min_width), + max_width: self.max_width.min(other.max_width), + is_signed: self.is_signed || other.is_signed, + } + } + + /// Widens this constraint's minimum to at least the given width. + pub fn widen_to(&mut self, width: BitWidth) -> bool { + if width > self.min_width { + self.min_width = width; + true + } else { + false + } + } + + /// Narrows this constraint's maximum to at most the given width. + pub fn narrow_max_to(&mut self, width: BitWidth) -> bool { + if width < self.max_width { + self.max_width = width; + true + } else { + false + } + } + + /// Returns the effective width to use for this value. + /// + /// Uses the minimum of forward-propagated min_width and backward-propagated + /// max_width, ensuring the value is at least as wide as what the definition + /// requires but no wider than what use sites need. + pub fn effective_width(&self) -> BitWidth { + self.min_width.min(self.max_width) + } +} + +/// Use context - how a value is used affects its max_width constraint. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum UseContext { + /// Used as a memory offset (64-bit sufficient). + MemoryOffset, + /// Used as a memory value (256-bit required for EVM compatibility). + MemoryValue, + /// Used as a storage key or value (256-bit required). + StorageAccess, + /// Used in a comparison (keeps narrow type). + Comparison, + /// Used in arithmetic (may need full width depending on operation). + Arithmetic, + /// Used as function argument (depends on callee). + FunctionArg, + /// Returned from function (may escape, assume full width). + FunctionReturn, + /// Used in external call (256-bit for EVM ABI). + ExternalCall, + /// General/unknown use. + General, +} + +impl UseContext { + /// Returns the maximum width needed for this use context. + fn max_width_needed(&self) -> BitWidth { + match self { + UseContext::MemoryOffset => BitWidth::I256, + UseContext::MemoryValue => BitWidth::I256, + UseContext::StorageAccess => BitWidth::I256, + UseContext::Comparison => BitWidth::I256, + UseContext::Arithmetic => BitWidth::I256, + UseContext::FunctionArg => BitWidth::I256, + UseContext::FunctionReturn => BitWidth::I256, + UseContext::ExternalCall => BitWidth::I256, + UseContext::General => BitWidth::I256, + } + } +} + +/// Type inference context holding all constraints. +#[derive(Clone)] +pub struct TypeInference { + /// Constraints for each value. + constraints: BTreeMap, + /// Use contexts for each value (for backward propagation). + uses: BTreeMap>, + /// Whether any constraint changed in the last iteration. + changed: bool, + /// Function return value IDs, keyed by FunctionId. + /// Used during the forward pass to propagate return value widths to call sites. + function_returns: BTreeMap>, + /// Per-value refined function-argument demand: the widest narrowed parameter width + /// across all call sites where this value is passed as an argument. + /// Set by `refine_demands_from_params` after parameter narrowing. + /// When present, overrides UseContext::FunctionArg (I256) in `use_demand_width`. + fn_arg_demand: BTreeMap, + /// Known constant values (from Literal expressions), used for shift-amount + /// analysis in forward inference. Only stores values that fit in u64. + known_constants: BTreeMap, + /// Type inference results for subobjects (each subobject has its own namespace). + pub sub_inferences: Vec, +} + +impl TypeInference { + /// Creates a new type inference context. + pub fn new() -> Self { + TypeInference { + constraints: BTreeMap::new(), + uses: BTreeMap::new(), + changed: false, + function_returns: BTreeMap::new(), + fn_arg_demand: BTreeMap::new(), + known_constants: BTreeMap::new(), + sub_inferences: Vec::new(), + } + } + + /// Gets the constraint for a value, creating a default if none exists. + pub fn get(&self, id: ValueId) -> TypeConstraint { + self.constraints.get(&id.0).copied().unwrap_or_default() + } + + /// Gets the effective width for a value (considering both min and max). + pub fn effective_width(&self, id: ValueId) -> BitWidth { + let constraint = self.get(id); + constraint + .min_width + .max(constraint.max_width.min(constraint.min_width)) + } + + /// Computes the widest width needed by any use site of this value. + /// + /// Unlike `max_width` on the constraint (which can be eagerly narrowed by + /// `narrow_from_use` before all uses are collected), this method correctly + /// examines ALL recorded use contexts and returns the WIDEST needed width. + /// + /// Every `UseContext` variant returns I256 from `max_width_needed`, so the + /// only path that yields a result below I256 is `UseContext::FunctionArg` + /// when `fn_arg_demand` carries a refined width for the value (populated + /// by `refine_demands_from_params` after parameter narrowing). In + /// particular, `MemoryOffset` deliberately stays at I256 — see the + /// `MemoryOffset` arm of `max_width_needed` for why narrowing offsets + /// here would bypass the use-site bounds check. + pub fn use_demand_width(&self, id: ValueId) -> BitWidth { + if let Some(uses) = self.uses.get(&id.0) { + if uses.is_empty() { + return BitWidth::I256; + } + let mut widest_needed = BitWidth::I1; + for use_ctx in uses { + let needed = match use_ctx { + UseContext::FunctionArg => self + .fn_arg_demand + .get(&id.0) + .copied() + .unwrap_or(BitWidth::I256), + _ => use_ctx.max_width_needed(), + }; + if needed > widest_needed { + widest_needed = needed; + } + } + widest_needed + } else { + BitWidth::I256 + } + } + + /// Widens a value's constraint to at least the given width. + fn widen(&mut self, id: ValueId, width: BitWidth) -> bool { + let mut constraint = self.get(id); + if constraint.widen_to(width) { + self.constraints.insert(id.0, constraint); + self.changed = true; + true + } else { + false + } + } + + /// Records a use of a value in a specific context (for backward propagation). + fn record_use(&mut self, id: ValueId, context: UseContext) { + self.uses.entry(id.0).or_default().insert(context); + } + + /// Narrows a value's max_width based on use context. + fn narrow_from_use(&mut self, id: ValueId, max_width: BitWidth) -> bool { + let mut constraint = self.get(id); + if constraint.narrow_max_to(max_width) { + self.constraints.insert(id.0, constraint); + self.changed = true; + true + } else { + false + } + } + + /// Marks a value as signed. + fn mark_signed(&mut self, id: ValueId) { + let mut constraint = self.get(id); + if !constraint.is_signed { + constraint.is_signed = true; + self.constraints.insert(id.0, constraint); + self.changed = true; + } + } + + /// Runs type inference on an object with both forward and backward passes. + /// + /// Each object in the tree (deploy code, runtime code) has its own ValueId + /// and FunctionId namespaces (both start at 0 per object). We process each + /// object with a fresh context to avoid cross-object constraint pollution. + pub fn infer_object(&mut self, object: &Object) { + for (function_id, function) in &object.functions { + if !function.return_values.is_empty() { + self.function_returns + .insert(function_id.0, function.return_values.clone()); + } + } + + loop { + self.changed = false; + + self.infer_block_forward(&object.code); + + for function in object.functions.values() { + self.infer_function_forward(function); + } + + if !self.changed { + break; + } + } + + self.collect_uses_block(&object.code); + for function in object.functions.values() { + self.collect_uses_function(function); + } + + self.propagate_use_demands(object); + + self.apply_backward_constraints(); + } + + /// Runs type inference on an object tree, including subobjects. + /// + /// Each subobject gets a fresh TypeInference context because different + /// objects in the tree have overlapping ValueId/FunctionId namespaces + /// (each object's translator allocates IDs starting from 0). + pub fn infer_object_tree(&mut self, object: &Object) { + self.infer_object(object); + + for subobject in &object.subobjects { + let mut sub_inference = TypeInference::new(); + sub_inference.infer_object_tree(subobject); + self.sub_inferences.push(sub_inference); + } + } + + /// Forward pass for a function. + fn infer_function_forward(&mut self, function: &Function) { + for (parameter_id, parameter_type) in &function.parameters { + if let Type::Int(width) = parameter_type { + self.widen(*parameter_id, *width); + } + } + + self.infer_block_forward(&function.body); + } + + /// Collect uses from a function for backward propagation. + fn collect_uses_function(&mut self, function: &Function) { + self.collect_uses_block(&function.body); + + for ret_id in &function.return_values { + self.record_use(*ret_id, UseContext::FunctionReturn); + } + } + + /// Apply backward constraints based on collected uses. + fn apply_backward_constraints(&mut self) { + for (id, uses) in &self.uses { + let mut widest_needed = BitWidth::I1; + for use_ctx in uses { + let needed = match use_ctx { + UseContext::FunctionArg => self + .fn_arg_demand + .get(id) + .copied() + .unwrap_or(BitWidth::I256), + _ => use_ctx.max_width_needed(), + }; + if needed > widest_needed { + widest_needed = needed; + } + } + + if widest_needed < BitWidth::I256 { + let mut constraint = self.constraints.get(id).copied().unwrap_or_default(); + constraint.narrow_max_to(widest_needed); + self.constraints.insert(*id, constraint); + } + } + } + + /// Computes the widest backward demand excluding "transparent-for-parameters" uses. + /// + /// Used by `narrow_function_params` to determine if only Comparison/Arithmetic + /// uses block parameter narrowing. Returns I256 if no uses recorded or + /// any truly width-requiring use needs I256. + /// + /// Comparison uses are excluded because param narrowing inserts + /// zero-extension at function entry, making comparison operations see the + /// correct (zero-extended) value for in-range inputs. + pub fn non_comparison_demand(&self, id: ValueId) -> BitWidth { + if let Some(uses) = self.uses.get(&id.0) { + if uses.is_empty() { + return BitWidth::I256; + } + let mut widest = BitWidth::I1; + for use_ctx in uses { + if matches!(use_ctx, UseContext::Comparison) { + continue; + } + let needed = match use_ctx { + UseContext::FunctionArg => self + .fn_arg_demand + .get(&id.0) + .copied() + .unwrap_or(BitWidth::I256), + _ => use_ctx.max_width_needed(), + }; + if needed > widest { + widest = needed; + } + } + widest + } else { + BitWidth::I256 + } + } + + /// Propagates use demands backward through transparent operations. + /// + /// For "transparent" operations (add, or, xor, and), the lower N bits of + /// the result depend only on the lower N bits of the operands. This means + /// if the result is only used in a context needing N bits (e.g., memory + /// offset → I64), the operands also only need N bits. + /// + /// This enables parameter narrowing through add chains: + /// `let pos := add(param, 32); mstore(pos, value)` → param only needs I64. + fn propagate_use_demands(&mut self, object: &Object) { + loop { + let mut changed = false; + changed |= self.propagate_demands_block(&object.code); + for function in object.functions.values() { + changed |= self.propagate_demands_block(&function.body); + } + if !changed { + break; + } + } + } + + fn propagate_demands_block(&mut self, block: &Block) -> bool { + let mut changed = false; + let mut snapshot: Vec = Vec::new(); + for_each_statement(&block.statements, &mut |statement| { + if let Statement::Let { bindings, value } = statement { + if bindings.len() == 1 { + let result_id = bindings[0]; + snapshot.clear(); + if let Some(uses) = self.uses.get(&result_id.0) { + snapshot.extend(uses.iter().copied()); + } + if !snapshot.is_empty() { + changed |= self.propagate_demand_to_expression(value, &snapshot); + } + } + } + }); + changed + } + + /// Propagates result uses to operands of transparent expressions. + fn propagate_demand_to_expression( + &mut self, + expression: &Expression, + result_uses: &[UseContext], + ) -> bool { + match expression { + Expression::Binary { + lhs, + rhs, + operation: + BinaryOperation::Add + | BinaryOperation::Sub + | BinaryOperation::Mul + | BinaryOperation::Or + | BinaryOperation::Xor + | BinaryOperation::And, + } => { + let mut changed = false; + for use_ctx in result_uses { + changed |= self.record_use_if_new(lhs.id, *use_ctx); + changed |= self.record_use_if_new(rhs.id, *use_ctx); + } + changed + } + Expression::Binary { + rhs, + operation: BinaryOperation::Shl, + .. + } => { + let mut changed = false; + for use_ctx in result_uses { + changed |= self.record_use_if_new(rhs.id, *use_ctx); + } + changed + } + Expression::Unary { + operand, + operation: UnaryOperation::Not, + } => { + let mut changed = false; + for use_ctx in result_uses { + changed |= self.record_use_if_new(operand.id, *use_ctx); + } + changed + } + Expression::Var(id) => { + let mut changed = false; + for use_ctx in result_uses { + changed |= self.record_use_if_new(*id, *use_ctx); + } + changed + } + _ => false, + } + } + + /// Records a use context for a value, returning true if it was new. + fn record_use_if_new(&mut self, id: ValueId, context: UseContext) -> bool { + let entry = self.uses.entry(id.0).or_default(); + if entry.contains(&context) { + false + } else { + entry.insert(context); + true + } + } + + /// Narrows function parameter types based on backward demand analysis. + /// + /// Uses the backward-inferred max_width for each parameter, which reflects + /// whether ALL use paths of the parameter are compatible with narrowing. + /// The backward pass + demand propagation through transparent ops ensures + /// that if ANY use path needs full width (storage values, external calls), + /// max_width stays at I256 and prevents narrowing. + /// + /// For parameters where only `Comparison` uses block narrowing, a relaxed + /// check is applied: if all non-comparison uses need ≤ I64 AND all callers + /// provably pass values ≤ I64, narrowing is safe. The zero-extension in the + /// function body preserves comparison semantics for values within the narrowed + /// range (e.g., `gt(zext(param_i64), threshold)` is correct when param ≤ 2^64). + /// + /// Returns true if any parameter was narrowed. + pub fn narrow_function_params(&self, object: &mut Object) -> bool { + let mut changed = false; + for function in object.functions.values_mut() { + for (parameter_id, parameter_type) in &mut function.parameters { + let constraint = self.get(*parameter_id); + + if !matches!(parameter_type, Type::Int(BitWidth::I256)) { + continue; + } + + if constraint.is_signed { + continue; + } + + let demand = constraint.max_width; + if demand < BitWidth::I256 { + let clamped = demand.max(BitWidth::I32); + *parameter_type = Type::Int(clamped); + changed = true; + } + } + } + + for (subobject, sub_inf) in object.subobjects.iter_mut().zip(self.sub_inferences.iter()) { + changed |= sub_inf.narrow_function_params(subobject); + } + changed + } + + /// Narrows function parameters based on call-site argument widths. + /// + /// For each function, examines ALL call sites and computes the forward + /// min_width of each argument. If every caller passes an argument that + /// provably fits in fewer than 256 bits, the parameter can be narrowed. + /// + /// This is the "forward" complement to the demand-based `narrow_function_params`: + /// - `narrow_function_params`: narrows based on how values are USED inside the function + /// - `narrow_function_params_from_callers`: narrows based on what callers PROVIDE + /// + /// Key use case: after guard_narrow inserts `and(value, 2^160-1)` for address + /// validation, the call-site argument has min_width=I160. This pass detects + /// that ALL callers provide I160 values and narrows the parameter to I160. + pub fn narrow_function_params_from_callers(&self, object: &mut Object) -> bool { + let mut argument_widths: BTreeMap<(u32, usize), BitWidth> = BTreeMap::new(); + let mut called_functions: BTreeSet = BTreeSet::new(); + + self.collect_argument_widths_block( + &object.code, + &mut argument_widths, + &mut called_functions, + ); + for function in object.functions.values() { + self.collect_argument_widths_block( + &function.body, + &mut argument_widths, + &mut called_functions, + ); + } + + let mut changed = false; + for (&function_id, function) in &mut object.functions { + if !called_functions.contains(&function_id.0) { + continue; + } + for (i, (_, parameter_type)) in function.parameters.iter_mut().enumerate() { + if !matches!(parameter_type, Type::Int(BitWidth::I256)) { + continue; + } + if let Some(&width) = argument_widths.get(&(function_id.0, i)) { + if width < BitWidth::I256 { + let clamped = width.max(BitWidth::I32); + *parameter_type = Type::Int(clamped); + changed = true; + } + } + } + } + + for (subobject, sub_inf) in object.subobjects.iter_mut().zip(self.sub_inferences.iter()) { + changed |= sub_inf.narrow_function_params_from_callers(subobject); + } + changed + } + + /// Walks a block (and all nested regions) collecting argument min_widths + /// at call sites. For each call to a function, records the widest argument + /// seen across all callers — caller-driven narrowing uses the maximum. + fn collect_argument_widths_block( + &self, + block: &Block, + argument_widths: &mut BTreeMap<(u32, usize), BitWidth>, + called_functions: &mut BTreeSet, + ) { + for_each_statement(&block.statements, &mut |statement| { + let call = match statement { + Statement::Let { + value: + Expression::Call { + function, + arguments, + }, + .. + } + | Statement::Expression(Expression::Call { + function, + arguments, + }) => Some((function, arguments)), + _ => None, + }; + if let Some((fid, arguments)) = call { + called_functions.insert(fid.0); + for (i, argument) in arguments.iter().enumerate() { + let arg_width = self.get(argument.id).min_width; + let entry = argument_widths.entry((fid.0, i)).or_insert(arg_width); + if arg_width > *entry { + *entry = arg_width; + } + } + } + }); + } + + /// Narrows function return types based on forward min_width analysis. + /// + /// For each function with returns, examines the return value IDs' min_width + /// from the forward pass. If the min_width is provably < I256, narrows + /// the return type. This enables LLVM to use narrow return types (e.g., i64) + /// instead of i256, reducing register pressure and spills. + /// + /// Safety: The forward pass's min_width represents the minimum bit-width + /// required to represent the value based on the operations that produce it. + /// Narrowing is safe because the function provably never produces values + /// wider than min_width. + /// + /// Returns true if any return type was narrowed. + pub fn narrow_function_returns(&self, object: &mut Object) -> bool { + let mut changed = false; + for function in object.functions.values_mut() { + for (i, ret_ty) in function.returns.iter_mut().enumerate() { + if !matches!(ret_ty, Type::Int(BitWidth::I256)) { + continue; + } + + let ret_id = match function.return_values.get(i) { + Some(id) => *id, + None => continue, + }; + + let constraint = self.get(ret_id); + + if constraint.is_signed { + continue; + } + + let width = constraint.min_width; + if width < BitWidth::I256 { + let clamped = width.max(BitWidth::I32); + *ret_ty = Type::Int(clamped); + changed = true; + } + } + } + + for (subobject, sub_inf) in object.subobjects.iter_mut().zip(self.sub_inferences.iter()) { + changed |= sub_inf.narrow_function_returns(subobject); + } + changed + } + + /// Narrows function return types based on backward demand analysis. + /// + /// For each function with I256 returns, examines ALL call sites to determine + /// the widest use demand for each return value. If all callers only use the + /// lower N bits (e.g., only as memory offsets needing I64), the return type + /// can be narrowed to N bits. + /// + /// This is more aggressive than forward-only narrowing because it catches cases + /// where a function internally computes I256 values (e.g., from SLOAD + arithmetic) + /// but all callers only need narrow results. + /// + /// Safety: Narrowing truncates the return value. This is safe because: + /// 1. All callers provably only use the lower N bits (backward demand analysis) + /// 2. Comparisons are excluded (UseContext::Comparison demands I256) + /// 3. External calls/storage are excluded (demand I256) + /// + /// Returns true if any return type was narrowed. + pub fn narrow_function_returns_from_demand(&self, object: &mut Object) -> bool { + let mut return_demands: BTreeMap> = BTreeMap::new(); + + self.collect_return_demands_block(&object.code, &mut return_demands); + for function in object.functions.values() { + self.collect_return_demands_block(&function.body, &mut return_demands); + } + + let mut changed = false; + for function in object.functions.values_mut() { + let demands = match return_demands.get(&function.id.0) { + Some(d) => d, + None => continue, + }; + + for (i, ret_ty) in function.returns.iter_mut().enumerate() { + if !matches!(ret_ty, Type::Int(BitWidth::I256)) { + continue; + } + + let demand = match demands.get(i) { + Some(d) => *d, + None => continue, + }; + + if demand < BitWidth::I256 { + let clamped = demand.max(BitWidth::I32); + *ret_ty = Type::Int(clamped); + changed = true; + } + } + } + + for (subobject, sub_inf) in object.subobjects.iter_mut().zip(self.sub_inferences.iter()) { + changed |= sub_inf.narrow_function_returns_from_demand(subobject); + } + changed + } + + /// Walks a block (and all nested regions) collecting return demands from + /// `Expression::Call` in `Let` statements. For each call binding, records the + /// widest use-demand across all call sites — narrowing uses the maximum. + fn collect_return_demands_block( + &self, + block: &Block, + demands: &mut BTreeMap>, + ) { + for_each_statement(&block.statements, &mut |statement| { + if let Statement::Let { + bindings, + value: Expression::Call { function, .. }, + } = statement + { + for (i, binding_id) in bindings.iter().enumerate() { + let demand = self.use_demand_width(*binding_id); + let entry = demands.entry(function.0).or_default(); + while entry.len() <= i { + entry.push(BitWidth::I1); + } + entry[i] = entry[i].max(demand); + } + } + }); + } + + /// Refines demand widths based on narrowed function parameter types. + /// + /// After `narrow_function_params` has narrowed function parameter types, + /// this method re-examines all call sites and updates use demands for + /// arguments. If a parameter was narrowed from I256 to I64, the argument + /// only needs I64, not I256. + /// + /// This enables cascading demand narrowing: if a value is only passed to + /// narrowed-parameter functions and used as memory offsets, it can be + /// fully narrowed to I64 even though it was originally classified as + /// FunctionArg (which defaults to I256). + pub fn refine_demands_from_params(&mut self, object: &Object) { + let parameter_widths: BTreeMap> = object + .functions + .iter() + .map(|(function_id, function)| { + let widths: Vec = function + .parameters + .iter() + .map(|(_, value_type)| match value_type { + Type::Int(bit_width) => *bit_width, + _ => BitWidth::I256, + }) + .collect(); + (function_id.0, widths) + }) + .collect(); + + self.refine_demands_in_block(&object.code, ¶meter_widths); + for function in object.functions.values() { + self.refine_demands_in_block(&function.body, ¶meter_widths); + } + + self.propagate_use_demands(object); + + self.apply_backward_constraints(); + + for (subobject, sub_inf) in object.subobjects.iter().zip(self.sub_inferences.iter_mut()) { + sub_inf.refine_demands_from_params(subobject); + } + } + + /// Walks a block (and all nested regions) looking for Call expressions and + /// updates argument demands based on the now-narrowed parameter widths. + fn refine_demands_in_block( + &mut self, + block: &Block, + parameter_widths: &BTreeMap>, + ) { + for_each_statement(&block.statements, &mut |statement| { + statement.for_each_expression(&mut |expression| { + self.refine_demands_in_expression(expression, parameter_widths); + }); + }); + } + + /// Checks an expression for Call and updates argument demands. + fn refine_demands_in_expression( + &mut self, + expression: &Expression, + parameter_widths: &BTreeMap>, + ) { + if let Expression::Call { + function, + arguments, + } = expression + { + if let Some(widths) = parameter_widths.get(&function.0) { + for (argument, parameter_width) in arguments.iter().zip(widths.iter()) { + let entry = self + .fn_arg_demand + .entry(argument.id.0) + .or_insert(BitWidth::I1); + *entry = (*entry).max(*parameter_width); + } + } else { + for argument in arguments { + let entry = self + .fn_arg_demand + .entry(argument.id.0) + .or_insert(BitWidth::I1); + *entry = BitWidth::I256; + } + } + } + } + + /// Forward pass: infers minimum types for a block. + fn infer_block_forward(&mut self, block: &Block) { + for statement in &block.statements { + self.infer_statement_forward(statement); + } + } + + /// Forward pass: infers minimum types for a region. + fn infer_region_forward(&mut self, region: &Region) { + for statement in ®ion.statements { + self.infer_statement_forward(statement); + } + } + + /// Collects uses from a block (recursing through nested regions and + /// `For::condition_statements`) for backward propagation. + fn collect_uses_block(&mut self, block: &Block) { + for_each_statement(&block.statements, &mut |statement| { + self.collect_uses_statement(statement); + }); + } + + /// Collects uses from a single statement (no recursion — caller is + /// responsible for walking nested regions, e.g. via `for_each_statement`). + fn collect_uses_statement(&mut self, statement: &Statement) { + match statement { + Statement::MStore { + offset, + value, + region, + } => { + self.record_use(offset.id, UseContext::MemoryOffset); + self.narrow_from_use(offset.id, BitWidth::I64); + if *region == MemoryRegion::FreePointerSlot { + self.record_use(value.id, UseContext::MemoryOffset); + self.narrow_from_use(value.id, BitWidth::I64); + } else { + self.record_use(value.id, UseContext::MemoryValue); + } + } + Statement::MStore8 { offset, value, .. } => { + self.record_use(offset.id, UseContext::MemoryOffset); + self.narrow_from_use(offset.id, BitWidth::I64); + self.record_use(value.id, UseContext::MemoryValue); + } + + Statement::SStore { key, value, .. } | Statement::TStore { key, value } => { + self.record_use(key.id, UseContext::StorageAccess); + self.record_use(value.id, UseContext::StorageAccess); + } + + Statement::MappingSStore { key, slot, value } => { + self.record_use(key.id, UseContext::StorageAccess); + self.record_use(slot.id, UseContext::StorageAccess); + self.record_use(value.id, UseContext::StorageAccess); + } + + Statement::If { condition, .. } => { + self.record_use(condition.id, UseContext::Comparison); + } + + Statement::Switch { scrutinee, .. } => { + self.record_use(scrutinee.id, UseContext::Comparison); + } + + Statement::For { initial_values, .. } => { + for value in initial_values { + self.record_use(value.id, UseContext::Arithmetic); + } + } + + Statement::Revert { offset, length } | Statement::Return { offset, length } => { + self.record_use(offset.id, UseContext::MemoryOffset); + self.narrow_from_use(offset.id, BitWidth::I64); + self.record_use(length.id, UseContext::MemoryOffset); + self.narrow_from_use(length.id, BitWidth::I64); + } + + Statement::ExternalCall { + gas, + address, + value, + args_offset, + args_length, + ret_offset, + ret_length, + .. + } => { + self.record_use(gas.id, UseContext::ExternalCall); + self.record_use(address.id, UseContext::ExternalCall); + if let Some(value) = value { + self.record_use(value.id, UseContext::ExternalCall); + } + self.record_use(args_offset.id, UseContext::MemoryOffset); + self.narrow_from_use(args_offset.id, BitWidth::I64); + self.record_use(args_length.id, UseContext::MemoryOffset); + self.narrow_from_use(args_length.id, BitWidth::I64); + self.record_use(ret_offset.id, UseContext::MemoryOffset); + self.narrow_from_use(ret_offset.id, BitWidth::I64); + self.record_use(ret_length.id, UseContext::MemoryOffset); + self.narrow_from_use(ret_length.id, BitWidth::I64); + } + + Statement::Log { + offset, + length, + topics, + } => { + self.record_use(offset.id, UseContext::MemoryOffset); + self.narrow_from_use(offset.id, BitWidth::I64); + self.record_use(length.id, UseContext::MemoryOffset); + self.narrow_from_use(length.id, BitWidth::I64); + for topic in topics { + self.record_use(topic.id, UseContext::MemoryValue); + } + } + + Statement::CodeCopy { + dest, + offset, + length, + } + | Statement::ExtCodeCopy { + dest, + offset, + length, + .. + } + | Statement::ReturnDataCopy { + dest, + offset, + length, + } + | Statement::CallDataCopy { + dest, + offset, + length, + } => { + self.record_use(dest.id, UseContext::MemoryOffset); + self.narrow_from_use(dest.id, BitWidth::I64); + self.record_use(offset.id, UseContext::MemoryOffset); + self.narrow_from_use(offset.id, BitWidth::I64); + self.record_use(length.id, UseContext::MemoryOffset); + self.narrow_from_use(length.id, BitWidth::I64); + } + + Statement::DataCopy { + dest, + offset, + length, + } => { + self.record_use(dest.id, UseContext::MemoryOffset); + self.narrow_from_use(dest.id, BitWidth::I64); + self.record_use(offset.id, UseContext::MemoryValue); + self.record_use(length.id, UseContext::MemoryOffset); + self.narrow_from_use(length.id, BitWidth::I64); + } + + Statement::MCopy { dest, src, length } => { + self.record_use(dest.id, UseContext::MemoryOffset); + self.narrow_from_use(dest.id, BitWidth::I64); + self.record_use(src.id, UseContext::MemoryOffset); + self.narrow_from_use(src.id, BitWidth::I64); + self.record_use(length.id, UseContext::MemoryOffset); + self.narrow_from_use(length.id, BitWidth::I64); + } + + Statement::Block(_) => {} + + Statement::Let { value, .. } => { + self.collect_uses_expression(value); + } + + Statement::Expression(expression) => { + self.collect_uses_expression(expression); + } + + Statement::Create { + value, + offset, + length, + salt, + .. + } => { + self.record_use(value.id, UseContext::ExternalCall); + self.record_use(offset.id, UseContext::MemoryOffset); + self.narrow_from_use(offset.id, BitWidth::I64); + self.record_use(length.id, UseContext::MemoryOffset); + self.narrow_from_use(length.id, BitWidth::I64); + if let Some(salt) = salt { + self.record_use(salt.id, UseContext::ExternalCall); + } + } + + Statement::SetImmutable { value, .. } => { + self.record_use(value.id, UseContext::General); + } + + Statement::SelfDestruct { address } => { + self.record_use(address.id, UseContext::ExternalCall); + } + + Statement::Leave { return_values } => { + for value in return_values { + self.record_use(value.id, UseContext::FunctionReturn); + } + } + + Statement::Break { values } | Statement::Continue { values } => { + for value in values { + self.record_use(value.id, UseContext::General); + } + } + + Statement::PanicRevert { .. } + | Statement::ErrorStringRevert { .. } + | Statement::CustomErrorRevert { .. } + | Statement::Stop + | Statement::Invalid => {} + } + } + + /// Collects uses from an expression. + fn collect_uses_expression(&mut self, expression: &Expression) { + match expression { + Expression::Binary { + lhs, + rhs, + operation, + } => match operation { + BinaryOperation::Lt + | BinaryOperation::Gt + | BinaryOperation::Slt + | BinaryOperation::Sgt + | BinaryOperation::Eq => { + self.record_use(lhs.id, UseContext::Comparison); + self.record_use(rhs.id, UseContext::Comparison); + } + BinaryOperation::Add + | BinaryOperation::Sub + | BinaryOperation::Mul + | BinaryOperation::Or + | BinaryOperation::Xor + | BinaryOperation::And => {} + BinaryOperation::Shl => { + self.record_use(lhs.id, UseContext::Arithmetic); + } + _ => { + self.record_use(lhs.id, UseContext::Arithmetic); + self.record_use(rhs.id, UseContext::Arithmetic); + } + }, + Expression::Ternary { a, b, n, .. } => { + self.record_use(a.id, UseContext::Arithmetic); + self.record_use(b.id, UseContext::Arithmetic); + self.record_use(n.id, UseContext::Arithmetic); + } + Expression::Unary { operand, operation } => match operation { + UnaryOperation::Not => {} + _ => { + self.record_use(operand.id, UseContext::Arithmetic); + } + }, + Expression::MLoad { offset, .. } => { + self.record_use(offset.id, UseContext::MemoryOffset); + self.narrow_from_use(offset.id, BitWidth::I64); + } + Expression::SLoad { key, .. } | Expression::TLoad { key } => { + self.record_use(key.id, UseContext::StorageAccess); + } + Expression::CallDataLoad { offset } => { + self.record_use(offset.id, UseContext::Arithmetic); + } + Expression::Keccak256 { offset, length } => { + self.record_use(offset.id, UseContext::MemoryOffset); + self.narrow_from_use(offset.id, BitWidth::I64); + self.record_use(length.id, UseContext::MemoryOffset); + self.narrow_from_use(length.id, BitWidth::I64); + } + Expression::Keccak256Pair { word0, word1 } => { + self.record_use(word0.id, UseContext::FunctionArg); + self.record_use(word1.id, UseContext::FunctionArg); + } + Expression::Keccak256Single { word0 } => { + self.record_use(word0.id, UseContext::FunctionArg); + } + Expression::MappingSLoad { key, slot } => { + self.record_use(key.id, UseContext::FunctionArg); + self.record_use(slot.id, UseContext::FunctionArg); + } + Expression::Call { arguments, .. } => { + for argument in arguments { + self.record_use(argument.id, UseContext::FunctionArg); + } + } + Expression::Balance { address } + | Expression::ExtCodeSize { address } + | Expression::ExtCodeHash { address } => { + self.record_use(address.id, UseContext::ExternalCall); + } + Expression::BlockHash { number } | Expression::BlobHash { index: number } => { + self.record_use(number.id, UseContext::MemoryOffset); + self.narrow_from_use(number.id, BitWidth::I64); + } + _ => {} + } + } + + /// Forward pass: infers types for a statement. + fn infer_statement_forward(&mut self, statement: &Statement) { + match statement { + Statement::Let { bindings, value } => { + if let Expression::Literal { value: literal, .. } = value { + if let Some(v) = literal.to_u64() { + if bindings.len() == 1 { + self.known_constants.insert(bindings[0].0, v); + } + } + } + let expr_width = self.infer_expression_width(value); + for binding in bindings { + self.widen(*binding, expr_width); + } + } + + Statement::MStore { offset, value, .. } => { + self.widen(offset.id, BitWidth::I64); + self.widen(value.id, BitWidth::I256); + } + + Statement::MStore8 { offset, value, .. } => { + self.widen(offset.id, BitWidth::I64); + self.widen(value.id, BitWidth::I8); + } + + Statement::SStore { key, value, .. } => { + self.widen(key.id, BitWidth::I256); + self.widen(value.id, BitWidth::I256); + } + + Statement::TStore { key, value } => { + self.widen(key.id, BitWidth::I256); + self.widen(value.id, BitWidth::I256); + } + + Statement::MappingSStore { key, slot, value } => { + self.widen(key.id, BitWidth::I256); + self.widen(slot.id, BitWidth::I256); + self.widen(value.id, BitWidth::I256); + } + + Statement::If { + condition, + then_region, + else_region, + outputs, + .. + } => { + self.widen(condition.id, BitWidth::I1); + self.infer_region_forward(then_region); + if let Some(else_region) = else_region { + self.infer_region_forward(else_region); + } + + for region in std::iter::once(then_region).chain(else_region.as_ref()) { + for (yield_val, output) in region.yields.iter().zip(outputs.iter()) { + let yield_constraint = self.get(yield_val.id); + self.widen(*output, yield_constraint.min_width); + } + } + } + + Statement::Switch { + scrutinee, + cases, + default, + outputs, + .. + } => { + self.widen(scrutinee.id, BitWidth::I64); + for case in cases { + self.infer_region_forward(&case.body); + for (yield_val, output) in case.body.yields.iter().zip(outputs.iter()) { + let yield_constraint = self.get(yield_val.id); + self.widen(*output, yield_constraint.min_width); + } + } + if let Some(default) = default { + self.infer_region_forward(default); + for (yield_val, output) in default.yields.iter().zip(outputs.iter()) { + let yield_constraint = self.get(yield_val.id); + self.widen(*output, yield_constraint.min_width); + } + } + } + + Statement::For { + loop_variables, + condition, + condition_statements, + body, + post, + post_input_variables, + outputs, + .. + } => { + for loop_var in loop_variables { + self.widen(*loop_var, BitWidth::I256); + } + for post_var in post_input_variables { + self.widen(*post_var, BitWidth::I256); + } + for output in outputs { + self.widen(*output, BitWidth::I256); + } + + for statement in condition_statements { + self.infer_statement_forward(statement); + } + let cond_width = self.infer_expression_width(condition); + let _ = cond_width; + + self.infer_region_forward(body); + self.infer_region_forward(post); + } + + Statement::Revert { offset, length } | Statement::Return { offset, length } => { + self.widen(offset.id, BitWidth::I64); + self.widen(length.id, BitWidth::I64); + } + + Statement::SelfDestruct { address } => { + self.widen(address.id, BitWidth::I160); + } + + Statement::ExternalCall { + gas, + address, + value, + args_offset, + args_length, + ret_offset, + ret_length, + result, + .. + } => { + self.widen(gas.id, BitWidth::I64); + self.widen(address.id, BitWidth::I160); + if let Some(value) = value { + self.widen(value.id, BitWidth::I256); + } + self.widen(args_offset.id, BitWidth::I64); + self.widen(args_length.id, BitWidth::I64); + self.widen(ret_offset.id, BitWidth::I64); + self.widen(ret_length.id, BitWidth::I64); + self.widen(*result, BitWidth::I1); + } + + Statement::Create { + value, + offset, + length, + result, + .. + } => { + self.widen(value.id, BitWidth::I256); + self.widen(offset.id, BitWidth::I64); + self.widen(length.id, BitWidth::I64); + self.widen(*result, BitWidth::I160); + } + + Statement::Log { + offset, + length, + topics, + } => { + self.widen(offset.id, BitWidth::I64); + self.widen(length.id, BitWidth::I64); + for topic in topics { + self.widen(topic.id, BitWidth::I256); + } + } + + Statement::CodeCopy { + dest, + offset, + length, + } + | Statement::ExtCodeCopy { + dest, + offset, + length, + .. + } + | Statement::ReturnDataCopy { + dest, + offset, + length, + } + | Statement::DataCopy { + dest, + offset, + length, + } + | Statement::CallDataCopy { + dest, + offset, + length, + } => { + self.widen(dest.id, BitWidth::I64); + self.widen(offset.id, BitWidth::I64); + self.widen(length.id, BitWidth::I64); + } + + Statement::MCopy { dest, src, length } => { + self.widen(dest.id, BitWidth::I64); + self.widen(src.id, BitWidth::I64); + self.widen(length.id, BitWidth::I64); + } + + Statement::Block(region) => { + self.infer_region_forward(region); + } + + Statement::Expression(expression) => { + let _ = self.infer_expression_width(expression); + } + + Statement::Break { .. } + | Statement::Continue { .. } + | Statement::Leave { .. } + | Statement::Stop + | Statement::Invalid + | Statement::PanicRevert { .. } + | Statement::ErrorStringRevert { .. } + | Statement::CustomErrorRevert { .. } => {} + + Statement::SetImmutable { value, .. } => { + self.widen(value.id, BitWidth::I256); + } + } + } + + /// Infers the minimum bit width for an expression result. + fn infer_expression_width(&mut self, expression: &Expression) -> BitWidth { + match expression { + Expression::Literal { value, .. } => BitWidth::from_max_value(value), + + Expression::Var(id) => self.get(*id).min_width, + + Expression::Binary { + operation, + lhs, + rhs, + } => { + let lhs_width = self.get(lhs.id).min_width; + let rhs_width = self.get(rhs.id).min_width; + + let capped_operand_width = lhs_width.max(rhs_width).min(BitWidth::I64); + + match operation { + BinaryOperation::Add => { + self.widen(lhs.id, capped_operand_width); + self.widen(rhs.id, capped_operand_width); + widen_by_one(lhs_width.max(rhs_width)) + } + BinaryOperation::Sub => BitWidth::I256, + BinaryOperation::Mul => { + self.widen(lhs.id, capped_operand_width); + self.widen(rhs.id, capped_operand_width); + double_width(lhs_width.max(rhs_width)) + } + BinaryOperation::Div + | BinaryOperation::SDiv + | BinaryOperation::Mod + | BinaryOperation::SMod => lhs_width, + BinaryOperation::Exp => BitWidth::I256, + + BinaryOperation::And => lhs_width.min(rhs_width), + BinaryOperation::Or | BinaryOperation::Xor => { + self.widen(lhs.id, capped_operand_width); + self.widen(rhs.id, capped_operand_width); + lhs_width.max(rhs_width) + } + + BinaryOperation::Shl => BitWidth::I256, + BinaryOperation::Shr | BinaryOperation::Sar => { + if let Some(&shift) = self.known_constants.get(&lhs.id.0) { + if shift >= 256 { + BitWidth::I1 + } else { + let remaining = 256u64.saturating_sub(shift); + BitWidth::from_bits(remaining.max(1) as u32) + } + } else { + rhs_width + } + } + + BinaryOperation::Lt + | BinaryOperation::Gt + | BinaryOperation::Slt + | BinaryOperation::Sgt + | BinaryOperation::Eq => { + if matches!(operation, BinaryOperation::Slt | BinaryOperation::Sgt) { + self.mark_signed(lhs.id); + self.mark_signed(rhs.id); + } + BitWidth::I1 + } + + BinaryOperation::Byte => BitWidth::I8, + + BinaryOperation::SignExtend => BitWidth::I256, + + BinaryOperation::AddMod | BinaryOperation::MulMod => BitWidth::I256, + } + } + + Expression::Ternary { operation, .. } => match operation { + BinaryOperation::AddMod | BinaryOperation::MulMod => BitWidth::I256, + _ => BitWidth::I256, + }, + + Expression::Unary { operation, operand } => match operation { + crate::ir::UnaryOperation::IsZero => BitWidth::I1, + crate::ir::UnaryOperation::Not => { + let _ = operand; + BitWidth::I256 + } + crate::ir::UnaryOperation::Clz => BitWidth::I256, + }, + + Expression::CallDataLoad { offset } => { + self.widen(offset.id, BitWidth::I256); + BitWidth::I256 + } + Expression::CallValue => BitWidth::I256, + Expression::Caller | Expression::Origin | Expression::Address => BitWidth::I160, + Expression::CallDataSize + | Expression::CodeSize + | Expression::ReturnDataSize + | Expression::MSize => BitWidth::I64, + Expression::GasPrice => BitWidth::I256, + Expression::ExtCodeSize { address } => { + self.widen(address.id, BitWidth::I160); + BitWidth::I64 + } + Expression::ExtCodeHash { address } => { + self.widen(address.id, BitWidth::I160); + BitWidth::I256 + } + Expression::BlockHash { number } => { + self.widen(number.id, BitWidth::I64); + BitWidth::I256 + } + Expression::Coinbase => BitWidth::I160, + Expression::Timestamp | Expression::Number | Expression::GasLimit | Expression::Gas => { + BitWidth::I64 + } + Expression::Difficulty | Expression::ChainId | Expression::BaseFee => BitWidth::I256, + Expression::SelfBalance | Expression::BlobBaseFee => BitWidth::I256, + Expression::BlobHash { index } => { + self.widen(index.id, BitWidth::I64); + BitWidth::I256 + } + Expression::Balance { address } => { + self.widen(address.id, BitWidth::I160); + BitWidth::I256 + } + + Expression::MLoad { offset, region } => { + self.widen(offset.id, BitWidth::I64); + if *region == MemoryRegion::FreePointerSlot { + BitWidth::I32 + } else { + BitWidth::I256 + } + } + Expression::SLoad { key, .. } => { + self.widen(key.id, BitWidth::I256); + BitWidth::I256 + } + Expression::TLoad { key } => { + self.widen(key.id, BitWidth::I256); + BitWidth::I256 + } + + Expression::Call { + function, + arguments: _, + } => { + if let Some(ret_ids) = self.function_returns.get(&function.0).cloned() { + let mut max_ret_width = BitWidth::I1; + for ret_id in &ret_ids { + let ret_width = self.get(*ret_id).min_width; + max_ret_width = max_ret_width.max(ret_width); + } + if max_ret_width > BitWidth::I1 { + max_ret_width + } else { + BitWidth::I256 + } + } else { + BitWidth::I256 + } + } + + Expression::Truncate { to, .. } => *to, + Expression::ZeroExtend { to, .. } => *to, + Expression::SignExtendTo { to, .. } => *to, + + Expression::Keccak256 { offset, length } => { + self.widen(offset.id, BitWidth::I64); + self.widen(length.id, BitWidth::I64); + BitWidth::I256 + } + + Expression::Keccak256Pair { .. } + | Expression::Keccak256Single { .. } + | Expression::MappingSLoad { .. } => BitWidth::I256, + + Expression::DataOffset { .. } => BitWidth::I256, + Expression::DataSize { .. } => BitWidth::I64, + + Expression::LoadImmutable { .. } => BitWidth::I256, + + Expression::LinkerSymbol { .. } => BitWidth::I160, + } + } + + /// Returns the inferred type for a value. + pub fn inferred_type(&self, id: ValueId) -> Type { + let constraint = self.get(id); + Type::Int(constraint.min_width) + } + + /// Returns all constraints. + pub fn constraints(&self) -> &BTreeMap { + &self.constraints + } +} + +impl Default for TypeInference { + fn default() -> Self { + Self::new() + } +} + +/// Widens a bit width by one level (e.g., I8 -> I32). +pub fn widen_by_one(width: BitWidth) -> BitWidth { + match width { + BitWidth::I1 => BitWidth::I8, + BitWidth::I8 => BitWidth::I32, + BitWidth::I32 => BitWidth::I64, + BitWidth::I64 => BitWidth::I128, + BitWidth::I128 => BitWidth::I160, + BitWidth::I160 => BitWidth::I256, + BitWidth::I256 => BitWidth::I256, + } +} + +/// Doubles a bit width (e.g., I32 -> I64). +pub fn double_width(width: BitWidth) -> BitWidth { + match width { + BitWidth::I1 => BitWidth::I8, + BitWidth::I8 => BitWidth::I32, + BitWidth::I32 => BitWidth::I64, + BitWidth::I64 => BitWidth::I128, + BitWidth::I128 => BitWidth::I256, + BitWidth::I160 => BitWidth::I256, + BitWidth::I256 => BitWidth::I256, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use num::BigUint; + + #[test] + fn test_literal_width_inference() { + let mut inference = TypeInference::new(); + + let expression = Expression::Literal { + value: BigUint::from(42u32), + value_type: Type::default(), + }; + let width = inference.infer_expression_width(&expression); + assert_eq!(width, BitWidth::I8); + + let expression = Expression::Literal { + value: BigUint::from(1u128) << 100, + value_type: Type::default(), + }; + let width = inference.infer_expression_width(&expression); + assert_eq!(width, BitWidth::I128); + + let expression = Expression::Literal { + value: BigUint::from(1u128) << 140, + value_type: Type::default(), + }; + let width = inference.infer_expression_width(&expression); + assert_eq!(width, BitWidth::I160); + } + + #[test] + fn test_comparison_returns_boolean() { + let mut inference = TypeInference::new(); + + inference.widen(ValueId(0), BitWidth::I64); + inference.widen(ValueId(1), BitWidth::I64); + + let expression = Expression::Binary { + operation: BinaryOperation::Lt, + lhs: crate::ir::Value::new(ValueId(0), Type::Int(BitWidth::I64)), + rhs: crate::ir::Value::new(ValueId(1), Type::Int(BitWidth::I64)), + }; + let width = inference.infer_expression_width(&expression); + assert_eq!(width, BitWidth::I1); + } + + #[test] + fn test_constraint_join() { + let c1 = TypeConstraint::with_width(BitWidth::I32); + let c2 = TypeConstraint::signed(BitWidth::I64); + let joined = c1.join(&c2); + assert_eq!(joined.min_width, BitWidth::I64); + assert!(joined.is_signed); + } +} diff --git a/crates/newyork/src/validate.rs b/crates/newyork/src/validate.rs new file mode 100644 index 000000000..07bef3b05 --- /dev/null +++ b/crates/newyork/src/validate.rs @@ -0,0 +1,878 @@ +//! IR validation passes for the newyork IR. +//! +//! This module provides validation passes to verify IR correctness: +//! - SSA well-formedness: All uses are dominated by definitions +//! - Type consistency: Operations have correctly typed operands +//! - Region validity: All regions have correct yields matching outputs +//! +//! # Usage +//! +//! ```ignore +//! use revive_newyork::validate::{validate_object, ValidationError}; +//! +//! let result = validate_object(&ir_object); +//! if let Err(errors) = result { +//! for error in errors { +//! eprintln!("Validation error: {}", error); +//! } +//! } +//! ``` + +use crate::ir::{Block, Expression, Function, Object, Region, Statement, Value, ValueId}; +use std::collections::BTreeSet; +use thiserror::Error; + +/// Validation error types. +#[derive(Error, Debug, Clone)] +pub enum ValidationError { + /// A value is used before it is defined. + #[error("SSA error: value v{0} used before definition at {1}")] + UseBeforeDef(u32, String), + + /// A value is defined multiple times. + #[error("SSA error: value v{0} defined multiple times")] + MultipleDef(u32), + + /// Type mismatch in an operation. + #[error("Type error: {0}")] + TypeMismatch(String), + + /// Region yields wrong number of values. + #[error("Region error: expected {expected} yields, got {actual} at {location}")] + YieldCountMismatch { + expected: usize, + actual: usize, + location: String, + }, + + /// Function has inconsistent return value count. + #[error("Function error: {0}")] + FunctionError(String), + + /// Unknown function called. + #[error("Unknown function: f{0}")] + UnknownFunction(u32), +} + +/// Result of validation. +pub type ValidationResult = Result<(), Vec>; + +/// Validates an IR object, returning all errors found. +pub fn validate_object(object: &Object) -> ValidationResult { + let mut validator = Validator::new(); + validator.validate_object(object); + validator.into_result() +} + +/// Validates a single function. +pub fn validate_function(function: &Function) -> ValidationResult { + let mut validator = Validator::new(); + validator.validate_function(function); + validator.into_result() +} + +/// Internal validator state. +struct Validator { + /// Set of defined value IDs (visible in current scope). + defined: BTreeSet, + /// Stack of defined sets for scope management. + scope_stack: Vec>, + /// Set of known function IDs. + known_functions: BTreeSet, + /// Collected errors. + errors: Vec, +} + +impl Validator { + fn new() -> Self { + Validator { + defined: BTreeSet::new(), + scope_stack: Vec::new(), + known_functions: BTreeSet::new(), + errors: Vec::new(), + } + } + + fn into_result(self) -> ValidationResult { + if self.errors.is_empty() { + Ok(()) + } else { + Err(self.errors) + } + } + + fn error(&mut self, err: ValidationError) { + self.errors.push(err); + } + + fn enter_scope(&mut self) { + self.scope_stack.push(self.defined.clone()); + } + + fn exit_scope(&mut self) { + if let Some(saved) = self.scope_stack.pop() { + self.defined = saved; + } + } + + fn define(&mut self, id: ValueId) { + if !self.defined.insert(id.0) { + self.error(ValidationError::MultipleDef(id.0)); + } + } + + fn use_value(&mut self, value: &Value, context: &str) { + self.use_value_id(value.id, context); + } + + fn use_value_id(&mut self, id: ValueId, context: &str) { + if !self.defined.contains(&id.0) { + self.error(ValidationError::UseBeforeDef(id.0, context.to_string())); + } + } + + fn validate_object(&mut self, object: &Object) { + for id in object.functions.keys() { + self.known_functions.insert(id.0); + } + + self.validate_block(&object.code, &format!("object '{}' code", object.name)); + + for function in object.functions.values() { + self.validate_function(function); + } + + // Subobjects compile to separate units with their own SSA ID and function-ID + // namespaces — they share no values or callables with the parent. Validate each + // with a fresh validator so the parent's defined IDs don't leak in and produce + // spurious MultipleDef errors when the subobject reuses the same value numbers. + for subobject in &object.subobjects { + if let Err(sub_errors) = validate_object(subobject) { + self.errors.extend(sub_errors); + } + } + } + + fn validate_function(&mut self, function: &Function) { + self.enter_scope(); + + for (id, _ty) in &function.parameters { + self.define(*id); + } + + for id in &function.return_values_initial { + self.define(*id); + } + + if function.returns.len() != function.return_values_initial.len() { + self.error(ValidationError::FunctionError(format!( + "function '{}': returns count ({}) != return_values_initial count ({})", + function.name, + function.returns.len(), + function.return_values_initial.len() + ))); + } + + if function.returns.len() != function.return_values.len() { + self.error(ValidationError::FunctionError(format!( + "function '{}': returns count ({}) != return_values count ({})", + function.name, + function.returns.len(), + function.return_values.len() + ))); + } + + self.validate_block(&function.body, &format!("function '{}'", function.name)); + + for id in &function.return_values { + self.use_value_id(*id, &format!("function '{}' return", function.name)); + } + + self.exit_scope(); + } + + fn validate_block(&mut self, block: &Block, context: &str) { + for (i, statement) in block.statements.iter().enumerate() { + self.validate_statement(statement, &format!("{}[{}]", context, i)); + } + } + + fn validate_region(&mut self, region: &Region, context: &str) { + for (i, statement) in region.statements.iter().enumerate() { + self.validate_statement(statement, &format!("{}[{}]", context, i)); + } + + for value in ®ion.yields { + self.use_value(value, &format!("{} yield", context)); + } + } + + fn validate_statement(&mut self, statement: &Statement, context: &str) { + match statement { + Statement::Let { bindings, value } => { + self.validate_expression(value, context); + + for id in bindings { + self.define(*id); + } + } + + Statement::MStore { + offset, value: v, .. + } => { + self.use_value(offset, context); + self.use_value(v, context); + } + + Statement::MStore8 { + offset, value: v, .. + } => { + self.use_value(offset, context); + self.use_value(v, context); + } + + Statement::MCopy { dest, src, length } => { + self.use_value(dest, context); + self.use_value(src, context); + self.use_value(length, context); + } + + Statement::SStore { key, value: v, .. } => { + self.use_value(key, context); + self.use_value(v, context); + } + + Statement::TStore { key, value: v } => { + self.use_value(key, context); + self.use_value(v, context); + } + + Statement::MappingSStore { + key, + slot, + value: v, + } => { + self.use_value(key, context); + self.use_value(slot, context); + self.use_value(v, context); + } + + Statement::If { + condition, + inputs, + then_region, + else_region, + outputs, + } => { + self.use_value(condition, context); + for v in inputs { + self.use_value(v, context); + } + + self.enter_scope(); + self.validate_region(then_region, &format!("{} then", context)); + let then_yield_count = then_region.yields.len(); + self.exit_scope(); + + let else_yield_count = if let Some(else_region) = else_region { + self.enter_scope(); + self.validate_region(else_region, &format!("{} else", context)); + let count = else_region.yields.len(); + self.exit_scope(); + count + } else { + inputs.len() + }; + + if outputs.len() != then_yield_count { + self.error(ValidationError::YieldCountMismatch { + expected: outputs.len(), + actual: then_yield_count, + location: format!("{} then", context), + }); + } + + if outputs.len() != else_yield_count { + self.error(ValidationError::YieldCountMismatch { + expected: outputs.len(), + actual: else_yield_count, + location: format!("{} else", context), + }); + } + + for id in outputs { + self.define(*id); + } + } + + Statement::Switch { + scrutinee, + inputs, + cases, + default, + outputs, + } => { + self.use_value(scrutinee, context); + for v in inputs { + self.use_value(v, context); + } + + for (i, case) in cases.iter().enumerate() { + self.enter_scope(); + self.validate_region(&case.body, &format!("{} case[{}]", context, i)); + + if outputs.len() != case.body.yields.len() { + self.error(ValidationError::YieldCountMismatch { + expected: outputs.len(), + actual: case.body.yields.len(), + location: format!("{} case[{}]", context, i), + }); + } + self.exit_scope(); + } + + if let Some(default_region) = default { + self.enter_scope(); + self.validate_region(default_region, &format!("{} default", context)); + + if outputs.len() != default_region.yields.len() { + self.error(ValidationError::YieldCountMismatch { + expected: outputs.len(), + actual: default_region.yields.len(), + location: format!("{} default", context), + }); + } + self.exit_scope(); + } + + for id in outputs { + self.define(*id); + } + } + + Statement::For { + initial_values, + loop_variables, + condition_statements, + condition, + body, + post_input_variables, + post, + outputs, + } => { + for v in initial_values { + self.use_value(v, context); + } + + if loop_variables.len() != initial_values.len() { + self.error(ValidationError::FunctionError(format!( + "{}: loop_variables count ({}) != initial_values count ({})", + context, + loop_variables.len(), + initial_values.len() + ))); + } + + if post_input_variables.len() != loop_variables.len() { + self.error(ValidationError::FunctionError(format!( + "{}: post_input_variables count ({}) != loop_variables count ({})", + context, + post_input_variables.len(), + loop_variables.len() + ))); + } + + self.enter_scope(); + for id in loop_variables { + self.define(*id); + } + + for (i, statement) in condition_statements.iter().enumerate() { + self.validate_statement(statement, &format!("{} cond_stmt[{}]", context, i)); + } + + self.validate_expression(condition, &format!("{} condition", context)); + + self.validate_region(body, &format!("{} body", context)); + + for id in post_input_variables { + self.define(*id); + } + + self.validate_region(post, &format!("{} post", context)); + + if loop_variables.len() != post.yields.len() { + self.error(ValidationError::YieldCountMismatch { + expected: loop_variables.len(), + actual: post.yields.len(), + location: format!("{} post", context), + }); + } + + self.exit_scope(); + + if outputs.len() != loop_variables.len() { + self.error(ValidationError::FunctionError(format!( + "{}: outputs count ({}) != loop_variables count ({})", + context, + outputs.len(), + loop_variables.len() + ))); + } + + for id in outputs { + self.define(*id); + } + } + + Statement::Break { values } | Statement::Continue { values } => { + for v in values { + self.use_value(v, context); + } + } + + Statement::Leave { return_values } => { + for v in return_values { + self.use_value(v, context); + } + } + + Statement::Revert { offset, length } => { + self.use_value(offset, context); + self.use_value(length, context); + } + + Statement::Return { offset, length } => { + self.use_value(offset, context); + self.use_value(length, context); + } + + Statement::Stop + | Statement::Invalid + | Statement::PanicRevert { .. } + | Statement::ErrorStringRevert { .. } + | Statement::CustomErrorRevert { .. } => {} + + Statement::SelfDestruct { address } => { + self.use_value(address, context); + } + + Statement::ExternalCall { + gas, + address, + value, + args_offset, + args_length, + ret_offset, + ret_length, + result, + .. + } => { + self.use_value(gas, context); + self.use_value(address, context); + if let Some(v) = value { + self.use_value(v, context); + } + self.use_value(args_offset, context); + self.use_value(args_length, context); + self.use_value(ret_offset, context); + self.use_value(ret_length, context); + self.define(*result); + } + + Statement::Create { + value, + offset, + length, + salt, + result, + .. + } => { + self.use_value(value, context); + self.use_value(offset, context); + self.use_value(length, context); + if let Some(s) = salt { + self.use_value(s, context); + } + self.define(*result); + } + + Statement::Log { + offset, + length, + topics, + } => { + self.use_value(offset, context); + self.use_value(length, context); + for t in topics { + self.use_value(t, context); + } + } + + Statement::CodeCopy { + dest, + offset, + length, + } => { + self.use_value(dest, context); + self.use_value(offset, context); + self.use_value(length, context); + } + + Statement::ExtCodeCopy { + address, + dest, + offset, + length, + } => { + self.use_value(address, context); + self.use_value(dest, context); + self.use_value(offset, context); + self.use_value(length, context); + } + + Statement::ReturnDataCopy { + dest, + offset, + length, + } => { + self.use_value(dest, context); + self.use_value(offset, context); + self.use_value(length, context); + } + + Statement::DataCopy { + dest, + offset, + length, + } => { + self.use_value(dest, context); + self.use_value(offset, context); + self.use_value(length, context); + } + + Statement::CallDataCopy { + dest, + offset, + length, + } => { + self.use_value(dest, context); + self.use_value(offset, context); + self.use_value(length, context); + } + + Statement::Block(region) => { + // A standalone `Statement::Block` is straight-line code in the codegen + // (no LLVM-level scoping, no phi merge — `generate_region` just lowers + // the statements). SSA values defined inside flow through to the + // surrounding scope, matching `Statement::For`/`If`/`Switch` which DO + // scope-isolate because their regions form control-flow splits. + self.validate_region(region, context); + } + + Statement::Expression(expression) => { + self.validate_expression(expression, context); + } + + Statement::SetImmutable { value, .. } => { + self.use_value(value, context); + } + } + } + + fn validate_expression(&mut self, expression: &Expression, context: &str) { + match expression { + Expression::Literal { .. } => {} + + Expression::Var(id) => { + self.use_value_id(*id, context); + } + + Expression::Binary { lhs, rhs, .. } => { + self.use_value(lhs, context); + self.use_value(rhs, context); + } + + Expression::Ternary { a, b, n, .. } => { + self.use_value(a, context); + self.use_value(b, context); + self.use_value(n, context); + } + + Expression::Unary { operand, .. } => { + self.use_value(operand, context); + } + + Expression::CallDataLoad { offset } => { + self.use_value(offset, context); + } + + Expression::CallValue + | Expression::Caller + | Expression::Origin + | Expression::CallDataSize + | Expression::CodeSize + | Expression::GasPrice + | Expression::ReturnDataSize + | Expression::Coinbase + | Expression::Timestamp + | Expression::Number + | Expression::Difficulty + | Expression::GasLimit + | Expression::ChainId + | Expression::SelfBalance + | Expression::BaseFee + | Expression::BlobBaseFee + | Expression::Gas + | Expression::MSize + | Expression::Address => {} + + Expression::ExtCodeSize { address } => { + self.use_value(address, context); + } + + Expression::ExtCodeHash { address } => { + self.use_value(address, context); + } + + Expression::BlockHash { number } => { + self.use_value(number, context); + } + + Expression::BlobHash { index } => { + self.use_value(index, context); + } + + Expression::Balance { address } => { + self.use_value(address, context); + } + + Expression::MLoad { offset, .. } => { + self.use_value(offset, context); + } + + Expression::SLoad { key, .. } => { + self.use_value(key, context); + } + + Expression::TLoad { key } => { + self.use_value(key, context); + } + + Expression::Call { + function, + arguments, + } => { + if !self.known_functions.contains(&function.0) { + self.error(ValidationError::UnknownFunction(function.0)); + } + for argument in arguments { + self.use_value(argument, context); + } + } + + Expression::Truncate { value, .. } + | Expression::ZeroExtend { value, .. } + | Expression::SignExtendTo { value, .. } => { + self.use_value(value, context); + } + + Expression::Keccak256 { offset, length } => { + self.use_value(offset, context); + self.use_value(length, context); + } + + Expression::Keccak256Pair { word0, word1 } => { + self.use_value(word0, context); + self.use_value(word1, context); + } + + Expression::Keccak256Single { word0 } => { + self.use_value(word0, context); + } + + Expression::MappingSLoad { key, slot } => { + self.use_value(key, context); + self.use_value(slot, context); + } + + Expression::DataOffset { .. } + | Expression::DataSize { .. } + | Expression::LoadImmutable { .. } + | Expression::LinkerSymbol { .. } => {} + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::ir::{ + BinaryOperation, BitWidth, Block, FunctionId, Object, Region, Statement, Type, Value, + ValueId, + }; + use num::BigUint; + use std::collections::BTreeMap; + + fn int_value(id: u32) -> Value { + Value::int(ValueId(id)) + } + + #[test] + fn test_valid_let() { + let object = Object { + name: "Test".to_string(), + code: Block { + statements: vec![ + Statement::Let { + bindings: vec![ValueId(0)], + value: Expression::Literal { + value: BigUint::from(0u64), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::Let { + bindings: vec![ValueId(1)], + value: Expression::Var(ValueId(0)), + }, + ], + }, + functions: BTreeMap::new(), + subobjects: Vec::new(), + data: BTreeMap::new(), + }; + assert!(validate_object(&object).is_ok()); + } + + #[test] + fn test_use_before_def() { + let object = Object { + name: "Test".to_string(), + code: Block { + statements: vec![Statement::Let { + bindings: vec![ValueId(1)], + value: Expression::Var(ValueId(0)), + }], + }, + functions: BTreeMap::new(), + subobjects: Vec::new(), + data: BTreeMap::new(), + }; + let result = validate_object(&object); + assert!(result.is_err()); + let errors = result.unwrap_err(); + assert!(errors + .iter() + .any(|e| matches!(e, ValidationError::UseBeforeDef(0, _)))); + } + + #[test] + fn test_if_yield_mismatch() { + let object = Object { + name: "Test".to_string(), + code: Block { + statements: vec![ + Statement::Let { + bindings: vec![ValueId(0)], + value: Expression::Literal { + value: BigUint::from(1u64), + value_type: Type::Int(BitWidth::I256), + }, + }, + Statement::If { + condition: int_value(0), + inputs: vec![], + then_region: Region { + statements: vec![], + yields: vec![int_value(0)], + }, + else_region: Some(Region { + statements: vec![], + yields: vec![], + }), + outputs: vec![ValueId(1)], + }, + ], + }, + functions: BTreeMap::new(), + subobjects: Vec::new(), + data: BTreeMap::new(), + }; + let result = validate_object(&object); + assert!(result.is_err()); + let errors = result.unwrap_err(); + assert!(errors + .iter() + .any(|e| matches!(e, ValidationError::YieldCountMismatch { .. }))); + } + + #[test] + fn test_valid_function() { + let mut functions = BTreeMap::new(); + functions.insert( + FunctionId(0), + Function { + id: FunctionId(0), + name: "add_one".to_string(), + parameters: vec![(ValueId(0), Type::Int(BitWidth::I256))], + returns: vec![Type::Int(BitWidth::I256)], + return_values_initial: vec![ValueId(1)], + return_values: vec![ValueId(2)], + body: Block { + statements: vec![Statement::Let { + bindings: vec![ValueId(2)], + value: Expression::Binary { + operation: BinaryOperation::Add, + lhs: int_value(0), + rhs: int_value(1), + }, + }], + }, + call_count: 0, + size_estimate: 0, + }, + ); + + let object = Object { + name: "Test".to_string(), + code: Block { statements: vec![] }, + functions, + subobjects: Vec::new(), + data: BTreeMap::new(), + }; + assert!(validate_object(&object).is_ok()); + } + + #[test] + fn test_function_return_count_mismatch() { + let mut functions = BTreeMap::new(); + functions.insert( + FunctionId(0), + Function { + id: FunctionId(0), + name: "bad".to_string(), + parameters: vec![], + returns: vec![Type::Int(BitWidth::I256), Type::Int(BitWidth::I256)], + return_values_initial: vec![ValueId(0)], + return_values: vec![ValueId(0)], + body: Block { statements: vec![] }, + call_count: 0, + size_estimate: 0, + }, + ); + + let object = Object { + name: "Test".to_string(), + code: Block { statements: vec![] }, + functions, + subobjects: Vec::new(), + data: BTreeMap::new(), + }; + let result = validate_object(&object); + assert!(result.is_err()); + let errors = result.unwrap_err(); + assert!(errors + .iter() + .any(|e| matches!(e, ValidationError::FunctionError(_)))); + } +} diff --git a/crates/resolc/Cargo.toml b/crates/resolc/Cargo.toml index dbecf6f2e..ac72f6fc1 100644 --- a/crates/resolc/Cargo.toml +++ b/crates/resolc/Cargo.toml @@ -33,6 +33,7 @@ normpath = { workspace = true } revive-common = { workspace = true } revive-llvm-context = { workspace = true } +revive-newyork = { workspace = true } revive-solc-json-interface = { workspace = true, features = ["resolc"] } revive-yul = { workspace = true } diff --git a/crates/resolc/src/lib.rs b/crates/resolc/src/lib.rs index 3007e1523..30325eeef 100644 --- a/crates/resolc/src/lib.rs +++ b/crates/resolc/src/lib.rs @@ -71,7 +71,46 @@ pub(crate) mod version; /// The rayon worker stack size. pub const RAYON_WORKER_STACK_SIZE: usize = 64 * 1024 * 1024; +/// Environment variable: when set to `"1"`, routes Yul lowering through the newyork IR +/// pipeline instead of the default `solc`/Yul path. Equivalent to passing `--newyork` +/// on the command line; the CLI flag and the env var are OR-ed by +/// [`resolve_use_newyork`]. +pub const RESOLC_USE_NEWYORK_ENV: &str = "RESOLC_USE_NEWYORK"; + +/// Returns whether the newyork IR pipeline should be used. +/// +/// The newyork pipeline is enabled if either the `--newyork` CLI flag is set +/// (passed in as `cli_flag`) or the [`RESOLC_USE_NEWYORK_ENV`] env var is set +/// to `"1"`. This is the single resolution point for the flag — every entry +/// point in this module takes a `use_newyork: bool` that callers compute via +/// this helper. +pub fn resolve_use_newyork(cli_flag: bool) -> bool { + cli_flag + || std::env::var(RESOLC_USE_NEWYORK_ENV) + .map(|value| value == "1") + .unwrap_or(false) +} + +/// Environment variable: when set, dumps compiled blobs and metadata for newyork +/// investigations (test harness only). +pub const RESOLC_DEBUG_BLOB_ENV: &str = "RESOLC_DEBUG_BLOB"; + +/// Environment variable: when set, prints the translated newyork IR for every compiled +/// object to stderr and `/tmp/newyork_ir_.txt`. +pub const RESOLC_DEBUG_IR_ENV: &str = "RESOLC_DEBUG_IR"; + +/// Environment variable: when set, appends the heap-optimization analysis result for +/// every compiled object to `/tmp/resolc_heap_debug.log`. +pub const RESOLC_DEBUG_HEAP_ENV: &str = "RESOLC_DEBUG_HEAP"; + +/// Environment variable: when set, appends the memory-optimization statistics for +/// every compiled object to a `resolc_mem_debug.log` file in the debug output directory. +pub const RESOLC_DEBUG_MEM_ENV: &str = "RESOLC_DEBUG_MEM"; + /// Runs the Yul mode. +/// +/// When `use_newyork` is `true`, each Yul source is routed through the newyork IR +/// pipeline instead of the direct Yul-to-LLVM path. pub fn yul( solc: &T, input_files: &[PathBuf], @@ -82,13 +121,15 @@ pub fn yul( debug_config: DebugConfig, llvm_arguments: &[String], memory_config: SolcStandardJsonInputSettingsPolkaVMMemory, + use_newyork: bool, ) -> anyhow::Result { let libraries = SolcStandardJsonInputSettingsLibraries::try_from(libraries)?; let solc_output = solc.validate_yul_paths(input_files, libraries.clone(), messages)?; solc_output.exit_on_error(); let linker_symbols = libraries.as_linker_symbols()?; - let project = Project::try_from_yul_paths(input_files, None, libraries, &debug_config)?; + let project = + Project::try_from_yul_paths(input_files, None, libraries, &debug_config, use_newyork)?; let mut build = project.compile( messages, optimizer_settings, @@ -107,6 +148,8 @@ pub fn yul( } /// Runs the standard output mode. +/// +/// See [`yul`] for the meaning of `use_newyork`. pub fn standard_output( solc: &T, input_files: &[PathBuf], @@ -124,6 +167,7 @@ pub fn standard_output( debug_config: DebugConfig, llvm_arguments: Vec, memory_config: SolcStandardJsonInputSettingsPolkaVMMemory, + use_newyork: bool, ) -> anyhow::Result { let solc_version = solc.version()?; let mut solc_input = SolcStandardJsonInput::try_from_solidity_paths( @@ -163,6 +207,7 @@ pub fn standard_output( solc_input.settings.libraries, &solc_version, &debug_config, + use_newyork, )?; solc_output.take_and_write_warnings(); solc_output.check_errors()?; @@ -186,6 +231,8 @@ pub fn standard_output( } /// Runs the standard JSON mode. +/// +/// See [`yul`] for the meaning of `use_newyork`. pub fn standard_json( solc: &T, metadata_hash: MetadataHash, @@ -196,6 +243,7 @@ pub fn standard_json( allow_paths: Option, mut debug_config: DebugConfig, detect_missing_libraries: bool, + use_newyork: bool, ) -> anyhow::Result<()> { let solc_version = solc.version()?; let mut solc_input = SolcStandardJsonInput::try_from(json_path.as_deref())?; @@ -239,6 +287,7 @@ pub fn standard_json( solc_input.settings.libraries, &solc_version, &debug_config, + use_newyork, )?; if solc_output.has_errors() { @@ -274,6 +323,8 @@ pub fn standard_json( } /// Runs the combined JSON mode. +/// +/// See [`yul`] for the meaning of `use_newyork`. pub fn combined_json( solc: &T, paths: &[PathBuf], @@ -294,6 +345,7 @@ pub fn combined_json( overwrite: bool, llvm_arguments: Vec, memory_config: SolcStandardJsonInputSettingsPolkaVMMemory, + use_newyork: bool, ) -> anyhow::Result<()> { let selectors = CombinedJsonSelector::from_cli(format.as_str()) .into_iter() @@ -342,6 +394,7 @@ pub fn combined_json( debug_config, llvm_arguments, memory_config, + use_newyork, )? .write_to_combined_json(&mut combined_json)?; diff --git a/crates/resolc/src/project/contract/ir/mod.rs b/crates/resolc/src/project/contract/ir/mod.rs index 7c358f1db..8a9beafef 100644 --- a/crates/resolc/src/project/contract/ir/mod.rs +++ b/crates/resolc/src/project/contract/ir/mod.rs @@ -5,8 +5,10 @@ use std::collections::BTreeSet; use serde::Deserialize; use serde::Serialize; +use self::newyork::NewYork; use self::yul::Yul; +pub mod newyork; pub mod yul; /// The contract source code. @@ -15,6 +17,8 @@ pub mod yul; pub enum IR { /// The Yul source code. Yul(Yul), + /// The newyork IR (via Yul translation). + NewYork(NewYork), } impl IR { @@ -22,6 +26,9 @@ impl IR { pub fn drain_factory_dependencies(&mut self) -> BTreeSet { match self { IR::Yul(ref mut yul) => yul.object.factory_dependencies.drain().collect(), + IR::NewYork(ref mut newyork) => { + newyork.yul_object.factory_dependencies.drain().collect() + } } } @@ -29,6 +36,7 @@ impl IR { pub fn get_missing_libraries(&self) -> BTreeSet { match self { Self::Yul(inner) => inner.get_missing_libraries(), + Self::NewYork(inner) => inner.get_missing_libraries(), } } } @@ -38,3 +46,9 @@ impl From for IR { Self::Yul(inner) } } + +impl From for IR { + fn from(inner: NewYork) -> Self { + Self::NewYork(inner) + } +} diff --git a/crates/resolc/src/project/contract/ir/newyork.rs b/crates/resolc/src/project/contract/ir/newyork.rs new file mode 100644 index 000000000..f6734aedb --- /dev/null +++ b/crates/resolc/src/project/contract/ir/newyork.rs @@ -0,0 +1,284 @@ +//! The contract compiled via newyork IR. +//! +//! This module integrates the newyork IR pipeline: +//! 1. Parse Yul source to Yul AST +//! 2. Translate Yul AST to newyork IR +//! 3. Run heap optimization analysis +//! 4. Generate LLVM IR from newyork IR + +use std::collections::BTreeSet; + +use inkwell::debug_info::AsDIScope; +use revive_llvm_context::PolkaVMCodeType; +use revive_newyork::{LlvmCodegen, TranslationResult}; +use revive_yul::lexer::Lexer; +use revive_yul::parser::statement::object::Object as YulObject; +use serde::{Deserialize, Serialize}; + +/// The contract compiled via newyork IR. +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct NewYork { + /// The Yul AST object (source). + pub yul_object: YulObject, +} + +impl NewYork { + /// Transforms the `solc` standard JSON output contract into a Yul object + /// for subsequent translation to newyork IR. + pub fn try_from_source(source_code: &str) -> anyhow::Result> { + if source_code.is_empty() { + return Ok(None); + }; + + let mut lexer = Lexer::new(source_code.to_owned()); + let object = YulObject::parse(&mut lexer, None) + .map_err(|error| anyhow::anyhow!("Yul parsing: {error:?}"))?; + + Ok(Some(Self { yul_object: object })) + } + + /// Get the list of missing deployable libraries. + pub fn get_missing_libraries(&self) -> BTreeSet { + self.yul_object.get_missing_libraries() + } + + /// Translate the Yul AST to newyork IR with heap optimization analysis. + /// + /// `debug_output_directory` is forwarded so the `NEWYORK_DUMP_IR` mid-pipeline IR snapshot is + /// written into `--debug-output-dir` (or skipped when none is configured). + fn translate_to_ir( + &self, + debug_output_directory: Option<&std::path::Path>, + ) -> anyhow::Result { + revive_newyork::translate_yul_object(&self.yul_object, debug_output_directory) + .map_err(|e| anyhow::anyhow!("newyork IR translation: {e}")) + } +} + +/// Code-size threshold for emitting the outlined single-word keccak256 helper. +/// +/// The helper body costs ~150 bytes; each call site it replaces saves ~20 bytes through +/// deduplication. Fewer than this many sites and the helper costs more than it returns. +const KECCAK_SINGLE_THRESHOLD: usize = 8; + +/// Heap-operation threshold above which `__sbrk_internal` is marked NoInline. +/// +/// `__sbrk_internal` has five basic blocks of bounds-checking; inlining it at too many +/// sites bloats the binary beyond the call-overhead savings on PolkaVM. +const SBRK_NOINLINE_THRESHOLD: usize = 30; + +/// File name of the heap-analysis log appended inside the debug output directory +/// when [`crate::RESOLC_DEBUG_HEAP_ENV`] is set. +const HEAP_DEBUG_LOG_FILE: &str = "resolc_heap_debug.log"; + +/// File name of the memory-optimization statistics log appended inside the debug output +/// directory when [`crate::RESOLC_DEBUG_MEM_ENV`] is set. +const MEM_DEBUG_LOG_FILE: &str = "resolc_mem_debug.log"; + +impl revive_llvm_context::PolkaVMWriteLLVM for NewYork { + fn declare(&mut self, context: &mut revive_llvm_context::PolkaVMContext) -> anyhow::Result<()> { + self.yul_object.declare(context)?; + + revive_llvm_context::PolkaVMKeccak256TwoWordsFunction.declare(context)?; + revive_llvm_context::PolkaVMCallValueFunction.declare(context)?; + revive_llvm_context::PolkaVMCallValueNonzeroFunction.declare(context)?; + revive_llvm_context::PolkaVMCallDataLoadFunction.declare(context)?; + revive_llvm_context::PolkaVMCallerFunction.declare(context)?; + revive_llvm_context::PolkaVMRevertEmptyFunction.declare(context)?; + revive_llvm_context::PolkaVMRevertFunction.declare(context)?; + revive_llvm_context::PolkaVMRevertPanicFunction.declare(context)?; + + Ok(()) + } + + fn into_llvm(self, context: &mut revive_llvm_context::PolkaVMContext) -> anyhow::Result<()> { + let translation_result = + self.translate_to_ir(context.debug_config().output_directory.as_deref())?; + let ir_object = translation_result.object; + let heap_opt = translation_result.heap_opt; + let type_info = translation_result.type_info; + let mem_opt = translation_result.mem_opt; + + // Dump the final, fully optimized IR annotated with the inferred type + // widths so the narrow pass's effect is visible in the dump. + if std::env::var(crate::RESOLC_DEBUG_IR_ENV).is_ok() { + if let Some(output_directory) = context.debug_config().output_directory.as_ref() { + use std::io::Write; + let ir_text = revive_newyork::print_object_with_types(&ir_object, &type_info); + let mut file_path = output_directory.to_owned(); + file_path.push(format!("{}.newyork.txt", ir_object.name.replace('/', "_"))); + if let Ok(mut f) = std::fs::File::create(&file_path) { + let _ = writeln!(f, "{}", ir_text); + } + } + } + let inline_decisions: std::collections::BTreeMap = + translation_result + .inline_results + .decisions + .into_iter() + .map(|(fid, decision)| (fid.0, decision)) + .collect(); + + let heap_op_count = ir_object.count_heap_operations(); + let keccak_single_count = ir_object.count_keccak256_single(); + let has_keccak_single = keccak_single_count >= KECCAK_SINGLE_THRESHOLD; + let use_native_heap = heap_opt.all_native(); + + if std::env::var(crate::RESOLC_DEBUG_HEAP_ENV).is_ok() { + if let Some(output_directory) = context.debug_config().output_directory.as_ref() { + use std::io::Write; + let mut log_path = output_directory.to_owned(); + log_path.push(HEAP_DEBUG_LOG_FILE); + if let Ok(mut file) = std::fs::OpenOptions::new() + .create(true) + .append(true) + .open(&log_path) + { + let _ = writeln!( + file, + "HEAP_OPT [{}]: all_native={}, total={}, unknown={}, tainted={}, escaping={}, native_regions={:?}, native_offsets={:?}, dynamic_escapes={}, dynamic_accesses={}", + ir_object.name, + use_native_heap, + heap_opt.total_accesses, + heap_opt.unknown_accesses, + heap_opt.tainted_count, + heap_opt.escaping_count, + heap_opt.native_safe_regions, + heap_opt.native_safe_offsets, + heap_opt.has_dynamic_escapes, + heap_opt.has_dynamic_accesses, + ); + } + } + } + + if std::env::var(crate::RESOLC_DEBUG_MEM_ENV).is_ok() { + if let Some(output_directory) = context.debug_config().output_directory.as_ref() { + use std::io::Write; + let mut log_path = output_directory.to_owned(); + log_path.push(MEM_DEBUG_LOG_FILE); + if let Ok(mut file) = std::fs::OpenOptions::new() + .create(true) + .append(true) + .open(&log_path) + { + let _ = writeln!( + file, + "MEM_OPT [{}]: loads_eliminated={}, stores_eliminated={}, values_tracked={}, keccak_pairs_fused={}, keccak_singles_fused={}, fmp_loads_eliminated={}", + ir_object.name, + mem_opt.loads_eliminated, + mem_opt.stores_eliminated, + mem_opt.values_tracked, + mem_opt.keccak_pairs_fused, + mem_opt.keccak_singles_fused, + mem_opt.fmp_loads_eliminated, + ); + } + } + } + + if let Some(debug_info) = context.debug_info() { + let di_builder = debug_info.builder(); + let object_name: &str = self.yul_object.identifier.as_str(); + let di_parent_scope = debug_info + .top_scope() + .expect("expected an existing debug-info scope"); + let object_scope = di_builder.create_namespace(di_parent_scope, object_name, true); + context.push_debug_scope(object_scope.as_debug_info_scope()); + } + + context.set_debug_location( + self.yul_object.location.line, + self.yul_object.location.column, + None, + )?; + + if self.yul_object.identifier.ends_with("_deployed") { + context.set_code_type(PolkaVMCodeType::Runtime); + + let mut codegen = LlvmCodegen::new( + heap_opt.clone(), + type_info.clone(), + inline_decisions.clone(), + ); + codegen + .generate_object(&ir_object, context) + .map_err(|e| anyhow::anyhow!("newyork LLVM codegen: {e}"))?; + } else { + context.set_code_type(PolkaVMCodeType::Deploy); + + revive_llvm_context::PolkaVMEntryFunction::default().into_llvm(context)?; + + revive_llvm_context::PolkaVMLoadImmutableDataFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMStoreImmutableDataFunction.into_llvm(context)?; + + if use_native_heap { + revive_llvm_context::PolkaVMLoadHeapWordNativeFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMStoreHeapWordNativeFunction.into_llvm(context)?; + } else { + revive_llvm_context::PolkaVMLoadHeapWordFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMStoreHeapWordFunction.into_llvm(context)?; + } + + revive_llvm_context::PolkaVMLoadStorageWordFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMStoreStorageWordFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMLoadTransientStorageWordFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMStoreTransientStorageWordFunction.into_llvm(context)?; + + revive_llvm_context::PolkaVMWordToPointerFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMExitFunction.into_llvm(context)?; + + revive_llvm_context::PolkaVMEventLogFunction::<0>.into_llvm(context)?; + revive_llvm_context::PolkaVMEventLogFunction::<1>.into_llvm(context)?; + revive_llvm_context::PolkaVMEventLogFunction::<2>.into_llvm(context)?; + revive_llvm_context::PolkaVMEventLogFunction::<3>.into_llvm(context)?; + revive_llvm_context::PolkaVMEventLogFunction::<4>.into_llvm(context)?; + + revive_llvm_context::PolkaVMDivisionFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMSignedDivisionFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMRemainderFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMSignedRemainderFunction.into_llvm(context)?; + + revive_llvm_context::PolkaVMSbrkFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMKeccak256TwoWordsFunction.into_llvm(context)?; + if has_keccak_single { + revive_llvm_context::PolkaVMKeccak256OneWordFunction.declare(context)?; + revive_llvm_context::PolkaVMKeccak256OneWordFunction.into_llvm(context)?; + } + revive_llvm_context::PolkaVMCallValueFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMCallValueNonzeroFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMCallDataLoadFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMCallerFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMRevertEmptyFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMRevertFunction.into_llvm(context)?; + revive_llvm_context::PolkaVMRevertPanicFunction.into_llvm(context)?; + + if heap_op_count > SBRK_NOINLINE_THRESHOLD { + if let Some(sbrk_func) = context.get_function("__sbrk_internal", false) { + revive_llvm_context::PolkaVMFunction::set_attributes( + context.llvm(), + sbrk_func.borrow().declaration(), + &[revive_llvm_context::PolkaVMAttribute::NoInline], + true, + ); + } + } + + let mut codegen = LlvmCodegen::new(heap_opt, type_info, inline_decisions); + codegen + .generate_object(&ir_object, context) + .map_err(|e| anyhow::anyhow!("newyork LLVM codegen: {e}"))?; + } + + context.set_debug_location( + self.yul_object.location.line, + self.yul_object.location.column, + None, + )?; + + context.pop_debug_scope(); + + Ok(()) + } +} diff --git a/crates/resolc/src/project/contract/mod.rs b/crates/resolc/src/project/contract/mod.rs index e428daf64..d6f4b43cd 100644 --- a/crates/resolc/src/project/contract/mod.rs +++ b/crates/resolc/src/project/contract/mod.rs @@ -55,6 +55,7 @@ impl Contract { pub fn object_identifier(&self) -> &str { match self.ir { IR::Yul(ref yul) => yul.object.identifier.as_str(), + IR::NewYork(ref newyork) => newyork.yul_object.identifier.as_str(), } } @@ -105,6 +106,21 @@ impl Contract { context.build(self.identifier.full_path.as_str(), metadata_bytes)? } + IR::NewYork(mut newyork) => { + let module = llvm.create_module(self.identifier.full_path.as_str()); + let mut context = + PolkaVMContext::new(&llvm, module, optimizer, debug_config, memory_config); + context.set_solidity_data(PolkaVMContextSolidityData::default()); + let yul_data = PolkaVMContextYulData::new(identifier_paths); + context.set_yul_data(yul_data); + + newyork.declare(&mut context)?; + newyork + .into_llvm(&mut context) + .map_err(|error| anyhow::anyhow!("NewYork IR generator: {error}"))?; + + context.build(self.identifier.full_path.as_str(), metadata_bytes)? + } }; Ok(ContractBuild::new( diff --git a/crates/resolc/src/project/mod.rs b/crates/resolc/src/project/mod.rs index 4a914b6e0..387daa3c2 100644 --- a/crates/resolc/src/project/mod.rs +++ b/crates/resolc/src/project/mod.rs @@ -27,6 +27,7 @@ use crate::build::Build; use crate::missing_libraries::MissingLibraries; use crate::process::input::Input as ProcessInput; use crate::process::Process; +use crate::project::contract::ir::newyork::NewYork; use crate::project::contract::ir::yul::Yul; use crate::project::contract::ir::IR; use crate::project::contract::Contract; @@ -142,11 +143,16 @@ impl Project { } /// Parses the Yul source code file and returns the source data. + /// + /// When `use_newyork` is `true`, each source is parsed into the `IR::NewYork` + /// variant; otherwise into `IR::Yul`. The downstream compile pipeline dispatches + /// on the IR variant. pub fn try_from_yul_paths( paths: &[PathBuf], solc_output: Option<&mut SolcStandardJsonOutput>, libraries: SolcStandardJsonInputSettingsLibraries, debug_config: &DebugConfig, + use_newyork: bool, ) -> anyhow::Result { let sources = paths .iter() @@ -155,15 +161,18 @@ impl Project { (path.to_string_lossy().to_string(), source) }) .collect::>(); - Self::try_from_yul_sources(sources, libraries, solc_output, debug_config) + Self::try_from_yul_sources(sources, libraries, solc_output, debug_config, use_newyork) } /// Parses the test Yul source code string and returns the source data. + /// + /// See [`Self::try_from_yul_paths`] for the meaning of `use_newyork`. pub fn try_from_yul_sources( sources: BTreeMap, libraries: SolcStandardJsonInputSettingsLibraries, mut solc_output: Option<&mut SolcStandardJsonOutput>, debug_config: &DebugConfig, + use_newyork: bool, ) -> anyhow::Result { #[cfg(feature = "parallel")] let iter = sources.into_par_iter(); @@ -176,11 +185,11 @@ impl Project { Ok(()) => source.take_content().expect("Always exists"), Err(error) => return Some((path, Err(error))), }; - let ir = match Yul::try_from_source(&source_code) { - Ok(ir) => ir?, + let (ir, object_identifier) = match parse_ir(&source_code, use_newyork) { + Ok(Some(parsed)) => parsed, + Ok(None) => return None, Err(error) => return Some((path, Err(error))), }; - let object_identifier = ir.object.identifier.clone(); let name = ContractIdentifier::new(path.clone(), Some(object_identifier)); let full_path = name.full_path.clone(); if let Err(error) = debug_config.dump_yul(&name.full_path, &source_code) { @@ -189,7 +198,7 @@ impl Project { let source_metadata = serde_json::json!({ "source_hash": Keccak256::from_slice(source_code.as_bytes()).to_string() }); - let contract = Contract::new(name, ir.into(), source_metadata); + let contract = Contract::new(name, ir, source_metadata); Some((full_path, Ok(contract))) }) .collect::>>(); @@ -210,11 +219,15 @@ impl Project { } /// Converts the `solc` JSON output into a convenient project. + /// + /// When `use_newyork` is `true`, each contract's optimized Yul IR is routed through + /// the newyork IR pipeline; otherwise through the direct Yul-to-LLVM path. pub fn try_from_standard_json_output( solc_output: &mut SolcStandardJsonOutput, libraries: SolcStandardJsonInputSettingsLibraries, solc_version: &SolcVersion, debug_config: &DebugConfig, + use_newyork: bool, ) -> anyhow::Result { let mut input_contracts = Vec::with_capacity(solc_output.contracts.len()); for (path, file) in solc_output.contracts.iter() { @@ -231,10 +244,9 @@ impl Project { let results = iter .filter_map(|(name, contract)| { - let ir = match Yul::try_from_source(&contract.ir_optimized) - .map(|yul| yul.map(IR::from)) - { - Ok(ir) => ir?, + let ir = match parse_ir(&contract.ir_optimized, use_newyork) { + Ok(Some((ir, _))) => ir, + Ok(None) => return None, Err(error) => return Some((name.full_path, Err(error))), }; if let Err(error) = debug_config.dump_yul(&name.full_path, &contract.ir_optimized) { @@ -261,3 +273,24 @@ impl Project { )) } } + +/// Parses a Yul source string into either the `IR::Yul` or `IR::NewYork` variant, +/// depending on `use_newyork`. Returns `Ok(None)` for empty sources. +/// +/// Yields the parsed IR together with the Yul object identifier (used for the +/// `ContractIdentifier`). +fn parse_ir(source_code: &str, use_newyork: bool) -> anyhow::Result> { + if use_newyork { + let Some(ir) = NewYork::try_from_source(source_code)? else { + return Ok(None); + }; + let identifier = ir.yul_object.identifier.clone(); + Ok(Some((IR::from(ir), identifier))) + } else { + let Some(ir) = Yul::try_from_source(source_code)? else { + return Ok(None); + }; + let identifier = ir.object.identifier.clone(); + Ok(Some((IR::from(ir), identifier))) + } +} diff --git a/crates/resolc/src/resolc/arguments.rs b/crates/resolc/src/resolc/arguments.rs index 047b098e8..3fdc5d3a1 100644 --- a/crates/resolc/src/resolc/arguments.rs +++ b/crates/resolc/src/resolc/arguments.rs @@ -106,6 +106,14 @@ pub struct Arguments { #[arg(long = "yul")] pub yul: bool, + /// Route Yul lowering through the newyork IR pipeline (experimental). + /// + /// This flag is orthogonal to the input mode: it composes with `--yul`, + /// `--standard-json`, `--combined-json`, and the default Solidity mode. + /// Equivalent to setting the `RESOLC_USE_NEWYORK=1` environment variable. + #[arg(long = "newyork", hide = true)] + pub newyork: bool, + /// Switch to linker mode, ignoring all options apart from `--libraries` and modify binaries in place. /// /// Unlinked contract binaries (caused by missing libraries or missing factory dependencies in turn) @@ -252,7 +260,10 @@ impl Arguments { let acceptable_count = 1 + self.standard_json.is_some() as usize; if modes > acceptable_count { messages.push(SolcStandardJsonOutputError::new_error( - "Only one modes is allowed at the same time: Yul, LLVM IR, PolkaVM assembly, combined JSON, standard JSON.",None,None)); + "Only one mode is allowed at the same time: Yul, combined JSON, standard JSON, link.", + None, + None, + )); } if self.yul && !self.libraries.is_empty() { diff --git a/crates/resolc/src/resolc/main.rs b/crates/resolc/src/resolc/main.rs index 4d5934bac..57dba2d00 100644 --- a/crates/resolc/src/resolc/main.rs +++ b/crates/resolc/src/resolc/main.rs @@ -176,6 +176,8 @@ fn main_inner( Some(arguments.stack_size), ); + let use_newyork = resolc::resolve_use_newyork(arguments.newyork); + let build = if arguments.yul { resolc::yul( &solc, @@ -187,6 +189,7 @@ fn main_inner( debug_config, &arguments.llvm_arguments, memory_config, + use_newyork, ) } else if let Some(standard_json) = arguments.standard_json { resolc::standard_json( @@ -199,6 +202,7 @@ fn main_inner( arguments.allow_paths, debug_config, arguments.detect_missing_libraries, + use_newyork, )?; return Ok(()); } else if let Some(format) = arguments.combined_json { @@ -222,6 +226,7 @@ fn main_inner( arguments.overwrite, arguments.llvm_arguments, memory_config, + use_newyork, )?; return Ok(()); } else if arguments.link { @@ -244,6 +249,7 @@ fn main_inner( debug_config, arguments.llvm_arguments, memory_config, + use_newyork, ) }?; diff --git a/crates/resolc/src/test_utils.rs b/crates/resolc/src/test_utils.rs index 8b9cb24f5..0f925d105 100644 --- a/crates/resolc/src/test_utils.rs +++ b/crates/resolc/src/test_utils.rs @@ -50,6 +50,8 @@ struct CachedBlob { solidity: String, /// The optimization level. opt: String, + /// Whether newyork IR pipeline is enabled. + use_newyork: bool, } /// Builds the Solidity project and returns the standard JSON output. @@ -108,13 +110,26 @@ pub fn build_solidity_with_options( if output.has_errors() { return Ok(output); } - let debug_config = DebugConfig::new(None, optimizer_settings.middle_end_as_string() != "z"); + let use_newyork = crate::resolve_use_newyork(false); + let debug_config = if std::env::var(crate::RESOLC_DEBUG_BLOB_ENV).is_ok() { + let suffix = if use_newyork { "newyork" } else { "yul" }; + DebugConfig::new( + Some(std::path::PathBuf::from(format!( + "/tmp/debug_llvm_{}", + suffix + ))), + optimizer_settings.middle_end_as_string() != "z", + ) + } else { + DebugConfig::new(None, optimizer_settings.middle_end_as_string() != "z") + }; let linker_symbols = libraries.as_linker_symbols()?; let build = Project::try_from_standard_json_output( &mut output, libraries, &solc_version, &debug_config, + use_newyork, )? .compile( &mut vec![], @@ -225,6 +240,7 @@ pub fn build_solidity_and_detect_missing_libraries( libraries, &solc_version, &DEBUG_CONFIG, + crate::resolve_use_newyork(false), )?; let missing_libraries = project.get_missing_libraries(&deployed_libraries); @@ -254,6 +270,7 @@ pub fn build_yul( Default::default(), None, &DEBUG_CONFIG, + false, )? .compile( &mut vec![], @@ -297,6 +314,7 @@ pub fn build_yul_standard_json( Default::default(), Some(&mut output), &DEBUG_CONFIG, + false, )? .compile( &mut vec![], @@ -335,11 +353,14 @@ pub fn compile_blob_with_options( optimizer_settings: OptimizerSettings, libraries: SolcStandardJsonInputSettingsLibraries, ) -> Vec { + let use_newyork = crate::resolve_use_newyork(false); + let id = CachedBlob { contract_name: contract_name.to_owned(), opt: optimizer_settings.middle_end_as_string(), solc_optimizer_enabled, solidity: source_code.to_owned(), + use_newyork, }; if let Some(blob) = PVM_BLOB_CACHE.lock().unwrap().get(&id) { @@ -372,6 +393,17 @@ pub fn compile_blob_with_options( let blob = hex::decode(bytecode).expect("hex encoding should always be valid"); assert_eq!(&blob[..3], b"PVM"); + if std::env::var(crate::RESOLC_DEBUG_BLOB_ENV).is_ok() { + eprintln!( + "DEBUG [{}]: blob size={}, first_bytes={:?}, use_newyork={}", + contract_name, + blob.len(), + &blob[..20.min(blob.len())], + std::env::var(crate::RESOLC_USE_NEWYORK_ENV).unwrap_or_default() + ); + std::fs::write(format!("/tmp/debug_blob_{}.pvm", contract_name), &blob).ok(); + } + PVM_BLOB_CACHE.lock().unwrap().insert(id, blob.clone()); blob @@ -446,6 +478,7 @@ fn compile_evm( solidity: source_code.to_owned(), solc_optimizer_enabled, opt: String::new(), + use_newyork: false, // EVM compilation never uses newyork }; let cache = if runtime { @@ -498,11 +531,13 @@ pub fn compile_yul_blob_with_options( yul_source: &str, optimizer_settings: OptimizerSettings, ) -> Vec { + let use_newyork = crate::resolve_use_newyork(false); let id = CachedBlob { contract_name: contract_name.to_owned(), opt: optimizer_settings.middle_end_as_string(), solc_optimizer_enabled: false, solidity: yul_source.to_owned(), + use_newyork, }; if let Some(blob) = PVM_BLOB_CACHE.lock().unwrap().get(&id) { return blob.clone(); @@ -521,6 +556,7 @@ pub fn compile_yul_blob_with_options( Default::default(), None, &DEBUG_CONFIG, + use_newyork, ) .expect("yul project should build") .compile( @@ -563,6 +599,7 @@ pub fn compile_yul_evm_deploy_code(contract_name: &str, yul_source: &str) -> Vec opt: String::new(), solc_optimizer_enabled: false, solidity: yul_source.to_owned(), + use_newyork: false, }; if let Some(blob) = EVM_BLOB_CACHE.lock().unwrap().get(&id) { return blob.clone(); @@ -626,6 +663,7 @@ pub fn compile_to_yul( solc_optimizer_enabled, solidity: source_code.to_owned(), opt: optimizer.mode.into(), + use_newyork: false, // Yul IR cache doesn't use newyork }; if let Some(yul) = YUL_IR_CACHE.lock().unwrap().get(&id) { diff --git a/crates/resolc/src/tests/cli/standard_json.rs b/crates/resolc/src/tests/cli/standard_json.rs index 20c1993e5..9c25462c3 100644 --- a/crates/resolc/src/tests/cli/standard_json.rs +++ b/crates/resolc/src/tests/cli/standard_json.rs @@ -187,7 +187,23 @@ fn assert_standard_json_errors_contain(output: &SolcStandardJsonOutput, error_me /// Asserts that the standard JSON output has no errors with severity `error`. fn assert_no_errors(output: &SolcStandardJsonOutput) { - assert!(!output.errors.iter().any(|error| error.is_error())); + let mut has_errors = false; + for error in output.errors.iter().filter(|error| error.is_error()) { + eprintln!( + "ERROR in {}: {}", + error + .source_location + .as_ref() + .map(|l| l.file.as_str()) + .unwrap_or("unknown"), + error.message, + ); + has_errors = true; + } + assert!( + !has_errors, + "the standard JSON output should not contain errors" + ); } /// Converts valid JSON text to `SolcStandardJsonOutput`. diff --git a/crates/resolc/src/tests/unit/yul_function_scoping.rs b/crates/resolc/src/tests/unit/yul_function_scoping.rs index 5f07e31b5..687647124 100644 --- a/crates/resolc/src/tests/unit/yul_function_scoping.rs +++ b/crates/resolc/src/tests/unit/yul_function_scoping.rs @@ -5,8 +5,7 @@ use crate::test_utils::build_yul; /// Reproducer from GH-474: duplicate `f` across switch cases. #[test] fn duplicate_function_names_in_switch_cases() { - let code = r#" -object "Test" { + let code = r#"object "Test" { code { { let size := datasize("Test_deployed") diff --git a/crates/runtime-api/build.rs b/crates/runtime-api/build.rs index 5783d1ced..66cc11525 100644 --- a/crates/runtime-api/build.rs +++ b/crates/runtime-api/build.rs @@ -24,7 +24,7 @@ fn compile(source_path: &str, bitcode_path: &str) { "-Xclang", "-target-feature", "-Xclang", - "+xtheadcondmov", + "+e,+m,+a,+c,+zbb,+auipc-addi-fusion,+ld-add-fusion,+lui-addi-fusion,+xtheadcondmov,+relax,+unaligned-scalar-mem", "-fno-exceptions", "-ffreestanding", "-Wall", diff --git a/crates/solc-json-interface/src/standard_json/input/settings/optimizer/details.rs b/crates/solc-json-interface/src/standard_json/input/settings/optimizer/details.rs index b6e44bccd..882726833 100644 --- a/crates/solc-json-interface/src/standard_json/input/settings/optimizer/details.rs +++ b/crates/solc-json-interface/src/standard_json/input/settings/optimizer/details.rs @@ -64,6 +64,7 @@ impl Details { } } + /// Creates disabled optimizer details. pub fn disabled(version: &semver::Version) -> Self { let inliner = if version >= &semver::Version::new(0, 8, 5) { Some(false) diff --git a/docs/404.html b/docs/404.html index 139914c5f..89273d3c5 100644 --- a/docs/404.html +++ b/docs/404.html @@ -36,10 +36,10 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-79c091ca.js"; + window.path_to_searchindex_js = "searchindex-767b23cd.js"; - +
diff --git a/docs/developer_guide.html b/docs/developer_guide.html index 4fcaca9fd..6b3b5f794 100644 --- a/docs/developer_guide.html +++ b/docs/developer_guide.html @@ -35,10 +35,10 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-79c091ca.js"; + window.path_to_searchindex_js = "searchindex-767b23cd.js"; - +
diff --git a/docs/developer_guide/architecture.html b/docs/developer_guide/architecture.html index c6a0c7d71..fb66ff443 100644 --- a/docs/developer_guide/architecture.html +++ b/docs/developer_guide/architecture.html @@ -35,10 +35,10 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-79c091ca.js"; + window.path_to_searchindex_js = "../searchindex-767b23cd.js"; - +
@@ -208,7 +208,7 @@

The L

We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM rv64emacb target and always leave assertions on. Furthermore, we need cross builds because resolc itself targets emscripten and musl. The revive-llvm-builer functions as a cross-platform build script and is used to build and release the LLVM dependency.

We also maintain the lld-sys crate for interfacing with LLD. The LLVM linker is used during the compilation process, but we don’t want to distribute another binary.

Custom optimizations

-

At the moment, no significant custom optimizations are implemented. Thus, we are missing some optimization opportunities that neither solc nor LLVM can realize (due to their lack of domain specific knowledge about the semantics of our target environment). Furthermore, solc optimizes for EVM gas and a target machine orthogonal to our target (BE 256-bit stack machine EVM vs. 64-bit LE RISC architecture PVM). We have started working on an additional IR layer between Yul and LLVM to capture missed optimization opportunities, though.

+

An experimental newyork optimizer introduces a custom IR layer between Yul and LLVM IR to capture optimization opportunities that neither solc nor LLVM can realize on their own. solc optimizes for EVM gas on a 256-bit big-endian stack machine, while LLVM lacks the domain knowledge to understand EVM memory semantics or Solidity patterns. The newyork IR bridges this gap with passes for type narrowing, memory optimization, function deduplication, and more.

@@ -218,7 +218,7 @@

Cus - @@ -232,7 +232,7 @@

Cus - diff --git a/docs/developer_guide/contributing.html b/docs/developer_guide/contributing.html index f4dae78a3..d930711f6 100644 --- a/docs/developer_guide/contributing.html +++ b/docs/developer_guide/contributing.html @@ -35,10 +35,10 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-79c091ca.js"; + window.path_to_searchindex_js = "../searchindex-767b23cd.js"; - +
diff --git a/docs/developer_guide/cross_compilation.html b/docs/developer_guide/cross_compilation.html index 50b523c3f..11eed881e 100644 --- a/docs/developer_guide/cross_compilation.html +++ b/docs/developer_guide/cross_compilation.html @@ -35,10 +35,10 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-79c091ca.js"; + window.path_to_searchindex_js = "../searchindex-767b23cd.js"; - +
diff --git a/docs/developer_guide/newyork_ir.html b/docs/developer_guide/newyork_ir.html new file mode 100644 index 000000000..da440a948 --- /dev/null +++ b/docs/developer_guide/newyork_ir.html @@ -0,0 +1,4010 @@ + + + + + + IR reference - revive compiler book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

Keyboard shortcuts

+
+

Press or to navigate between chapters

+

Press S or / to search in the book

+

Press ? to show this help

+

Press Esc to hide this help

+
+
+
+
+ + + + + + + + + + + + + +
+ +
+
+ + + + + + + +
+
+

newyork IR reference

+

A per-operation reference for the newyork IR: textual syntax, operand and result types, purity, region and static-slot annotations, and examples.

+

How to read this reference

+

This appendix enumerates every operation the newyork IR supports. It is a lookup, not a walkthrough: each entry is self-contained and intended to be reachable by anchor.

+

Operations are grouped by function (memory and storage writes, pure expressions, control flow, and so on) rather than alphabetically. Jump to a specific operation from the operation index below, or use the sidebar.

+

Every operation appears in two places in the codebase. The canonical Rust definition is a variant of either Expression or Statement in ir.rs. The textual rendering used by debug dumps and by this appendix is produced by the printer in printer.rs. Treat the printed syntax as a debug surface, not a stable input language: there is no parser for it, and printer details change when passes add new annotations.

+

Entry format

+

Each operation entry has the same shape:

+
+ + + + + + + + + + + + + +
FieldWhat it shows
HeadingThe printed operation name (e.g. mstore) followed by the Expression or Statement variant it corresponds to in ir.rs.
DescriptionA short prose summary of what the operation does and any semantic notes worth knowing before reading the rest of the entry.
SyntaxThe literal printer output, including any optional debug annotations (region tags, static-slot comments). Anything inside /* ... */ is a debug-only annotation and is not part of the operation itself.
ExampleA minimal printed snippet, using the printer’s actual v0/v1/… naming.
OperandsOne row per input or structural participant in the printed syntax. Value operands list the narrowest type the operation guarantees (default i256; narrower widths only appear when type inference has narrowed an upstream definition). Vector-of-operands fields show Vec<…> as the type. Non-value participants such as nested regions are listed with an em-dash type to mark them as structural rather than as operands.
Result and purityThe type the operation produces (or none for statements that bind no value), followed by a purity label, either Pure or Effectful. Pure operations may be reordered, deduplicated, or eliminated by the simplifier; effectful ones may not. Effectful entries may carry a parenthetical describing the nature of the side effect when informative (e.g. “control flow”, “terminator”, or a note about revert/trap behavior).
AnnotationsOperation-specific fields the printer surfaces as /* ... */ comments in the dump (region tag for memory ops, static-slot hint for storage ops, type suffix for non-default widths). Listed here as a table of source fieldprinted form.
+
+

Syntax notation

+

Syntax templates in each entry use the following conventions:

+
+ + + + + + + + + + + + + +
NotationMeaning
add, mload, if, else, case, let, yield, …Literal printer tokens: bare lowercase identifiers and keywords that the printer emits verbatim.
$offset, $value, $key, $lhs, $rhs, …Role names ($-prefixed): placeholders for SSA value references the printer renders as v followed by a decimal id (v0, v1, …).
<type>, <region>, <hex>, <id>, <bits>, <func_name>, <N>, <length>, …Metavariables: stand for compile-time fields (type tags, hex values, identifier strings, integer counts), not SSA values. The concrete values they take are enumerated in the Annotations section of each entry or in the type system reference.
[…]Optional parts. Anything inside the brackets may or may not appear in any given dump, depending on the conditions described in the operation’s Annotations section.
[: <type>]Optional type suffix on a value reference. Suppressed when the value’s type is the default i256 integer; present otherwise (: i32, : ptr<heap>, …).
/* … */Debug-only annotations the printer attaches to certain operations (memory region tag, static-slot hint, etc.).
Repetition: “more entries of the same shape.” Used in vector operand lists ($arg_0, $arg_1, …) and in multi-line block bodies ({ … }).
+
+

Operation index

+

Pure expressions

+
Constants and variables
+ +
Arithmetic
+ +
Bit-width conversions
+ +
Hashing
+ +
Environment reads
+ +
Calldata, returndata, and code
+ +
Memory and storage loads
+ +
Linker
+ +
Function call
+ +

Memory and storage writes

+ +

Bulk copies

+ +

Bindings and wrappers

+ +

Structured control flow

+ +

External interaction

+ +

Termination

+ +

Type system

+

Every value in the IR carries a Type. The operation entries below refer to widths (i1i256), address spaces (ptr<heap>, etc.), and memory regions (scratch, etc.) by their printed form; this section is the reference for those names.

+

Type

+

The umbrella enum. Three variants:

+
+ + + + + + + + + +
VariantPrinted asDescription
Int(BitWidth)i1, i8, …, i256An integer at one of seven widths; see BitWidth.
Ptr(AddressSpace)ptr<heap>, ptr<stack>, ptr<storage>, ptr<code>A pointer tagged with its address space; see AddressSpace.
VoidvoidUnit type. Used for statements that produce no value and for void-returning functions.
+
+

BitWidth

+

The seven rungs of integer width. Newly minted values default to I256; type inference narrows them down to one of the lower rungs when it can prove the upper bits are zero or unused.

+
+ + + + + + + + + + + + + +
VariantPrinted asTypical use
I1i1Boolean. Result type of every comparison and iszero.
I8i8Byte values. The narrowest meaningful integer.
I32i32PolkaVM pointer width (XLEN); minimum width for function parameters under the rv64e ABI.
I64i64PolkaVM native register width; most narrowed values land here.
I128i128Two registers; arithmetic that overflows i64 but doesn’t need full 256-bit emulation.
I160i160Ethereum addresses; result of caller, origin, mapping keys.
I256i256EVM word width. The default and conservative ceiling.
+
+

AddressSpace

+

The address space a pointer points into. Carried on every Ptr value so the codegen can lower loads and stores without a separate alias-analysis pass.

+
+ + + + + + + + + + +
VariantPrinted asPoints intoEndianness
Heapptr<heap>Emulated EVM linear memory (the simulated mload/mstore region).Big-endian (by EVM contract).
Stackptr<stack>Native PolkaVM stack allocations.Little-endian (no swap).
Storageptr<storage>Contract storage; key/value with 256-bit slots.Big-endian on the wire.
Codeptr<code>Read-only code/data segment.Big-endian.
+
+

MemoryRegion

+

A refinement carried by every memory load and store on top of AddressSpace::Heap. The tag tells later passes what kind of heap address an offset is hitting, which drives both free-memory-pointer propagation and byte-swap elimination.

+
+ + + + + + + + + + +
VariantAddress rangePrinted asMeaning
Scratch0x000x3f/* scratch */EVM scratch space; safe to touch without consulting the free memory pointer.
FreePointerSlotexactly 0x40/* free_ptr */Slot that stores the free memory pointer itself.
Dynamic0x80 and above/* dynamic */Real heap allocations.
Unknowneverything else (constants in 0x410x7f, plus all non-constant offsets)(suppressed)Conservative fallback used when the offset isn’t a constant or doesn’t slot cleanly.
+
+

Pure expressions

+

Pure expressions produce values without side effects. The simplifier may freely reorder, deduplicate, and eliminate them. They appear on the right-hand side of a let binding, or as operands of other expressions and effectful statements; the operand positions accept SSA value references only, so any pure expression that is consumed elsewhere is first bound by a let. Examples in this section wrap each expression in a let v := … to give it somewhere to land.

+

0x<hex>

+

(Expression::Literal)

+

Description

+

A compile-time constant value with a declared type. New literals minted by the translator default to Int(I256); passes that synthesize constants at narrower widths (e.g. a one-bit boolean from a constant comparison) attach the narrower type directly.

+

Syntax

+
0x<hex>[: <type>]
+
+

Example

+
let v0 := 0x2a              // 42 at the default i256
+let v1 := 0x1: i1           // boolean true
+let v2 := 0x80: i64         // narrowed by type inference
+
+

Operands

+

None — literals are leaves.

+

Result and purity

+
+ + + + + + + +
ResultPurity
Same as the literal’s value_typePure
+
+

Annotations

+
+ + + + + + + + +
Source fieldPrinted as
value: BigUint0x<hex> in the syntax position (not a comment annotation; it is the expression itself)
value_type: Type: <type> suffix when value_type is not the default Int(I256); suppressed otherwise
+
+

v<id>

+

(Expression::Var)

+

Description

+

A reference to an existing SSA value, used as the entire right-hand side of a let. In a typical dump this is rare because the simplifier collapses let v := v<id> into the consumers of v via copy propagation; expect to see it only in dumps taken before simplification has run.

+

Syntax

+
v<id>
+
+

Example

+
let v5 := v3                // copy; usually eliminated by simplify
+
+

Operands

+

None — the expression is the value reference itself.

+

Result and purity

+
+ + + + + + + +
ResultPurity
Same as the referenced value’s typePure
+
+

Annotations

+

None.

+

add

+

(Expression::Binary with BinaryOperation::Add)

+

Description

+

Modular addition. Wraps on overflow; per EVM, the result is (lhs + rhs) mod 2^N where N is the operand width.

+

Syntax

+
add($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := add(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256
rhsi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
widen_by_one(max(width(lhs), width(rhs))) — one tier above the wider operand to account for the carry bitPure
+
+

Annotations

+

None.

+

sub

+

(Expression::Binary with BinaryOperation::Sub)

+

Description

+

Modular subtraction. Wraps on underflow; the result is (lhs - rhs) mod 2^256 regardless of operand widths.

+

Syntax

+
sub($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := sub(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256
rhsi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — conservative; underflow on narrower operands could borrow into upper bitsPure
+
+

Annotations

+

None.

+

mul

+

(Expression::Binary with BinaryOperation::Mul)

+

Description

+

Modular multiplication. The result is (lhs * rhs) mod 2^256.

+

Syntax

+
mul($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := mul(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256
rhsi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
double_width(max(width(lhs), width(rhs))) — the tier holding twice the wider operand’s bits (skipping i160 at the i128i256 transition)Pure
+
+

Annotations

+

None.

+

div

+

(Expression::Binary with BinaryOperation::Div)

+

Description

+

Unsigned integer division. Per EVM, div(x, 0) = 0 (no trap on division by zero).

+

Syntax

+
div($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := div(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Dividend.
rhsi256Divisor; 0 yields a result of 0, not a trap.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
width(lhs) — the quotient cannot exceed the dividendPure
+
+

Annotations

+

None.

+

sdiv

+

(Expression::Binary with BinaryOperation::SDiv)

+

Description

+

Signed two’s-complement integer division. Per EVM, sdiv(x, 0) = 0; quotient is truncated toward zero.

+

Syntax

+
sdiv($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := sdiv(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Dividend, treated as signed.
rhsi256Divisor, treated as signed; 0 yields 0.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
width(lhs)Pure
+
+

Annotations

+

None.

+

mod

+

(Expression::Binary with BinaryOperation::Mod)

+

Description

+

Unsigned modulo. Per EVM, mod(x, 0) = 0.

+

Syntax

+
mod($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := mod(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Dividend.
rhsi256Divisor; 0 yields 0.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
width(lhs)Pure
+
+

Annotations

+

None.

+

smod

+

(Expression::Binary with BinaryOperation::SMod)

+

Description

+

Signed modulo. Per EVM, smod(x, 0) = 0; the result takes the sign of the dividend.

+

Syntax

+
smod($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := smod(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Dividend, treated as signed.
rhsi256Divisor, treated as signed; 0 yields 0.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
width(lhs)Pure
+
+

Annotations

+

None.

+

exp

+

(Expression::Binary with BinaryOperation::Exp)

+

Description

+

Modular exponentiation: (lhs ^ rhs) mod 2^256. The most expensive arithmetic opcode in EVM (variable gas cost proportional to the byte length of rhs).

+

Syntax

+
exp($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := exp(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Base.
rhsi256Exponent.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — conservative; exponentiation can fill any widthPure
+
+

Annotations

+

None.

+

and

+

(Expression::Binary with BinaryOperation::And)

+

Description

+

Bitwise AND. The common idiom for type narrowing: a constant mask on the right lets forward analysis pick up a tight result width.

+

Syntax

+
and($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := and(v0, v1)
+let v3 := and(v0, 0xff)     // type inference narrows result to i8
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256
rhsi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
min(width(lhs), width(rhs)) — AND can only clear bits, so the result fits in the narrower operandPure
+
+

Annotations

+

None.

+

or

+

(Expression::Binary with BinaryOperation::Or)

+

Description

+

Bitwise OR.

+

Syntax

+
or($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := or(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256
rhsi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
max(width(lhs), width(rhs))Pure
+
+

Annotations

+

None.

+

xor

+

(Expression::Binary with BinaryOperation::Xor)

+

Description

+

Bitwise XOR.

+

Syntax

+
xor($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := xor(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256
rhsi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
max(width(lhs), width(rhs))Pure
+
+

Annotations

+

None.

+

shl

+

(Expression::Binary with BinaryOperation::Shl)

+

Description

+

Logical left shift. Operand order follows EVM: shl(shift, value) computes value << shift. Shifts ≥ 256 produce 0.

+

Syntax

+
shl($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := shl(v0, v1)       // v1 shifted left by v0 bits
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Shift amount in bits.
rhsi256Value to shift.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — conservative; bits may shift into any widthPure
+
+

Annotations

+

None.

+

shr

+

(Expression::Binary with BinaryOperation::Shr)

+

Description

+

Logical right shift. Operand order follows EVM: shr(shift, value) computes value >> shift with zero-fill from the left. Shifts ≥ 256 produce 0.

+

Syntax

+
shr($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := shr(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Shift amount in bits.
rhsi256Value to shift.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
If lhs is a known constant k: tier holding 256 - k bits (or i1 for k ≥ 256). Otherwise: width(rhs).Pure
+
+

Annotations

+

None.

+

sar

+

(Expression::Binary with BinaryOperation::Sar)

+

Description

+

Arithmetic (signed) right shift. Operand order follows EVM: sar(shift, value) shifts value right by shift bits, preserving the sign bit. Shifts ≥ 256 saturate to 0 for non-negative values and to -1 (all-ones) for negative values.

+

Syntax

+
sar($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := sar(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Shift amount in bits.
rhsi256Value to shift, treated as signed.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
Same shape as shr forward inference (constant shift narrows the result; non-constant falls back to width(rhs)).Pure
+
+

Annotations

+

None.

+

lt

+

(Expression::Binary with BinaryOperation::Lt)

+

Description

+

Unsigned less-than comparison. Returns 1 if lhs < rhs, else 0.

+

Syntax

+
lt($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := lt(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Compared unsigned.
rhsi256Compared unsigned.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i1Pure
+
+

Annotations

+

None.

+

gt

+

(Expression::Binary with BinaryOperation::Gt)

+

Description

+

Unsigned greater-than comparison. Returns 1 if lhs > rhs, else 0.

+

Syntax

+
gt($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := gt(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Compared unsigned.
rhsi256Compared unsigned.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i1Pure
+
+

Annotations

+

None.

+

slt

+

(Expression::Binary with BinaryOperation::Slt)

+

Description

+

Signed less-than comparison. Operands are treated as two’s complement.

+

Syntax

+
slt($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := slt(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Compared signed.
rhsi256Compared signed.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i1Pure
+
+

Annotations

+

None.

+

sgt

+

(Expression::Binary with BinaryOperation::Sgt)

+

Description

+

Signed greater-than comparison. Operands are treated as two’s complement.

+

Syntax

+
sgt($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := sgt(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Compared signed.
rhsi256Compared signed.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i1Pure
+
+

Annotations

+

None.

+

eq

+

(Expression::Binary with BinaryOperation::Eq)

+

Description

+

Equality comparison. Returns 1 if lhs == rhs, else 0. Signedness is irrelevant.

+

Syntax

+
eq($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := eq(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256
rhsi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i1Pure
+
+

Annotations

+

None.

+

byte

+

(Expression::Binary with BinaryOperation::Byte)

+

Description

+

Extract a single byte from a 256-bit word. byte(i, x) returns the i-th byte of x with byte 0 being the most significant. If i ≥ 32, the result is 0.

+

Syntax

+
byte($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := byte(v0, v1)      // v0 = byte index, v1 = word
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Byte position; 0 = most significant byte. Values ≥ 32 yield 0.
rhsi256Source word.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i8Pure
+
+

Annotations

+

None.

+

signextend

+

(Expression::Binary with BinaryOperation::SignExtend)

+

Description

+

Sign-extend an integer from a byte position. Per EVM, signextend(b, x) treats byte b of x as the most significant byte of a smaller signed integer and extends its sign through the upper bytes.

+

Syntax

+
signextend($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := signextend(v0, v1)  // v0 = byte position, v1 = value
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Byte position of the sign byte (0–31).
rhsi256Source value.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — the extended value occupies the full wordPure
+
+

Annotations

+

The width-targeted sign-extension primitive sext<i<bits>> (Expression::SignExtendTo) is a separate operation; see the bit-width conversions section.

+

addmod

+

(Expression::Ternary with BinaryOperation::AddMod)

+

Description

+

Ternary modular addition: (a + b) mod n, computed without intermediate overflow. Per EVM, n = 0 yields 0.

+

Syntax

+
addmod($a[: <type>], $b[: <type>], $n[: <type>])
+
+

Example

+
let v3 := addmod(v0, v1, v2)
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
ai256First addend.
bi256Second addend.
ni256Modulus; 0 yields 0.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — conservativePure
+
+

Annotations

+

None.

+

mulmod

+

(Expression::Ternary with BinaryOperation::MulMod)

+

Description

+

Ternary modular multiplication: (a * b) mod n, computed without intermediate overflow. Per EVM, n = 0 yields 0.

+

Syntax

+
mulmod($a[: <type>], $b[: <type>], $n[: <type>])
+
+

Example

+
let v3 := mulmod(v0, v1, v2)
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
ai256First factor.
bi256Second factor.
ni256Modulus; 0 yields 0.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — conservativePure
+
+

Annotations

+

None.

+

iszero

+

(Expression::Unary with UnaryOperation::IsZero)

+

Description

+

Returns 1 if the operand is 0, else 0. Also serves as the logical NOT for boolean values.

+

Syntax

+
iszero($operand[: <type>])
+
+

Example

+
let v1 := iszero(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
operandi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i1Pure
+
+

Annotations

+

None.

+

not

+

(Expression::Unary with UnaryOperation::Not)

+

Description

+

Bitwise complement. Inverts every bit; equivalent to xor(operand, 2^256 - 1).

+

Syntax

+
not($operand[: <type>])
+
+

Example

+
let v1 := not(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
operandi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — the complement fills the full word regardless of operand widthPure
+
+

Annotations

+

None.

+

clz

+

(Expression::Unary with UnaryOperation::Clz)

+

Description

+

Count leading zeros. Returns the number of leading zero bits in the operand, where a value of 0 returns 256 (the full width). Not an EVM opcode; reaches newyork as a Yul builtin (FunctionName::Clz) and is translated directly by the Yul-to-newyork translator.

+

Syntax

+
clz($operand[: <type>])
+
+

Example

+
let v1 := clz(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
operandi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — in practice the value fits in nine bits (max 256), so type inference often narrows furtherPure
+
+

Annotations

+

None.

+

truncate<i<bits>>

+

(Expression::Truncate)

+

Description

+

Reinterpret a wider integer as a narrower one by discarding the upper bits. The destination width is carried in the IR’s to: BitWidth field and is rendered inside the angle brackets of the printer mnemonic. Narrowing-only; the source width must be greater than or equal to the destination width.

+

Syntax

+
truncate<i<bits>>($value[: <type>])
+
+

Example

+
let v1 := truncate<i64>(v0)
+let v2 := truncate<i8>(v1)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
valuei256Source value; must be at least as wide as the destination.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
The destination width from the to fieldPure
+
+

Annotations

+

None. The destination width is part of the operation name, not a debug annotation.

+

zext<i<bits>>

+

(Expression::ZeroExtend)

+

Description

+

Reinterpret a narrower integer as a wider one by zero-filling the upper bits. The destination width is carried in the IR’s to: BitWidth field. Widening-only.

+

Syntax

+
zext<i<bits>>($value[: <type>])
+
+

Example

+
let v1 := zext<i256>(v0: i8)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
valuei256Source value; must be no wider than the destination.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
The destination width from the to fieldPure
+
+

Annotations

+

None.

+

sext<i<bits>>

+

(Expression::SignExtendTo)

+

Description

+

Reinterpret a narrower signed integer as a wider one by sign-extending the high bit. The destination width is carried in the IR’s to: BitWidth field. Distinct from signextend (Expression::Binary), which is the EVM byte-position primitive; this one specifies the destination width directly and is introduced by passes that produce a sign-extended value at a known target width.

+

Syntax

+
sext<i<bits>>($value[: <type>])
+
+

Example

+
let v1 := sext<i256>(v0: i64)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
valuei256Source value; must be no wider than the destination.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
The destination width from the to fieldPure
+
+

Annotations

+

None.

+

keccak256

+

(Expression::Keccak256)

+

Description

+

Compute the Keccak-256 hash of length bytes of emulated EVM linear memory starting at offset. The general-purpose hashing primitive; the two specialized variants below cover the common scratch-space patterns more compactly.

+

Syntax

+
keccak256($offset[: <type>], $length[: <type>])
+
+

Example

+
let v2 := keccak256(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
offseti256Byte offset into linear memory; forward analysis widens to at least i64.
lengthi256Length of the region to hash, in bytes; forward analysis widens to at least i64.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure — the hash is a deterministic function of the memory contents at evaluation time. Passes that hoist or dedupe must respect intervening memory writes.
+
+

Annotations

+

None.

+

keccak256_pair

+

(Expression::Keccak256Pair)

+

Description

+

Compound hash of two 256-bit words. Equivalent to mstore(0, word0); mstore(32, word1); keccak256(0, 64) but emitted as a single outlined call after the keccak-fusion pass recognizes the pattern. The mapping-key idiom; see also mapping_sload.

+

Syntax

+
keccak256_pair($word0[: <type>], $word1[: <type>])
+
+

Example

+
let v2 := keccak256_pair(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
word0i256First word; the high 32 bytes of the hash input.
word1i256Second word; the low 32 bytes of the hash input.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

keccak256_single

+

(Expression::Keccak256Single)

+

Description

+

Compound hash of a single 256-bit word. Equivalent to mstore(0, word0); keccak256(0, 32) but emitted as a single outlined call after the keccak-fusion pass.

+

Syntax

+
keccak256_single($word0[: <type>])
+
+

Example

+
let v1 := keccak256_single(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
word0i256The word to hash.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

caller

+

(Expression::Caller)

+

Description

+

Address of the immediate caller of the current call frame.

+

Syntax

+
caller()
+
+

Example

+
let v0 := caller()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i160Pure
+
+

Annotations

+

None.

+

callvalue

+

(Expression::CallValue)

+

Description

+

Value (wei) attached to the current call.

+

Syntax

+
callvalue()
+
+

Example

+
let v0 := callvalue()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

origin

+

(Expression::Origin)

+

Description

+

Address of the original externally owned account that initiated the transaction.

+

Syntax

+
origin()
+
+

Example

+
let v0 := origin()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i160Pure
+
+

Annotations

+

None.

+

address

+

(Expression::Address)

+

Description

+

Address of the contract executing the current call frame.

+

Syntax

+
address()
+
+

Example

+
let v0 := address()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i160Pure
+
+

Annotations

+

None.

+

chainid

+

(Expression::ChainId)

+

Description

+

Chain identifier of the network the contract is executing on.

+

Syntax

+
chainid()
+
+

Example

+
let v0 := chainid()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

gas

+

(Expression::Gas)

+

Description

+

Remaining gas at the point of evaluation. Modelled as a pure expression for IR purposes; in practice it changes between evaluations, so any simplifier that deduplicates pure expressions must respect gas as a barrier.

+

Syntax

+
gas()
+
+

Example

+
let v0 := gas()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure (per IR; see Description)
+
+

Annotations

+

None.

+

msize

+

(Expression::MSize)

+

Description

+

Highest byte offset of emulated EVM linear memory that has been touched, rounded up to the next 32-byte boundary. Unlike gas, classified as side-effectful by the simplifier: unused msize() bindings are not eliminated, because the result depends on the program’s memory-access history and would change if the surrounding statements were reordered.

+

Syntax

+
msize()
+
+

Example

+
let v0 := msize()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Effectful (see Description)
+
+

Annotations

+

None.

+

coinbase

+

(Expression::Coinbase)

+

Description

+

Address of the block’s coinbase (block author).

+

Syntax

+
coinbase()
+
+

Example

+
let v0 := coinbase()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i160Pure
+
+

Annotations

+

None.

+

timestamp

+

(Expression::Timestamp)

+

Description

+

Block timestamp, as a Unix epoch second.

+

Syntax

+
timestamp()
+
+

Example

+
let v0 := timestamp()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure
+
+

Annotations

+

None.

+

number

+

(Expression::Number)

+

Description

+

Current block number.

+

Syntax

+
number()
+
+

Example

+
let v0 := number()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure
+
+

Annotations

+

None.

+

difficulty

+

(Expression::Difficulty)

+

Description

+

Pre-merge block difficulty. On post-merge chains this is the block’s prevrandao value.

+

Syntax

+
difficulty()
+
+

Example

+
let v0 := difficulty()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

gaslimit

+

(Expression::GasLimit)

+

Description

+

Block gas limit.

+

Syntax

+
gaslimit()
+
+

Example

+
let v0 := gaslimit()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure
+
+

Annotations

+

None.

+

basefee

+

(Expression::BaseFee)

+

Description

+

Current block’s EIP-1559 base fee per gas.

+

Syntax

+
basefee()
+
+

Example

+
let v0 := basefee()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

blobbasefee

+

(Expression::BlobBaseFee)

+

Description

+

Current block’s EIP-4844 blob base fee per gas.

+

Syntax

+
blobbasefee()
+
+

Example

+
let v0 := blobbasefee()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

blobhash

+

(Expression::BlobHash)

+

Description

+

Versioned hash of the blob at the given index in the current transaction’s blob list.

+

Syntax

+
blobhash($index[: <type>])
+
+

Example

+
let v1 := blobhash(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
indexi256Blob index; forward analysis widens to at least i64.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

blockhash

+

(Expression::BlockHash)

+

Description

+

Hash of the block with the given number. Per EVM, valid only for the most recent 256 blocks; outside that range the result is 0.

+

Syntax

+
blockhash($number[: <type>])
+
+

Example

+
let v1 := blockhash(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
numberi256Block number; forward analysis widens to at least i64.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

selfbalance

+

(Expression::SelfBalance)

+

Description

+

Balance (in wei) of the contract executing the current call frame. Cheaper than balance(address()).

+

Syntax

+
selfbalance()
+
+

Example

+
let v0 := selfbalance()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

gasprice

+

(Expression::GasPrice)

+

Description

+

Effective gas price of the current transaction.

+

Syntax

+
gasprice()
+
+

Example

+
let v0 := gasprice()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

calldataload

+

(Expression::CallDataLoad)

+

Description

+

Read 32 bytes from the current call’s calldata at the given offset. Reads past the end of calldata return zero bytes.

+

Syntax

+
calldataload($offset[: <type>])
+
+

Example

+
let v1 := calldataload(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
offseti256Byte offset into calldata.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

calldatasize

+

(Expression::CallDataSize)

+

Description

+

Length of the current call’s calldata, in bytes.

+

Syntax

+
calldatasize()
+
+

Example

+
let v0 := calldatasize()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure
+
+

Annotations

+

None.

+

returndatasize

+

(Expression::ReturnDataSize)

+

Description

+

Length of the most recently returned data buffer from a sub-call, in bytes. Modelled as pure per IR but reflects the last ExternalCall / Create result; consumers must respect that ordering.

+

Syntax

+
returndatasize()
+
+

Example

+
let v0 := returndatasize()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure (per IR; see Description)
+
+

Annotations

+

None.

+

codesize

+

(Expression::CodeSize)

+

Description

+

Size of the currently executing code, in bytes.

+

Syntax

+
codesize()
+
+

Example

+
let v0 := codesize()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure
+
+

Annotations

+

None.

+

extcodesize

+

(Expression::ExtCodeSize)

+

Description

+

Size of the code deployed at the given address, in bytes. Returns 0 for accounts with no deployed code.

+

Syntax

+
extcodesize($address[: <type>])
+
+

Example

+
let v1 := extcodesize(v0: i160)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
addressi256Account address; forward analysis widens to at least i160.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure
+
+

Annotations

+

None.

+

extcodehash

+

(Expression::ExtCodeHash)

+

Description

+

Keccak-256 hash of the code deployed at the given address. Returns 0 for non-existent accounts.

+

Syntax

+
extcodehash($address[: <type>])
+
+

Example

+
let v1 := extcodehash(v0: i160)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
addressi256Account address; forward analysis widens to at least i160.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

balance

+

(Expression::Balance)

+

Description

+

Balance (in wei) of the given account address. Use selfbalance for the contract executing the current call frame (cheaper).

+

Syntax

+
balance($address[: <type>])
+
+

Example

+
let v1 := balance(v0: i160)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
addressi256Account address; forward analysis widens to at least i160.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

mload

+

(Expression::MLoad)

+

Description

+

Read a 32-byte word from emulated EVM linear memory at offset. The word is read big-endian per EVM semantics. Pure per IR, but reads after writes return the new value; the memory passes track read/write dependencies separately.

+

Syntax

+
mload($offset[: <type>]) [/* <region> */]
+
+

Example

+
let v1 := mload(v0)
+let v2 := mload(v3) /* free_ptr */
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
offseti256Byte offset into linear memory; forward analysis widens to at least i64.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i32 when region is FreePointerSlot; i256 otherwisePure (per IR; see Description)
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
region: MemoryRegion/* scratch */ · /* free_ptr */ · /* dynamic */ (Unknown is suppressed)
+
+

Same tagging rules as mstore. The region also determines the result width: a load from FreePointerSlot produces an i32 since the FMP fits in a pointer-sized word.

+

sload

+

(Expression::SLoad)

+

Description

+

Read a 32-byte word from persistent contract storage at the given key. Pure per IR; reads after writes to the same slot return the new value.

+

Syntax

+
sload($key[: <type>]) [/* slot: 0x<hex> */]
+
+

Example

+
let v1 := sload(v0)
+let v2 := sload(v3) /* slot: 0x0 */
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
keyi256Storage slot.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure (per IR; see Description)
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
static_slot: Option<BigUint>/* slot: 0x<hex> */ when set; suppressed otherwise
+
+

Same tagging rules as sstore. The printer renders the annotation whenever the field is Some and the deduplicator’s canonicalizer partitions signatures by slot; no pass currently writes Some(...), however, so in present-day dumps the annotation is dormant.

+

tload

+

(Expression::TLoad)

+

Description

+

Read a 32-byte word from transient storage at the given key. Transient storage is wiped at the end of the transaction; pair with tstore.

+

Syntax

+
tload($key[: <type>])
+
+

Example

+
let v1 := tload(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
keyi256Transient storage slot.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure (per IR; see Description)
+
+

Annotations

+

None. The IR does not track a static slot for tload.

+

mapping_sload

+

(Expression::MappingSLoad)

+

Description

+

Compound load for a Solidity mapping element. Equivalent to mstore(0, key); mstore(32, slot); sload(keccak256(0, 64)) but emitted as a single outlined call after the compound_outlining pass recognizes the pattern (it fuses a keccak256_pair — itself produced by mem_opt’s keccak fusion — followed by an sload whose key has a single consumer). Only valid when the intermediate hash is used exclusively by this load.

+

Syntax

+
mapping_sload($key[: <type>], $slot[: <type>])
+
+

Example

+
let v2 := mapping_sload(v0: i160, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
keyi256Mapping key; often narrowed to i160 for address keys.
sloti256The mapping’s declared storage slot.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure (per IR; see Description)
+
+

Annotations

+

None. The fused statement’s effective storage slot is the keccak hash of the key and the declared slot, which is never a compile-time constant; no static_slot hint is surfaced.

+

dataoffset

+

(Expression::DataOffset)

+

Description

+

Offset of a named data segment within the deployed code. The identifier is a string carried in the IR’s id: String field; the linker resolves it to a concrete offset.

+

Syntax

+
dataoffset("<id>")
+
+

Example

+
let v0 := dataoffset("MyContract_deployed")
+
+

Operands

+

None — the identifier is a quoted string literal in the syntax position, not an operand.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
id: StringThe quoted identifier in the syntax position (not a comment annotation; it is the expression itself).
+
+

datasize

+

(Expression::DataSize)

+

Description

+

Size of a named data segment within the deployed code, in bytes. The identifier is resolved by the linker.

+

Syntax

+
datasize("<id>")
+
+

Example

+
let v0 := datasize("MyContract_deployed")
+
+

Operands

+

None — the identifier is a quoted string literal in the syntax position, not an operand.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
id: StringThe quoted identifier in the syntax position.
+
+

loadimmutable

+

(Expression::LoadImmutable)

+

Description

+

Read the value of a named immutable variable. Immutables are written once during contract construction by SetImmutable and read afterwards via this expression.

+

Syntax

+
loadimmutable("<key>")
+
+

Example

+
let v0 := loadimmutable("MyContract.owner")
+
+

Operands

+

None — the key is a quoted string literal in the syntax position.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
key: StringThe quoted identifier in the syntax position.
+
+

linkersymbol

+

(Expression::LinkerSymbol)

+

Description

+

Address of an external library, resolved by the linker. The path encodes the library’s source location and identifier.

+

Syntax

+
linkersymbol("<path>")
+
+

Example

+
let v0 := linkersymbol("contracts/Library.sol:L")
+
+

Operands

+

None — the path is a quoted string literal in the syntax position.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i160Pure
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
path: StringThe quoted path in the syntax position.
+
+

<func_name>

+

(Expression::Call; the printer emits func_<id> when no function name is registered)

+

Description

+

Internal function call. Invokes a user-defined function declared earlier in the same object; the mnemonic is the function’s Yul-level name, or func_<id> if the printer has no name registered for the FunctionId. Distinct from call and the other EVM call-opcode statements, which cross the contract boundary.

+

Syntax

+
<func_name>([$argument_0[: <type>], $argument_1[: <type>], …])
+
+

Example

+
let v3 := abi_decode_uint256(v0, v1, v2)
+let v4, v5 := returns_two(v0)           // multi-return via let multi-binding
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
argumentsVec<Value>Zero or more argument values, in declaration order; each operand may carry a : <type> suffix.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
One or more values, widths taken from the callee’s declared return types (or the inferred return widths, narrowed via the interprocedural pass). Falls back to i256 when the callee’s returns are unknown to type inference.Effectful — the simplifier treats every call as side-effectful regardless of callee body, so unused call bindings are not DCE’d. The transitive purity of the callee is not tracked at the IR level.
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
function: FunctionIdThe callee’s name in the syntax position (or func_<id> if the printer has no name registered).
+
+

Memory and storage writes

+

The six operations in this section all modify external state: emulated EVM linear memory, persistent storage, or transient storage. They are statements (not expressions) and they are never pure. Simplification and deduplication never reorder them with respect to each other or with respect to reverts; the memory passes treat them as the side-effect boundary for their analyses.

+

mstore

+

(Statement::MStore)

+

Description

+

Write a 32-byte word to emulated EVM linear memory at offset. The word is stored big-endian, matching EVM semantics; the codegen handles the byte swap on PolkaVM’s little-endian RISC-V target.

+

Syntax

+
mstore($offset[: <type>], $value[: <type>]) [/* <region> */]
+
+

Example

+
mstore(v0, v1)                    // Unknown region; no annotation printed
+mstore(v2, v3) /* scratch */      // offset proven to land in 0x00..0x3f
+mstore(v4, v5) /* free_ptr */     // offset is exactly 0x40
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
offseti256Byte offset into linear memory; forward analysis widens to at least i64.
valuei256The 32-byte word to store. Narrower values are zero-extended at codegen time.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
region: MemoryRegion/* scratch */ · /* free_ptr */ · /* dynamic */ (Unknown is suppressed)
+
+

Assigned at translation time from the constant offset (if any); consumed by mem_opt, FMP propagation, and byte-swap mode selection.

+

mstore8

+

(Statement::MStore8)

+

Description

+

Write a single byte to emulated EVM linear memory at offset. The low 8 bits of value are stored; the upper bits are ignored. The operation is otherwise identical to mstore: same operand shape, same region tag, same side-effect classification.

+

Syntax

+
mstore8($offset[: <type>], $value[: <type>]) [/* <region> */]
+
+

Example

+
mstore8(v0, v1: i8)             // value narrowed to i8 by type inference
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
offseti256Byte offset into linear memory; forward analysis widens to at least i64.
valuei256Only the low 8 bits are stored. Often narrowed to i8 by type inference.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
region: MemoryRegion/* scratch */ · /* free_ptr */ · /* dynamic */ (Unknown is suppressed)
+
+

Same tagging rules as mstore. Most mstore8s carry an Unknown region in practice because single-byte writes typically target offsets the translator cannot prove constant.

+

mcopy

+

(Statement::MCopy)

+

Description

+

Copy length bytes from src to dest within emulated EVM linear memory. The Yul builtin mcopy maps directly onto this statement; unlike mstore, it does not carry a region tag because the source and destination ranges may straddle multiple regions.

+

Syntax

+
mcopy($dest[: <type>], $src[: <type>], $length[: <type>])
+
+

Example

+
mcopy(v0, v1, v2)               // dest, src, length
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
desti256Destination byte offset in linear memory.
srci256Source byte offset in linear memory.
lengthi256Number of bytes to copy. Overlapping ranges follow EVM-defined memmove semantics.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None. mcopy carries no region tag because the source and destination ranges may straddle multiple regions, and no static-slot hint because the copy is not storage-bound.

+

sstore

+

(Statement::SStore)

+

Description

+

Write a 32-byte word to persistent contract storage at key. The operation is the durable counterpart of mstore: the value survives across transactions and is observable to subsequent calls to the contract.

+

Syntax

+
sstore($key[: <type>], $value[: <type>]) [/* slot: 0x<hex> */]
+
+

Example

+
sstore(v0, v1)
+sstore(v2, v3) /* slot: 0x0 */
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
keyi256Storage slot. May be a constant slot, a keccak-derived slot for mappings or dynamic arrays, or an arbitrary expression.
valuei256The 256-bit word to store.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
static_slot: Option<BigUint>/* slot: 0x<hex> */ when set; suppressed otherwise
+
+

The printer renders the annotation whenever the field is Some, and the deduplicator’s canonicalizer and mapping-fusion analyses consume it as part of the signature. No pass currently writes Some(...), so the annotation is dormant in present-day dumps; when absent, alias and dedup analyses fall back to the conservative “may alias any slot” assumption.

+

tstore

+

(Statement::TStore)

+

Description

+

Write a 32-byte word to transient storage at key. Transient storage is wiped at the end of the transaction, so tstore is the right primitive for per-transaction bookkeeping (reentrancy guards, cached results) without the gas cost of sstore on EVM. On PolkaVM the transient backing store is provided by pallet-revive.

+

Syntax

+
tstore($key[: <type>], $value[: <type>])
+
+

Example

+
tstore(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
keyi256Transient storage slot.
valuei256The 256-bit word to store.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None. Unlike sstore, the IR does not track a static slot for tstore: transient storage’s short-lived lifetime makes the slot-aware optimizations less valuable, and the translator does not produce the annotation.

+

mapping_sstore

+

(Statement::MappingSStore)

+

Description

+

Compound store for a Solidity mapping element. Equivalent to the three-operation sequence mstore(0, key); mstore(32, slot); sstore(keccak256(0, 64), value) but emitted as a single outlined statement after the compound_outlining pass recognizes the pattern (it fuses a keccak256_pair followed by an sstore whose key has a single consumer). Only valid when the intermediate hash is not observed by any other statement.

+

Syntax

+
mapping_sstore($key[: <type>], $slot[: <type>], $value[: <type>])
+
+

Example

+
mapping_sstore(v0: i160, v1, v2)        // address key, declared slot, value
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
keyi256Mapping key. Often narrowed to i160 for address keys.
sloti256The mapping’s declared storage slot. Typically a small constant.
valuei256The value to store at the computed storage location.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None. mapping_sstore deliberately drops the static_slot annotation that the original sstore may have carried, because the fused statement’s effective slot is the keccak hash of the key and the declared slot, which is never a compile-time constant.

+

Bulk copies

+

Multi-byte memory copies from the five EVM-accessible byte sources (code, external code, returndata, embedded data, and calldata) into emulated EVM linear memory. All five take the same shape: a destination memory offset, a source offset, and a length. They are effectful and act as opaque barriers to the memory passes.

+

codecopy

+

(Statement::CodeCopy)

+

Description

+

Copy length bytes from the currently executing code at offset into emulated EVM linear memory at dest. Reads past the end of code yield zero bytes.

+

Syntax

+
codecopy($dest[: <type>], $offset[: <type>], $length[: <type>])
+
+

Example

+
codecopy(v0, v1, v2)
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
desti256Destination byte offset in linear memory.
offseti256Source byte offset in the executing code.
lengthi256Number of bytes to copy.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None.

+

extcodecopy

+

(Statement::ExtCodeCopy)

+

Description

+

Copy length bytes from the code at address starting at offset into emulated EVM linear memory at dest. Reads beyond the code yield zero bytes; non-existent accounts yield all zeros.

+

Syntax

+
extcodecopy($address[: <type>], $dest[: <type>], $offset[: <type>], $length[: <type>])
+
+

Example

+
extcodecopy(v0: i160, v1, v2, v3)
+
+

Operands

+
+ + + + + + + + + + +
NameTypeNotes
addressi256Account whose code to read; narrows to i160.
desti256Destination byte offset in linear memory.
offseti256Source byte offset in the external code.
lengthi256Number of bytes to copy.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None.

+

returndatacopy

+

(Statement::ReturnDataCopy)

+

Description

+

Copy length bytes from the most recent sub-call’s return data starting at offset into emulated EVM linear memory at dest. Per EVM, reads past the return data’s end revert; the memory passes treat this as a potential trap site.

+

Syntax

+
returndatacopy($dest[: <type>], $offset[: <type>], $length[: <type>])
+
+

Example

+
returndatacopy(v0, v1, v2)
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
desti256Destination byte offset in linear memory.
offseti256Source byte offset in the return-data buffer.
lengthi256Number of bytes to copy.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful (may revert on out-of-range reads, per EVM)
+
+

Annotations

+

None.

+

datacopy

+

(Statement::DataCopy)

+

Description

+

Copy length bytes from an embedded data segment starting at offset into emulated EVM linear memory at dest. The source segment is resolved by the linker, typically used to pull constants compiled into the bytecode into runtime memory.

+

Syntax

+
datacopy($dest[: <type>], $offset[: <type>], $length[: <type>])
+
+

Example

+
datacopy(v0, v1, v2)
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
desti256Destination byte offset in linear memory.
offseti256Source byte offset in the data segment.
lengthi256Number of bytes to copy.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None.

+

calldatacopy

+

(Statement::CallDataCopy)

+

Description

+

Copy length bytes from the current call’s calldata starting at offset into emulated EVM linear memory at dest. Reads past the end of calldata yield zero bytes.

+

Syntax

+
calldatacopy($dest[: <type>], $offset[: <type>], $length[: <type>])
+
+

Example

+
calldatacopy(v0, v1, v2)
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
desti256Destination byte offset in linear memory.
offseti256Source byte offset in calldata.
lengthi256Number of bytes to copy.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None.

+

Bindings and wrappers

+

The statements that bind SSA values, hold loose expressions evaluated for their side effects, and write to immutable storage. Every pure expression in the appendix’s earlier sections appears on the right-hand side of one of these statements (almost always let).

+

let

+

(Statement::Let)

+

Description

+

SSA binding: evaluate an expression and bind its result(s) to a list of fresh value ids. The let statement is the only mechanism by which pure expressions enter the value namespace; every v<id> in a dump was produced by a let (or by a value-yielding control-flow statement or by a parameter at function entry).

+

Syntax

+
let $binding_0[, $binding_1, …] := $expression
+
+

Example

+
let v3 := add(v0, v1)
+let v4, v5 := if v2 [v0, v1] { … } else { … }   // multi-binding from a value-yielding If
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
bindingsVec<ValueId>One or more fresh SSA ids to bind. Most expressions produce one value; control-flow statements may produce several.
valueExpressionThe right-hand side; see any of the Pure expression entries.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None directly — the bound ids carry the expression’s result(s)Effectful (binding establishment); the right-hand side’s purity is independent
+
+

Annotations

+

None.

+

Expression statement

+

(Statement::Expression)

+

Description

+

Wraps an expression evaluated for its observable consequences but whose value is not bound. Typically a user-defined function call (Expression::Call) whose return values the source code discarded, or another Yul expression statement that does not have a dedicated Statement:: variant. EVM external calls (call, delegatecall, etc.) and contract creation (create, create2) translate to dedicated Statement::ExternalCall and Statement::Create variants, not through this wrapper.

+

Syntax

+
$expression
+
+

Example

+
keccak256(v0, v1)           // hash computed but not bound to a value
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
expressionExpressionAny expression; result is discarded.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful (per its statement position)
+
+

Annotations

+

None.

+

setimmutable

+

(Statement::SetImmutable)

+

Description

+

Write an immutable variable during contract construction. Immutables are written once in the constructor and read later via loadimmutable. The key is a string identifier resolved by the linker.

+

Syntax

+
setimmutable("<key>", $value[: <type>])
+
+

Example

+
setimmutable("MyContract.owner", v0: i160)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
valuei256The value to store; the key is a quoted string literal in the syntax position.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
key: StringThe quoted identifier in the syntax position.
+
+

Structured control flow

+

The IR’s control flow is structured: if, switch, and for are statements with explicit nested regions, each carrying input values and yielding output values. The three jump-like statements (break, continue, leave) are scoped to their nearest enclosing construct. Nested blocks create lexical scope without otherwise changing control flow.

+

if

+

(Statement::If)

+

Description

+

Conditional execution with optional value yields. The then region runs when condition is non-zero; the else region runs otherwise. If outputs is non-empty, both regions must yield the same number of values and the statement is bound by a let.

+

Syntax

+
if $condition[: <type>] [[$input_0, $input_1, …]] { … } [else { … }]
+
+

Example

+
if v0 {
+    sstore(v1, v2)
+}
+
+let v5, v6 := if v3 [v1, v2] {
+    let v7 := add(v2, 0x1)
+    yield v1, v7
+} else {
+    yield v1, v2
+}
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
conditioni256Branch selector; non-zero takes the then region. Often narrowed to i1.
inputsVec<Value>Values threaded into both regions, printed in square brackets after the condition.
(regions)The then_region is mandatory; the else_region is optional and, when absent, implicitly yields the inputs unchanged.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None for the statement form; for the value-yielding form, one value per outputs binding, types taken from the yielded valuesEffectful (control flow)
+
+

Annotations

+

None.

+

switch

+

(Statement::Switch)

+

Description

+

Multi-way dispatch on a scrutinee value. Each case matches a specific constant and runs its region; an optional default region catches non-matching values. Like if, switch may yield values via outputs and accept thread-through values via inputs.

+

Syntax

+
switch $scrutinee[: <type>] [[$input_0, …]]
+case 0x<hex> {
+    …
+}
+[case 0x<hex> {
+    …
+} …]
+[default {
+    …
+}]
+
+

Example

+
switch v0
+case 0x0 {
+    sstore(v1, v2)
+}
+case 0x1 {
+    sstore(v1, v3)
+}
+default {
+    invalid()
+}
+
+

Operands

+
+ + + + + + + + + + +
NameTypeNotes
scrutineei256The value to compare against each case.
inputsVec<Value>Values threaded into every case and default region.
casesVec<SwitchCase>Each case carries a constant value: BigUint and a region.
(default)Optional fall-through region.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None for the statement form; one value per outputs binding for the value-yielding formEffectful (control flow)
+
+

Annotations

+

None.

+

for

+

(Statement::For)

+

Description

+

Structured loop with explicit loop-carried variables. Each iteration evaluates condition_statements followed by condition; if the condition is non-zero, the body region runs, then the post region runs, and the loop iterates. Loop-carried variables are passed as SSA values through each region. break exits the loop and continue jumps to the post region.

+

Syntax

+
for { $variable_0 := $initial_0[, …] }
+    [// condition_statements:
+        …]
+    $condition
+    { // post
+        …
+    }
+{
+    … body …
+}
+
+

Example

+
for { v1 := 0x0 }
+    lt(v1, 0xa)
+    { // post
+        let v3 := add(v1, 0x1)
+        yield v3
+    }
+{
+    sstore(v1, v2)
+    yield v1
+}
+
+

Operands

+
+ + + + + + + + + + + + + + +
NameTypeNotes
initial_valuesVec<Value>Starting values for the loop-carried variables.
loop_variablesVec<ValueId>SSA ids visible inside condition, body, and post.
condition_statementsVec<Statement>Statements evaluated each iteration before the condition expression; emitted into the loop header block. Printed only when non-empty, behind a // condition_statements: comment.
conditionExpressionRe-evaluated each iteration; non-zero continues, zero exits.
bodyRegionLoop body; yields current loop-carried values.
post_input_variablesVec<ValueId>Input SSA ids for the post region (one per loop-carried variable); receive the body’s yielded values merged with continue-site values via phi nodes in the LLVM codegen.
postRegionRuns after each body iteration (and after continue); yields updated loop-carried values.
outputsVec<ValueId>Final loop-carried values after exit.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None for the statement form; one value per outputs binding for the value-yielding formEffectful (control flow)
+
+

Annotations

+

None.

+

break

+

(Statement::Break)

+

Description

+

Exit the innermost enclosing for loop. Carries the current values of loop-carried variables at the break point; these become the loop’s outputs.

+

Syntax

+
break
+
+

Example

+
if v0 { break }
+
+

Operands

+

None in the printed form; the IR’s values: Vec<Value> field carries the loop-carried values internally.

+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful (control flow)
+
+

Annotations

+

None.

+

continue

+

(Statement::Continue)

+

Description

+

Skip to the post region of the innermost enclosing for loop. Like break, carries the current values of loop-carried variables internally.

+

Syntax

+
continue
+
+

Example

+
if v0 { continue }
+
+

Operands

+

None in the printed form; the IR’s values field carries the loop-carried values internally.

+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful (control flow)
+
+

Annotations

+

None.

+

leave

+

(Statement::Leave)

+

Description

+

Exit the current function, returning the listed values as the function’s return values. The Yul-level leave keyword translates directly to this statement; the inlining pass eliminates intra-function leaves where possible via the exit-flag transformation.

+

Syntax

+
leave [[$value_0[: <type>], $value_1[: <type>], …]]
+
+

Example

+
leave [v0, v1]              // returns v0 and v1 from the function
+leave                       // returns nothing (void function)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
return_valuesVec<Value>Empty for void functions; otherwise one entry per declared return.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful (control flow)
+
+

Annotations

+

None.

+

Nested block

+

(Statement::Block)

+

Description

+

A lexical scope without conditional or iterative behavior. The body is a region; control falls through after the region’s statements complete. Used to bound the visibility of inner bindings.

+

Syntax

+
{
+    …
+}
+
+

Example

+
{
+    let v0 := add(v1, v2)
+    sstore(v3, v0)
+}                           // v0 is no longer in scope here
+
+

Operands

+

None — the body is a region, not an operand.

+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful (per the body’s contents)
+
+

Annotations

+

None.

+

External interaction

+

Statements that cross the contract boundary: external calls (four kinds), contract creation (two kinds), and event log emission. All produce or rely on external state and act as barriers to memory and storage analyses.

+

call

+

(Statement::ExternalCall with CallKind::Call)

+

Description

+

Standard external call that may transfer value. Reads args_length bytes from emulated EVM linear memory at args_offset as calldata, executes the target, and writes up to ret_length bytes of return data into linear memory at ret_offset. The boolean result indicates success.

+

Syntax

+
let $result := call($gas[: <type>], $address[: <type>], $value[: <type>], $args_offset[: <type>], $args_length[: <type>], $ret_offset[: <type>], $ret_length[: <type>])
+
+

Example

+
let v8 := call(v0, v1: i160, v2, v3, v4, v5, v6)
+
+

Operands

+
+ + + + + + + + + + + + + +
NameTypeNotes
gasi256Gas to forward to the target.
addressi256Callee address; narrows to i160.
valuei256Wei to transfer with the call.
args_offseti256Calldata source offset in linear memory.
args_lengthi256Calldata length in bytes.
ret_offseti256Return-data destination offset in linear memory.
ret_lengthi256Maximum return-data length.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 (success flag: 1 on success, 0 on revert/error; narrowable to i1)Effectful
+
+

Annotations

+

None.

+

callcode

+

(Statement::ExternalCall with CallKind::CallCode)

+

Description

+

Deprecated EVM opcode that executes the callee’s code in the caller’s context but with the callee’s storage. Preserved for Solidity compatibility; new code should use delegatecall.

+

Syntax

+
let $result := callcode($gas[: <type>], $address[: <type>], $value[: <type>], $args_offset[: <type>], $args_length[: <type>], $ret_offset[: <type>], $ret_length[: <type>])
+
+

Example

+
let v8 := callcode(v0, v1: i160, v2, v3, v4, v5, v6)
+
+

Operands

+

Same shape as call.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 (success flag; narrowable to i1)Effectful
+
+

Annotations

+

None.

+

delegatecall

+

(Statement::ExternalCall with CallKind::DelegateCall)

+

Description

+

Execute the callee’s code in the caller’s context: same storage, same sender, same call value. The standard mechanism for library calls and proxy patterns. No value operand (the caller’s call value is inherited).

+

Syntax

+
let $result := delegatecall($gas[: <type>], $address[: <type>], $args_offset[: <type>], $args_length[: <type>], $ret_offset[: <type>], $ret_length[: <type>])
+
+

Example

+
let v7 := delegatecall(v0, v1: i160, v2, v3, v4, v5)
+
+

Operands

+

Same shape as call minus the value operand.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 (success flag; narrowable to i1)Effectful
+
+

Annotations

+

None.

+

staticcall

+

(Statement::ExternalCall with CallKind::StaticCall)

+

Description

+

Read-only external call. Any state modification in the callee (including nested calls) causes the call to revert. No value operand.

+

Syntax

+
let $result := staticcall($gas[: <type>], $address[: <type>], $args_offset[: <type>], $args_length[: <type>], $ret_offset[: <type>], $ret_length[: <type>])
+
+

Example

+
let v7 := staticcall(v0, v1: i160, v2, v3, v4, v5)
+
+

Operands

+

Same shape as call minus the value operand.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 (success flag; narrowable to i1)Effectful (no state writes, but still an external boundary and may revert)
+
+

Annotations

+

None.

+

create

+

(Statement::Create with CreateKind::Create)

+

Description

+

Deploy a new contract with the given init-code bytes, transferring value wei from the caller. The new contract’s address is derived from the caller’s address and nonce; on failure the result is 0.

+

Syntax

+
let $result := create($value[: <type>], $offset[: <type>], $length[: <type>])
+
+

Example

+
let v4 := create(v0, v1, v2)
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
valuei256Wei to transfer to the new contract.
offseti256Linear-memory offset of the init code.
lengthi256Length of the init code in bytes.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 (created address; narrowable to i160 on success, 0 on failure)Effectful
+
+

Annotations

+

None.

+

create2

+

(Statement::Create with CreateKind::Create2)

+

Description

+

Deploy a new contract with a deterministic address derived from the caller’s address, the salt, and the init-code hash. Same operand shape as create plus an additional salt.

+

Syntax

+
let $result := create2($value[: <type>], $offset[: <type>], $length[: <type>], $salt[: <type>])
+
+

Example

+
let v5 := create2(v0, v1, v2, v3)
+
+

Operands

+

Same as create plus salt: i256.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 (created address; narrowable to i160 on success, 0 on failure)Effectful
+
+

Annotations

+

None.

+

log<N>

+

(Statement::Log)

+

Description

+

Emit an event log entry. The mnemonic suffix <N> is the number of indexed topics (0 through 4), determined by the length of the IR’s topics field. The data portion is read from length bytes of emulated EVM linear memory at offset.

+

Syntax

+
log<N>($offset[: <type>], $length[: <type>][, $topic_0[: <type>], …])
+
+

Example

+
log0(v0, v1)
+log2(v0, v1, v2, v3)            // two topics
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
offseti256Data source offset in linear memory.
lengthi256Data length in bytes.
topicsVec<Value>Zero to four indexed topic values; the length determines the mnemonic suffix.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None.

+

Termination

+

Statements that end the current call frame. Three plain forms (return, revert, stop), two unconditional traps (invalid, selfdestruct), and three outlined revert variants that encode common Solidity error patterns into single nodes that can be deduplicated across call sites.

+

return

+

(Statement::Return)

+

Description

+

End the current call frame successfully, returning length bytes from emulated EVM linear memory at offset as the return data.

+

Syntax

+
return($offset[: <type>], $length[: <type>])
+
+

Example

+
return(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
offseti256Return-data source offset.
lengthi256Return-data length.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+

None.

+

revert

+

(Statement::Revert)

+

Description

+

End the current call frame with a revert, undoing all state changes made during the call, and returning length bytes of revert data from emulated EVM linear memory at offset.

+

Syntax

+
revert($offset[: <type>], $length[: <type>])
+
+

Example

+
revert(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
offseti256Revert-data source offset.
lengthi256Revert-data length.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+

None.

+

stop

+

(Statement::Stop)

+

Description

+

End the current call frame successfully with empty return data.

+

Syntax

+
stop()
+
+

Example

+
stop()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+

None.

+

invalid

+

(Statement::Invalid)

+

Description

+

Unconditional invalid-opcode trap. Consumes all remaining gas and reverts. Used for unreachable branches and assertion failures.

+

Syntax

+
invalid()
+
+

Example

+
invalid()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+

None.

+

selfdestruct

+

(Statement::SelfDestruct)

+

Description

+

End the current call frame and transfer the contract’s remaining balance to address. Post-Cancun, the contract storage is not deleted (selfdestruct is effectively deprecated; the opcode still exists for legacy compatibility).

+

Syntax

+
selfdestruct($address[: <type>])
+
+

Example

+
selfdestruct(v0: i160)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
addressi256Recipient of the contract’s balance; narrows to i160.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+

None.

+

panic_revert

+

(Statement::PanicRevert)

+

Description

+

Outlined Solidity panic revert. Equivalent to writing the Panic(uint256) ABI encoding (selector 0x4e487b71 plus the panic code) into emulated EVM linear memory and reverting, but emitted as a single statement that lowers to one outlined helper call. Common panic codes: 0x01 assertion failure, 0x11 arithmetic overflow, 0x12 division by zero, 0x32 array-out-of-bounds, 0x41 memory overflow.

+

Syntax

+
panic_revert(0x<hex>)
+
+

Example

+
panic_revert(0x11)              // arithmetic overflow
+
+

Operands

+

None — the panic code is stored as a u8 field on the IR, not an SSA operand.

+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
code: u8The panic code in 0x<hex> form (two hex digits, zero-padded).
+
+

error_string_revert

+

(Statement::ErrorStringRevert)

+

Description

+

Outlined Solidity Error(string) revert. Equivalent to writing the Error selector (0x08c379a0), the string offset and length, and up to four 32-byte data words into emulated EVM linear memory and reverting. The string length and the data words are stored as compile-time fields; no SSA operands.

+

Syntax

+
error_string_revert(<length>, <N>_words)
+
+

Example

+
error_string_revert(12, 1_words)        // 12-byte string in one 32-byte word
+
+

Operands

+

None — the string length and data are compile-time fields, not SSA operands.

+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+
+ + + + + + + + +
Source fieldPrinted as
length: u8The string length in bytes, in the first syntax position.
data: Vec<BigUint>The number of 32-byte data words (1–4), printed as <N>_words in the second syntax position. The actual data is stored separately and not shown in the printed form.
+
+

custom_error_revert

+

(Statement::CustomErrorRevert)

+

Description

+

Outlined Solidity custom-error revert. Encodes the error selector (left-shifted by 224 bits) and zero to three argument values into scratch memory and reverts. No FMP load is needed; the encoding uses the scratch region at offset 0.

+

Syntax

+
custom_error_revert(0x<hex>, [$arg_0, $arg_1, …])
+
+

Example

+
custom_error_revert(0xa28c4c1100000000000000000000000000000000000000000000000000000000, [v0, v1])
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
argumentsVec<Value>0–3 argument values; the selector is a compile-time field.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
selector: BigUintThe 4-byte error selector shifted left by 224 bits, printed in hex in the first syntax position.
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/docs/developer_guide/newyork_optimizer.html b/docs/developer_guide/newyork_optimizer.html new file mode 100644 index 000000000..88fc8069d --- /dev/null +++ b/docs/developer_guide/newyork_optimizer.html @@ -0,0 +1,523 @@ + + + + + + The newyork optimizer - revive compiler book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

Keyboard shortcuts

+
+

Press or to navigate between chapters

+

Press S or / to search in the book

+

Press ? to show this help

+

Press Esc to hide this help

+
+
+
+
+ + + + + + + + + + + + + +
+ +
+
+ + + + + + + +
+
+

The newyork optimizer

+

The newyork crate (crates/newyork/) introduces an additional intermediate representation (IR) layer between Yul and LLVM IR. It enables domain-specific optimizations that neither solc nor LLVM can perform on their own, because they lack semantic knowledge about the cross-domain compilation from EVM to PolkaVM.

+
+

Note

+

The newyork optimizer is experimental. It is gated behind the RESOLC_USE_NEWYORK=1 environment variable (for standard JSON mode) or the --newyork CLI flag, and not yet enabled by default.

+
+

Motivation

+

The EVM and PolkaVM are fundamentally different machines:

+
+ + + + + + + + + + +
PropertyEVMPolkaVM (RISC-V)
Word size256-bit64-bit
EndiannessBig-endianLittle-endian
ArchitectureStack machineRegister-based
Memory modelLinear with free pointer conventionFlat address space
+
+

solc optimizes Yul IR for EVM gas costs on a 256-bit big-endian stack machine. LLVM, on the other hand, operates at too low a level to understand EVM memory semantics or Solidity patterns. By the time Yul reaches LLVM IR, the high-level intent is lost.

+

The newyork IR sits between these two worlds and recovers enough semantic information to make optimization decisions that neither compiler can make alone.

+

Pipeline overview

+
                    ┌──────────────────────────────────────────────────┐
+Yul AST ──────────► │                  newyork IR                      │ ──► LLVM IR ──► RISC-V
+            from_yul│                                                  │ to_llvm
+                    │  1. inline                                       │
+                    │  2. simplify (pass 1)                            │
+                    │  3. dedup (exact + fuzzy)                        │
+                    │  4. mem_opt + fmp_prop + keccak_fold             │
+                    │  5. simplify (pass 2)                            │
+                    │  6. compound_outlining + guard_narrow            │
+                    │  7. simplify (pass 3)                            │
+                    │  8. dedup (exact + fuzzy, pass 2)                │
+                    │  ── recursive on subobjects ──                   │
+                    │  9. heap_opt (analysis)                          │
+                    │ 10. type_inference (4 iterative rounds)          │
+                    │ 11. validate                                     │
+                    └──────────────────────────────────────────────────┘
+
+

The optimizer runs the following passes in order:

+
    +
  1. Inlining – custom heuristics tuned for PolkaVM call overhead, with Tarjan SCC-based recursion detection and quadratic leave-overhead modeling.
  2. +
  3. Simplify (pass 1) – constant folding, algebraic identities, strength reduction (mul by power-of-2 to shl), copy propagation, dead code elimination, environment read CSE (callvalue, caller, origin, etc.), and revert pattern outlining (panic selectors, custom error selectors).
  4. +
  5. Function deduplication – exact structural match, then fuzzy dedup (functions differing only in literal constants are parameterized and merged, up to 4 differing positions).
  6. +
  7. Memory optimization – load-after-store elimination, keccak256 fusion (mstore + keccak256 sequences into Keccak256Single/Keccak256Pair nodes), free memory pointer propagation (replaces mload(0x40) with a known constant), and constant keccak256 folding (precomputes hashes of compile-time-constant inputs).
  8. +
  9. Simplify (pass 2) – cleans up dead code and new constant expressions exposed by memory optimization and keccak folding.
  10. +
  11. Compound outlining – detects keccak256_pair + sload/sstore sequences and fuses them into MappingSLoad/MappingSStore IR nodes, eliminating intermediate hash values. Guard narrowing – detects if gt(val, MASK) { revert } and iszero(eq(val, and(val, MASK))) patterns and inserts AND-mask narrowing, giving type inference proof that values fit in fewer bits.
  12. +
  13. Simplify (pass 3) – propagates opportunities created by compound outlining and guard narrowing.
  14. +
  15. Function deduplication (pass 2) – catches new duplicates exposed by guard narrowing and compound outlining canonicalization.
  16. +
  17. Heap analysis – analyzes memory access patterns (alignment, static offsets, taintedness, escaping regions) to determine which accesses can use native little-endian layout, skipping byte-swap operations. Uses GCD-based alignment propagation and per-region taint tracking.
  18. +
  19. Type inference – narrows 256-bit values to smaller widths (I1, I8, I32, I64, I128, I160) where provable. Runs iteratively for up to 4 cascading refinement rounds, combining forward min-width propagation, backward use-context demands, transparent-operation demand propagation, and interprocedural parameter/return narrowing.
  20. +
  21. Validation – checks SSA well-formedness (use-before-def, multiple definitions), yield count consistency, and function reference correctness.
  22. +
+

Steps 1-8 run recursively on subobjects (deployed contract code), where optimization impact is greatest. Steps 9-11 run on the full object tree.

+

IR design

+

The newyork IR is an SSA form with structured control flow, inspired by MLIR’s SCF dialect. Key design choices:

+
    +
  • Explicit types with address spaces: Every value carries a bit-width (I1, I8, I32, I64, I128, I160, I256) and pointers carry address space information (Heap, Stack, Storage, Code). All values start as I256 and are narrowed by type inference.
  • +
  • Pure expressions vs. effectful statements: Expressions compute values without side effects; statements perform memory, storage, or control flow effects. This separation simplifies analysis and rewriting.
  • +
  • Semantic annotations: Memory operations are tagged with region information (Scratch, FreePointerSlot, Dynamic). Storage operations carry static slot values when known at compile time.
  • +
  • Structured control flow: If, Switch, and For nodes preserve the high-level structure from Yul, with explicit region arguments and yields for value flow across control edges.
  • +
+

For per-operation detail — printed syntax, operand and result types, and more — see the newyork IR reference.

+

Key optimizations explained

+

Type narrowing

+

EVM operates on 256-bit words, but most values in practice fit in 32 or 64 bits. The type inference pass performs bidirectional analysis:

+
    +
  • Forward: computes minimum width from literal values and operation semantics (e.g., add(I64, I8) produces I65, rounded up to I128).
  • +
  • Backward use tracking: classifies each value’s uses into 9 context categories (MemoryOffset, MemoryValue, StorageAccess, Comparison, Arithmetic, FunctionArg, FunctionReturn, ExternalCall, General). All categories conservatively demand the full I256 width by default; the categorisation is what enables the interprocedural phase to selectively relax the demand for narrowed function arguments. Earlier versions narrowed directly from the use category, but that was unsound for memory offsets — mload(2^128) aliased to mload(0) because the bounds check ran on an already-truncated value (commit ccca38df).
  • +
  • Transparent demand propagation: for modular-arithmetic operations (Add, Sub, Mul, And, Or, Xor), propagates narrow demands backward through operands, exploiting the property that trunc(op(a,b), N) == op(trunc(a,N), trunc(b,N)).
  • +
  • Interprocedural: iteratively narrows function parameter and return types in up to four rounds, combining four narrowing strategies — body-driven parameter narrowing, caller-driven parameter narrowing, forward-based return narrowing, and demand-based return narrowing — and re-running full inference between rounds. Parameters are clamped to at least I32 (XLEN on PolkaVM).
  • +
+

This allows LLVM to emit native 32/64-bit instructions instead of software-emulated 256-bit arithmetic, and eliminates expensive multi-instruction comparison sequences (16-20 RISC-V instructions for i256 comparisons reduced to 1-2 for i64).

+

Guard narrowing

+

Solidity emits runtime guards that prove values fit in narrow ranges (e.g., address validation via if gt(val, 2^160-1) { revert }). The guard narrowing pass detects these patterns and inserts explicit AND-mask narrowing after the guard. This gives downstream type inference proof that the value fits in fewer bits, enabling cascading narrowing of comparisons, arithmetic, and memory operations that use the guarded value.

+

Two pattern families are recognized:

+
    +
  • GT-based guards: if gt(val, MASK) { <terminates> } where MASK is a boundary value like 2^N - 1
  • +
  • EQ-based guards: iszero(eq(val, and(val, MASK))) patterns common in Solidity’s address validation
  • +
+

Heap optimization

+

PVM doesn’t provide EVM-compatible linear memory, so the compiler emulates it using a byte buffer with byte-swap operations for big-endian compatibility. The heap analysis pass determines which memory accesses can use native little-endian layout by analyzing access patterns:

+
    +
  • Tracks alignment and static offset information for all memory accesses using GCD-based propagation
  • +
  • Propagates taintedness when addresses escape to external calls, are written by external sources (codecopy, calldatacopy), or use unaligned access patterns
  • +
  • Tracks variable-accessed offsets to prevent mode mismatches between native and byte-swap accesses to the same location
  • +
  • Handles loop-carried variables conservatively (marked as non-literal to prevent false constant propagation)
  • +
+

The codegen backend supports four memory access modes: AllNative (all accesses skip byte-swap), InlineNative (constant-offset accesses use native layout), InlineByteSwap (constant-offset accesses use inline byte-swap), and ByteSwap (standard byte-swap through helper functions).

+

Free memory pointer range proof

+

The Solidity free memory pointer (mload(0x40)) always fits in 32 bits — sbrk enforces FMP < heap_size on every store, regardless of which memory mode the contract uses. After every literal mload(0x40), codegen emits a trunc N → zext 256 chain (where N is bits(heap_size - 1), e.g. 17 for the 131,072-byte default heap). The trunc-extend round-trip is a no-op semantically, but exposes the bound to LLVM’s IPSCCP range analysis, which then propagates it through every add(fmp, K) and eliminates the trailing safe_truncate_int_to_xlen overflow checks at every FMP-derived offset use. Despite only affecting a single codegen site, this is the single largest contributor to the optimizer’s code-size reduction.

+

A subtle gating issue: the byte-order mode (InlineNative / ByteSwap) and the value bound on FMP are independent invariants. fmp_native_safe() and can_use_native(0x40) protect against mixing little-endian writers with big-endian readers on the FMP slot, which would corrupt the stored offset; the value bound is unrelated and holds in every mode. Earlier versions of the codegen gated the load-side range proof on the byte-order checks, which suppressed the optimization for any contract with dynamic memory accesses. Decoupling the two reasonings — keeping the byte-order gate on the store side, dropping it from the load-side range proof — is what makes the multiplicative IPSCCP effect available to OZ-class contracts.

+

Soundness traps for FMP optimizations

+

The FMP slot is small but easy to mis-optimize. The codebase carries several +regression tests for previously-found soundness bugs; new FMP-related changes +should be verified against them:

+
    +
  • mload_at_fmp_slot (crates/integration/src/tests.rs, fixed in +1fd6063c): tests mload(0x40) and offsets near it (0x21, 0x3f, 0x42) +on a contract that also performs dynamic mloads. Catches byte-order mismatches +when one access goes native (LE) and another goes byte-swap (BE). The fix +blocks native mode for FMP whenever has_dynamic_accesses is true.
  • +
  • mload_huge_offset_traps (fixed in ccca38df): tests that +mload(2^128) and mload(2^255) correctly trap via the gas-exhaustion +path. Catches UseContext::MemoryOffset narrowing bypassing the +safe_truncate_int_to_xlen overflow check at the use site — +mload(2^128) aliasing to mload(0) and returning the zero-initialized +scratch slot. The fix classifies MemoryOffset as I256 so it doesn’t +drive narrowing; the bounds check at the use site catches out-of-range.
  • +
  • FMP i32 shortcut removal (dbcfc921): an earlier optimization stored +only 4 bytes at offset 0x40 instead of the full 32-byte EVM word, breaking +any inline assembly using mstore(0x40, ...) for non-FMP purposes. +Caused a cascade of 249/251 retester failures via allocator corruption. +No dedicated regression test was added — the retester corpus was sufficient +coverage — but the lesson generalizes: writes to 0x40 must store the full +word, even when the high bits are provably zero, because the slot is part +of the same 32-byte memory region read by other code.
  • +
+

When adding an optimization that touches FMP, distinguish carefully between: +the byte-order encoding at the slot (must be consistent between writers +and readers), the value bound (FMP < heap_size, always true), and the +stored width (must be 32 bytes for mstore(0x40, ...), even though only +the low N bits are non-zero).

+

Keccak256 fusion and folding

+

Two complementary optimizations target the common Solidity pattern of hashing values for storage slot computation:

+
    +
  • Fusion: Recognizes mstore + keccak256 sequences and fuses them into dedicated IR nodes (Keccak256Single, Keccak256Pair), eliminating intermediate memory traffic.
  • +
  • Constant folding: When all keccak256 inputs are compile-time constants, the hash is computed at compile time and replaced with a literal.
  • +
+

Compound outlining (mapping access)

+

Solidity mapping accesses follow a predictable pattern: hash a key with a storage slot, then load/store the result. The compound outlining pass detects keccak256_pair(key, slot) followed by sload/sstore and fuses them into MappingSLoad/MappingSStore IR nodes. These are lowered to outlined helper functions (__revive_mapping_sload, __revive_mapping_sstore) that combine the hash computation with the storage operation, eliminating intermediate values and redundant byte-swaps.

+

Fuzzy function deduplication

+

Solidity generates many near-identical functions that differ only in literal constants (e.g., error selectors, storage slot offsets). Fuzzy deduplication identifies such groups, parameterizes the differing literals (up to 4 positions), and replaces all copies with calls to a single shared implementation.

+

Revert pattern outlining

+

The simplify pass detects common revert patterns and replaces them with compact IR nodes:

+
    +
  • Panic reverts: Solidity Panic(uint256) sequences (selector 0x4e487b71 + encoded panic code) are collapsed into PanicRevert { code } nodes, which are lowered to shared helper functions.
  • +
  • Custom error reverts: ABI-encoded custom error reverts with known selectors are collapsed into CustomErrorRevert { selector, args } nodes.
  • +
+

These patterns appear dozens of times in typical contracts, and outlining them into shared blocks eliminates significant code duplication.

+

Outlined helper functions

+

The LLVM codegen backend generates approximately 15 types of outlined helper functions for common operations:

+
    +
  • Storage: __revive_sload_word, __revive_sstore_word (handle byte-swap internally)
  • +
  • Mapping: __revive_mapping_sload, __revive_mapping_sstore (keccak256 + storage in one call)
  • +
  • Callvalue: __revive_callvalue, __revive_callvalue_nonzero (boolean optimization for non-payable checks)
  • +
  • Calldataload: __revive_calldataload (outlined when >= 20 call sites)
  • +
  • Memory: __revive_store_bswap, __revive_exit_checked, __revive_return_word
  • +
  • Errors: __revive_error_string_revert_N, __revive_custom_error_N (per data-word count)
  • +
  • Keccak wrappers: __keccak256_slot_N (one noinline wrapper per constant slot, internally dispatching to __revive_keccak256_two_words)
  • +
+

Additionally, common exit patterns (revert with constant length, zero-value returns) are deduplicated into shared LLVM basic blocks, saving hundreds of instruction copies in large contracts.

+

Codesize results

+

Integration test contracts

+

Reproducible with cargo test --package revive-integration -- codesize. The main column is the value committed to crates/integration/codesize.json on main; the newyork column is the value produced by the same test with RESOLC_USE_NEWYORK=1 set, currently committed on this branch.

+
+ + + + + + + + + + + + + + +
Contractmain (bytes)newyork (bytes)Reduction
Baseline870479−44.9%
Computation2,4181,376−43.1%
DivisionArithmetics9,3277,192−22.9%
ERC2017,16010,138−40.9%
Events1,6621,279−23.0%
FibonacciIterative1,427949−33.5%
Flipper2,2401,123−49.9%
SHA18,0096,286−21.5%
+
+

OpenZeppelin contracts

+

Measured by running oz-tests/oz.sh against real-world contracts generated with the OpenZeppelin Wizard. The numbers below are a development snapshot — there is no committed measurement file in the repo, so these may drift as the optimizer evolves; rerun the script for fresh figures.

+
+ + + + + + + + + + + + + + + +
Contractnewyork (bytes)
oz_gov81,840
erc72152,634
erc2045,703
oz_stable45,052
oz_rwa41,581
erc115533,087
oz_simple_erc2017,024
proxy3,748
Total320,669
+
+

For comparison, building the same contracts without the newyork optimizer at the equivalent snapshot produced 563,526 bytes total — a reduction of about −43% across the corpus.

+

Per-contract reductions in the integration suite range from roughly −21% (SHA1, where the bulk of the work is the SHA-1 inner loop and offers little to optimise) to nearly −50% (Flipper, where the optimiser strips away most of Solidity’s dispatch and storage-access scaffolding).

+

Development history and challenges

+

The newyork optimizer was developed over roughly three months — from early February 2026 through early May 2026 — largely through AI-assisted pair programming with Claude. The development progressed through several distinct phases:

+

Phase 1 – Initial scaffolding: The first draft established the core IR data structures, Yul-to-IR translation, and LLVM codegen. Early commits focused on getting a correct round-trip through the new pipeline.

+

Phase 2 – Optimization passes: Once the baseline was stable, optimization passes were added iteratively: inlining, simplification, memory optimization, function deduplication, keccak256 fusion, and type inference. Each pass was validated against differential tests comparing EVM and PVM execution.

+

Phase 3 – Soundness hardening: Several type inference and narrowing approaches turned out to be unsound and had to be reworked:

+
    +
  • An early type inference approach caused namespace collisions across subobjects and was scoped per-object.
  • +
  • Caller-based parameter narrowing was polluted by overly aggressive inference and replaced with body-based structural analysis.
  • +
  • Backward demand-driven narrowing required multiple iterations to become provably safe.
  • +
+

Phase 4 – Measuring and tuning: Systematic measurement of OpenZeppelin contracts revealed which optimizations had the most impact and which approaches regressed performance.

+

Approaches that did not work

+
+ + + + + + + + + + +
ApproachOutcome
Storage bswap decomposition (4x bswap.i64)Regressed: LLVM handles bswap.i256 better natively
NoInline on __revive_int_truncate+62% regression: PolkaVM call overhead exceeds inline cost
Native FMP memory (inline sbrk)Mixed: small contracts improved, large ones regressed from sbrk bloat
Shared overflow trap blockMixed: prevented LLVM from eliminating individual dead overflow checks
+
+

These results highlight a recurring theme: interacting well with LLVM’s own optimization passes is critical. Optimizations at the IR level can inadvertently inhibit LLVM’s downstream passes, sometimes causing surprising regressions.

+

Known limitations and future work

+

The following opportunities have been identified but are not yet implemented:

+
    +
  • Bitwise algebraic simplifications: BitAnd, BitOr, BitXor identity patterns fall through without simplification.
  • +
  • Cross-control-flow memory optimization: Memory state is conservatively cleared at if/switch/for boundaries. Preserving state across simple branches would enable more load-after-store eliminations.
  • +
  • Adaptive inlining thresholds: Current thresholds are static constants. Profile-guided or contract-size-aware heuristics could improve decisions for diverse contract sizes.
  • +
  • Extended fuzzy deduplication: The current pass only compares functions by structure of Let bindings. Extending to consider literals inside MStore, Return, Revert, and Log statements would find more deduplication opportunities.
  • +
  • Type checking in validation: The validator checks SSA well-formedness and structural correctness, but does not yet verify type consistency of operations (the TypeMismatch error variant exists but is not yet wired).
  • +
  • Loop variable narrowing: Loop-carried variables are conservatively widened to I256. Reaching a fixed-point across loop iterations could allow narrower types for simple counters.
  • +
+

Environment variables

+

A small set of environment variables controls or inspects the newyork pipeline. Only RESOLC_USE_NEWYORK affects generated bytecode; the others are read-only inspection knobs used while debugging the optimizer.

+
+ + + + + + + + + + + +
VariableEffect
RESOLC_USE_NEWYORK=1Routes Yul lowering through the newyork pipeline. Equivalent to passing --newyork on the command line; the CLI flag and this variable are OR-ed by resolve_use_newyork (crates/resolc/src/lib.rs).
RESOLC_DEBUG_IRWhen set, prints the translated newyork IR for every object to stderr. Additionally writes <output_directory>/<object>.newyork.txt whenever the debug config carries an output directory.
RESOLC_DEBUG_HEAPWhen set, appends per-object heap-analysis details — native regions/offsets, taintedness, dynamic escapes, escaping ranges — to <output_directory>/resolc_heap_debug.log. Requires the debug config to carry an output directory.
NEWYORK_DUMP_IRWhen set, writes the IR for every translated object to /tmp/newyork_ir_<object>.txt from inside translate_yul_object (crates/newyork/src/lib.rs). Independent of RESOLC_DEBUG_IR — fires before codegen and needs no output directory.
RESOLC_DEBUG_BLOBTest harness only. Dumps the compiled PVM blob to /tmp/debug_blob_<contract>.pvm and the LLVM IR debug directory to /tmp/debug_llvm_newyork or /tmp/debug_llvm_yul. Used by crates/resolc/src/test_utils.rs when comparing newyork against the Yul path.
+
+

All of these gate on presence/value at the start of compilation; flipping them mid-run has no effect.

+

Module reference

+
+ + + + + + + + + + + + + + + + + + + + +
ModulePurpose
lib.rsPipeline orchestration and pass sequencing
ir.rsCore IR data structures (types, expressions, statements, functions, objects)
from_yul.rsYul AST to newyork IR translation (two-pass with forward reference support)
to_llvm.rsnewyork IR to LLVM IR codegen with outlined helpers and narrowing
simplify.rsConstant folding, algebraic identities, strength reduction, copy propagation, DCE, environment read CSE, revert outlining, callvalue hoisting, function deduplication (exact and fuzzy), constant keccak folding
inline.rsFunction inlining with PolkaVM-tuned heuristics (Tarjan SCC, leave elimination)
type_inference.rsBidirectional integer width narrowing with transparent demand propagation
mem_opt.rsLoad-after-store elimination, keccak256 fusion, FMP propagation
heap_opt.rsHeap access pattern analysis, alignment tracking, byte-swap elimination
compound_outlining.rsMapping access pattern detection and fusion (keccak256_pair + sload/sstore)
guard_narrow.rsGuard pattern detection and AND-mask narrowing insertion
validate.rsIR well-formedness checks (SSA, yields, function references)
printer.rsHuman-readable IR pretty printer with configurable output
ssa.rsSSA construction helpers (scope management, phi-node merging)
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/docs/developer_guide/target.html b/docs/developer_guide/target.html index 5fd8c5382..702e8e1b6 100644 --- a/docs/developer_guide/target.html +++ b/docs/developer_guide/target.html @@ -35,10 +35,10 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-79c091ca.js"; + window.path_to_searchindex_js = "../searchindex-767b23cd.js"; - +
@@ -198,7 +198,7 @@

- @@ -212,7 +212,7 @@

- diff --git a/docs/developer_guide/testing.html b/docs/developer_guide/testing.html index da72fcc03..87b80e32a 100644 --- a/docs/developer_guide/testing.html +++ b/docs/developer_guide/testing.html @@ -35,10 +35,10 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-79c091ca.js"; + window.path_to_searchindex_js = "../searchindex-767b23cd.js"; - +
diff --git a/docs/faq.html b/docs/faq.html index e0402de77..676e7ec0b 100644 --- a/docs/faq.html +++ b/docs/faq.html @@ -35,10 +35,10 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-79c091ca.js"; + window.path_to_searchindex_js = "searchindex-767b23cd.js"; - +
diff --git a/docs/index.html b/docs/index.html index b4587ed06..cb7936b3d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -35,10 +35,10 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-79c091ca.js"; + window.path_to_searchindex_js = "searchindex-767b23cd.js"; - +
diff --git a/docs/print.html b/docs/print.html index 13de18a73..2647777a6 100644 --- a/docs/print.html +++ b/docs/print.html @@ -36,10 +36,10 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-79c091ca.js"; + window.path_to_searchindex_js = "searchindex-767b23cd.js"; - +
@@ -643,7 +643,4042 @@

The L

We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM rv64emacb target and always leave assertions on. Furthermore, we need cross builds because resolc itself targets emscripten and musl. The revive-llvm-builer functions as a cross-platform build script and is used to build and release the LLVM dependency.

We also maintain the lld-sys crate for interfacing with LLD. The LLVM linker is used during the compilation process, but we don’t want to distribute another binary.

Custom optimizations

-

At the moment, no significant custom optimizations are implemented. Thus, we are missing some optimization opportunities that neither solc nor LLVM can realize (due to their lack of domain specific knowledge about the semantics of our target environment). Furthermore, solc optimizes for EVM gas and a target machine orthogonal to our target (BE 256-bit stack machine EVM vs. 64-bit LE RISC architecture PVM). We have started working on an additional IR layer between Yul and LLVM to capture missed optimization opportunities, though.

+

An experimental newyork optimizer introduces a custom IR layer between Yul and LLVM IR to capture optimization opportunities that neither solc nor LLVM can realize on their own. solc optimizes for EVM gas on a 256-bit big-endian stack machine, while LLVM lacks the domain knowledge to understand EVM memory semantics or Solidity patterns. The newyork IR bridges this gap with passes for type narrowing, memory optimization, function deduplication, and more.

+
+

The newyork optimizer

+

The newyork crate (crates/newyork/) introduces an additional intermediate representation (IR) layer between Yul and LLVM IR. It enables domain-specific optimizations that neither solc nor LLVM can perform on their own, because they lack semantic knowledge about the cross-domain compilation from EVM to PolkaVM.

+
+

Note

+

The newyork optimizer is experimental. It is gated behind the RESOLC_USE_NEWYORK=1 environment variable (for standard JSON mode) or the --newyork CLI flag, and not yet enabled by default.

+
+

Motivation

+

The EVM and PolkaVM are fundamentally different machines:

+
+ + + + + + + + + + +
PropertyEVMPolkaVM (RISC-V)
Word size256-bit64-bit
EndiannessBig-endianLittle-endian
ArchitectureStack machineRegister-based
Memory modelLinear with free pointer conventionFlat address space
+
+

solc optimizes Yul IR for EVM gas costs on a 256-bit big-endian stack machine. LLVM, on the other hand, operates at too low a level to understand EVM memory semantics or Solidity patterns. By the time Yul reaches LLVM IR, the high-level intent is lost.

+

The newyork IR sits between these two worlds and recovers enough semantic information to make optimization decisions that neither compiler can make alone.

+

Pipeline overview

+
                    ┌──────────────────────────────────────────────────┐
+Yul AST ──────────► │                  newyork IR                      │ ──► LLVM IR ──► RISC-V
+            from_yul│                                                  │ to_llvm
+                    │  1. inline                                       │
+                    │  2. simplify (pass 1)                            │
+                    │  3. dedup (exact + fuzzy)                        │
+                    │  4. mem_opt + fmp_prop + keccak_fold             │
+                    │  5. simplify (pass 2)                            │
+                    │  6. compound_outlining + guard_narrow            │
+                    │  7. simplify (pass 3)                            │
+                    │  8. dedup (exact + fuzzy, pass 2)                │
+                    │  ── recursive on subobjects ──                   │
+                    │  9. heap_opt (analysis)                          │
+                    │ 10. type_inference (4 iterative rounds)          │
+                    │ 11. validate                                     │
+                    └──────────────────────────────────────────────────┘
+
+

The optimizer runs the following passes in order:

+
    +
  1. Inlining – custom heuristics tuned for PolkaVM call overhead, with Tarjan SCC-based recursion detection and quadratic leave-overhead modeling.
  2. +
  3. Simplify (pass 1) – constant folding, algebraic identities, strength reduction (mul by power-of-2 to shl), copy propagation, dead code elimination, environment read CSE (callvalue, caller, origin, etc.), and revert pattern outlining (panic selectors, custom error selectors).
  4. +
  5. Function deduplication – exact structural match, then fuzzy dedup (functions differing only in literal constants are parameterized and merged, up to 4 differing positions).
  6. +
  7. Memory optimization – load-after-store elimination, keccak256 fusion (mstore + keccak256 sequences into Keccak256Single/Keccak256Pair nodes), free memory pointer propagation (replaces mload(0x40) with a known constant), and constant keccak256 folding (precomputes hashes of compile-time-constant inputs).
  8. +
  9. Simplify (pass 2) – cleans up dead code and new constant expressions exposed by memory optimization and keccak folding.
  10. +
  11. Compound outlining – detects keccak256_pair + sload/sstore sequences and fuses them into MappingSLoad/MappingSStore IR nodes, eliminating intermediate hash values. Guard narrowing – detects if gt(val, MASK) { revert } and iszero(eq(val, and(val, MASK))) patterns and inserts AND-mask narrowing, giving type inference proof that values fit in fewer bits.
  12. +
  13. Simplify (pass 3) – propagates opportunities created by compound outlining and guard narrowing.
  14. +
  15. Function deduplication (pass 2) – catches new duplicates exposed by guard narrowing and compound outlining canonicalization.
  16. +
  17. Heap analysis – analyzes memory access patterns (alignment, static offsets, taintedness, escaping regions) to determine which accesses can use native little-endian layout, skipping byte-swap operations. Uses GCD-based alignment propagation and per-region taint tracking.
  18. +
  19. Type inference – narrows 256-bit values to smaller widths (I1, I8, I32, I64, I128, I160) where provable. Runs iteratively for up to 4 cascading refinement rounds, combining forward min-width propagation, backward use-context demands, transparent-operation demand propagation, and interprocedural parameter/return narrowing.
  20. +
  21. Validation – checks SSA well-formedness (use-before-def, multiple definitions), yield count consistency, and function reference correctness.
  22. +
+

Steps 1-8 run recursively on subobjects (deployed contract code), where optimization impact is greatest. Steps 9-11 run on the full object tree.

+

IR design

+

The newyork IR is an SSA form with structured control flow, inspired by MLIR’s SCF dialect. Key design choices:

+
    +
  • Explicit types with address spaces: Every value carries a bit-width (I1, I8, I32, I64, I128, I160, I256) and pointers carry address space information (Heap, Stack, Storage, Code). All values start as I256 and are narrowed by type inference.
  • +
  • Pure expressions vs. effectful statements: Expressions compute values without side effects; statements perform memory, storage, or control flow effects. This separation simplifies analysis and rewriting.
  • +
  • Semantic annotations: Memory operations are tagged with region information (Scratch, FreePointerSlot, Dynamic). Storage operations carry static slot values when known at compile time.
  • +
  • Structured control flow: If, Switch, and For nodes preserve the high-level structure from Yul, with explicit region arguments and yields for value flow across control edges.
  • +
+

For per-operation detail — printed syntax, operand and result types, and more — see the newyork IR reference.

+

Key optimizations explained

+

Type narrowing

+

EVM operates on 256-bit words, but most values in practice fit in 32 or 64 bits. The type inference pass performs bidirectional analysis:

+
    +
  • Forward: computes minimum width from literal values and operation semantics (e.g., add(I64, I8) produces I65, rounded up to I128).
  • +
  • Backward use tracking: classifies each value’s uses into 9 context categories (MemoryOffset, MemoryValue, StorageAccess, Comparison, Arithmetic, FunctionArg, FunctionReturn, ExternalCall, General). All categories conservatively demand the full I256 width by default; the categorisation is what enables the interprocedural phase to selectively relax the demand for narrowed function arguments. Earlier versions narrowed directly from the use category, but that was unsound for memory offsets — mload(2^128) aliased to mload(0) because the bounds check ran on an already-truncated value (commit ccca38df).
  • +
  • Transparent demand propagation: for modular-arithmetic operations (Add, Sub, Mul, And, Or, Xor), propagates narrow demands backward through operands, exploiting the property that trunc(op(a,b), N) == op(trunc(a,N), trunc(b,N)).
  • +
  • Interprocedural: iteratively narrows function parameter and return types in up to four rounds, combining four narrowing strategies — body-driven parameter narrowing, caller-driven parameter narrowing, forward-based return narrowing, and demand-based return narrowing — and re-running full inference between rounds. Parameters are clamped to at least I32 (XLEN on PolkaVM).
  • +
+

This allows LLVM to emit native 32/64-bit instructions instead of software-emulated 256-bit arithmetic, and eliminates expensive multi-instruction comparison sequences (16-20 RISC-V instructions for i256 comparisons reduced to 1-2 for i64).

+

Guard narrowing

+

Solidity emits runtime guards that prove values fit in narrow ranges (e.g., address validation via if gt(val, 2^160-1) { revert }). The guard narrowing pass detects these patterns and inserts explicit AND-mask narrowing after the guard. This gives downstream type inference proof that the value fits in fewer bits, enabling cascading narrowing of comparisons, arithmetic, and memory operations that use the guarded value.

+

Two pattern families are recognized:

+
    +
  • GT-based guards: if gt(val, MASK) { <terminates> } where MASK is a boundary value like 2^N - 1
  • +
  • EQ-based guards: iszero(eq(val, and(val, MASK))) patterns common in Solidity’s address validation
  • +
+

Heap optimization

+

PVM doesn’t provide EVM-compatible linear memory, so the compiler emulates it using a byte buffer with byte-swap operations for big-endian compatibility. The heap analysis pass determines which memory accesses can use native little-endian layout by analyzing access patterns:

+
    +
  • Tracks alignment and static offset information for all memory accesses using GCD-based propagation
  • +
  • Propagates taintedness when addresses escape to external calls, are written by external sources (codecopy, calldatacopy), or use unaligned access patterns
  • +
  • Tracks variable-accessed offsets to prevent mode mismatches between native and byte-swap accesses to the same location
  • +
  • Handles loop-carried variables conservatively (marked as non-literal to prevent false constant propagation)
  • +
+

The codegen backend supports four memory access modes: AllNative (all accesses skip byte-swap), InlineNative (constant-offset accesses use native layout), InlineByteSwap (constant-offset accesses use inline byte-swap), and ByteSwap (standard byte-swap through helper functions).

+

Free memory pointer range proof

+

The Solidity free memory pointer (mload(0x40)) always fits in 32 bits — sbrk enforces FMP < heap_size on every store, regardless of which memory mode the contract uses. After every literal mload(0x40), codegen emits a trunc N → zext 256 chain (where N is bits(heap_size - 1), e.g. 17 for the 131,072-byte default heap). The trunc-extend round-trip is a no-op semantically, but exposes the bound to LLVM’s IPSCCP range analysis, which then propagates it through every add(fmp, K) and eliminates the trailing safe_truncate_int_to_xlen overflow checks at every FMP-derived offset use. Despite only affecting a single codegen site, this is the single largest contributor to the optimizer’s code-size reduction.

+

A subtle gating issue: the byte-order mode (InlineNative / ByteSwap) and the value bound on FMP are independent invariants. fmp_native_safe() and can_use_native(0x40) protect against mixing little-endian writers with big-endian readers on the FMP slot, which would corrupt the stored offset; the value bound is unrelated and holds in every mode. Earlier versions of the codegen gated the load-side range proof on the byte-order checks, which suppressed the optimization for any contract with dynamic memory accesses. Decoupling the two reasonings — keeping the byte-order gate on the store side, dropping it from the load-side range proof — is what makes the multiplicative IPSCCP effect available to OZ-class contracts.

+

Soundness traps for FMP optimizations

+

The FMP slot is small but easy to mis-optimize. The codebase carries several +regression tests for previously-found soundness bugs; new FMP-related changes +should be verified against them:

+
    +
  • mload_at_fmp_slot (crates/integration/src/tests.rs, fixed in +1fd6063c): tests mload(0x40) and offsets near it (0x21, 0x3f, 0x42) +on a contract that also performs dynamic mloads. Catches byte-order mismatches +when one access goes native (LE) and another goes byte-swap (BE). The fix +blocks native mode for FMP whenever has_dynamic_accesses is true.
  • +
  • mload_huge_offset_traps (fixed in ccca38df): tests that +mload(2^128) and mload(2^255) correctly trap via the gas-exhaustion +path. Catches UseContext::MemoryOffset narrowing bypassing the +safe_truncate_int_to_xlen overflow check at the use site — +mload(2^128) aliasing to mload(0) and returning the zero-initialized +scratch slot. The fix classifies MemoryOffset as I256 so it doesn’t +drive narrowing; the bounds check at the use site catches out-of-range.
  • +
  • FMP i32 shortcut removal (dbcfc921): an earlier optimization stored +only 4 bytes at offset 0x40 instead of the full 32-byte EVM word, breaking +any inline assembly using mstore(0x40, ...) for non-FMP purposes. +Caused a cascade of 249/251 retester failures via allocator corruption. +No dedicated regression test was added — the retester corpus was sufficient +coverage — but the lesson generalizes: writes to 0x40 must store the full +word, even when the high bits are provably zero, because the slot is part +of the same 32-byte memory region read by other code.
  • +
+

When adding an optimization that touches FMP, distinguish carefully between: +the byte-order encoding at the slot (must be consistent between writers +and readers), the value bound (FMP < heap_size, always true), and the +stored width (must be 32 bytes for mstore(0x40, ...), even though only +the low N bits are non-zero).

+

Keccak256 fusion and folding

+

Two complementary optimizations target the common Solidity pattern of hashing values for storage slot computation:

+
    +
  • Fusion: Recognizes mstore + keccak256 sequences and fuses them into dedicated IR nodes (Keccak256Single, Keccak256Pair), eliminating intermediate memory traffic.
  • +
  • Constant folding: When all keccak256 inputs are compile-time constants, the hash is computed at compile time and replaced with a literal.
  • +
+

Compound outlining (mapping access)

+

Solidity mapping accesses follow a predictable pattern: hash a key with a storage slot, then load/store the result. The compound outlining pass detects keccak256_pair(key, slot) followed by sload/sstore and fuses them into MappingSLoad/MappingSStore IR nodes. These are lowered to outlined helper functions (__revive_mapping_sload, __revive_mapping_sstore) that combine the hash computation with the storage operation, eliminating intermediate values and redundant byte-swaps.

+

Fuzzy function deduplication

+

Solidity generates many near-identical functions that differ only in literal constants (e.g., error selectors, storage slot offsets). Fuzzy deduplication identifies such groups, parameterizes the differing literals (up to 4 positions), and replaces all copies with calls to a single shared implementation.

+

Revert pattern outlining

+

The simplify pass detects common revert patterns and replaces them with compact IR nodes:

+
    +
  • Panic reverts: Solidity Panic(uint256) sequences (selector 0x4e487b71 + encoded panic code) are collapsed into PanicRevert { code } nodes, which are lowered to shared helper functions.
  • +
  • Custom error reverts: ABI-encoded custom error reverts with known selectors are collapsed into CustomErrorRevert { selector, args } nodes.
  • +
+

These patterns appear dozens of times in typical contracts, and outlining them into shared blocks eliminates significant code duplication.

+

Outlined helper functions

+

The LLVM codegen backend generates approximately 15 types of outlined helper functions for common operations:

+
    +
  • Storage: __revive_sload_word, __revive_sstore_word (handle byte-swap internally)
  • +
  • Mapping: __revive_mapping_sload, __revive_mapping_sstore (keccak256 + storage in one call)
  • +
  • Callvalue: __revive_callvalue, __revive_callvalue_nonzero (boolean optimization for non-payable checks)
  • +
  • Calldataload: __revive_calldataload (outlined when >= 20 call sites)
  • +
  • Memory: __revive_store_bswap, __revive_exit_checked, __revive_return_word
  • +
  • Errors: __revive_error_string_revert_N, __revive_custom_error_N (per data-word count)
  • +
  • Keccak wrappers: __keccak256_slot_N (one noinline wrapper per constant slot, internally dispatching to __revive_keccak256_two_words)
  • +
+

Additionally, common exit patterns (revert with constant length, zero-value returns) are deduplicated into shared LLVM basic blocks, saving hundreds of instruction copies in large contracts.

+

Codesize results

+

Integration test contracts

+

Reproducible with cargo test --package revive-integration -- codesize. The main column is the value committed to crates/integration/codesize.json on main; the newyork column is the value produced by the same test with RESOLC_USE_NEWYORK=1 set, currently committed on this branch.

+
+ + + + + + + + + + + + + + +
Contractmain (bytes)newyork (bytes)Reduction
Baseline870479−44.9%
Computation2,4181,376−43.1%
DivisionArithmetics9,3277,192−22.9%
ERC2017,16010,138−40.9%
Events1,6621,279−23.0%
FibonacciIterative1,427949−33.5%
Flipper2,2401,123−49.9%
SHA18,0096,286−21.5%
+
+

OpenZeppelin contracts

+

Measured by running oz-tests/oz.sh against real-world contracts generated with the OpenZeppelin Wizard. The numbers below are a development snapshot — there is no committed measurement file in the repo, so these may drift as the optimizer evolves; rerun the script for fresh figures.

+
+ + + + + + + + + + + + + + + +
Contractnewyork (bytes)
oz_gov81,840
erc72152,634
erc2045,703
oz_stable45,052
oz_rwa41,581
erc115533,087
oz_simple_erc2017,024
proxy3,748
Total320,669
+
+

For comparison, building the same contracts without the newyork optimizer at the equivalent snapshot produced 563,526 bytes total — a reduction of about −43% across the corpus.

+

Per-contract reductions in the integration suite range from roughly −21% (SHA1, where the bulk of the work is the SHA-1 inner loop and offers little to optimise) to nearly −50% (Flipper, where the optimiser strips away most of Solidity’s dispatch and storage-access scaffolding).

+

Development history and challenges

+

The newyork optimizer was developed over roughly three months — from early February 2026 through early May 2026 — largely through AI-assisted pair programming with Claude. The development progressed through several distinct phases:

+

Phase 1 – Initial scaffolding: The first draft established the core IR data structures, Yul-to-IR translation, and LLVM codegen. Early commits focused on getting a correct round-trip through the new pipeline.

+

Phase 2 – Optimization passes: Once the baseline was stable, optimization passes were added iteratively: inlining, simplification, memory optimization, function deduplication, keccak256 fusion, and type inference. Each pass was validated against differential tests comparing EVM and PVM execution.

+

Phase 3 – Soundness hardening: Several type inference and narrowing approaches turned out to be unsound and had to be reworked:

+
    +
  • An early type inference approach caused namespace collisions across subobjects and was scoped per-object.
  • +
  • Caller-based parameter narrowing was polluted by overly aggressive inference and replaced with body-based structural analysis.
  • +
  • Backward demand-driven narrowing required multiple iterations to become provably safe.
  • +
+

Phase 4 – Measuring and tuning: Systematic measurement of OpenZeppelin contracts revealed which optimizations had the most impact and which approaches regressed performance.

+

Approaches that did not work

+
+ + + + + + + + + + +
ApproachOutcome
Storage bswap decomposition (4x bswap.i64)Regressed: LLVM handles bswap.i256 better natively
NoInline on __revive_int_truncate+62% regression: PolkaVM call overhead exceeds inline cost
Native FMP memory (inline sbrk)Mixed: small contracts improved, large ones regressed from sbrk bloat
Shared overflow trap blockMixed: prevented LLVM from eliminating individual dead overflow checks
+
+

These results highlight a recurring theme: interacting well with LLVM’s own optimization passes is critical. Optimizations at the IR level can inadvertently inhibit LLVM’s downstream passes, sometimes causing surprising regressions.

+

Known limitations and future work

+

The following opportunities have been identified but are not yet implemented:

+
    +
  • Bitwise algebraic simplifications: BitAnd, BitOr, BitXor identity patterns fall through without simplification.
  • +
  • Cross-control-flow memory optimization: Memory state is conservatively cleared at if/switch/for boundaries. Preserving state across simple branches would enable more load-after-store eliminations.
  • +
  • Adaptive inlining thresholds: Current thresholds are static constants. Profile-guided or contract-size-aware heuristics could improve decisions for diverse contract sizes.
  • +
  • Extended fuzzy deduplication: The current pass only compares functions by structure of Let bindings. Extending to consider literals inside MStore, Return, Revert, and Log statements would find more deduplication opportunities.
  • +
  • Type checking in validation: The validator checks SSA well-formedness and structural correctness, but does not yet verify type consistency of operations (the TypeMismatch error variant exists but is not yet wired).
  • +
  • Loop variable narrowing: Loop-carried variables are conservatively widened to I256. Reaching a fixed-point across loop iterations could allow narrower types for simple counters.
  • +
+

Environment variables

+

A small set of environment variables controls or inspects the newyork pipeline. Only RESOLC_USE_NEWYORK affects generated bytecode; the others are read-only inspection knobs used while debugging the optimizer.

+
+ + + + + + + + + + + +
VariableEffect
RESOLC_USE_NEWYORK=1Routes Yul lowering through the newyork pipeline. Equivalent to passing --newyork on the command line; the CLI flag and this variable are OR-ed by resolve_use_newyork (crates/resolc/src/lib.rs).
RESOLC_DEBUG_IRWhen set, prints the translated newyork IR for every object to stderr. Additionally writes <output_directory>/<object>.newyork.txt whenever the debug config carries an output directory.
RESOLC_DEBUG_HEAPWhen set, appends per-object heap-analysis details — native regions/offsets, taintedness, dynamic escapes, escaping ranges — to <output_directory>/resolc_heap_debug.log. Requires the debug config to carry an output directory.
NEWYORK_DUMP_IRWhen set, writes the IR for every translated object to /tmp/newyork_ir_<object>.txt from inside translate_yul_object (crates/newyork/src/lib.rs). Independent of RESOLC_DEBUG_IR — fires before codegen and needs no output directory.
RESOLC_DEBUG_BLOBTest harness only. Dumps the compiled PVM blob to /tmp/debug_blob_<contract>.pvm and the LLVM IR debug directory to /tmp/debug_llvm_newyork or /tmp/debug_llvm_yul. Used by crates/resolc/src/test_utils.rs when comparing newyork against the Yul path.
+
+

All of these gate on presence/value at the start of compilation; flipping them mid-run has no effect.

+

Module reference

+
+ + + + + + + + + + + + + + + + + + + + +
ModulePurpose
lib.rsPipeline orchestration and pass sequencing
ir.rsCore IR data structures (types, expressions, statements, functions, objects)
from_yul.rsYul AST to newyork IR translation (two-pass with forward reference support)
to_llvm.rsnewyork IR to LLVM IR codegen with outlined helpers and narrowing
simplify.rsConstant folding, algebraic identities, strength reduction, copy propagation, DCE, environment read CSE, revert outlining, callvalue hoisting, function deduplication (exact and fuzzy), constant keccak folding
inline.rsFunction inlining with PolkaVM-tuned heuristics (Tarjan SCC, leave elimination)
type_inference.rsBidirectional integer width narrowing with transparent demand propagation
mem_opt.rsLoad-after-store elimination, keccak256 fusion, FMP propagation
heap_opt.rsHeap access pattern analysis, alignment tracking, byte-swap elimination
compound_outlining.rsMapping access pattern detection and fusion (keccak256_pair + sload/sstore)
guard_narrow.rsGuard pattern detection and AND-mask narrowing insertion
validate.rsIR well-formedness checks (SSA, yields, function references)
printer.rsHuman-readable IR pretty printer with configurable output
ssa.rsSSA construction helpers (scope management, phi-node merging)
+
+
+

newyork IR reference

+

A per-operation reference for the newyork IR: textual syntax, operand and result types, purity, region and static-slot annotations, and examples.

+

How to read this reference

+

This appendix enumerates every operation the newyork IR supports. It is a lookup, not a walkthrough: each entry is self-contained and intended to be reachable by anchor.

+

Operations are grouped by function (memory and storage writes, pure expressions, control flow, and so on) rather than alphabetically. Jump to a specific operation from the operation index below, or use the sidebar.

+

Every operation appears in two places in the codebase. The canonical Rust definition is a variant of either Expression or Statement in ir.rs. The textual rendering used by debug dumps and by this appendix is produced by the printer in printer.rs. Treat the printed syntax as a debug surface, not a stable input language: there is no parser for it, and printer details change when passes add new annotations.

+

Entry format

+

Each operation entry has the same shape:

+
+ + + + + + + + + + + + + +
FieldWhat it shows
HeadingThe printed operation name (e.g. mstore) followed by the Expression or Statement variant it corresponds to in ir.rs.
DescriptionA short prose summary of what the operation does and any semantic notes worth knowing before reading the rest of the entry.
SyntaxThe literal printer output, including any optional debug annotations (region tags, static-slot comments). Anything inside /* ... */ is a debug-only annotation and is not part of the operation itself.
ExampleA minimal printed snippet, using the printer’s actual v0/v1/… naming.
OperandsOne row per input or structural participant in the printed syntax. Value operands list the narrowest type the operation guarantees (default i256; narrower widths only appear when type inference has narrowed an upstream definition). Vector-of-operands fields show Vec<…> as the type. Non-value participants such as nested regions are listed with an em-dash type to mark them as structural rather than as operands.
Result and purityThe type the operation produces (or none for statements that bind no value), followed by a purity label, either Pure or Effectful. Pure operations may be reordered, deduplicated, or eliminated by the simplifier; effectful ones may not. Effectful entries may carry a parenthetical describing the nature of the side effect when informative (e.g. “control flow”, “terminator”, or a note about revert/trap behavior).
AnnotationsOperation-specific fields the printer surfaces as /* ... */ comments in the dump (region tag for memory ops, static-slot hint for storage ops, type suffix for non-default widths). Listed here as a table of source fieldprinted form.
+
+

Syntax notation

+

Syntax templates in each entry use the following conventions:

+
+ + + + + + + + + + + + + +
NotationMeaning
add, mload, if, else, case, let, yield, …Literal printer tokens: bare lowercase identifiers and keywords that the printer emits verbatim.
$offset, $value, $key, $lhs, $rhs, …Role names ($-prefixed): placeholders for SSA value references the printer renders as v followed by a decimal id (v0, v1, …).
<type>, <region>, <hex>, <id>, <bits>, <func_name>, <N>, <length>, …Metavariables: stand for compile-time fields (type tags, hex values, identifier strings, integer counts), not SSA values. The concrete values they take are enumerated in the Annotations section of each entry or in the type system reference.
[…]Optional parts. Anything inside the brackets may or may not appear in any given dump, depending on the conditions described in the operation’s Annotations section.
[: <type>]Optional type suffix on a value reference. Suppressed when the value’s type is the default i256 integer; present otherwise (: i32, : ptr<heap>, …).
/* … */Debug-only annotations the printer attaches to certain operations (memory region tag, static-slot hint, etc.).
Repetition: “more entries of the same shape.” Used in vector operand lists ($arg_0, $arg_1, …) and in multi-line block bodies ({ … }).
+
+

Operation index

+

Pure expressions

+
Constants and variables
+ +
Arithmetic
+ +
Bit-width conversions
+ +
Hashing
+ +
Environment reads
+ +
Calldata, returndata, and code
+ +
Memory and storage loads
+ +
Linker
+ +
Function call
+ +

Memory and storage writes

+ +

Bulk copies

+ +

Bindings and wrappers

+ +

Structured control flow

+ +

External interaction

+ +

Termination

+ +

Type system

+

Every value in the IR carries a Type. The operation entries below refer to widths (i1i256), address spaces (ptr<heap>, etc.), and memory regions (scratch, etc.) by their printed form; this section is the reference for those names.

+

Type

+

The umbrella enum. Three variants:

+
+ + + + + + + + + +
VariantPrinted asDescription
Int(BitWidth)i1, i8, …, i256An integer at one of seven widths; see BitWidth.
Ptr(AddressSpace)ptr<heap>, ptr<stack>, ptr<storage>, ptr<code>A pointer tagged with its address space; see AddressSpace.
VoidvoidUnit type. Used for statements that produce no value and for void-returning functions.
+
+

BitWidth

+

The seven rungs of integer width. Newly minted values default to I256; type inference narrows them down to one of the lower rungs when it can prove the upper bits are zero or unused.

+
+ + + + + + + + + + + + + +
VariantPrinted asTypical use
I1i1Boolean. Result type of every comparison and iszero.
I8i8Byte values. The narrowest meaningful integer.
I32i32PolkaVM pointer width (XLEN); minimum width for function parameters under the rv64e ABI.
I64i64PolkaVM native register width; most narrowed values land here.
I128i128Two registers; arithmetic that overflows i64 but doesn’t need full 256-bit emulation.
I160i160Ethereum addresses; result of caller, origin, mapping keys.
I256i256EVM word width. The default and conservative ceiling.
+
+

AddressSpace

+

The address space a pointer points into. Carried on every Ptr value so the codegen can lower loads and stores without a separate alias-analysis pass.

+
+ + + + + + + + + + +
VariantPrinted asPoints intoEndianness
Heapptr<heap>Emulated EVM linear memory (the simulated mload/mstore region).Big-endian (by EVM contract).
Stackptr<stack>Native PolkaVM stack allocations.Little-endian (no swap).
Storageptr<storage>Contract storage; key/value with 256-bit slots.Big-endian on the wire.
Codeptr<code>Read-only code/data segment.Big-endian.
+
+

MemoryRegion

+

A refinement carried by every memory load and store on top of AddressSpace::Heap. The tag tells later passes what kind of heap address an offset is hitting, which drives both free-memory-pointer propagation and byte-swap elimination.

+
+ + + + + + + + + + +
VariantAddress rangePrinted asMeaning
Scratch0x000x3f/* scratch */EVM scratch space; safe to touch without consulting the free memory pointer.
FreePointerSlotexactly 0x40/* free_ptr */Slot that stores the free memory pointer itself.
Dynamic0x80 and above/* dynamic */Real heap allocations.
Unknowneverything else (constants in 0x410x7f, plus all non-constant offsets)(suppressed)Conservative fallback used when the offset isn’t a constant or doesn’t slot cleanly.
+
+

Pure expressions

+

Pure expressions produce values without side effects. The simplifier may freely reorder, deduplicate, and eliminate them. They appear on the right-hand side of a let binding, or as operands of other expressions and effectful statements; the operand positions accept SSA value references only, so any pure expression that is consumed elsewhere is first bound by a let. Examples in this section wrap each expression in a let v := … to give it somewhere to land.

+

0x<hex>

+

(Expression::Literal)

+

Description

+

A compile-time constant value with a declared type. New literals minted by the translator default to Int(I256); passes that synthesize constants at narrower widths (e.g. a one-bit boolean from a constant comparison) attach the narrower type directly.

+

Syntax

+
0x<hex>[: <type>]
+
+

Example

+
let v0 := 0x2a              // 42 at the default i256
+let v1 := 0x1: i1           // boolean true
+let v2 := 0x80: i64         // narrowed by type inference
+
+

Operands

+

None — literals are leaves.

+

Result and purity

+
+ + + + + + + +
ResultPurity
Same as the literal’s value_typePure
+
+

Annotations

+
+ + + + + + + + +
Source fieldPrinted as
value: BigUint0x<hex> in the syntax position (not a comment annotation; it is the expression itself)
value_type: Type: <type> suffix when value_type is not the default Int(I256); suppressed otherwise
+
+

v<id>

+

(Expression::Var)

+

Description

+

A reference to an existing SSA value, used as the entire right-hand side of a let. In a typical dump this is rare because the simplifier collapses let v := v<id> into the consumers of v via copy propagation; expect to see it only in dumps taken before simplification has run.

+

Syntax

+
v<id>
+
+

Example

+
let v5 := v3                // copy; usually eliminated by simplify
+
+

Operands

+

None — the expression is the value reference itself.

+

Result and purity

+
+ + + + + + + +
ResultPurity
Same as the referenced value’s typePure
+
+

Annotations

+

None.

+

add

+

(Expression::Binary with BinaryOperation::Add)

+

Description

+

Modular addition. Wraps on overflow; per EVM, the result is (lhs + rhs) mod 2^N where N is the operand width.

+

Syntax

+
add($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := add(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256
rhsi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
widen_by_one(max(width(lhs), width(rhs))) — one tier above the wider operand to account for the carry bitPure
+
+

Annotations

+

None.

+

sub

+

(Expression::Binary with BinaryOperation::Sub)

+

Description

+

Modular subtraction. Wraps on underflow; the result is (lhs - rhs) mod 2^256 regardless of operand widths.

+

Syntax

+
sub($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := sub(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256
rhsi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — conservative; underflow on narrower operands could borrow into upper bitsPure
+
+

Annotations

+

None.

+

mul

+

(Expression::Binary with BinaryOperation::Mul)

+

Description

+

Modular multiplication. The result is (lhs * rhs) mod 2^256.

+

Syntax

+
mul($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := mul(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256
rhsi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
double_width(max(width(lhs), width(rhs))) — the tier holding twice the wider operand’s bits (skipping i160 at the i128i256 transition)Pure
+
+

Annotations

+

None.

+

div

+

(Expression::Binary with BinaryOperation::Div)

+

Description

+

Unsigned integer division. Per EVM, div(x, 0) = 0 (no trap on division by zero).

+

Syntax

+
div($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := div(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Dividend.
rhsi256Divisor; 0 yields a result of 0, not a trap.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
width(lhs) — the quotient cannot exceed the dividendPure
+
+

Annotations

+

None.

+

sdiv

+

(Expression::Binary with BinaryOperation::SDiv)

+

Description

+

Signed two’s-complement integer division. Per EVM, sdiv(x, 0) = 0; quotient is truncated toward zero.

+

Syntax

+
sdiv($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := sdiv(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Dividend, treated as signed.
rhsi256Divisor, treated as signed; 0 yields 0.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
width(lhs)Pure
+
+

Annotations

+

None.

+

mod

+

(Expression::Binary with BinaryOperation::Mod)

+

Description

+

Unsigned modulo. Per EVM, mod(x, 0) = 0.

+

Syntax

+
mod($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := mod(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Dividend.
rhsi256Divisor; 0 yields 0.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
width(lhs)Pure
+
+

Annotations

+

None.

+

smod

+

(Expression::Binary with BinaryOperation::SMod)

+

Description

+

Signed modulo. Per EVM, smod(x, 0) = 0; the result takes the sign of the dividend.

+

Syntax

+
smod($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := smod(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Dividend, treated as signed.
rhsi256Divisor, treated as signed; 0 yields 0.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
width(lhs)Pure
+
+

Annotations

+

None.

+

exp

+

(Expression::Binary with BinaryOperation::Exp)

+

Description

+

Modular exponentiation: (lhs ^ rhs) mod 2^256. The most expensive arithmetic opcode in EVM (variable gas cost proportional to the byte length of rhs).

+

Syntax

+
exp($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := exp(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Base.
rhsi256Exponent.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — conservative; exponentiation can fill any widthPure
+
+

Annotations

+

None.

+

and

+

(Expression::Binary with BinaryOperation::And)

+

Description

+

Bitwise AND. The common idiom for type narrowing: a constant mask on the right lets forward analysis pick up a tight result width.

+

Syntax

+
and($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := and(v0, v1)
+let v3 := and(v0, 0xff)     // type inference narrows result to i8
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256
rhsi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
min(width(lhs), width(rhs)) — AND can only clear bits, so the result fits in the narrower operandPure
+
+

Annotations

+

None.

+

or

+

(Expression::Binary with BinaryOperation::Or)

+

Description

+

Bitwise OR.

+

Syntax

+
or($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := or(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256
rhsi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
max(width(lhs), width(rhs))Pure
+
+

Annotations

+

None.

+

xor

+

(Expression::Binary with BinaryOperation::Xor)

+

Description

+

Bitwise XOR.

+

Syntax

+
xor($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := xor(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256
rhsi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
max(width(lhs), width(rhs))Pure
+
+

Annotations

+

None.

+

shl

+

(Expression::Binary with BinaryOperation::Shl)

+

Description

+

Logical left shift. Operand order follows EVM: shl(shift, value) computes value << shift. Shifts ≥ 256 produce 0.

+

Syntax

+
shl($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := shl(v0, v1)       // v1 shifted left by v0 bits
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Shift amount in bits.
rhsi256Value to shift.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — conservative; bits may shift into any widthPure
+
+

Annotations

+

None.

+

shr

+

(Expression::Binary with BinaryOperation::Shr)

+

Description

+

Logical right shift. Operand order follows EVM: shr(shift, value) computes value >> shift with zero-fill from the left. Shifts ≥ 256 produce 0.

+

Syntax

+
shr($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := shr(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Shift amount in bits.
rhsi256Value to shift.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
If lhs is a known constant k: tier holding 256 - k bits (or i1 for k ≥ 256). Otherwise: width(rhs).Pure
+
+

Annotations

+

None.

+

sar

+

(Expression::Binary with BinaryOperation::Sar)

+

Description

+

Arithmetic (signed) right shift. Operand order follows EVM: sar(shift, value) shifts value right by shift bits, preserving the sign bit. Shifts ≥ 256 saturate to 0 for non-negative values and to -1 (all-ones) for negative values.

+

Syntax

+
sar($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := sar(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Shift amount in bits.
rhsi256Value to shift, treated as signed.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
Same shape as shr forward inference (constant shift narrows the result; non-constant falls back to width(rhs)).Pure
+
+

Annotations

+

None.

+

lt

+

(Expression::Binary with BinaryOperation::Lt)

+

Description

+

Unsigned less-than comparison. Returns 1 if lhs < rhs, else 0.

+

Syntax

+
lt($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := lt(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Compared unsigned.
rhsi256Compared unsigned.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i1Pure
+
+

Annotations

+

None.

+

gt

+

(Expression::Binary with BinaryOperation::Gt)

+

Description

+

Unsigned greater-than comparison. Returns 1 if lhs > rhs, else 0.

+

Syntax

+
gt($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := gt(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Compared unsigned.
rhsi256Compared unsigned.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i1Pure
+
+

Annotations

+

None.

+

slt

+

(Expression::Binary with BinaryOperation::Slt)

+

Description

+

Signed less-than comparison. Operands are treated as two’s complement.

+

Syntax

+
slt($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := slt(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Compared signed.
rhsi256Compared signed.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i1Pure
+
+

Annotations

+

None.

+

sgt

+

(Expression::Binary with BinaryOperation::Sgt)

+

Description

+

Signed greater-than comparison. Operands are treated as two’s complement.

+

Syntax

+
sgt($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := sgt(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Compared signed.
rhsi256Compared signed.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i1Pure
+
+

Annotations

+

None.

+

eq

+

(Expression::Binary with BinaryOperation::Eq)

+

Description

+

Equality comparison. Returns 1 if lhs == rhs, else 0. Signedness is irrelevant.

+

Syntax

+
eq($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := eq(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256
rhsi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i1Pure
+
+

Annotations

+

None.

+

byte

+

(Expression::Binary with BinaryOperation::Byte)

+

Description

+

Extract a single byte from a 256-bit word. byte(i, x) returns the i-th byte of x with byte 0 being the most significant. If i ≥ 32, the result is 0.

+

Syntax

+
byte($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := byte(v0, v1)      // v0 = byte index, v1 = word
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Byte position; 0 = most significant byte. Values ≥ 32 yield 0.
rhsi256Source word.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i8Pure
+
+

Annotations

+

None.

+

signextend

+

(Expression::Binary with BinaryOperation::SignExtend)

+

Description

+

Sign-extend an integer from a byte position. Per EVM, signextend(b, x) treats byte b of x as the most significant byte of a smaller signed integer and extends its sign through the upper bytes.

+

Syntax

+
signextend($lhs[: <type>], $rhs[: <type>])
+
+

Example

+
let v2 := signextend(v0, v1)  // v0 = byte position, v1 = value
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
lhsi256Byte position of the sign byte (0–31).
rhsi256Source value.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — the extended value occupies the full wordPure
+
+

Annotations

+

The width-targeted sign-extension primitive sext<i<bits>> (Expression::SignExtendTo) is a separate operation; see the bit-width conversions section.

+

addmod

+

(Expression::Ternary with BinaryOperation::AddMod)

+

Description

+

Ternary modular addition: (a + b) mod n, computed without intermediate overflow. Per EVM, n = 0 yields 0.

+

Syntax

+
addmod($a[: <type>], $b[: <type>], $n[: <type>])
+
+

Example

+
let v3 := addmod(v0, v1, v2)
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
ai256First addend.
bi256Second addend.
ni256Modulus; 0 yields 0.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — conservativePure
+
+

Annotations

+

None.

+

mulmod

+

(Expression::Ternary with BinaryOperation::MulMod)

+

Description

+

Ternary modular multiplication: (a * b) mod n, computed without intermediate overflow. Per EVM, n = 0 yields 0.

+

Syntax

+
mulmod($a[: <type>], $b[: <type>], $n[: <type>])
+
+

Example

+
let v3 := mulmod(v0, v1, v2)
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
ai256First factor.
bi256Second factor.
ni256Modulus; 0 yields 0.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — conservativePure
+
+

Annotations

+

None.

+

iszero

+

(Expression::Unary with UnaryOperation::IsZero)

+

Description

+

Returns 1 if the operand is 0, else 0. Also serves as the logical NOT for boolean values.

+

Syntax

+
iszero($operand[: <type>])
+
+

Example

+
let v1 := iszero(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
operandi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i1Pure
+
+

Annotations

+

None.

+

not

+

(Expression::Unary with UnaryOperation::Not)

+

Description

+

Bitwise complement. Inverts every bit; equivalent to xor(operand, 2^256 - 1).

+

Syntax

+
not($operand[: <type>])
+
+

Example

+
let v1 := not(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
operandi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — the complement fills the full word regardless of operand widthPure
+
+

Annotations

+

None.

+

clz

+

(Expression::Unary with UnaryOperation::Clz)

+

Description

+

Count leading zeros. Returns the number of leading zero bits in the operand, where a value of 0 returns 256 (the full width). Not an EVM opcode; reaches newyork as a Yul builtin (FunctionName::Clz) and is translated directly by the Yul-to-newyork translator.

+

Syntax

+
clz($operand[: <type>])
+
+

Example

+
let v1 := clz(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
operandi256
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 — in practice the value fits in nine bits (max 256), so type inference often narrows furtherPure
+
+

Annotations

+

None.

+

truncate<i<bits>>

+

(Expression::Truncate)

+

Description

+

Reinterpret a wider integer as a narrower one by discarding the upper bits. The destination width is carried in the IR’s to: BitWidth field and is rendered inside the angle brackets of the printer mnemonic. Narrowing-only; the source width must be greater than or equal to the destination width.

+

Syntax

+
truncate<i<bits>>($value[: <type>])
+
+

Example

+
let v1 := truncate<i64>(v0)
+let v2 := truncate<i8>(v1)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
valuei256Source value; must be at least as wide as the destination.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
The destination width from the to fieldPure
+
+

Annotations

+

None. The destination width is part of the operation name, not a debug annotation.

+

zext<i<bits>>

+

(Expression::ZeroExtend)

+

Description

+

Reinterpret a narrower integer as a wider one by zero-filling the upper bits. The destination width is carried in the IR’s to: BitWidth field. Widening-only.

+

Syntax

+
zext<i<bits>>($value[: <type>])
+
+

Example

+
let v1 := zext<i256>(v0: i8)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
valuei256Source value; must be no wider than the destination.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
The destination width from the to fieldPure
+
+

Annotations

+

None.

+

sext<i<bits>>

+

(Expression::SignExtendTo)

+

Description

+

Reinterpret a narrower signed integer as a wider one by sign-extending the high bit. The destination width is carried in the IR’s to: BitWidth field. Distinct from signextend (Expression::Binary), which is the EVM byte-position primitive; this one specifies the destination width directly and is introduced by passes that produce a sign-extended value at a known target width.

+

Syntax

+
sext<i<bits>>($value[: <type>])
+
+

Example

+
let v1 := sext<i256>(v0: i64)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
valuei256Source value; must be no wider than the destination.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
The destination width from the to fieldPure
+
+

Annotations

+

None.

+

keccak256

+

(Expression::Keccak256)

+

Description

+

Compute the Keccak-256 hash of length bytes of emulated EVM linear memory starting at offset. The general-purpose hashing primitive; the two specialized variants below cover the common scratch-space patterns more compactly.

+

Syntax

+
keccak256($offset[: <type>], $length[: <type>])
+
+

Example

+
let v2 := keccak256(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
offseti256Byte offset into linear memory; forward analysis widens to at least i64.
lengthi256Length of the region to hash, in bytes; forward analysis widens to at least i64.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure — the hash is a deterministic function of the memory contents at evaluation time. Passes that hoist or dedupe must respect intervening memory writes.
+
+

Annotations

+

None.

+

keccak256_pair

+

(Expression::Keccak256Pair)

+

Description

+

Compound hash of two 256-bit words. Equivalent to mstore(0, word0); mstore(32, word1); keccak256(0, 64) but emitted as a single outlined call after the keccak-fusion pass recognizes the pattern. The mapping-key idiom; see also mapping_sload.

+

Syntax

+
keccak256_pair($word0[: <type>], $word1[: <type>])
+
+

Example

+
let v2 := keccak256_pair(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
word0i256First word; the high 32 bytes of the hash input.
word1i256Second word; the low 32 bytes of the hash input.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

keccak256_single

+

(Expression::Keccak256Single)

+

Description

+

Compound hash of a single 256-bit word. Equivalent to mstore(0, word0); keccak256(0, 32) but emitted as a single outlined call after the keccak-fusion pass.

+

Syntax

+
keccak256_single($word0[: <type>])
+
+

Example

+
let v1 := keccak256_single(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
word0i256The word to hash.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

caller

+

(Expression::Caller)

+

Description

+

Address of the immediate caller of the current call frame.

+

Syntax

+
caller()
+
+

Example

+
let v0 := caller()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i160Pure
+
+

Annotations

+

None.

+

callvalue

+

(Expression::CallValue)

+

Description

+

Value (wei) attached to the current call.

+

Syntax

+
callvalue()
+
+

Example

+
let v0 := callvalue()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

origin

+

(Expression::Origin)

+

Description

+

Address of the original externally owned account that initiated the transaction.

+

Syntax

+
origin()
+
+

Example

+
let v0 := origin()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i160Pure
+
+

Annotations

+

None.

+

address

+

(Expression::Address)

+

Description

+

Address of the contract executing the current call frame.

+

Syntax

+
address()
+
+

Example

+
let v0 := address()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i160Pure
+
+

Annotations

+

None.

+

chainid

+

(Expression::ChainId)

+

Description

+

Chain identifier of the network the contract is executing on.

+

Syntax

+
chainid()
+
+

Example

+
let v0 := chainid()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

gas

+

(Expression::Gas)

+

Description

+

Remaining gas at the point of evaluation. Modelled as a pure expression for IR purposes; in practice it changes between evaluations, so any simplifier that deduplicates pure expressions must respect gas as a barrier.

+

Syntax

+
gas()
+
+

Example

+
let v0 := gas()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure (per IR; see Description)
+
+

Annotations

+

None.

+

msize

+

(Expression::MSize)

+

Description

+

Highest byte offset of emulated EVM linear memory that has been touched, rounded up to the next 32-byte boundary. Unlike gas, classified as side-effectful by the simplifier: unused msize() bindings are not eliminated, because the result depends on the program’s memory-access history and would change if the surrounding statements were reordered.

+

Syntax

+
msize()
+
+

Example

+
let v0 := msize()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Effectful (see Description)
+
+

Annotations

+

None.

+

coinbase

+

(Expression::Coinbase)

+

Description

+

Address of the block’s coinbase (block author).

+

Syntax

+
coinbase()
+
+

Example

+
let v0 := coinbase()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i160Pure
+
+

Annotations

+

None.

+

timestamp

+

(Expression::Timestamp)

+

Description

+

Block timestamp, as a Unix epoch second.

+

Syntax

+
timestamp()
+
+

Example

+
let v0 := timestamp()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure
+
+

Annotations

+

None.

+

number

+

(Expression::Number)

+

Description

+

Current block number.

+

Syntax

+
number()
+
+

Example

+
let v0 := number()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure
+
+

Annotations

+

None.

+

difficulty

+

(Expression::Difficulty)

+

Description

+

Pre-merge block difficulty. On post-merge chains this is the block’s prevrandao value.

+

Syntax

+
difficulty()
+
+

Example

+
let v0 := difficulty()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

gaslimit

+

(Expression::GasLimit)

+

Description

+

Block gas limit.

+

Syntax

+
gaslimit()
+
+

Example

+
let v0 := gaslimit()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure
+
+

Annotations

+

None.

+

basefee

+

(Expression::BaseFee)

+

Description

+

Current block’s EIP-1559 base fee per gas.

+

Syntax

+
basefee()
+
+

Example

+
let v0 := basefee()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

blobbasefee

+

(Expression::BlobBaseFee)

+

Description

+

Current block’s EIP-4844 blob base fee per gas.

+

Syntax

+
blobbasefee()
+
+

Example

+
let v0 := blobbasefee()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

blobhash

+

(Expression::BlobHash)

+

Description

+

Versioned hash of the blob at the given index in the current transaction’s blob list.

+

Syntax

+
blobhash($index[: <type>])
+
+

Example

+
let v1 := blobhash(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
indexi256Blob index; forward analysis widens to at least i64.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

blockhash

+

(Expression::BlockHash)

+

Description

+

Hash of the block with the given number. Per EVM, valid only for the most recent 256 blocks; outside that range the result is 0.

+

Syntax

+
blockhash($number[: <type>])
+
+

Example

+
let v1 := blockhash(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
numberi256Block number; forward analysis widens to at least i64.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

selfbalance

+

(Expression::SelfBalance)

+

Description

+

Balance (in wei) of the contract executing the current call frame. Cheaper than balance(address()).

+

Syntax

+
selfbalance()
+
+

Example

+
let v0 := selfbalance()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

gasprice

+

(Expression::GasPrice)

+

Description

+

Effective gas price of the current transaction.

+

Syntax

+
gasprice()
+
+

Example

+
let v0 := gasprice()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

calldataload

+

(Expression::CallDataLoad)

+

Description

+

Read 32 bytes from the current call’s calldata at the given offset. Reads past the end of calldata return zero bytes.

+

Syntax

+
calldataload($offset[: <type>])
+
+

Example

+
let v1 := calldataload(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
offseti256Byte offset into calldata.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

calldatasize

+

(Expression::CallDataSize)

+

Description

+

Length of the current call’s calldata, in bytes.

+

Syntax

+
calldatasize()
+
+

Example

+
let v0 := calldatasize()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure
+
+

Annotations

+

None.

+

returndatasize

+

(Expression::ReturnDataSize)

+

Description

+

Length of the most recently returned data buffer from a sub-call, in bytes. Modelled as pure per IR but reflects the last ExternalCall / Create result; consumers must respect that ordering.

+

Syntax

+
returndatasize()
+
+

Example

+
let v0 := returndatasize()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure (per IR; see Description)
+
+

Annotations

+

None.

+

codesize

+

(Expression::CodeSize)

+

Description

+

Size of the currently executing code, in bytes.

+

Syntax

+
codesize()
+
+

Example

+
let v0 := codesize()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure
+
+

Annotations

+

None.

+

extcodesize

+

(Expression::ExtCodeSize)

+

Description

+

Size of the code deployed at the given address, in bytes. Returns 0 for accounts with no deployed code.

+

Syntax

+
extcodesize($address[: <type>])
+
+

Example

+
let v1 := extcodesize(v0: i160)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
addressi256Account address; forward analysis widens to at least i160.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure
+
+

Annotations

+

None.

+

extcodehash

+

(Expression::ExtCodeHash)

+

Description

+

Keccak-256 hash of the code deployed at the given address. Returns 0 for non-existent accounts.

+

Syntax

+
extcodehash($address[: <type>])
+
+

Example

+
let v1 := extcodehash(v0: i160)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
addressi256Account address; forward analysis widens to at least i160.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

balance

+

(Expression::Balance)

+

Description

+

Balance (in wei) of the given account address. Use selfbalance for the contract executing the current call frame (cheaper).

+

Syntax

+
balance($address[: <type>])
+
+

Example

+
let v1 := balance(v0: i160)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
addressi256Account address; forward analysis widens to at least i160.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+

None.

+

mload

+

(Expression::MLoad)

+

Description

+

Read a 32-byte word from emulated EVM linear memory at offset. The word is read big-endian per EVM semantics. Pure per IR, but reads after writes return the new value; the memory passes track read/write dependencies separately.

+

Syntax

+
mload($offset[: <type>]) [/* <region> */]
+
+

Example

+
let v1 := mload(v0)
+let v2 := mload(v3) /* free_ptr */
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
offseti256Byte offset into linear memory; forward analysis widens to at least i64.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i32 when region is FreePointerSlot; i256 otherwisePure (per IR; see Description)
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
region: MemoryRegion/* scratch */ · /* free_ptr */ · /* dynamic */ (Unknown is suppressed)
+
+

Same tagging rules as mstore. The region also determines the result width: a load from FreePointerSlot produces an i32 since the FMP fits in a pointer-sized word.

+

sload

+

(Expression::SLoad)

+

Description

+

Read a 32-byte word from persistent contract storage at the given key. Pure per IR; reads after writes to the same slot return the new value.

+

Syntax

+
sload($key[: <type>]) [/* slot: 0x<hex> */]
+
+

Example

+
let v1 := sload(v0)
+let v2 := sload(v3) /* slot: 0x0 */
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
keyi256Storage slot.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure (per IR; see Description)
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
static_slot: Option<BigUint>/* slot: 0x<hex> */ when set; suppressed otherwise
+
+

Same tagging rules as sstore. The printer renders the annotation whenever the field is Some and the deduplicator’s canonicalizer partitions signatures by slot; no pass currently writes Some(...), however, so in present-day dumps the annotation is dormant.

+

tload

+

(Expression::TLoad)

+

Description

+

Read a 32-byte word from transient storage at the given key. Transient storage is wiped at the end of the transaction; pair with tstore.

+

Syntax

+
tload($key[: <type>])
+
+

Example

+
let v1 := tload(v0)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
keyi256Transient storage slot.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure (per IR; see Description)
+
+

Annotations

+

None. The IR does not track a static slot for tload.

+

mapping_sload

+

(Expression::MappingSLoad)

+

Description

+

Compound load for a Solidity mapping element. Equivalent to mstore(0, key); mstore(32, slot); sload(keccak256(0, 64)) but emitted as a single outlined call after the compound_outlining pass recognizes the pattern (it fuses a keccak256_pair — itself produced by mem_opt’s keccak fusion — followed by an sload whose key has a single consumer). Only valid when the intermediate hash is used exclusively by this load.

+

Syntax

+
mapping_sload($key[: <type>], $slot[: <type>])
+
+

Example

+
let v2 := mapping_sload(v0: i160, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
keyi256Mapping key; often narrowed to i160 for address keys.
sloti256The mapping’s declared storage slot.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure (per IR; see Description)
+
+

Annotations

+

None. The fused statement’s effective storage slot is the keccak hash of the key and the declared slot, which is never a compile-time constant; no static_slot hint is surfaced.

+

dataoffset

+

(Expression::DataOffset)

+

Description

+

Offset of a named data segment within the deployed code. The identifier is a string carried in the IR’s id: String field; the linker resolves it to a concrete offset.

+

Syntax

+
dataoffset("<id>")
+
+

Example

+
let v0 := dataoffset("MyContract_deployed")
+
+

Operands

+

None — the identifier is a quoted string literal in the syntax position, not an operand.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
id: StringThe quoted identifier in the syntax position (not a comment annotation; it is the expression itself).
+
+

datasize

+

(Expression::DataSize)

+

Description

+

Size of a named data segment within the deployed code, in bytes. The identifier is resolved by the linker.

+

Syntax

+
datasize("<id>")
+
+

Example

+
let v0 := datasize("MyContract_deployed")
+
+

Operands

+

None — the identifier is a quoted string literal in the syntax position, not an operand.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i64Pure
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
id: StringThe quoted identifier in the syntax position.
+
+

loadimmutable

+

(Expression::LoadImmutable)

+

Description

+

Read the value of a named immutable variable. Immutables are written once during contract construction by SetImmutable and read afterwards via this expression.

+

Syntax

+
loadimmutable("<key>")
+
+

Example

+
let v0 := loadimmutable("MyContract.owner")
+
+

Operands

+

None — the key is a quoted string literal in the syntax position.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256Pure
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
key: StringThe quoted identifier in the syntax position.
+
+

linkersymbol

+

(Expression::LinkerSymbol)

+

Description

+

Address of an external library, resolved by the linker. The path encodes the library’s source location and identifier.

+

Syntax

+
linkersymbol("<path>")
+
+

Example

+
let v0 := linkersymbol("contracts/Library.sol:L")
+
+

Operands

+

None — the path is a quoted string literal in the syntax position.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i160Pure
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
path: StringThe quoted path in the syntax position.
+
+

<func_name>

+

(Expression::Call; the printer emits func_<id> when no function name is registered)

+

Description

+

Internal function call. Invokes a user-defined function declared earlier in the same object; the mnemonic is the function’s Yul-level name, or func_<id> if the printer has no name registered for the FunctionId. Distinct from call and the other EVM call-opcode statements, which cross the contract boundary.

+

Syntax

+
<func_name>([$argument_0[: <type>], $argument_1[: <type>], …])
+
+

Example

+
let v3 := abi_decode_uint256(v0, v1, v2)
+let v4, v5 := returns_two(v0)           // multi-return via let multi-binding
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
argumentsVec<Value>Zero or more argument values, in declaration order; each operand may carry a : <type> suffix.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
One or more values, widths taken from the callee’s declared return types (or the inferred return widths, narrowed via the interprocedural pass). Falls back to i256 when the callee’s returns are unknown to type inference.Effectful — the simplifier treats every call as side-effectful regardless of callee body, so unused call bindings are not DCE’d. The transitive purity of the callee is not tracked at the IR level.
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
function: FunctionIdThe callee’s name in the syntax position (or func_<id> if the printer has no name registered).
+
+

Memory and storage writes

+

The six operations in this section all modify external state: emulated EVM linear memory, persistent storage, or transient storage. They are statements (not expressions) and they are never pure. Simplification and deduplication never reorder them with respect to each other or with respect to reverts; the memory passes treat them as the side-effect boundary for their analyses.

+

mstore

+

(Statement::MStore)

+

Description

+

Write a 32-byte word to emulated EVM linear memory at offset. The word is stored big-endian, matching EVM semantics; the codegen handles the byte swap on PolkaVM’s little-endian RISC-V target.

+

Syntax

+
mstore($offset[: <type>], $value[: <type>]) [/* <region> */]
+
+

Example

+
mstore(v0, v1)                    // Unknown region; no annotation printed
+mstore(v2, v3) /* scratch */      // offset proven to land in 0x00..0x3f
+mstore(v4, v5) /* free_ptr */     // offset is exactly 0x40
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
offseti256Byte offset into linear memory; forward analysis widens to at least i64.
valuei256The 32-byte word to store. Narrower values are zero-extended at codegen time.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
region: MemoryRegion/* scratch */ · /* free_ptr */ · /* dynamic */ (Unknown is suppressed)
+
+

Assigned at translation time from the constant offset (if any); consumed by mem_opt, FMP propagation, and byte-swap mode selection.

+

mstore8

+

(Statement::MStore8)

+

Description

+

Write a single byte to emulated EVM linear memory at offset. The low 8 bits of value are stored; the upper bits are ignored. The operation is otherwise identical to mstore: same operand shape, same region tag, same side-effect classification.

+

Syntax

+
mstore8($offset[: <type>], $value[: <type>]) [/* <region> */]
+
+

Example

+
mstore8(v0, v1: i8)             // value narrowed to i8 by type inference
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
offseti256Byte offset into linear memory; forward analysis widens to at least i64.
valuei256Only the low 8 bits are stored. Often narrowed to i8 by type inference.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
region: MemoryRegion/* scratch */ · /* free_ptr */ · /* dynamic */ (Unknown is suppressed)
+
+

Same tagging rules as mstore. Most mstore8s carry an Unknown region in practice because single-byte writes typically target offsets the translator cannot prove constant.

+

mcopy

+

(Statement::MCopy)

+

Description

+

Copy length bytes from src to dest within emulated EVM linear memory. The Yul builtin mcopy maps directly onto this statement; unlike mstore, it does not carry a region tag because the source and destination ranges may straddle multiple regions.

+

Syntax

+
mcopy($dest[: <type>], $src[: <type>], $length[: <type>])
+
+

Example

+
mcopy(v0, v1, v2)               // dest, src, length
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
desti256Destination byte offset in linear memory.
srci256Source byte offset in linear memory.
lengthi256Number of bytes to copy. Overlapping ranges follow EVM-defined memmove semantics.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None. mcopy carries no region tag because the source and destination ranges may straddle multiple regions, and no static-slot hint because the copy is not storage-bound.

+

sstore

+

(Statement::SStore)

+

Description

+

Write a 32-byte word to persistent contract storage at key. The operation is the durable counterpart of mstore: the value survives across transactions and is observable to subsequent calls to the contract.

+

Syntax

+
sstore($key[: <type>], $value[: <type>]) [/* slot: 0x<hex> */]
+
+

Example

+
sstore(v0, v1)
+sstore(v2, v3) /* slot: 0x0 */
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
keyi256Storage slot. May be a constant slot, a keccak-derived slot for mappings or dynamic arrays, or an arbitrary expression.
valuei256The 256-bit word to store.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
static_slot: Option<BigUint>/* slot: 0x<hex> */ when set; suppressed otherwise
+
+

The printer renders the annotation whenever the field is Some, and the deduplicator’s canonicalizer and mapping-fusion analyses consume it as part of the signature. No pass currently writes Some(...), so the annotation is dormant in present-day dumps; when absent, alias and dedup analyses fall back to the conservative “may alias any slot” assumption.

+

tstore

+

(Statement::TStore)

+

Description

+

Write a 32-byte word to transient storage at key. Transient storage is wiped at the end of the transaction, so tstore is the right primitive for per-transaction bookkeeping (reentrancy guards, cached results) without the gas cost of sstore on EVM. On PolkaVM the transient backing store is provided by pallet-revive.

+

Syntax

+
tstore($key[: <type>], $value[: <type>])
+
+

Example

+
tstore(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
keyi256Transient storage slot.
valuei256The 256-bit word to store.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None. Unlike sstore, the IR does not track a static slot for tstore: transient storage’s short-lived lifetime makes the slot-aware optimizations less valuable, and the translator does not produce the annotation.

+

mapping_sstore

+

(Statement::MappingSStore)

+

Description

+

Compound store for a Solidity mapping element. Equivalent to the three-operation sequence mstore(0, key); mstore(32, slot); sstore(keccak256(0, 64), value) but emitted as a single outlined statement after the compound_outlining pass recognizes the pattern (it fuses a keccak256_pair followed by an sstore whose key has a single consumer). Only valid when the intermediate hash is not observed by any other statement.

+

Syntax

+
mapping_sstore($key[: <type>], $slot[: <type>], $value[: <type>])
+
+

Example

+
mapping_sstore(v0: i160, v1, v2)        // address key, declared slot, value
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
keyi256Mapping key. Often narrowed to i160 for address keys.
sloti256The mapping’s declared storage slot. Typically a small constant.
valuei256The value to store at the computed storage location.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None. mapping_sstore deliberately drops the static_slot annotation that the original sstore may have carried, because the fused statement’s effective slot is the keccak hash of the key and the declared slot, which is never a compile-time constant.

+

Bulk copies

+

Multi-byte memory copies from the five EVM-accessible byte sources (code, external code, returndata, embedded data, and calldata) into emulated EVM linear memory. All five take the same shape: a destination memory offset, a source offset, and a length. They are effectful and act as opaque barriers to the memory passes.

+

codecopy

+

(Statement::CodeCopy)

+

Description

+

Copy length bytes from the currently executing code at offset into emulated EVM linear memory at dest. Reads past the end of code yield zero bytes.

+

Syntax

+
codecopy($dest[: <type>], $offset[: <type>], $length[: <type>])
+
+

Example

+
codecopy(v0, v1, v2)
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
desti256Destination byte offset in linear memory.
offseti256Source byte offset in the executing code.
lengthi256Number of bytes to copy.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None.

+

extcodecopy

+

(Statement::ExtCodeCopy)

+

Description

+

Copy length bytes from the code at address starting at offset into emulated EVM linear memory at dest. Reads beyond the code yield zero bytes; non-existent accounts yield all zeros.

+

Syntax

+
extcodecopy($address[: <type>], $dest[: <type>], $offset[: <type>], $length[: <type>])
+
+

Example

+
extcodecopy(v0: i160, v1, v2, v3)
+
+

Operands

+
+ + + + + + + + + + +
NameTypeNotes
addressi256Account whose code to read; narrows to i160.
desti256Destination byte offset in linear memory.
offseti256Source byte offset in the external code.
lengthi256Number of bytes to copy.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None.

+

returndatacopy

+

(Statement::ReturnDataCopy)

+

Description

+

Copy length bytes from the most recent sub-call’s return data starting at offset into emulated EVM linear memory at dest. Per EVM, reads past the return data’s end revert; the memory passes treat this as a potential trap site.

+

Syntax

+
returndatacopy($dest[: <type>], $offset[: <type>], $length[: <type>])
+
+

Example

+
returndatacopy(v0, v1, v2)
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
desti256Destination byte offset in linear memory.
offseti256Source byte offset in the return-data buffer.
lengthi256Number of bytes to copy.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful (may revert on out-of-range reads, per EVM)
+
+

Annotations

+

None.

+

datacopy

+

(Statement::DataCopy)

+

Description

+

Copy length bytes from an embedded data segment starting at offset into emulated EVM linear memory at dest. The source segment is resolved by the linker, typically used to pull constants compiled into the bytecode into runtime memory.

+

Syntax

+
datacopy($dest[: <type>], $offset[: <type>], $length[: <type>])
+
+

Example

+
datacopy(v0, v1, v2)
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
desti256Destination byte offset in linear memory.
offseti256Source byte offset in the data segment.
lengthi256Number of bytes to copy.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None.

+

calldatacopy

+

(Statement::CallDataCopy)

+

Description

+

Copy length bytes from the current call’s calldata starting at offset into emulated EVM linear memory at dest. Reads past the end of calldata yield zero bytes.

+

Syntax

+
calldatacopy($dest[: <type>], $offset[: <type>], $length[: <type>])
+
+

Example

+
calldatacopy(v0, v1, v2)
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
desti256Destination byte offset in linear memory.
offseti256Source byte offset in calldata.
lengthi256Number of bytes to copy.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None.

+

Bindings and wrappers

+

The statements that bind SSA values, hold loose expressions evaluated for their side effects, and write to immutable storage. Every pure expression in the appendix’s earlier sections appears on the right-hand side of one of these statements (almost always let).

+

let

+

(Statement::Let)

+

Description

+

SSA binding: evaluate an expression and bind its result(s) to a list of fresh value ids. The let statement is the only mechanism by which pure expressions enter the value namespace; every v<id> in a dump was produced by a let (or by a value-yielding control-flow statement or by a parameter at function entry).

+

Syntax

+
let $binding_0[, $binding_1, …] := $expression
+
+

Example

+
let v3 := add(v0, v1)
+let v4, v5 := if v2 [v0, v1] { … } else { … }   // multi-binding from a value-yielding If
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
bindingsVec<ValueId>One or more fresh SSA ids to bind. Most expressions produce one value; control-flow statements may produce several.
valueExpressionThe right-hand side; see any of the Pure expression entries.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None directly — the bound ids carry the expression’s result(s)Effectful (binding establishment); the right-hand side’s purity is independent
+
+

Annotations

+

None.

+

Expression statement

+

(Statement::Expression)

+

Description

+

Wraps an expression evaluated for its observable consequences but whose value is not bound. Typically a user-defined function call (Expression::Call) whose return values the source code discarded, or another Yul expression statement that does not have a dedicated Statement:: variant. EVM external calls (call, delegatecall, etc.) and contract creation (create, create2) translate to dedicated Statement::ExternalCall and Statement::Create variants, not through this wrapper.

+

Syntax

+
$expression
+
+

Example

+
keccak256(v0, v1)           // hash computed but not bound to a value
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
expressionExpressionAny expression; result is discarded.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful (per its statement position)
+
+

Annotations

+

None.

+

setimmutable

+

(Statement::SetImmutable)

+

Description

+

Write an immutable variable during contract construction. Immutables are written once in the constructor and read later via loadimmutable. The key is a string identifier resolved by the linker.

+

Syntax

+
setimmutable("<key>", $value[: <type>])
+
+

Example

+
setimmutable("MyContract.owner", v0: i160)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
valuei256The value to store; the key is a quoted string literal in the syntax position.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
key: StringThe quoted identifier in the syntax position.
+
+

Structured control flow

+

The IR’s control flow is structured: if, switch, and for are statements with explicit nested regions, each carrying input values and yielding output values. The three jump-like statements (break, continue, leave) are scoped to their nearest enclosing construct. Nested blocks create lexical scope without otherwise changing control flow.

+

if

+

(Statement::If)

+

Description

+

Conditional execution with optional value yields. The then region runs when condition is non-zero; the else region runs otherwise. If outputs is non-empty, both regions must yield the same number of values and the statement is bound by a let.

+

Syntax

+
if $condition[: <type>] [[$input_0, $input_1, …]] { … } [else { … }]
+
+

Example

+
if v0 {
+    sstore(v1, v2)
+}
+
+let v5, v6 := if v3 [v1, v2] {
+    let v7 := add(v2, 0x1)
+    yield v1, v7
+} else {
+    yield v1, v2
+}
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
conditioni256Branch selector; non-zero takes the then region. Often narrowed to i1.
inputsVec<Value>Values threaded into both regions, printed in square brackets after the condition.
(regions)The then_region is mandatory; the else_region is optional and, when absent, implicitly yields the inputs unchanged.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None for the statement form; for the value-yielding form, one value per outputs binding, types taken from the yielded valuesEffectful (control flow)
+
+

Annotations

+

None.

+

switch

+

(Statement::Switch)

+

Description

+

Multi-way dispatch on a scrutinee value. Each case matches a specific constant and runs its region; an optional default region catches non-matching values. Like if, switch may yield values via outputs and accept thread-through values via inputs.

+

Syntax

+
switch $scrutinee[: <type>] [[$input_0, …]]
+case 0x<hex> {
+    …
+}
+[case 0x<hex> {
+    …
+} …]
+[default {
+    …
+}]
+
+

Example

+
switch v0
+case 0x0 {
+    sstore(v1, v2)
+}
+case 0x1 {
+    sstore(v1, v3)
+}
+default {
+    invalid()
+}
+
+

Operands

+
+ + + + + + + + + + +
NameTypeNotes
scrutineei256The value to compare against each case.
inputsVec<Value>Values threaded into every case and default region.
casesVec<SwitchCase>Each case carries a constant value: BigUint and a region.
(default)Optional fall-through region.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None for the statement form; one value per outputs binding for the value-yielding formEffectful (control flow)
+
+

Annotations

+

None.

+

for

+

(Statement::For)

+

Description

+

Structured loop with explicit loop-carried variables. Each iteration evaluates condition_statements followed by condition; if the condition is non-zero, the body region runs, then the post region runs, and the loop iterates. Loop-carried variables are passed as SSA values through each region. break exits the loop and continue jumps to the post region.

+

Syntax

+
for { $variable_0 := $initial_0[, …] }
+    [// condition_statements:
+        …]
+    $condition
+    { // post
+        …
+    }
+{
+    … body …
+}
+
+

Example

+
for { v1 := 0x0 }
+    lt(v1, 0xa)
+    { // post
+        let v3 := add(v1, 0x1)
+        yield v3
+    }
+{
+    sstore(v1, v2)
+    yield v1
+}
+
+

Operands

+
+ + + + + + + + + + + + + + +
NameTypeNotes
initial_valuesVec<Value>Starting values for the loop-carried variables.
loop_variablesVec<ValueId>SSA ids visible inside condition, body, and post.
condition_statementsVec<Statement>Statements evaluated each iteration before the condition expression; emitted into the loop header block. Printed only when non-empty, behind a // condition_statements: comment.
conditionExpressionRe-evaluated each iteration; non-zero continues, zero exits.
bodyRegionLoop body; yields current loop-carried values.
post_input_variablesVec<ValueId>Input SSA ids for the post region (one per loop-carried variable); receive the body’s yielded values merged with continue-site values via phi nodes in the LLVM codegen.
postRegionRuns after each body iteration (and after continue); yields updated loop-carried values.
outputsVec<ValueId>Final loop-carried values after exit.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None for the statement form; one value per outputs binding for the value-yielding formEffectful (control flow)
+
+

Annotations

+

None.

+

break

+

(Statement::Break)

+

Description

+

Exit the innermost enclosing for loop. Carries the current values of loop-carried variables at the break point; these become the loop’s outputs.

+

Syntax

+
break
+
+

Example

+
if v0 { break }
+
+

Operands

+

None in the printed form; the IR’s values: Vec<Value> field carries the loop-carried values internally.

+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful (control flow)
+
+

Annotations

+

None.

+

continue

+

(Statement::Continue)

+

Description

+

Skip to the post region of the innermost enclosing for loop. Like break, carries the current values of loop-carried variables internally.

+

Syntax

+
continue
+
+

Example

+
if v0 { continue }
+
+

Operands

+

None in the printed form; the IR’s values field carries the loop-carried values internally.

+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful (control flow)
+
+

Annotations

+

None.

+

leave

+

(Statement::Leave)

+

Description

+

Exit the current function, returning the listed values as the function’s return values. The Yul-level leave keyword translates directly to this statement; the inlining pass eliminates intra-function leaves where possible via the exit-flag transformation.

+

Syntax

+
leave [[$value_0[: <type>], $value_1[: <type>], …]]
+
+

Example

+
leave [v0, v1]              // returns v0 and v1 from the function
+leave                       // returns nothing (void function)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
return_valuesVec<Value>Empty for void functions; otherwise one entry per declared return.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful (control flow)
+
+

Annotations

+

None.

+

Nested block

+

(Statement::Block)

+

Description

+

A lexical scope without conditional or iterative behavior. The body is a region; control falls through after the region’s statements complete. Used to bound the visibility of inner bindings.

+

Syntax

+
{
+    …
+}
+
+

Example

+
{
+    let v0 := add(v1, v2)
+    sstore(v3, v0)
+}                           // v0 is no longer in scope here
+
+

Operands

+

None — the body is a region, not an operand.

+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful (per the body’s contents)
+
+

Annotations

+

None.

+

External interaction

+

Statements that cross the contract boundary: external calls (four kinds), contract creation (two kinds), and event log emission. All produce or rely on external state and act as barriers to memory and storage analyses.

+

call

+

(Statement::ExternalCall with CallKind::Call)

+

Description

+

Standard external call that may transfer value. Reads args_length bytes from emulated EVM linear memory at args_offset as calldata, executes the target, and writes up to ret_length bytes of return data into linear memory at ret_offset. The boolean result indicates success.

+

Syntax

+
let $result := call($gas[: <type>], $address[: <type>], $value[: <type>], $args_offset[: <type>], $args_length[: <type>], $ret_offset[: <type>], $ret_length[: <type>])
+
+

Example

+
let v8 := call(v0, v1: i160, v2, v3, v4, v5, v6)
+
+

Operands

+
+ + + + + + + + + + + + + +
NameTypeNotes
gasi256Gas to forward to the target.
addressi256Callee address; narrows to i160.
valuei256Wei to transfer with the call.
args_offseti256Calldata source offset in linear memory.
args_lengthi256Calldata length in bytes.
ret_offseti256Return-data destination offset in linear memory.
ret_lengthi256Maximum return-data length.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 (success flag: 1 on success, 0 on revert/error; narrowable to i1)Effectful
+
+

Annotations

+

None.

+

callcode

+

(Statement::ExternalCall with CallKind::CallCode)

+

Description

+

Deprecated EVM opcode that executes the callee’s code in the caller’s context but with the callee’s storage. Preserved for Solidity compatibility; new code should use delegatecall.

+

Syntax

+
let $result := callcode($gas[: <type>], $address[: <type>], $value[: <type>], $args_offset[: <type>], $args_length[: <type>], $ret_offset[: <type>], $ret_length[: <type>])
+
+

Example

+
let v8 := callcode(v0, v1: i160, v2, v3, v4, v5, v6)
+
+

Operands

+

Same shape as call.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 (success flag; narrowable to i1)Effectful
+
+

Annotations

+

None.

+

delegatecall

+

(Statement::ExternalCall with CallKind::DelegateCall)

+

Description

+

Execute the callee’s code in the caller’s context: same storage, same sender, same call value. The standard mechanism for library calls and proxy patterns. No value operand (the caller’s call value is inherited).

+

Syntax

+
let $result := delegatecall($gas[: <type>], $address[: <type>], $args_offset[: <type>], $args_length[: <type>], $ret_offset[: <type>], $ret_length[: <type>])
+
+

Example

+
let v7 := delegatecall(v0, v1: i160, v2, v3, v4, v5)
+
+

Operands

+

Same shape as call minus the value operand.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 (success flag; narrowable to i1)Effectful
+
+

Annotations

+

None.

+

staticcall

+

(Statement::ExternalCall with CallKind::StaticCall)

+

Description

+

Read-only external call. Any state modification in the callee (including nested calls) causes the call to revert. No value operand.

+

Syntax

+
let $result := staticcall($gas[: <type>], $address[: <type>], $args_offset[: <type>], $args_length[: <type>], $ret_offset[: <type>], $ret_length[: <type>])
+
+

Example

+
let v7 := staticcall(v0, v1: i160, v2, v3, v4, v5)
+
+

Operands

+

Same shape as call minus the value operand.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 (success flag; narrowable to i1)Effectful (no state writes, but still an external boundary and may revert)
+
+

Annotations

+

None.

+

create

+

(Statement::Create with CreateKind::Create)

+

Description

+

Deploy a new contract with the given init-code bytes, transferring value wei from the caller. The new contract’s address is derived from the caller’s address and nonce; on failure the result is 0.

+

Syntax

+
let $result := create($value[: <type>], $offset[: <type>], $length[: <type>])
+
+

Example

+
let v4 := create(v0, v1, v2)
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
valuei256Wei to transfer to the new contract.
offseti256Linear-memory offset of the init code.
lengthi256Length of the init code in bytes.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 (created address; narrowable to i160 on success, 0 on failure)Effectful
+
+

Annotations

+

None.

+

create2

+

(Statement::Create with CreateKind::Create2)

+

Description

+

Deploy a new contract with a deterministic address derived from the caller’s address, the salt, and the init-code hash. Same operand shape as create plus an additional salt.

+

Syntax

+
let $result := create2($value[: <type>], $offset[: <type>], $length[: <type>], $salt[: <type>])
+
+

Example

+
let v5 := create2(v0, v1, v2, v3)
+
+

Operands

+

Same as create plus salt: i256.

+

Result and purity

+
+ + + + + + + +
ResultPurity
i256 (created address; narrowable to i160 on success, 0 on failure)Effectful
+
+

Annotations

+

None.

+

log<N>

+

(Statement::Log)

+

Description

+

Emit an event log entry. The mnemonic suffix <N> is the number of indexed topics (0 through 4), determined by the length of the IR’s topics field. The data portion is read from length bytes of emulated EVM linear memory at offset.

+

Syntax

+
log<N>($offset[: <type>], $length[: <type>][, $topic_0[: <type>], …])
+
+

Example

+
log0(v0, v1)
+log2(v0, v1, v2, v3)            // two topics
+
+

Operands

+
+ + + + + + + + + +
NameTypeNotes
offseti256Data source offset in linear memory.
lengthi256Data length in bytes.
topicsVec<Value>Zero to four indexed topic values; the length determines the mnemonic suffix.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
NoneEffectful
+
+

Annotations

+

None.

+

Termination

+

Statements that end the current call frame. Three plain forms (return, revert, stop), two unconditional traps (invalid, selfdestruct), and three outlined revert variants that encode common Solidity error patterns into single nodes that can be deduplicated across call sites.

+

return

+

(Statement::Return)

+

Description

+

End the current call frame successfully, returning length bytes from emulated EVM linear memory at offset as the return data.

+

Syntax

+
return($offset[: <type>], $length[: <type>])
+
+

Example

+
return(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
offseti256Return-data source offset.
lengthi256Return-data length.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+

None.

+

revert

+

(Statement::Revert)

+

Description

+

End the current call frame with a revert, undoing all state changes made during the call, and returning length bytes of revert data from emulated EVM linear memory at offset.

+

Syntax

+
revert($offset[: <type>], $length[: <type>])
+
+

Example

+
revert(v0, v1)
+
+

Operands

+
+ + + + + + + + +
NameTypeNotes
offseti256Revert-data source offset.
lengthi256Revert-data length.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+

None.

+

stop

+

(Statement::Stop)

+

Description

+

End the current call frame successfully with empty return data.

+

Syntax

+
stop()
+
+

Example

+
stop()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+

None.

+

invalid

+

(Statement::Invalid)

+

Description

+

Unconditional invalid-opcode trap. Consumes all remaining gas and reverts. Used for unreachable branches and assertion failures.

+

Syntax

+
invalid()
+
+

Example

+
invalid()
+
+

Operands

+

None.

+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+

None.

+

selfdestruct

+

(Statement::SelfDestruct)

+

Description

+

End the current call frame and transfer the contract’s remaining balance to address. Post-Cancun, the contract storage is not deleted (selfdestruct is effectively deprecated; the opcode still exists for legacy compatibility).

+

Syntax

+
selfdestruct($address[: <type>])
+
+

Example

+
selfdestruct(v0: i160)
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
addressi256Recipient of the contract’s balance; narrows to i160.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+

None.

+

panic_revert

+

(Statement::PanicRevert)

+

Description

+

Outlined Solidity panic revert. Equivalent to writing the Panic(uint256) ABI encoding (selector 0x4e487b71 plus the panic code) into emulated EVM linear memory and reverting, but emitted as a single statement that lowers to one outlined helper call. Common panic codes: 0x01 assertion failure, 0x11 arithmetic overflow, 0x12 division by zero, 0x32 array-out-of-bounds, 0x41 memory overflow.

+

Syntax

+
panic_revert(0x<hex>)
+
+

Example

+
panic_revert(0x11)              // arithmetic overflow
+
+

Operands

+

None — the panic code is stored as a u8 field on the IR, not an SSA operand.

+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
code: u8The panic code in 0x<hex> form (two hex digits, zero-padded).
+
+

error_string_revert

+

(Statement::ErrorStringRevert)

+

Description

+

Outlined Solidity Error(string) revert. Equivalent to writing the Error selector (0x08c379a0), the string offset and length, and up to four 32-byte data words into emulated EVM linear memory and reverting. The string length and the data words are stored as compile-time fields; no SSA operands.

+

Syntax

+
error_string_revert(<length>, <N>_words)
+
+

Example

+
error_string_revert(12, 1_words)        // 12-byte string in one 32-byte word
+
+

Operands

+

None — the string length and data are compile-time fields, not SSA operands.

+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+
+ + + + + + + + +
Source fieldPrinted as
length: u8The string length in bytes, in the first syntax position.
data: Vec<BigUint>The number of 32-byte data words (1–4), printed as <N>_words in the second syntax position. The actual data is stored separately and not shown in the printed form.
+
+

custom_error_revert

+

(Statement::CustomErrorRevert)

+

Description

+

Outlined Solidity custom-error revert. Encodes the error selector (left-shifted by 224 bits) and zero to three argument values into scratch memory and reverts. No FMP load is needed; the encoding uses the scratch region at offset 0.

+

Syntax

+
custom_error_revert(0x<hex>, [$arg_0, $arg_1, …])
+
+

Example

+
custom_error_revert(0xa28c4c1100000000000000000000000000000000000000000000000000000000, [v0, v1])
+
+

Operands

+
+ + + + + + + +
NameTypeNotes
argumentsVec<Value>0–3 argument values; the selector is a compile-time field.
+
+

Result and purity

+
+ + + + + + + +
ResultPurity
None — terminates the call frameEffectful (terminator)
+
+

Annotations

+
+ + + + + + + +
Source fieldPrinted as
selector: BigUintThe 4-byte error selector shifted left by 224 bits, printed in hex in the first syntax position.
+

PVM and the pallet-revive runtime target

The revive compiler targets PolkaVM (PVM) via pallet-revive on Polkadot.

diff --git a/docs/revive_runner.html b/docs/revive_runner.html index e52b4e5e1..cd8ed1d17 100644 --- a/docs/revive_runner.html +++ b/docs/revive_runner.html @@ -35,10 +35,10 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-79c091ca.js"; + window.path_to_searchindex_js = "searchindex-767b23cd.js"; - +
diff --git a/docs/roadmap.html b/docs/roadmap.html index 4e0df65b2..70c416db8 100644 --- a/docs/roadmap.html +++ b/docs/roadmap.html @@ -35,10 +35,10 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-79c091ca.js"; + window.path_to_searchindex_js = "searchindex-767b23cd.js"; - +
diff --git a/docs/searcher-c2a407aa.js b/docs/searcher-c2a407aa.js index 6afc6ff66..1eb079d5d 100644 --- a/docs/searcher-c2a407aa.js +++ b/docs/searcher-c2a407aa.js @@ -437,7 +437,7 @@ window.search = window.search || {}; if (yes) { loadSearchScript( window.path_to_searchindex_js || - path_to_root + 'searchindex-79c091ca.js', + path_to_root + 'searchindex-767b23cd.js', 'mdbook-search-index'); search_wrap.classList.remove('hidden'); searchicon.setAttribute('aria-expanded', 'true'); diff --git a/docs/searchindex-767b23cd.js b/docs/searchindex-767b23cd.js new file mode 100644 index 000000000..1d43b6f3c --- /dev/null +++ b/docs/searchindex-767b23cd.js @@ -0,0 +1 @@ +window.search = Object.assign(window.search, JSON.parse('{"doc_urls":["welcome.html#welcome","welcome.html#target-audience","welcome.html#other-polkadot-contracts-resources","welcome.html#about","user_guide.html#resolc-user-guide","user_guide.html#revive-vs-resolc-nomenclature","user_guide/installation.html#installation","user_guide/installation.html#resolc-binary-releases","user_guide/installation.html#installing-the-solc-dependency","user_guide/installation.html#revive-npm-package","user_guide/installation.html#buidling-resolc-from-source","user_guide/cli.html#cli-usage","user_guide/cli.html#llvm-optimization-levels","user_guide/cli.html#stack-size","user_guide/cli.html#heap-size","user_guide/cli.html#solc","user_guide/cli.html#debug-artifacts","user_guide/cli.html#debug-info","user_guide/cli.html#deploy-time-linking","user_guide/js.html#js-npm-package","user_guide/tooling.html#tooling-integration","user_guide/tooling.html#solidity-toolkits","user_guide/tooling.html#compiler-explorer","user_guide/tooling.html#remix-ide","user_guide/std_json.html#standard-json-interface","user_guide/std_json.html#the-settingspolkavm-object","user_guide/std_json.html#settingspolkavmdebuginformation","user_guide/std_json.html#the-settingspolkavmmemoryconfig-object","user_guide/std_json.html#the-settingsoptimizer-object","user_guide/std_json.html#settingsoptimizermode","user_guide/std_json.html#settingsllvmarguments","user_guide/std_json.html#the-settingsoutputselection-object","user_guide/std_json.html#the-all--wildcard","user_guide/std_json.html#the-contract-level-evm-output-selection","user_guide/differences.html#differences-to-evm","user_guide/differences.html#deploy-code-vs-runtime-code","user_guide/differences.html#solidity","user_guide/differences.html#the-6364-gas-rule","user_guide/differences.html#addresscreationcode","user_guide/differences.html#yul-functions","user_guide/differences.html#mload-mstore-msize-mcopy-memory-related-functions","user_guide/differences.html#calldataload-calldatacopy","user_guide/differences.html#codecopy","user_guide/differences.html#create-create2","user_guide/differences.html#dataoffset","user_guide/differences.html#datasize","user_guide/differences.html#revert-return","user_guide/differences.html#prevrandao-difficulty","user_guide/differences.html#pc-extcodecopy","user_guide/differences.html#blobhash-blobbasefee","user_guide/differences.html#difference-regarding-the-solc-via-ir-mode","user_guide/differences.html#example-state-variable-initialization-order-in-inheritance","user_guide/rust_libraries.html#rust-contract-libraries","revive_runner.html#revive-runner-sandbox","revive_runner.html#installation-and-usage","revive_runner.html#trace-logs","revive_runner.html#automatic-contract-instantiation","revive_runner.html#example","developer_guide.html#developer-guide","developer_guide/contributing.html#contributor-guide","developer_guide/contributing.html#getting-started","developer_guide/contributing.html#using-the-makefile","developer_guide/contributing.html#codebase-organization","developer_guide/contributing.html#contribution-rules","developer_guide/contributing.html#style-guide","developer_guide/contributing.html#ai-policy","developer_guide/architecture.html#compiler-architecture-and-internals","developer_guide/architecture.html#resolc","developer_guide/architecture.html#reproducible-contract-builds","developer_guide/architecture.html#the-revive-compiler-libraries","developer_guide/architecture.html#evm-heap-memory","developer_guide/architecture.html#the-llvm-dependency","developer_guide/architecture.html#custom-optimizations","developer_guide/newyork_optimizer.html#the-newyork-optimizer","developer_guide/newyork_optimizer.html#motivation","developer_guide/newyork_optimizer.html#pipeline-overview","developer_guide/newyork_optimizer.html#ir-design","developer_guide/newyork_optimizer.html#key-optimizations-explained","developer_guide/newyork_optimizer.html#type-narrowing","developer_guide/newyork_optimizer.html#guard-narrowing","developer_guide/newyork_optimizer.html#heap-optimization","developer_guide/newyork_optimizer.html#free-memory-pointer-range-proof","developer_guide/newyork_optimizer.html#soundness-traps-for-fmp-optimizations","developer_guide/newyork_optimizer.html#keccak256-fusion-and-folding","developer_guide/newyork_optimizer.html#compound-outlining-mapping-access","developer_guide/newyork_optimizer.html#fuzzy-function-deduplication","developer_guide/newyork_optimizer.html#revert-pattern-outlining","developer_guide/newyork_optimizer.html#outlined-helper-functions","developer_guide/newyork_optimizer.html#codesize-results","developer_guide/newyork_optimizer.html#integration-test-contracts","developer_guide/newyork_optimizer.html#openzeppelin-contracts","developer_guide/newyork_optimizer.html#development-history-and-challenges","developer_guide/newyork_optimizer.html#approaches-that-did-not-work","developer_guide/newyork_optimizer.html#known-limitations-and-future-work","developer_guide/newyork_optimizer.html#environment-variables","developer_guide/newyork_optimizer.html#module-reference","developer_guide/newyork_ir.html#newyork-ir-reference","developer_guide/newyork_ir.html#how-to-read-this-reference","developer_guide/newyork_ir.html#entry-format","developer_guide/newyork_ir.html#syntax-notation","developer_guide/newyork_ir.html#operation-index","developer_guide/newyork_ir.html#type-system","developer_guide/newyork_ir.html#type","developer_guide/newyork_ir.html#bitwidth","developer_guide/newyork_ir.html#addressspace","developer_guide/newyork_ir.html#memoryregion","developer_guide/newyork_ir.html#pure-expressions-1","developer_guide/newyork_ir.html#0xhex","developer_guide/newyork_ir.html#vid","developer_guide/newyork_ir.html#add","developer_guide/newyork_ir.html#sub","developer_guide/newyork_ir.html#mul","developer_guide/newyork_ir.html#div","developer_guide/newyork_ir.html#sdiv","developer_guide/newyork_ir.html#mod","developer_guide/newyork_ir.html#smod","developer_guide/newyork_ir.html#exp","developer_guide/newyork_ir.html#and","developer_guide/newyork_ir.html#or","developer_guide/newyork_ir.html#xor","developer_guide/newyork_ir.html#shl","developer_guide/newyork_ir.html#shr","developer_guide/newyork_ir.html#sar","developer_guide/newyork_ir.html#lt","developer_guide/newyork_ir.html#gt","developer_guide/newyork_ir.html#slt","developer_guide/newyork_ir.html#sgt","developer_guide/newyork_ir.html#eq","developer_guide/newyork_ir.html#byte","developer_guide/newyork_ir.html#signextend","developer_guide/newyork_ir.html#addmod","developer_guide/newyork_ir.html#mulmod","developer_guide/newyork_ir.html#iszero","developer_guide/newyork_ir.html#not","developer_guide/newyork_ir.html#clz","developer_guide/newyork_ir.html#truncateibits","developer_guide/newyork_ir.html#zextibits","developer_guide/newyork_ir.html#sextibits","developer_guide/newyork_ir.html#keccak256","developer_guide/newyork_ir.html#keccak256_pair","developer_guide/newyork_ir.html#keccak256_single","developer_guide/newyork_ir.html#caller","developer_guide/newyork_ir.html#callvalue","developer_guide/newyork_ir.html#origin","developer_guide/newyork_ir.html#address","developer_guide/newyork_ir.html#chainid","developer_guide/newyork_ir.html#gas","developer_guide/newyork_ir.html#msize","developer_guide/newyork_ir.html#coinbase","developer_guide/newyork_ir.html#timestamp","developer_guide/newyork_ir.html#number","developer_guide/newyork_ir.html#difficulty","developer_guide/newyork_ir.html#gaslimit","developer_guide/newyork_ir.html#basefee","developer_guide/newyork_ir.html#blobbasefee","developer_guide/newyork_ir.html#blobhash","developer_guide/newyork_ir.html#blockhash","developer_guide/newyork_ir.html#selfbalance","developer_guide/newyork_ir.html#gasprice","developer_guide/newyork_ir.html#calldataload","developer_guide/newyork_ir.html#calldatasize","developer_guide/newyork_ir.html#returndatasize","developer_guide/newyork_ir.html#codesize","developer_guide/newyork_ir.html#extcodesize","developer_guide/newyork_ir.html#extcodehash","developer_guide/newyork_ir.html#balance","developer_guide/newyork_ir.html#mload","developer_guide/newyork_ir.html#sload","developer_guide/newyork_ir.html#tload","developer_guide/newyork_ir.html#mapping_sload","developer_guide/newyork_ir.html#dataoffset","developer_guide/newyork_ir.html#datasize","developer_guide/newyork_ir.html#loadimmutable","developer_guide/newyork_ir.html#linkersymbol","developer_guide/newyork_ir.html#func_name","developer_guide/newyork_ir.html#memory-and-storage-writes-1","developer_guide/newyork_ir.html#mstore","developer_guide/newyork_ir.html#mstore8","developer_guide/newyork_ir.html#mcopy","developer_guide/newyork_ir.html#sstore","developer_guide/newyork_ir.html#tstore","developer_guide/newyork_ir.html#mapping_sstore","developer_guide/newyork_ir.html#bulk-copies-1","developer_guide/newyork_ir.html#codecopy","developer_guide/newyork_ir.html#extcodecopy","developer_guide/newyork_ir.html#returndatacopy","developer_guide/newyork_ir.html#datacopy","developer_guide/newyork_ir.html#calldatacopy","developer_guide/newyork_ir.html#bindings-and-wrappers-1","developer_guide/newyork_ir.html#let","developer_guide/newyork_ir.html#expression-statement","developer_guide/newyork_ir.html#setimmutable","developer_guide/newyork_ir.html#structured-control-flow-1","developer_guide/newyork_ir.html#if","developer_guide/newyork_ir.html#switch","developer_guide/newyork_ir.html#for","developer_guide/newyork_ir.html#break","developer_guide/newyork_ir.html#continue","developer_guide/newyork_ir.html#leave","developer_guide/newyork_ir.html#nested-block","developer_guide/newyork_ir.html#external-interaction-1","developer_guide/newyork_ir.html#call","developer_guide/newyork_ir.html#callcode","developer_guide/newyork_ir.html#delegatecall","developer_guide/newyork_ir.html#staticcall","developer_guide/newyork_ir.html#create","developer_guide/newyork_ir.html#create2","developer_guide/newyork_ir.html#logn","developer_guide/newyork_ir.html#termination-1","developer_guide/newyork_ir.html#return","developer_guide/newyork_ir.html#revert","developer_guide/newyork_ir.html#stop","developer_guide/newyork_ir.html#invalid","developer_guide/newyork_ir.html#selfdestruct","developer_guide/newyork_ir.html#panic_revert","developer_guide/newyork_ir.html#error_string_revert","developer_guide/newyork_ir.html#custom_error_revert","developer_guide/target.html#pvm-and-the-pallet-revive-runtime-target","developer_guide/target.html#target-cpu-configuration","developer_guide/target.html#why-pvm","developer_guide/target.html#host-environment-pallet-revive","developer_guide/testing.html#testing-strategy","developer_guide/testing.html#bug-compatibility-with-ethereum-solidity","developer_guide/testing.html#differential-integration-tests","developer_guide/testing.html#the-differential-testing-utility","developer_guide/cross_compilation.html#cross-compilation","developer_guide/cross_compilation.html#wasm-via-emscripten","developer_guide/cross_compilation.html#musl-libc","faq.html#faq","faq.html#what-evm-version-do-you-support","faq.html#is-inline-assembly-supported","faq.html#do-you-support-opcode-xy","faq.html#in-what-solidity-version-should-i-write-my-dapp","faq.html#tool-xy-says-the-contract-size-is-larger-than-24kb-and-will-fail-to-deploy","faq.html#is-resolc-a-drop-in-replacement-for-solc","roadmap.html#vision-and-roadmap","roadmap.html#roadmap"],"index":{"documentStore":{"docInfo":{"0":{"body":74,"breadcrumbs":2,"title":1},"1":{"body":22,"breadcrumbs":3,"title":2},"10":{"body":6,"breadcrumbs":7,"title":3},"100":{"body":133,"breadcrumbs":8,"title":2},"101":{"body":25,"breadcrumbs":8,"title":2},"102":{"body":39,"breadcrumbs":7,"title":1},"103":{"body":92,"breadcrumbs":7,"title":1},"104":{"body":61,"breadcrumbs":7,"title":1},"105":{"body":80,"breadcrumbs":7,"title":1},"106":{"body":42,"breadcrumbs":8,"title":2},"107":{"body":83,"breadcrumbs":7,"title":1},"108":{"body":56,"breadcrumbs":7,"title":1},"109":{"body":51,"breadcrumbs":7,"title":1},"11":{"body":33,"breadcrumbs":8,"title":2},"110":{"body":47,"breadcrumbs":7,"title":1},"111":{"body":47,"breadcrumbs":7,"title":1},"112":{"body":49,"breadcrumbs":7,"title":1},"113":{"body":51,"breadcrumbs":7,"title":1},"114":{"body":40,"breadcrumbs":7,"title":1},"115":{"body":48,"breadcrumbs":7,"title":1},"116":{"body":51,"breadcrumbs":7,"title":1},"117":{"body":59,"breadcrumbs":6,"title":0},"118":{"body":30,"breadcrumbs":6,"title":0},"119":{"body":31,"breadcrumbs":7,"title":1},"12":{"body":53,"breadcrumbs":9,"title":3},"120":{"body":58,"breadcrumbs":7,"title":1},"121":{"body":65,"breadcrumbs":7,"title":1},"122":{"body":77,"breadcrumbs":7,"title":1},"123":{"body":40,"breadcrumbs":7,"title":1},"124":{"body":40,"breadcrumbs":7,"title":1},"125":{"body":39,"breadcrumbs":7,"title":1},"126":{"body":39,"breadcrumbs":7,"title":1},"127":{"body":37,"breadcrumbs":7,"title":1},"128":{"body":63,"breadcrumbs":7,"title":1},"129":{"body":81,"breadcrumbs":7,"title":1},"13":{"body":62,"breadcrumbs":8,"title":2},"130":{"body":57,"breadcrumbs":7,"title":1},"131":{"body":57,"breadcrumbs":7,"title":1},"132":{"body":32,"breadcrumbs":7,"title":1},"133":{"body":38,"breadcrumbs":6,"title":0},"134":{"body":61,"breadcrumbs":7,"title":1},"135":{"body":64,"breadcrumbs":7,"title":1},"136":{"body":45,"breadcrumbs":7,"title":1},"137":{"body":66,"breadcrumbs":7,"title":1},"138":{"body":84,"breadcrumbs":7,"title":1},"139":{"body":68,"breadcrumbs":7,"title":1},"14":{"body":75,"breadcrumbs":8,"title":2},"140":{"body":42,"breadcrumbs":7,"title":1},"141":{"body":23,"breadcrumbs":7,"title":1},"142":{"body":22,"breadcrumbs":7,"title":1},"143":{"body":24,"breadcrumbs":7,"title":1},"144":{"body":23,"breadcrumbs":7,"title":1},"145":{"body":22,"breadcrumbs":7,"title":1},"146":{"body":41,"breadcrumbs":7,"title":1},"147":{"body":53,"breadcrumbs":7,"title":1},"148":{"body":22,"breadcrumbs":7,"title":1},"149":{"body":22,"breadcrumbs":7,"title":1},"15":{"body":10,"breadcrumbs":7,"title":1},"150":{"body":20,"breadcrumbs":7,"title":1},"151":{"body":27,"breadcrumbs":7,"title":1},"152":{"body":20,"breadcrumbs":7,"title":1},"153":{"body":25,"breadcrumbs":7,"title":1},"154":{"body":26,"breadcrumbs":7,"title":1},"155":{"body":37,"breadcrumbs":7,"title":1},"156":{"body":42,"breadcrumbs":7,"title":1},"157":{"body":26,"breadcrumbs":7,"title":1},"158":{"body":22,"breadcrumbs":7,"title":1},"159":{"body":40,"breadcrumbs":7,"title":1},"16":{"body":26,"breadcrumbs":8,"title":2},"160":{"body":22,"breadcrumbs":7,"title":1},"161":{"body":41,"breadcrumbs":7,"title":1},"162":{"body":22,"breadcrumbs":7,"title":1},"163":{"body":40,"breadcrumbs":7,"title":1},"164":{"body":41,"breadcrumbs":7,"title":1},"165":{"body":42,"breadcrumbs":7,"title":1},"166":{"body":98,"breadcrumbs":7,"title":1},"167":{"body":84,"breadcrumbs":7,"title":1},"168":{"body":49,"breadcrumbs":7,"title":1},"169":{"body":98,"breadcrumbs":7,"title":1},"17":{"body":15,"breadcrumbs":8,"title":2},"170":{"body":54,"breadcrumbs":7,"title":1},"171":{"body":43,"breadcrumbs":7,"title":1},"172":{"body":47,"breadcrumbs":7,"title":1},"173":{"body":42,"breadcrumbs":7,"title":1},"174":{"body":134,"breadcrumbs":7,"title":1},"175":{"body":33,"breadcrumbs":9,"title":3},"176":{"body":110,"breadcrumbs":7,"title":1},"177":{"body":106,"breadcrumbs":7,"title":1},"178":{"body":98,"breadcrumbs":7,"title":1},"179":{"body":107,"breadcrumbs":7,"title":1},"18":{"body":236,"breadcrumbs":9,"title":3},"180":{"body":88,"breadcrumbs":7,"title":1},"181":{"body":113,"breadcrumbs":7,"title":1},"182":{"body":36,"breadcrumbs":8,"title":2},"183":{"body":63,"breadcrumbs":7,"title":1},"184":{"body":79,"breadcrumbs":7,"title":1},"185":{"body":80,"breadcrumbs":7,"title":1},"186":{"body":69,"breadcrumbs":7,"title":1},"187":{"body":63,"breadcrumbs":7,"title":1},"188":{"body":25,"breadcrumbs":8,"title":2},"189":{"body":98,"breadcrumbs":6,"title":0},"19":{"body":31,"breadcrumbs":9,"title":3},"190":{"body":75,"breadcrumbs":8,"title":2},"191":{"body":59,"breadcrumbs":7,"title":1},"192":{"body":36,"breadcrumbs":9,"title":3},"193":{"body":107,"breadcrumbs":6,"title":0},"194":{"body":107,"breadcrumbs":7,"title":1},"195":{"body":186,"breadcrumbs":6,"title":0},"196":{"body":45,"breadcrumbs":7,"title":1},"197":{"body":43,"breadcrumbs":7,"title":1},"198":{"body":73,"breadcrumbs":7,"title":1},"199":{"body":48,"breadcrumbs":8,"title":2},"2":{"body":7,"breadcrumbs":4,"title":3},"20":{"body":9,"breadcrumbs":7,"title":2},"200":{"body":24,"breadcrumbs":8,"title":2},"201":{"body":120,"breadcrumbs":7,"title":1},"202":{"body":62,"breadcrumbs":7,"title":1},"203":{"body":69,"breadcrumbs":7,"title":1},"204":{"body":65,"breadcrumbs":7,"title":1},"205":{"body":75,"breadcrumbs":7,"title":1},"206":{"body":59,"breadcrumbs":7,"title":1},"207":{"body":81,"breadcrumbs":7,"title":1},"208":{"body":30,"breadcrumbs":7,"title":1},"209":{"body":52,"breadcrumbs":7,"title":1},"21":{"body":14,"breadcrumbs":7,"title":2},"210":{"body":58,"breadcrumbs":7,"title":1},"211":{"body":28,"breadcrumbs":7,"title":1},"212":{"body":33,"breadcrumbs":7,"title":1},"213":{"body":53,"breadcrumbs":7,"title":1},"214":{"body":89,"breadcrumbs":7,"title":1},"215":{"body":100,"breadcrumbs":7,"title":1},"216":{"body":79,"breadcrumbs":7,"title":1},"217":{"body":9,"breadcrumbs":12,"title":5},"218":{"body":14,"breadcrumbs":10,"title":3},"219":{"body":199,"breadcrumbs":8,"title":1},"22":{"body":11,"breadcrumbs":7,"title":2},"220":{"body":34,"breadcrumbs":11,"title":4},"221":{"body":63,"breadcrumbs":6,"title":2},"222":{"body":34,"breadcrumbs":8,"title":4},"223":{"body":187,"breadcrumbs":7,"title":3},"224":{"body":73,"breadcrumbs":7,"title":3},"225":{"body":19,"breadcrumbs":6,"title":2},"226":{"body":69,"breadcrumbs":7,"title":3},"227":{"body":12,"breadcrumbs":6,"title":2},"228":{"body":0,"breadcrumbs":2,"title":1},"229":{"body":12,"breadcrumbs":4,"title":3},"23":{"body":14,"breadcrumbs":7,"title":2},"230":{"body":10,"breadcrumbs":4,"title":3},"231":{"body":4,"breadcrumbs":4,"title":3},"232":{"body":25,"breadcrumbs":5,"title":4},"233":{"body":13,"breadcrumbs":9,"title":8},"234":{"body":9,"breadcrumbs":5,"title":4},"235":{"body":66,"breadcrumbs":4,"title":2},"236":{"body":49,"breadcrumbs":3,"title":1},"24":{"body":15,"breadcrumbs":9,"title":3},"25":{"body":6,"breadcrumbs":8,"title":2},"26":{"body":9,"breadcrumbs":7,"title":1},"27":{"body":31,"breadcrumbs":8,"title":2},"28":{"body":8,"breadcrumbs":8,"title":2},"29":{"body":10,"breadcrumbs":7,"title":1},"3":{"body":15,"breadcrumbs":1,"title":0},"30":{"body":13,"breadcrumbs":7,"title":1},"31":{"body":4,"breadcrumbs":8,"title":2},"32":{"body":63,"breadcrumbs":7,"title":1},"33":{"body":83,"breadcrumbs":11,"title":5},"34":{"body":23,"breadcrumbs":7,"title":2},"35":{"body":41,"breadcrumbs":10,"title":5},"36":{"body":6,"breadcrumbs":6,"title":1},"37":{"body":18,"breadcrumbs":8,"title":3},"38":{"body":5,"breadcrumbs":6,"title":1},"39":{"body":58,"breadcrumbs":7,"title":2},"4":{"body":43,"breadcrumbs":6,"title":3},"40":{"body":64,"breadcrumbs":12,"title":7},"41":{"body":16,"breadcrumbs":7,"title":2},"42":{"body":3,"breadcrumbs":6,"title":1},"43":{"body":101,"breadcrumbs":7,"title":2},"44":{"body":3,"breadcrumbs":6,"title":1},"45":{"body":7,"breadcrumbs":6,"title":1},"46":{"body":8,"breadcrumbs":7,"title":2},"47":{"body":4,"breadcrumbs":7,"title":2},"48":{"body":10,"breadcrumbs":7,"title":2},"49":{"body":20,"breadcrumbs":7,"title":2},"5":{"body":52,"breadcrumbs":7,"title":4},"50":{"body":24,"breadcrumbs":11,"title":6},"51":{"body":57,"breadcrumbs":11,"title":6},"52":{"body":167,"breadcrumbs":9,"title":3},"53":{"body":36,"breadcrumbs":6,"title":3},"54":{"body":21,"breadcrumbs":5,"title":2},"55":{"body":38,"breadcrumbs":5,"title":2},"56":{"body":15,"breadcrumbs":6,"title":3},"57":{"body":120,"breadcrumbs":4,"title":1},"58":{"body":11,"breadcrumbs":4,"title":2},"59":{"body":11,"breadcrumbs":6,"title":2},"6":{"body":24,"breadcrumbs":5,"title":1},"60":{"body":8,"breadcrumbs":6,"title":2},"61":{"body":39,"breadcrumbs":6,"title":2},"62":{"body":85,"breadcrumbs":6,"title":2},"63":{"body":44,"breadcrumbs":6,"title":2},"64":{"body":107,"breadcrumbs":6,"title":2},"65":{"body":112,"breadcrumbs":6,"title":2},"66":{"body":58,"breadcrumbs":7,"title":3},"67":{"body":55,"breadcrumbs":5,"title":1},"68":{"body":76,"breadcrumbs":7,"title":3},"69":{"body":65,"breadcrumbs":7,"title":3},"7":{"body":21,"breadcrumbs":7,"title":3},"70":{"body":57,"breadcrumbs":7,"title":3},"71":{"body":69,"breadcrumbs":6,"title":2},"72":{"body":49,"breadcrumbs":6,"title":2},"73":{"body":45,"breadcrumbs":6,"title":2},"74":{"body":84,"breadcrumbs":5,"title":1},"75":{"body":334,"breadcrumbs":6,"title":2},"76":{"body":116,"breadcrumbs":6,"title":2},"77":{"body":0,"breadcrumbs":7,"title":3},"78":{"body":182,"breadcrumbs":6,"title":2},"79":{"body":72,"breadcrumbs":6,"title":2},"8":{"body":13,"breadcrumbs":7,"title":3},"80":{"body":118,"breadcrumbs":6,"title":2},"81":{"body":147,"breadcrumbs":9,"title":5},"82":{"body":196,"breadcrumbs":8,"title":4},"83":{"body":40,"breadcrumbs":7,"title":3},"84":{"body":43,"breadcrumbs":8,"title":4},"85":{"body":32,"breadcrumbs":7,"title":3},"86":{"body":56,"breadcrumbs":7,"title":3},"87":{"body":84,"breadcrumbs":7,"title":3},"88":{"body":0,"breadcrumbs":6,"title":2},"89":{"body":62,"breadcrumbs":7,"title":3},"9":{"body":5,"breadcrumbs":7,"title":3},"90":{"body":92,"breadcrumbs":6,"title":2},"91":{"body":144,"breadcrumbs":7,"title":3},"92":{"body":71,"breadcrumbs":6,"title":2},"93":{"body":114,"breadcrumbs":8,"title":4},"94":{"body":125,"breadcrumbs":6,"title":2},"95":{"body":139,"breadcrumbs":6,"title":2},"96":{"body":16,"breadcrumbs":9,"title":3},"97":{"body":71,"breadcrumbs":8,"title":2},"98":{"body":174,"breadcrumbs":8,"title":2},"99":{"body":135,"breadcrumbs":8,"title":2}},"docs":{"0":{"body":"Hello and a warm welcome to the revive Solidity compiler book! Warning Solidity on PVM is running on the pallet-revive runtime. This introduces observable semantic differences in comparison with the EVM. Study the differences section carefully. Ignoring these differences may lead to defunct contracts. Notable examples: The 63/64 gas rule isn’t implemented in the pallet (introduces potential DoS vector when calling other contracts) Contract instantiation works differently (by hash instead of by code) The gas model implemented by pallet-revive differs from Ethereum The heap size is fixed instead of gas-metered and there’s a fixed amount of stack size (contracts working fine on EVM may trap on PVM)","breadcrumbs":"Welcome » Welcome","id":"0","title":"Welcome"},"1":{"body":"Solidity dApp developers should read the user guide. Solidity on PolkaVM introduces important differences to EVM which should be well understood. Contributors will find the developer guide helpful for getting up to speed.","breadcrumbs":"Welcome » Target audience","id":"1","title":"Target audience"},"10":{"body":"Please follow the build instructions in the revive README.md.","breadcrumbs":"resolc user guide » Installation » Buidling resolc from source","id":"10","title":"Buidling resolc from source"},"100":{"body":"Pure expressions Constants and variables 0x v Arithmetic add sub mul div sdiv mod smod exp and or xor shl shr sar lt gt slt sgt eq byte signextend addmod mulmod iszero not clz Bit-width conversions truncate> zext> sext> Hashing keccak256 keccak256_pair keccak256_single Environment reads caller callvalue origin address chainid gas msize coinbase timestamp number difficulty gaslimit basefee blobbasefee blobhash blockhash selfbalance gasprice Calldata, returndata, and code calldataload calldatasize returndatasize codesize extcodesize extcodehash balance Memory and storage loads mload sload tload mapping_sload Linker dataoffset datasize loadimmutable linkersymbol Function call Memory and storage writes mstore mstore8 mcopy sstore tstore mapping_sstore Bulk copies codecopy extcodecopy returndatacopy datacopy calldatacopy Bindings and wrappers let expression statement setimmutable Structured control flow if switch for break continue leave nested block External interaction call callcode delegatecall staticcall create create2 log Termination return revert stop invalid selfdestruct panic_revert error_string_revert custom_error_revert","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » Operation index","id":"100","title":"Operation index"},"101":{"body":"Every value in the IR carries a Type. The operation entries below refer to widths ( i1… i256), address spaces ( ptr, etc.), and memory regions ( scratch, etc.) by their printed form; this section is the reference for those names.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » Type system","id":"101","title":"Type system"},"102":{"body":"The umbrella enum. Three variants: Variant Printed as Description Int(BitWidth) i1, i8, …, i256 An integer at one of seven widths; see BitWidth. Ptr(AddressSpace) ptr, ptr, ptr, ptr A pointer tagged with its address space; see AddressSpace. Void void Unit type. Used for statements that produce no value and for void-returning functions.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » Type","id":"102","title":"Type"},"103":{"body":"The seven rungs of integer width. Newly minted values default to I256; type inference narrows them down to one of the lower rungs when it can prove the upper bits are zero or unused. Variant Printed as Typical use I1 i1 Boolean. Result type of every comparison and iszero. I8 i8 Byte values. The narrowest meaningful integer. I32 i32 PolkaVM pointer width (XLEN); minimum width for function parameters under the rv64e ABI. I64 i64 PolkaVM native register width; most narrowed values land here. I128 i128 Two registers; arithmetic that overflows i64 but doesn’t need full 256-bit emulation. I160 i160 Ethereum addresses; result of caller, origin, mapping keys. I256 i256 EVM word width. The default and conservative ceiling.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » BitWidth","id":"103","title":"BitWidth"},"104":{"body":"The address space a pointer points into. Carried on every Ptr value so the codegen can lower loads and stores without a separate alias-analysis pass. Variant Printed as Points into Endianness Heap ptr Emulated EVM linear memory (the simulated mload/ mstore region). Big-endian (by EVM contract). Stack ptr Native PolkaVM stack allocations. Little-endian (no swap). Storage ptr Contract storage; key/value with 256-bit slots. Big-endian on the wire. Code ptr Read-only code/data segment. Big-endian.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » AddressSpace","id":"104","title":"AddressSpace"},"105":{"body":"A refinement carried by every memory load and store on top of AddressSpace::Heap. The tag tells later passes what kind of heap address an offset is hitting, which drives both free-memory-pointer propagation and byte-swap elimination. Variant Address range Printed as Meaning Scratch 0x00– 0x3f /* scratch */ EVM scratch space; safe to touch without consulting the free memory pointer. FreePointerSlot exactly 0x40 /* free_ptr */ Slot that stores the free memory pointer itself. Dynamic 0x80 and above /* dynamic */ Real heap allocations. Unknown everything else (constants in 0x41– 0x7f, plus all non-constant offsets) (suppressed) Conservative fallback used when the offset isn’t a constant or doesn’t slot cleanly.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » MemoryRegion","id":"105","title":"MemoryRegion"},"106":{"body":"Pure expressions produce values without side effects. The simplifier may freely reorder, deduplicate, and eliminate them. They appear on the right-hand side of a let binding, or as operands of other expressions and effectful statements; the operand positions accept SSA value references only, so any pure expression that is consumed elsewhere is first bound by a let. Examples in this section wrap each expression in a let v := … to give it somewhere to land.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » Pure expressions","id":"106","title":"Pure expressions"},"107":{"body":"( Expression::Literal) Description A compile-time constant value with a declared type. New literals minted by the translator default to Int(I256); passes that synthesize constants at narrower widths (e.g. a one-bit boolean from a constant comparison) attach the narrower type directly. Syntax 0x[: ] Example let v0 := 0x2a // 42 at the default i256\\nlet v1 := 0x1: i1 // boolean true\\nlet v2 := 0x80: i64 // narrowed by type inference Operands None — literals are leaves. Result and purity Result Purity Same as the literal’s value_type Pure Annotations Source field Printed as value: BigUint 0x in the syntax position (not a comment annotation; it is the expression itself) value_type: Type : suffix when value_type is not the default Int(I256); suppressed otherwise","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » 0x","id":"107","title":"0x"},"108":{"body":"( Expression::Var) Description A reference to an existing SSA value, used as the entire right-hand side of a let. In a typical dump this is rare because the simplifier collapses let v := v into the consumers of v via copy propagation; expect to see it only in dumps taken before simplification has run. Syntax v Example let v5 := v3 // copy; usually eliminated by simplify Operands None — the expression is the value reference itself. Result and purity Result Purity Same as the referenced value’s type Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » v","id":"108","title":"v"},"109":{"body":"( Expression::Binary with BinaryOperation::Add) Description Modular addition. Wraps on overflow; per EVM, the result is (lhs + rhs) mod 2^N where N is the operand width. Syntax add($lhs[: ], $rhs[: ]) Example let v2 := add(v0, v1) Operands Name Type Notes lhs i256 — rhs i256 — Result and purity Result Purity widen_by_one(max(width(lhs), width(rhs))) — one tier above the wider operand to account for the carry bit Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » add","id":"109","title":"add"},"11":{"body":"We aim to keep the resolc CLI usage close to solc. There are a few things and options worthwhile to know about in resolc which do not exist in the Ethereum world. This chapter explains those in more detail than the CLI help message. Tip For the complete help about CLI options, please see resolc --help.","breadcrumbs":"resolc user guide » Command Line Interface » CLI usage","id":"11","title":"CLI usage"},"110":{"body":"( Expression::Binary with BinaryOperation::Sub) Description Modular subtraction. Wraps on underflow; the result is (lhs - rhs) mod 2^256 regardless of operand widths. Syntax sub($lhs[: ], $rhs[: ]) Example let v2 := sub(v0, v1) Operands Name Type Notes lhs i256 — rhs i256 — Result and purity Result Purity i256 — conservative; underflow on narrower operands could borrow into upper bits Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » sub","id":"110","title":"sub"},"111":{"body":"( Expression::Binary with BinaryOperation::Mul) Description Modular multiplication. The result is (lhs * rhs) mod 2^256. Syntax mul($lhs[: ], $rhs[: ]) Example let v2 := mul(v0, v1) Operands Name Type Notes lhs i256 — rhs i256 — Result and purity Result Purity double_width(max(width(lhs), width(rhs))) — the tier holding twice the wider operand’s bits (skipping i160 at the i128 → i256 transition) Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » mul","id":"111","title":"mul"},"112":{"body":"( Expression::Binary with BinaryOperation::Div) Description Unsigned integer division. Per EVM, div(x, 0) = 0 (no trap on division by zero). Syntax div($lhs[: ], $rhs[: ]) Example let v2 := div(v0, v1) Operands Name Type Notes lhs i256 Dividend. rhs i256 Divisor; 0 yields a result of 0, not a trap. Result and purity Result Purity width(lhs) — the quotient cannot exceed the dividend Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » div","id":"112","title":"div"},"113":{"body":"( Expression::Binary with BinaryOperation::SDiv) Description Signed two’s-complement integer division. Per EVM, sdiv(x, 0) = 0; quotient is truncated toward zero. Syntax sdiv($lhs[: ], $rhs[: ]) Example let v2 := sdiv(v0, v1) Operands Name Type Notes lhs i256 Dividend, treated as signed. rhs i256 Divisor, treated as signed; 0 yields 0. Result and purity Result Purity width(lhs) Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » sdiv","id":"113","title":"sdiv"},"114":{"body":"( Expression::Binary with BinaryOperation::Mod) Description Unsigned modulo. Per EVM, mod(x, 0) = 0. Syntax mod($lhs[: ], $rhs[: ]) Example let v2 := mod(v0, v1) Operands Name Type Notes lhs i256 Dividend. rhs i256 Divisor; 0 yields 0. Result and purity Result Purity width(lhs) Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » mod","id":"114","title":"mod"},"115":{"body":"( Expression::Binary with BinaryOperation::SMod) Description Signed modulo. Per EVM, smod(x, 0) = 0; the result takes the sign of the dividend. Syntax smod($lhs[: ], $rhs[: ]) Example let v2 := smod(v0, v1) Operands Name Type Notes lhs i256 Dividend, treated as signed. rhs i256 Divisor, treated as signed; 0 yields 0. Result and purity Result Purity width(lhs) Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » smod","id":"115","title":"smod"},"116":{"body":"( Expression::Binary with BinaryOperation::Exp) Description Modular exponentiation: (lhs ^ rhs) mod 2^256. The most expensive arithmetic opcode in EVM (variable gas cost proportional to the byte length of rhs). Syntax exp($lhs[: ], $rhs[: ]) Example let v2 := exp(v0, v1) Operands Name Type Notes lhs i256 Base. rhs i256 Exponent. Result and purity Result Purity i256 — conservative; exponentiation can fill any width Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » exp","id":"116","title":"exp"},"117":{"body":"( Expression::Binary with BinaryOperation::And) Description Bitwise AND. The common idiom for type narrowing: a constant mask on the right lets forward analysis pick up a tight result width. Syntax and($lhs[: ], $rhs[: ]) Example let v2 := and(v0, v1)\\nlet v3 := and(v0, 0xff) // type inference narrows result to i8 Operands Name Type Notes lhs i256 — rhs i256 — Result and purity Result Purity min(width(lhs), width(rhs)) — AND can only clear bits, so the result fits in the narrower operand Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » and","id":"117","title":"and"},"118":{"body":"( Expression::Binary with BinaryOperation::Or) Description Bitwise OR. Syntax or($lhs[: ], $rhs[: ]) Example let v2 := or(v0, v1) Operands Name Type Notes lhs i256 — rhs i256 — Result and purity Result Purity max(width(lhs), width(rhs)) Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » or","id":"118","title":"or"},"119":{"body":"( Expression::Binary with BinaryOperation::Xor) Description Bitwise XOR. Syntax xor($lhs[: ], $rhs[: ]) Example let v2 := xor(v0, v1) Operands Name Type Notes lhs i256 — rhs i256 — Result and purity Result Purity max(width(lhs), width(rhs)) Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » xor","id":"119","title":"xor"},"12":{"body":"-O, --optimization resolc exposes the optimization level setting for the LLVM backend. The performance and size of compiled contracts varies wiedly between different optimization levels. Valid levels are the following: 0: No optimizations are applied. 1: Basic optimizations for execution time. 2: Advanced optimizations for execution time. 3: Aggressive optimizations for execution time. s: Optimize for code size. z: Aggressively optimize for code size. By default, -Oz is applied.","breadcrumbs":"resolc user guide » Command Line Interface » LLVM optimization levels","id":"12","title":"LLVM optimization levels"},"120":{"body":"( Expression::Binary with BinaryOperation::Shl) Description Logical left shift. Operand order follows EVM: shl(shift, value) computes value << shift. Shifts ≥ 256 produce 0. Syntax shl($lhs[: ], $rhs[: ]) Example let v2 := shl(v0, v1) // v1 shifted left by v0 bits Operands Name Type Notes lhs i256 Shift amount in bits. rhs i256 Value to shift. Result and purity Result Purity i256 — conservative; bits may shift into any width Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » shl","id":"120","title":"shl"},"121":{"body":"( Expression::Binary with BinaryOperation::Shr) Description Logical right shift. Operand order follows EVM: shr(shift, value) computes value >> shift with zero-fill from the left. Shifts ≥ 256 produce 0. Syntax shr($lhs[: ], $rhs[: ]) Example let v2 := shr(v0, v1) Operands Name Type Notes lhs i256 Shift amount in bits. rhs i256 Value to shift. Result and purity Result Purity If lhs is a known constant k: tier holding 256 - k bits (or i1 for k ≥ 256). Otherwise: width(rhs). Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » shr","id":"121","title":"shr"},"122":{"body":"( Expression::Binary with BinaryOperation::Sar) Description Arithmetic (signed) right shift. Operand order follows EVM: sar(shift, value) shifts value right by shift bits, preserving the sign bit. Shifts ≥ 256 saturate to 0 for non-negative values and to -1 (all-ones) for negative values. Syntax sar($lhs[: ], $rhs[: ]) Example let v2 := sar(v0, v1) Operands Name Type Notes lhs i256 Shift amount in bits. rhs i256 Value to shift, treated as signed. Result and purity Result Purity Same shape as shr forward inference (constant shift narrows the result; non-constant falls back to width(rhs)). Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » sar","id":"122","title":"sar"},"123":{"body":"( Expression::Binary with BinaryOperation::Lt) Description Unsigned less-than comparison. Returns 1 if lhs < rhs, else 0. Syntax lt($lhs[: ], $rhs[: ]) Example let v2 := lt(v0, v1) Operands Name Type Notes lhs i256 Compared unsigned. rhs i256 Compared unsigned. Result and purity Result Purity i1 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » lt","id":"123","title":"lt"},"124":{"body":"( Expression::Binary with BinaryOperation::Gt) Description Unsigned greater-than comparison. Returns 1 if lhs > rhs, else 0. Syntax gt($lhs[: ], $rhs[: ]) Example let v2 := gt(v0, v1) Operands Name Type Notes lhs i256 Compared unsigned. rhs i256 Compared unsigned. Result and purity Result Purity i1 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » gt","id":"124","title":"gt"},"125":{"body":"( Expression::Binary with BinaryOperation::Slt) Description Signed less-than comparison. Operands are treated as two’s complement. Syntax slt($lhs[: ], $rhs[: ]) Example let v2 := slt(v0, v1) Operands Name Type Notes lhs i256 Compared signed. rhs i256 Compared signed. Result and purity Result Purity i1 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » slt","id":"125","title":"slt"},"126":{"body":"( Expression::Binary with BinaryOperation::Sgt) Description Signed greater-than comparison. Operands are treated as two’s complement. Syntax sgt($lhs[: ], $rhs[: ]) Example let v2 := sgt(v0, v1) Operands Name Type Notes lhs i256 Compared signed. rhs i256 Compared signed. Result and purity Result Purity i1 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » sgt","id":"126","title":"sgt"},"127":{"body":"( Expression::Binary with BinaryOperation::Eq) Description Equality comparison. Returns 1 if lhs == rhs, else 0. Signedness is irrelevant. Syntax eq($lhs[: ], $rhs[: ]) Example let v2 := eq(v0, v1) Operands Name Type Notes lhs i256 — rhs i256 — Result and purity Result Purity i1 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » eq","id":"127","title":"eq"},"128":{"body":"( Expression::Binary with BinaryOperation::Byte) Description Extract a single byte from a 256-bit word. byte(i, x) returns the i-th byte of x with byte 0 being the most significant. If i ≥ 32, the result is 0. Syntax byte($lhs[: ], $rhs[: ]) Example let v2 := byte(v0, v1) // v0 = byte index, v1 = word Operands Name Type Notes lhs i256 Byte position; 0 = most significant byte. Values ≥ 32 yield 0. rhs i256 Source word. Result and purity Result Purity i8 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » byte","id":"128","title":"byte"},"129":{"body":"( Expression::Binary with BinaryOperation::SignExtend) Description Sign-extend an integer from a byte position. Per EVM, signextend(b, x) treats byte b of x as the most significant byte of a smaller signed integer and extends its sign through the upper bytes. Syntax signextend($lhs[: ], $rhs[: ]) Example let v2 := signextend(v0, v1) // v0 = byte position, v1 = value Operands Name Type Notes lhs i256 Byte position of the sign byte (0–31). rhs i256 Source value. Result and purity Result Purity i256 — the extended value occupies the full word Pure Annotations The width-targeted sign-extension primitive sext> ( Expression::SignExtendTo) is a separate operation; see the bit-width conversions section.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » signextend","id":"129","title":"signextend"},"13":{"body":"--stack-size PVM is a register machine with a traditional stack memory space for local variables. This controls the total amount of stack space the contract can use. You are incentivized to keep this value as small as possible: Increasing the stack size will increase gas costs due to increased startup costs. The stack size contributes to the total memory size a contract can use, which includes the contract’s code size. Default value: 131072 Warning If the contract uses more stack memory than configured, it will compile fine but eventually revert execution at runtime!","breadcrumbs":"resolc user guide » Command Line Interface » Stack size","id":"13","title":"Stack size"},"130":{"body":"( Expression::Ternary with BinaryOperation::AddMod) Description Ternary modular addition: (a + b) mod n, computed without intermediate overflow. Per EVM, n = 0 yields 0. Syntax addmod($a[: ], $b[: ], $n[: ]) Example let v3 := addmod(v0, v1, v2) Operands Name Type Notes a i256 First addend. b i256 Second addend. n i256 Modulus; 0 yields 0. Result and purity Result Purity i256 — conservative Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » addmod","id":"130","title":"addmod"},"131":{"body":"( Expression::Ternary with BinaryOperation::MulMod) Description Ternary modular multiplication: (a * b) mod n, computed without intermediate overflow. Per EVM, n = 0 yields 0. Syntax mulmod($a[: ], $b[: ], $n[: ]) Example let v3 := mulmod(v0, v1, v2) Operands Name Type Notes a i256 First factor. b i256 Second factor. n i256 Modulus; 0 yields 0. Result and purity Result Purity i256 — conservative Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » mulmod","id":"131","title":"mulmod"},"132":{"body":"( Expression::Unary with UnaryOperation::IsZero) Description Returns 1 if the operand is 0, else 0. Also serves as the logical NOT for boolean values. Syntax iszero($operand[: ]) Example let v1 := iszero(v0) Operands Name Type Notes operand i256 — Result and purity Result Purity i1 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » iszero","id":"132","title":"iszero"},"133":{"body":"( Expression::Unary with UnaryOperation::Not) Description Bitwise complement. Inverts every bit; equivalent to xor(operand, 2^256 - 1). Syntax not($operand[: ]) Example let v1 := not(v0) Operands Name Type Notes operand i256 — Result and purity Result Purity i256 — the complement fills the full word regardless of operand width Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » not","id":"133","title":"not"},"134":{"body":"( Expression::Unary with UnaryOperation::Clz) Description Count leading zeros. Returns the number of leading zero bits in the operand, where a value of 0 returns 256 (the full width). Not an EVM opcode; reaches newyork as a Yul builtin ( FunctionName::Clz) and is translated directly by the Yul-to-newyork translator. Syntax clz($operand[: ]) Example let v1 := clz(v0) Operands Name Type Notes operand i256 — Result and purity Result Purity i256 — in practice the value fits in nine bits (max 256), so type inference often narrows further Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » clz","id":"134","title":"clz"},"135":{"body":"( Expression::Truncate) Description Reinterpret a wider integer as a narrower one by discarding the upper bits. The destination width is carried in the IR’s to: BitWidth field and is rendered inside the angle brackets of the printer mnemonic. Narrowing-only; the source width must be greater than or equal to the destination width. Syntax truncate>($value[: ]) Example let v1 := truncate(v0)\\nlet v2 := truncate(v1) Operands Name Type Notes value i256 Source value; must be at least as wide as the destination. Result and purity Result Purity The destination width from the to field Pure Annotations None. The destination width is part of the operation name, not a debug annotation.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » truncate>","id":"135","title":"truncate>"},"136":{"body":"( Expression::ZeroExtend) Description Reinterpret a narrower integer as a wider one by zero-filling the upper bits. The destination width is carried in the IR’s to: BitWidth field. Widening-only. Syntax zext>($value[: ]) Example let v1 := zext(v0: i8) Operands Name Type Notes value i256 Source value; must be no wider than the destination. Result and purity Result Purity The destination width from the to field Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » zext>","id":"136","title":"zext>"},"137":{"body":"( Expression::SignExtendTo) Description Reinterpret a narrower signed integer as a wider one by sign-extending the high bit. The destination width is carried in the IR’s to: BitWidth field. Distinct from signextend ( Expression::Binary), which is the EVM byte-position primitive; this one specifies the destination width directly and is introduced by passes that produce a sign-extended value at a known target width. Syntax sext>($value[: ]) Example let v1 := sext(v0: i64) Operands Name Type Notes value i256 Source value; must be no wider than the destination. Result and purity Result Purity The destination width from the to field Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » sext>","id":"137","title":"sext>"},"138":{"body":"( Expression::Keccak256) Description Compute the Keccak-256 hash of length bytes of emulated EVM linear memory starting at offset. The general-purpose hashing primitive; the two specialized variants below cover the common scratch-space patterns more compactly. Syntax keccak256($offset[: ], $length[: ]) Example let v2 := keccak256(v0, v1) Operands Name Type Notes offset i256 Byte offset into linear memory; forward analysis widens to at least i64. length i256 Length of the region to hash, in bytes; forward analysis widens to at least i64. Result and purity Result Purity i256 Pure — the hash is a deterministic function of the memory contents at evaluation time. Passes that hoist or dedupe must respect intervening memory writes. Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » keccak256","id":"138","title":"keccak256"},"139":{"body":"( Expression::Keccak256Pair) Description Compound hash of two 256-bit words. Equivalent to mstore(0, word0); mstore(32, word1); keccak256(0, 64) but emitted as a single outlined call after the keccak-fusion pass recognizes the pattern. The mapping-key idiom; see also mapping_sload. Syntax keccak256_pair($word0[: ], $word1[: ]) Example let v2 := keccak256_pair(v0, v1) Operands Name Type Notes word0 i256 First word; the high 32 bytes of the hash input. word1 i256 Second word; the low 32 bytes of the hash input. Result and purity Result Purity i256 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » keccak256_pair","id":"139","title":"keccak256_pair"},"14":{"body":"--heap-size Unlike the EVM, due to the lack of dynamic memory metering, PVM contracts emulate the EVM heap memory with a static buffer. Consequentially, instead of infinite memory with exponentially growing gas costs, PVM contracts have a finite amount of memory with constant gas costs available. You are incentivized to keep this value as small as possible:\\n1.Increasing the heap size will increase startup costs.\\n2.The heap size contributes to the total memory size a contract can use, which includes the contract’s code size Default value: 131072 Warning If the contract uses more heap memory than configured, it will compile fine but eventually revert execution at runtime!","breadcrumbs":"resolc user guide » Command Line Interface » Heap size","id":"14","title":"Heap size"},"140":{"body":"( Expression::Keccak256Single) Description Compound hash of a single 256-bit word. Equivalent to mstore(0, word0); keccak256(0, 32) but emitted as a single outlined call after the keccak-fusion pass. Syntax keccak256_single($word0[: ]) Example let v1 := keccak256_single(v0) Operands Name Type Notes word0 i256 The word to hash. Result and purity Result Purity i256 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » keccak256_single","id":"140","title":"keccak256_single"},"141":{"body":"( Expression::Caller) Description Address of the immediate caller of the current call frame. Syntax caller() Example let v0 := caller() Operands None. Result and purity Result Purity i160 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » caller","id":"141","title":"caller"},"142":{"body":"( Expression::CallValue) Description Value (wei) attached to the current call. Syntax callvalue() Example let v0 := callvalue() Operands None. Result and purity Result Purity i256 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » callvalue","id":"142","title":"callvalue"},"143":{"body":"( Expression::Origin) Description Address of the original externally owned account that initiated the transaction. Syntax origin() Example let v0 := origin() Operands None. Result and purity Result Purity i160 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » origin","id":"143","title":"origin"},"144":{"body":"( Expression::Address) Description Address of the contract executing the current call frame. Syntax address() Example let v0 := address() Operands None. Result and purity Result Purity i160 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » address","id":"144","title":"address"},"145":{"body":"( Expression::ChainId) Description Chain identifier of the network the contract is executing on. Syntax chainid() Example let v0 := chainid() Operands None. Result and purity Result Purity i256 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » chainid","id":"145","title":"chainid"},"146":{"body":"( Expression::Gas) Description Remaining gas at the point of evaluation. Modelled as a pure expression for IR purposes; in practice it changes between evaluations, so any simplifier that deduplicates pure expressions must respect gas as a barrier. Syntax gas() Example let v0 := gas() Operands None. Result and purity Result Purity i64 Pure (per IR; see Description) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » gas","id":"146","title":"gas"},"147":{"body":"( Expression::MSize) Description Highest byte offset of emulated EVM linear memory that has been touched, rounded up to the next 32-byte boundary. Unlike gas, classified as side-effectful by the simplifier: unused msize() bindings are not eliminated, because the result depends on the program’s memory-access history and would change if the surrounding statements were reordered. Syntax msize() Example let v0 := msize() Operands None. Result and purity Result Purity i64 Effectful (see Description) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » msize","id":"147","title":"msize"},"148":{"body":"( Expression::Coinbase) Description Address of the block’s coinbase (block author). Syntax coinbase() Example let v0 := coinbase() Operands None. Result and purity Result Purity i160 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » coinbase","id":"148","title":"coinbase"},"149":{"body":"( Expression::Timestamp) Description Block timestamp, as a Unix epoch second. Syntax timestamp() Example let v0 := timestamp() Operands None. Result and purity Result Purity i64 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » timestamp","id":"149","title":"timestamp"},"15":{"body":"--solc Specify the path to the solc executable. By default, the one in ${PATH} is used.","breadcrumbs":"resolc user guide » Command Line Interface » solc","id":"15","title":"solc"},"150":{"body":"( Expression::Number) Description Current block number. Syntax number() Example let v0 := number() Operands None. Result and purity Result Purity i64 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » number","id":"150","title":"number"},"151":{"body":"( Expression::Difficulty) Description Pre-merge block difficulty. On post-merge chains this is the block’s prevrandao value. Syntax difficulty() Example let v0 := difficulty() Operands None. Result and purity Result Purity i256 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » difficulty","id":"151","title":"difficulty"},"152":{"body":"( Expression::GasLimit) Description Block gas limit. Syntax gaslimit() Example let v0 := gaslimit() Operands None. Result and purity Result Purity i64 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » gaslimit","id":"152","title":"gaslimit"},"153":{"body":"( Expression::BaseFee) Description Current block’s EIP-1559 base fee per gas. Syntax basefee() Example let v0 := basefee() Operands None. Result and purity Result Purity i256 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » basefee","id":"153","title":"basefee"},"154":{"body":"( Expression::BlobBaseFee) Description Current block’s EIP-4844 blob base fee per gas. Syntax blobbasefee() Example let v0 := blobbasefee() Operands None. Result and purity Result Purity i256 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » blobbasefee","id":"154","title":"blobbasefee"},"155":{"body":"( Expression::BlobHash) Description Versioned hash of the blob at the given index in the current transaction’s blob list. Syntax blobhash($index[: ]) Example let v1 := blobhash(v0) Operands Name Type Notes index i256 Blob index; forward analysis widens to at least i64. Result and purity Result Purity i256 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » blobhash","id":"155","title":"blobhash"},"156":{"body":"( Expression::BlockHash) Description Hash of the block with the given number. Per EVM, valid only for the most recent 256 blocks; outside that range the result is 0. Syntax blockhash($number[: ]) Example let v1 := blockhash(v0) Operands Name Type Notes number i256 Block number; forward analysis widens to at least i64. Result and purity Result Purity i256 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » blockhash","id":"156","title":"blockhash"},"157":{"body":"( Expression::SelfBalance) Description Balance (in wei) of the contract executing the current call frame. Cheaper than balance(address()). Syntax selfbalance() Example let v0 := selfbalance() Operands None. Result and purity Result Purity i256 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » selfbalance","id":"157","title":"selfbalance"},"158":{"body":"( Expression::GasPrice) Description Effective gas price of the current transaction. Syntax gasprice() Example let v0 := gasprice() Operands None. Result and purity Result Purity i256 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » gasprice","id":"158","title":"gasprice"},"159":{"body":"( Expression::CallDataLoad) Description Read 32 bytes from the current call’s calldata at the given offset. Reads past the end of calldata return zero bytes. Syntax calldataload($offset[: ]) Example let v1 := calldataload(v0) Operands Name Type Notes offset i256 Byte offset into calldata. Result and purity Result Purity i256 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » calldataload","id":"159","title":"calldataload"},"16":{"body":"--debug-output-dir Dump all intermediary compiler artifacts to files in the specified directory. This includes the YUL IR, optimized and unoptimized LLVM IR, the ELF object and the PVM assembly. Useful for debugging and development purposes.","breadcrumbs":"resolc user guide » Command Line Interface » Debug artifacts","id":"16","title":"Debug artifacts"},"160":{"body":"( Expression::CallDataSize) Description Length of the current call’s calldata, in bytes. Syntax calldatasize() Example let v0 := calldatasize() Operands None. Result and purity Result Purity i64 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » calldatasize","id":"160","title":"calldatasize"},"161":{"body":"( Expression::ReturnDataSize) Description Length of the most recently returned data buffer from a sub-call, in bytes. Modelled as pure per IR but reflects the last ExternalCall / Create result; consumers must respect that ordering. Syntax returndatasize() Example let v0 := returndatasize() Operands None. Result and purity Result Purity i64 Pure (per IR; see Description) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » returndatasize","id":"161","title":"returndatasize"},"162":{"body":"( Expression::CodeSize) Description Size of the currently executing code, in bytes. Syntax codesize() Example let v0 := codesize() Operands None. Result and purity Result Purity i64 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » codesize","id":"162","title":"codesize"},"163":{"body":"( Expression::ExtCodeSize) Description Size of the code deployed at the given address, in bytes. Returns 0 for accounts with no deployed code. Syntax extcodesize($address[: ]) Example let v1 := extcodesize(v0: i160) Operands Name Type Notes address i256 Account address; forward analysis widens to at least i160. Result and purity Result Purity i64 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » extcodesize","id":"163","title":"extcodesize"},"164":{"body":"( Expression::ExtCodeHash) Description Keccak-256 hash of the code deployed at the given address. Returns 0 for non-existent accounts. Syntax extcodehash($address[: ]) Example let v1 := extcodehash(v0: i160) Operands Name Type Notes address i256 Account address; forward analysis widens to at least i160. Result and purity Result Purity i256 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » extcodehash","id":"164","title":"extcodehash"},"165":{"body":"( Expression::Balance) Description Balance (in wei) of the given account address. Use selfbalance for the contract executing the current call frame (cheaper). Syntax balance($address[: ]) Example let v1 := balance(v0: i160) Operands Name Type Notes address i256 Account address; forward analysis widens to at least i160. Result and purity Result Purity i256 Pure Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » balance","id":"165","title":"balance"},"166":{"body":"( Expression::MLoad) Description Read a 32-byte word from emulated EVM linear memory at offset. The word is read big-endian per EVM semantics. Pure per IR, but reads after writes return the new value; the memory passes track read/write dependencies separately. Syntax mload($offset[: ]) [/* */] Example let v1 := mload(v0)\\nlet v2 := mload(v3) /* free_ptr */ Operands Name Type Notes offset i256 Byte offset into linear memory; forward analysis widens to at least i64. Result and purity Result Purity i32 when region is FreePointerSlot; i256 otherwise Pure (per IR; see Description) Annotations Source field Printed as region: MemoryRegion /* scratch */ · /* free_ptr */ · /* dynamic */ ( Unknown is suppressed) Same tagging rules as mstore. The region also determines the result width: a load from FreePointerSlot produces an i32 since the FMP fits in a pointer-sized word.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » mload","id":"166","title":"mload"},"167":{"body":"( Expression::SLoad) Description Read a 32-byte word from persistent contract storage at the given key. Pure per IR; reads after writes to the same slot return the new value. Syntax sload($key[: ]) [/* slot: 0x */] Example let v1 := sload(v0)\\nlet v2 := sload(v3) /* slot: 0x0 */ Operands Name Type Notes key i256 Storage slot. Result and purity Result Purity i256 Pure (per IR; see Description) Annotations Source field Printed as static_slot: Option /* slot: 0x */ when set; suppressed otherwise Same tagging rules as sstore. The printer renders the annotation whenever the field is Some and the deduplicator’s canonicalizer partitions signatures by slot; no pass currently writes Some(...), however, so in present-day dumps the annotation is dormant.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » sload","id":"167","title":"sload"},"168":{"body":"( Expression::TLoad) Description Read a 32-byte word from transient storage at the given key. Transient storage is wiped at the end of the transaction; pair with tstore. Syntax tload($key[: ]) Example let v1 := tload(v0) Operands Name Type Notes key i256 Transient storage slot. Result and purity Result Purity i256 Pure (per IR; see Description) Annotations None. The IR does not track a static slot for tload.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » tload","id":"168","title":"tload"},"169":{"body":"( Expression::MappingSLoad) Description Compound load for a Solidity mapping element. Equivalent to mstore(0, key); mstore(32, slot); sload(keccak256(0, 64)) but emitted as a single outlined call after the compound_outlining pass recognizes the pattern (it fuses a keccak256_pair — itself produced by mem_opt’s keccak fusion — followed by an sload whose key has a single consumer). Only valid when the intermediate hash is used exclusively by this load. Syntax mapping_sload($key[: ], $slot[: ]) Example let v2 := mapping_sload(v0: i160, v1) Operands Name Type Notes key i256 Mapping key; often narrowed to i160 for address keys. slot i256 The mapping’s declared storage slot. Result and purity Result Purity i256 Pure (per IR; see Description) Annotations None. The fused statement’s effective storage slot is the keccak hash of the key and the declared slot, which is never a compile-time constant; no static_slot hint is surfaced.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » mapping_sload","id":"169","title":"mapping_sload"},"17":{"body":"-g Generate source based debug information in the output code file. Useful for debugging and development purposes and disabled by default.","breadcrumbs":"resolc user guide » Command Line Interface » Debug info","id":"17","title":"Debug info"},"170":{"body":"( Expression::DataOffset) Description Offset of a named data segment within the deployed code. The identifier is a string carried in the IR’s id: String field; the linker resolves it to a concrete offset. Syntax dataoffset(\\"\\") Example let v0 := dataoffset(\\"MyContract_deployed\\") Operands None — the identifier is a quoted string literal in the syntax position, not an operand. Result and purity Result Purity i256 Pure Annotations Source field Printed as id: String The quoted identifier in the syntax position (not a comment annotation; it is the expression itself).","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » dataoffset","id":"170","title":"dataoffset"},"171":{"body":"( Expression::DataSize) Description Size of a named data segment within the deployed code, in bytes. The identifier is resolved by the linker. Syntax datasize(\\"\\") Example let v0 := datasize(\\"MyContract_deployed\\") Operands None — the identifier is a quoted string literal in the syntax position, not an operand. Result and purity Result Purity i64 Pure Annotations Source field Printed as id: String The quoted identifier in the syntax position.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » datasize","id":"171","title":"datasize"},"172":{"body":"( Expression::LoadImmutable) Description Read the value of a named immutable variable. Immutables are written once during contract construction by SetImmutable and read afterwards via this expression. Syntax loadimmutable(\\"\\") Example let v0 := loadimmutable(\\"MyContract.owner\\") Operands None — the key is a quoted string literal in the syntax position. Result and purity Result Purity i256 Pure Annotations Source field Printed as key: String The quoted identifier in the syntax position.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » loadimmutable","id":"172","title":"loadimmutable"},"173":{"body":"( Expression::LinkerSymbol) Description Address of an external library, resolved by the linker. The path encodes the library’s source location and identifier. Syntax linkersymbol(\\"\\") Example let v0 := linkersymbol(\\"contracts/Library.sol:L\\") Operands None — the path is a quoted string literal in the syntax position. Result and purity Result Purity i160 Pure Annotations Source field Printed as path: String The quoted path in the syntax position.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » linkersymbol","id":"173","title":"linkersymbol"},"174":{"body":"( Expression::Call; the printer emits func_ when no function name is registered) Description Internal function call. Invokes a user-defined function declared earlier in the same object; the mnemonic is the function’s Yul-level name, or func_ if the printer has no name registered for the FunctionId. Distinct from call and the other EVM call-opcode statements, which cross the contract boundary. Syntax ([$argument_0[: ], $argument_1[: ], …]) Example let v3 := abi_decode_uint256(v0, v1, v2)\\nlet v4, v5 := returns_two(v0) // multi-return via let multi-binding Operands Name Type Notes arguments Vec Zero or more argument values, in declaration order; each operand may carry a : suffix. Result and purity Result Purity One or more values, widths taken from the callee’s declared return types (or the inferred return widths, narrowed via the interprocedural pass). Falls back to i256 when the callee’s returns are unknown to type inference. Effectful — the simplifier treats every call as side-effectful regardless of callee body, so unused call bindings are not DCE’d. The transitive purity of the callee is not tracked at the IR level. Annotations Source field Printed as function: FunctionId The callee’s name in the syntax position (or func_ if the printer has no name registered).","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » ","id":"174","title":""},"175":{"body":"The six operations in this section all modify external state: emulated EVM linear memory, persistent storage, or transient storage. They are statements (not expressions) and they are never pure. Simplification and deduplication never reorder them with respect to each other or with respect to reverts; the memory passes treat them as the side-effect boundary for their analyses.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » Memory and storage writes","id":"175","title":"Memory and storage writes"},"176":{"body":"( Statement::MStore) Description Write a 32-byte word to emulated EVM linear memory at offset. The word is stored big-endian, matching EVM semantics; the codegen handles the byte swap on PolkaVM’s little-endian RISC-V target. Syntax mstore($offset[: ], $value[: ]) [/* */] Example mstore(v0, v1) // Unknown region; no annotation printed\\nmstore(v2, v3) /* scratch */ // offset proven to land in 0x00..0x3f\\nmstore(v4, v5) /* free_ptr */ // offset is exactly 0x40 Operands Name Type Notes offset i256 Byte offset into linear memory; forward analysis widens to at least i64. value i256 The 32-byte word to store. Narrower values are zero-extended at codegen time. Result and purity Result Purity None Effectful Annotations Source field Printed as region: MemoryRegion /* scratch */ · /* free_ptr */ · /* dynamic */ ( Unknown is suppressed) Assigned at translation time from the constant offset (if any); consumed by mem_opt, FMP propagation, and byte-swap mode selection.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » mstore","id":"176","title":"mstore"},"177":{"body":"( Statement::MStore8) Description Write a single byte to emulated EVM linear memory at offset. The low 8 bits of value are stored; the upper bits are ignored. The operation is otherwise identical to mstore: same operand shape, same region tag, same side-effect classification. Syntax mstore8($offset[: ], $value[: ]) [/* */] Example mstore8(v0, v1: i8) // value narrowed to i8 by type inference Operands Name Type Notes offset i256 Byte offset into linear memory; forward analysis widens to at least i64. value i256 Only the low 8 bits are stored. Often narrowed to i8 by type inference. Result and purity Result Purity None Effectful Annotations Source field Printed as region: MemoryRegion /* scratch */ · /* free_ptr */ · /* dynamic */ ( Unknown is suppressed) Same tagging rules as mstore. Most mstore8s carry an Unknown region in practice because single-byte writes typically target offsets the translator cannot prove constant.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » mstore8","id":"177","title":"mstore8"},"178":{"body":"( Statement::MCopy) Description Copy length bytes from src to dest within emulated EVM linear memory. The Yul builtin mcopy maps directly onto this statement; unlike mstore, it does not carry a region tag because the source and destination ranges may straddle multiple regions. Syntax mcopy($dest[: ], $src[: ], $length[: ]) Example mcopy(v0, v1, v2) // dest, src, length Operands Name Type Notes dest i256 Destination byte offset in linear memory. src i256 Source byte offset in linear memory. length i256 Number of bytes to copy. Overlapping ranges follow EVM-defined memmove semantics. Result and purity Result Purity None Effectful Annotations None. mcopy carries no region tag because the source and destination ranges may straddle multiple regions, and no static-slot hint because the copy is not storage-bound.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » mcopy","id":"178","title":"mcopy"},"179":{"body":"( Statement::SStore) Description Write a 32-byte word to persistent contract storage at key. The operation is the durable counterpart of mstore: the value survives across transactions and is observable to subsequent calls to the contract. Syntax sstore($key[: ], $value[: ]) [/* slot: 0x */] Example sstore(v0, v1)\\nsstore(v2, v3) /* slot: 0x0 */ Operands Name Type Notes key i256 Storage slot. May be a constant slot, a keccak-derived slot for mappings or dynamic arrays, or an arbitrary expression. value i256 The 256-bit word to store. Result and purity Result Purity None Effectful Annotations Source field Printed as static_slot: Option /* slot: 0x */ when set; suppressed otherwise The printer renders the annotation whenever the field is Some, and the deduplicator’s canonicalizer and mapping-fusion analyses consume it as part of the signature. No pass currently writes Some(...), so the annotation is dormant in present-day dumps; when absent, alias and dedup analyses fall back to the conservative “may alias any slot” assumption.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » sstore","id":"179","title":"sstore"},"18":{"body":"--link [--libraries ] In Solidity, 3 things can happen with libraries: They are not externally callable and thus can be inlined. The solc Solidity optimizer inlines those (usually the case). Note: resolc always activates the solc Solidity optimizer. If the solc Solidity optimizer is disabled or for some reason fails to inline them (both rare), they are not inlined and require linking. They are externally callable but still linked at compile time. This is the case if at compile time the library address is known (i.e. --libraries supplied in CLI or the corresponding setting in STD JSON input). They are linked at deploy time. This happens when the compiler does not know the library address (i.e. --libraries flag is missing or the provided libraries are incomplete, same for STD JSON input). This case is rare because it’s discourage and should never be used by production dApps. In cases 1.2 and 3: Some of the produced code blobs will be in the “unlinked” raw ELF object format and not yet deployable. To make them deployable, they need to be “linked” (done using the resolc --link linker mode explained below). The compiler emitted DELEGATECALL instructions to call non-inlined (unlinked) libraries. The contract deployer must make sure to deploy any libraries prior to contract deployment. Warning Using deploy time linking is officially discouraged. Mainly due to bytecode hashes changing after the fact. We decided to support it in resolc regardless, due to popular request. Similar to how it works in solc, --libraries may be used to provide libraries during linking mode. Unlike with solc, where linking implies a simple string substitution mechanism, resolc needs to resolve actual missing ELF symbols. This is due to how factory dependencies work in PVM. As a consequence, it isn’t sufficient to just provide the unlinked blobs to the linker. Instead, they must be provided in the exact same directory structure the Solidity source code was found during compile time. Example: The contract src/foo/bar.sol:Bar is involved in deploy time linking. It may be a factory dependency. The contract blob needs to be provided inside a relative src/foo/ directory to --link. Otherwise symbol resolution may fail. Note Tooling is supposed to take care of this. In the future, we may append explicit linkage data to simplify the deploy time linking feature.","breadcrumbs":"resolc user guide » Command Line Interface » Deploy time linking","id":"18","title":"Deploy time linking"},"180":{"body":"( Statement::TStore) Description Write a 32-byte word to transient storage at key. Transient storage is wiped at the end of the transaction, so tstore is the right primitive for per-transaction bookkeeping (reentrancy guards, cached results) without the gas cost of sstore on EVM. On PolkaVM the transient backing store is provided by pallet-revive. Syntax tstore($key[: ], $value[: ]) Example tstore(v0, v1) Operands Name Type Notes key i256 Transient storage slot. value i256 The 256-bit word to store. Result and purity Result Purity None Effectful Annotations None. Unlike sstore, the IR does not track a static slot for tstore: transient storage’s short-lived lifetime makes the slot-aware optimizations less valuable, and the translator does not produce the annotation.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » tstore","id":"180","title":"tstore"},"181":{"body":"( Statement::MappingSStore) Description Compound store for a Solidity mapping element. Equivalent to the three-operation sequence mstore(0, key); mstore(32, slot); sstore(keccak256(0, 64), value) but emitted as a single outlined statement after the compound_outlining pass recognizes the pattern (it fuses a keccak256_pair followed by an sstore whose key has a single consumer). Only valid when the intermediate hash is not observed by any other statement. Syntax mapping_sstore($key[: ], $slot[: ], $value[: ]) Example mapping_sstore(v0: i160, v1, v2) // address key, declared slot, value Operands Name Type Notes key i256 Mapping key. Often narrowed to i160 for address keys. slot i256 The mapping’s declared storage slot. Typically a small constant. value i256 The value to store at the computed storage location. Result and purity Result Purity None Effectful Annotations None. mapping_sstore deliberately drops the static_slot annotation that the original sstore may have carried, because the fused statement’s effective slot is the keccak hash of the key and the declared slot, which is never a compile-time constant.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » mapping_sstore","id":"181","title":"mapping_sstore"},"182":{"body":"Multi-byte memory copies from the five EVM-accessible byte sources (code, external code, returndata, embedded data, and calldata) into emulated EVM linear memory. All five take the same shape: a destination memory offset, a source offset, and a length. They are effectful and act as opaque barriers to the memory passes.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » Bulk copies","id":"182","title":"Bulk copies"},"183":{"body":"( Statement::CodeCopy) Description Copy length bytes from the currently executing code at offset into emulated EVM linear memory at dest. Reads past the end of code yield zero bytes. Syntax codecopy($dest[: ], $offset[: ], $length[: ]) Example codecopy(v0, v1, v2) Operands Name Type Notes dest i256 Destination byte offset in linear memory. offset i256 Source byte offset in the executing code. length i256 Number of bytes to copy. Result and purity Result Purity None Effectful Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » codecopy","id":"183","title":"codecopy"},"184":{"body":"( Statement::ExtCodeCopy) Description Copy length bytes from the code at address starting at offset into emulated EVM linear memory at dest. Reads beyond the code yield zero bytes; non-existent accounts yield all zeros. Syntax extcodecopy($address[: ], $dest[: ], $offset[: ], $length[: ]) Example extcodecopy(v0: i160, v1, v2, v3) Operands Name Type Notes address i256 Account whose code to read; narrows to i160. dest i256 Destination byte offset in linear memory. offset i256 Source byte offset in the external code. length i256 Number of bytes to copy. Result and purity Result Purity None Effectful Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » extcodecopy","id":"184","title":"extcodecopy"},"185":{"body":"( Statement::ReturnDataCopy) Description Copy length bytes from the most recent sub-call’s return data starting at offset into emulated EVM linear memory at dest. Per EVM, reads past the return data’s end revert; the memory passes treat this as a potential trap site. Syntax returndatacopy($dest[: ], $offset[: ], $length[: ]) Example returndatacopy(v0, v1, v2) Operands Name Type Notes dest i256 Destination byte offset in linear memory. offset i256 Source byte offset in the return-data buffer. length i256 Number of bytes to copy. Result and purity Result Purity None Effectful (may revert on out-of-range reads, per EVM) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » returndatacopy","id":"185","title":"returndatacopy"},"186":{"body":"( Statement::DataCopy) Description Copy length bytes from an embedded data segment starting at offset into emulated EVM linear memory at dest. The source segment is resolved by the linker, typically used to pull constants compiled into the bytecode into runtime memory. Syntax datacopy($dest[: ], $offset[: ], $length[: ]) Example datacopy(v0, v1, v2) Operands Name Type Notes dest i256 Destination byte offset in linear memory. offset i256 Source byte offset in the data segment. length i256 Number of bytes to copy. Result and purity Result Purity None Effectful Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » datacopy","id":"186","title":"datacopy"},"187":{"body":"( Statement::CallDataCopy) Description Copy length bytes from the current call’s calldata starting at offset into emulated EVM linear memory at dest. Reads past the end of calldata yield zero bytes. Syntax calldatacopy($dest[: ], $offset[: ], $length[: ]) Example calldatacopy(v0, v1, v2) Operands Name Type Notes dest i256 Destination byte offset in linear memory. offset i256 Source byte offset in calldata. length i256 Number of bytes to copy. Result and purity Result Purity None Effectful Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » calldatacopy","id":"187","title":"calldatacopy"},"188":{"body":"The statements that bind SSA values, hold loose expressions evaluated for their side effects, and write to immutable storage. Every pure expression in the appendix’s earlier sections appears on the right-hand side of one of these statements (almost always let).","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » Bindings and wrappers","id":"188","title":"Bindings and wrappers"},"189":{"body":"( Statement::Let) Description SSA binding: evaluate an expression and bind its result(s) to a list of fresh value ids. The let statement is the only mechanism by which pure expressions enter the value namespace; every v in a dump was produced by a let (or by a value-yielding control-flow statement or by a parameter at function entry). Syntax let $binding_0[, $binding_1, …] := $expression Example let v3 := add(v0, v1)\\nlet v4, v5 := if v2 [v0, v1] { … } else { … } // multi-binding from a value-yielding If Operands Name Type Notes bindings Vec One or more fresh SSA ids to bind. Most expressions produce one value; control-flow statements may produce several. value Expression The right-hand side; see any of the Pure expression entries. Result and purity Result Purity None directly — the bound ids carry the expression’s result(s) Effectful (binding establishment); the right-hand side’s purity is independent Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » let","id":"189","title":"let"},"19":{"body":"The resolc compiler driver is published as an NPM package under @parity/resolc. It’s usable from Node.js code or directly from the command line: npx @parity/resolc@latest --bin crates/integration/contracts/flipper.sol -o /tmp/out Note While the npm package makes a nice portable option, it doesn’t expose all options.","breadcrumbs":"resolc user guide » JS NPM package » JS NPM package","id":"19","title":"JS NPM package"},"190":{"body":"( Statement::Expression) Description Wraps an expression evaluated for its observable consequences but whose value is not bound. Typically a user-defined function call ( Expression::Call) whose return values the source code discarded, or another Yul expression statement that does not have a dedicated Statement:: variant. EVM external calls ( call, delegatecall, etc.) and contract creation ( create, create2) translate to dedicated Statement::ExternalCall and Statement::Create variants, not through this wrapper. Syntax $expression Example keccak256(v0, v1) // hash computed but not bound to a value Operands Name Type Notes expression Expression Any expression; result is discarded. Result and purity Result Purity None Effectful (per its statement position) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » Expression statement","id":"190","title":"Expression statement"},"191":{"body":"( Statement::SetImmutable) Description Write an immutable variable during contract construction. Immutables are written once in the constructor and read later via loadimmutable. The key is a string identifier resolved by the linker. Syntax setimmutable(\\"\\", $value[: ]) Example setimmutable(\\"MyContract.owner\\", v0: i160) Operands Name Type Notes value i256 The value to store; the key is a quoted string literal in the syntax position. Result and purity Result Purity None Effectful Annotations Source field Printed as key: String The quoted identifier in the syntax position.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » setimmutable","id":"191","title":"setimmutable"},"192":{"body":"The IR’s control flow is structured: if, switch, and for are statements with explicit nested regions, each carrying input values and yielding output values. The three jump-like statements ( break, continue, leave) are scoped to their nearest enclosing construct. Nested blocks create lexical scope without otherwise changing control flow.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » Structured control flow","id":"192","title":"Structured control flow"},"193":{"body":"( Statement::If) Description Conditional execution with optional value yields. The then region runs when condition is non-zero; the else region runs otherwise. If outputs is non-empty, both regions must yield the same number of values and the statement is bound by a let. Syntax if $condition[: ] [[$input_0, $input_1, …]] { … } [else { … }] Example if v0 { sstore(v1, v2)\\n} let v5, v6 := if v3 [v1, v2] { let v7 := add(v2, 0x1) yield v1, v7\\n} else { yield v1, v2\\n} Operands Name Type Notes condition i256 Branch selector; non-zero takes the then region. Often narrowed to i1. inputs Vec Values threaded into both regions, printed in square brackets after the condition. (regions) — The then_region is mandatory; the else_region is optional and, when absent, implicitly yields the inputs unchanged. Result and purity Result Purity None for the statement form; for the value-yielding form, one value per outputs binding, types taken from the yielded values Effectful (control flow) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » if","id":"193","title":"if"},"194":{"body":"( Statement::Switch) Description Multi-way dispatch on a scrutinee value. Each case matches a specific constant and runs its region; an optional default region catches non-matching values. Like if, switch may yield values via outputs and accept thread-through values via inputs. Syntax switch $scrutinee[: ] [[$input_0, …]]\\ncase 0x { …\\n}\\n[case 0x { …\\n} …]\\n[default { …\\n}] Example switch v0\\ncase 0x0 { sstore(v1, v2)\\n}\\ncase 0x1 { sstore(v1, v3)\\n}\\ndefault { invalid()\\n} Operands Name Type Notes scrutinee i256 The value to compare against each case. inputs Vec Values threaded into every case and default region. cases Vec Each case carries a constant value: BigUint and a region. (default) — Optional fall-through region. Result and purity Result Purity None for the statement form; one value per outputs binding for the value-yielding form Effectful (control flow) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » switch","id":"194","title":"switch"},"195":{"body":"( Statement::For) Description Structured loop with explicit loop-carried variables. Each iteration evaluates condition_statements followed by condition; if the condition is non-zero, the body region runs, then the post region runs, and the loop iterates. Loop-carried variables are passed as SSA values through each region. break exits the loop and continue jumps to the post region. Syntax for { $variable_0 := $initial_0[, …] } [// condition_statements: …] $condition { // post … }\\n{ … body …\\n} Example for { v1 := 0x0 } lt(v1, 0xa) { // post let v3 := add(v1, 0x1) yield v3 }\\n{ sstore(v1, v2) yield v1\\n} Operands Name Type Notes initial_values Vec Starting values for the loop-carried variables. loop_variables Vec SSA ids visible inside condition, body, and post. condition_statements Vec Statements evaluated each iteration before the condition expression; emitted into the loop header block. Printed only when non-empty, behind a // condition_statements: comment. condition Expression Re-evaluated each iteration; non-zero continues, zero exits. body Region Loop body; yields current loop-carried values. post_input_variables Vec Input SSA ids for the post region (one per loop-carried variable); receive the body’s yielded values merged with continue-site values via phi nodes in the LLVM codegen. post Region Runs after each body iteration (and after continue); yields updated loop-carried values. outputs Vec Final loop-carried values after exit. Result and purity Result Purity None for the statement form; one value per outputs binding for the value-yielding form Effectful (control flow) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » for","id":"195","title":"for"},"196":{"body":"( Statement::Break) Description Exit the innermost enclosing for loop. Carries the current values of loop-carried variables at the break point; these become the loop’s outputs. Syntax break Example if v0 { break } Operands None in the printed form; the IR’s values: Vec field carries the loop-carried values internally. Result and purity Result Purity None Effectful (control flow) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » break","id":"196","title":"break"},"197":{"body":"( Statement::Continue) Description Skip to the post region of the innermost enclosing for loop. Like break, carries the current values of loop-carried variables internally. Syntax continue Example if v0 { continue } Operands None in the printed form; the IR’s values field carries the loop-carried values internally. Result and purity Result Purity None Effectful (control flow) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » continue","id":"197","title":"continue"},"198":{"body":"( Statement::Leave) Description Exit the current function, returning the listed values as the function’s return values. The Yul-level leave keyword translates directly to this statement; the inlining pass eliminates intra-function leaves where possible via the exit-flag transformation. Syntax leave [[$value_0[: ], $value_1[: ], …]] Example leave [v0, v1] // returns v0 and v1 from the function\\nleave // returns nothing (void function) Operands Name Type Notes return_values Vec Empty for void functions; otherwise one entry per declared return. Result and purity Result Purity None Effectful (control flow) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » leave","id":"198","title":"leave"},"199":{"body":"( Statement::Block) Description A lexical scope without conditional or iterative behavior. The body is a region; control falls through after the region’s statements complete. Used to bound the visibility of inner bindings. Syntax { …\\n} Example { let v0 := add(v1, v2) sstore(v3, v0)\\n} // v0 is no longer in scope here Operands None — the body is a region, not an operand. Result and purity Result Purity None Effectful (per the body’s contents) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » Nested block","id":"199","title":"Nested block"},"2":{"body":"Head to contracts.polkadot.io for more general information about contracts on Polkadot.","breadcrumbs":"Welcome » Other Polkadot contracts resources","id":"2","title":"Other Polkadot contracts resources"},"20":{"body":"resolc achieved successful integration with a variety of third party developer tools.","breadcrumbs":"resolc user guide » Tooling integration » Tooling integration","id":"20","title":"Tooling integration"},"200":{"body":"Statements that cross the contract boundary: external calls (four kinds), contract creation (two kinds), and event log emission. All produce or rely on external state and act as barriers to memory and storage analyses.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » External interaction","id":"200","title":"External interaction"},"201":{"body":"( Statement::ExternalCall with CallKind::Call) Description Standard external call that may transfer value. Reads args_length bytes from emulated EVM linear memory at args_offset as calldata, executes the target, and writes up to ret_length bytes of return data into linear memory at ret_offset. The boolean result indicates success. Syntax let $result := call($gas[: ], $address[: ], $value[: ], $args_offset[: ], $args_length[: ], $ret_offset[: ], $ret_length[: ]) Example let v8 := call(v0, v1: i160, v2, v3, v4, v5, v6) Operands Name Type Notes gas i256 Gas to forward to the target. address i256 Callee address; narrows to i160. value i256 Wei to transfer with the call. args_offset i256 Calldata source offset in linear memory. args_length i256 Calldata length in bytes. ret_offset i256 Return-data destination offset in linear memory. ret_length i256 Maximum return-data length. Result and purity Result Purity i256 (success flag: 1 on success, 0 on revert/error; narrowable to i1) Effectful Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » call","id":"201","title":"call"},"202":{"body":"( Statement::ExternalCall with CallKind::CallCode) Description Deprecated EVM opcode that executes the callee’s code in the caller’s context but with the callee’s storage. Preserved for Solidity compatibility; new code should use delegatecall. Syntax let $result := callcode($gas[: ], $address[: ], $value[: ], $args_offset[: ], $args_length[: ], $ret_offset[: ], $ret_length[: ]) Example let v8 := callcode(v0, v1: i160, v2, v3, v4, v5, v6) Operands Same shape as call. Result and purity Result Purity i256 (success flag; narrowable to i1) Effectful Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » callcode","id":"202","title":"callcode"},"203":{"body":"( Statement::ExternalCall with CallKind::DelegateCall) Description Execute the callee’s code in the caller’s context: same storage, same sender, same call value. The standard mechanism for library calls and proxy patterns. No value operand (the caller’s call value is inherited). Syntax let $result := delegatecall($gas[: ], $address[: ], $args_offset[: ], $args_length[: ], $ret_offset[: ], $ret_length[: ]) Example let v7 := delegatecall(v0, v1: i160, v2, v3, v4, v5) Operands Same shape as call minus the value operand. Result and purity Result Purity i256 (success flag; narrowable to i1) Effectful Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » delegatecall","id":"203","title":"delegatecall"},"204":{"body":"( Statement::ExternalCall with CallKind::StaticCall) Description Read-only external call. Any state modification in the callee (including nested calls) causes the call to revert. No value operand. Syntax let $result := staticcall($gas[: ], $address[: ], $args_offset[: ], $args_length[: ], $ret_offset[: ], $ret_length[: ]) Example let v7 := staticcall(v0, v1: i160, v2, v3, v4, v5) Operands Same shape as call minus the value operand. Result and purity Result Purity i256 (success flag; narrowable to i1) Effectful (no state writes, but still an external boundary and may revert) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » staticcall","id":"204","title":"staticcall"},"205":{"body":"( Statement::Create with CreateKind::Create) Description Deploy a new contract with the given init-code bytes, transferring value wei from the caller. The new contract’s address is derived from the caller’s address and nonce; on failure the result is 0. Syntax let $result := create($value[: ], $offset[: ], $length[: ]) Example let v4 := create(v0, v1, v2) Operands Name Type Notes value i256 Wei to transfer to the new contract. offset i256 Linear-memory offset of the init code. length i256 Length of the init code in bytes. Result and purity Result Purity i256 (created address; narrowable to i160 on success, 0 on failure) Effectful Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » create","id":"205","title":"create"},"206":{"body":"( Statement::Create with CreateKind::Create2) Description Deploy a new contract with a deterministic address derived from the caller’s address, the salt, and the init-code hash. Same operand shape as create plus an additional salt. Syntax let $result := create2($value[: ], $offset[: ], $length[: ], $salt[: ]) Example let v5 := create2(v0, v1, v2, v3) Operands Same as create plus salt: i256. Result and purity Result Purity i256 (created address; narrowable to i160 on success, 0 on failure) Effectful Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » create2","id":"206","title":"create2"},"207":{"body":"( Statement::Log) Description Emit an event log entry. The mnemonic suffix is the number of indexed topics ( 0 through 4), determined by the length of the IR’s topics field. The data portion is read from length bytes of emulated EVM linear memory at offset. Syntax log($offset[: ], $length[: ][, $topic_0[: ], …]) Example log0(v0, v1)\\nlog2(v0, v1, v2, v3) // two topics Operands Name Type Notes offset i256 Data source offset in linear memory. length i256 Data length in bytes. topics Vec Zero to four indexed topic values; the length determines the mnemonic suffix. Result and purity Result Purity None Effectful Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » log","id":"207","title":"log"},"208":{"body":"Statements that end the current call frame. Three plain forms ( return, revert, stop), two unconditional traps ( invalid, selfdestruct), and three outlined revert variants that encode common Solidity error patterns into single nodes that can be deduplicated across call sites.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » Termination","id":"208","title":"Termination"},"209":{"body":"( Statement::Return) Description End the current call frame successfully, returning length bytes from emulated EVM linear memory at offset as the return data. Syntax return($offset[: ], $length[: ]) Example return(v0, v1) Operands Name Type Notes offset i256 Return-data source offset. length i256 Return-data length. Result and purity Result Purity None — terminates the call frame Effectful (terminator) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » return","id":"209","title":"return"},"21":{"body":"Support for resolc is available in forks of the hardhat and foundry Solidity toolkits: The Parity Hardhat fork The Parity Foundry fork","breadcrumbs":"resolc user guide » Tooling integration » Solidity toolkits","id":"21","title":"Solidity toolkits"},"210":{"body":"( Statement::Revert) Description End the current call frame with a revert, undoing all state changes made during the call, and returning length bytes of revert data from emulated EVM linear memory at offset. Syntax revert($offset[: ], $length[: ]) Example revert(v0, v1) Operands Name Type Notes offset i256 Revert-data source offset. length i256 Revert-data length. Result and purity Result Purity None — terminates the call frame Effectful (terminator) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » revert","id":"210","title":"revert"},"211":{"body":"( Statement::Stop) Description End the current call frame successfully with empty return data. Syntax stop() Example stop() Operands None. Result and purity Result Purity None — terminates the call frame Effectful (terminator) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » stop","id":"211","title":"stop"},"212":{"body":"( Statement::Invalid) Description Unconditional invalid-opcode trap. Consumes all remaining gas and reverts. Used for unreachable branches and assertion failures. Syntax invalid() Example invalid() Operands None. Result and purity Result Purity None — terminates the call frame Effectful (terminator) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » invalid","id":"212","title":"invalid"},"213":{"body":"( Statement::SelfDestruct) Description End the current call frame and transfer the contract’s remaining balance to address. Post-Cancun, the contract storage is not deleted (selfdestruct is effectively deprecated; the opcode still exists for legacy compatibility). Syntax selfdestruct($address[: ]) Example selfdestruct(v0: i160) Operands Name Type Notes address i256 Recipient of the contract’s balance; narrows to i160. Result and purity Result Purity None — terminates the call frame Effectful (terminator) Annotations None.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » selfdestruct","id":"213","title":"selfdestruct"},"214":{"body":"( Statement::PanicRevert) Description Outlined Solidity panic revert. Equivalent to writing the Panic(uint256) ABI encoding (selector 0x4e487b71 plus the panic code) into emulated EVM linear memory and reverting, but emitted as a single statement that lowers to one outlined helper call. Common panic codes: 0x01 assertion failure, 0x11 arithmetic overflow, 0x12 division by zero, 0x32 array-out-of-bounds, 0x41 memory overflow. Syntax panic_revert(0x) Example panic_revert(0x11) // arithmetic overflow Operands None — the panic code is stored as a u8 field on the IR, not an SSA operand. Result and purity Result Purity None — terminates the call frame Effectful (terminator) Annotations Source field Printed as code: u8 The panic code in 0x form (two hex digits, zero-padded).","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » panic_revert","id":"214","title":"panic_revert"},"215":{"body":"( Statement::ErrorStringRevert) Description Outlined Solidity Error(string) revert. Equivalent to writing the Error selector ( 0x08c379a0), the string offset and length, and up to four 32-byte data words into emulated EVM linear memory and reverting. The string length and the data words are stored as compile-time fields; no SSA operands. Syntax error_string_revert(, _words) Example error_string_revert(12, 1_words) // 12-byte string in one 32-byte word Operands None — the string length and data are compile-time fields, not SSA operands. Result and purity Result Purity None — terminates the call frame Effectful (terminator) Annotations Source field Printed as length: u8 The string length in bytes, in the first syntax position. data: Vec The number of 32-byte data words (1–4), printed as _words in the second syntax position. The actual data is stored separately and not shown in the printed form.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » error_string_revert","id":"215","title":"error_string_revert"},"216":{"body":"( Statement::CustomErrorRevert) Description Outlined Solidity custom-error revert. Encodes the error selector (left-shifted by 224 bits) and zero to three argument values into scratch memory and reverts. No FMP load is needed; the encoding uses the scratch region at offset 0. Syntax custom_error_revert(0x, [$arg_0, $arg_1, …]) Example custom_error_revert(0xa28c4c1100000000000000000000000000000000000000000000000000000000, [v0, v1]) Operands Name Type Notes arguments Vec 0–3 argument values; the selector is a compile-time field. Result and purity Result Purity None — terminates the call frame Effectful (terminator) Annotations Source field Printed as selector: BigUint The 4-byte error selector shifted left by 224 bits, printed in hex in the first syntax position.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » custom_error_revert","id":"216","title":"custom_error_revert"},"217":{"body":"The revive compiler targets PolkaVM (PVM) via pallet-revive on Polkadot.","breadcrumbs":"Developer Guide » PVM and the pallet-revive runtime target » PVM and the pallet-revive runtime target","id":"217","title":"PVM and the pallet-revive runtime target"},"218":{"body":"The exact target CPU configuration can be found here. Note The PVM linker requires fully relocatable ELF objects.","breadcrumbs":"Developer Guide » PVM and the pallet-revive runtime target » Target CPU configuration","id":"218","title":"Target CPU configuration"},"219":{"body":"PVM is a RISC-V based VM designed to overcome the flaws of WebAssebmly (Wasm). Wasm was believed to be a more efficient successor to the rather slow EVM. However, Wasm is far from an ideal target for smart contracts as some of its design decisions are unfavorable for short-lived workloads. The main problem is on-chain Wasm bytecode compilation or interpretation overhead. Prior benchmarks consistently ignoring this overhead seeded the blockchain industry with flawed assumptions: Only when ignoring the startup overhead Wasm is much faster than the slow computing EVM. In practice however, gains are nullified entirely and Wasm loses completely even against very slow VMs like the EVM. Executing Wasm contracts is in fact so inefficient that typical contract workloads are orders of magnitude more expensive than the equivalent EVM variant. On the other hand, since RISC-V is similar to CPUs found in validator hardware (x86 and ARM), bytecode translation mostly boils down to a linear mapping from one instruction to another. The embedded ISA specification reduces the number of general purpose registers, in turn removing the need for expensive register allocation. This guarantees single-pass O(n) JIT compilation of contract bytecode. The close proximity of PVM bytecode with actual validator CPU bytecode effectively allows to move all expensive compilation workload off-chain. Benchmarks ( 1, 2) show that with the PVM JIT, sandboxed PVM code executes at around half the speed of native code, which falls into the same ballpark of the state-of-the-art wasmtime Wasm implementation (while EVM sits somewhere around 1/10 to less than 1/100 of native speed). However, the PVM JIT compiler only uses a fraction of the time wasmtime requires to compile the code. Note The PVM JIT isn’t available yet in pallet-revive. At the time of writing, the contract code is interpreted, which is orders of magnitude slower than the JIT.","breadcrumbs":"Developer Guide » PVM and the pallet-revive runtime target » Why PVM","id":"219","title":"Why PVM"},"22":{"body":"resolc is available on godbolt.org for the Solidity and Yul input languages. See also the announcement post on the forum.","breadcrumbs":"resolc user guide » Tooling integration » Compiler explorer","id":"22","title":"Compiler explorer"},"220":{"body":"The revive compiler targets the pallet-revive runtime environment. pallet-revive exposes a syscall like interface for contract interactions with the host environment. This is provided by the revive-runtime-api library. After the initial launch on the Polkadot Asset Hub blockchain, the runtime API is considered stable and backwards compatible indefinitively.","breadcrumbs":"Developer Guide » PVM and the pallet-revive runtime target » Host environment: pallet-revive","id":"220","title":"Host environment: pallet-revive"},"221":{"body":"Contributors are encouraged to implement some appropriate unit and integration tests together with any bug fixes or new feature implementations. However, when it comes to testing the code generation logic, our testing strategy goes way beyond simple unit and integration tests. This chapter explains how the revive compiler implementation is tested for correctness and how we define correctness. Tip Running the integration tests require the evm tool from go-ethereum in your $PATH. Either install it using your package manager or to build it from source: git clone https://github.com/ethereum/go-ethereum/\\ncd go-ethereum\\nmake all\\nexport PATH=/path/to/go-ethereum/build/bin/:$PATH","breadcrumbs":"Developer Guide » Testing strategy » Testing strategy","id":"221","title":"Testing strategy"},"222":{"body":"As a Solidity compiler, we aim to preserve contract code semantics as close as possible to Solidity compiled to EVM with the solc reference implementation. As highlighted in the user guide, due to the underlying target difference, this isn’t always possible. However, wherever it is possible, we follow the philosophy of bug compatibility with the Ethereum contracts stack.","breadcrumbs":"Developer Guide » Testing strategy » Bug compatibility with Ethereum Solidity","id":"222","title":"Bug compatibility with Ethereum Solidity"},"223":{"body":"A high level of bug compatibility with Ethereum is ensured through differential testing with the Ethereum solc and EVM contracts stack. The revive-integration library is the central integration test utility, providing a set of Solidity integration test cases. Further, it implements differential tests against the reference implementation by combining the revive-runner sandbox, the go-ethereum EVM tool and the revive-differential. The revive-runner library provides a declarative test specification format. This vastly simplifies writing differential test cases and removes a lot of room for errors in test logic. Example: { \\"differential\\": true, \\"actions\\": [ { \\"Instantiate\\": { \\"code\\": { \\"Solidity\\": { \\"contract\\": \\"Bitwise\\" } } } }, { \\"Call\\": { \\"dest\\": { \\"Instantiated\\": 0 }, \\"data\\": \\"3fa4f245\\" } } ]\\n} Above example instantiates the Bitwise contract and calls it with some defined calldata. The revive-runner library implements a helper wrapper to execute test specs on the go-ethereum standalone evm tool. This allows the revive-runner to execute specs against the EVM and the pallet-revive runtime. Key to differential testing is setting \\"differential\\": true, resulting in the following: The Bitwise contract is compiled to EVM and PVM code. The runner executes the defined actions on the EVM and collects all state changes (storage, balance) and execution results. The runner executes each action on the PVM. Observed state changes after each step as well as the final execution result is asserted to match the EVM counterparts exactly. Note how we never defined any expected outcome manually. Instead, we simply observe and collect the data defining the “correct” outcome. Differential testing in combination with declarative test specifications proved to be simple, yet very effective, in ensuring expected Ethereum Solidity semantics on pallet-revive.","breadcrumbs":"Developer Guide » Testing strategy » Differential integration tests","id":"223","title":"Differential integration tests"},"224":{"body":"A lot of nuanced bugs caused by tiny implementation details inside the revive compiler and the pallet-revive runtime could be identified and eliminated early on thanks to the differential testing strategy. Thus, we decided to take this approach further and created a comprehensive test runner and a large suite of more complex test cases. The Revive Differential Tests follow the exact same strategy but implement a much more powerful test spec format, spec runner and reports. This allows differentially testing much more complex test cases (for example testing Uniswap pair creations and swaps), executed via transactions sent to actual blockchain nodes.","breadcrumbs":"Developer Guide » Testing strategy » The differential testing utility","id":"224","title":"The differential testing utility"},"225":{"body":"We cross-compile the resolc.js frontend executable to Wasm for running it in a Node.js or browser environment. The musl target is used to obtain statically linked ELF binaries for Linux.","breadcrumbs":"Developer Guide » Cross compilation » Cross compilation","id":"225","title":"Cross compilation"},"226":{"body":"The REVIVE_LLVM_TARGET_PREFIX environment variable is used to control the target environment LLVM dependency. This requires a compatible LLVM build, obtainable via the revive-llvm build script. Example: # Build the host LLVM dependency with PolkaVM target support\\nmake install-llvm\\nexport LLVM_SYS_221_PREFIX=${PWD}/target-llvm/gnu/target-final # Build the target LLVM dependency with PolkaVM target support\\nrevive-llvm emsdk\\nsource emsdk/emsdk_env.sh\\nrevive-llvm --target-env emscripten build --llvm-projects lld\\nexport REVIVE_LLVM_TARGET_PREFIX=${PWD}/target-llvm/emscripten/target-final # Build the resolc frontend executable\\nmake install-wasm\\nmake test-wasm","breadcrumbs":"Developer Guide » Cross compilation » Wasm via emscripten","id":"226","title":"Wasm via emscripten"},"227":{"body":"rust-musl-cross is a straightforward way to cross compile Rust to musl. The Dockerfile is an executable example of how to do that.","breadcrumbs":"Developer Guide » Cross compilation » musl libc","id":"227","title":"musl libc"},"228":{"body":"","breadcrumbs":"FAQ » FAQ","id":"228","title":"FAQ"},"229":{"body":"We neither do nor don’t support any EVM version. We support Solidity versions, starting from solc version 0.8.0 onwards.","breadcrumbs":"FAQ » What EVM version do you support?","id":"229","title":"What EVM version do you support?"},"23":{"body":"There is remix IDE fork with resolc support at remix.polkadot.io. Unfortunately this is no longer actively maintained (there might be bugs and outdated resolc versions).","breadcrumbs":"resolc user guide » Tooling integration » Remix IDE","id":"23","title":"Remix IDE"},"230":{"body":"Yes, almost all inline assembly features are supported ( see the differences in Yul translation chapter).","breadcrumbs":"FAQ » Is inline assembly supported","id":"230","title":"Is inline assembly supported"},"231":{"body":"See above, the same applies.","breadcrumbs":"FAQ » Do you support opcode XY?","id":"231","title":"Do you support opcode XY?"},"232":{"body":"We generally recommend to always use the latest supported version to profit from latest bugfixes, features and performance improvements. Find out about the latest supported version by running resolc --supported-solc-versions or checking here.","breadcrumbs":"FAQ » In what Solidity version should I write my dApp?","id":"232","title":"In what Solidity version should I write my dApp?"},"233":{"body":"The 24kb code size restriction only exist for the EVM. Our limit is currently around 1mb and may increase further in the future.","breadcrumbs":"FAQ » Tool XY says the contract size is larger than 24kb and will fail to deploy?","id":"233","title":"Tool XY says the contract size is larger than 24kb and will fail to deploy?"},"234":{"body":"No. resolc aims to work similarly to solc, but it’s not considered a drop-in replacement.","breadcrumbs":"FAQ » Is resolc a drop-in replacement for solc?","id":"234","title":"Is resolc a drop-in replacement for solc?"},"235":{"body":"The revive compiler speeds up Solidity contracts significantly. revive provides a decisive edge over other contract platforms. Notably, the compiler eliminates the need of rewriting Solidity dApps in Rust or even as single dApp parachains for scaling reasons. Retaining as high compatibility with Ethereum Solidity as possible keeps entry barriers low. We believe in Dr. Gavin Wood’s ĐApps: What Web 3.0 Looks Like manifesto and the ecosystem of the Solidity programming language. Our motivation lies in the realization that for a true web3 revolution, significant scaling efforts, like the ones provided by the PVM and this project, are necessary to unfold.","breadcrumbs":"Roadmap and Vision » Vision and Roadmap","id":"235","title":"Vision and Roadmap"},"236":{"body":"The first major release, resolc v1.0.0, emits functional PVM code from given Solidity sources. It relies on solc and LLVM for optimizations. The main priority of this release was delivering a mostly feature complete and safe Solidity v0.8.0 compiler. Focus for the second major release is on the custom optimization pipeline, which aims to significantly improve emitted code blob sizes. The below roadmap gives a rough overview of the project’s development timeline.","breadcrumbs":"Roadmap and Vision » Roadmap","id":"236","title":"Roadmap"},"24":{"body":"The revive compiler is mostly compatible with the solc standard JSON interface. There are a few differences and additional (PVM related) input configurations:","breadcrumbs":"resolc user guide » Standard JSON interface » Standard JSON interface","id":"24","title":"Standard JSON interface"},"25":{"body":"Used to configure PVM specific compiler settings.","breadcrumbs":"resolc user guide » Standard JSON interface » The settings.polkavm object","id":"25","title":"The settings.polkavm object"},"26":{"body":"A boolean value allowing to enable debug information. Corresponds to resolc -g.","breadcrumbs":"resolc user guide » Standard JSON interface » settings.polkavm.debugInformation","id":"26","title":"settings.polkavm.debugInformation"},"27":{"body":"Used to apply PVM specific memory configuration settings. settings.polkavm.memoryConfig.heapSize A numerical value allowing to configure the contract heap size. Corresponds to resolc --heap-size. settings.polkavm.memoryConfig.stackSize A numerical value allowing to configure the contract stack size. Corresponds to resolc --stack-size.","breadcrumbs":"resolc user guide » Standard JSON interface » The settings.polkavm.memoryConfig object","id":"27","title":"The settings.polkavm.memoryConfig object"},"28":{"body":"The settings.optimizer object is augmented with support for PVM specific optimization settings.","breadcrumbs":"resolc user guide » Standard JSON interface » The settings.optimizer object","id":"28","title":"The settings.optimizer object"},"29":{"body":"A single char value to configure the LLVM optimizer settings. Corresponds to resolc -O.","breadcrumbs":"resolc user guide » Standard JSON interface » settings.optimizer.mode","id":"29","title":"settings.optimizer.mode"},"3":{"body":"This mdBook documents the revive Solidity compiler project. The content is found under book/. Run make book to observe changes.","breadcrumbs":"Welcome » About","id":"3","title":"About"},"30":{"body":"Allows to specify arbitrary command line arguments to LLVM initialization. Used mainly for development and debugging purposes.","breadcrumbs":"resolc user guide » Standard JSON interface » settings.llvmArguments","id":"30","title":"settings.llvmArguments"},"31":{"body":"Used to select desired outputs.","breadcrumbs":"resolc user guide » Standard JSON interface » The settings.outputSelection object","id":"31","title":"The settings.outputSelection object"},"32":{"body":"Resolc supports the “all” ( *) wildcard for the file-level (first-level) and contract-level (second-level) keys. A file-level key can be either the wildcard or a specific file name, whereas the contract-level key can only be the wildcard for robustness reasons. Thus, output can be requested in 2 ways: // All files and all contracts:\\n{ \\"settings\\": { \\"outputSelection\\": { \\"*\\": { \\"*\\": [/* specific contract-level output fields */], \\"\\": [/* specific file-level output fields */] } } }\\n} // Specific files and all their contracts:\\n{ \\"settings\\": { \\"outputSelection\\": { \\"path/to/my/file.sol\\": { \\"*\\": [/* specific contract-level output fields */], \\"\\": [/* specific file-level output fields */] }, // Rest of files... } }\\n}","breadcrumbs":"resolc user guide » Standard JSON interface » The “all” ( *) wildcard","id":"32","title":"The “all” ( *) wildcard"},"33":{"body":"Note Currently, resolc supports requesting either the full evm output, or one more level of specificity, such as evm.bytecode. When requesting code generation, such as evm.bytecode or evm.assembly, the resolc compilation process additionally needs ast, metadata, irOptimized, and evm.methodIdentifiers selectors. These selectors will be automatically added if code generation is needed, but will only be included in the output if explicitly requested. { \\"settings\\": { \\"outputSelection\\": { \\"path/to/my/file1.sol\\": { // Contracts in this file will generate bytecode. // Only these fields of the JSON output selection will be in the `contracts` output. \\"*\\": [\\"abi\\", \\"evm.methodIdentifiers\\", \\"metadata\\", \\"evm.bytecode\\"], // Only this field of the JSON output selection will be in the `sources` output. \\"\\": [\\"ast\\"] }, \\"path/to/my/file2.sol\\": { // No contracts in this file will generate bytecode. \\"*\\": [\\"abi\\", \\"evm.methodIdentifiers\\", \\"metadata\\"], // No `ast` will be in the `sources` output (only the automatically added `id`, // similar to solc as this is not a configurable output selection). \\"\\": [] }, } }\\n}","breadcrumbs":"resolc user guide » Standard JSON interface » The contract-level evm output selection","id":"33","title":"The contract-level evm output selection"},"34":{"body":"This section highlights some potentially observable differences in the YUL EVM dialect translation compared to Ethereum Solidity. Solidity developers deploying dApps to pallet-revive ought to read and understand this section well.","breadcrumbs":"resolc user guide » Differences to EVM » Differences to EVM","id":"34","title":"Differences to EVM"},"35":{"body":"Our contract runtime does not differentiate between runtime code and deploy (constructor) code.\\nInstead, both are emitted into a single PVM contract code blob and live on-chain.\\nTherefore, in EVM terminology, the deploy code equals the runtime code. Tip In constructor code, the codesize instruction will return the call data size instead of the actual code blob size.","breadcrumbs":"resolc user guide » Differences to EVM » Deploy code vs. runtime code","id":"35","title":"Deploy code vs. runtime code"},"36":{"body":"We are aware of the following differences in the translation of Solidity code.","breadcrumbs":"resolc user guide » Differences to EVM » Solidity","id":"36","title":"Solidity"},"37":{"body":"pallet-revive doesn’t apply the 63/64 gas rule. We strongly advice to change any code calling untrusted contracts to supply a limited amount of gas only!","breadcrumbs":"resolc user guide » Differences to EVM » The 63/64 gas rule","id":"37","title":"The 63/64 gas rule"},"38":{"body":"This returns the bytecode keccak256 hash instead.","breadcrumbs":"resolc user guide » Differences to EVM » address.creationCode","id":"38","title":"address.creationCode"},"39":{"body":"The below list contains noteworthy differences in the translation of YUL functions. Note Many functions receive memory buffer offset pointer or size arguments. The PVM pointer size is 32 bit, supplying memory offset or buffer size values above 2^32-1 may lead to OutOfGas errors trap contract execution. The solc compiler ought to always emit valid memory references, so Solidity dApp authors don’t need to worry about this unless they deal with low level assembly code.","breadcrumbs":"resolc user guide » Differences to EVM » YUL functions","id":"39","title":"YUL functions"},"4":{"body":"resolc is a Solidity v0.8 compiler for Polkadot native smart contracts. Solidity compiled with resolc targets PolaVM (PVM). Thanks to additional compiler optimizations and the PVM JIT, contract code can execute much faster than the EVM equivalent. resolc supports almost all Solidity v0.8 features including inline assembly, offering a high level of comptability with the Ethereum Solidity reference implementation.","breadcrumbs":"resolc user guide » resolc user guide","id":"4","title":"resolc user guide"},"40":{"body":"In general, revive preserves the memory layout, meaning low level memory operations are supported. However, a few caveats apply: The EVM linear heap memory is emulated using a fixed byte buffer of 128kb. This implies that the maximum memory a contract can use is limited to 128kb (on Ethereum, contract memory is capped by gas and therefore varies). Thus, accessing memory offsets larger than the fixed buffer size will trap the contract at runtime with an OutOfBound error. The compiler might detect and optimize unused memory reads and writes, leading to a different msize compared to what the EVM would see.","breadcrumbs":"resolc user guide » Differences to EVM » mload, mstore, msize, mcopy (memory related functions)","id":"40","title":"mload, mstore, msize, mcopy (memory related functions)"},"41":{"body":"In the constructor code, the offset is ignored and this always returns 0. Warning pallet-revive restricts the calldata size (to 128kb at the time of writing).","breadcrumbs":"resolc user guide » Differences to EVM » calldataload, calldatacopy","id":"41","title":"calldataload, calldatacopy"},"42":{"body":"Only supported in constructor code.","breadcrumbs":"resolc user guide » Differences to EVM » codecopy","id":"42","title":"codecopy"},"43":{"body":"Deployments on revive work different than on EVM. In a nutshell: Instead of supplying the deploy code concatenated with the constructor arguments (the EVM deploy model), the revive runtime expects two pointers: A buffer containing the code hash to deploy. The constructor arguments buffer. To make contract instantiation using the new keyword in Solidity work seamlessly, revive translates the dataoffset and datasize instructions so that they assume the contract hash instead of the contract code.\\nThe hash is always of constant size.\\nThus, revive is able to supply the expected code hash and constructor arguments pointer to the runtime. Warning This might fall apart in code creating contracts inside assembly blocks. We strongly discourage using the create family opcodes to manually craft deployments in assembly blocks! Usually, the reason for using assembly blocks is to save gas, which is likely futile on revive due to the underlying differences in the VM architectures, gas models and transaction costs.","breadcrumbs":"resolc user guide » Differences to EVM » create, create2","id":"43","title":"create, create2"},"44":{"body":"Returns the contract hash.","breadcrumbs":"resolc user guide » Differences to EVM » dataoffset","id":"44","title":"dataoffset"},"45":{"body":"Returns the contract hash size (constant value of 32).","breadcrumbs":"resolc user guide » Differences to EVM » datasize","id":"45","title":"datasize"},"46":{"body":"pallet-revive restricts the returndata size (to 128kb at the time of writing).","breadcrumbs":"resolc user guide » Differences to EVM » revert, return","id":"46","title":"revert, return"},"47":{"body":"Translates to a constant value of 2500000000000000.","breadcrumbs":"resolc user guide » Differences to EVM » prevrandao, difficulty","id":"47","title":"prevrandao, difficulty"},"48":{"body":"Only valid to use in EVM (they also have no use case in PVM) and produce a compile time error.","breadcrumbs":"resolc user guide » Differences to EVM » pc, extcodecopy","id":"48","title":"pc, extcodecopy"},"49":{"body":"Related to the Ethereum rollup model and produce a compile time error. Polkadot offers a superior rollup model, removing the use case for blob data related opcodes.","breadcrumbs":"resolc user guide » Differences to EVM » blobhash, blobbasefee","id":"49","title":"blobhash, blobbasefee"},"5":{"body":"revive is the name of the overarching “Solidity to PolkaVM” compiler project, which contains multiple components (for example the Yul parser, the code generation library, the resolc executable itself, and many more things). resolc is the name of the compiler driver executable, combining many revive components in a single and easy to use binary application. In other words, revive is the whole compiler infrastructure (more like LLVM) and resolc is a user-facing single-entrypoint compiler frontend (more like clang).","breadcrumbs":"resolc user guide » revive vs. resolc nomenclature","id":"5","title":"revive vs. resolc nomenclature"},"50":{"body":"There are two different compilation pipelines available in solc and there are small differences between them. Since resolc processes the YUL IR, always assume the solc IR based codegen behavior for contracts compiled with the revive compiler.","breadcrumbs":"resolc user guide » Differences to EVM » Difference regarding the solc via-ir mode","id":"50","title":"Difference regarding the solc via-ir mode"},"51":{"body":"With via-ir, base constructors run before derived state variables are initialized: contract InnerContract { uint public innerConstructedStartTokenId; constructor() { innerConstructedStartTokenId = _startTokenId(); } function _startTokenId() internal view virtual returns (uint) { return 0; }\\n} contract Test is InnerContract { uint public START_TOKEN_ID = 1; constructor() InnerContract() { } function _startTokenId() internal view virtual override returns (uint) { return START_TOKEN_ID; }\\n} Here, innerConstructedStartTokenId in Test returns 0 (with legacy EVM codegen it’d return 1).","breadcrumbs":"resolc user guide » Differences to EVM » Example: State variable initialization order in inheritance","id":"51","title":"Example: State variable initialization order in inheritance"},"52":{"body":"Note This is not yet implemented but something for consideration on the roadmap. Solidity - tightly coupled to the EVM - introduces some inherent inefficiencies that are by design and either needs to be followed or can’t be easily worked around, even with efforts like better optimized compiler and VM implementations. This represents a technical dead end. So far the EVM sees no adoption beyond the blockchain industry. Chances are that the EVM end up deprecated for technical reasons (or maybe not and the RISC-V idea gets abandoned, who knows). PVM, however, is a general purpose VM. It supports LLVM based mainstream programming languages like Rust. It’s a common software engineering practice to compose applications from pieces written in multiple languages, using each to their own strength. For example, AI solutions traditionally use the python scripting language for convenient developer experience, while the underlying AI models get implemented in a lower level language such as C++. The same pattern can of course be applied to dApps, where we’d expect application specific languages like Solidity mixed with libraries implementing computationally complex algorithms in a lower level language. Business logic and user interfaces are naturally implemented as regular Solidity dApps which can include (link against) Rust libraries. Rust is a fast, safe low level language and the Polkadot SDK is written in Rust itself, making it an excellent choice. For example, ZK proof verifiers or expensive DeFi primitives would benefit greatly from Rust implementations. revive provides tooling support and a small Rust contracts SDK for seamless integration with Rust libraries.","breadcrumbs":"resolc user guide » Rust contract libraries » Rust contract libraries","id":"52","title":"Rust contract libraries"},"53":{"body":"Running contract code usually requires a blockchain node. While local dev nodes can be used, sometimes it’s just not desirable to do so. Instead, it can be much more convenient to run and debug contract code with a stripped down environment. This is where the revive-runner comes in handy. In a nutshell, it is a single-binary no-blockchain pallet-revive runtime.","breadcrumbs":"revive-runner sandbox » revive-runner sandbox","id":"53","title":"revive-runner sandbox"},"54":{"body":"Inside the root revive repository directory, install it from source (requires Rust installed): make install-revive-runner After installing, see revive-runner --help for usage help.","breadcrumbs":"revive-runner sandbox » Installation and usage","id":"54","title":"Installation and usage"},"55":{"body":"The standard RUST_LOG environment variable controls the log output from the contract execution. This includes revive runtime logs and PVM execution trace logs. Sometimes it’s convenient to have more fine granular insight. Some useful filters: RUST_LOG=runtime=trace: The pallet-revive runtime trace logs. RUST_LOG=polkavm=trace: Low level PolkaVM instruction tracing.","breadcrumbs":"revive-runner sandbox » Trace logs","id":"55","title":"Trace logs"},"56":{"body":"To avoid running the constract in an unitialized state, revive-runner automatically instantiates the contract before calling it (constructor arguments can be provided).","breadcrumbs":"revive-runner sandbox » Automatic contract instantiation","id":"56","title":"Automatic contract instantiation"},"57":{"body":"Suppose we want to trace the syscalls of the execution of a compiled contract file Flipper.pvm: RUST_LOG=runtime=trace revive-runner -f Flipper.pvm\\n[DEBUG runtime::revive] Contract memory usage: purgable=6144/3145728 KB baseline=103063/1572864\\n[TRACE runtime::revive::strace] call_data_size() = Ok(0) gas_consumed: Weight { ref_time: 985209, proof_size: 0 }\\n[TRACE runtime::revive::strace] value_transferred(out_ptr: 4294836096) = Ok(()) gas_consumed: Weight { ref_time: 2937634, proof_size: 0 }\\n[TRACE runtime::revive::strace] call_data_copy(out_ptr: 131216, out_len: 0, offset: 0) = Ok(()) gas_consumed: Weight { ref_time: 4084483, proof_size: 0 }\\n[TRACE runtime::revive::strace] seal_return(flags: 0, data_ptr: 131216, data_len: 0) = Err(TrapReason::Return(ReturnData { flags: 0, data: [] })) gas_consumed: Weight { ref_time: 5510615, proof_size: 0 }\\n[TRACE runtime::revive] frame finished with: Ok(ExecReturnValue { flags: (empty), data: [] })\\n[TRACE runtime::revive::strace] call_data_size() = Ok(0) gas_consumed: Weight { ref_time: 985209, proof_size: 0 }\\n[TRACE runtime::revive::strace] seal_return(flags: 1, data_ptr: 131088, data_len: 0) = Err(TrapReason::Return(ReturnData { flags: 1, data: [] })) gas_consumed: Weight { ref_time: 2456669, proof_size: 0 }\\n[TRACE runtime::revive] frame finished with: Ok(ExecReturnValue { flags: REVERT, data: [] })","breadcrumbs":"revive-runner sandbox » Example","id":"57","title":"Example"},"58":{"body":"This chapter covers internal aspects of the compiler and helps contributors getting started with the revive codebase.","breadcrumbs":"Developer Guide » Developer guide","id":"58","title":"Developer guide"},"59":{"body":"The revive compiler is an open source software project and we gladly accept quality contributions from anyone!","breadcrumbs":"Developer Guide » Contributor guide » Contributor guide","id":"59","title":"Contributor guide"},"6":{"body":"Building Solidity contracts for PolkaVM requires installing the following two compilers: solc: The Ethereum Solidity reference compiler implementation. resolc: The revive Solidity compiler YUL frontend and PolkaVM code generator.","breadcrumbs":"resolc user guide » Installation » Installation","id":"6","title":"Installation"},"60":{"body":"A quick reference on how to build the Solidity compiler is maintained in the project’s README.md.","breadcrumbs":"Developer Guide » Contributor guide » Getting started","id":"60","title":"Getting started"},"61":{"body":"The Makefile comprehensively encapsulates all development aspects of this codebase. It is kept concise and readable. Please read and use it! You’ll learn for example: How to build and install a resolc development version. How to run tests and benchmarks. How to cross-compile resolc. As a general rule-of-thumb: If make test runs fine locally, chances for green CI pipelines are good.","breadcrumbs":"Developer Guide » Contributor guide » Using the Makefile","id":"61","title":"Using the Makefile"},"62":{"body":"For the most parts, revive is a rather standard Rust workspace codebase. There are some non-Rust dependencies, which sometimes complicates things a little bit. The crates/ dir All Rust crates live under the crates/ directory. The workspace automatically considers any crate found therein. If you need to add a new create, please implement it there. Compiler library crates should be named with the revive- prefix. The crate location doesn’t need the prefix. Dependencies Dependencies should be added as workspace dependencies. Try to avoid pinning dependencies whenever possible. If possible, add dev dependencies as dev-dependencies only. Please do always include the Cargo.lock dependency lock file with your PR. Please don’t run cargo update together with other changes (it is preferred to update the lock file in a dedicated dependency update PR).","breadcrumbs":"Developer Guide » Contributor guide » Codebase organization","id":"62","title":"Codebase organization"},"63":{"body":"Changes must be submitted via a pull request (PR) to the github upstream repository. Ensure that your branch passes make test locally when submitting a pull request. A PR must not be merged until CI fully passes. Exceptions can be made (for example to fix CI issues itself). No force pushes to the main branch and open PR branches. Maintainers can request changes or deny contributions at their own discretion.","breadcrumbs":"Developer Guide » Contributor guide » Contribution rules","id":"63","title":"Contribution rules"},"64":{"body":"We require the official Rust formatter and clippy linter. In addition to that, please also consider the following best-effort aspects: Avoid magic numbers and strings. Instead, add them as module constants. Avoid abbreviated variable and function names. Always provide meaningful and readable symbols. Don’t write macros and don’t use third party macros for things that can easily be expressed in few lines of code or outlined into functions. Avoid import aliasing. Please use the parent or fully qualified path for conflicting symbols. Any inline comments must provide additional semantic meaning, explain counter-intuitive behavior or highlight non-obvious design decisions. In other words, try to make the code expressive enough to a degree it doesn’t need comments expressing the same thing again in the English language. Delete such comments if your AI assistant generated them. Public items must have a meaningful doc comment. Provide meaningful panic messages to .expect() or just use .unwrap().","breadcrumbs":"Developer Guide » Contributor guide » Style guide","id":"64","title":"Style guide"},"65":{"body":"Contributors may use whatever AI assistance tools they wish to whatever degree they wish in the process of creating their contribution, given they acknowledge the following: Project maintainers may reject any contribution (or portions of it) if the contribution shows signs of problematic involvement of generative AI. Judgement of “problematic involvement” lies at the sole discretion of project maintainers. No proof (whether a contribution was in fact AI generated or not) is required. Rationale: No one enjoys reading soulless and uncanny LLM slop. Please review and fix any AI slop yourself prior to submitting a PR. A Solidity compiler is security sensitive software. Even miniscule mistakes can ultimately lead to loss of funds. AI models are inherently stochastic. They regurarly fail to capture important nuances or produce straight hallucinations. Code that was “blindly” generated has no home here. revive is a large codebase. Generative AI assistants may not have enough “context window” to sufficiently capture correctness, consistency and style aspects of the codebase. We’d like to keep this codebase maintainable by humans for the forseeable future.","breadcrumbs":"Developer Guide » Contributor guide » AI policy","id":"65","title":"AI policy"},"66":{"body":"revive relies on solc, the Ethereum Solidity compiler, as the Solidity frontend to process smart contracts written in Solidity. LLVM, a popular and powerful compiler framework, is used as the compiler backend and does the heavy lifting in terms of optimizitations and RISC-V code generation. revive mainly takes care of lowering the Yul intermediate representation (IR) produced by solc to LLVM IR. This approach provides a good balance between maintaining a high level of Ethereum compatibility, good contract performance and feasible engineering efforts.","breadcrumbs":"Developer Guide » Compiler architecture » Compiler architecture and internals","id":"66","title":"Compiler architecture and internals"},"67":{"body":"resolc is the overarching compiler driver library and binary. When compiling a Solidity source file with resolc, the following steps happen under the hood: solc is used to lower the Solidity source code into YUL intermediate representation. revive lowers the YUL IR into LLVM IR. LLVM optimizes the code and emits a RISC-V ELF shared object (through LLD). The PolkaVM linker finally links the ELF shared object into a PolkaVM blob. This compilation process can be visualized as follows:","breadcrumbs":"Developer Guide » Compiler architecture » resolc","id":"67","title":"resolc"},"68":{"body":"Because on-chain contract code is identified via its code blob hash, it is crucial to maintain reproducible contract builds. A given compiler version must reproduce the contract build exactly on every target platform resolc supports via the official binary releases. To ensure this, we employ the following measures: The code generation must be fully deterministic. For example iterating over standard HashMap invalidates this due to its internal state, making it an invalid operation in revive. To circumvent that, a BTreeMap can be used instead. We release fully statically linked resolc binaries. This prevents dynamic linking of potentially differentiating libraries. The only non-bundled dependency is the solc compiler. This is considered fine because the same properties apply to solc.","breadcrumbs":"Developer Guide » Compiler architecture » Reproducible contract builds","id":"68","title":"Reproducible contract builds"},"69":{"body":"The main compiler logic is implemented in the revive-yul and revive-llvm-context crates. The Yul library implements a lexer and parser and lowers the resulting tree into LLVM IR. It does so by emitting LL using the LLVM builder and our own revive-llvm-context compiler context crate. The revive LLVM context crate encapsulates code generation logic (decoupled from the parser). The Yul library also implements a simple visitor interface (see visitor.rs). If you want to work with the AST, it is strongly recommended to implement visitors. The LLVM code generation is implemented using a dedicated trait for historical reasons only.","breadcrumbs":"Developer Guide » Compiler architecture » The revive compiler libraries","id":"69","title":"The revive compiler libraries"},"7":{"body":"resolc is supported an all major operating systems and installation is straightforward.\\nPlease find our binary releases for the following platforms: Linux (MUSL) MacOS (universal) Windows Wasm via emscripten","breadcrumbs":"resolc user guide » Installation » resolc binary releases","id":"7","title":"resolc binary releases"},"70":{"body":"PVM doesn’t offer a similar API. Hence the emitted contract code emulates the linear EVM heap memory using a static byte buffer. Data inside this byte buffer is kept big endian for EVM compatibility reasons (unaligned access is allowed and makes optimizing this non-trivial). Unlike with the EVM, where heap memory usage is gas metered, our heap size is static (the size is user controllable via a setting flag). The compiler emits bound checks to prevent overflows.","breadcrumbs":"Developer Guide » Compiler architecture » EVM heap memory","id":"70","title":"EVM heap memory"},"71":{"body":"LLVM is a special non Rust dependency. We interface its builder interface via the inkwell wrapper crate. We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM rv64emacb target and always leave assertions on. Furthermore, we need cross builds because resolc itself targets emscripten and musl. The revive-llvm-builer functions as a cross-platform build script and is used to build and release the LLVM dependency. We also maintain the lld-sys crate for interfacing with LLD. The LLVM linker is used during the compilation process, but we don’t want to distribute another binary.","breadcrumbs":"Developer Guide » Compiler architecture » The LLVM dependency","id":"71","title":"The LLVM dependency"},"72":{"body":"An experimental newyork optimizer introduces a custom IR layer between Yul and LLVM IR to capture optimization opportunities that neither solc nor LLVM can realize on their own. solc optimizes for EVM gas on a 256-bit big-endian stack machine, while LLVM lacks the domain knowledge to understand EVM memory semantics or Solidity patterns. The newyork IR bridges this gap with passes for type narrowing, memory optimization, function deduplication, and more.","breadcrumbs":"Developer Guide » Compiler architecture » Custom optimizations","id":"72","title":"Custom optimizations"},"73":{"body":"The newyork crate ( crates/newyork/) introduces an additional intermediate representation (IR) layer between Yul and LLVM IR. It enables domain-specific optimizations that neither solc nor LLVM can perform on their own, because they lack semantic knowledge about the cross-domain compilation from EVM to PolkaVM. Note The newyork optimizer is experimental. It is gated behind the RESOLC_USE_NEWYORK=1 environment variable (for standard JSON mode) or the --newyork CLI flag, and not yet enabled by default.","breadcrumbs":"Developer Guide » The newyork optimizer » The newyork optimizer","id":"73","title":"The newyork optimizer"},"74":{"body":"The EVM and PolkaVM are fundamentally different machines: Property EVM PolkaVM (RISC-V) Word size 256-bit 64-bit Endianness Big-endian Little-endian Architecture Stack machine Register-based Memory model Linear with free pointer convention Flat address space solc optimizes Yul IR for EVM gas costs on a 256-bit big-endian stack machine. LLVM, on the other hand, operates at too low a level to understand EVM memory semantics or Solidity patterns. By the time Yul reaches LLVM IR, the high-level intent is lost. The newyork IR sits between these two worlds and recovers enough semantic information to make optimization decisions that neither compiler can make alone.","breadcrumbs":"Developer Guide » The newyork optimizer » Motivation","id":"74","title":"Motivation"},"75":{"body":"┌──────────────────────────────────────────────────┐\\nYul AST ──────────► │ newyork IR │ ──► LLVM IR ──► RISC-V from_yul│ │ to_llvm │ 1. inline │ │ 2. simplify (pass 1) │ │ 3. dedup (exact + fuzzy) │ │ 4. mem_opt + fmp_prop + keccak_fold │ │ 5. simplify (pass 2) │ │ 6. compound_outlining + guard_narrow │ │ 7. simplify (pass 3) │ │ 8. dedup (exact + fuzzy, pass 2) │ │ ── recursive on subobjects ── │ │ 9. heap_opt (analysis) │ │ 10. type_inference (4 iterative rounds) │ │ 11. validate │ └──────────────────────────────────────────────────┘ The optimizer runs the following passes in order: Inlining – custom heuristics tuned for PolkaVM call overhead, with Tarjan SCC-based recursion detection and quadratic leave-overhead modeling. Simplify (pass 1) – constant folding, algebraic identities, strength reduction ( mul by power-of-2 to shl), copy propagation, dead code elimination, environment read CSE ( callvalue, caller, origin, etc.), and revert pattern outlining (panic selectors, custom error selectors). Function deduplication – exact structural match, then fuzzy dedup (functions differing only in literal constants are parameterized and merged, up to 4 differing positions). Memory optimization – load-after-store elimination, keccak256 fusion ( mstore + keccak256 sequences into Keccak256Single/ Keccak256Pair nodes), free memory pointer propagation (replaces mload(0x40) with a known constant), and constant keccak256 folding (precomputes hashes of compile-time-constant inputs). Simplify (pass 2) – cleans up dead code and new constant expressions exposed by memory optimization and keccak folding. Compound outlining – detects keccak256_pair + sload/ sstore sequences and fuses them into MappingSLoad/ MappingSStore IR nodes, eliminating intermediate hash values. Guard narrowing – detects if gt(val, MASK) { revert } and iszero(eq(val, and(val, MASK))) patterns and inserts AND-mask narrowing, giving type inference proof that values fit in fewer bits. Simplify (pass 3) – propagates opportunities created by compound outlining and guard narrowing. Function deduplication (pass 2) – catches new duplicates exposed by guard narrowing and compound outlining canonicalization. Heap analysis – analyzes memory access patterns (alignment, static offsets, taintedness, escaping regions) to determine which accesses can use native little-endian layout, skipping byte-swap operations. Uses GCD-based alignment propagation and per-region taint tracking. Type inference – narrows 256-bit values to smaller widths ( I1, I8, I32, I64, I128, I160) where provable. Runs iteratively for up to 4 cascading refinement rounds, combining forward min-width propagation, backward use-context demands, transparent-operation demand propagation, and interprocedural parameter/return narrowing. Validation – checks SSA well-formedness (use-before-def, multiple definitions), yield count consistency, and function reference correctness. Steps 1-8 run recursively on subobjects (deployed contract code), where optimization impact is greatest. Steps 9-11 run on the full object tree.","breadcrumbs":"Developer Guide » The newyork optimizer » Pipeline overview","id":"75","title":"Pipeline overview"},"76":{"body":"The newyork IR is an SSA form with structured control flow, inspired by MLIR’s SCF dialect. Key design choices: Explicit types with address spaces: Every value carries a bit-width ( I1, I8, I32, I64, I128, I160, I256) and pointers carry address space information ( Heap, Stack, Storage, Code). All values start as I256 and are narrowed by type inference. Pure expressions vs. effectful statements: Expressions compute values without side effects; statements perform memory, storage, or control flow effects. This separation simplifies analysis and rewriting. Semantic annotations: Memory operations are tagged with region information ( Scratch, FreePointerSlot, Dynamic). Storage operations carry static slot values when known at compile time. Structured control flow: If, Switch, and For nodes preserve the high-level structure from Yul, with explicit region arguments and yields for value flow across control edges. For per-operation detail — printed syntax, operand and result types, and more — see the newyork IR reference.","breadcrumbs":"Developer Guide » The newyork optimizer » IR design","id":"76","title":"IR design"},"77":{"body":"","breadcrumbs":"Developer Guide » The newyork optimizer » Key optimizations explained","id":"77","title":"Key optimizations explained"},"78":{"body":"EVM operates on 256-bit words, but most values in practice fit in 32 or 64 bits. The type inference pass performs bidirectional analysis: Forward: computes minimum width from literal values and operation semantics (e.g., add(I64, I8) produces I65, rounded up to I128). Backward use tracking: classifies each value’s uses into 9 context categories ( MemoryOffset, MemoryValue, StorageAccess, Comparison, Arithmetic, FunctionArg, FunctionReturn, ExternalCall, General). All categories conservatively demand the full I256 width by default; the categorisation is what enables the interprocedural phase to selectively relax the demand for narrowed function arguments. Earlier versions narrowed directly from the use category, but that was unsound for memory offsets — mload(2^128) aliased to mload(0) because the bounds check ran on an already-truncated value (commit ccca38df). Transparent demand propagation: for modular-arithmetic operations ( Add, Sub, Mul, And, Or, Xor), propagates narrow demands backward through operands, exploiting the property that trunc(op(a,b), N) == op(trunc(a,N), trunc(b,N)). Interprocedural: iteratively narrows function parameter and return types in up to four rounds, combining four narrowing strategies — body-driven parameter narrowing, caller-driven parameter narrowing, forward-based return narrowing, and demand-based return narrowing — and re-running full inference between rounds. Parameters are clamped to at least I32 (XLEN on PolkaVM). This allows LLVM to emit native 32/64-bit instructions instead of software-emulated 256-bit arithmetic, and eliminates expensive multi-instruction comparison sequences (16-20 RISC-V instructions for i256 comparisons reduced to 1-2 for i64).","breadcrumbs":"Developer Guide » The newyork optimizer » Type narrowing","id":"78","title":"Type narrowing"},"79":{"body":"Solidity emits runtime guards that prove values fit in narrow ranges (e.g., address validation via if gt(val, 2^160-1) { revert }). The guard narrowing pass detects these patterns and inserts explicit AND-mask narrowing after the guard. This gives downstream type inference proof that the value fits in fewer bits, enabling cascading narrowing of comparisons, arithmetic, and memory operations that use the guarded value. Two pattern families are recognized: GT-based guards: if gt(val, MASK) { } where MASK is a boundary value like 2^N - 1 EQ-based guards: iszero(eq(val, and(val, MASK))) patterns common in Solidity’s address validation","breadcrumbs":"Developer Guide » The newyork optimizer » Guard narrowing","id":"79","title":"Guard narrowing"},"8":{"body":"resolc uses solc during the compilation process, please refer to the Ethereum Solidity documentation for installation instructions.","breadcrumbs":"resolc user guide » Installation » Installing the solc dependency","id":"8","title":"Installing the solc dependency"},"80":{"body":"PVM doesn’t provide EVM-compatible linear memory, so the compiler emulates it using a byte buffer with byte-swap operations for big-endian compatibility. The heap analysis pass determines which memory accesses can use native little-endian layout by analyzing access patterns: Tracks alignment and static offset information for all memory accesses using GCD-based propagation Propagates taintedness when addresses escape to external calls, are written by external sources ( codecopy, calldatacopy), or use unaligned access patterns Tracks variable-accessed offsets to prevent mode mismatches between native and byte-swap accesses to the same location Handles loop-carried variables conservatively (marked as non-literal to prevent false constant propagation) The codegen backend supports four memory access modes: AllNative (all accesses skip byte-swap), InlineNative (constant-offset accesses use native layout), InlineByteSwap (constant-offset accesses use inline byte-swap), and ByteSwap (standard byte-swap through helper functions).","breadcrumbs":"Developer Guide » The newyork optimizer » Heap optimization","id":"80","title":"Heap optimization"},"81":{"body":"The Solidity free memory pointer ( mload(0x40)) always fits in 32 bits — sbrk enforces FMP < heap_size on every store, regardless of which memory mode the contract uses. After every literal mload(0x40), codegen emits a trunc N → zext 256 chain (where N is bits(heap_size - 1), e.g. 17 for the 131,072-byte default heap). The trunc-extend round-trip is a no-op semantically, but exposes the bound to LLVM’s IPSCCP range analysis, which then propagates it through every add(fmp, K) and eliminates the trailing safe_truncate_int_to_xlen overflow checks at every FMP-derived offset use. Despite only affecting a single codegen site, this is the single largest contributor to the optimizer’s code-size reduction. A subtle gating issue: the byte-order mode ( InlineNative / ByteSwap) and the value bound on FMP are independent invariants. fmp_native_safe() and can_use_native(0x40) protect against mixing little-endian writers with big-endian readers on the FMP slot, which would corrupt the stored offset; the value bound is unrelated and holds in every mode. Earlier versions of the codegen gated the load-side range proof on the byte-order checks, which suppressed the optimization for any contract with dynamic memory accesses. Decoupling the two reasonings — keeping the byte-order gate on the store side, dropping it from the load-side range proof — is what makes the multiplicative IPSCCP effect available to OZ-class contracts.","breadcrumbs":"Developer Guide » The newyork optimizer » Free memory pointer range proof","id":"81","title":"Free memory pointer range proof"},"82":{"body":"The FMP slot is small but easy to mis-optimize. The codebase carries several\\nregression tests for previously-found soundness bugs; new FMP-related changes\\nshould be verified against them: mload_at_fmp_slot ( crates/integration/src/tests.rs, fixed in 1fd6063c): tests mload(0x40) and offsets near it ( 0x21, 0x3f, 0x42)\\non a contract that also performs dynamic mloads. Catches byte-order mismatches\\nwhen one access goes native (LE) and another goes byte-swap (BE). The fix\\nblocks native mode for FMP whenever has_dynamic_accesses is true. mload_huge_offset_traps (fixed in ccca38df): tests that mload(2^128) and mload(2^255) correctly trap via the gas-exhaustion\\npath. Catches UseContext::MemoryOffset narrowing bypassing the safe_truncate_int_to_xlen overflow check at the use site — mload(2^128) aliasing to mload(0) and returning the zero-initialized\\nscratch slot. The fix classifies MemoryOffset as I256 so it doesn’t\\ndrive narrowing; the bounds check at the use site catches out-of-range. FMP i32 shortcut removal ( dbcfc921): an earlier optimization stored\\nonly 4 bytes at offset 0x40 instead of the full 32-byte EVM word, breaking\\nany inline assembly using mstore(0x40, ...) for non-FMP purposes.\\nCaused a cascade of 249/251 retester failures via allocator corruption.\\nNo dedicated regression test was added — the retester corpus was sufficient\\ncoverage — but the lesson generalizes: writes to 0x40 must store the full\\nword, even when the high bits are provably zero, because the slot is part\\nof the same 32-byte memory region read by other code. When adding an optimization that touches FMP, distinguish carefully between:\\nthe byte-order encoding at the slot (must be consistent between writers\\nand readers), the value bound (FMP < heap_size, always true), and the stored width (must be 32 bytes for mstore(0x40, ...), even though only\\nthe low N bits are non-zero).","breadcrumbs":"Developer Guide » The newyork optimizer » Soundness traps for FMP optimizations","id":"82","title":"Soundness traps for FMP optimizations"},"83":{"body":"Two complementary optimizations target the common Solidity pattern of hashing values for storage slot computation: Fusion: Recognizes mstore + keccak256 sequences and fuses them into dedicated IR nodes ( Keccak256Single, Keccak256Pair), eliminating intermediate memory traffic. Constant folding: When all keccak256 inputs are compile-time constants, the hash is computed at compile time and replaced with a literal.","breadcrumbs":"Developer Guide » The newyork optimizer » Keccak256 fusion and folding","id":"83","title":"Keccak256 fusion and folding"},"84":{"body":"Solidity mapping accesses follow a predictable pattern: hash a key with a storage slot, then load/store the result. The compound outlining pass detects keccak256_pair(key, slot) followed by sload/ sstore and fuses them into MappingSLoad/ MappingSStore IR nodes. These are lowered to outlined helper functions ( __revive_mapping_sload, __revive_mapping_sstore) that combine the hash computation with the storage operation, eliminating intermediate values and redundant byte-swaps.","breadcrumbs":"Developer Guide » The newyork optimizer » Compound outlining (mapping access)","id":"84","title":"Compound outlining (mapping access)"},"85":{"body":"Solidity generates many near-identical functions that differ only in literal constants (e.g., error selectors, storage slot offsets). Fuzzy deduplication identifies such groups, parameterizes the differing literals (up to 4 positions), and replaces all copies with calls to a single shared implementation.","breadcrumbs":"Developer Guide » The newyork optimizer » Fuzzy function deduplication","id":"85","title":"Fuzzy function deduplication"},"86":{"body":"The simplify pass detects common revert patterns and replaces them with compact IR nodes: Panic reverts: Solidity Panic(uint256) sequences (selector 0x4e487b71 + encoded panic code) are collapsed into PanicRevert { code } nodes, which are lowered to shared helper functions. Custom error reverts: ABI-encoded custom error reverts with known selectors are collapsed into CustomErrorRevert { selector, args } nodes. These patterns appear dozens of times in typical contracts, and outlining them into shared blocks eliminates significant code duplication.","breadcrumbs":"Developer Guide » The newyork optimizer » Revert pattern outlining","id":"86","title":"Revert pattern outlining"},"87":{"body":"The LLVM codegen backend generates approximately 15 types of outlined helper functions for common operations: Storage: __revive_sload_word, __revive_sstore_word (handle byte-swap internally) Mapping: __revive_mapping_sload, __revive_mapping_sstore (keccak256 + storage in one call) Callvalue: __revive_callvalue, __revive_callvalue_nonzero (boolean optimization for non-payable checks) Calldataload: __revive_calldataload (outlined when >= 20 call sites) Memory: __revive_store_bswap, __revive_exit_checked, __revive_return_word Errors: __revive_error_string_revert_N, __revive_custom_error_N (per data-word count) Keccak wrappers: __keccak256_slot_N (one noinline wrapper per constant slot, internally dispatching to __revive_keccak256_two_words) Additionally, common exit patterns (revert with constant length, zero-value returns) are deduplicated into shared LLVM basic blocks, saving hundreds of instruction copies in large contracts.","breadcrumbs":"Developer Guide » The newyork optimizer » Outlined helper functions","id":"87","title":"Outlined helper functions"},"88":{"body":"","breadcrumbs":"Developer Guide » The newyork optimizer » Codesize results","id":"88","title":"Codesize results"},"89":{"body":"Reproducible with cargo test --package revive-integration -- codesize. The main column is the value committed to crates/integration/codesize.json on main; the newyork column is the value produced by the same test with RESOLC_USE_NEWYORK=1 set, currently committed on this branch. Contract main (bytes) newyork (bytes) Reduction Baseline 870 479 −44.9% Computation 2,418 1,376 −43.1% DivisionArithmetics 9,327 7,192 −22.9% ERC20 17,160 10,138 −40.9% Events 1,662 1,279 −23.0% FibonacciIterative 1,427 949 −33.5% Flipper 2,240 1,123 −49.9% SHA1 8,009 6,286 −21.5%","breadcrumbs":"Developer Guide » The newyork optimizer » Integration test contracts","id":"89","title":"Integration test contracts"},"9":{"body":"We distribute the revive compiler as node.js module.","breadcrumbs":"resolc user guide » Installation » revive NPM package","id":"9","title":"revive NPM package"},"90":{"body":"Measured by running oz-tests/oz.sh against real-world contracts generated with the OpenZeppelin Wizard. The numbers below are a development snapshot — there is no committed measurement file in the repo, so these may drift as the optimizer evolves; rerun the script for fresh figures. Contract newyork (bytes) oz_gov 81,840 erc721 52,634 erc20 45,703 oz_stable 45,052 oz_rwa 41,581 erc1155 33,087 oz_simple_erc20 17,024 proxy 3,748 Total 320,669 For comparison, building the same contracts without the newyork optimizer at the equivalent snapshot produced 563,526 bytes total — a reduction of about −43% across the corpus. Per-contract reductions in the integration suite range from roughly −21% (SHA1, where the bulk of the work is the SHA-1 inner loop and offers little to optimise) to nearly −50% (Flipper, where the optimiser strips away most of Solidity’s dispatch and storage-access scaffolding).","breadcrumbs":"Developer Guide » The newyork optimizer » OpenZeppelin contracts","id":"90","title":"OpenZeppelin contracts"},"91":{"body":"The newyork optimizer was developed over roughly three months — from early February 2026 through early May 2026 — largely through AI-assisted pair programming with Claude. The development progressed through several distinct phases: Phase 1 – Initial scaffolding: The first draft established the core IR data structures, Yul-to-IR translation, and LLVM codegen. Early commits focused on getting a correct round-trip through the new pipeline. Phase 2 – Optimization passes: Once the baseline was stable, optimization passes were added iteratively: inlining, simplification, memory optimization, function deduplication, keccak256 fusion, and type inference. Each pass was validated against differential tests comparing EVM and PVM execution. Phase 3 – Soundness hardening: Several type inference and narrowing approaches turned out to be unsound and had to be reworked: An early type inference approach caused namespace collisions across subobjects and was scoped per-object. Caller-based parameter narrowing was polluted by overly aggressive inference and replaced with body-based structural analysis. Backward demand-driven narrowing required multiple iterations to become provably safe. Phase 4 – Measuring and tuning: Systematic measurement of OpenZeppelin contracts revealed which optimizations had the most impact and which approaches regressed performance.","breadcrumbs":"Developer Guide » The newyork optimizer » Development history and challenges","id":"91","title":"Development history and challenges"},"92":{"body":"Approach Outcome Storage bswap decomposition (4x bswap.i64) Regressed: LLVM handles bswap.i256 better natively NoInline on __revive_int_truncate +62% regression: PolkaVM call overhead exceeds inline cost Native FMP memory (inline sbrk) Mixed: small contracts improved, large ones regressed from sbrk bloat Shared overflow trap block Mixed: prevented LLVM from eliminating individual dead overflow checks These results highlight a recurring theme: interacting well with LLVM’s own optimization passes is critical. Optimizations at the IR level can inadvertently inhibit LLVM’s downstream passes, sometimes causing surprising regressions.","breadcrumbs":"Developer Guide » The newyork optimizer » Approaches that did not work","id":"92","title":"Approaches that did not work"},"93":{"body":"The following opportunities have been identified but are not yet implemented: Bitwise algebraic simplifications: BitAnd, BitOr, BitXor identity patterns fall through without simplification. Cross-control-flow memory optimization: Memory state is conservatively cleared at if/ switch/ for boundaries. Preserving state across simple branches would enable more load-after-store eliminations. Adaptive inlining thresholds: Current thresholds are static constants. Profile-guided or contract-size-aware heuristics could improve decisions for diverse contract sizes. Extended fuzzy deduplication: The current pass only compares functions by structure of Let bindings. Extending to consider literals inside MStore, Return, Revert, and Log statements would find more deduplication opportunities. Type checking in validation: The validator checks SSA well-formedness and structural correctness, but does not yet verify type consistency of operations (the TypeMismatch error variant exists but is not yet wired). Loop variable narrowing: Loop-carried variables are conservatively widened to I256. Reaching a fixed-point across loop iterations could allow narrower types for simple counters.","breadcrumbs":"Developer Guide » The newyork optimizer » Known limitations and future work","id":"93","title":"Known limitations and future work"},"94":{"body":"A small set of environment variables controls or inspects the newyork pipeline. Only RESOLC_USE_NEWYORK affects generated bytecode; the others are read-only inspection knobs used while debugging the optimizer. Variable Effect RESOLC_USE_NEWYORK=1 Routes Yul lowering through the newyork pipeline. Equivalent to passing --newyork on the command line; the CLI flag and this variable are OR-ed by resolve_use_newyork ( crates/resolc/src/lib.rs). RESOLC_DEBUG_IR When set, prints the translated newyork IR for every object to stderr. Additionally writes /.newyork.txt whenever the debug config carries an output directory. RESOLC_DEBUG_HEAP When set, appends per-object heap-analysis details — native regions/offsets, taintedness, dynamic escapes, escaping ranges — to /resolc_heap_debug.log. Requires the debug config to carry an output directory. NEWYORK_DUMP_IR When set, writes the IR for every translated object to /tmp/newyork_ir_.txt from inside translate_yul_object ( crates/newyork/src/lib.rs). Independent of RESOLC_DEBUG_IR — fires before codegen and needs no output directory. RESOLC_DEBUG_BLOB Test harness only. Dumps the compiled PVM blob to /tmp/debug_blob_.pvm and the LLVM IR debug directory to /tmp/debug_llvm_newyork or /tmp/debug_llvm_yul. Used by crates/resolc/src/test_utils.rs when comparing newyork against the Yul path. All of these gate on presence/value at the start of compilation; flipping them mid-run has no effect.","breadcrumbs":"Developer Guide » The newyork optimizer » Environment variables","id":"94","title":"Environment variables"},"95":{"body":"Module Purpose lib.rs Pipeline orchestration and pass sequencing ir.rs Core IR data structures (types, expressions, statements, functions, objects) from_yul.rs Yul AST to newyork IR translation (two-pass with forward reference support) to_llvm.rs newyork IR to LLVM IR codegen with outlined helpers and narrowing simplify.rs Constant folding, algebraic identities, strength reduction, copy propagation, DCE, environment read CSE, revert outlining, callvalue hoisting, function deduplication (exact and fuzzy), constant keccak folding inline.rs Function inlining with PolkaVM-tuned heuristics (Tarjan SCC, leave elimination) type_inference.rs Bidirectional integer width narrowing with transparent demand propagation mem_opt.rs Load-after-store elimination, keccak256 fusion, FMP propagation heap_opt.rs Heap access pattern analysis, alignment tracking, byte-swap elimination compound_outlining.rs Mapping access pattern detection and fusion ( keccak256_pair + sload/ sstore) guard_narrow.rs Guard pattern detection and AND-mask narrowing insertion validate.rs IR well-formedness checks (SSA, yields, function references) printer.rs Human-readable IR pretty printer with configurable output ssa.rs SSA construction helpers (scope management, phi-node merging)","breadcrumbs":"Developer Guide » The newyork optimizer » Module reference","id":"95","title":"Module reference"},"96":{"body":"A per-operation reference for the newyork IR: textual syntax, operand and result types, purity, region and static-slot annotations, and examples.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » newyork IR reference","id":"96","title":"newyork IR reference"},"97":{"body":"This appendix enumerates every operation the newyork IR supports. It is a lookup, not a walkthrough: each entry is self-contained and intended to be reachable by anchor. Operations are grouped by function (memory and storage writes, pure expressions, control flow, and so on) rather than alphabetically. Jump to a specific operation from the operation index below, or use the sidebar. Every operation appears in two places in the codebase. The canonical Rust definition is a variant of either Expression or Statement in ir.rs. The textual rendering used by debug dumps and by this appendix is produced by the printer in printer.rs. Treat the printed syntax as a debug surface, not a stable input language: there is no parser for it, and printer details change when passes add new annotations.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » How to read this reference","id":"97","title":"How to read this reference"},"98":{"body":"Each operation entry has the same shape: Field What it shows Heading The printed operation name (e.g. mstore) followed by the Expression or Statement variant it corresponds to in ir.rs. Description A short prose summary of what the operation does and any semantic notes worth knowing before reading the rest of the entry. Syntax The literal printer output, including any optional debug annotations (region tags, static-slot comments). Anything inside /* ... */ is a debug-only annotation and is not part of the operation itself. Example A minimal printed snippet, using the printer’s actual v0/ v1/… naming. Operands One row per input or structural participant in the printed syntax. Value operands list the narrowest type the operation guarantees (default i256; narrower widths only appear when type inference has narrowed an upstream definition). Vector-of-operands fields show Vec<…> as the type. Non-value participants such as nested regions are listed with an em-dash type to mark them as structural rather than as operands. Result and purity The type the operation produces (or none for statements that bind no value), followed by a purity label, either Pure or Effectful. Pure operations may be reordered, deduplicated, or eliminated by the simplifier; effectful ones may not. Effectful entries may carry a parenthetical describing the nature of the side effect when informative (e.g. “control flow”, “terminator”, or a note about revert/trap behavior). Annotations Operation-specific fields the printer surfaces as /* ... */ comments in the dump (region tag for memory ops, static-slot hint for storage ops, type suffix for non-default widths). Listed here as a table of source field → printed form.","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » Entry format","id":"98","title":"Entry format"},"99":{"body":"Syntax templates in each entry use the following conventions: Notation Meaning add, mload, if, else, case, let, yield, … Literal printer tokens: bare lowercase identifiers and keywords that the printer emits verbatim. $offset, $value, $key, $lhs, $rhs, … Role names ( $-prefixed): placeholders for SSA value references the printer renders as v followed by a decimal id ( v0, v1, …). , , , , , , , , … Metavariables: stand for compile-time fields (type tags, hex values, identifier strings, integer counts), not SSA values. The concrete values they take are enumerated in the Annotations section of each entry or in the type system reference. […] Optional parts. Anything inside the brackets may or may not appear in any given dump, depending on the conditions described in the operation’s Annotations section. [: ] Optional type suffix on a value reference. Suppressed when the value’s type is the default i256 integer; present otherwise ( : i32, : ptr, …). /* … */ Debug-only annotations the printer attaches to certain operations (memory region tag, static-slot hint, etc.). … Repetition: “more entries of the same shape.” Used in vector operand lists ( $arg_0, $arg_1, …) and in multi-line block bodies ( { … }).","breadcrumbs":"Developer Guide » The newyork optimizer » IR reference » Syntax notation","id":"99","title":"Syntax notation"}},"length":237,"save":true},"fields":["title","body","breadcrumbs"],"index":{"body":{"root":{"0":{".":{"8":{".":{"0":{"df":1,"docs":{"229":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":28,"docs":{"112":{"tf":2.0},"113":{"tf":2.0},"114":{"tf":2.0},"115":{"tf":2.0},"12":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":2.0},"130":{"tf":2.0},"131":{"tf":2.0},"132":{"tf":1.4142135623730951},"134":{"tf":1.0},"156":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"201":{"tf":1.0},"205":{"tf":1.4142135623730951},"206":{"tf":1.0},"207":{"tf":1.0},"216":{"tf":1.0},"223":{"tf":1.0},"41":{"tf":1.0},"51":{"tf":1.4142135623730951},"57":{"tf":3.4641016151377544}},"x":{"0":{"0":{".":{".":{"0":{"df":0,"docs":{},"x":{"3":{"df":0,"docs":{},"f":{"df":1,"docs":{"176":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"105":{"tf":1.0}}},"1":{"df":1,"docs":{"214":{"tf":1.0}}},"8":{"c":{"3":{"7":{"9":{"a":{"0":{"df":1,"docs":{"215":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":4,"docs":{"167":{"tf":1.0},"179":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0}}},"1":{"1":{"df":1,"docs":{"214":{"tf":1.0}}},"2":{"df":1,"docs":{"214":{"tf":1.0}}},"df":4,"docs":{"107":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0}}},"2":{"1":{"df":1,"docs":{"82":{"tf":1.0}}},"a":{"df":1,"docs":{"107":{"tf":1.0}}},"df":0,"docs":{}},"3":{"2":{"df":1,"docs":{"214":{"tf":1.0}}},"df":0,"docs":{},"f":{"df":2,"docs":{"105":{"tf":1.0},"82":{"tf":1.0}}}},"4":{"0":{"df":3,"docs":{"105":{"tf":1.0},"176":{"tf":1.0},"82":{"tf":1.4142135623730951}}},"1":{"df":2,"docs":{"105":{"tf":1.0},"214":{"tf":1.0}}},"2":{"df":1,"docs":{"82":{"tf":1.0}}},"df":0,"docs":{},"e":{"4":{"8":{"7":{"b":{"7":{"1":{"df":2,"docs":{"214":{"tf":1.0},"86":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"7":{"df":0,"docs":{},"f":{"df":1,"docs":{"105":{"tf":1.0}}}},"8":{"0":{"df":2,"docs":{"105":{"tf":1.0},"107":{"tf":1.0}}},"df":0,"docs":{}},"<":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":6,"docs":{"100":{"tf":1.0},"107":{"tf":1.7320508075688772},"167":{"tf":1.4142135623730951},"179":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"214":{"tf":1.0}}}}}},"a":{"df":1,"docs":{"195":{"tf":1.0}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":1,"docs":{"117":{"tf":1.0}}}}},"–":{"3":{"1":{"df":1,"docs":{"129":{"tf":1.0}}},"df":1,"docs":{"216":{"tf":1.0}}},"df":0,"docs":{}}},"1":{",":{"1":{"2":{"3":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"7":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"3":{"7":{"6":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{"2":{"7":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"6":{"2":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},".":{"2":{"df":1,"docs":{"18":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"14":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"/":{"1":{"0":{"0":{"df":1,"docs":{"219":{"tf":1.0}}},"df":1,"docs":{"219":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"0":{",":{"1":{"3":{"8":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"75":{"tf":1.0}}},"1":{"df":1,"docs":{"75":{"tf":1.4142135623730951}}},"2":{"8":{"df":0,"docs":{},"k":{"b":{"df":3,"docs":{"40":{"tf":1.4142135623730951},"41":{"tf":1.0},"46":{"tf":1.0}}},"df":0,"docs":{}}},"df":1,"docs":{"215":{"tf":1.0}}},"3":{"1":{",":{"0":{"7":{"2":{"df":1,"docs":{"81":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"0":{"7":{"2":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}},"df":0,"docs":{}},"8":{"8":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"1":{"6":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"5":{"5":{"9":{"df":1,"docs":{"153":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"87":{"tf":1.0}}},"6":{"df":1,"docs":{"78":{"tf":1.0}}},"7":{",":{"0":{"2":{"4":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"1":{"6":{"0":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"81":{"tf":1.0}}},"_":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"215":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":18,"docs":{"12":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"127":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"201":{"tf":1.0},"219":{"tf":1.0},"39":{"tf":1.0},"51":{"tf":1.4142135623730951},"57":{"tf":1.4142135623730951},"75":{"tf":2.0},"78":{"tf":1.0},"79":{"tf":1.4142135623730951},"81":{"tf":1.0},"90":{"tf":1.0},"91":{"tf":1.0}},"f":{"d":{"6":{"0":{"6":{"3":{"c":{"df":1,"docs":{"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"m":{"b":{"df":1,"docs":{"233":{"tf":1.0}}},"df":0,"docs":{}},"–":{"4":{"df":1,"docs":{"215":{"tf":1.0}}},"df":0,"docs":{}}},"2":{",":{"2":{"4":{"0":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{"1":{"8":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"0":{"2":{"6":{"df":1,"docs":{"91":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":2,"docs":{"78":{"tf":1.0},"87":{"tf":1.0}}},"1":{".":{"5":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"90":{"tf":1.0}}},"2":{".":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"4":{"df":1,"docs":{"216":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"3":{".":{"0":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{"5":{"6":{"6":{"6":{"9":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"9":{"/":{"2":{"5":{"1":{"df":1,"docs":{"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"k":{"b":{"df":1,"docs":{"233":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"5":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"df":1,"docs":{"47":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"df":19,"docs":{"103":{"tf":1.0},"104":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.7320508075688772},"122":{"tf":1.0},"128":{"tf":1.0},"134":{"tf":1.4142135623730951},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"156":{"tf":1.0},"164":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.4142135623730951},"75":{"tf":1.0},"78":{"tf":1.4142135623730951},"81":{"tf":1.0}}},"df":0,"docs":{}},"9":{"3":{"7":{"6":{"3":{"4":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"^":{"1":{"6":{"0":{"df":1,"docs":{"79":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"5":{"6":{"df":4,"docs":{"110":{"tf":1.0},"111":{"tf":1.0},"116":{"tf":1.0},"133":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"3":{"2":{"df":1,"docs":{"39":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{},"n":{"df":2,"docs":{"109":{"tf":1.0},"79":{"tf":1.0}}}},"df":6,"docs":{"12":{"tf":1.0},"219":{"tf":1.0},"32":{"tf":1.0},"75":{"tf":2.449489742783178},"78":{"tf":1.0},"91":{"tf":1.0}}},"3":{",":{"7":{"4":{"8":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},".":{"0":{"df":1,"docs":{"235":{"tf":1.0}}},"df":0,"docs":{}},"2":{"/":{"6":{"4":{"df":1,"docs":{"78":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"0":{",":{"6":{"6":{"9":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":17,"docs":{"128":{"tf":1.4142135623730951},"139":{"tf":1.4142135623730951},"140":{"tf":1.0},"147":{"tf":1.0},"159":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"176":{"tf":1.4142135623730951},"179":{"tf":1.0},"180":{"tf":1.0},"215":{"tf":1.7320508075688772},"39":{"tf":1.0},"45":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.7320508075688772}}},"3":{",":{"0":{"8":{"7":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},".":{"5":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":4,"docs":{"12":{"tf":1.0},"18":{"tf":1.4142135623730951},"75":{"tf":1.7320508075688772},"91":{"tf":1.0}},"f":{"a":{"4":{"df":0,"docs":{},"f":{"2":{"4":{"5":{"df":1,"docs":{"223":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}},"4":{"0":{".":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"8":{"4":{"4":{"8":{"3":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"1":{",":{"5":{"8":{"1":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"9":{"4":{"8":{"3":{"6":{"0":{"9":{"6":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"107":{"tf":1.0}}},"3":{".":{"1":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"90":{"tf":1.0}}},"4":{".":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"5":{",":{"0":{"5":{"2":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"7":{"0":{"3":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"7":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"8":{"4":{"4":{"df":1,"docs":{"154":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"9":{".":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":6,"docs":{"207":{"tf":1.0},"216":{"tf":1.0},"75":{"tf":2.0},"82":{"tf":1.0},"85":{"tf":1.0},"91":{"tf":1.0}},"x":{"df":1,"docs":{"92":{"tf":1.0}}}},"5":{"0":{"df":1,"docs":{"90":{"tf":1.0}}},"2":{",":{"6":{"3":{"4":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"5":{"1":{"0":{"6":{"1":{"5":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"3":{",":{"5":{"2":{"6":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"75":{"tf":1.0}}},"6":{",":{"2":{"8":{"6":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"df":1,"docs":{"92":{"tf":1.0}}},"3":{"/":{"6":{"4":{"df":2,"docs":{"0":{"tf":1.0},"37":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{"df":5,"docs":{"139":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"74":{"tf":1.0},"78":{"tf":1.0}}},"df":1,"docs":{"75":{"tf":1.0}}},"7":{",":{"1":{"9":{"2":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"75":{"tf":1.0}}},"8":{",":{"0":{"0":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"1":{",":{"8":{"4":{"0":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"7":{"0":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":2,"docs":{"177":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951}}},"9":{",":{"3":{"2":{"7":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"8":{"5":{"2":{"0":{"9":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":2,"docs":{"75":{"tf":1.4142135623730951},"78":{"tf":1.0}}},"_":{"_":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"n":{"df":1,"docs":{"87":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"_":{"c":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"87":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"87":{"tf":1.0}},"e":{"_":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":1,"docs":{"87":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"_":{"df":0,"docs":{},"n":{"df":1,"docs":{"87":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"n":{"df":1,"docs":{"87":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"_":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"87":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"92":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"k":{"df":0,"docs":{},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"87":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"m":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":2,"docs":{"84":{"tf":1.0},"87":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"84":{"tf":1.0},"87":{"tf":1.0}}}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"87":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"_":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"87":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"87":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"_":{"b":{"df":0,"docs":{},"s":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"87":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"a":{"b":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}},"df":0,"docs":{}}},"b":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":1,"docs":{"64":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"_":{"d":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"2":{"5":{"6":{"(":{"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"174":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":4,"docs":{"103":{"tf":1.0},"214":{"tf":1.0},"33":{"tf":1.4142135623730951},"86":{"tf":1.0}}},"o":{"df":0,"docs":{},"v":{"df":5,"docs":{"105":{"tf":1.0},"109":{"tf":1.0},"223":{"tf":1.0},"231":{"tf":1.0},"39":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"179":{"tf":1.0},"193":{"tf":1.0}}}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":3,"docs":{"106":{"tf":1.0},"194":{"tf":1.0},"59":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"df":11,"docs":{"147":{"tf":1.0},"182":{"tf":1.0},"40":{"tf":1.0},"70":{"tf":1.0},"75":{"tf":1.4142135623730951},"80":{"tf":3.1622776601683795},"81":{"tf":1.0},"82":{"tf":1.0},"84":{"tf":1.4142135623730951},"90":{"tf":1.0},"95":{"tf":1.4142135623730951}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":6,"docs":{"109":{"tf":1.0},"143":{"tf":1.0},"163":{"tf":1.4142135623730951},"164":{"tf":1.4142135623730951},"165":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"20":{"tf":1.0}}}}}},"k":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"t":{"df":2,"docs":{"182":{"tf":1.0},"200":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"223":{"tf":1.7320508075688772}}}},"v":{"df":2,"docs":{"18":{"tf":1.0},"23":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":6,"docs":{"18":{"tf":1.0},"215":{"tf":1.0},"219":{"tf":1.0},"224":{"tf":1.0},"35":{"tf":1.0},"98":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"93":{"tf":1.0}}}}},"d":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"109":{"tf":1.0}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":1,"docs":{"81":{"tf":1.0}}}}},"i":{"6":{"4":{"df":1,"docs":{"78":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"v":{"0":{"df":2,"docs":{"109":{"tf":1.0},"189":{"tf":1.0}}},"1":{"df":2,"docs":{"195":{"tf":1.0},"199":{"tf":1.0}}},"2":{"df":1,"docs":{"193":{"tf":1.0}}},"df":0,"docs":{}}},"df":7,"docs":{"100":{"tf":1.0},"109":{"tf":1.0},"62":{"tf":1.4142135623730951},"64":{"tf":1.0},"78":{"tf":1.0},"97":{"tf":1.0},"99":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"130":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"i":{"df":0,"docs":{},"t":{"df":7,"docs":{"109":{"tf":1.0},"130":{"tf":1.0},"206":{"tf":1.0},"24":{"tf":1.0},"4":{"tf":1.0},"64":{"tf":1.4142135623730951},"73":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":3,"docs":{"33":{"tf":1.0},"87":{"tf":1.0},"94":{"tf":1.0}}}}}}},"m":{"df":0,"docs":{},"o":{"d":{"(":{"$":{"a":{"df":1,"docs":{"130":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"130":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"130":{"tf":1.0}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{".":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"38":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":29,"docs":{"100":{"tf":1.0},"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.4142135623730951},"141":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":2.0},"148":{"tf":1.0},"163":{"tf":1.7320508075688772},"164":{"tf":1.7320508075688772},"165":{"tf":1.7320508075688772},"169":{"tf":1.0},"173":{"tf":1.0},"18":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"201":{"tf":1.7320508075688772},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.7320508075688772},"206":{"tf":1.7320508075688772},"213":{"tf":1.4142135623730951},"74":{"tf":1.0},"76":{"tf":1.4142135623730951},"79":{"tf":1.4142135623730951},"80":{"tf":1.0}},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":2,"docs":{"102":{"tf":1.0},"104":{"tf":1.0}},"e":{":":{":":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"105":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":4,"docs":{"33":{"tf":1.4142135623730951},"62":{"tf":1.0},"82":{"tf":1.4142135623730951},"91":{"tf":1.0}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}},"v":{"a":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"12":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"37":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"81":{"tf":1.0},"94":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"172":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"g":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"64":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"df":9,"docs":{"194":{"tf":1.0},"219":{"tf":1.0},"223":{"tf":1.4142135623730951},"52":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"90":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.0}}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"12":{"tf":1.4142135623730951},"91":{"tf":1.0}}}}}}}},"i":{"df":4,"docs":{"52":{"tf":1.4142135623730951},"64":{"tf":1.0},"65":{"tf":2.6457513110645907},"91":{"tf":1.0}},"m":{"df":4,"docs":{"11":{"tf":1.0},"222":{"tf":1.0},"234":{"tf":1.0},"236":{"tf":1.0}}}},"l":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"r":{"a":{"df":3,"docs":{"75":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"df":1,"docs":{"52":{"tf":1.0}}}}}}}}},"i":{"a":{"df":2,"docs":{"104":{"tf":1.0},"179":{"tf":1.4142135623730951}},"s":{"df":3,"docs":{"64":{"tf":1.0},"78":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":3,"docs":{"75":{"tf":1.4142135623730951},"80":{"tf":1.0},"95":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"n":{"df":1,"docs":{"80":{"tf":1.0}}},"o":{"c":{"df":4,"docs":{"104":{"tf":1.0},"105":{"tf":1.0},"219":{"tf":1.0},"82":{"tf":1.0}}},"df":0,"docs":{},"w":{"df":9,"docs":{"219":{"tf":1.0},"223":{"tf":1.0},"224":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"30":{"tf":1.0},"70":{"tf":1.0},"78":{"tf":1.0},"93":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"74":{"tf":1.0}}}},"p":{"df":0,"docs":{},"h":{"a":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"97":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"e":{"a":{"d":{"df":0,"docs":{},"i":{"df":1,"docs":{"78":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"w":{"a":{"df":0,"docs":{},"y":{"df":13,"docs":{"18":{"tf":1.0},"188":{"tf":1.0},"222":{"tf":1.0},"232":{"tf":1.0},"39":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":1.0},"50":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.0},"71":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":7,"docs":{"0":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"37":{"tf":1.0}}}}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":3,"docs":{"175":{"tf":1.0},"179":{"tf":1.4142135623730951},"200":{"tf":1.0}},"i":{"df":19,"docs":{"104":{"tf":1.0},"117":{"tf":1.0},"138":{"tf":1.4142135623730951},"155":{"tf":1.0},"156":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.0},"95":{"tf":1.0}}}},"z":{"df":2,"docs":{"75":{"tf":1.0},"80":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"97":{"tf":1.0}}}}}},"d":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"117":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"117":{"tf":1.4142135623730951}}},"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"75":{"tf":1.0},"79":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":1,"docs":{"135":{"tf":1.0}}}},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":109,"docs":{"107":{"tf":1.4142135623730951},"108":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.4142135623730951},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.7320508075688772},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.4142135623730951},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.7320508075688772},"180":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"76":{"tf":1.0},"96":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.7320508075688772},"99":{"tf":1.7320508075688772}}},"u":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":4,"docs":{"190":{"tf":1.0},"219":{"tf":1.0},"71":{"tf":1.0},"82":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"59":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"98":{"tf":1.0},"99":{"tf":1.0}}}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"43":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"220":{"tf":1.4142135623730951},"70":{"tf":1.0}}},"p":{"df":1,"docs":{"235":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"r":{"df":6,"docs":{"106":{"tf":1.0},"188":{"tf":1.0},"86":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}}},"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"18":{"tf":1.0},"94":{"tf":1.0}},"i":{"df":0,"docs":{},"x":{"df":1,"docs":{"97":{"tf":1.4142135623730951}},"’":{"df":1,"docs":{"188":{"tf":1.0}}}}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"5":{"tf":1.0},"52":{"tf":1.4142135623730951}}},"df":7,"docs":{"12":{"tf":1.4142135623730951},"231":{"tf":1.0},"27":{"tf":1.0},"37":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"68":{"tf":1.0}}}},"r":{"df":0,"docs":{},"o":{"a":{"c":{"df":0,"docs":{},"h":{"df":4,"docs":{"224":{"tf":1.0},"66":{"tf":1.0},"91":{"tf":1.7320508075688772},"92":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"221":{"tf":1.0}}}}},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"87":{"tf":1.0}}}}}}}}},"r":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"179":{"tf":1.0},"30":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"43":{"tf":1.0},"66":{"tf":1.0},"74":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"g":{"_":{"0":{"df":2,"docs":{"216":{"tf":1.0},"99":{"tf":1.0}}},"1":{"df":2,"docs":{"216":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"86":{"tf":1.0}},"s":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":4,"docs":{"201":{"tf":1.7320508075688772},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0}}}}}}}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":4,"docs":{"201":{"tf":1.7320508075688772},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0}}}}}}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"_":{"1":{"df":1,"docs":{"174":{"tf":1.0}}},"df":0,"docs":{}},"df":8,"docs":{"174":{"tf":1.4142135623730951},"216":{"tf":1.7320508075688772},"30":{"tf":1.0},"39":{"tf":1.0},"43":{"tf":1.7320508075688772},"56":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":7,"docs":{"100":{"tf":1.0},"103":{"tf":1.0},"116":{"tf":1.0},"122":{"tf":1.0},"214":{"tf":1.4142135623730951},"78":{"tf":1.7320508075688772},"79":{"tf":1.0}}}}}}}},"m":{"df":1,"docs":{"219":{"tf":1.0}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":3,"docs":{"219":{"tf":1.4142135623730951},"233":{"tf":1.0},"52":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"y":{"df":2,"docs":{"179":{"tf":1.0},"214":{"tf":1.0}}}},"df":0,"docs":{}},"t":{"df":1,"docs":{"219":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"58":{"tf":1.0},"61":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"l":{"df":6,"docs":{"16":{"tf":1.0},"230":{"tf":1.4142135623730951},"39":{"tf":1.0},"4":{"tf":1.0},"43":{"tf":1.7320508075688772},"82":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"212":{"tf":1.0},"214":{"tf":1.0},"223":{"tf":1.0},"71":{"tf":1.0}}}},"t":{"df":1,"docs":{"220":{"tf":1.0}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":1,"docs":{"176":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"64":{"tf":1.0},"65":{"tf":1.4142135623730951},"91":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"m":{"df":2,"docs":{"43":{"tf":1.0},"50":{"tf":1.0}},"p":{"df":0,"docs":{},"t":{"df":2,"docs":{"179":{"tf":1.0},"219":{"tf":1.0}}}}}}},"t":{"df":4,"docs":{"33":{"tf":1.7320508075688772},"69":{"tf":1.0},"75":{"tf":1.0},"95":{"tf":1.0}}}},"t":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"h":{"df":3,"docs":{"107":{"tf":1.0},"142":{"tf":1.0},"99":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"u":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"28":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"148":{"tf":1.0},"39":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":3,"docs":{"33":{"tf":1.4142135623730951},"56":{"tf":1.4142135623730951},"62":{"tf":1.0}}}},"df":0,"docs":{}}}}},"v":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":6,"docs":{"14":{"tf":1.0},"21":{"tf":1.0},"219":{"tf":1.0},"22":{"tf":1.0},"50":{"tf":1.0},"81":{"tf":1.0}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"d":{"df":3,"docs":{"56":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}},"w":{"a":{"df":0,"docs":{},"r":{"df":3,"docs":{"180":{"tf":1.0},"36":{"tf":1.0},"93":{"tf":1.0}}},"y":{"df":1,"docs":{"90":{"tf":1.0}}}},"df":0,"docs":{}}},"b":{"a":{"c":{"df":0,"docs":{},"k":{"df":4,"docs":{"122":{"tf":1.0},"174":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"d":{"df":4,"docs":{"12":{"tf":1.0},"66":{"tf":1.0},"80":{"tf":1.0},"87":{"tf":1.0}}},"df":0,"docs":{}}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":4,"docs":{"220":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.4142135623730951},"91":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"n":{"c":{"df":6,"docs":{"100":{"tf":1.0},"157":{"tf":1.0},"165":{"tf":1.4142135623730951},"213":{"tf":1.4142135623730951},"223":{"tf":1.0},"66":{"tf":1.0}},"e":{"(":{"$":{"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"165":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"157":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"165":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"219":{"tf":1.0}}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"99":{"tf":1.0}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"146":{"tf":1.0},"182":{"tf":1.0},"200":{"tf":1.0},"235":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"e":{"df":14,"docs":{"116":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"17":{"tf":1.0},"219":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.0},"52":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.4142135623730951},"78":{"tf":1.4142135623730951},"79":{"tf":1.4142135623730951},"80":{"tf":1.0},"91":{"tf":1.4142135623730951}},"f":{"df":0,"docs":{},"e":{"df":2,"docs":{"100":{"tf":1.0},"153":{"tf":1.7320508075688772}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"89":{"tf":1.0},"91":{"tf":1.0}},"e":{"=":{"1":{"0":{"3":{"0":{"6":{"3":{"/":{"1":{"5":{"7":{"2":{"8":{"6":{"4":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"i":{"c":{"df":2,"docs":{"12":{"tf":1.0},"87":{"tf":1.0}}},"df":0,"docs":{}}}},"df":3,"docs":{"129":{"tf":1.0},"130":{"tf":1.7320508075688772},"131":{"tf":1.7320508075688772}},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":2,"docs":{"196":{"tf":1.0},"91":{"tf":1.0}}}}},"df":1,"docs":{"128":{"tf":1.0}},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":7,"docs":{"108":{"tf":1.0},"195":{"tf":1.0},"51":{"tf":1.0},"56":{"tf":1.0},"75":{"tf":1.0},"94":{"tf":1.0},"98":{"tf":1.0}}}}},"h":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":4,"docs":{"199":{"tf":1.0},"50":{"tf":1.0},"64":{"tf":1.0},"98":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"195":{"tf":1.0},"73":{"tf":1.0}}},"df":0,"docs":{}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":2,"docs":{"219":{"tf":1.0},"235":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"w":{"df":7,"docs":{"101":{"tf":1.0},"138":{"tf":1.0},"18":{"tf":1.0},"236":{"tf":1.0},"39":{"tf":1.0},"90":{"tf":1.0},"97":{"tf":1.0}}}}},"n":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":2,"docs":{"219":{"tf":1.4142135623730951},"61":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"52":{"tf":1.0},"92":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":11,"docs":{"12":{"tf":1.0},"146":{"tf":1.0},"35":{"tf":1.0},"50":{"tf":1.0},"66":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.0},"74":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.0},"82":{"tf":1.4142135623730951}}}}}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":3,"docs":{"184":{"tf":1.0},"221":{"tf":1.0},"52":{"tf":1.0}}},"df":0,"docs":{}}}}},"i":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"78":{"tf":1.0},"95":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"g":{"df":8,"docs":{"104":{"tf":1.7320508075688772},"166":{"tf":1.0},"176":{"tf":1.0},"70":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.4142135623730951},"80":{"tf":1.0},"81":{"tf":1.0}},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"107":{"tf":1.0},"194":{"tf":1.0},"216":{"tf":1.0}}}}}}},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":7,"docs":{"225":{"tf":1.0},"5":{"tf":1.0},"53":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.4142135623730951},"7":{"tf":1.4142135623730951},"71":{"tf":1.0}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"a":{"d":{"d":{"df":1,"docs":{"109":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"130":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"117":{"tf":1.0}}},"df":0,"docs":{}}},"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":1,"docs":{"128":{"tf":1.0}}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"112":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"q":{"df":1,"docs":{"127":{"tf":1.0}}},"x":{"df":0,"docs":{},"p":{"df":1,"docs":{"116":{"tf":1.0}}}}},"g":{"df":0,"docs":{},"t":{"df":1,"docs":{"124":{"tf":1.0}}}},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"123":{"tf":1.0}}}},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"114":{"tf":1.0}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"111":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"131":{"tf":1.0}}},"df":0,"docs":{}}}}}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"118":{"tf":1.0}}}},"s":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"122":{"tf":1.0}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"113":{"tf":1.0}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":1,"docs":{"126":{"tf":1.0}}}},"h":{"df":0,"docs":{},"l":{"df":1,"docs":{"120":{"tf":1.0}}},"r":{"df":1,"docs":{"121":{"tf":1.0}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"129":{"tf":1.0}}},"df":0,"docs":{}}}}}}}}},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"125":{"tf":1.0}}}},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"115":{"tf":1.0}}},"df":0,"docs":{}}},"u":{"b":{"df":1,"docs":{"110":{"tf":1.0}}},"df":0,"docs":{}}},"x":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"119":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}}},"d":{"df":12,"docs":{"100":{"tf":1.0},"106":{"tf":1.0},"147":{"tf":1.0},"174":{"tf":1.4142135623730951},"188":{"tf":1.4142135623730951},"189":{"tf":2.449489742783178},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"199":{"tf":1.0},"93":{"tf":1.0},"98":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"0":{"df":1,"docs":{"189":{"tf":1.0}}},"1":{"df":1,"docs":{"189":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":1,"docs":{"19":{"tf":1.0}}},"t":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"93":{"tf":1.0}}},"df":0,"docs":{}}},"df":35,"docs":{"100":{"tf":1.0},"103":{"tf":1.4142135623730951},"104":{"tf":1.0},"107":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"117":{"tf":1.0},"120":{"tf":1.7320508075688772},"121":{"tf":1.4142135623730951},"122":{"tf":1.7320508075688772},"128":{"tf":1.0},"129":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.4142135623730951},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"177":{"tf":1.7320508075688772},"179":{"tf":1.0},"180":{"tf":1.0},"216":{"tf":1.4142135623730951},"39":{"tf":1.0},"62":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.7320508075688772},"75":{"tf":1.4142135623730951},"76":{"tf":1.0},"78":{"tf":2.0},"79":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.4142135623730951},"99":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"93":{"tf":1.0}}}},"s":{"(":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"s":{"df":1,"docs":{"81":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":5,"docs":{"102":{"tf":1.0},"103":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":6,"docs":{"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"133":{"tf":1.0},"223":{"tf":1.7320508075688772},"93":{"tf":1.0}}}}},"x":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"93":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}},"o":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"92":{"tf":1.0}}}},"b":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":3,"docs":{"100":{"tf":1.0},"154":{"tf":1.7320508075688772},"49":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":9,"docs":{"154":{"tf":1.0},"155":{"tf":1.7320508075688772},"18":{"tf":1.7320508075688772},"236":{"tf":1.0},"35":{"tf":1.4142135623730951},"49":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"94":{"tf":1.0}},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"(":{"$":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":1,"docs":{"155":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"155":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"155":{"tf":1.0},"49":{"tf":1.0}}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"k":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":5,"docs":{"219":{"tf":1.0},"220":{"tf":1.0},"224":{"tf":1.0},"52":{"tf":1.0},"53":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":16,"docs":{"100":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"156":{"tf":1.7320508075688772},"192":{"tf":1.0},"195":{"tf":1.0},"199":{"tf":1.0},"43":{"tf":1.7320508075688772},"82":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.0},"92":{"tf":1.0},"99":{"tf":1.0}},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"(":{"$":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"b":{"df":1,"docs":{"156":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"156":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"156":{"tf":1.0}}}}},"df":0,"docs":{}},"’":{"df":4,"docs":{"148":{"tf":1.0},"151":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0}}}}},"df":0,"docs":{}}},"o":{"d":{"df":0,"docs":{},"i":{"df":6,"docs":{"174":{"tf":1.0},"195":{"tf":2.449489742783178},"199":{"tf":1.4142135623730951},"78":{"tf":1.0},"91":{"tf":1.0},"99":{"tf":1.0}}},"y":{"df":0,"docs":{},"’":{"df":2,"docs":{"195":{"tf":1.0},"199":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"219":{"tf":1.0}}}},"o":{"df":0,"docs":{},"k":{"df":2,"docs":{"0":{"tf":1.0},"3":{"tf":1.4142135623730951}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":1,"docs":{"180":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":6,"docs":{"103":{"tf":1.0},"107":{"tf":1.4142135623730951},"132":{"tf":1.0},"201":{"tf":1.0},"26":{"tf":1.0},"87":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"110":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"h":{"df":4,"docs":{"105":{"tf":1.0},"18":{"tf":1.0},"193":{"tf":1.4142135623730951},"35":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":7,"docs":{"147":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"200":{"tf":1.0},"204":{"tf":1.0},"79":{"tf":1.0},"93":{"tf":1.0}}}}},"df":11,"docs":{"106":{"tf":1.0},"178":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.4142135623730951},"193":{"tf":1.0},"199":{"tf":1.0},"214":{"tf":1.0},"70":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.7320508075688772},"82":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"r":{"a":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":3,"docs":{"135":{"tf":1.0},"193":{"tf":1.0},"99":{"tf":1.0}}}}}},"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":5,"docs":{"193":{"tf":1.0},"212":{"tf":1.0},"63":{"tf":1.7320508075688772},"89":{"tf":1.0},"93":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"k":{"df":6,"docs":{"100":{"tf":1.0},"192":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":2.0},"197":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"72":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"225":{"tf":1.0}}}}}}}},"s":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"p":{".":{"df":0,"docs":{},"i":{"2":{"5":{"6":{"df":1,"docs":{"92":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"4":{"df":1,"docs":{"92":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":1,"docs":{"92":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":8,"docs":{"14":{"tf":1.0},"161":{"tf":1.0},"185":{"tf":1.0},"39":{"tf":1.4142135623730951},"40":{"tf":1.4142135623730951},"43":{"tf":1.4142135623730951},"70":{"tf":1.4142135623730951},"80":{"tf":1.0}}}}}},"g":{"df":6,"docs":{"221":{"tf":1.0},"222":{"tf":1.4142135623730951},"223":{"tf":1.0},"224":{"tf":1.0},"23":{"tf":1.0},"82":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":1,"docs":{"232":{"tf":1.0}}}}}},"i":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"10":{"tf":1.0}}}},"df":0,"docs":{},"l":{"d":{"df":9,"docs":{"10":{"tf":1.0},"221":{"tf":1.0},"226":{"tf":2.449489742783178},"6":{"tf":1.0},"60":{"tf":1.0},"61":{"tf":1.0},"68":{"tf":1.7320508075688772},"71":{"tf":2.0},"90":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"69":{"tf":1.0},"71":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"71":{"tf":1.0}}}},"t":{"df":1,"docs":{"71":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"134":{"tf":1.0},"178":{"tf":1.0},"71":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"k":{"df":3,"docs":{"100":{"tf":1.0},"182":{"tf":1.0},"90":{"tf":1.0}}}},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"82":{"tf":1.0}}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"e":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"128":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":1,"docs":{"128":{"tf":1.0}}},"v":{"0":{"df":1,"docs":{"128":{"tf":1.0}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"d":{"df":6,"docs":{"18":{"tf":1.0},"186":{"tf":1.0},"219":{"tf":2.23606797749979},"33":{"tf":1.4142135623730951},"38":{"tf":1.0},"94":{"tf":1.0}}},"df":0,"docs":{}}},"df":48,"docs":{"100":{"tf":1.0},"103":{"tf":1.0},"105":{"tf":1.0},"116":{"tf":1.0},"128":{"tf":2.6457513110645907},"129":{"tf":2.6457513110645907},"137":{"tf":1.0},"138":{"tf":1.7320508075688772},"139":{"tf":1.4142135623730951},"147":{"tf":1.4142135623730951},"159":{"tf":1.7320508075688772},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"166":{"tf":1.4142135623730951},"167":{"tf":1.0},"168":{"tf":1.0},"171":{"tf":1.0},"176":{"tf":2.23606797749979},"177":{"tf":1.7320508075688772},"178":{"tf":2.0},"179":{"tf":1.0},"180":{"tf":1.0},"182":{"tf":1.4142135623730951},"183":{"tf":2.23606797749979},"184":{"tf":2.23606797749979},"185":{"tf":2.0},"186":{"tf":2.0},"187":{"tf":2.23606797749979},"201":{"tf":1.7320508075688772},"205":{"tf":1.4142135623730951},"207":{"tf":1.4142135623730951},"209":{"tf":1.0},"210":{"tf":1.0},"215":{"tf":2.23606797749979},"216":{"tf":1.0},"40":{"tf":1.0},"70":{"tf":1.4142135623730951},"75":{"tf":1.0},"80":{"tf":2.449489742783178},"81":{"tf":2.0},"82":{"tf":2.6457513110645907},"84":{"tf":1.0},"87":{"tf":1.0},"89":{"tf":1.4142135623730951},"90":{"tf":1.4142135623730951},"95":{"tf":1.0}},"s":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"p":{"df":2,"docs":{"80":{"tf":1.0},"81":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"c":{"a":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"180":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"(":{"$":{"df":0,"docs":{},"g":{"a":{"df":1,"docs":{"201":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"201":{"tf":1.0}}},"df":0,"docs":{}}},"_":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"_":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"y":{"(":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"57":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"s":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"d":{"df":2,"docs":{"100":{"tf":1.0},"202":{"tf":1.0}},"e":{"(":{"$":{"df":0,"docs":{},"g":{"a":{"df":1,"docs":{"202":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"202":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":4,"docs":{"100":{"tf":1.0},"187":{"tf":1.0},"41":{"tf":1.0},"80":{"tf":1.0}}},"y":{"(":{"$":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"187":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"187":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":8,"docs":{"100":{"tf":1.0},"159":{"tf":1.7320508075688772},"160":{"tf":1.0},"182":{"tf":1.0},"187":{"tf":1.7320508075688772},"201":{"tf":1.7320508075688772},"223":{"tf":1.0},"41":{"tf":1.0}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"159":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"159":{"tf":1.0}}},"df":0,"docs":{}}},"df":4,"docs":{"100":{"tf":1.0},"159":{"tf":1.0},"41":{"tf":1.0},"87":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":2,"docs":{"100":{"tf":1.0},"160":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":38,"docs":{"0":{"tf":1.0},"100":{"tf":1.4142135623730951},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"144":{"tf":1.0},"157":{"tf":1.0},"161":{"tf":1.0},"165":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":2.23606797749979},"179":{"tf":1.0},"18":{"tf":1.0},"190":{"tf":1.7320508075688772},"200":{"tf":1.0},"201":{"tf":1.7320508075688772},"202":{"tf":1.0},"203":{"tf":2.0},"204":{"tf":2.0},"208":{"tf":1.4142135623730951},"209":{"tf":1.4142135623730951},"210":{"tf":1.7320508075688772},"211":{"tf":1.4142135623730951},"212":{"tf":1.0},"213":{"tf":1.4142135623730951},"214":{"tf":1.4142135623730951},"215":{"tf":1.0},"216":{"tf":1.0},"223":{"tf":1.4142135623730951},"35":{"tf":1.0},"37":{"tf":1.0},"56":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":1.0},"85":{"tf":1.0},"87":{"tf":1.4142135623730951},"92":{"tf":1.0}},"e":{"df":3,"docs":{"174":{"tf":1.4142135623730951},"201":{"tf":1.0},"204":{"tf":1.0}},"e":{"df":0,"docs":{},"’":{"df":3,"docs":{"174":{"tf":1.7320508075688772},"202":{"tf":1.4142135623730951},"203":{"tf":1.0}}}},"r":{"df":7,"docs":{"100":{"tf":1.0},"103":{"tf":1.0},"141":{"tf":2.0},"205":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"91":{"tf":1.0}},"’":{"df":4,"docs":{"202":{"tf":1.0},"203":{"tf":1.4142135623730951},"205":{"tf":1.0},"206":{"tf":1.0}}}}},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"d":{":":{":":{"c":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"201":{"tf":1.0}},"l":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"202":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"203":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"c":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"204":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":5,"docs":{"100":{"tf":1.0},"142":{"tf":1.7320508075688772},"75":{"tf":1.0},"87":{"tf":1.0},"95":{"tf":1.0}}}}},"df":0,"docs":{}},"’":{"df":4,"docs":{"159":{"tf":1.0},"160":{"tf":1.0},"185":{"tf":1.0},"187":{"tf":1.0}}}}},"n":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"(":{"0":{"df":0,"docs":{},"x":{"4":{"0":{"df":1,"docs":{"81":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":1,"docs":{"213":{"tf":1.0}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"97":{"tf":1.0}},"i":{"c":{"df":3,"docs":{"167":{"tf":1.0},"179":{"tf":1.0},"75":{"tf":1.0}}},"df":0,"docs":{}}}},"’":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}},"p":{"df":1,"docs":{"40":{"tf":1.0}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":2,"docs":{"65":{"tf":1.4142135623730951},"72":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"18":{"tf":1.0},"66":{"tf":1.0}},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"0":{"tf":1.0},"82":{"tf":1.0}}}}}}}},"g":{"df":0,"docs":{},"o":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":2,"docs":{"62":{"tf":1.0},"89":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"df":24,"docs":{"101":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"109":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"170":{"tf":1.0},"174":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.4142135623730951},"181":{"tf":1.0},"189":{"tf":1.0},"192":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":2.6457513110645907},"196":{"tf":2.0},"197":{"tf":2.0},"76":{"tf":1.7320508075688772},"80":{"tf":1.0},"82":{"tf":1.0},"93":{"tf":1.0},"94":{"tf":1.4142135623730951},"98":{"tf":1.0}}}}},"s":{"c":{"a":{"d":{"df":3,"docs":{"75":{"tf":1.0},"79":{"tf":1.0},"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":7,"docs":{"18":{"tf":2.0},"194":{"tf":3.0},"223":{"tf":1.4142135623730951},"224":{"tf":1.4142135623730951},"48":{"tf":1.0},"49":{"tf":1.0},"99":{"tf":1.0}}}},"t":{"c":{"df":0,"docs":{},"h":{"df":3,"docs":{"194":{"tf":1.0},"75":{"tf":1.0},"82":{"tf":1.7320508075688772}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"78":{"tf":1.7320508075688772}},"s":{"df":1,"docs":{"78":{"tf":1.0}}}}}}}}},"u":{"df":0,"docs":{},"s":{"df":5,"docs":{"204":{"tf":1.0},"224":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.0},"92":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"40":{"tf":1.0}}}},"df":0,"docs":{}}}},"c":{"c":{"a":{"3":{"8":{"d":{"df":0,"docs":{},"f":{"df":2,"docs":{"78":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"d":{"df":1,"docs":{"221":{"tf":1.0}}},"df":1,"docs":{"52":{"tf":1.0}},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"103":{"tf":1.0}}}},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"223":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"99":{"tf":1.0}}}}},"df":0,"docs":{}}}},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":6,"docs":{"145":{"tf":1.0},"151":{"tf":1.0},"219":{"tf":1.4142135623730951},"35":{"tf":1.0},"68":{"tf":1.0},"81":{"tf":1.0}},"i":{"d":{"df":2,"docs":{"100":{"tf":1.0},"145":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"91":{"tf":1.0}}}}}}},"n":{"c":{"df":2,"docs":{"52":{"tf":1.0},"61":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":12,"docs":{"146":{"tf":1.0},"147":{"tf":1.0},"18":{"tf":1.0},"192":{"tf":1.0},"210":{"tf":1.0},"223":{"tf":1.4142135623730951},"3":{"tf":1.0},"37":{"tf":1.0},"62":{"tf":1.0},"63":{"tf":1.4142135623730951},"82":{"tf":1.0},"97":{"tf":1.0}}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"11":{"tf":1.0},"221":{"tf":1.0},"230":{"tf":1.0},"58":{"tf":1.0}}}}}},"r":{"df":1,"docs":{"29":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"157":{"tf":1.0},"165":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"k":{"df":10,"docs":{"232":{"tf":1.0},"70":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.4142135623730951},"82":{"tf":1.4142135623730951},"87":{"tf":1.0},"92":{"tf":1.0},"93":{"tf":1.4142135623730951},"95":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"52":{"tf":1.0},"76":{"tf":1.0}}},"df":0,"docs":{}}}},"i":{"df":2,"docs":{"61":{"tf":1.0},"63":{"tf":1.4142135623730951}},"r":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"v":{"df":1,"docs":{"68":{"tf":1.0}}}}}},"df":0,"docs":{}}},"l":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":1,"docs":{"78":{"tf":1.0}}}},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"5":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"81":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"df":1,"docs":{"177":{"tf":1.0}},"i":{"df":3,"docs":{"147":{"tf":1.0},"78":{"tf":1.0},"82":{"tf":1.0}}}}}}},"u":{"d":{"df":1,"docs":{"91":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"75":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"105":{"tf":1.0}}}}},"r":{"df":2,"docs":{"117":{"tf":1.0},"93":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"df":4,"docs":{"11":{"tf":2.0},"18":{"tf":1.0},"73":{"tf":1.0},"94":{"tf":1.0}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"64":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"221":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":3,"docs":{"11":{"tf":1.0},"219":{"tf":1.0},"222":{"tf":1.0}}}}},"z":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"134":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"134":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"134":{"tf":1.0}}}},"o":{"d":{"df":0,"docs":{},"e":{"/":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"104":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"b":{"a":{"df":0,"docs":{},"s":{"df":6,"docs":{"58":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.4142135623730951},"65":{"tf":1.7320508075688772},"82":{"tf":1.0},"97":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":4,"docs":{"100":{"tf":1.0},"183":{"tf":1.0},"42":{"tf":1.0},"80":{"tf":1.0}}},"y":{"(":{"$":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"183":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"183":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":53,"docs":{"0":{"tf":1.0},"100":{"tf":1.0},"104":{"tf":1.0},"12":{"tf":1.4142135623730951},"13":{"tf":1.0},"14":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.4142135623730951},"164":{"tf":1.0},"17":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"18":{"tf":1.4142135623730951},"182":{"tf":1.4142135623730951},"183":{"tf":1.7320508075688772},"184":{"tf":2.0},"19":{"tf":1.0},"190":{"tf":1.0},"202":{"tf":1.4142135623730951},"203":{"tf":1.0},"205":{"tf":1.7320508075688772},"206":{"tf":1.0},"214":{"tf":2.23606797749979},"219":{"tf":2.0},"221":{"tf":1.0},"222":{"tf":1.0},"223":{"tf":1.4142135623730951},"233":{"tf":1.0},"236":{"tf":1.4142135623730951},"33":{"tf":1.4142135623730951},"35":{"tf":3.0},"36":{"tf":1.0},"37":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":2.23606797749979},"5":{"tf":1.0},"53":{"tf":1.4142135623730951},"6":{"tf":1.0},"64":{"tf":1.4142135623730951},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.4142135623730951},"68":{"tf":1.7320508075688772},"69":{"tf":1.4142135623730951},"70":{"tf":1.0},"75":{"tf":1.7320508075688772},"76":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"86":{"tf":1.7320508075688772}},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":11,"docs":{"104":{"tf":1.0},"176":{"tf":1.4142135623730951},"195":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.7320508075688772},"87":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.0},"95":{"tf":1.0}}}}},"s":{"df":5,"docs":{"100":{"tf":1.0},"162":{"tf":1.7320508075688772},"35":{"tf":1.0},"88":{"tf":1.0},"89":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"b":{"a":{"df":0,"docs":{},"s":{"df":2,"docs":{"100":{"tf":1.0},"148":{"tf":2.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":2,"docs":{"108":{"tf":1.0},"86":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"223":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"91":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"n":{"df":1,"docs":{"89":{"tf":1.4142135623730951}}}}}},"m":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":5,"docs":{"223":{"tf":1.4142135623730951},"5":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"84":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":2,"docs":{"221":{"tf":1.0},"53":{"tf":1.0}}},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":3,"docs":{"19":{"tf":1.0},"30":{"tf":1.0},"94":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"107":{"tf":1.0},"170":{"tf":1.0},"195":{"tf":1.0},"64":{"tf":2.0},"98":{"tf":1.4142135623730951}}}}},"i":{"df":0,"docs":{},"t":{"df":4,"docs":{"78":{"tf":1.0},"89":{"tf":1.4142135623730951},"90":{"tf":1.0},"91":{"tf":1.0}}}},"o":{"df":0,"docs":{},"n":{"df":9,"docs":{"117":{"tf":1.0},"138":{"tf":1.0},"208":{"tf":1.0},"214":{"tf":1.0},"52":{"tf":1.0},"79":{"tf":1.0},"83":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.4142135623730951}}}}},"p":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"86":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"138":{"tf":1.0}}}}}},"df":0,"docs":{},"r":{"df":10,"docs":{"123":{"tf":1.4142135623730951},"124":{"tf":1.4142135623730951},"125":{"tf":1.4142135623730951},"126":{"tf":1.4142135623730951},"194":{"tf":1.0},"34":{"tf":1.0},"40":{"tf":1.0},"91":{"tf":1.0},"93":{"tf":1.0},"94":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":11,"docs":{"0":{"tf":1.0},"103":{"tf":1.0},"107":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"78":{"tf":1.7320508075688772},"79":{"tf":1.0},"90":{"tf":1.0}}}}}}},"t":{"df":11,"docs":{"202":{"tf":1.0},"213":{"tf":1.0},"220":{"tf":1.0},"222":{"tf":1.4142135623730951},"223":{"tf":1.0},"226":{"tf":1.0},"235":{"tf":1.0},"24":{"tf":1.0},"66":{"tf":1.0},"70":{"tf":1.0},"80":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":61,"docs":{"0":{"tf":1.0},"107":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"16":{"tf":1.0},"169":{"tf":1.0},"18":{"tf":2.23606797749979},"181":{"tf":1.0},"186":{"tf":1.0},"19":{"tf":1.0},"215":{"tf":1.4142135623730951},"216":{"tf":1.0},"217":{"tf":1.0},"219":{"tf":2.23606797749979},"22":{"tf":1.0},"220":{"tf":1.0},"221":{"tf":1.0},"222":{"tf":1.4142135623730951},"223":{"tf":1.0},"224":{"tf":1.0},"225":{"tf":1.4142135623730951},"227":{"tf":1.0},"235":{"tf":1.4142135623730951},"236":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"3":{"tf":1.0},"33":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.7320508075688772},"40":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":2.0},"50":{"tf":1.7320508075688772},"52":{"tf":1.0},"57":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.0},"6":{"tf":1.7320508075688772},"60":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":2.0},"67":{"tf":1.7320508075688772},"68":{"tf":1.4142135623730951},"69":{"tf":1.7320508075688772},"70":{"tf":1.0},"71":{"tf":1.4142135623730951},"73":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"8":{"tf":1.0},"80":{"tf":1.0},"83":{"tf":1.4142135623730951},"9":{"tf":1.0},"94":{"tf":1.4142135623730951},"99":{"tf":1.0}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"83":{"tf":1.0}}}}},"df":4,"docs":{"113":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"133":{"tf":1.4142135623730951}}}}}},"t":{"df":4,"docs":{"11":{"tf":1.0},"199":{"tf":1.0},"219":{"tf":1.0},"236":{"tf":1.0}}},"x":{"df":2,"docs":{"224":{"tf":1.4142135623730951},"52":{"tf":1.0}}}},"i":{"c":{"df":1,"docs":{"62":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"5":{"tf":1.4142135623730951}}},"s":{"df":1,"docs":{"52":{"tf":1.0}}},"u":{"df":0,"docs":{},"n":{"d":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"169":{"tf":1.0},"181":{"tf":1.0},"75":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}}}}},"df":6,"docs":{"139":{"tf":1.0},"140":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"75":{"tf":1.7320508075688772},"84":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":2,"docs":{"224":{"tf":1.0},"61":{"tf":1.0}}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"4":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}}}},"df":13,"docs":{"120":{"tf":1.0},"121":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"138":{"tf":1.0},"181":{"tf":1.0},"190":{"tf":1.0},"219":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0},"83":{"tf":1.4142135623730951},"84":{"tf":1.0},"89":{"tf":1.0}}}}}},"n":{"c":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"43":{"tf":1.0}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"61":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"170":{"tf":1.0},"99":{"tf":1.0}}}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":4,"docs":{"193":{"tf":2.23606797749979},"195":{"tf":2.449489742783178},"199":{"tf":1.0},"99":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"195":{"tf":2.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":1,"docs":{"94":{"tf":1.4142135623730951}},"u":{"df":0,"docs":{},"r":{"df":9,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"218":{"tf":1.4142135623730951},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.7320508075688772},"29":{"tf":1.0},"33":{"tf":1.0},"95":{"tf":1.0}}}}}},"l":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":2,"docs":{"18":{"tf":1.0},"190":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"14":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"v":{"df":11,"docs":{"103":{"tf":1.0},"105":{"tf":1.0},"110":{"tf":1.0},"116":{"tf":1.0},"120":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"179":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.0},"93":{"tf":1.4142135623730951}}}}},"i":{"d":{"df":6,"docs":{"220":{"tf":1.0},"234":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"93":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":5,"docs":{"219":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0},"82":{"tf":1.0},"93":{"tf":1.0}}}}},"t":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":25,"docs":{"100":{"tf":1.0},"105":{"tf":1.7320508075688772},"107":{"tf":1.7320508075688772},"117":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.4142135623730951},"14":{"tf":1.0},"169":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"179":{"tf":1.0},"181":{"tf":1.4142135623730951},"186":{"tf":1.0},"194":{"tf":1.4142135623730951},"43":{"tf":1.0},"45":{"tf":1.0},"47":{"tf":1.0},"64":{"tf":1.0},"75":{"tf":2.449489742783178},"80":{"tf":1.7320508075688772},"83":{"tf":1.4142135623730951},"85":{"tf":1.0},"87":{"tf":1.4142135623730951},"93":{"tf":1.0},"95":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"56":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"172":{"tf":1.0},"191":{"tf":1.0},"192":{"tf":1.0},"95":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":7,"docs":{"191":{"tf":1.0},"35":{"tf":1.4142135623730951},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.7320508075688772},"51":{"tf":1.7320508075688772},"56":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"105":{"tf":1.0}}}},"m":{"df":8,"docs":{"106":{"tf":1.0},"108":{"tf":1.0},"161":{"tf":1.0},"169":{"tf":1.0},"176":{"tf":1.0},"179":{"tf":1.0},"181":{"tf":1.0},"212":{"tf":1.0}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"39":{"tf":1.0},"43":{"tf":1.0},"5":{"tf":1.0},"97":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"138":{"tf":1.0},"199":{"tf":1.0},"3":{"tf":1.0}}}},"x":{"df":0,"docs":{},"t":{"df":6,"docs":{"202":{"tf":1.0},"203":{"tf":1.0},"65":{"tf":1.0},"69":{"tf":2.0},"75":{"tf":1.0},"78":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":4,"docs":{"100":{"tf":1.0},"192":{"tf":1.0},"195":{"tf":2.0},"197":{"tf":1.7320508075688772}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":59,"docs":{"0":{"tf":2.0},"104":{"tf":1.4142135623730951},"12":{"tf":1.0},"13":{"tf":1.7320508075688772},"14":{"tf":2.0},"144":{"tf":1.0},"145":{"tf":1.0},"157":{"tf":1.0},"165":{"tf":1.0},"167":{"tf":1.0},"172":{"tf":1.0},"174":{"tf":1.0},"179":{"tf":1.4142135623730951},"18":{"tf":2.0},"190":{"tf":1.0},"191":{"tf":1.0},"2":{"tf":1.4142135623730951},"200":{"tf":1.4142135623730951},"205":{"tf":1.4142135623730951},"206":{"tf":1.0},"213":{"tf":1.0},"219":{"tf":2.23606797749979},"220":{"tf":1.0},"222":{"tf":1.4142135623730951},"223":{"tf":2.0},"233":{"tf":1.0},"235":{"tf":1.4142135623730951},"27":{"tf":1.4142135623730951},"32":{"tf":2.449489742783178},"33":{"tf":2.0},"35":{"tf":1.4142135623730951},"37":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.4142135623730951},"40":{"tf":1.7320508075688772},"43":{"tf":2.0},"44":{"tf":1.0},"45":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.4142135623730951},"52":{"tf":1.4142135623730951},"53":{"tf":1.4142135623730951},"55":{"tf":1.0},"56":{"tf":1.4142135623730951},"57":{"tf":1.4142135623730951},"6":{"tf":1.0},"66":{"tf":1.4142135623730951},"68":{"tf":2.0},"70":{"tf":1.0},"75":{"tf":1.0},"81":{"tf":1.7320508075688772},"82":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.0},"89":{"tf":1.4142135623730951},"90":{"tf":2.23606797749979},"91":{"tf":1.0},"92":{"tf":1.0},"93":{"tf":1.4142135623730951}},"s":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"’":{"df":4,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"205":{"tf":1.0},"213":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":5,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"59":{"tf":1.0},"63":{"tf":1.4142135623730951},"65":{"tf":2.0}},"o":{"df":0,"docs":{},"r":{"df":6,"docs":{"1":{"tf":1.0},"221":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.0},"65":{"tf":1.0},"81":{"tf":1.0}}}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"l":{"df":19,"docs":{"100":{"tf":1.0},"13":{"tf":1.0},"189":{"tf":1.4142135623730951},"192":{"tf":1.7320508075688772},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"226":{"tf":1.0},"55":{"tf":1.0},"70":{"tf":1.0},"76":{"tf":2.0},"93":{"tf":1.0},"94":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":3,"docs":{"52":{"tf":1.0},"53":{"tf":1.0},"55":{"tf":1.0}}},"t":{"df":2,"docs":{"74":{"tf":1.0},"99":{"tf":1.0}}}},"r":{"df":0,"docs":{},"s":{"df":2,"docs":{"100":{"tf":1.0},"129":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"i":{"df":13,"docs":{"100":{"tf":1.0},"108":{"tf":1.4142135623730951},"178":{"tf":1.7320508075688772},"182":{"tf":1.4142135623730951},"183":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"185":{"tf":1.4142135623730951},"186":{"tf":1.4142135623730951},"187":{"tf":1.4142135623730951},"75":{"tf":1.0},"85":{"tf":1.0},"87":{"tf":1.0},"95":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"91":{"tf":1.0},"95":{"tf":1.0}}},"p":{"df":0,"docs":{},"u":{"df":2,"docs":{"82":{"tf":1.0},"90":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":6,"docs":{"221":{"tf":1.4142135623730951},"223":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0},"91":{"tf":1.0},"93":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"82":{"tf":1.0}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":5,"docs":{"18":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"29":{"tf":1.0},"98":{"tf":1.0}}},"df":0,"docs":{}}}}}},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":2,"docs":{"81":{"tf":1.0},"82":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":7,"docs":{"116":{"tf":1.0},"13":{"tf":1.4142135623730951},"14":{"tf":1.7320508075688772},"180":{"tf":1.0},"43":{"tf":1.0},"74":{"tf":1.0},"92":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"134":{"tf":1.0},"75":{"tf":1.0},"87":{"tf":1.0},"99":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"64":{"tf":1.0},"93":{"tf":1.0}},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"179":{"tf":1.0},"223":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"52":{"tf":1.0}}}},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"52":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"82":{"tf":1.0}}}},"df":2,"docs":{"138":{"tf":1.0},"58":{"tf":1.0}}}}}},"p":{"df":0,"docs":{},"u":{"df":2,"docs":{"218":{"tf":1.4142135623730951},"219":{"tf":1.4142135623730951}}}},"r":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"43":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":4,"docs":{"62":{"tf":2.449489742783178},"69":{"tf":1.7320508075688772},"71":{"tf":1.4142135623730951},"73":{"tf":1.0}},"s":{"/":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"/":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"j":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"89":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"r":{"c":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"82":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"r":{"c":{"/":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"b":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"94":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":1,"docs":{"73":{"tf":1.0}}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"r":{"c":{"/":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"b":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"94":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"94":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":11,"docs":{"100":{"tf":1.0},"161":{"tf":1.0},"190":{"tf":1.0},"192":{"tf":1.0},"205":{"tf":1.4142135623730951},"206":{"tf":1.7320508075688772},"224":{"tf":1.0},"43":{"tf":1.7320508075688772},"62":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0}},"e":{"(":{"$":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"205":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"205":{"tf":1.0}}},"df":0,"docs":{}}},"2":{"(":{"$":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"206":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"206":{"tf":1.0}}},"df":0,"docs":{}}},"df":4,"docs":{"100":{"tf":1.0},"190":{"tf":1.0},"206":{"tf":1.0},"43":{"tf":1.0}}},"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"d":{":":{":":{"c":{"df":0,"docs":{},"r":{"df":1,"docs":{"205":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"2":{"df":1,"docs":{"206":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":3,"docs":{"190":{"tf":1.0},"200":{"tf":1.0},"224":{"tf":1.0}}}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"92":{"tf":1.0}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":8,"docs":{"174":{"tf":1.0},"200":{"tf":1.0},"225":{"tf":1.4142135623730951},"227":{"tf":1.4142135623730951},"61":{"tf":1.0},"71":{"tf":1.4142135623730951},"73":{"tf":1.0},"93":{"tf":1.0}}}}},"u":{"c":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":2,"docs":{"75":{"tf":1.0},"95":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":30,"docs":{"141":{"tf":1.0},"142":{"tf":1.0},"144":{"tf":1.0},"150":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"162":{"tf":1.0},"165":{"tf":1.0},"167":{"tf":1.0},"179":{"tf":1.0},"183":{"tf":1.0},"187":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"208":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"213":{"tf":1.0},"233":{"tf":1.0},"33":{"tf":1.0},"89":{"tf":1.0},"93":{"tf":1.4142135623730951}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"(":{"0":{"df":0,"docs":{},"x":{"<":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":1,"docs":{"216":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":2,"docs":{"100":{"tf":1.0},"216":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}}}}},"df":6,"docs":{"216":{"tf":1.0},"236":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951},"86":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"86":{"tf":1.0}}}}}}}}}}}}}}}}}}},"d":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":7,"docs":{"1":{"tf":1.0},"18":{"tf":1.0},"232":{"tf":1.0},"235":{"tf":1.4142135623730951},"34":{"tf":1.0},"39":{"tf":1.0},"52":{"tf":1.4142135623730951}}}},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"98":{"tf":1.0}}}},"t":{"a":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":2,"docs":{"100":{"tf":1.0},"186":{"tf":1.0}}},"y":{"(":{"$":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"186":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"186":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":21,"docs":{"161":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"18":{"tf":1.0},"182":{"tf":1.0},"185":{"tf":1.4142135623730951},"186":{"tf":1.4142135623730951},"201":{"tf":1.7320508075688772},"207":{"tf":1.7320508075688772},"209":{"tf":1.7320508075688772},"210":{"tf":1.7320508075688772},"211":{"tf":1.0},"215":{"tf":2.449489742783178},"223":{"tf":1.4142135623730951},"35":{"tf":1.0},"49":{"tf":1.0},"57":{"tf":2.0},"70":{"tf":1.0},"87":{"tf":1.0},"91":{"tf":1.0},"95":{"tf":1.0}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"(":{"\\"":{"<":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"170":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"170":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":4,"docs":{"100":{"tf":1.0},"170":{"tf":1.0},"43":{"tf":1.0},"44":{"tf":1.0}}}}}}}},"s":{"df":4,"docs":{"100":{"tf":1.0},"171":{"tf":1.0},"43":{"tf":1.0},"45":{"tf":1.0}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"(":{"\\"":{"<":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"171":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"171":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"’":{"df":1,"docs":{"185":{"tf":1.0}}}},"df":0,"docs":{}},"y":{"df":2,"docs":{"167":{"tf":1.0},"179":{"tf":1.0}}}},"b":{"c":{"df":0,"docs":{},"f":{"c":{"9":{"2":{"1":{"df":1,"docs":{"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"95":{"tf":1.0}},"’":{"d":{"df":1,"docs":{"174":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":3,"docs":{"52":{"tf":1.0},"75":{"tf":1.4142135623730951},"92":{"tf":1.0}}},"df":0,"docs":{},"l":{"df":1,"docs":{"39":{"tf":1.0}}}},"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":11,"docs":{"135":{"tf":1.0},"16":{"tf":1.7320508075688772},"17":{"tf":1.7320508075688772},"26":{"tf":1.0},"30":{"tf":1.0},"53":{"tf":1.0},"57":{"tf":1.0},"94":{"tf":2.0},"97":{"tf":1.4142135623730951},"98":{"tf":1.4142135623730951},"99":{"tf":1.0}}}}},"c":{"df":0,"docs":{},"i":{"d":{"df":2,"docs":{"18":{"tf":1.0},"224":{"tf":1.0}}},"df":0,"docs":{},"m":{"df":1,"docs":{"99":{"tf":1.0}}},"s":{"df":5,"docs":{"219":{"tf":1.0},"235":{"tf":1.0},"64":{"tf":1.0},"74":{"tf":1.0},"93":{"tf":1.0}}}},"l":{"a":{"df":0,"docs":{},"r":{"df":6,"docs":{"107":{"tf":1.0},"169":{"tf":1.4142135623730951},"174":{"tf":1.7320508075688772},"181":{"tf":1.7320508075688772},"198":{"tf":1.0},"223":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"92":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":2,"docs":{"69":{"tf":1.0},"81":{"tf":1.0}}}}}}},"d":{"df":0,"docs":{},"i":{"c":{"df":5,"docs":{"190":{"tf":1.4142135623730951},"62":{"tf":1.0},"69":{"tf":1.0},"82":{"tf":1.0},"83":{"tf":1.0}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"p":{"df":3,"docs":{"138":{"tf":1.0},"179":{"tf":1.0},"75":{"tf":1.7320508075688772}},"l":{"df":12,"docs":{"106":{"tf":1.0},"146":{"tf":1.0},"175":{"tf":1.0},"208":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":1.4142135623730951},"85":{"tf":1.4142135623730951},"87":{"tf":1.0},"91":{"tf":1.0},"93":{"tf":1.4142135623730951},"95":{"tf":1.0},"98":{"tf":1.0}},"i":{"c":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"’":{"df":2,"docs":{"167":{"tf":1.0},"179":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":13,"docs":{"103":{"tf":1.4142135623730951},"107":{"tf":1.7320508075688772},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"17":{"tf":1.0},"194":{"tf":2.23606797749979},"73":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.0},"98":{"tf":1.4142135623730951},"99":{"tf":1.0}}}}}},"df":1,"docs":{"75":{"tf":1.0}},"i":{"df":1,"docs":{"52":{"tf":1.0}},"n":{"df":5,"docs":{"174":{"tf":1.0},"178":{"tf":1.0},"190":{"tf":1.0},"221":{"tf":1.0},"223":{"tf":2.0}},"i":{"df":0,"docs":{},"t":{"df":3,"docs":{"75":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"64":{"tf":1.0},"65":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"a":{"df":0,"docs":{},"l":{"df":5,"docs":{"100":{"tf":1.0},"18":{"tf":1.0},"190":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0}},"l":{"(":{"$":{"df":0,"docs":{},"g":{"a":{"df":1,"docs":{"203":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"203":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"t":{"df":2,"docs":{"213":{"tf":1.0},"64":{"tf":1.0}}}},"i":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"181":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"df":1,"docs":{"236":{"tf":1.0}}}}},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":4,"docs":{"75":{"tf":1.4142135623730951},"78":{"tf":2.23606797749979},"91":{"tf":1.0},"95":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"63":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":9,"docs":{"147":{"tf":1.0},"166":{"tf":1.0},"18":{"tf":1.4142135623730951},"226":{"tf":1.7320508075688772},"62":{"tf":3.0},"68":{"tf":1.0},"71":{"tf":1.7320508075688772},"8":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":12,"docs":{"163":{"tf":1.4142135623730951},"164":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"18":{"tf":3.1622776601683795},"205":{"tf":1.0},"206":{"tf":1.0},"233":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.7320508075688772},"43":{"tf":2.23606797749979},"75":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"c":{"df":3,"docs":{"202":{"tf":1.0},"213":{"tf":1.0},"52":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":5,"docs":{"179":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"51":{"tf":1.0},"81":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":2,"docs":{"98":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":106,"docs":{"102":{"tf":1.0},"107":{"tf":1.0},"108":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.4142135623730951},"147":{"tf":1.4142135623730951},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.4142135623730951},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.4142135623730951},"167":{"tf":1.4142135623730951},"168":{"tf":1.4142135623730951},"169":{"tf":1.4142135623730951},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"98":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":4,"docs":{"219":{"tf":1.4142135623730951},"52":{"tf":1.0},"64":{"tf":1.0},"76":{"tf":1.4142135623730951}}}},"r":{"df":2,"docs":{"31":{"tf":1.0},"53":{"tf":1.0}}}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"81":{"tf":1.0}}}}},"t":{"df":7,"docs":{"178":{"tf":1.7320508075688772},"183":{"tf":1.4142135623730951},"184":{"tf":1.7320508075688772},"185":{"tf":1.4142135623730951},"186":{"tf":1.4142135623730951},"187":{"tf":1.4142135623730951},"223":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":11,"docs":{"135":{"tf":2.23606797749979},"136":{"tf":1.7320508075688772},"137":{"tf":2.0},"178":{"tf":1.7320508075688772},"182":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"201":{"tf":1.0}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":5,"docs":{"11":{"tf":1.0},"224":{"tf":1.0},"76":{"tf":1.0},"94":{"tf":1.0},"97":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":6,"docs":{"40":{"tf":1.0},"75":{"tf":1.7320508075688772},"79":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":1.0},"95":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"166":{"tf":1.0},"207":{"tf":1.4142135623730951},"75":{"tf":1.0},"80":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"138":{"tf":1.0},"206":{"tf":1.0},"68":{"tf":1.0}}}}}}}}}}},"v":{"df":2,"docs":{"53":{"tf":1.0},"62":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":12,"docs":{"1":{"tf":1.4142135623730951},"16":{"tf":1.0},"17":{"tf":1.0},"20":{"tf":1.0},"236":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0},"52":{"tf":1.0},"58":{"tf":1.0},"61":{"tf":1.4142135623730951},"90":{"tf":1.0},"91":{"tf":1.7320508075688772}}}}}}}},"i":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"34":{"tf":1.0},"76":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":15,"docs":{"0":{"tf":2.23606797749979},"1":{"tf":1.0},"12":{"tf":1.0},"222":{"tf":1.0},"230":{"tf":1.0},"24":{"tf":1.0},"34":{"tf":1.4142135623730951},"36":{"tf":1.0},"39":{"tf":1.0},"40":{"tf":1.0},"43":{"tf":1.4142135623730951},"50":{"tf":1.7320508075688772},"74":{"tf":1.0},"75":{"tf":1.4142135623730951},"85":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":5,"docs":{"223":{"tf":3.0},"224":{"tf":2.0},"35":{"tf":1.0},"68":{"tf":1.0},"91":{"tf":1.0}}}}}}}},"i":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"100":{"tf":1.0},"151":{"tf":2.0},"47":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"214":{"tf":1.0}}}}},"r":{"df":2,"docs":{"16":{"tf":1.0},"62":{"tf":1.0}},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":8,"docs":{"107":{"tf":1.0},"134":{"tf":1.0},"137":{"tf":1.0},"178":{"tf":1.0},"189":{"tf":1.0},"19":{"tf":1.0},"198":{"tf":1.0},"78":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":5,"docs":{"16":{"tf":1.0},"18":{"tf":1.4142135623730951},"54":{"tf":1.0},"62":{"tf":1.0},"94":{"tf":2.0}}}}}}},"df":0,"docs":{}}},"s":{"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"17":{"tf":1.0},"18":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"a":{"df":0,"docs":{},"r":{"d":{"df":2,"docs":{"135":{"tf":1.0},"190":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"43":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"63":{"tf":1.0},"65":{"tf":1.0}}}}}},"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"h":{"df":3,"docs":{"194":{"tf":1.0},"87":{"tf":1.0},"90":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"137":{"tf":1.0},"174":{"tf":1.0},"91":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"82":{"tf":1.0}}}}}}}}},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":2,"docs":{"71":{"tf":1.0},"9":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"v":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"112":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"112":{"tf":1.0}}},"df":0,"docs":{}},"x":{"df":1,"docs":{"112":{"tf":1.0}}}},"df":2,"docs":{"100":{"tf":1.0},"112":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"93":{"tf":1.0}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":4,"docs":{"112":{"tf":1.4142135623730951},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{},"s":{"df":3,"docs":{"112":{"tf":1.4142135623730951},"113":{"tf":1.0},"214":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"89":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"r":{"df":4,"docs":{"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0}}}}}}}},"o":{"c":{"df":1,"docs":{"64":{"tf":1.0}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"227":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"3":{"tf":1.0},"8":{"tf":1.0}}}}}}}},"df":1,"docs":{"0":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":9,"docs":{"103":{"tf":1.0},"105":{"tf":1.0},"19":{"tf":1.0},"37":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.0},"70":{"tf":1.0},"80":{"tf":1.0},"82":{"tf":1.0}}}}}}},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"72":{"tf":1.0},"73":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.0}}},"’":{"df":0,"docs":{},"t":{"df":5,"docs":{"229":{"tf":1.0},"39":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.4142135623730951},"71":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"167":{"tf":1.0},"179":{"tf":1.0}}}}},"df":0,"docs":{}}},"u":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"x":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"111":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"w":{"df":0,"docs":{},"n":{"df":3,"docs":{"103":{"tf":1.0},"219":{"tf":1.0},"53":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"m":{"df":2,"docs":{"79":{"tf":1.0},"92":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"86":{"tf":1.0}}}}}},"r":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"91":{"tf":1.0}}}}},"df":1,"docs":{"235":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"90":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"df":2,"docs":{"105":{"tf":1.0},"82":{"tf":1.0}},"n":{"df":2,"docs":{"78":{"tf":1.4142135623730951},"91":{"tf":1.0}}},"r":{"df":3,"docs":{"19":{"tf":1.0},"5":{"tf":1.0},"67":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"p":{"df":3,"docs":{"181":{"tf":1.0},"234":{"tf":1.4142135623730951},"81":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"e":{"df":6,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"18":{"tf":1.7320508075688772},"222":{"tf":1.0},"43":{"tf":1.0},"68":{"tf":1.0}}},"m":{"df":0,"docs":{},"p":{"df":9,"docs":{"108":{"tf":1.4142135623730951},"16":{"tf":1.0},"167":{"tf":1.0},"179":{"tf":1.0},"189":{"tf":1.0},"94":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"75":{"tf":1.0},"86":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"179":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":6,"docs":{"172":{"tf":1.0},"18":{"tf":1.4142135623730951},"191":{"tf":1.0},"210":{"tf":1.0},"71":{"tf":1.0},"8":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"m":{"df":11,"docs":{"105":{"tf":1.4142135623730951},"14":{"tf":1.0},"166":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"179":{"tf":1.0},"68":{"tf":1.0},"76":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"94":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"g":{"df":6,"docs":{"107":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"81":{"tf":1.0},"85":{"tf":1.0},"98":{"tf":1.4142135623730951}}}},"a":{"c":{"df":0,"docs":{},"h":{"df":13,"docs":{"106":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"192":{"tf":1.0},"194":{"tf":1.7320508075688772},"195":{"tf":2.23606797749979},"223":{"tf":1.4142135623730951},"52":{"tf":1.0},"78":{"tf":1.0},"91":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"224":{"tf":1.0},"91":{"tf":2.0}},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"174":{"tf":1.0},"188":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"i":{"df":2,"docs":{"5":{"tf":1.0},"82":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"52":{"tf":1.0},"64":{"tf":1.0}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"235":{"tf":1.0}}}}}}}}}},"d":{"df":1,"docs":{"94":{"tf":1.0}},"g":{"df":2,"docs":{"235":{"tf":1.0},"76":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":50,"docs":{"106":{"tf":1.4142135623730951},"147":{"tf":1.4142135623730951},"158":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":1.4142135623730951},"175":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.4142135623730951},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.4142135623730951},"182":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.4142135623730951},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"219":{"tf":1.0},"223":{"tf":1.0},"76":{"tf":1.7320508075688772},"81":{"tf":1.0},"94":{"tf":1.4142135623730951},"98":{"tf":2.0}}}},"df":0,"docs":{}},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"219":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"235":{"tf":1.0},"52":{"tf":1.0},"64":{"tf":1.0},"66":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"p":{"df":2,"docs":{"153":{"tf":1.0},"154":{"tf":1.0}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"169":{"tf":1.0},"181":{"tf":1.0}}}}}}},"f":{"df":5,"docs":{"16":{"tf":1.0},"18":{"tf":1.4142135623730951},"218":{"tf":1.0},"225":{"tf":1.0},"67":{"tf":1.4142135623730951}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":17,"docs":{"105":{"tf":1.0},"106":{"tf":1.0},"108":{"tf":1.0},"147":{"tf":1.0},"198":{"tf":1.0},"224":{"tf":1.0},"235":{"tf":1.0},"75":{"tf":1.7320508075688772},"78":{"tf":1.0},"81":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":1.0},"92":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.7320508075688772},"98":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"193":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"w":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"106":{"tf":1.0}}}}}}}}},"m":{"b":{"df":0,"docs":{},"e":{"d":{"df":3,"docs":{"182":{"tf":1.0},"186":{"tf":1.0},"219":{"tf":1.0}}},"df":0,"docs":{}}},"df":1,"docs":{"98":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"200":{"tf":1.0}}}},"t":{"df":19,"docs":{"139":{"tf":1.0},"140":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":1.0},"18":{"tf":1.0},"181":{"tf":1.0},"195":{"tf":1.0},"207":{"tf":1.0},"214":{"tf":1.0},"236":{"tf":1.4142135623730951},"35":{"tf":1.0},"39":{"tf":1.0},"67":{"tf":1.0},"69":{"tf":1.0},"70":{"tf":1.4142135623730951},"78":{"tf":1.0},"79":{"tf":1.0},"81":{"tf":1.0},"99":{"tf":1.0}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"68":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"i":{"df":5,"docs":{"193":{"tf":1.0},"195":{"tf":1.0},"198":{"tf":1.0},"211":{"tf":1.0},"57":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":3,"docs":{"226":{"tf":1.4142135623730951},"7":{"tf":1.0},"71":{"tf":1.0}}}}}}}}},"d":{"df":0,"docs":{},"k":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"s":{"d":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"226":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":1,"docs":{"226":{"tf":1.0}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"l":{"df":26,"docs":{"103":{"tf":1.0},"104":{"tf":1.0},"138":{"tf":1.0},"14":{"tf":1.0},"147":{"tf":1.0},"166":{"tf":1.0},"175":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"182":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"201":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"40":{"tf":1.0},"70":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.0}}}}},"n":{"a":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"26":{"tf":1.0},"73":{"tf":1.4142135623730951},"78":{"tf":1.0},"79":{"tf":1.0},"93":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":2,"docs":{"61":{"tf":1.0},"69":{"tf":1.0}}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":3,"docs":{"192":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0}}}}},"o":{"d":{"df":6,"docs":{"173":{"tf":1.0},"208":{"tf":1.0},"214":{"tf":1.0},"216":{"tf":1.4142135623730951},"82":{"tf":1.0},"86":{"tf":1.4142135623730951}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"221":{"tf":1.0}}}},"df":0,"docs":{}}}}},"d":{"df":12,"docs":{"159":{"tf":1.0},"168":{"tf":1.0},"180":{"tf":1.0},"183":{"tf":1.0},"185":{"tf":1.0},"187":{"tf":1.0},"208":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"213":{"tf":1.0},"52":{"tf":1.4142135623730951}},"i":{"a":{"df":0,"docs":{},"n":{"df":9,"docs":{"104":{"tf":2.23606797749979},"166":{"tf":1.0},"176":{"tf":1.4142135623730951},"70":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":2.0},"75":{"tf":1.0},"80":{"tf":1.4142135623730951},"81":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"81":{"tf":1.0}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"52":{"tf":1.0},"66":{"tf":1.0}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"64":{"tf":1.0}}}}}}},"j":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"65":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":3,"docs":{"64":{"tf":1.0},"65":{"tf":1.0},"74":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"223":{"tf":1.4142135623730951},"63":{"tf":1.0},"68":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"189":{"tf":1.0}}}},"i":{"df":0,"docs":{},"r":{"df":2,"docs":{"108":{"tf":1.0},"219":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"df":8,"docs":{"101":{"tf":1.0},"189":{"tf":1.4142135623730951},"198":{"tf":1.0},"207":{"tf":1.0},"235":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":2.0},"99":{"tf":1.7320508075688772}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}}}},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"102":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"97":{"tf":1.0},"99":{"tf":1.0}}}}}},"v":{"df":1,"docs":{"226":{"tf":1.0}},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":10,"docs":{"100":{"tf":1.0},"220":{"tf":1.7320508075688772},"225":{"tf":1.0},"226":{"tf":1.4142135623730951},"53":{"tf":1.0},"55":{"tf":1.0},"73":{"tf":1.0},"75":{"tf":1.0},"94":{"tf":1.4142135623730951},"95":{"tf":1.0}}}}}}}},"p":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"149":{"tf":1.0}}}},"df":0,"docs":{}}},"q":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"127":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"127":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"127":{"tf":1.0},"79":{"tf":1.0}},"u":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"127":{"tf":1.0},"135":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":11,"docs":{"133":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"219":{"tf":1.0},"4":{"tf":1.0},"90":{"tf":1.0},"94":{"tf":1.0}}}},"df":0,"docs":{}}}}},"r":{"c":{"1":{"1":{"5":{"5":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"0":{"df":2,"docs":{"89":{"tf":1.0},"90":{"tf":1.0}}},"df":0,"docs":{}},"7":{"2":{"1":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"r":{"(":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"(":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"(":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"215":{"tf":1.0}}}}}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"(":{"1":{"2":{"df":1,"docs":{"215":{"tf":1.0}}},"df":0,"docs":{}},"<":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"215":{"tf":1.0}}}}}}}}},"df":0,"docs":{}},"df":2,"docs":{"100":{"tf":1.0},"215":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}}}}}},"df":13,"docs":{"208":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.7320508075688772},"223":{"tf":1.0},"39":{"tf":1.0},"40":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"75":{"tf":1.0},"85":{"tf":1.0},"86":{"tf":1.4142135623730951},"87":{"tf":1.0},"93":{"tf":1.0}}}}}},"s":{"c":{"a":{"df":0,"docs":{},"p":{"df":3,"docs":{"75":{"tf":1.0},"80":{"tf":1.0},"94":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":2,"docs":{"189":{"tf":1.0},"91":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"t":{"c":{"df":4,"docs":{"101":{"tf":1.4142135623730951},"190":{"tf":1.0},"75":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"/":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"d":{"/":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"/":{":":{"$":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"221":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":14,"docs":{"0":{"tf":1.0},"103":{"tf":1.0},"11":{"tf":1.0},"221":{"tf":1.7320508075688772},"222":{"tf":1.4142135623730951},"223":{"tf":2.23606797749979},"235":{"tf":1.0},"34":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"49":{"tf":1.0},"6":{"tf":1.0},"66":{"tf":1.4142135623730951},"8":{"tf":1.0}}}}}}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":6,"docs":{"138":{"tf":1.0},"146":{"tf":1.4142135623730951},"188":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"195":{"tf":1.7320508075688772}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":5,"docs":{"219":{"tf":1.0},"235":{"tf":1.0},"52":{"tf":1.0},"65":{"tf":1.0},"82":{"tf":1.4142135623730951}},"t":{"df":3,"docs":{"200":{"tf":1.0},"207":{"tf":1.0},"89":{"tf":1.0}},"u":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"105":{"tf":1.0}}}}}}},"m":{".":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":67,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"103":{"tf":1.0},"104":{"tf":1.4142135623730951},"105":{"tf":1.0},"109":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"134":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"14":{"tf":1.4142135623730951},"147":{"tf":1.0},"156":{"tf":1.0},"166":{"tf":1.4142135623730951},"174":{"tf":1.0},"175":{"tf":1.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.0},"178":{"tf":1.4142135623730951},"180":{"tf":1.0},"182":{"tf":1.4142135623730951},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.7320508075688772},"186":{"tf":1.0},"187":{"tf":1.0},"190":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"219":{"tf":2.23606797749979},"221":{"tf":1.0},"222":{"tf":1.0},"223":{"tf":2.6457513110645907},"229":{"tf":1.4142135623730951},"233":{"tf":1.0},"33":{"tf":1.4142135623730951},"34":{"tf":1.4142135623730951},"35":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.4142135623730951},"43":{"tf":1.4142135623730951},"48":{"tf":1.0},"51":{"tf":1.0},"52":{"tf":1.7320508075688772},"70":{"tf":2.0},"72":{"tf":1.4142135623730951},"73":{"tf":1.0},"74":{"tf":2.0},"78":{"tf":1.0},"80":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.0}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":1,"docs":{"90":{"tf":1.0}}}}}},"x":{"a":{"c":{"df":0,"docs":{},"t":{"df":5,"docs":{"18":{"tf":1.0},"218":{"tf":1.0},"224":{"tf":1.0},"75":{"tf":1.7320508075688772},"95":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":4,"docs":{"105":{"tf":1.0},"176":{"tf":1.0},"223":{"tf":1.0},"68":{"tf":1.0}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":120,"docs":{"0":{"tf":1.0},"106":{"tf":1.0},"107":{"tf":1.0},"108":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"18":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"223":{"tf":1.4142135623730951},"224":{"tf":1.0},"226":{"tf":1.0},"227":{"tf":1.0},"5":{"tf":1.0},"51":{"tf":1.0},"52":{"tf":1.4142135623730951},"57":{"tf":1.0},"61":{"tf":1.0},"63":{"tf":1.0},"68":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":2,"docs":{"112":{"tf":1.0},"92":{"tf":1.0}},"l":{"df":1,"docs":{"52":{"tf":1.0}}},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"63":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"169":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":26,"docs":{"12":{"tf":1.7320508075688772},"13":{"tf":1.0},"14":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"15":{"tf":1.0},"157":{"tf":1.0},"162":{"tf":1.0},"165":{"tf":1.0},"183":{"tf":1.4142135623730951},"193":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"219":{"tf":1.4142135623730951},"223":{"tf":2.449489742783178},"224":{"tf":1.0},"225":{"tf":1.0},"226":{"tf":1.0},"227":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951},"55":{"tf":1.4142135623730951},"57":{"tf":1.0},"91":{"tf":1.0}}}}},"df":0,"docs":{}},"h":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":7,"docs":{"108":{"tf":1.0},"11":{"tf":1.0},"164":{"tf":1.0},"184":{"tf":1.0},"213":{"tf":1.0},"233":{"tf":1.0},"93":{"tf":1.0}}}},"t":{"df":4,"docs":{"195":{"tf":1.7320508075688772},"196":{"tf":1.0},"198":{"tf":1.4142135623730951},"87":{"tf":1.0}}}},"p":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"116":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"116":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"116":{"tf":1.0}},"e":{"c":{"df":0,"docs":{},"t":{"df":5,"docs":{"108":{"tf":1.0},"223":{"tf":1.4142135623730951},"43":{"tf":1.4142135623730951},"52":{"tf":1.0},"64":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":4,"docs":{"116":{"tf":1.0},"219":{"tf":1.7320508075688772},"52":{"tf":1.0},"78":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"72":{"tf":1.0},"73":{"tf":1.0}}}}}}}}},"l":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":5,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"221":{"tf":1.0},"64":{"tf":1.0},"77":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":5,"docs":{"18":{"tf":1.0},"192":{"tf":1.0},"195":{"tf":1.0},"76":{"tf":1.4142135623730951},"79":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.0}}}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"78":{"tf":1.0}}}},"r":{"df":1,"docs":{"22":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"116":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":2,"docs":{"116":{"tf":1.4142135623730951},"14":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"221":{"tf":1.0},"226":{"tf":1.4142135623730951}}}},"s":{"df":5,"docs":{"12":{"tf":1.0},"19":{"tf":1.0},"220":{"tf":1.0},"75":{"tf":1.4142135623730951},"81":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":19,"docs":{"100":{"tf":1.4142135623730951},"106":{"tf":2.23606797749979},"107":{"tf":1.0},"108":{"tf":1.0},"146":{"tf":1.4142135623730951},"170":{"tf":1.0},"172":{"tf":1.0},"175":{"tf":1.0},"179":{"tf":1.0},"188":{"tf":1.4142135623730951},"189":{"tf":2.449489742783178},"190":{"tf":2.6457513110645907},"195":{"tf":1.4142135623730951},"64":{"tf":1.7320508075688772},"75":{"tf":1.0},"76":{"tf":1.4142135623730951},"95":{"tf":1.0},"97":{"tf":1.4142135623730951},"98":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"144":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"b":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"165":{"tf":1.0}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":1,"docs":{"153":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":22,"docs":{"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"137":{"tf":1.0}}}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"b":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":1,"docs":{"154":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"155":{"tf":1.0}}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"156":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"141":{"tf":1.0},"174":{"tf":1.0},"190":{"tf":1.0}},"l":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"159":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":1,"docs":{"160":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"142":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"145":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"o":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":1,"docs":{"162":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"b":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"148":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"170":{"tf":1.0}}}}}}}},"s":{"df":1,"docs":{"171":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"151":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"164":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":1,"docs":{"163":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"g":{"a":{"df":1,"docs":{"146":{"tf":1.0}},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"152":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"158":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"k":{"df":0,"docs":{},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"df":1,"docs":{"138":{"tf":1.0}},"p":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"139":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":1,"docs":{"140":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"173":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"107":{"tf":1.0}}}}}},"o":{"a":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"172":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"m":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"169":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"166":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":1,"docs":{"147":{"tf":1.0}}}},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"b":{"df":1,"docs":{"150":{"tf":1.0}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"143":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"161":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"b":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"157":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":2,"docs":{"129":{"tf":1.0},"137":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"167":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"130":{"tf":1.0},"131":{"tf":1.0}}}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":1,"docs":{"149":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"168":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"135":{"tf":1.0}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":3,"docs":{"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0}}}}},"df":0,"docs":{}}},"v":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"108":{"tf":1.0}}}},"df":0,"docs":{}},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"136":{"tf":1.0}}},"df":0,"docs":{}}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"’":{"df":1,"docs":{"189":{"tf":1.0}}}}}}}}}}},"t":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":3,"docs":{"100":{"tf":1.0},"184":{"tf":1.0},"48":{"tf":1.0}}},"y":{"(":{"$":{"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"184":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"184":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"(":{"$":{"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"164":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"164":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"164":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":2,"docs":{"100":{"tf":1.0},"163":{"tf":1.0}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"(":{"$":{"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"163":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"163":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":5,"docs":{"129":{"tf":1.7320508075688772},"137":{"tf":1.4142135623730951},"176":{"tf":1.0},"81":{"tf":1.0},"93":{"tf":1.4142135623730951}}},"df":0,"docs":{},"s":{"df":1,"docs":{"129":{"tf":1.0}}}},"r":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"l":{"c":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"161":{"tf":1.0},"78":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":12,"docs":{"100":{"tf":1.0},"143":{"tf":1.0},"173":{"tf":1.0},"175":{"tf":1.0},"18":{"tf":1.4142135623730951},"182":{"tf":1.0},"184":{"tf":1.0},"190":{"tf":1.0},"200":{"tf":1.7320508075688772},"201":{"tf":1.0},"204":{"tf":1.4142135623730951},"80":{"tf":1.4142135623730951}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"128":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"f":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"5":{"tf":1.0}}},"t":{"df":3,"docs":{"18":{"tf":1.0},"219":{"tf":1.0},"65":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"131":{"tf":1.4142135623730951}},"i":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":3,"docs":{"18":{"tf":1.4142135623730951},"233":{"tf":1.0},"65":{"tf":1.0}},"u":{"df":0,"docs":{},"r":{"df":5,"docs":{"205":{"tf":1.4142135623730951},"206":{"tf":1.0},"212":{"tf":1.0},"214":{"tf":1.0},"82":{"tf":1.0}}}}}},"l":{"df":0,"docs":{},"l":{"b":{"a":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"105":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":8,"docs":{"122":{"tf":1.0},"174":{"tf":1.0},"179":{"tf":1.0},"194":{"tf":1.0},"199":{"tf":1.0},"219":{"tf":1.0},"43":{"tf":1.0},"93":{"tf":1.0}}},"s":{"df":1,"docs":{"80":{"tf":1.0}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"43":{"tf":1.0},"79":{"tf":1.0}}}}}},"q":{"df":1,"docs":{"228":{"tf":1.0}}},"r":{"df":2,"docs":{"219":{"tf":1.0},"52":{"tf":1.0}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"219":{"tf":1.0},"4":{"tf":1.0}}}}}}},"df":1,"docs":{"57":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"66":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":6,"docs":{"18":{"tf":1.0},"221":{"tf":1.0},"230":{"tf":1.0},"232":{"tf":1.0},"236":{"tf":1.0},"4":{"tf":1.0}}}}}},"b":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"91":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":2,"docs":{"153":{"tf":1.0},"154":{"tf":1.0}}},"w":{"df":4,"docs":{"11":{"tf":1.0},"24":{"tf":1.0},"40":{"tf":1.0},"64":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"75":{"tf":1.0},"79":{"tf":1.0}}}}}},"i":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"a":{"c":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"89":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"d":{"df":25,"docs":{"107":{"tf":1.0},"135":{"tf":1.4142135623730951},"136":{"tf":1.4142135623730951},"137":{"tf":1.4142135623730951},"166":{"tf":1.0},"167":{"tf":1.4142135623730951},"170":{"tf":1.4142135623730951},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"179":{"tf":1.4142135623730951},"191":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"207":{"tf":1.0},"214":{"tf":1.4142135623730951},"215":{"tf":1.7320508075688772},"216":{"tf":1.4142135623730951},"32":{"tf":2.0},"33":{"tf":1.4142135623730951},"98":{"tf":2.0},"99":{"tf":1.0}}},"df":0,"docs":{}}},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"90":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":8,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"32":{"tf":2.8284271247461903},"33":{"tf":1.4142135623730951},"57":{"tf":1.0},"62":{"tf":1.4142135623730951},"67":{"tf":1.0},"90":{"tf":1.0}}},"l":{"df":4,"docs":{"116":{"tf":1.0},"121":{"tf":1.0},"133":{"tf":1.0},"136":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"55":{"tf":1.0}}}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"195":{"tf":1.0},"223":{"tf":1.0},"226":{"tf":1.4142135623730951},"67":{"tf":1.0}}}},"d":{"df":4,"docs":{"1":{"tf":1.0},"232":{"tf":1.0},"7":{"tf":1.0},"93":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"55":{"tf":1.0},"61":{"tf":1.0},"68":{"tf":1.0}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}},"t":{"df":1,"docs":{"14":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"94":{"tf":1.0}}},"s":{"df":0,"docs":{},"t":{"df":9,"docs":{"106":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"139":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"236":{"tf":1.0},"32":{"tf":1.0},"91":{"tf":1.0}}}}},"t":{"df":7,"docs":{"117":{"tf":1.0},"134":{"tf":1.0},"166":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.4142135623730951},"81":{"tf":1.0}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"182":{"tf":1.4142135623730951}}}},"x":{"df":7,"docs":{"0":{"tf":1.4142135623730951},"221":{"tf":1.0},"40":{"tf":1.4142135623730951},"63":{"tf":1.0},"65":{"tf":1.0},"82":{"tf":2.0},"93":{"tf":1.0}}}},"l":{"a":{"df":0,"docs":{},"g":{"df":10,"docs":{"18":{"tf":1.0},"198":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"57":{"tf":2.0},"70":{"tf":1.0},"73":{"tf":1.0},"94":{"tf":1.0}}},"t":{"df":1,"docs":{"74":{"tf":1.0}}},"w":{"df":1,"docs":{"219":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":1,"docs":{"94":{"tf":1.0}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}}},"df":2,"docs":{"89":{"tf":1.0},"90":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"w":{"df":13,"docs":{"100":{"tf":1.0},"189":{"tf":1.4142135623730951},"192":{"tf":1.7320508075688772},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"76":{"tf":2.0},"93":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}}}}},"m":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"f":{"df":1,"docs":{"81":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"75":{"tf":1.0}}}}}}},"df":7,"docs":{"166":{"tf":1.0},"176":{"tf":1.0},"216":{"tf":1.0},"81":{"tf":2.0},"82":{"tf":2.8284271247461903},"92":{"tf":1.0},"95":{"tf":1.0}}}},"o":{"c":{"df":0,"docs":{},"u":{"df":1,"docs":{"236":{"tf":1.0}},"s":{"df":1,"docs":{"91":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"d":{"df":3,"docs":{"75":{"tf":1.7320508075688772},"83":{"tf":1.4142135623730951},"95":{"tf":1.4142135623730951}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":25,"docs":{"10":{"tf":1.0},"12":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"169":{"tf":1.0},"178":{"tf":1.0},"181":{"tf":1.0},"195":{"tf":1.0},"222":{"tf":1.0},"223":{"tf":1.0},"224":{"tf":1.0},"36":{"tf":1.0},"52":{"tf":1.0},"6":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"67":{"tf":1.4142135623730951},"68":{"tf":1.0},"7":{"tf":1.0},"75":{"tf":1.0},"84":{"tf":1.4142135623730951},"93":{"tf":1.0},"98":{"tf":1.4142135623730951},"99":{"tf":1.4142135623730951}}}}}},"r":{"c":{"df":1,"docs":{"63":{"tf":1.0}}},"df":0,"docs":{},"k":{"df":2,"docs":{"21":{"tf":1.7320508075688772},"23":{"tf":1.0}}},"m":{"a":{"df":0,"docs":{},"t":{"df":4,"docs":{"18":{"tf":1.0},"223":{"tf":1.0},"224":{"tf":1.0},"98":{"tf":1.0}},"t":{"df":1,"docs":{"64":{"tf":1.0}}}}},"df":11,"docs":{"101":{"tf":1.0},"193":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"195":{"tf":1.4142135623730951},"196":{"tf":1.0},"197":{"tf":1.0},"208":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"76":{"tf":1.0},"98":{"tf":1.0}},"e":{"d":{"df":3,"docs":{"75":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.0}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.0}}}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":15,"docs":{"117":{"tf":1.0},"122":{"tf":1.0},"138":{"tf":1.4142135623730951},"155":{"tf":1.0},"156":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"201":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.4142135623730951},"95":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"n":{"d":{"df":6,"docs":{"18":{"tf":1.0},"218":{"tf":1.0},"219":{"tf":1.0},"3":{"tf":1.0},"62":{"tf":1.0},"82":{"tf":1.0}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"r":{"df":5,"docs":{"200":{"tf":1.0},"207":{"tf":1.0},"215":{"tf":1.0},"78":{"tf":1.4142135623730951},"80":{"tf":1.0}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"219":{"tf":1.0}}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":14,"docs":{"141":{"tf":1.0},"144":{"tf":1.0},"157":{"tf":1.0},"165":{"tf":1.0},"208":{"tf":1.0},"209":{"tf":1.4142135623730951},"210":{"tf":1.4142135623730951},"211":{"tf":1.4142135623730951},"212":{"tf":1.0},"213":{"tf":1.4142135623730951},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"57":{"tf":1.4142135623730951}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"66":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":4,"docs":{"105":{"tf":1.0},"166":{"tf":1.4142135623730951},"176":{"tf":1.4142135623730951},"177":{"tf":1.0}}}}}},"df":4,"docs":{"105":{"tf":1.7320508075688772},"74":{"tf":1.0},"75":{"tf":1.0},"81":{"tf":1.4142135623730951}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"106":{"tf":1.0}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":3,"docs":{"105":{"tf":1.0},"166":{"tf":1.4142135623730951},"76":{"tf":1.0}}}}}}}}}}}}}},"s":{"df":0,"docs":{},"h":{"df":2,"docs":{"189":{"tf":1.4142135623730951},"90":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"y":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":1,"docs":{"75":{"tf":1.0}}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":5,"docs":{"225":{"tf":1.0},"226":{"tf":1.0},"5":{"tf":1.0},"6":{"tf":1.0},"66":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":8,"docs":{"103":{"tf":1.0},"129":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"33":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.4142135623730951},"82":{"tf":1.4142135623730951}},"i":{"df":4,"docs":{"218":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.4142135623730951}}}}},"n":{"c":{"_":{"<":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"174":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"m":{"df":3,"docs":{"100":{"tf":1.0},"174":{"tf":1.0},"99":{"tf":1.0}},"e":{">":{"(":{"[":{"$":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"_":{"0":{"df":1,"docs":{"174":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":1,"docs":{"78":{"tf":1.0}}}}},"df":26,"docs":{"100":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.0},"138":{"tf":1.0},"174":{"tf":2.0},"189":{"tf":1.0},"190":{"tf":1.0},"198":{"tf":2.23606797749979},"236":{"tf":1.0},"39":{"tf":1.7320508075688772},"40":{"tf":1.0},"51":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951},"71":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":2.0},"78":{"tf":1.4142135623730951},"80":{"tf":1.0},"84":{"tf":1.0},"85":{"tf":1.4142135623730951},"86":{"tf":1.0},"87":{"tf":1.4142135623730951},"91":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":2.0},"97":{"tf":1.0}},"i":{"d":{"df":1,"docs":{"174":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{":":{":":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"z":{"df":1,"docs":{"134":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"78":{"tf":1.0}}}}}}}},"’":{"df":2,"docs":{"174":{"tf":1.0},"198":{"tf":1.0}}}}}}}},"d":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"74":{"tf":1.0}}}}}}},"df":1,"docs":{"65":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"134":{"tf":1.0},"223":{"tf":1.0},"224":{"tf":1.0},"233":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"71":{"tf":1.0}}}}}}}}}},"s":{"df":0,"docs":{},"e":{"df":5,"docs":{"169":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"75":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0}}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":8,"docs":{"139":{"tf":1.0},"140":{"tf":1.0},"169":{"tf":1.0},"179":{"tf":1.0},"75":{"tf":1.0},"83":{"tf":1.4142135623730951},"91":{"tf":1.0},"95":{"tf":1.4142135623730951}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"43":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":4,"docs":{"18":{"tf":1.0},"233":{"tf":1.0},"65":{"tf":1.0},"93":{"tf":1.0}}}}},"z":{"df":0,"docs":{},"z":{"df":0,"docs":{},"i":{"df":4,"docs":{"75":{"tf":1.7320508075688772},"85":{"tf":1.4142135623730951},"93":{"tf":1.0},"95":{"tf":1.0}}}}}}},"g":{"a":{"df":21,"docs":{"0":{"tf":1.7320508075688772},"100":{"tf":1.0},"116":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.4142135623730951},"146":{"tf":2.23606797749979},"147":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"158":{"tf":1.0},"180":{"tf":1.0},"201":{"tf":1.4142135623730951},"212":{"tf":1.0},"37":{"tf":1.7320508075688772},"40":{"tf":1.0},"43":{"tf":1.4142135623730951},"70":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.0},"82":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"219":{"tf":1.0}}}},"p":{"df":1,"docs":{"72":{"tf":1.0}}},"s":{"_":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"100":{"tf":1.0},"152":{"tf":1.7320508075688772}}}}}}},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"100":{"tf":1.0},"158":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"e":{"df":3,"docs":{"73":{"tf":1.0},"81":{"tf":1.7320508075688772},"94":{"tf":1.0}}}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"235":{"tf":1.0}}}}}},"c":{"d":{"df":2,"docs":{"75":{"tf":1.0},"80":{"tf":1.0}}},"df":0,"docs":{}},"df":2,"docs":{"17":{"tf":1.0},"26":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":23,"docs":{"138":{"tf":1.0},"17":{"tf":1.0},"2":{"tf":1.0},"219":{"tf":1.0},"221":{"tf":1.0},"232":{"tf":1.0},"33":{"tf":2.0},"40":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.0},"6":{"tf":1.0},"61":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":2.0},"66":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.4142135623730951},"78":{"tf":1.0},"82":{"tf":1.0},"85":{"tf":1.0},"87":{"tf":1.0},"90":{"tf":1.0},"94":{"tf":1.0}}}}},"t":{"df":5,"docs":{"1":{"tf":1.0},"52":{"tf":1.0},"58":{"tf":1.0},"60":{"tf":1.0},"91":{"tf":1.0}}}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"221":{"tf":1.0}},"h":{"df":0,"docs":{},"u":{"b":{"df":1,"docs":{"63":{"tf":1.0}}},"df":0,"docs":{}}}},"v":{"df":0,"docs":{},"e":{"df":4,"docs":{"106":{"tf":1.0},"236":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.0}},"n":{"df":13,"docs":{"155":{"tf":1.0},"156":{"tf":1.0},"159":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"205":{"tf":1.0},"236":{"tf":1.0},"65":{"tf":1.0},"68":{"tf":1.0},"99":{"tf":1.0}}}}}},"l":{"a":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"59":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":2,"docs":{"221":{"tf":1.4142135623730951},"223":{"tf":1.4142135623730951}},"e":{"df":2,"docs":{"221":{"tf":1.0},"82":{"tf":1.4142135623730951}}},"o":{"d":{"df":2,"docs":{"61":{"tf":1.0},"66":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"55":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"124":{"tf":1.0},"126":{"tf":1.0},"135":{"tf":1.0}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"61":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":2,"docs":{"85":{"tf":1.0},"97":{"tf":1.0}}}},"w":{"df":1,"docs":{"14":{"tf":1.0}}}}},"t":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"124":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"124":{"tf":1.0}}},"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"75":{"tf":1.0},"79":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"124":{"tf":1.0},"79":{"tf":1.0}}},"u":{"a":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":2,"docs":{"219":{"tf":1.0},"98":{"tf":1.0}}}}}},"d":{"_":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":1,"docs":{"75":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":4,"docs":{"180":{"tf":1.0},"75":{"tf":1.7320508075688772},"79":{"tf":2.6457513110645907},"95":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"d":{"df":7,"docs":{"1":{"tf":1.4142135623730951},"222":{"tf":1.0},"4":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.0},"64":{"tf":1.0},"93":{"tf":1.0}}},"df":0,"docs":{}}}},"h":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"219":{"tf":1.0}}},"l":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}}},"n":{"d":{"df":6,"docs":{"106":{"tf":1.0},"108":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.4142135623730951},"219":{"tf":1.0},"74":{"tf":1.0}},"i":{"df":1,"docs":{"53":{"tf":1.0}}},"l":{"df":4,"docs":{"176":{"tf":1.0},"80":{"tf":1.0},"87":{"tf":1.0},"92":{"tf":1.0}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"67":{"tf":1.0}}}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"91":{"tf":1.0}}}},"h":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"219":{"tf":1.0}}}},"df":0,"docs":{}}},"df":1,"docs":{"94":{"tf":1.0}}},"s":{"_":{"d":{"df":0,"docs":{},"y":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"c":{"_":{"a":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"82":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{},"h":{"df":21,"docs":{"0":{"tf":1.0},"100":{"tf":1.0},"138":{"tf":2.0},"139":{"tf":1.7320508075688772},"140":{"tf":1.4142135623730951},"155":{"tf":1.0},"156":{"tf":1.0},"164":{"tf":1.0},"169":{"tf":1.4142135623730951},"18":{"tf":1.0},"181":{"tf":1.4142135623730951},"190":{"tf":1.0},"206":{"tf":1.0},"38":{"tf":1.0},"43":{"tf":2.0},"44":{"tf":1.0},"45":{"tf":1.0},"68":{"tf":1.0},"75":{"tf":1.4142135623730951},"83":{"tf":1.4142135623730951},"84":{"tf":1.4142135623730951}},"m":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":2,"docs":{"2":{"tf":1.0},"98":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"195":{"tf":1.0}}}}},"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":1,"docs":{"75":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":3,"docs":{"14":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0}}}}}},"df":13,"docs":{"0":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.4142135623730951},"14":{"tf":2.449489742783178},"27":{"tf":1.4142135623730951},"40":{"tf":1.0},"70":{"tf":2.0},"75":{"tf":1.0},"76":{"tf":1.0},"80":{"tf":1.4142135623730951},"81":{"tf":1.0},"94":{"tf":1.0},"95":{"tf":1.0}}},"v":{"df":0,"docs":{},"i":{"df":1,"docs":{"66":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":1,"docs":{"0":{"tf":1.0}}}},"p":{"df":4,"docs":{"1":{"tf":1.0},"11":{"tf":1.7320508075688772},"54":{"tf":1.4142135623730951},"58":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":7,"docs":{"214":{"tf":1.0},"223":{"tf":1.0},"80":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.4142135623730951},"95":{"tf":1.4142135623730951}}}}}},"n":{"c":{"df":1,"docs":{"70":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"e":{"df":7,"docs":{"103":{"tf":1.0},"199":{"tf":1.0},"218":{"tf":1.0},"232":{"tf":1.0},"51":{"tf":1.0},"65":{"tf":1.0},"98":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"75":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.0}}}}}}},"x":{"df":3,"docs":{"214":{"tf":1.0},"216":{"tf":1.0},"99":{"tf":1.4142135623730951}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":9,"docs":{"137":{"tf":1.0},"139":{"tf":1.0},"223":{"tf":1.0},"235":{"tf":1.0},"4":{"tf":1.0},"66":{"tf":1.0},"74":{"tf":1.0},"76":{"tf":1.0},"82":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"147":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":4,"docs":{"222":{"tf":1.0},"34":{"tf":1.0},"64":{"tf":1.0},"92":{"tf":1.0}}}}}}}}},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"169":{"tf":1.0},"178":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"69":{"tf":1.0}},"i":{"df":2,"docs":{"147":{"tf":1.0},"91":{"tf":1.0}}}}}}},"t":{"df":1,"docs":{"105":{"tf":1.0}}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"138":{"tf":1.0},"95":{"tf":1.0}}}}},"l":{"d":{"df":4,"docs":{"111":{"tf":1.0},"121":{"tf":1.0},"188":{"tf":1.0},"81":{"tf":1.0}}},"df":0,"docs":{}},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"65":{"tf":1.0}}}},"o":{"d":{"df":1,"docs":{"67":{"tf":1.0}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"220":{"tf":1.4142135623730951},"226":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{":":{"/":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"u":{"b":{".":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":1,"docs":{"221":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"u":{"b":{"df":1,"docs":{"220":{"tf":1.0}}},"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"df":2,"docs":{"65":{"tf":1.0},"95":{"tf":1.0}}}},"df":0,"docs":{}},"n":{"d":{"df":0,"docs":{},"r":{"df":1,"docs":{"87":{"tf":1.0}}}},"df":0,"docs":{}}}},"i":{".":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}},"1":{"2":{"8":{"df":5,"docs":{"103":{"tf":1.4142135623730951},"111":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0}}},"df":0,"docs":{}},"6":{"0":{"df":23,"docs":{"103":{"tf":1.4142135623730951},"111":{"tf":1.0},"141":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"148":{"tf":1.0},"163":{"tf":1.4142135623730951},"164":{"tf":1.4142135623730951},"165":{"tf":1.4142135623730951},"169":{"tf":1.4142135623730951},"173":{"tf":1.0},"181":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"191":{"tf":1.0},"201":{"tf":1.4142135623730951},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"213":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.0}}},"df":0,"docs":{}},"df":18,"docs":{"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.4142135623730951},"107":{"tf":1.0},"121":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"132":{"tf":1.0},"193":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0}}},"2":{"5":{"6":{"df":86,"docs":{"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.7320508075688772},"107":{"tf":1.0},"109":{"tf":1.4142135623730951},"110":{"tf":1.7320508075688772},"111":{"tf":1.7320508075688772},"112":{"tf":1.4142135623730951},"113":{"tf":1.4142135623730951},"114":{"tf":1.4142135623730951},"115":{"tf":1.4142135623730951},"116":{"tf":1.7320508075688772},"117":{"tf":1.4142135623730951},"118":{"tf":1.4142135623730951},"119":{"tf":1.4142135623730951},"120":{"tf":1.7320508075688772},"121":{"tf":1.4142135623730951},"122":{"tf":1.4142135623730951},"123":{"tf":1.4142135623730951},"124":{"tf":1.4142135623730951},"125":{"tf":1.4142135623730951},"126":{"tf":1.4142135623730951},"127":{"tf":1.4142135623730951},"128":{"tf":1.4142135623730951},"129":{"tf":1.7320508075688772},"130":{"tf":2.0},"131":{"tf":2.0},"132":{"tf":1.0},"133":{"tf":1.4142135623730951},"134":{"tf":1.4142135623730951},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.7320508075688772},"139":{"tf":1.7320508075688772},"140":{"tf":1.4142135623730951},"142":{"tf":1.0},"145":{"tf":1.0},"151":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.4142135623730951},"156":{"tf":1.4142135623730951},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.4142135623730951},"163":{"tf":1.0},"164":{"tf":1.4142135623730951},"165":{"tf":1.4142135623730951},"166":{"tf":1.4142135623730951},"167":{"tf":1.4142135623730951},"168":{"tf":1.4142135623730951},"169":{"tf":1.7320508075688772},"170":{"tf":1.0},"172":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"178":{"tf":1.7320508075688772},"179":{"tf":1.4142135623730951},"180":{"tf":1.4142135623730951},"181":{"tf":1.7320508075688772},"183":{"tf":1.7320508075688772},"184":{"tf":2.0},"185":{"tf":1.7320508075688772},"186":{"tf":1.7320508075688772},"187":{"tf":1.7320508075688772},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"201":{"tf":2.8284271247461903},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":2.0},"206":{"tf":1.4142135623730951},"207":{"tf":1.4142135623730951},"209":{"tf":1.4142135623730951},"210":{"tf":1.4142135623730951},"213":{"tf":1.0},"76":{"tf":1.4142135623730951},"78":{"tf":1.4142135623730951},"82":{"tf":1.0},"93":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"3":{"2":{"df":7,"docs":{"103":{"tf":1.4142135623730951},"166":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0},"82":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{}},"6":{"4":{"df":22,"docs":{"103":{"tf":1.7320508075688772},"107":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.4142135623730951},"146":{"tf":1.0},"147":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"152":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"166":{"tf":1.0},"171":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0}}},"5":{"df":1,"docs":{"78":{"tf":1.0}}},"df":0,"docs":{}},"8":{"df":9,"docs":{"102":{"tf":1.0},"103":{"tf":1.4142135623730951},"117":{"tf":1.0},"128":{"tf":1.0},"136":{"tf":1.0},"177":{"tf":1.7320508075688772},"75":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0}}},"d":{"df":7,"docs":{"170":{"tf":1.4142135623730951},"171":{"tf":1.0},"189":{"tf":1.7320508075688772},"195":{"tf":1.4142135623730951},"23":{"tf":1.4142135623730951},"33":{"tf":1.0},"99":{"tf":1.4142135623730951}},"e":{"a":{"df":1,"docs":{"52":{"tf":1.0}},"l":{"df":1,"docs":{"219":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"177":{"tf":1.0},"75":{"tf":1.0},"85":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":11,"docs":{"145":{"tf":1.0},"170":{"tf":1.7320508075688772},"171":{"tf":1.7320508075688772},"172":{"tf":1.0},"173":{"tf":1.0},"191":{"tf":1.4142135623730951},"224":{"tf":1.0},"68":{"tf":1.0},"85":{"tf":1.0},"93":{"tf":1.0},"99":{"tf":1.4142135623730951}}}}}}}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":2,"docs":{"117":{"tf":1.0},"139":{"tf":1.0}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":4,"docs":{"0":{"tf":1.0},"177":{"tf":1.0},"219":{"tf":1.4142135623730951},"41":{"tf":1.0}}}}}},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"df":1,"docs":{"141":{"tf":1.0}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"t":{"df":3,"docs":{"172":{"tf":1.4142135623730951},"188":{"tf":1.0},"191":{"tf":1.4142135623730951}}}}},"p":{"a":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"75":{"tf":1.0},"91":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":13,"docs":{"0":{"tf":1.4142135623730951},"219":{"tf":1.0},"221":{"tf":1.7320508075688772},"222":{"tf":1.0},"223":{"tf":1.7320508075688772},"224":{"tf":1.4142135623730951},"4":{"tf":1.0},"52":{"tf":2.449489742783178},"6":{"tf":1.0},"62":{"tf":1.0},"69":{"tf":2.23606797749979},"85":{"tf":1.0},"93":{"tf":1.0}}}}}}},"i":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"193":{"tf":1.0}}}}}}},"df":2,"docs":{"18":{"tf":1.0},"40":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"1":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":4,"docs":{"232":{"tf":1.0},"236":{"tf":1.0},"92":{"tf":1.0},"93":{"tf":1.0}}}}}}},"n":{"a":{"d":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"92":{"tf":1.0}}}}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"u":{"d":{"df":10,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"16":{"tf":1.0},"204":{"tf":1.0},"33":{"tf":1.0},"4":{"tf":1.0},"52":{"tf":1.0},"55":{"tf":1.0},"62":{"tf":1.0},"98":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":3,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":1.0},"233":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"220":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":3,"docs":{"189":{"tf":1.0},"81":{"tf":1.0},"94":{"tf":1.0}}},"df":0,"docs":{}}}},"x":{"df":5,"docs":{"100":{"tf":1.0},"128":{"tf":1.0},"155":{"tf":1.7320508075688772},"207":{"tf":1.4142135623730951},"97":{"tf":1.0}}}},"i":{"c":{"df":1,"docs":{"201":{"tf":1.0}}},"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"u":{"df":1,"docs":{"92":{"tf":1.0}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"219":{"tf":1.0},"52":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":2,"docs":{"219":{"tf":1.0},"52":{"tf":1.0}}}},"df":0,"docs":{}}}}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":13,"docs":{"103":{"tf":1.0},"107":{"tf":1.0},"117":{"tf":1.0},"122":{"tf":1.0},"134":{"tf":1.0},"174":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951},"76":{"tf":1.0},"78":{"tf":1.4142135623730951},"79":{"tf":1.0},"91":{"tf":2.0},"98":{"tf":1.0}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"o":{"df":1,"docs":{"17":{"tf":1.0}},"r":{"df":0,"docs":{},"m":{"df":7,"docs":{"17":{"tf":1.0},"2":{"tf":1.0},"26":{"tf":1.0},"74":{"tf":1.0},"76":{"tf":1.4142135623730951},"80":{"tf":1.0},"98":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"52":{"tf":1.0},"65":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"203":{"tf":1.0},"51":{"tf":1.0}}}}}},"i":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"92":{"tf":1.0}}}}},"df":0,"docs":{}}},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"205":{"tf":1.7320508075688772},"206":{"tf":1.0}},"i":{"a":{"df":0,"docs":{},"l":{"_":{"0":{"df":1,"docs":{"195":{"tf":1.0}}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"195":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":6,"docs":{"143":{"tf":1.0},"220":{"tf":1.0},"30":{"tf":1.0},"51":{"tf":1.4142135623730951},"82":{"tf":1.0},"91":{"tf":1.0}}}}},"k":{"df":0,"docs":{},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"71":{"tf":1.0}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":12,"docs":{"18":{"tf":2.23606797749979},"198":{"tf":1.0},"230":{"tf":1.4142135623730951},"4":{"tf":1.0},"64":{"tf":1.0},"75":{"tf":1.4142135623730951},"80":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.0},"92":{"tf":1.4142135623730951},"93":{"tf":1.0},"95":{"tf":1.0}},"e":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"80":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{},"n":{"df":2,"docs":{"80":{"tf":1.0},"81":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"51":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":2,"docs":{"199":{"tf":1.0},"90":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"196":{"tf":1.0},"197":{"tf":1.0}}}}}}}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"0":{"df":2,"docs":{"193":{"tf":1.0},"194":{"tf":1.0}}},"1":{"df":1,"docs":{"193":{"tf":1.0}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":12,"docs":{"139":{"tf":1.4142135623730951},"18":{"tf":1.4142135623730951},"192":{"tf":1.0},"193":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"195":{"tf":1.0},"22":{"tf":1.0},"24":{"tf":1.0},"75":{"tf":1.0},"83":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"75":{"tf":1.0},"79":{"tf":1.0},"95":{"tf":1.0}}}}},"i":{"d":{"df":11,"docs":{"135":{"tf":1.0},"18":{"tf":1.0},"195":{"tf":1.0},"224":{"tf":1.0},"43":{"tf":1.0},"54":{"tf":1.0},"70":{"tf":1.0},"93":{"tf":1.0},"94":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"55":{"tf":1.0}}}}}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"94":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"76":{"tf":1.0}}}}},"t":{"a":{"df":0,"docs":{},"l":{"df":7,"docs":{"221":{"tf":1.0},"226":{"tf":1.4142135623730951},"54":{"tf":2.23606797749979},"6":{"tf":1.4142135623730951},"61":{"tf":1.0},"7":{"tf":1.0},"8":{"tf":1.4142135623730951}}},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":4,"docs":{"0":{"tf":1.0},"223":{"tf":1.7320508075688772},"43":{"tf":1.0},"56":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":12,"docs":{"0":{"tf":1.4142135623730951},"14":{"tf":1.0},"18":{"tf":1.0},"223":{"tf":1.0},"35":{"tf":1.4142135623730951},"38":{"tf":1.0},"43":{"tf":1.4142135623730951},"53":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"78":{"tf":1.0},"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":9,"docs":{"10":{"tf":1.0},"18":{"tf":1.0},"219":{"tf":1.0},"35":{"tf":1.0},"43":{"tf":1.0},"55":{"tf":1.0},"78":{"tf":1.7320508075688772},"8":{"tf":1.0},"87":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"(":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"102":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"i":{"2":{"5":{"6":{"df":1,"docs":{"107":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":10,"docs":{"102":{"tf":1.0},"103":{"tf":1.4142135623730951},"112":{"tf":1.0},"113":{"tf":1.0},"129":{"tf":1.4142135623730951},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"95":{"tf":1.0},"99":{"tf":1.4142135623730951}},"r":{"df":6,"docs":{"20":{"tf":1.4142135623730951},"221":{"tf":1.7320508075688772},"223":{"tf":2.0},"52":{"tf":1.0},"89":{"tf":1.4142135623730951},"90":{"tf":1.0}}}},"n":{"d":{"df":1,"docs":{"97":{"tf":1.0}}},"df":0,"docs":{},"t":{"df":1,"docs":{"74":{"tf":1.0}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"100":{"tf":1.0},"200":{"tf":1.0},"220":{"tf":1.0},"92":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"f":{"a":{"c":{"df":5,"docs":{"220":{"tf":1.0},"24":{"tf":1.4142135623730951},"52":{"tf":1.0},"69":{"tf":1.0},"71":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}},"m":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}},"df":10,"docs":{"130":{"tf":1.0},"131":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"73":{"tf":1.0},"75":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":8,"docs":{"174":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.4142135623730951},"51":{"tf":1.4142135623730951},"58":{"tf":1.0},"66":{"tf":1.0},"68":{"tf":1.0},"87":{"tf":1.4142135623730951}}},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"219":{"tf":1.4142135623730951}}}},"o":{"c":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"174":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"138":{"tf":1.0}}}}}}},"r":{"a":{"df":1,"docs":{"198":{"tf":1.0}}},"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":6,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"137":{"tf":1.0},"52":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}}}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":5,"docs":{"100":{"tf":1.0},"194":{"tf":1.0},"208":{"tf":1.0},"212":{"tf":2.0},"68":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"81":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"133":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"174":{"tf":1.0}}},"l":{"df":0,"docs":{},"v":{"df":2,"docs":{"18":{"tf":1.0},"65":{"tf":1.4142135623730951}}}}}}},"p":{"df":0,"docs":{},"s":{"c":{"c":{"df":0,"docs":{},"p":{"df":1,"docs":{"81":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{".":{"df":0,"docs":{},"r":{"df":3,"docs":{"95":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}}}},"df":30,"docs":{"101":{"tf":1.0},"146":{"tf":1.4142135623730951},"16":{"tf":1.4142135623730951},"161":{"tf":1.4142135623730951},"166":{"tf":1.4142135623730951},"167":{"tf":1.4142135623730951},"168":{"tf":1.4142135623730951},"169":{"tf":1.0},"174":{"tf":1.0},"180":{"tf":1.0},"214":{"tf":1.0},"50":{"tf":1.7320508075688772},"51":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"69":{"tf":1.0},"72":{"tf":1.7320508075688772},"73":{"tf":1.4142135623730951},"74":{"tf":1.7320508075688772},"75":{"tf":1.7320508075688772},"76":{"tf":1.7320508075688772},"83":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":1.0},"91":{"tf":1.4142135623730951},"92":{"tf":1.0},"94":{"tf":1.7320508075688772},"95":{"tf":2.449489742783178},"96":{"tf":1.4142135623730951},"97":{"tf":1.0}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"33":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"127":{"tf":1.0}}}}}}},"’":{"df":8,"docs":{"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"170":{"tf":1.0},"192":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"207":{"tf":1.0}}}},"s":{"a":{"df":1,"docs":{"219":{"tf":1.0}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":5,"docs":{"0":{"tf":1.0},"105":{"tf":1.0},"18":{"tf":1.0},"219":{"tf":1.0},"222":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"u":{"df":2,"docs":{"63":{"tf":1.0},"81":{"tf":1.0}}}},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"132":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"q":{"(":{"df":0,"docs":{},"v":{"df":2,"docs":{"75":{"tf":1.0},"79":{"tf":1.0}}}},"df":0,"docs":{}}},"v":{"0":{"df":1,"docs":{"132":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"103":{"tf":1.0},"132":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"64":{"tf":1.0}}},"r":{"df":7,"docs":{"195":{"tf":2.23606797749979},"199":{"tf":1.0},"68":{"tf":1.0},"75":{"tf":1.4142135623730951},"78":{"tf":1.0},"91":{"tf":1.4142135623730951},"93":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":10,"docs":{"105":{"tf":1.0},"107":{"tf":1.0},"108":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.0},"63":{"tf":1.0},"71":{"tf":1.0},"98":{"tf":1.0}}}}}},"’":{"d":{"df":1,"docs":{"51":{"tf":1.0}}},"df":6,"docs":{"18":{"tf":1.0},"19":{"tf":1.0},"234":{"tf":1.0},"52":{"tf":1.0},"53":{"tf":1.0},"55":{"tf":1.0}}}}},"j":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"219":{"tf":2.23606797749979},"4":{"tf":1.0}}}},"s":{"df":1,"docs":{"19":{"tf":1.0}},"o":{"df":0,"docs":{},"n":{"df":4,"docs":{"18":{"tf":1.4142135623730951},"24":{"tf":1.4142135623730951},"33":{"tf":1.4142135623730951},"73":{"tf":1.0}}}}},"u":{"d":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":3,"docs":{"192":{"tf":1.0},"195":{"tf":1.0},"97":{"tf":1.0}}}}}},"k":{"b":{"df":1,"docs":{"57":{"tf":1.0}}},"df":2,"docs":{"121":{"tf":1.7320508075688772},"81":{"tf":1.0}},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"138":{"tf":1.0}}}}}}}}},"0":{"df":2,"docs":{"139":{"tf":1.0},"140":{"tf":1.0}}},"df":0,"docs":{},"v":{"0":{"df":2,"docs":{"138":{"tf":1.0},"190":{"tf":1.0}}},"df":0,"docs":{}}},"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"(":{"$":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"0":{"df":1,"docs":{"139":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"84":{"tf":1.0}}}}},"v":{"0":{"df":1,"docs":{"139":{"tf":1.0}}},"df":0,"docs":{}}},"df":6,"docs":{"100":{"tf":1.0},"139":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"75":{"tf":1.0},"95":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":2,"docs":{"100":{"tf":1.0},"140":{"tf":1.0}},"e":{"(":{"$":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"0":{"df":1,"docs":{"140":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"140":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"df":8,"docs":{"100":{"tf":1.0},"138":{"tf":1.0},"38":{"tf":1.0},"75":{"tf":1.7320508075688772},"83":{"tf":1.7320508075688772},"87":{"tf":1.0},"91":{"tf":1.0},"95":{"tf":1.0}},"p":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":2,"docs":{"75":{"tf":1.0},"83":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":2,"docs":{"75":{"tf":1.0},"83":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":10,"docs":{"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"164":{"tf":1.0},"169":{"tf":1.4142135623730951},"179":{"tf":1.0},"181":{"tf":1.0},"75":{"tf":1.0},"87":{"tf":1.0},"95":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":6,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"235":{"tf":1.0},"65":{"tf":1.0},"81":{"tf":1.0}}}},"p":{"df":0,"docs":{},"t":{"df":2,"docs":{"61":{"tf":1.0},"70":{"tf":1.0}}}},"y":{"/":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"104":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":16,"docs":{"103":{"tf":1.0},"139":{"tf":1.0},"167":{"tf":1.4142135623730951},"168":{"tf":1.4142135623730951},"169":{"tf":2.449489742783178},"172":{"tf":1.4142135623730951},"179":{"tf":1.4142135623730951},"180":{"tf":1.4142135623730951},"181":{"tf":2.6457513110645907},"191":{"tf":1.7320508075688772},"223":{"tf":1.0},"32":{"tf":1.7320508075688772},"76":{"tf":1.0},"77":{"tf":1.0},"84":{"tf":1.0},"99":{"tf":1.0}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":3,"docs":{"198":{"tf":1.0},"43":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{}}}}}},"i":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"105":{"tf":1.0},"200":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"o":{"b":{"df":1,"docs":{"94":{"tf":1.0}}},"df":0,"docs":{},"w":{"df":4,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"52":{"tf":1.0},"98":{"tf":1.0}},"l":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"g":{"df":2,"docs":{"72":{"tf":1.0},"73":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":7,"docs":{"121":{"tf":1.0},"137":{"tf":1.0},"18":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"86":{"tf":1.0},"93":{"tf":1.0}}}}}}},"l":{"a":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"98":{"tf":1.0}}}}},"c":{"df":0,"docs":{},"k":{"df":3,"docs":{"14":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.0}}}},"df":0,"docs":{},"n":{"d":{"df":3,"docs":{"103":{"tf":1.0},"106":{"tf":1.0},"176":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"g":{"df":5,"docs":{"22":{"tf":1.0},"235":{"tf":1.0},"52":{"tf":2.6457513110645907},"64":{"tf":1.0},"97":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"g":{"df":5,"docs":{"224":{"tf":1.0},"65":{"tf":1.0},"87":{"tf":1.0},"91":{"tf":1.0},"92":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"233":{"tf":1.0},"40":{"tf":1.0}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"81":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"161":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"105":{"tf":1.0},"191":{"tf":1.0}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"232":{"tf":1.7320508075688772}}}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"220":{"tf":1.0}}}},"df":0,"docs":{}}},"y":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"72":{"tf":1.0},"73":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":3,"docs":{"40":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":5,"docs":{"0":{"tf":1.0},"134":{"tf":1.4142135623730951},"39":{"tf":1.0},"40":{"tf":1.0},"65":{"tf":1.0}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"61":{"tf":1.0}}}},"v":{"df":7,"docs":{"100":{"tf":1.0},"107":{"tf":1.0},"192":{"tf":1.0},"198":{"tf":2.449489742783178},"71":{"tf":1.0},"75":{"tf":1.0},"95":{"tf":1.0}}}},"df":1,"docs":{"82":{"tf":1.0}},"f":{"df":0,"docs":{},"t":{"df":3,"docs":{"120":{"tf":1.4142135623730951},"121":{"tf":1.0},"216":{"tf":1.4142135623730951}}}},"g":{"a":{"c":{"df":0,"docs":{},"i":{"df":2,"docs":{"213":{"tf":1.0},"51":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":20,"docs":{"116":{"tf":1.0},"138":{"tf":2.0},"160":{"tf":1.0},"161":{"tf":1.0},"178":{"tf":2.0},"182":{"tf":1.0},"183":{"tf":1.7320508075688772},"184":{"tf":1.7320508075688772},"185":{"tf":1.7320508075688772},"186":{"tf":1.7320508075688772},"187":{"tf":1.7320508075688772},"201":{"tf":1.4142135623730951},"205":{"tf":1.7320508075688772},"206":{"tf":1.0},"207":{"tf":2.449489742783178},"209":{"tf":2.0},"210":{"tf":2.0},"215":{"tf":2.23606797749979},"87":{"tf":1.0},"99":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"s":{"df":4,"docs":{"123":{"tf":1.0},"125":{"tf":1.0},"180":{"tf":1.0},"219":{"tf":1.0}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"82":{"tf":1.0}}}}}},"t":{"df":1,"docs":{"117":{"tf":1.0}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":15,"docs":{"12":{"tf":2.0},"174":{"tf":1.4142135623730951},"198":{"tf":1.0},"223":{"tf":1.0},"32":{"tf":3.1622776601683795},"33":{"tf":1.4142135623730951},"39":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.7320508075688772},"55":{"tf":1.0},"66":{"tf":1.0},"74":{"tf":1.4142135623730951},"76":{"tf":1.0},"92":{"tf":1.0}}}}},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"69":{"tf":1.0}}}},"i":{"c":{"df":2,"docs":{"192":{"tf":1.0},"199":{"tf":1.0}}},"df":0,"docs":{}}}},"h":{"df":22,"docs":{"109":{"tf":1.4142135623730951},"110":{"tf":1.4142135623730951},"111":{"tf":1.4142135623730951},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.4142135623730951},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.4142135623730951},"122":{"tf":1.0},"123":{"tf":1.4142135623730951},"124":{"tf":1.4142135623730951},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.4142135623730951},"128":{"tf":1.0},"129":{"tf":1.0},"99":{"tf":1.0}}},"i":{"b":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"c":{"df":1,"docs":{"227":{"tf":1.0}}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":11,"docs":{"173":{"tf":1.0},"18":{"tf":3.4641016151377544},"203":{"tf":1.0},"220":{"tf":1.0},"223":{"tf":1.7320508075688772},"5":{"tf":1.0},"52":{"tf":2.0},"62":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.7320508075688772}}},"y":{"df":0,"docs":{},"’":{"df":1,"docs":{"173":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":2,"docs":{"235":{"tf":1.0},"65":{"tf":1.0}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"180":{"tf":1.0}}}}}},"t":{"df":1,"docs":{"66":{"tf":1.0}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":5,"docs":{"152":{"tf":1.0},"233":{"tf":1.0},"37":{"tf":1.0},"40":{"tf":1.0},"93":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":26,"docs":{"104":{"tf":1.0},"138":{"tf":1.4142135623730951},"147":{"tf":1.0},"166":{"tf":1.4142135623730951},"175":{"tf":1.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"178":{"tf":1.7320508075688772},"182":{"tf":1.0},"183":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"185":{"tf":1.4142135623730951},"186":{"tf":1.4142135623730951},"187":{"tf":1.4142135623730951},"201":{"tf":2.0},"205":{"tf":1.0},"207":{"tf":1.4142135623730951},"209":{"tf":1.0},"210":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"219":{"tf":1.0},"40":{"tf":1.0},"70":{"tf":1.0},"74":{"tf":1.0},"80":{"tf":1.0}}}},"df":5,"docs":{"19":{"tf":1.0},"30":{"tf":1.0},"64":{"tf":1.0},"94":{"tf":1.0},"99":{"tf":1.0}}},"k":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":5,"docs":{"18":{"tf":3.605551275463989},"225":{"tf":1.0},"52":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"r":{"df":10,"docs":{"100":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"173":{"tf":1.0},"18":{"tf":1.4142135623730951},"186":{"tf":1.0},"191":{"tf":1.0},"218":{"tf":1.0},"67":{"tf":1.0},"71":{"tf":1.0}},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"(":{"\\"":{"<":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"173":{"tf":1.0}}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"/":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{":":{"df":0,"docs":{},"l":{"df":1,"docs":{"173":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":2,"docs":{"100":{"tf":1.0},"173":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"64":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"x":{"df":2,"docs":{"225":{"tf":1.0},"7":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":6,"docs":{"155":{"tf":1.0},"189":{"tf":1.0},"198":{"tf":1.0},"39":{"tf":1.0},"98":{"tf":1.7320508075688772},"99":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"’":{"df":1,"docs":{"107":{"tf":1.0}}}}},"df":15,"docs":{"107":{"tf":1.4142135623730951},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"191":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.0},"83":{"tf":1.0},"85":{"tf":1.4142135623730951},"93":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}}},"t":{"df":0,"docs":{},"l":{"df":8,"docs":{"104":{"tf":1.0},"176":{"tf":1.0},"62":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.0},"90":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":4,"docs":{"180":{"tf":1.0},"219":{"tf":1.0},"35":{"tf":1.0},"62":{"tf":1.0}}}}},"l":{"d":{"df":3,"docs":{"226":{"tf":1.0},"67":{"tf":1.0},"71":{"tf":1.4142135623730951}}},"df":1,"docs":{"69":{"tf":1.0}},"m":{"df":1,"docs":{"65":{"tf":1.0}}},"v":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"226":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"226":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"_":{"2":{"2":{"1":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"=":{"$":{"df":0,"docs":{},"{":{"df":0,"docs":{},"p":{"df":0,"docs":{},"w":{"d":{"df":0,"docs":{},"}":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"226":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":23,"docs":{"12":{"tf":1.4142135623730951},"16":{"tf":1.0},"195":{"tf":1.0},"226":{"tf":3.0},"236":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"69":{"tf":2.449489742783178},"71":{"tf":2.449489742783178},"72":{"tf":1.7320508075688772},"73":{"tf":1.4142135623730951},"74":{"tf":1.4142135623730951},"75":{"tf":1.0},"78":{"tf":1.0},"87":{"tf":1.4142135623730951},"91":{"tf":1.0},"92":{"tf":1.4142135623730951},"94":{"tf":1.0},"95":{"tf":1.0}},"’":{"df":2,"docs":{"81":{"tf":1.0},"92":{"tf":1.4142135623730951}}}}}},"o":{"a":{"d":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"84":{"tf":1.0}}}}}}},"df":10,"docs":{"100":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"166":{"tf":1.0},"169":{"tf":1.4142135623730951},"216":{"tf":1.0},"75":{"tf":1.0},"81":{"tf":1.4142135623730951},"93":{"tf":1.0},"95":{"tf":1.0}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"(":{"\\"":{"<":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"172":{"tf":1.0}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"n":{"df":1,"docs":{"172":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":3,"docs":{"100":{"tf":1.0},"172":{"tf":1.0},"191":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"c":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"13":{"tf":1.0},"53":{"tf":1.0},"61":{"tf":1.0},"63":{"tf":1.0}}},"t":{"df":4,"docs":{"173":{"tf":1.0},"181":{"tf":1.0},"62":{"tf":1.0},"80":{"tf":1.0}}}},"df":0,"docs":{},"k":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"g":{"0":{"(":{"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"207":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"2":{"(":{"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"207":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"<":{"df":0,"docs":{},"n":{">":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"207":{"tf":1.0}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":2,"docs":{"100":{"tf":1.0},"207":{"tf":1.0}}}},"df":4,"docs":{"200":{"tf":1.0},"207":{"tf":1.0},"55":{"tf":2.23606797749979},"93":{"tf":1.0}},"i":{"c":{"df":7,"docs":{"120":{"tf":1.0},"121":{"tf":1.0},"132":{"tf":1.0},"221":{"tf":1.0},"223":{"tf":1.0},"52":{"tf":1.0},"69":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"199":{"tf":1.0},"23":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"235":{"tf":1.0}},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"97":{"tf":1.0}}}}},"p":{"_":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"195":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":6,"docs":{"195":{"tf":3.4641016151377544},"196":{"tf":1.7320508075688772},"197":{"tf":1.7320508075688772},"80":{"tf":1.0},"90":{"tf":1.0},"93":{"tf":1.7320508075688772}},"’":{"df":1,"docs":{"196":{"tf":1.0}}}},"s":{"df":1,"docs":{"188":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"219":{"tf":1.0}}},"s":{"df":1,"docs":{"65":{"tf":1.0}}},"t":{"df":1,"docs":{"74":{"tf":1.0}}}},"t":{"df":2,"docs":{"223":{"tf":1.0},"224":{"tf":1.0}}},"w":{"df":9,"docs":{"139":{"tf":1.0},"177":{"tf":1.4142135623730951},"235":{"tf":1.0},"39":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"55":{"tf":1.0},"74":{"tf":1.0},"82":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"c":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"99":{"tf":1.0}}}},"df":0,"docs":{}},"df":10,"docs":{"103":{"tf":1.0},"104":{"tf":1.0},"214":{"tf":1.0},"52":{"tf":1.4142135623730951},"66":{"tf":1.0},"67":{"tf":1.4142135623730951},"69":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":1.0},"94":{"tf":1.0}}}}}},"t":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"123":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"123":{"tf":1.0}}},"1":{"df":1,"docs":{"195":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"123":{"tf":1.0}}}},"m":{"a":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"13":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.7320508075688772}}}}},"o":{"df":1,"docs":{"7":{"tf":1.0}}},"r":{"df":0,"docs":{},"o":{"df":1,"docs":{"64":{"tf":1.4142135623730951}}}}},"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"210":{"tf":1.0},"63":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"64":{"tf":1.0}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"d":{"df":1,"docs":{"219":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}}},"i":{"df":0,"docs":{},"n":{"df":5,"docs":{"219":{"tf":1.0},"236":{"tf":1.0},"63":{"tf":1.0},"69":{"tf":1.0},"89":{"tf":1.7320508075688772}},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"18":{"tf":1.0},"30":{"tf":1.0},"66":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"m":{"df":1,"docs":{"52":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":7,"docs":{"23":{"tf":1.0},"60":{"tf":1.0},"63":{"tf":1.0},"65":{"tf":1.7320508075688772},"66":{"tf":1.0},"68":{"tf":1.0},"71":{"tf":1.0}}}}},"df":0,"docs":{}}}},"j":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"236":{"tf":1.4142135623730951},"7":{"tf":1.0}}}}},"k":{"df":0,"docs":{},"e":{"df":16,"docs":{"18":{"tf":1.4142135623730951},"180":{"tf":1.0},"19":{"tf":1.0},"221":{"tf":1.0},"226":{"tf":1.7320508075688772},"3":{"tf":1.0},"43":{"tf":1.0},"52":{"tf":1.0},"54":{"tf":1.0},"61":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"70":{"tf":1.0},"74":{"tf":1.4142135623730951},"81":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"61":{"tf":1.4142135623730951}}}}}}},"n":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"221":{"tf":1.0},"95":{"tf":1.0}}}},"d":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"193":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":3,"docs":{"39":{"tf":1.0},"5":{"tf":1.4142135623730951},"85":{"tf":1.0}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":1,"docs":{"235":{"tf":1.0}}}}}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"223":{"tf":1.0},"43":{"tf":1.0}}}},"df":0,"docs":{}}},"p":{"df":10,"docs":{"103":{"tf":1.0},"139":{"tf":1.0},"169":{"tf":1.4142135623730951},"178":{"tf":1.0},"179":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"219":{"tf":1.0},"84":{"tf":1.4142135623730951},"87":{"tf":1.0},"95":{"tf":1.0}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"(":{"$":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"169":{"tf":1.0}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"169":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"139":{"tf":1.0},"169":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"100":{"tf":1.0},"181":{"tf":1.4142135623730951}},"e":{"(":{"$":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"181":{"tf":1.0}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"181":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":2,"docs":{"75":{"tf":1.0},"84":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"75":{"tf":1.0},"84":{"tf":1.0}}}}}}},"’":{"df":2,"docs":{"169":{"tf":1.0},"181":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"k":{"df":2,"docs":{"80":{"tf":1.0},"98":{"tf":1.0}}}},"s":{"df":0,"docs":{},"k":{"df":4,"docs":{"117":{"tf":1.0},"75":{"tf":1.7320508075688772},"79":{"tf":2.0},"95":{"tf":1.0}}}},"t":{"c":{"df":0,"docs":{},"h":{"df":4,"docs":{"176":{"tf":1.0},"194":{"tf":1.4142135623730951},"223":{"tf":1.0},"75":{"tf":1.0}}}},"df":0,"docs":{}},"x":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":2,"docs":{"118":{"tf":1.0},"119":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":1,"docs":{"134":{"tf":1.0}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":2,"docs":{"201":{"tf":1.0},"40":{"tf":1.0}}}}}}},"y":{"b":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":3,"docs":{"100":{"tf":1.0},"178":{"tf":1.7320508075688772},"40":{"tf":1.0}}},"y":{"(":{"$":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"178":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"178":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"3":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":4,"docs":{"105":{"tf":1.0},"40":{"tf":1.0},"64":{"tf":1.0},"99":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":2,"docs":{"103":{"tf":1.0},"64":{"tf":1.7320508075688772}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"68":{"tf":1.0},"90":{"tf":1.4142135623730951},"91":{"tf":1.4142135623730951}}}}}},"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":3,"docs":{"18":{"tf":1.0},"189":{"tf":1.0},"203":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":2,"docs":{"176":{"tf":1.0},"75":{"tf":1.0}},"’":{"df":1,"docs":{"169":{"tf":1.0}}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":1,"docs":{"178":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":50,"docs":{"100":{"tf":1.4142135623730951},"101":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":2.0},"13":{"tf":1.7320508075688772},"138":{"tf":2.0},"14":{"tf":2.449489742783178},"147":{"tf":1.4142135623730951},"166":{"tf":1.7320508075688772},"175":{"tf":1.7320508075688772},"176":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"178":{"tf":1.7320508075688772},"182":{"tf":2.0},"183":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"185":{"tf":1.7320508075688772},"186":{"tf":1.7320508075688772},"187":{"tf":1.4142135623730951},"200":{"tf":1.0},"201":{"tf":2.0},"205":{"tf":1.0},"207":{"tf":1.4142135623730951},"209":{"tf":1.0},"210":{"tf":1.0},"214":{"tf":1.4142135623730951},"215":{"tf":1.0},"216":{"tf":1.0},"27":{"tf":1.0},"39":{"tf":1.7320508075688772},"40":{"tf":2.8284271247461903},"57":{"tf":1.0},"70":{"tf":1.7320508075688772},"72":{"tf":1.4142135623730951},"74":{"tf":1.4142135623730951},"75":{"tf":2.0},"76":{"tf":1.4142135623730951},"78":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":2.0},"81":{"tf":2.0},"82":{"tf":1.0},"83":{"tf":1.0},"87":{"tf":1.0},"91":{"tf":1.0},"92":{"tf":1.0},"93":{"tf":1.4142135623730951},"97":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"78":{"tf":1.0},"82":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":4,"docs":{"105":{"tf":1.0},"166":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0}}}}}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"78":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"r":{"df":0,"docs":{},"g":{"df":5,"docs":{"151":{"tf":1.4142135623730951},"195":{"tf":1.0},"63":{"tf":1.0},"75":{"tf":1.0},"95":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"11":{"tf":1.0},"64":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"a":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"99":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"14":{"tf":1.0},"70":{"tf":1.0}}}}}},"i":{"d":{"df":1,"docs":{"94":{"tf":1.0}}},"df":1,"docs":{"82":{"tf":1.0}},"n":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"117":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":1,"docs":{"75":{"tf":1.0}},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"98":{"tf":1.0}},"u":{"df":0,"docs":{},"m":{"df":2,"docs":{"103":{"tf":1.0},"78":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}},"t":{"df":2,"docs":{"103":{"tf":1.0},"107":{"tf":1.0}}},"u":{"df":2,"docs":{"203":{"tf":1.0},"204":{"tf":1.0}}}},"s":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"80":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"s":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}},"t":{"a":{"df":0,"docs":{},"k":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}},"x":{"df":3,"docs":{"52":{"tf":1.0},"81":{"tf":1.0},"92":{"tf":1.4142135623730951}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"’":{"df":1,"docs":{"76":{"tf":1.0}}}}},"o":{"a":{"d":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"166":{"tf":1.0}}}}}}}}},"0":{"df":2,"docs":{"78":{"tf":1.0},"82":{"tf":1.0}},"x":{"4":{"0":{"df":3,"docs":{"75":{"tf":1.0},"81":{"tf":1.4142135623730951},"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"2":{"^":{"1":{"2":{"8":{"df":2,"docs":{"78":{"tf":1.0},"82":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"5":{"5":{"df":1,"docs":{"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"166":{"tf":1.0}}},"3":{"df":1,"docs":{"166":{"tf":1.0}}},"df":0,"docs":{}}},"_":{"a":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"f":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"82":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}}},"df":6,"docs":{"100":{"tf":1.0},"104":{"tf":1.0},"166":{"tf":1.0},"40":{"tf":1.0},"82":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":3,"docs":{"135":{"tf":1.0},"174":{"tf":1.0},"207":{"tf":1.4142135623730951}}}}}}},"o":{"d":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"114":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"114":{"tf":1.0}}},"df":0,"docs":{}},"x":{"df":1,"docs":{"114":{"tf":1.0}}}},"df":8,"docs":{"100":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"114":{"tf":1.0},"116":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0}},"e":{"df":7,"docs":{"176":{"tf":1.0},"18":{"tf":1.4142135623730951},"50":{"tf":1.0},"73":{"tf":1.0},"80":{"tf":1.4142135623730951},"81":{"tf":1.7320508075688772},"82":{"tf":1.0}},"l":{"df":9,"docs":{"0":{"tf":1.0},"146":{"tf":1.0},"161":{"tf":1.0},"43":{"tf":1.4142135623730951},"49":{"tf":1.4142135623730951},"52":{"tf":1.0},"65":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0}}}},"i":{"df":0,"docs":{},"f":{"df":1,"docs":{"204":{"tf":1.0}},"i":{"df":1,"docs":{"175":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":7,"docs":{"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"116":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"78":{"tf":1.0}}}},"df":3,"docs":{"64":{"tf":1.0},"9":{"tf":1.0},"95":{"tf":1.4142135623730951}},"o":{"df":2,"docs":{"114":{"tf":1.0},"115":{"tf":1.0}}},"u":{"df":2,"docs":{"130":{"tf":1.0},"131":{"tf":1.0}}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"91":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":17,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"138":{"tf":1.0},"14":{"tf":1.0},"174":{"tf":1.4142135623730951},"189":{"tf":1.0},"2":{"tf":1.0},"219":{"tf":1.4142135623730951},"224":{"tf":1.7320508075688772},"33":{"tf":1.0},"5":{"tf":1.7320508075688772},"53":{"tf":1.0},"55":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.0},"93":{"tf":1.4142135623730951},"99":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"219":{"tf":1.0},"236":{"tf":1.0},"24":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":2,"docs":{"235":{"tf":1.0},"74":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"219":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":3,"docs":{"100":{"tf":1.0},"147":{"tf":2.0},"40":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"176":{"tf":1.0}}}}}}}}},"0":{"df":4,"docs":{"139":{"tf":1.0},"140":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0}},"x":{"4":{"0":{"df":1,"docs":{"82":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}},"3":{"2":{"df":3,"docs":{"139":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"176":{"tf":1.0}}},"2":{"df":1,"docs":{"176":{"tf":1.0}}},"4":{"df":1,"docs":{"176":{"tf":1.0}}},"df":0,"docs":{}}},"8":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"177":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"177":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"177":{"tf":1.4142135623730951}}},"df":12,"docs":{"100":{"tf":1.0},"104":{"tf":1.0},"166":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.4142135623730951},"178":{"tf":1.0},"179":{"tf":1.0},"40":{"tf":1.0},"75":{"tf":1.0},"83":{"tf":1.0},"93":{"tf":1.0},"98":{"tf":1.0}}}}}}},"u":{"c":{"df":0,"docs":{},"h":{"df":4,"docs":{"219":{"tf":1.0},"224":{"tf":1.4142135623730951},"4":{"tf":1.0},"53":{"tf":1.0}}}},"df":0,"docs":{},"l":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"111":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"111":{"tf":1.0}}},"df":0,"docs":{}}},"df":4,"docs":{"100":{"tf":1.0},"111":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"d":{"(":{"$":{"a":{"df":1,"docs":{"131":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"131":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"131":{"tf":1.0}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":6,"docs":{"174":{"tf":1.4142135623730951},"182":{"tf":1.0},"189":{"tf":1.0},"194":{"tf":1.0},"78":{"tf":1.0},"99":{"tf":1.0}},"p":{"df":0,"docs":{},"l":{"df":8,"docs":{"111":{"tf":1.0},"131":{"tf":1.0},"178":{"tf":1.4142135623730951},"5":{"tf":1.0},"52":{"tf":1.0},"75":{"tf":1.0},"81":{"tf":1.0},"91":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"l":{"df":4,"docs":{"225":{"tf":1.0},"227":{"tf":1.7320508075688772},"7":{"tf":1.0},"71":{"tf":1.0}}}}}},"n":{">":{"_":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"215":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":78,"docs":{"101":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.4142135623730951},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"159":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"174":{"tf":2.449489742783178},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"198":{"tf":1.0},"201":{"tf":1.0},"205":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"213":{"tf":1.0},"216":{"tf":1.0},"32":{"tf":1.0},"5":{"tf":1.4142135623730951},"62":{"tf":1.0},"64":{"tf":1.0},"98":{"tf":1.4142135623730951},"99":{"tf":1.0}},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":2,"docs":{"189":{"tf":1.0},"91":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":33,"docs":{"103":{"tf":1.4142135623730951},"107":{"tf":1.7320508075688772},"110":{"tf":1.0},"117":{"tf":1.7320508075688772},"122":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.4142135623730951},"136":{"tf":1.0},"137":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.4142135623730951},"181":{"tf":1.0},"184":{"tf":1.0},"193":{"tf":1.0},"201":{"tf":1.4142135623730951},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"213":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":2.449489742783178},"76":{"tf":1.0},"78":{"tf":3.1622776601683795},"79":{"tf":2.23606797749979},"82":{"tf":1.4142135623730951},"91":{"tf":1.7320508075688772},"93":{"tf":1.4142135623730951},"95":{"tf":1.7320508075688772},"98":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"103":{"tf":1.0},"98":{"tf":1.0}}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":10,"docs":{"103":{"tf":1.0},"104":{"tf":1.0},"219":{"tf":1.4142135623730951},"4":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.7320508075688772},"82":{"tf":1.4142135623730951},"92":{"tf":1.4142135623730951},"94":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":2,"docs":{"52":{"tf":1.0},"98":{"tf":1.0}}}}}},"df":8,"docs":{"109":{"tf":1.0},"130":{"tf":2.0},"131":{"tf":2.0},"207":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.4142135623730951},"82":{"tf":1.0},"99":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"82":{"tf":1.0},"85":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"192":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"90":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"235":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"d":{"df":12,"docs":{"103":{"tf":1.0},"18":{"tf":1.7320508075688772},"216":{"tf":1.0},"219":{"tf":1.0},"235":{"tf":1.0},"33":{"tf":1.4142135623730951},"39":{"tf":1.0},"52":{"tf":1.0},"62":{"tf":1.4142135623730951},"64":{"tf":1.0},"71":{"tf":1.0},"94":{"tf":1.0}}},"df":0,"docs":{}},"g":{"df":1,"docs":{"122":{"tf":1.4142135623730951}}},"s":{"df":0,"docs":{},"t":{"df":5,"docs":{"100":{"tf":1.0},"192":{"tf":1.4142135623730951},"199":{"tf":1.0},"204":{"tf":1.0},"98":{"tf":1.0}}}},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"145":{"tf":1.0}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"169":{"tf":1.0},"175":{"tf":1.4142135623730951},"18":{"tf":1.0},"181":{"tf":1.0},"223":{"tf":1.0}}}}},"w":{"df":13,"docs":{"107":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"202":{"tf":1.0},"205":{"tf":1.7320508075688772},"206":{"tf":1.0},"221":{"tf":1.0},"43":{"tf":1.0},"62":{"tf":1.0},"75":{"tf":1.4142135623730951},"82":{"tf":1.0},"91":{"tf":1.0},"97":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"103":{"tf":1.0}}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"_":{"d":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"94":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":13,"docs":{"134":{"tf":1.4142135623730951},"72":{"tf":1.4142135623730951},"73":{"tf":2.0},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.4142135623730951},"89":{"tf":1.4142135623730951},"90":{"tf":1.4142135623730951},"91":{"tf":1.0},"94":{"tf":2.23606797749979},"95":{"tf":1.4142135623730951},"96":{"tf":1.4142135623730951},"97":{"tf":1.0}}}}}}},"x":{"df":0,"docs":{},"t":{"df":1,"docs":{"147":{"tf":1.0}}}}},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"134":{"tf":1.0}}}}},"o":{"d":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"j":{"df":3,"docs":{"19":{"tf":1.0},"225":{"tf":1.0},"9":{"tf":1.0}}}},"df":10,"docs":{"195":{"tf":1.0},"208":{"tf":1.0},"224":{"tf":1.0},"53":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951},"76":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":1.7320508075688772},"95":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"87":{"tf":1.0},"92":{"tf":1.0}}}}}}},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"n":{"c":{"df":1,"docs":{"205":{"tf":1.0}}},"df":17,"docs":{"105":{"tf":1.0},"122":{"tf":1.4142135623730951},"164":{"tf":1.0},"18":{"tf":1.0},"184":{"tf":1.0},"193":{"tf":1.7320508075688772},"194":{"tf":1.0},"195":{"tf":1.7320508075688772},"62":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"80":{"tf":1.0},"82":{"tf":1.4142135623730951},"87":{"tf":1.0},"98":{"tf":1.4142135623730951}},"e":{"df":101,"docs":{"107":{"tf":1.0},"108":{"tf":1.4142135623730951},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.4142135623730951},"142":{"tf":1.4142135623730951},"143":{"tf":1.4142135623730951},"144":{"tf":1.4142135623730951},"145":{"tf":1.4142135623730951},"146":{"tf":1.4142135623730951},"147":{"tf":1.4142135623730951},"148":{"tf":1.4142135623730951},"149":{"tf":1.4142135623730951},"150":{"tf":1.4142135623730951},"151":{"tf":1.4142135623730951},"152":{"tf":1.4142135623730951},"153":{"tf":1.4142135623730951},"154":{"tf":1.4142135623730951},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.4142135623730951},"158":{"tf":1.4142135623730951},"159":{"tf":1.0},"160":{"tf":1.4142135623730951},"161":{"tf":1.4142135623730951},"162":{"tf":1.4142135623730951},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.4142135623730951},"179":{"tf":1.0},"180":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"183":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"185":{"tf":1.4142135623730951},"186":{"tf":1.4142135623730951},"187":{"tf":1.4142135623730951},"189":{"tf":1.4142135623730951},"190":{"tf":1.4142135623730951},"191":{"tf":1.0},"193":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"195":{"tf":1.4142135623730951},"196":{"tf":1.7320508075688772},"197":{"tf":1.7320508075688772},"198":{"tf":1.4142135623730951},"199":{"tf":1.7320508075688772},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.4142135623730951},"209":{"tf":1.4142135623730951},"210":{"tf":1.4142135623730951},"211":{"tf":1.7320508075688772},"212":{"tf":1.7320508075688772},"213":{"tf":1.4142135623730951},"214":{"tf":1.4142135623730951},"215":{"tf":1.4142135623730951},"216":{"tf":1.0},"98":{"tf":1.0}}}},"t":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"133":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"133":{"tf":1.0}}},"df":0,"docs":{}}},"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"0":{"tf":1.0},"235":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":1,"docs":{"99":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"e":{"df":78,"docs":{"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"159":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"18":{"tf":1.4142135623730951},"180":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"19":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"198":{"tf":1.0},"201":{"tf":1.0},"205":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"213":{"tf":1.0},"216":{"tf":1.0},"218":{"tf":1.0},"219":{"tf":1.0},"223":{"tf":1.0},"33":{"tf":1.0},"39":{"tf":1.0},"52":{"tf":1.0},"73":{"tf":1.0},"98":{"tf":1.4142135623730951}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":1,"docs":{"39":{"tf":1.0}}}}}}}}},"h":{"df":1,"docs":{"198":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"m":{"df":2,"docs":{"19":{"tf":1.7320508075688772},"9":{"tf":1.0}}},"x":{"df":1,"docs":{"19":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"n":{"c":{"df":2,"docs":{"224":{"tf":1.0},"65":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"219":{"tf":1.0}}}}}}},"m":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":16,"docs":{"100":{"tf":1.0},"134":{"tf":1.0},"150":{"tf":2.0},"156":{"tf":1.7320508075688772},"178":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"193":{"tf":1.0},"207":{"tf":1.0},"215":{"tf":1.0},"219":{"tf":1.0},"64":{"tf":1.0},"90":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"27":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":2,"docs":{"43":{"tf":1.0},"53":{"tf":1.0}}}}}}}}},"o":{"(":{"df":0,"docs":{},"n":{"df":1,"docs":{"219":{"tf":1.0}}}},"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":13,"docs":{"16":{"tf":1.0},"174":{"tf":1.0},"18":{"tf":1.0},"218":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.4142135623730951},"31":{"tf":1.0},"67":{"tf":1.4142135623730951},"75":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.7320508075688772},"95":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":7,"docs":{"0":{"tf":1.0},"179":{"tf":1.0},"181":{"tf":1.0},"190":{"tf":1.0},"223":{"tf":1.4142135623730951},"3":{"tf":1.0},"34":{"tf":1.0}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"225":{"tf":1.0},"226":{"tf":1.0}}}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":1,"docs":{"64":{"tf":1.0}}}}}}},"c":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"129":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":3,"docs":{"12":{"tf":1.0},"19":{"tf":1.0},"29":{"tf":1.0}},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"4":{"tf":1.0},"49":{"tf":1.0},"70":{"tf":1.0},"90":{"tf":1.0}}}},"i":{"c":{"df":0,"docs":{},"i":{"df":3,"docs":{"18":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":34,"docs":{"105":{"tf":1.7320508075688772},"138":{"tf":1.7320508075688772},"147":{"tf":1.0},"159":{"tf":1.7320508075688772},"166":{"tf":1.7320508075688772},"170":{"tf":1.4142135623730951},"176":{"tf":2.449489742783178},"177":{"tf":2.0},"178":{"tf":1.4142135623730951},"182":{"tf":1.4142135623730951},"183":{"tf":2.23606797749979},"184":{"tf":2.23606797749979},"185":{"tf":2.23606797749979},"186":{"tf":2.23606797749979},"187":{"tf":2.23606797749979},"201":{"tf":1.4142135623730951},"205":{"tf":1.7320508075688772},"206":{"tf":1.0},"207":{"tf":1.7320508075688772},"209":{"tf":1.7320508075688772},"210":{"tf":1.7320508075688772},"215":{"tf":1.0},"216":{"tf":1.0},"39":{"tf":1.4142135623730951},"40":{"tf":1.0},"41":{"tf":1.0},"57":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":2.0},"81":{"tf":1.4142135623730951},"82":{"tf":1.4142135623730951},"85":{"tf":1.0},"99":{"tf":1.0}}}}}}},"k":{"(":{"0":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"n":{"c":{"df":3,"docs":{"172":{"tf":1.0},"191":{"tf":1.0},"91":{"tf":1.0}}},"df":26,"docs":{"102":{"tf":1.0},"103":{"tf":1.0},"107":{"tf":1.0},"109":{"tf":1.0},"122":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.4142135623730951},"15":{"tf":1.0},"174":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.4142135623730951},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.4142135623730951},"198":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"219":{"tf":1.0},"235":{"tf":1.0},"33":{"tf":1.0},"65":{"tf":1.0},"82":{"tf":1.0},"87":{"tf":1.4142135623730951},"92":{"tf":1.0},"98":{"tf":1.4142135623730951}},"t":{"df":0,"docs":{},"o":{"df":1,"docs":{"178":{"tf":1.0}}}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"229":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"p":{"(":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"(":{"a":{",":{"df":0,"docs":{},"n":{"df":1,"docs":{"78":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"a":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":1,"docs":{"182":{"tf":1.0}}}}},"c":{"df":0,"docs":{},"o":{"d":{"df":9,"docs":{"116":{"tf":1.0},"134":{"tf":1.0},"174":{"tf":1.0},"202":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"231":{"tf":1.0},"43":{"tf":1.0},"49":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"81":{"tf":1.0},"98":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"59":{"tf":1.0},"63":{"tf":1.0}},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"90":{"tf":1.4142135623730951},"91":{"tf":1.0}}}}}}}}}}},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":110,"docs":{"106":{"tf":1.4142135623730951},"107":{"tf":1.0},"108":{"tf":1.0},"109":{"tf":1.7320508075688772},"110":{"tf":1.7320508075688772},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.4142135623730951},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.4142135623730951},"121":{"tf":1.4142135623730951},"122":{"tf":1.4142135623730951},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.4142135623730951},"126":{"tf":1.4142135623730951},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.7320508075688772},"133":{"tf":1.7320508075688772},"134":{"tf":1.7320508075688772},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.4142135623730951},"171":{"tf":1.4142135623730951},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.4142135623730951},"176":{"tf":1.0},"177":{"tf":1.4142135623730951},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.4142135623730951},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.7320508075688772},"204":{"tf":1.7320508075688772},"205":{"tf":1.0},"206":{"tf":1.4142135623730951},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.4142135623730951},"215":{"tf":1.7320508075688772},"216":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":2.0},"99":{"tf":1.0}},"’":{"df":1,"docs":{"111":{"tf":1.0}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":1,"docs":{"99":{"tf":1.0}}}}}}}},"df":24,"docs":{"100":{"tf":1.0},"101":{"tf":1.0},"129":{"tf":1.0},"135":{"tf":1.0},"175":{"tf":1.0},"177":{"tf":1.0},"179":{"tf":1.0},"181":{"tf":1.0},"40":{"tf":1.0},"68":{"tf":1.0},"7":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":1.7320508075688772},"78":{"tf":1.7320508075688772},"79":{"tf":1.0},"80":{"tf":1.0},"84":{"tf":1.0},"87":{"tf":1.0},"93":{"tf":1.0},"96":{"tf":1.0},"97":{"tf":2.23606797749979},"98":{"tf":2.8284271247461903},"99":{"tf":1.0}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":3,"docs":{"72":{"tf":1.0},"75":{"tf":1.0},"93":{"tf":1.4142135623730951}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":27,"docs":{"12":{"tf":3.3166247903554},"16":{"tf":1.0},"18":{"tf":1.7320508075688772},"180":{"tf":1.0},"236":{"tf":1.4142135623730951},"28":{"tf":1.0},"29":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"67":{"tf":1.0},"70":{"tf":1.0},"72":{"tf":2.23606797749979},"73":{"tf":1.7320508075688772},"74":{"tf":1.4142135623730951},"75":{"tf":2.0},"77":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":2.0},"83":{"tf":1.0},"87":{"tf":1.0},"90":{"tf":1.4142135623730951},"91":{"tf":2.23606797749979},"92":{"tf":1.4142135623730951},"93":{"tf":1.0},"94":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"90":{"tf":1.4142135623730951}}},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"’":{"df":1,"docs":{"81":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"66":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"n":{"<":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"167":{"tf":1.0},"179":{"tf":1.0}}}}}}}}},"df":0,"docs":{}},"df":6,"docs":{"11":{"tf":1.4142135623730951},"19":{"tf":1.4142135623730951},"193":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"98":{"tf":1.0},"99":{"tf":1.4142135623730951}}}}}}},"r":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"118":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"118":{"tf":1.0}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}}}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":10,"docs":{"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"161":{"tf":1.0},"174":{"tf":1.0},"219":{"tf":1.4142135623730951},"51":{"tf":1.0},"75":{"tf":1.0},"81":{"tf":1.7320508075688772},"82":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":5,"docs":{"100":{"tf":1.0},"103":{"tf":1.0},"143":{"tf":2.0},"181":{"tf":1.0},"75":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"94":{"tf":1.0}},"w":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":11,"docs":{"107":{"tf":1.0},"121":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"177":{"tf":1.0},"179":{"tf":1.0},"18":{"tf":1.0},"192":{"tf":1.0},"193":{"tf":1.0},"198":{"tf":1.0},"99":{"tf":1.0}}}}}}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":2,"docs":{"34":{"tf":1.0},"39":{"tf":1.0}}}}},"t":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"57":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":2,"docs":{"223":{"tf":1.4142135623730951},"92":{"tf":1.0}}}}},"d":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"23":{"tf":1.0}}}},"df":0,"docs":{}},"df":5,"docs":{"185":{"tf":1.0},"214":{"tf":1.0},"232":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":14,"docs":{"139":{"tf":1.0},"140":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"208":{"tf":1.0},"214":{"tf":1.4142135623730951},"215":{"tf":1.0},"216":{"tf":1.0},"64":{"tf":1.0},"75":{"tf":2.0},"84":{"tf":1.7320508075688772},"86":{"tf":1.4142135623730951},"87":{"tf":1.7320508075688772},"95":{"tf":1.4142135623730951}}}}},"o":{"df":0,"docs":{},"f":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"40":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"g":{"a":{"df":1,"docs":{"39":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{">":{"/":{"<":{"df":0,"docs":{},"o":{"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{">":{".":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":1,"docs":{"94":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{"_":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"_":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":1,"docs":{"94":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":14,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"192":{"tf":1.0},"193":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"195":{"tf":1.4142135623730951},"196":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":2.23606797749979},"33":{"tf":3.0},"55":{"tf":1.0},"94":{"tf":1.7320508075688772},"95":{"tf":1.0},"98":{"tf":1.0}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"32":{"tf":1.4142135623730951},"33":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}},"s":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"156":{"tf":1.0}}},"df":0,"docs":{}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"5":{"tf":1.0},"67":{"tf":1.0}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"219":{"tf":1.0}}}}},"df":3,"docs":{"235":{"tf":1.0},"68":{"tf":1.0},"91":{"tf":1.0}},"f":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":9,"docs":{"103":{"tf":1.0},"109":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"214":{"tf":1.7320508075688772},"70":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"92":{"tf":1.4142135623730951}}}}}},"h":{"df":0,"docs":{},"e":{"a":{"d":{"df":3,"docs":{"219":{"tf":1.7320508075688772},"75":{"tf":1.4142135623730951},"92":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"l":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"178":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":1,"docs":{"91":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.0}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":2,"docs":{"236":{"tf":1.0},"75":{"tf":1.0}}}}}}}}},"w":{"df":0,"docs":{},"n":{"df":1,"docs":{"143":{"tf":1.0}}}},"z":{"_":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":1,"docs":{"90":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"w":{"a":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"c":{"2":{"0":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"90":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":3,"docs":{"12":{"tf":1.0},"81":{"tf":1.0},"90":{"tf":1.0}}}},"p":{"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":4,"docs":{"19":{"tf":1.7320508075688772},"221":{"tf":1.0},"89":{"tf":1.0},"9":{"tf":1.0}}}},"df":0,"docs":{}}},"d":{"df":1,"docs":{"214":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":3,"docs":{"168":{"tf":1.0},"224":{"tf":1.0},"91":{"tf":1.0}}}},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":13,"docs":{"0":{"tf":1.7320508075688772},"180":{"tf":1.0},"217":{"tf":1.4142135623730951},"219":{"tf":1.0},"220":{"tf":1.7320508075688772},"223":{"tf":1.4142135623730951},"224":{"tf":1.0},"34":{"tf":1.0},"37":{"tf":1.0},"41":{"tf":1.0},"46":{"tf":1.0},"53":{"tf":1.0},"55":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"i":{"c":{"(":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"2":{"5":{"6":{"df":2,"docs":{"214":{"tf":1.0},"86":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"(":{"0":{"df":0,"docs":{},"x":{"1":{"1":{"df":1,"docs":{"214":{"tf":1.0}}},"df":0,"docs":{}},"<":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":1,"docs":{"214":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":2,"docs":{"100":{"tf":1.0},"214":{"tf":1.0}}}}}}}}},"df":4,"docs":{"214":{"tf":2.23606797749979},"64":{"tf":1.0},"75":{"tf":1.0},"86":{"tf":1.4142135623730951}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"86":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}},"r":{"a":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"235":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":4,"docs":{"103":{"tf":1.0},"189":{"tf":1.0},"78":{"tf":2.0},"91":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"/":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"75":{"tf":1.0}}}}}}}}},"df":2,"docs":{"75":{"tf":1.0},"85":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"98":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}},"y":{"/":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{"@":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"19":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"5":{"tf":1.0},"69":{"tf":1.4142135623730951},"97":{"tf":1.0}}}}},"t":{"df":6,"docs":{"135":{"tf":1.0},"179":{"tf":1.0},"62":{"tf":1.0},"82":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}},"i":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":1,"docs":{"98":{"tf":1.4142135623730951}}}}},"df":2,"docs":{"20":{"tf":1.0},"64":{"tf":1.0}},"t":{"df":1,"docs":{"167":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"s":{"df":33,"docs":{"104":{"tf":1.0},"105":{"tf":1.0},"107":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"179":{"tf":1.0},"181":{"tf":1.0},"182":{"tf":1.0},"185":{"tf":1.0},"195":{"tf":1.0},"198":{"tf":1.0},"219":{"tf":1.0},"63":{"tf":1.4142135623730951},"72":{"tf":1.0},"75":{"tf":3.0},"78":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":1.0},"91":{"tf":1.7320508075688772},"92":{"tf":1.4142135623730951},"93":{"tf":1.0},"94":{"tf":1.0},"95":{"tf":1.4142135623730951},"97":{"tf":1.0}}},"t":{"df":4,"docs":{"159":{"tf":1.0},"183":{"tf":1.0},"185":{"tf":1.0},"187":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"/":{"df":0,"docs":{},"m":{"df":0,"docs":{},"y":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"1":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}},"2":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"=":{"/":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":1,"docs":{"221":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":6,"docs":{"15":{"tf":1.4142135623730951},"173":{"tf":2.0},"221":{"tf":1.0},"64":{"tf":1.0},"82":{"tf":1.0},"94":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":18,"docs":{"138":{"tf":1.0},"139":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"203":{"tf":1.0},"208":{"tf":1.0},"52":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.7320508075688772},"79":{"tf":1.7320508075688772},"80":{"tf":1.4142135623730951},"83":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":1.7320508075688772},"87":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.7320508075688772}}}}}}},"y":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"87":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"c":{"df":1,"docs":{"48":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":33,"docs":{"109":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"146":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"156":{"tf":1.0},"161":{"tf":1.4142135623730951},"166":{"tf":1.7320508075688772},"167":{"tf":1.4142135623730951},"168":{"tf":1.0},"169":{"tf":1.0},"180":{"tf":1.0},"185":{"tf":1.4142135623730951},"190":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.4142135623730951},"198":{"tf":1.0},"199":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"87":{"tf":1.4142135623730951},"90":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":1.0}},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":8,"docs":{"12":{"tf":1.0},"232":{"tf":1.0},"66":{"tf":1.0},"73":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"167":{"tf":1.0},"175":{"tf":1.0},"179":{"tf":1.0}}}}}}}},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":2,"docs":{"78":{"tf":1.0},"91":{"tf":2.23606797749979}}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"195":{"tf":1.0},"95":{"tf":1.0}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":1,"docs":{"222":{"tf":1.0}}}}}}}}}}},"i":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"117":{"tf":1.0}}}},"df":0,"docs":{},"e":{"c":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{}},"n":{"df":1,"docs":{"62":{"tf":1.0}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":7,"docs":{"236":{"tf":1.0},"50":{"tf":1.0},"61":{"tf":1.0},"75":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.4142135623730951},"95":{"tf":1.0}}}}}}}},"l":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"97":{"tf":1.0}},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"99":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"208":{"tf":1.0}}}},"t":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":4,"docs":{"235":{"tf":1.0},"68":{"tf":1.0},"7":{"tf":1.0},"71":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":8,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.7320508075688772},"64":{"tf":1.4142135623730951},"65":{"tf":1.0},"7":{"tf":1.0},"8":{"tf":1.0}}}},"df":0,"docs":{}},"u":{"df":3,"docs":{"105":{"tf":1.0},"206":{"tf":1.4142135623730951},"214":{"tf":1.0}}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"104":{"tf":1.4142135623730951},"146":{"tf":1.0},"196":{"tf":1.0},"93":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":11,"docs":{"102":{"tf":1.0},"103":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.7320508075688772},"166":{"tf":1.0},"39":{"tf":1.4142135623730951},"43":{"tf":1.4142135623730951},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"81":{"tf":1.4142135623730951}}}}}}},"l":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":1,"docs":{"4":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":6,"docs":{"2":{"tf":1.4142135623730951},"217":{"tf":1.0},"220":{"tf":1.0},"4":{"tf":1.0},"49":{"tf":1.0},"52":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":16,"docs":{"1":{"tf":1.0},"103":{"tf":1.4142135623730951},"104":{"tf":1.0},"180":{"tf":1.0},"217":{"tf":1.0},"226":{"tf":1.4142135623730951},"5":{"tf":1.0},"55":{"tf":1.0},"6":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"73":{"tf":1.0},"74":{"tf":1.4142135623730951},"75":{"tf":1.0},"78":{"tf":1.0},"92":{"tf":1.0},"95":{"tf":1.0}},"’":{"df":1,"docs":{"176":{"tf":1.0}}}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"91":{"tf":1.0}}}}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"18":{"tf":1.0},"66":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"207":{"tf":1.0},"65":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":16,"docs":{"106":{"tf":1.0},"107":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.7320508075688772},"137":{"tf":1.0},"170":{"tf":1.4142135623730951},"171":{"tf":1.4142135623730951},"172":{"tf":1.4142135623730951},"173":{"tf":1.4142135623730951},"174":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.4142135623730951},"215":{"tf":1.4142135623730951},"216":{"tf":1.0},"75":{"tf":1.0},"85":{"tf":1.0}}}},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":6,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"198":{"tf":1.0},"222":{"tf":1.7320508075688772},"235":{"tf":1.0},"62":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"t":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"195":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":5,"docs":{"151":{"tf":1.0},"195":{"tf":2.6457513110645907},"197":{"tf":1.0},"213":{"tf":1.0},"22":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":4,"docs":{"0":{"tf":1.0},"185":{"tf":1.0},"34":{"tf":1.0},"68":{"tf":1.0}}}}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"224":{"tf":1.0},"66":{"tf":1.0},"75":{"tf":1.0}}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":6,"docs":{"134":{"tf":1.0},"146":{"tf":1.0},"177":{"tf":1.0},"219":{"tf":1.0},"52":{"tf":1.0},"78":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":3,"docs":{"62":{"tf":1.4142135623730951},"63":{"tf":1.7320508075688772},"65":{"tf":1.0}},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.0}}}}}}}},"d":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"84":{"tf":1.0}}}},"df":0,"docs":{}}},"df":1,"docs":{"151":{"tf":1.0}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"62":{"tf":1.0}}}},"i":{"df":0,"docs":{},"x":{"df":2,"docs":{"62":{"tf":1.4142135623730951},"99":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{"/":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"94":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"t":{"df":3,"docs":{"167":{"tf":1.0},"179":{"tf":1.0},"99":{"tf":1.0}}}},"r":{"df":0,"docs":{},"v":{"df":6,"docs":{"122":{"tf":1.0},"202":{"tf":1.0},"222":{"tf":1.0},"40":{"tf":1.0},"76":{"tf":1.0},"93":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"95":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"68":{"tf":1.0},"70":{"tf":1.0},"80":{"tf":1.4142135623730951},"92":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"82":{"tf":1.0}}}}}},"r":{"a":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"o":{"df":2,"docs":{"151":{"tf":1.0},"47":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"158":{"tf":1.0}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":5,"docs":{"129":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"180":{"tf":1.0},"52":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"t":{"df":28,"docs":{"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"107":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.0},"179":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.7320508075688772},"216":{"tf":1.4142135623730951},"76":{"tf":1.0},"94":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":2.0}},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"r":{"df":2,"docs":{"95":{"tf":1.0},"97":{"tf":1.0}}}},"df":8,"docs":{"135":{"tf":1.0},"167":{"tf":1.0},"174":{"tf":1.7320508075688772},"179":{"tf":1.0},"95":{"tf":1.0},"97":{"tf":1.4142135623730951},"98":{"tf":1.4142135623730951},"99":{"tf":2.0}},"’":{"df":1,"docs":{"98":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"219":{"tf":1.0},"65":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"236":{"tf":1.0}}}}}}}},"o":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}}},"df":1,"docs":{"219":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":7,"docs":{"33":{"tf":1.0},"50":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"71":{"tf":1.0},"8":{"tf":1.0}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":20,"docs":{"102":{"tf":1.0},"106":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"137":{"tf":1.0},"166":{"tf":1.0},"169":{"tf":1.0},"18":{"tf":1.0},"180":{"tf":1.0},"189":{"tf":1.7320508075688772},"200":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.0},"78":{"tf":1.0},"89":{"tf":1.0},"90":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}},"t":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"93":{"tf":1.0}}},"t":{"df":1,"docs":{"232":{"tf":1.0}}}}},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"m":{"df":3,"docs":{"235":{"tf":1.0},"52":{"tf":1.0},"91":{"tf":1.0}},"’":{"df":1,"docs":{"147":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"91":{"tf":1.0}}}}}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":6,"docs":{"226":{"tf":1.0},"235":{"tf":1.0},"3":{"tf":1.0},"5":{"tf":1.0},"59":{"tf":1.0},"65":{"tf":1.4142135623730951}},"’":{"df":2,"docs":{"236":{"tf":1.0},"60":{"tf":1.0}}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"f":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}},"df":5,"docs":{"52":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.0},"81":{"tf":1.7320508075688772}}}},"p":{"a":{"df":0,"docs":{},"g":{"df":8,"docs":{"105":{"tf":1.0},"108":{"tf":1.0},"176":{"tf":1.0},"75":{"tf":2.449489742783178},"78":{"tf":1.4142135623730951},"80":{"tf":1.7320508075688772},"81":{"tf":1.0},"95":{"tf":1.7320508075688772}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"68":{"tf":1.0},"74":{"tf":1.0},"78":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"116":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"98":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"81":{"tf":1.0}}}},"df":0,"docs":{}}},"v":{"a":{"b":{"df":0,"docs":{},"l":{"df":3,"docs":{"75":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":4,"docs":{"103":{"tf":1.0},"177":{"tf":1.0},"223":{"tf":1.0},"79":{"tf":1.0}},"n":{"df":1,"docs":{"176":{"tf":1.0}}}},"i":{"d":{"df":10,"docs":{"18":{"tf":2.23606797749979},"180":{"tf":1.0},"220":{"tf":1.0},"223":{"tf":1.4142135623730951},"235":{"tf":1.4142135623730951},"52":{"tf":1.0},"56":{"tf":1.0},"64":{"tf":1.7320508075688772},"66":{"tf":1.0},"80":{"tf":1.0}}},"df":0,"docs":{}}},"x":{"df":0,"docs":{},"i":{"df":2,"docs":{"203":{"tf":1.0},"90":{"tf":1.0}},"m":{"df":1,"docs":{"219":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"r":{"(":{"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":1,"docs":{"102":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"<":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"102":{"tf":1.0},"104":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":4,"docs":{"101":{"tf":1.0},"102":{"tf":1.0},"104":{"tf":1.0},"99":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"102":{"tf":1.0},"104":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"102":{"tf":1.0},"104":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":1,"docs":{"104":{"tf":1.0}}}},"u":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"51":{"tf":1.4142135623730951},"64":{"tf":1.0}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"19":{"tf":1.0}}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":2,"docs":{"186":{"tf":1.0},"63":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"e":{"df":74,"docs":{"100":{"tf":1.0},"106":{"tf":1.7320508075688772},"107":{"tf":1.0},"108":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.7320508075688772},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.4142135623730951},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.4142135623730951},"167":{"tf":1.4142135623730951},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"175":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.4142135623730951},"76":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.4142135623730951}}},"g":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"=":{"6":{"1":{"4":{"4":{"/":{"3":{"1":{"4":{"5":{"7":{"2":{"8":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":106,"docs":{"107":{"tf":1.4142135623730951},"108":{"tf":1.4142135623730951},"109":{"tf":1.4142135623730951},"110":{"tf":1.4142135623730951},"111":{"tf":1.4142135623730951},"112":{"tf":1.4142135623730951},"113":{"tf":1.4142135623730951},"114":{"tf":1.4142135623730951},"115":{"tf":1.4142135623730951},"116":{"tf":1.4142135623730951},"117":{"tf":1.4142135623730951},"118":{"tf":1.4142135623730951},"119":{"tf":1.4142135623730951},"120":{"tf":1.4142135623730951},"121":{"tf":1.4142135623730951},"122":{"tf":1.4142135623730951},"123":{"tf":1.4142135623730951},"124":{"tf":1.4142135623730951},"125":{"tf":1.4142135623730951},"126":{"tf":1.4142135623730951},"127":{"tf":1.4142135623730951},"128":{"tf":1.4142135623730951},"129":{"tf":1.4142135623730951},"130":{"tf":1.4142135623730951},"131":{"tf":1.4142135623730951},"132":{"tf":1.4142135623730951},"133":{"tf":1.4142135623730951},"134":{"tf":1.4142135623730951},"135":{"tf":1.4142135623730951},"136":{"tf":1.4142135623730951},"137":{"tf":1.4142135623730951},"138":{"tf":1.4142135623730951},"139":{"tf":1.4142135623730951},"140":{"tf":1.4142135623730951},"141":{"tf":1.4142135623730951},"142":{"tf":1.4142135623730951},"143":{"tf":1.4142135623730951},"144":{"tf":1.4142135623730951},"145":{"tf":1.4142135623730951},"146":{"tf":1.4142135623730951},"147":{"tf":1.4142135623730951},"148":{"tf":1.4142135623730951},"149":{"tf":1.4142135623730951},"150":{"tf":1.4142135623730951},"151":{"tf":1.4142135623730951},"152":{"tf":1.4142135623730951},"153":{"tf":1.4142135623730951},"154":{"tf":1.4142135623730951},"155":{"tf":1.4142135623730951},"156":{"tf":1.4142135623730951},"157":{"tf":1.4142135623730951},"158":{"tf":1.4142135623730951},"159":{"tf":1.4142135623730951},"160":{"tf":1.4142135623730951},"161":{"tf":1.4142135623730951},"162":{"tf":1.4142135623730951},"163":{"tf":1.4142135623730951},"164":{"tf":1.4142135623730951},"165":{"tf":1.4142135623730951},"166":{"tf":1.4142135623730951},"167":{"tf":1.4142135623730951},"168":{"tf":1.4142135623730951},"169":{"tf":1.4142135623730951},"170":{"tf":1.4142135623730951},"171":{"tf":1.4142135623730951},"172":{"tf":1.4142135623730951},"173":{"tf":1.4142135623730951},"174":{"tf":1.7320508075688772},"176":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"178":{"tf":1.4142135623730951},"179":{"tf":1.4142135623730951},"180":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"183":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"185":{"tf":1.4142135623730951},"186":{"tf":1.4142135623730951},"187":{"tf":1.4142135623730951},"189":{"tf":1.7320508075688772},"190":{"tf":1.4142135623730951},"191":{"tf":1.4142135623730951},"193":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"195":{"tf":1.4142135623730951},"196":{"tf":1.4142135623730951},"197":{"tf":1.4142135623730951},"198":{"tf":1.4142135623730951},"199":{"tf":1.4142135623730951},"201":{"tf":1.4142135623730951},"202":{"tf":1.4142135623730951},"203":{"tf":1.4142135623730951},"204":{"tf":1.4142135623730951},"205":{"tf":1.4142135623730951},"206":{"tf":1.4142135623730951},"207":{"tf":1.4142135623730951},"209":{"tf":1.4142135623730951},"210":{"tf":1.4142135623730951},"211":{"tf":1.4142135623730951},"212":{"tf":1.4142135623730951},"213":{"tf":1.4142135623730951},"214":{"tf":1.4142135623730951},"215":{"tf":1.4142135623730951},"216":{"tf":1.4142135623730951},"96":{"tf":1.0},"98":{"tf":1.4142135623730951}}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":9,"docs":{"138":{"tf":1.0},"146":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"219":{"tf":1.0},"30":{"tf":1.0},"52":{"tf":1.0},"82":{"tf":1.0},"95":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"63":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"m":{"df":26,"docs":{"0":{"tf":1.4142135623730951},"13":{"tf":1.0},"14":{"tf":1.4142135623730951},"16":{"tf":1.0},"18":{"tf":1.0},"217":{"tf":1.4142135623730951},"218":{"tf":1.0},"219":{"tf":2.6457513110645907},"223":{"tf":1.4142135623730951},"235":{"tf":1.0},"236":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"35":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.4142135623730951},"48":{"tf":1.0},"52":{"tf":1.0},"55":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"80":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.0}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}}}}},"q":{"df":0,"docs":{},"u":{"a":{"d":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"64":{"tf":1.0}}}},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"59":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"60":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"t":{"df":5,"docs":{"170":{"tf":1.4142135623730951},"171":{"tf":1.4142135623730951},"172":{"tf":1.4142135623730951},"173":{"tf":1.4142135623730951},"191":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"112":{"tf":1.0},"113":{"tf":1.0}}}}}}}}}},"r":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"78":{"tf":1.0}},"g":{"df":9,"docs":{"105":{"tf":1.0},"156":{"tf":1.0},"178":{"tf":1.7320508075688772},"185":{"tf":1.0},"79":{"tf":1.0},"81":{"tf":2.0},"82":{"tf":1.0},"90":{"tf":1.0},"94":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"108":{"tf":1.0},"18":{"tf":1.4142135623730951}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}}}},"w":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"97":{"tf":1.0}}}},"df":0,"docs":{}},"df":3,"docs":{"134":{"tf":1.0},"74":{"tf":1.0},"93":{"tf":1.0}}}},"d":{"/":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"166":{"tf":1.0}}}}}}},"a":{"b":{"df":0,"docs":{},"l":{"df":3,"docs":{"61":{"tf":1.0},"64":{"tf":1.0},"95":{"tf":1.0}}}},"df":0,"docs":{}},"df":26,"docs":{"1":{"tf":1.0},"100":{"tf":1.0},"104":{"tf":1.0},"159":{"tf":1.4142135623730951},"166":{"tf":1.7320508075688772},"167":{"tf":1.4142135623730951},"168":{"tf":1.0},"172":{"tf":1.4142135623730951},"183":{"tf":1.0},"184":{"tf":1.4142135623730951},"185":{"tf":1.4142135623730951},"187":{"tf":1.0},"191":{"tf":1.0},"201":{"tf":1.0},"204":{"tf":1.0},"207":{"tf":1.0},"34":{"tf":1.0},"40":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0},"82":{"tf":1.0},"94":{"tf":1.0},"95":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"81":{"tf":1.0},"82":{"tf":1.0}}}},"m":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"m":{"d":{"df":2,"docs":{"10":{"tf":1.0},"60":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"df":2,"docs":{"105":{"tf":1.0},"90":{"tf":1.0}},"i":{"df":0,"docs":{},"z":{"df":2,"docs":{"235":{"tf":1.0},"72":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":8,"docs":{"18":{"tf":1.0},"235":{"tf":1.0},"32":{"tf":1.0},"43":{"tf":1.0},"52":{"tf":1.0},"69":{"tf":1.0},"70":{"tf":1.0},"81":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":2,"docs":{"195":{"tf":1.0},"39":{"tf":1.0}}}},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"156":{"tf":1.0},"161":{"tf":1.0},"185":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"213":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":5,"docs":{"139":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"79":{"tf":1.0},"83":{"tf":1.0}}}},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"232":{"tf":1.0},"69":{"tf":1.0}}},"df":0,"docs":{}}}}},"v":{"df":1,"docs":{"74":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"92":{"tf":1.0}},"s":{"df":1,"docs":{"75":{"tf":1.7320508075688772}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":2,"docs":{"219":{"tf":1.0},"78":{"tf":1.0}},"t":{"df":5,"docs":{"75":{"tf":1.0},"81":{"tf":1.0},"89":{"tf":1.0},"90":{"tf":1.4142135623730951},"95":{"tf":1.0}}}},"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"84":{"tf":1.0}}},"df":0,"docs":{}}}},"df":2,"docs":{"195":{"tf":1.0},"78":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"180":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"f":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":16,"docs":{"101":{"tf":1.4142135623730951},"106":{"tf":1.0},"108":{"tf":1.4142135623730951},"222":{"tf":1.0},"223":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"6":{"tf":1.0},"60":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"8":{"tf":1.0},"95":{"tf":1.7320508075688772},"96":{"tf":1.4142135623730951},"97":{"tf":1.0},"99":{"tf":1.7320508075688772}},"e":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"108":{"tf":1.0}}},"df":0,"docs":{}}}}},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"105":{"tf":1.0},"75":{"tf":1.0}}}},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"161":{"tf":1.0}}}},"df":0,"docs":{}}}},"g":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"50":{"tf":1.0}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":5,"docs":{"110":{"tf":1.0},"133":{"tf":1.0},"174":{"tf":1.0},"18":{"tf":1.0},"81":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":20,"docs":{"101":{"tf":1.0},"104":{"tf":1.0},"138":{"tf":1.0},"166":{"tf":2.0},"176":{"tf":1.7320508075688772},"177":{"tf":2.0},"178":{"tf":2.0},"192":{"tf":1.0},"193":{"tf":2.449489742783178},"194":{"tf":2.23606797749979},"195":{"tf":2.6457513110645907},"197":{"tf":1.0},"199":{"tf":1.4142135623730951},"216":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":1.4142135623730951},"82":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":1.7320508075688772},"99":{"tf":1.4142135623730951}},"s":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"94":{"tf":1.0}}}}}}}}},"df":0,"docs":{}},"’":{"df":1,"docs":{"199":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":5,"docs":{"103":{"tf":1.4142135623730951},"13":{"tf":1.0},"174":{"tf":1.7320508075688772},"219":{"tf":1.4142135623730951},"74":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":3,"docs":{"82":{"tf":1.4142135623730951},"91":{"tf":1.0},"92":{"tf":2.0}}}}}},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":3,"docs":{"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0}}}}}}}}}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}},"l":{"a":{"df":0,"docs":{},"t":{"df":4,"docs":{"24":{"tf":1.0},"40":{"tf":1.0},"49":{"tf":1.4142135623730951},"82":{"tf":1.0}}},"x":{"df":1,"docs":{"78":{"tf":1.0}}}},"df":1,"docs":{"18":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"s":{"df":4,"docs":{"236":{"tf":1.7320508075688772},"68":{"tf":1.4142135623730951},"7":{"tf":1.4142135623730951},"71":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"i":{"df":3,"docs":{"200":{"tf":1.0},"236":{"tf":1.0},"66":{"tf":1.0}}},"o":{"c":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"218":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"146":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"23":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":1,"docs":{"23":{"tf":1.4142135623730951}}}},"o":{"df":0,"docs":{},"v":{"df":4,"docs":{"219":{"tf":1.0},"223":{"tf":1.0},"49":{"tf":1.0},"82":{"tf":1.0}}}}},"n":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"135":{"tf":1.0},"167":{"tf":1.0},"179":{"tf":1.0},"97":{"tf":1.0},"99":{"tf":1.0}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"106":{"tf":1.0},"147":{"tf":1.0},"175":{"tf":1.0},"98":{"tf":1.0}}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"99":{"tf":1.0}}}}}},"l":{"a":{"c":{"df":6,"docs":{"234":{"tf":1.4142135623730951},"75":{"tf":1.0},"83":{"tf":1.0},"85":{"tf":1.0},"86":{"tf":1.0},"91":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"df":1,"docs":{"90":{"tf":1.0}},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"224":{"tf":1.0}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"54":{"tf":1.0},"63":{"tf":1.0}}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":1,"docs":{"52":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"66":{"tf":1.0},"67":{"tf":1.0},"73":{"tf":1.0}}}}}}},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":2,"docs":{"68":{"tf":1.7320508075688772},"89":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"q":{"df":0,"docs":{},"u":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":4,"docs":{"18":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.7320508075688772},"63":{"tf":1.7320508075688772}}}}},"i":{"df":0,"docs":{},"r":{"df":13,"docs":{"18":{"tf":1.0},"218":{"tf":1.0},"219":{"tf":1.0},"221":{"tf":1.0},"226":{"tf":1.0},"53":{"tf":1.0},"54":{"tf":1.0},"6":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"71":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":1,"docs":{"90":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{".":{"df":0,"docs":{},"j":{"df":1,"docs":{"225":{"tf":1.0}}}},"_":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"_":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"b":{"df":1,"docs":{"94":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"94":{"tf":1.0}}}},"df":0,"docs":{}}},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"94":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"=":{"1":{"df":3,"docs":{"73":{"tf":1.0},"89":{"tf":1.0},"94":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"94":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}}}}},"df":28,"docs":{"10":{"tf":1.0},"11":{"tf":1.7320508075688772},"12":{"tf":1.0},"18":{"tf":2.0},"19":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"226":{"tf":1.0},"23":{"tf":1.4142135623730951},"232":{"tf":1.0},"234":{"tf":1.4142135623730951},"236":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"29":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.4142135623730951},"4":{"tf":2.0},"5":{"tf":2.0},"50":{"tf":1.0},"6":{"tf":1.0},"61":{"tf":1.4142135623730951},"67":{"tf":1.7320508075688772},"68":{"tf":1.4142135623730951},"7":{"tf":1.4142135623730951},"71":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}},"v":{"df":6,"docs":{"170":{"tf":1.0},"171":{"tf":1.0},"173":{"tf":1.0},"18":{"tf":1.0},"186":{"tf":1.0},"191":{"tf":1.0}},"e":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"94":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"138":{"tf":1.0},"146":{"tf":1.0},"161":{"tf":1.0},"175":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"t":{"df":2,"docs":{"32":{"tf":1.0},"98":{"tf":1.0}},"r":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"233":{"tf":1.0},"41":{"tf":1.0},"46":{"tf":1.0}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"(":{"df":1,"docs":{"189":{"tf":1.4142135623730951}}},"df":113,"docs":{"103":{"tf":1.4142135623730951},"107":{"tf":1.4142135623730951},"108":{"tf":1.4142135623730951},"109":{"tf":1.7320508075688772},"110":{"tf":1.7320508075688772},"111":{"tf":1.7320508075688772},"112":{"tf":1.7320508075688772},"113":{"tf":1.4142135623730951},"114":{"tf":1.4142135623730951},"115":{"tf":1.7320508075688772},"116":{"tf":1.4142135623730951},"117":{"tf":2.23606797749979},"118":{"tf":1.4142135623730951},"119":{"tf":1.4142135623730951},"120":{"tf":1.4142135623730951},"121":{"tf":1.4142135623730951},"122":{"tf":1.7320508075688772},"123":{"tf":1.4142135623730951},"124":{"tf":1.4142135623730951},"125":{"tf":1.4142135623730951},"126":{"tf":1.4142135623730951},"127":{"tf":1.4142135623730951},"128":{"tf":1.7320508075688772},"129":{"tf":1.4142135623730951},"130":{"tf":1.4142135623730951},"131":{"tf":1.4142135623730951},"132":{"tf":1.4142135623730951},"133":{"tf":1.4142135623730951},"134":{"tf":1.4142135623730951},"135":{"tf":1.4142135623730951},"136":{"tf":1.4142135623730951},"137":{"tf":1.4142135623730951},"138":{"tf":1.4142135623730951},"139":{"tf":1.4142135623730951},"140":{"tf":1.4142135623730951},"141":{"tf":1.4142135623730951},"142":{"tf":1.4142135623730951},"143":{"tf":1.4142135623730951},"144":{"tf":1.4142135623730951},"145":{"tf":1.4142135623730951},"146":{"tf":1.4142135623730951},"147":{"tf":1.7320508075688772},"148":{"tf":1.4142135623730951},"149":{"tf":1.4142135623730951},"150":{"tf":1.4142135623730951},"151":{"tf":1.4142135623730951},"152":{"tf":1.4142135623730951},"153":{"tf":1.4142135623730951},"154":{"tf":1.4142135623730951},"155":{"tf":1.4142135623730951},"156":{"tf":1.7320508075688772},"157":{"tf":1.4142135623730951},"158":{"tf":1.4142135623730951},"159":{"tf":1.4142135623730951},"160":{"tf":1.4142135623730951},"161":{"tf":1.7320508075688772},"162":{"tf":1.4142135623730951},"163":{"tf":1.4142135623730951},"164":{"tf":1.4142135623730951},"165":{"tf":1.4142135623730951},"166":{"tf":1.7320508075688772},"167":{"tf":1.4142135623730951},"168":{"tf":1.4142135623730951},"169":{"tf":1.4142135623730951},"170":{"tf":1.4142135623730951},"171":{"tf":1.4142135623730951},"172":{"tf":1.4142135623730951},"173":{"tf":1.4142135623730951},"174":{"tf":1.4142135623730951},"176":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"178":{"tf":1.4142135623730951},"179":{"tf":1.4142135623730951},"180":{"tf":1.7320508075688772},"181":{"tf":1.4142135623730951},"183":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"185":{"tf":1.4142135623730951},"186":{"tf":1.4142135623730951},"187":{"tf":1.4142135623730951},"189":{"tf":1.4142135623730951},"190":{"tf":1.7320508075688772},"191":{"tf":1.4142135623730951},"193":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"195":{"tf":1.4142135623730951},"196":{"tf":1.4142135623730951},"197":{"tf":1.4142135623730951},"198":{"tf":1.4142135623730951},"199":{"tf":1.4142135623730951},"201":{"tf":2.0},"202":{"tf":1.7320508075688772},"203":{"tf":1.7320508075688772},"204":{"tf":1.7320508075688772},"205":{"tf":2.0},"206":{"tf":1.7320508075688772},"207":{"tf":1.4142135623730951},"209":{"tf":1.4142135623730951},"210":{"tf":1.4142135623730951},"211":{"tf":1.4142135623730951},"212":{"tf":1.4142135623730951},"213":{"tf":1.4142135623730951},"214":{"tf":1.4142135623730951},"215":{"tf":1.4142135623730951},"216":{"tf":1.4142135623730951},"223":{"tf":1.7320508075688772},"69":{"tf":1.0},"76":{"tf":1.0},"84":{"tf":1.0},"88":{"tf":1.0},"92":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":1.0}}}}}},"t":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":4,"docs":{"201":{"tf":1.7320508075688772},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0}}}}}}}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":4,"docs":{"201":{"tf":1.7320508075688772},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0}}}}}}}}},"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"235":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.4142135623730951}}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"209":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"209":{"tf":1.0}}},"df":0,"docs":{}}},"_":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"198":{"tf":1.0}}}}},"df":0,"docs":{}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":2,"docs":{"100":{"tf":1.0},"185":{"tf":1.0}}},"y":{"(":{"$":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"185":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"185":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":3,"docs":{"100":{"tf":1.0},"182":{"tf":1.0},"46":{"tf":1.0}},"s":{"df":2,"docs":{"100":{"tf":1.0},"161":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":34,"docs":{"100":{"tf":1.0},"102":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"132":{"tf":1.0},"134":{"tf":1.4142135623730951},"159":{"tf":1.0},"161":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"174":{"tf":2.0},"185":{"tf":1.7320508075688772},"190":{"tf":1.0},"198":{"tf":2.23606797749979},"201":{"tf":1.7320508075688772},"208":{"tf":1.0},"209":{"tf":2.23606797749979},"210":{"tf":1.0},"211":{"tf":1.0},"35":{"tf":1.0},"38":{"tf":1.0},"41":{"tf":1.0},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"51":{"tf":2.449489742783178},"78":{"tf":1.7320508075688772},"82":{"tf":1.0},"87":{"tf":1.0},"93":{"tf":1.0}},"s":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"(":{"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"174":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}},"v":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"91":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"210":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"210":{"tf":1.0}}},"df":0,"docs":{}}},"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"201":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"98":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":20,"docs":{"100":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"175":{"tf":1.0},"185":{"tf":1.4142135623730951},"204":{"tf":1.4142135623730951},"208":{"tf":1.4142135623730951},"210":{"tf":2.23606797749979},"212":{"tf":1.0},"214":{"tf":1.4142135623730951},"215":{"tf":1.4142135623730951},"216":{"tf":1.4142135623730951},"46":{"tf":1.0},"57":{"tf":1.0},"75":{"tf":1.4142135623730951},"79":{"tf":1.0},"86":{"tf":2.23606797749979},"87":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"65":{"tf":1.0}}}},"v":{"df":39,"docs":{"0":{"tf":1.7320508075688772},"10":{"tf":1.0},"180":{"tf":1.0},"217":{"tf":1.7320508075688772},"219":{"tf":1.0},"220":{"tf":2.23606797749979},"221":{"tf":1.0},"223":{"tf":2.8284271247461903},"224":{"tf":1.7320508075688772},"226":{"tf":1.7320508075688772},"235":{"tf":1.4142135623730951},"24":{"tf":1.0},"3":{"tf":1.0},"34":{"tf":1.0},"37":{"tf":1.0},"40":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":2.23606797749979},"46":{"tf":1.0},"5":{"tf":2.0},"50":{"tf":1.0},"52":{"tf":1.0},"53":{"tf":1.7320508075688772},"54":{"tf":1.7320508075688772},"55":{"tf":1.4142135623730951},"56":{"tf":1.0},"57":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.0},"6":{"tf":1.0},"62":{"tf":1.4142135623730951},"65":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":2.23606797749979},"71":{"tf":1.0},"89":{"tf":1.0},"9":{"tf":1.4142135623730951}},"e":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"=":{"$":{"df":0,"docs":{},"{":{"df":0,"docs":{},"p":{"df":0,"docs":{},"w":{"d":{"df":0,"docs":{},"}":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"226":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":1,"docs":{"226":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"235":{"tf":1.0}}}}}}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"91":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"235":{"tf":1.0},"76":{"tf":1.0}}}}}}},"h":{"df":22,"docs":{"109":{"tf":1.7320508075688772},"110":{"tf":1.7320508075688772},"111":{"tf":1.7320508075688772},"112":{"tf":1.4142135623730951},"113":{"tf":1.4142135623730951},"114":{"tf":1.4142135623730951},"115":{"tf":1.4142135623730951},"116":{"tf":2.0},"117":{"tf":1.4142135623730951},"118":{"tf":1.4142135623730951},"119":{"tf":1.4142135623730951},"120":{"tf":1.4142135623730951},"121":{"tf":1.4142135623730951},"122":{"tf":1.4142135623730951},"123":{"tf":1.7320508075688772},"124":{"tf":1.7320508075688772},"125":{"tf":1.4142135623730951},"126":{"tf":1.4142135623730951},"127":{"tf":1.7320508075688772},"128":{"tf":1.4142135623730951},"129":{"tf":1.4142135623730951},"99":{"tf":1.0}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":8,"docs":{"106":{"tf":1.0},"108":{"tf":1.0},"117":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.4142135623730951},"180":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.4142135623730951}}}}},"s":{"c":{"df":8,"docs":{"176":{"tf":1.0},"219":{"tf":1.4142135623730951},"52":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"a":{"d":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"p":{"df":3,"docs":{"235":{"tf":1.0},"236":{"tf":1.4142135623730951},"52":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"99":{"tf":1.0}}},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"49":{"tf":1.4142135623730951}}}}}},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"223":{"tf":1.0}}},"t":{"df":1,"docs":{"54":{"tf":1.0}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"236":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"90":{"tf":1.0},"91":{"tf":1.0}}}}}},"n":{"d":{"df":5,"docs":{"147":{"tf":1.0},"75":{"tf":1.4142135623730951},"78":{"tf":1.7320508075688772},"81":{"tf":1.0},"91":{"tf":1.0}}},"df":0,"docs":{}},"t":{"df":1,"docs":{"94":{"tf":1.0}}}},"w":{"df":1,"docs":{"98":{"tf":1.0}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":7,"docs":{"0":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"177":{"tf":1.0},"37":{"tf":1.4142135623730951},"61":{"tf":1.0},"63":{"tf":1.0}}}},"n":{"df":18,"docs":{"0":{"tf":1.0},"108":{"tf":1.0},"193":{"tf":1.4142135623730951},"194":{"tf":1.0},"195":{"tf":1.7320508075688772},"221":{"tf":1.0},"225":{"tf":1.0},"232":{"tf":1.0},"3":{"tf":1.0},"51":{"tf":1.0},"53":{"tf":1.4142135623730951},"56":{"tf":1.0},"61":{"tf":1.4142135623730951},"62":{"tf":1.0},"75":{"tf":2.0},"78":{"tf":1.0},"90":{"tf":1.0},"94":{"tf":1.0}},"g":{"df":1,"docs":{"103":{"tf":1.4142135623730951}}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":6,"docs":{"223":{"tf":2.449489742783178},"224":{"tf":1.4142135623730951},"53":{"tf":1.4142135623730951},"54":{"tf":1.4142135623730951},"56":{"tf":1.0},"57":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":14,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"186":{"tf":1.0},"217":{"tf":1.0},"220":{"tf":1.7320508075688772},"223":{"tf":1.0},"224":{"tf":1.0},"35":{"tf":2.0},"40":{"tf":1.0},"43":{"tf":1.4142135623730951},"53":{"tf":1.0},"55":{"tf":1.4142135623730951},"79":{"tf":1.0}},"e":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"57":{"tf":1.7320508075688772}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":1,"docs":{"57":{"tf":2.449489742783178}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"s":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"=":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"=":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":1,"docs":{"55":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"=":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":2,"docs":{"55":{"tf":1.0},"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}}},"df":1,"docs":{"55":{"tf":1.0}}}}}},"df":8,"docs":{"227":{"tf":1.4142135623730951},"235":{"tf":1.0},"52":{"tf":2.8284271247461903},"54":{"tf":1.0},"62":{"tf":1.7320508075688772},"64":{"tf":1.0},"71":{"tf":1.0},"97":{"tf":1.0}}}}},"v":{"6":{"4":{"df":0,"docs":{},"e":{"df":1,"docs":{"103":{"tf":1.0}},"m":{"a":{"c":{"b":{"df":1,"docs":{"71":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"x":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"81":{"tf":1.0},"82":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":4,"docs":{"105":{"tf":1.0},"236":{"tf":1.0},"52":{"tf":1.0},"91":{"tf":1.0}}}},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"206":{"tf":2.0}}}},"m":{"df":0,"docs":{},"e":{"df":26,"docs":{"107":{"tf":1.0},"108":{"tf":1.0},"122":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.4142135623730951},"174":{"tf":1.0},"177":{"tf":2.0},"18":{"tf":1.4142135623730951},"182":{"tf":1.0},"193":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":2.0},"204":{"tf":1.0},"206":{"tf":1.4142135623730951},"219":{"tf":1.0},"224":{"tf":1.0},"231":{"tf":1.0},"52":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"80":{"tf":1.0},"82":{"tf":1.0},"89":{"tf":1.0},"90":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}}},"n":{"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"x":{"df":3,"docs":{"219":{"tf":1.0},"223":{"tf":1.0},"53":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"122":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"122":{"tf":1.0}}}}}}},"v":{"0":{"df":1,"docs":{"122":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"122":{"tf":1.0}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"122":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":2,"docs":{"43":{"tf":1.0},"87":{"tf":1.0}}}}},"b":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":2,"docs":{"81":{"tf":1.0},"92":{"tf":1.4142135623730951}}}}},"c":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"d":{"df":2,"docs":{"90":{"tf":1.0},"91":{"tf":1.0}}},"df":0,"docs":{}}}}},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"235":{"tf":1.4142135623730951}}}}},"c":{"df":2,"docs":{"75":{"tf":1.0},"95":{"tf":1.0}}},"df":0,"docs":{},"f":{"df":1,"docs":{"76":{"tf":1.0}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":4,"docs":{"192":{"tf":1.4142135623730951},"199":{"tf":1.4142135623730951},"91":{"tf":1.0},"95":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"h":{"df":9,"docs":{"101":{"tf":1.0},"105":{"tf":1.7320508075688772},"138":{"tf":1.0},"166":{"tf":1.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.0},"216":{"tf":1.4142135623730951},"76":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":4,"docs":{"226":{"tf":1.0},"52":{"tf":1.0},"71":{"tf":1.0},"90":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"194":{"tf":1.7320508075688772}}}}}}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"113":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"113":{"tf":1.0}}},"df":0,"docs":{}},"x":{"df":1,"docs":{"113":{"tf":1.0}}}},"df":2,"docs":{"100":{"tf":1.0},"113":{"tf":1.0}}}},"k":{"df":1,"docs":{"52":{"tf":1.4142135623730951}}}},"df":1,"docs":{"12":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"(":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"m":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"52":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"43":{"tf":1.0}}}}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":7,"docs":{"130":{"tf":1.0},"131":{"tf":1.0},"139":{"tf":1.0},"149":{"tf":1.0},"215":{"tf":1.0},"236":{"tf":1.0},"32":{"tf":1.0}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":8,"docs":{"0":{"tf":1.0},"101":{"tf":1.0},"106":{"tf":1.0},"129":{"tf":1.0},"175":{"tf":1.0},"188":{"tf":1.0},"34":{"tf":1.4142135623730951},"99":{"tf":1.4142135623730951}}}}}},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"219":{"tf":1.0}}},"df":21,"docs":{"102":{"tf":1.4142135623730951},"108":{"tf":1.0},"11":{"tf":1.0},"129":{"tf":1.0},"139":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"161":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"189":{"tf":1.0},"22":{"tf":1.0},"230":{"tf":1.0},"231":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"54":{"tf":1.0},"69":{"tf":1.0},"76":{"tf":1.0}}},"g":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"104":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"186":{"tf":1.7320508075688772}}}}}}},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"176":{"tf":1.0},"31":{"tf":1.0},"33":{"tf":2.0},"78":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":8,"docs":{"193":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":2.0},"33":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951},"85":{"tf":1.0},"86":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{}},"f":{"b":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"100":{"tf":1.0},"157":{"tf":1.7320508075688772},"165":{"tf":1.0}}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"(":{"$":{"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"213":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"213":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"208":{"tf":1.0},"213":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}}}}},"df":1,"docs":{"97":{"tf":1.0}}}},"m":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":14,"docs":{"0":{"tf":1.0},"166":{"tf":1.0},"176":{"tf":1.0},"178":{"tf":1.0},"222":{"tf":1.0},"223":{"tf":1.0},"64":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.0},"74":{"tf":1.4142135623730951},"76":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.0},"98":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"203":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}}},"t":{"df":1,"docs":{"224":{"tf":1.0}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":5,"docs":{"104":{"tf":1.0},"129":{"tf":1.0},"166":{"tf":1.0},"215":{"tf":1.0},"76":{"tf":1.0}}}},"df":0,"docs":{}},"q":{"df":0,"docs":{},"u":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":6,"docs":{"181":{"tf":1.0},"75":{"tf":1.4142135623730951},"78":{"tf":1.0},"83":{"tf":1.0},"86":{"tf":1.0},"95":{"tf":1.0}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"v":{"df":1,"docs":{"132":{"tf":1.0}}}},"t":{"df":14,"docs":{"12":{"tf":1.0},"167":{"tf":1.0},"179":{"tf":1.0},"18":{"tf":1.0},"223":{"tf":1.4142135623730951},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"32":{"tf":1.4142135623730951},"33":{"tf":1.0},"70":{"tf":1.0},"89":{"tf":1.0},"94":{"tf":2.0}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"(":{"\\"":{"<":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"191":{"tf":1.0}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"n":{"df":1,"docs":{"191":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":3,"docs":{"100":{"tf":1.0},"172":{"tf":1.0},"191":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":1,"docs":{"30":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"28":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"29":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{".":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"26":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":1,"docs":{"27":{"tf":1.0}}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"s":{"df":1,"docs":{"27":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":1,"docs":{"27":{"tf":1.0}}}}}}}},"df":0,"docs":{}}}}}}}},"df":1,"docs":{"25":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"102":{"tf":1.0},"103":{"tf":1.0}}},"r":{"df":3,"docs":{"189":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.4142135623730951}}}}},"x":{"df":0,"docs":{},"t":{"<":{"df":0,"docs":{},"i":{"2":{"5":{"6":{">":{"(":{"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"137":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"<":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":3,"docs":{"100":{"tf":1.0},"129":{"tf":1.0},"137":{"tf":1.0}},"s":{">":{">":{"(":{"$":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"137":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"t":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"126":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"126":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"126":{"tf":1.0}}}},"h":{"a":{"1":{"df":2,"docs":{"89":{"tf":1.0},"90":{"tf":1.0}}},"df":1,"docs":{"90":{"tf":1.0}},"p":{"df":0,"docs":{},"e":{"df":9,"docs":{"122":{"tf":1.0},"177":{"tf":1.0},"182":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"206":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":5,"docs":{"67":{"tf":1.4142135623730951},"85":{"tf":1.0},"86":{"tf":1.4142135623730951},"87":{"tf":1.0},"92":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":4,"docs":{"120":{"tf":2.6457513110645907},"121":{"tf":2.23606797749979},"122":{"tf":2.6457513110645907},"216":{"tf":1.4142135623730951}}}}},"l":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"120":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"120":{"tf":1.0}}}}}}},"v":{"0":{"df":1,"docs":{"120":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"120":{"tf":1.0},"75":{"tf":1.0}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}},"df":3,"docs":{"180":{"tf":1.0},"219":{"tf":1.0},"98":{"tf":1.0}}}},"w":{"df":3,"docs":{"219":{"tf":1.0},"65":{"tf":1.0},"98":{"tf":1.4142135623730951}},"n":{"df":1,"docs":{"215":{"tf":1.0}}}}},"r":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"121":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"121":{"tf":1.0}}}}}}},"v":{"0":{"df":1,"docs":{"121":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0}}}},"i":{"d":{"df":0,"docs":{},"e":{"b":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"97":{"tf":1.0}}}},"df":0,"docs":{}},"df":11,"docs":{"106":{"tf":1.4142135623730951},"108":{"tf":1.0},"147":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"177":{"tf":1.0},"188":{"tf":1.4142135623730951},"189":{"tf":1.0},"76":{"tf":1.0},"81":{"tf":1.7320508075688772},"98":{"tf":1.0}},"’":{"df":1,"docs":{"189":{"tf":1.0}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":2,"docs":{"167":{"tf":1.0},"179":{"tf":1.0}}}}}},"df":8,"docs":{"113":{"tf":1.7320508075688772},"115":{"tf":2.0},"122":{"tf":1.7320508075688772},"125":{"tf":1.7320508075688772},"126":{"tf":1.7320508075688772},"129":{"tf":2.23606797749979},"137":{"tf":1.7320508075688772},"65":{"tf":1.0}},"e":{"d":{"df":1,"docs":{"127":{"tf":1.0}}},"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"129":{"tf":1.0}}}}},"b":{"df":1,"docs":{"129":{"tf":1.0}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"129":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"129":{"tf":1.0},"137":{"tf":1.0}}},"df":0,"docs":{}}}}}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"235":{"tf":1.0},"236":{"tf":1.0}}}}}}},"df":4,"docs":{"128":{"tf":1.4142135623730951},"129":{"tf":1.0},"235":{"tf":1.0},"86":{"tf":1.0}}},"df":0,"docs":{}}}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":4,"docs":{"18":{"tf":1.0},"219":{"tf":1.0},"33":{"tf":1.0},"70":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"234":{"tf":1.0}}}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"l":{"df":5,"docs":{"18":{"tf":1.0},"221":{"tf":1.0},"223":{"tf":1.0},"69":{"tf":1.0},"93":{"tf":1.4142135623730951}},"i":{"df":1,"docs":{"223":{"tf":1.0}},"f":{"df":4,"docs":{"108":{"tf":1.0},"175":{"tf":1.0},"91":{"tf":1.0},"93":{"tf":1.4142135623730951}},"i":{"df":11,"docs":{"106":{"tf":1.0},"108":{"tf":1.4142135623730951},"146":{"tf":1.0},"147":{"tf":1.0},"174":{"tf":1.0},"18":{"tf":1.0},"223":{"tf":1.0},"75":{"tf":2.449489742783178},"76":{"tf":1.0},"86":{"tf":1.0},"98":{"tf":1.0}}},"y":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"104":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":16,"docs":{"128":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.4142135623730951},"169":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"208":{"tf":1.0},"214":{"tf":1.0},"219":{"tf":1.0},"235":{"tf":1.0},"29":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.4142135623730951},"53":{"tf":1.0},"81":{"tf":1.4142135623730951},"85":{"tf":1.0}}}}},"t":{"df":2,"docs":{"219":{"tf":1.0},"74":{"tf":1.0}},"e":{"df":6,"docs":{"185":{"tf":1.0},"195":{"tf":1.0},"208":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.4142135623730951},"87":{"tf":1.0}}}},"x":{"df":1,"docs":{"175":{"tf":1.0}}},"z":{"df":0,"docs":{},"e":{"df":22,"docs":{"0":{"tf":1.4142135623730951},"12":{"tf":1.7320508075688772},"13":{"tf":2.449489742783178},"14":{"tf":2.449489742783178},"162":{"tf":1.0},"163":{"tf":1.0},"166":{"tf":1.0},"171":{"tf":1.0},"233":{"tf":1.4142135623730951},"236":{"tf":1.0},"27":{"tf":2.0},"35":{"tf":1.4142135623730951},"39":{"tf":1.7320508075688772},"40":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"70":{"tf":1.4142135623730951},"74":{"tf":1.0},"81":{"tf":1.0},"93":{"tf":1.4142135623730951}}}}},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":4,"docs":{"111":{"tf":1.0},"197":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"(":{"$":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"167":{"tf":1.0}}}}}},"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"(":{"0":{"df":1,"docs":{"169":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"v":{"0":{"df":1,"docs":{"167":{"tf":1.0}}},"3":{"df":1,"docs":{"167":{"tf":1.0}}},"df":0,"docs":{}}},"df":6,"docs":{"100":{"tf":1.0},"167":{"tf":1.0},"169":{"tf":1.0},"75":{"tf":1.0},"84":{"tf":1.0},"95":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{},"p":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}},"t":{"df":19,"docs":{"104":{"tf":1.0},"105":{"tf":1.4142135623730951},"167":{"tf":2.449489742783178},"168":{"tf":1.4142135623730951},"169":{"tf":2.449489742783178},"178":{"tf":1.0},"179":{"tf":2.6457513110645907},"180":{"tf":1.7320508075688772},"181":{"tf":2.6457513110645907},"76":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":2.0},"83":{"tf":1.0},"84":{"tf":1.4142135623730951},"85":{"tf":1.0},"87":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":1.4142135623730951},"99":{"tf":1.0}}},"w":{"df":1,"docs":{"219":{"tf":1.7320508075688772}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"219":{"tf":1.0}}}}}},"t":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"125":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"125":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"125":{"tf":1.0}}}},"m":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":8,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"181":{"tf":1.0},"50":{"tf":1.0},"52":{"tf":1.0},"82":{"tf":1.0},"92":{"tf":1.0},"94":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"129":{"tf":1.0},"75":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"219":{"tf":1.0},"4":{"tf":1.0},"66":{"tf":1.0}}}}},"df":0,"docs":{},"o":{"d":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"115":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"115":{"tf":1.0}}},"df":0,"docs":{}},"x":{"df":1,"docs":{"115":{"tf":1.0}}}},"df":2,"docs":{"100":{"tf":1.0},"115":{"tf":1.0}}},"df":0,"docs":{}}},"n":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"90":{"tf":1.4142135623730951}}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"98":{"tf":1.0}}}}}}}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":4,"docs":{"52":{"tf":1.0},"59":{"tf":1.0},"65":{"tf":1.0},"78":{"tf":1.0}}}},"df":0,"docs":{}}}},"l":{"c":{"df":21,"docs":{"11":{"tf":1.0},"15":{"tf":2.0},"18":{"tf":2.23606797749979},"222":{"tf":1.0},"223":{"tf":1.0},"229":{"tf":1.0},"232":{"tf":1.0},"234":{"tf":1.4142135623730951},"236":{"tf":1.0},"24":{"tf":1.0},"33":{"tf":1.0},"39":{"tf":1.0},"50":{"tf":1.7320508075688772},"6":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.0},"68":{"tf":1.4142135623730951},"72":{"tf":1.4142135623730951},"73":{"tf":1.0},"74":{"tf":1.0},"8":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":1,"docs":{"65":{"tf":1.0}}},"i":{"d":{"df":40,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.4142135623730951},"169":{"tf":1.0},"18":{"tf":2.23606797749979},"181":{"tf":1.0},"202":{"tf":1.0},"208":{"tf":1.0},"21":{"tf":1.4142135623730951},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"22":{"tf":1.0},"222":{"tf":1.7320508075688772},"223":{"tf":1.7320508075688772},"229":{"tf":1.0},"232":{"tf":1.0},"235":{"tf":2.0},"236":{"tf":1.4142135623730951},"3":{"tf":1.0},"34":{"tf":1.4142135623730951},"36":{"tf":1.4142135623730951},"39":{"tf":1.0},"4":{"tf":2.0},"43":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.7320508075688772},"6":{"tf":1.7320508075688772},"60":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.7320508075688772},"67":{"tf":1.4142135623730951},"72":{"tf":1.0},"74":{"tf":1.0},"79":{"tf":1.0},"8":{"tf":1.0},"81":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0},"85":{"tf":1.0},"86":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"y":{"df":0,"docs":{},"’":{"df":2,"docs":{"79":{"tf":1.0},"90":{"tf":1.0}}}}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"52":{"tf":1.0}}},"i":{"df":0,"docs":{},"m":{"df":4,"docs":{"53":{"tf":1.0},"55":{"tf":1.0},"62":{"tf":1.0},"92":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"106":{"tf":1.0},"219":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"n":{"d":{"df":2,"docs":{"82":{"tf":1.4142135623730951},"91":{"tf":1.0}}},"df":0,"docs":{}},"r":{"c":{"df":44,"docs":{"10":{"tf":1.0},"107":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"135":{"tf":1.4142135623730951},"136":{"tf":1.0},"137":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"17":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.4142135623730951},"174":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.7320508075688772},"179":{"tf":1.0},"18":{"tf":1.0},"182":{"tf":1.4142135623730951},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.4142135623730951},"187":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"201":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"221":{"tf":1.0},"226":{"tf":1.0},"236":{"tf":1.0},"33":{"tf":1.4142135623730951},"54":{"tf":1.0},"59":{"tf":1.0},"67":{"tf":1.4142135623730951},"80":{"tf":1.0},"98":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"a":{"c":{"df":0,"docs":{},"e":{"df":8,"docs":{"101":{"tf":1.0},"102":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"13":{"tf":1.4142135623730951},"138":{"tf":1.0},"74":{"tf":1.0},"76":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"df":2,"docs":{"223":{"tf":1.4142135623730951},"224":{"tf":1.4142135623730951}},"i":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"138":{"tf":1.0},"71":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":13,"docs":{"194":{"tf":1.0},"219":{"tf":1.0},"223":{"tf":1.4142135623730951},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"32":{"tf":2.449489742783178},"33":{"tf":1.0},"52":{"tf":1.0},"71":{"tf":1.0},"73":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}},"i":{"df":4,"docs":{"137":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"30":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"d":{"df":3,"docs":{"1":{"tf":1.0},"219":{"tf":1.4142135623730951},"235":{"tf":1.0}}},"df":0,"docs":{}}}},"q":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"193":{"tf":1.0}}}},"df":0,"docs":{}}},"r":{"c":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"/":{"b":{"a":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{":":{"b":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":1,"docs":{"178":{"tf":2.0}}},"df":0,"docs":{}},"s":{"a":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":12,"docs":{"106":{"tf":1.0},"108":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.4142135623730951},"195":{"tf":1.7320508075688772},"214":{"tf":1.0},"215":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.4142135623730951},"99":{"tf":1.4142135623730951}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"(":{"$":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"179":{"tf":1.0}}}}}},"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"(":{"0":{"df":1,"docs":{"181":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"v":{"0":{"df":1,"docs":{"179":{"tf":1.0}}},"1":{"df":3,"docs":{"193":{"tf":1.0},"194":{"tf":1.4142135623730951},"195":{"tf":1.0}}},"2":{"df":1,"docs":{"179":{"tf":1.0}}},"3":{"df":1,"docs":{"199":{"tf":1.0}}},"df":0,"docs":{}}},"df":8,"docs":{"100":{"tf":1.0},"167":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"75":{"tf":1.0},"84":{"tf":1.0},"95":{"tf":1.0}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":3,"docs":{"220":{"tf":1.0},"91":{"tf":1.0},"97":{"tf":1.0}}}},"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"13":{"tf":1.0}}}}}},"df":9,"docs":{"0":{"tf":1.0},"104":{"tf":1.4142135623730951},"13":{"tf":2.6457513110645907},"222":{"tf":1.0},"223":{"tf":1.0},"27":{"tf":1.4142135623730951},"72":{"tf":1.0},"74":{"tf":1.4142135623730951},"76":{"tf":1.0}}}},"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"223":{"tf":1.0}}}}},"r":{"d":{"df":8,"docs":{"201":{"tf":1.0},"203":{"tf":1.0},"24":{"tf":1.4142135623730951},"55":{"tf":1.0},"62":{"tf":1.0},"68":{"tf":1.0},"73":{"tf":1.0},"80":{"tf":1.0}}},"df":0,"docs":{}}},"df":1,"docs":{"99":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":11,"docs":{"138":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"195":{"tf":1.0},"229":{"tf":1.0},"58":{"tf":1.0},"60":{"tf":1.0},"76":{"tf":1.0},"94":{"tf":1.0}},"u":{"df":0,"docs":{},"p":{"df":3,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"219":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":10,"docs":{"175":{"tf":1.0},"200":{"tf":1.0},"204":{"tf":1.4142135623730951},"210":{"tf":1.0},"219":{"tf":1.0},"223":{"tf":1.4142135623730951},"51":{"tf":1.4142135623730951},"56":{"tf":1.0},"68":{"tf":1.0},"93":{"tf":1.4142135623730951}},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{":":{":":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"199":{"tf":1.0}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"k":{"df":1,"docs":{"196":{"tf":1.0}}}},"df":0,"docs":{}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"187":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"183":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":1,"docs":{"197":{"tf":1.0}}}}}}}},"r":{"df":3,"docs":{"190":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0}}},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"216":{"tf":1.0}}}}}}}}}}}}}}}}}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"186":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"215":{"tf":1.0}}}}}}}}}}}}}}}}}},"x":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"190":{"tf":1.0}}}}}}},"t":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"184":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"l":{"c":{"a":{"df":0,"docs":{},"l":{"df":5,"docs":{"190":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"195":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"f":{"df":1,"docs":{"193":{"tf":1.0}}},"n":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"212":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"l":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"v":{"df":1,"docs":{"198":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":1,"docs":{"189":{"tf":1.0}}}},"o":{"df":0,"docs":{},"g":{"df":1,"docs":{"207":{"tf":1.0}}}}},"m":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"181":{"tf":1.0}}}}}}}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"178":{"tf":1.0}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"176":{"tf":1.0}},"e":{"8":{"df":1,"docs":{"177":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"p":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"214":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"185":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":1,"docs":{"209":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"210":{"tf":1.0}}}}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"213":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"191":{"tf":1.0}}}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"179":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"211":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"194":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"180":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"df":25,"docs":{"100":{"tf":1.0},"102":{"tf":1.0},"106":{"tf":1.0},"147":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"178":{"tf":1.0},"181":{"tf":1.4142135623730951},"188":{"tf":1.4142135623730951},"189":{"tf":1.7320508075688772},"190":{"tf":2.0},"192":{"tf":1.4142135623730951},"193":{"tf":1.4142135623730951},"194":{"tf":1.0},"195":{"tf":1.4142135623730951},"198":{"tf":1.0},"199":{"tf":1.0},"200":{"tf":1.0},"208":{"tf":1.0},"214":{"tf":1.0},"76":{"tf":1.4142135623730951},"93":{"tf":1.0},"95":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.4142135623730951}},"’":{"df":2,"docs":{"169":{"tf":1.0},"181":{"tf":1.0}}}}}}}},"i":{"c":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":4,"docs":{"167":{"tf":1.0},"169":{"tf":1.0},"179":{"tf":1.0},"181":{"tf":1.0}}}}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"100":{"tf":1.0},"204":{"tf":1.0}},"l":{"(":{"$":{"df":0,"docs":{},"g":{"a":{"df":1,"docs":{"204":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"204":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":14,"docs":{"14":{"tf":1.0},"168":{"tf":1.0},"178":{"tf":1.0},"180":{"tf":1.0},"225":{"tf":1.0},"68":{"tf":1.0},"70":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.0},"80":{"tf":1.0},"93":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":1.4142135623730951},"99":{"tf":1.0}}},"df":0,"docs":{}}}},"d":{"df":1,"docs":{"18":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":1,"docs":{"94":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":3,"docs":{"223":{"tf":1.0},"67":{"tf":1.0},"75":{"tf":1.4142135623730951}}}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":3,"docs":{"18":{"tf":1.0},"204":{"tf":1.0},"213":{"tf":1.0}}}}},"o":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"p":{"df":3,"docs":{"100":{"tf":1.0},"208":{"tf":1.0},"211":{"tf":1.7320508075688772}}},"r":{"a":{"df":0,"docs":{},"g":{"df":25,"docs":{"100":{"tf":1.4142135623730951},"104":{"tf":1.4142135623730951},"167":{"tf":1.4142135623730951},"168":{"tf":1.7320508075688772},"169":{"tf":1.4142135623730951},"175":{"tf":1.7320508075688772},"178":{"tf":1.0},"179":{"tf":1.4142135623730951},"180":{"tf":1.7320508075688772},"181":{"tf":1.4142135623730951},"188":{"tf":1.0},"200":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"213":{"tf":1.0},"223":{"tf":1.0},"76":{"tf":1.7320508075688772},"83":{"tf":1.0},"84":{"tf":1.4142135623730951},"85":{"tf":1.0},"87":{"tf":1.4142135623730951},"90":{"tf":1.0},"92":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}},"e":{"a":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"78":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"’":{"df":1,"docs":{"180":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":15,"docs":{"104":{"tf":1.0},"105":{"tf":1.4142135623730951},"176":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"179":{"tf":1.0},"180":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"191":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.4142135623730951},"75":{"tf":1.0},"81":{"tf":1.7320508075688772},"82":{"tf":1.7320508075688772},"93":{"tf":1.0},"95":{"tf":1.0}}}}},"r":{"a":{"d":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"178":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":2,"docs":{"227":{"tf":1.0},"7":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":3,"docs":{"221":{"tf":1.4142135623730951},"224":{"tf":1.4142135623730951},"78":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":3,"docs":{"52":{"tf":1.0},"75":{"tf":1.0},"95":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":9,"docs":{"170":{"tf":2.0},"171":{"tf":1.4142135623730951},"172":{"tf":1.4142135623730951},"173":{"tf":1.4142135623730951},"18":{"tf":1.0},"191":{"tf":1.7320508075688772},"215":{"tf":2.23606797749979},"64":{"tf":1.0},"99":{"tf":1.0}}}},"p":{"df":2,"docs":{"53":{"tf":1.0},"90":{"tf":1.0}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"37":{"tf":1.0},"43":{"tf":1.0},"69":{"tf":1.0}}}}}}},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":10,"docs":{"100":{"tf":1.0},"18":{"tf":1.0},"192":{"tf":1.4142135623730951},"195":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.7320508075688772},"91":{"tf":1.4142135623730951},"93":{"tf":1.4142135623730951},"95":{"tf":1.0},"98":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}},"u":{"d":{"df":0,"docs":{},"i":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}},"y":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":2,"docs":{"64":{"tf":1.0},"65":{"tf":1.0}}}}}},"u":{"b":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"110":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"110":{"tf":1.0}}},"df":0,"docs":{}}},"df":5,"docs":{"100":{"tf":1.0},"110":{"tf":1.0},"161":{"tf":1.0},"185":{"tf":1.0},"78":{"tf":1.0}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"63":{"tf":1.4142135623730951},"65":{"tf":1.0}}}}},"o":{"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"75":{"tf":1.4142135623730951},"91":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":1,"docs":{"179":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}},"t":{"df":0,"docs":{},"l":{"df":1,"docs":{"81":{"tf":1.0}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"110":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":7,"docs":{"20":{"tf":1.0},"201":{"tf":1.7320508075688772},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0}},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"209":{"tf":1.0},"211":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"219":{"tf":1.0}}}}}}}},"df":0,"docs":{},"h":{"df":5,"docs":{"33":{"tf":1.4142135623730951},"52":{"tf":1.0},"64":{"tf":1.0},"85":{"tf":1.0},"98":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":3,"docs":{"18":{"tf":1.0},"65":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{},"x":{"df":5,"docs":{"107":{"tf":1.0},"174":{"tf":1.0},"207":{"tf":1.4142135623730951},"98":{"tf":1.0},"99":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"224":{"tf":1.0},"90":{"tf":1.0}}}},"m":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"98":{"tf":1.0}}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"49":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":4,"docs":{"18":{"tf":1.0},"37":{"tf":1.0},"39":{"tf":1.0},"43":{"tf":1.4142135623730951}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":20,"docs":{"18":{"tf":1.0},"21":{"tf":1.0},"226":{"tf":1.4142135623730951},"229":{"tf":1.7320508075688772},"23":{"tf":1.0},"230":{"tf":1.4142135623730951},"231":{"tf":1.0},"232":{"tf":1.7320508075688772},"28":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"42":{"tf":1.0},"52":{"tf":1.4142135623730951},"68":{"tf":1.0},"7":{"tf":1.0},"80":{"tf":1.0},"95":{"tf":1.0},"97":{"tf":1.0}}}},"s":{"df":2,"docs":{"18":{"tf":1.0},"57":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":9,"docs":{"105":{"tf":1.0},"107":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"179":{"tf":1.0},"81":{"tf":1.0},"99":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.0}}},"f":{"a":{"c":{"df":3,"docs":{"169":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"92":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"147":{"tf":1.0}}},"df":0,"docs":{}}}}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"179":{"tf":1.0}}}}}}},"w":{"a":{"df":0,"docs":{},"p":{"df":10,"docs":{"104":{"tf":1.0},"105":{"tf":1.0},"176":{"tf":1.4142135623730951},"224":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":2.23606797749979},"82":{"tf":1.0},"84":{"tf":1.0},"87":{"tf":1.0},"95":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"h":{"df":5,"docs":{"100":{"tf":1.0},"192":{"tf":1.0},"194":{"tf":2.0},"76":{"tf":1.0},"93":{"tf":1.0}}}},"df":0,"docs":{}}}},"y":{"df":1,"docs":{"71":{"tf":1.0}},"m":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"x":{"df":109,"docs":{"107":{"tf":1.4142135623730951},"108":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.7320508075688772},"171":{"tf":1.7320508075688772},"172":{"tf":1.7320508075688772},"173":{"tf":1.7320508075688772},"174":{"tf":1.4142135623730951},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.7320508075688772},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.7320508075688772},"216":{"tf":1.4142135623730951},"76":{"tf":1.0},"96":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.4142135623730951},"99":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":1,"docs":{"107":{"tf":1.0}}}}}}},"s":{"c":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"220":{"tf":1.0},"57":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"91":{"tf":1.0}}}},"df":3,"docs":{"101":{"tf":1.0},"7":{"tf":1.0},"99":{"tf":1.0}}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"98":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":9,"docs":{"102":{"tf":1.0},"105":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"177":{"tf":1.4142135623730951},"178":{"tf":1.4142135623730951},"76":{"tf":1.0},"98":{"tf":1.4142135623730951},"99":{"tf":1.4142135623730951}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.0}},"e":{"d":{"df":3,"docs":{"75":{"tf":1.0},"80":{"tf":1.0},"94":{"tf":1.0}}},"df":0,"docs":{}}}}},"k":{"df":0,"docs":{},"e":{"df":7,"docs":{"115":{"tf":1.0},"18":{"tf":1.0},"182":{"tf":1.0},"193":{"tf":1.0},"224":{"tf":1.0},"66":{"tf":1.0},"99":{"tf":1.0}},"n":{"df":3,"docs":{"108":{"tf":1.0},"174":{"tf":1.0},"193":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":17,"docs":{"1":{"tf":1.0},"129":{"tf":1.0},"137":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"201":{"tf":1.4142135623730951},"217":{"tf":1.4142135623730951},"218":{"tf":1.4142135623730951},"219":{"tf":1.0},"220":{"tf":1.0},"222":{"tf":1.0},"225":{"tf":1.0},"226":{"tf":2.23606797749979},"4":{"tf":1.0},"68":{"tf":1.0},"71":{"tf":1.4142135623730951},"83":{"tf":1.0}}}}},"j":{"a":{"df":0,"docs":{},"n":{"df":2,"docs":{"75":{"tf":1.0},"95":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"52":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"105":{"tf":1.0}}}},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"99":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"66":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":12,"docs":{"100":{"tf":1.0},"208":{"tf":1.0},"209":{"tf":1.4142135623730951},"210":{"tf":1.4142135623730951},"211":{"tf":1.4142135623730951},"212":{"tf":1.4142135623730951},"213":{"tf":1.4142135623730951},"214":{"tf":1.4142135623730951},"215":{"tf":1.4142135623730951},"216":{"tf":1.4142135623730951},"79":{"tf":1.0},"98":{"tf":1.0}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":1,"docs":{"35":{"tf":1.0}}}}}}}}},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"130":{"tf":1.0},"131":{"tf":1.0}}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":11,"docs":{"221":{"tf":2.6457513110645907},"223":{"tf":3.4641016151377544},"224":{"tf":3.0},"226":{"tf":1.0},"51":{"tf":1.4142135623730951},"61":{"tf":1.4142135623730951},"63":{"tf":1.0},"82":{"tf":2.0},"89":{"tf":1.7320508075688772},"91":{"tf":1.0},"94":{"tf":1.0}},"s":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"z":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"90":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"x":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"96":{"tf":1.0},"97":{"tf":1.0}}}},"df":0,"docs":{}}}}},"h":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"k":{"df":2,"docs":{"224":{"tf":1.0},"4":{"tf":1.0}}}}},"df":1,"docs":{"128":{"tf":1.0}},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"92":{"tf":1.0}}}},"n":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"193":{"tf":1.0}}}}}}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"35":{"tf":1.0},"40":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}}}},"’":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":5,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"5":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.4142135623730951}}}},"r":{"d":{"df":2,"docs":{"20":{"tf":1.0},"64":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":3,"docs":{"101":{"tf":1.0},"11":{"tf":1.0},"18":{"tf":1.0}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"82":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"a":{"d":{"df":2,"docs":{"193":{"tf":1.0},"194":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":6,"docs":{"102":{"tf":1.0},"181":{"tf":1.0},"192":{"tf":1.0},"208":{"tf":1.4142135623730951},"216":{"tf":1.0},"91":{"tf":1.0}}},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"93":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":14,"docs":{"129":{"tf":1.0},"190":{"tf":1.0},"194":{"tf":1.4142135623730951},"195":{"tf":1.0},"199":{"tf":1.0},"207":{"tf":1.0},"223":{"tf":1.0},"67":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.0},"91":{"tf":2.0},"93":{"tf":1.0},"94":{"tf":1.0}}}}}}},"u":{"df":5,"docs":{"18":{"tf":1.0},"224":{"tf":1.0},"32":{"tf":1.0},"40":{"tf":1.0},"43":{"tf":1.0}},"m":{"b":{"df":1,"docs":{"61":{"tf":1.0}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"109":{"tf":1.0},"111":{"tf":1.0},"121":{"tf":1.0}}}},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"117":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}}}},"m":{"df":0,"docs":{},"e":{"df":20,"docs":{"107":{"tf":1.0},"12":{"tf":1.7320508075688772},"138":{"tf":1.0},"169":{"tf":1.0},"176":{"tf":1.4142135623730951},"18":{"tf":2.8284271247461903},"181":{"tf":1.0},"215":{"tf":1.4142135623730951},"216":{"tf":1.0},"219":{"tf":1.4142135623730951},"41":{"tf":1.0},"46":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"83":{"tf":1.4142135623730951},"86":{"tf":1.0},"99":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"236":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":2,"docs":{"100":{"tf":1.0},"149":{"tf":2.0}}}}},"df":0,"docs":{}}}}},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"224":{"tf":1.0}}}},"p":{"df":3,"docs":{"11":{"tf":1.0},"221":{"tf":1.0},"35":{"tf":1.0}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"(":{"$":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"168":{"tf":1.0}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"168":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"168":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"p":{"/":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"_":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"b":{"_":{"<":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{">":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":1,"docs":{"94":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"94":{"tf":1.0}}}}}}}}},"y":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"94":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"_":{"<":{"df":0,"docs":{},"o":{"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{">":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":1,"docs":{"94":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}}},"o":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":1,"docs":{"75":{"tf":1.0}}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"221":{"tf":1.0},"62":{"tf":1.0}}}}}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"99":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"l":{"df":7,"docs":{"18":{"tf":1.0},"20":{"tf":1.4142135623730951},"221":{"tf":1.0},"223":{"tf":1.4142135623730951},"233":{"tf":1.0},"52":{"tf":1.0},"65":{"tf":1.0}},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}}}},"p":{"df":1,"docs":{"105":{"tf":1.0}},"i":{"c":{"_":{"0":{"df":1,"docs":{"207":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"207":{"tf":2.23606797749979}}},"df":0,"docs":{}}},"t":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"13":{"tf":1.4142135623730951},"14":{"tf":1.0},"90":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"u":{"c":{"df":0,"docs":{},"h":{"df":3,"docs":{"105":{"tf":1.0},"147":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"113":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"r":{"a":{"c":{"df":0,"docs":{},"e":{"df":2,"docs":{"55":{"tf":2.0},"57":{"tf":3.0}}},"k":{"df":8,"docs":{"166":{"tf":1.0},"168":{"tf":1.0},"174":{"tf":1.0},"180":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.4142135623730951},"95":{"tf":1.0}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"13":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"83":{"tf":1.0}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"81":{"tf":1.0}}},"t":{"df":1,"docs":{"69":{"tf":1.0}}}},"n":{"df":0,"docs":{},"s":{"a":{"c":{"df":0,"docs":{},"t":{"df":7,"docs":{"143":{"tf":1.0},"158":{"tf":1.0},"168":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.4142135623730951},"224":{"tf":1.0},"43":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":1,"docs":{"155":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"201":{"tf":1.4142135623730951},"205":{"tf":1.4142135623730951},"213":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"198":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"168":{"tf":1.7320508075688772},"175":{"tf":1.0},"180":{"tf":2.23606797749979}}}}},"t":{"df":2,"docs":{"111":{"tf":1.0},"174":{"tf":1.0}}}},"l":{"a":{"df":0,"docs":{},"t":{"df":17,"docs":{"107":{"tf":1.0},"134":{"tf":1.4142135623730951},"176":{"tf":1.0},"177":{"tf":1.0},"180":{"tf":1.0},"190":{"tf":1.0},"198":{"tf":1.0},"219":{"tf":1.0},"230":{"tf":1.0},"34":{"tf":1.0},"36":{"tf":1.0},"39":{"tf":1.0},"43":{"tf":1.0},"47":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.4142135623730951},"95":{"tf":1.0}},"e":{"_":{"df":0,"docs":{},"y":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"o":{"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"94":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"p":{"a":{"df":0,"docs":{},"r":{"df":3,"docs":{"75":{"tf":1.0},"78":{"tf":1.0},"95":{"tf":1.0}}}},"df":0,"docs":{}}}},"p":{"df":9,"docs":{"0":{"tf":1.0},"112":{"tf":1.4142135623730951},"185":{"tf":1.0},"208":{"tf":1.0},"212":{"tf":1.0},"39":{"tf":1.0},"40":{"tf":1.0},"82":{"tf":1.4142135623730951},"92":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":10,"docs":{"113":{"tf":1.4142135623730951},"115":{"tf":1.4142135623730951},"122":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"129":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"185":{"tf":1.0},"97":{"tf":1.0}}}},"df":0,"docs":{},"e":{"df":2,"docs":{"69":{"tf":1.0},"75":{"tf":1.0}}}},"i":{"df":2,"docs":{"62":{"tf":1.0},"64":{"tf":1.0}},"p":{"df":2,"docs":{"81":{"tf":1.0},"91":{"tf":1.0}}},"v":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"70":{"tf":1.0}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"e":{"df":4,"docs":{"107":{"tf":1.0},"223":{"tf":1.4142135623730951},"235":{"tf":1.0},"82":{"tf":1.4142135623730951}}},"n":{"c":{"(":{"b":{",":{"df":0,"docs":{},"n":{"df":1,"docs":{"78":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"(":{"a":{",":{"b":{"df":1,"docs":{"78":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"a":{"df":0,"docs":{},"t":{"df":2,"docs":{"113":{"tf":1.0},"78":{"tf":1.0}},"e":{"<":{"df":0,"docs":{},"i":{"6":{"4":{">":{"(":{"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"135":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"8":{">":{"(":{"df":0,"docs":{},"v":{"1":{"df":1,"docs":{"135":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"<":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"100":{"tf":1.0},"135":{"tf":1.0}},"s":{">":{">":{"(":{"$":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"135":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":1,"docs":{"81":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"(":{"$":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"180":{"tf":1.0}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"180":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"168":{"tf":1.0},"180":{"tf":1.7320508075688772}}}}}}},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":3,"docs":{"75":{"tf":1.0},"91":{"tf":1.0},"95":{"tf":1.0}}}},"r":{"df":0,"docs":{},"n":{"df":2,"docs":{"219":{"tf":1.0},"91":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"111":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":16,"docs":{"103":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"200":{"tf":1.0},"207":{"tf":1.0},"208":{"tf":1.0},"214":{"tf":1.0},"43":{"tf":1.0},"50":{"tf":1.0},"6":{"tf":1.0},"74":{"tf":1.0},"79":{"tf":1.0},"81":{"tf":1.0},"83":{"tf":1.0},"95":{"tf":1.0},"97":{"tf":1.0}},"’":{"df":3,"docs":{"113":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"75":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}},"df":89,"docs":{"101":{"tf":1.4142135623730951},"102":{"tf":1.4142135623730951},"103":{"tf":1.4142135623730951},"107":{"tf":2.449489742783178},"108":{"tf":1.0},"109":{"tf":1.7320508075688772},"110":{"tf":1.7320508075688772},"111":{"tf":1.7320508075688772},"112":{"tf":1.7320508075688772},"113":{"tf":1.7320508075688772},"114":{"tf":1.7320508075688772},"115":{"tf":1.7320508075688772},"116":{"tf":1.7320508075688772},"117":{"tf":2.23606797749979},"118":{"tf":1.7320508075688772},"119":{"tf":1.7320508075688772},"120":{"tf":1.7320508075688772},"121":{"tf":1.7320508075688772},"122":{"tf":1.7320508075688772},"123":{"tf":1.7320508075688772},"124":{"tf":1.7320508075688772},"125":{"tf":1.7320508075688772},"126":{"tf":1.7320508075688772},"127":{"tf":1.7320508075688772},"128":{"tf":1.7320508075688772},"129":{"tf":1.7320508075688772},"130":{"tf":2.0},"131":{"tf":2.0},"132":{"tf":1.4142135623730951},"133":{"tf":1.4142135623730951},"134":{"tf":1.7320508075688772},"135":{"tf":1.4142135623730951},"136":{"tf":1.4142135623730951},"137":{"tf":1.4142135623730951},"138":{"tf":1.7320508075688772},"139":{"tf":1.7320508075688772},"140":{"tf":1.4142135623730951},"155":{"tf":1.4142135623730951},"156":{"tf":1.4142135623730951},"159":{"tf":1.4142135623730951},"163":{"tf":1.4142135623730951},"164":{"tf":1.4142135623730951},"165":{"tf":1.4142135623730951},"166":{"tf":1.4142135623730951},"167":{"tf":1.4142135623730951},"168":{"tf":1.4142135623730951},"169":{"tf":1.7320508075688772},"174":{"tf":2.449489742783178},"176":{"tf":1.7320508075688772},"177":{"tf":2.23606797749979},"178":{"tf":2.0},"179":{"tf":1.7320508075688772},"180":{"tf":1.7320508075688772},"181":{"tf":2.0},"183":{"tf":2.0},"184":{"tf":2.23606797749979},"185":{"tf":2.0},"186":{"tf":2.0},"187":{"tf":2.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.4142135623730951},"193":{"tf":1.7320508075688772},"194":{"tf":1.4142135623730951},"195":{"tf":1.0},"198":{"tf":1.7320508075688772},"201":{"tf":2.8284271247461903},"202":{"tf":2.6457513110645907},"203":{"tf":2.449489742783178},"204":{"tf":2.449489742783178},"205":{"tf":2.0},"206":{"tf":2.0},"207":{"tf":2.0},"209":{"tf":1.7320508075688772},"210":{"tf":1.7320508075688772},"213":{"tf":1.4142135623730951},"216":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":1.7320508075688772},"78":{"tf":1.7320508075688772},"79":{"tf":1.0},"87":{"tf":1.0},"91":{"tf":1.7320508075688772},"93":{"tf":1.7320508075688772},"95":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":2.449489742783178},"99":{"tf":2.449489742783178}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"93":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"i":{"c":{"df":8,"docs":{"103":{"tf":1.0},"108":{"tf":1.0},"177":{"tf":1.0},"181":{"tf":1.0},"186":{"tf":1.0},"190":{"tf":1.0},"219":{"tf":1.0},"86":{"tf":1.0}}},"df":0,"docs":{}}}}},"u":{"8":{"df":2,"docs":{"214":{"tf":1.4142135623730951},"215":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"51":{"tf":2.0}}}}},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"m":{"b":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"a":{"df":1,"docs":{"102":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"n":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":2,"docs":{"70":{"tf":1.0},"80":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"z":{"df":1,"docs":{"134":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":1,"docs":{"132":{"tf":1.0}}}}}}}},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"133":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}}},"c":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"193":{"tf":1.0}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"208":{"tf":1.0},"212":{"tf":1.0}}}}},"df":0,"docs":{}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"103":{"tf":1.0},"19":{"tf":1.0},"3":{"tf":1.0},"62":{"tf":1.0},"67":{"tf":1.0}},"f":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"110":{"tf":1.4142135623730951}}}}}},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"222":{"tf":1.0},"43":{"tf":1.0},"52":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"d":{"df":3,"docs":{"34":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"o":{"df":1,"docs":{"210":{"tf":1.0}}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"219":{"tf":1.0}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"235":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":1,"docs":{"23":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"224":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":2,"docs":{"102":{"tf":1.0},"221":{"tf":1.4142135623730951}},"i":{"df":1,"docs":{"56":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"7":{"tf":1.0}}}}}},"x":{"df":1,"docs":{"149":{"tf":1.0}}}},"k":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"n":{"df":5,"docs":{"105":{"tf":1.0},"166":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951}}}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"39":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"k":{"df":6,"docs":{"14":{"tf":1.0},"147":{"tf":1.0},"178":{"tf":1.0},"18":{"tf":1.0},"180":{"tf":1.0},"70":{"tf":1.0}}},"n":{"df":0,"docs":{},"k":{"df":1,"docs":{"18":{"tf":1.7320508075688772}}}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"212":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"l":{"df":1,"docs":{"81":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":4,"docs":{"112":{"tf":1.0},"114":{"tf":1.0},"123":{"tf":1.7320508075688772},"124":{"tf":1.7320508075688772}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"78":{"tf":1.0},"91":{"tf":1.0}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"63":{"tf":1.0}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"37":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"s":{"df":4,"docs":{"103":{"tf":1.0},"147":{"tf":1.0},"174":{"tf":1.0},"40":{"tf":1.0}}}},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"64":{"tf":1.0}}}},"df":0,"docs":{}}}},"p":{"d":{"a":{"df":0,"docs":{},"t":{"df":2,"docs":{"195":{"tf":1.0},"62":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":10,"docs":{"1":{"tf":1.0},"117":{"tf":1.0},"147":{"tf":1.0},"201":{"tf":1.0},"215":{"tf":1.0},"235":{"tf":1.0},"52":{"tf":1.0},"75":{"tf":1.7320508075688772},"78":{"tf":1.4142135623730951},"85":{"tf":1.0}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":6,"docs":{"103":{"tf":1.0},"110":{"tf":1.0},"129":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"177":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"m":{"df":3,"docs":{"63":{"tf":1.0},"71":{"tf":1.0},"98":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"s":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":4,"docs":{"11":{"tf":1.4142135623730951},"54":{"tf":1.4142135623730951},"57":{"tf":1.0},"70":{"tf":1.0}}}},"df":54,"docs":{"102":{"tf":1.0},"103":{"tf":1.0},"105":{"tf":1.0},"108":{"tf":1.0},"13":{"tf":1.7320508075688772},"14":{"tf":1.4142135623730951},"15":{"tf":1.0},"16":{"tf":1.0},"165":{"tf":1.0},"169":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":2.0},"186":{"tf":1.0},"199":{"tf":1.0},"202":{"tf":1.0},"212":{"tf":1.0},"216":{"tf":1.0},"219":{"tf":1.0},"221":{"tf":1.0},"225":{"tf":1.0},"226":{"tf":1.0},"232":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"40":{"tf":1.4142135623730951},"43":{"tf":1.7320508075688772},"48":{"tf":1.4142135623730951},"49":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.4142135623730951},"53":{"tf":1.0},"55":{"tf":1.0},"61":{"tf":1.4142135623730951},"64":{"tf":1.7320508075688772},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.4142135623730951},"70":{"tf":1.0},"71":{"tf":2.0},"75":{"tf":2.0},"78":{"tf":1.7320508075688772},"79":{"tf":1.0},"8":{"tf":1.0},"80":{"tf":2.449489742783178},"81":{"tf":1.4142135623730951},"82":{"tf":1.7320508075688772},"94":{"tf":1.4142135623730951},"97":{"tf":1.4142135623730951},"98":{"tf":1.0},"99":{"tf":1.4142135623730951}},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{":":{":":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}}}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"r":{"df":8,"docs":{"1":{"tf":1.0},"174":{"tf":1.0},"190":{"tf":1.0},"222":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.0},"70":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"108":{"tf":1.0},"18":{"tf":1.0},"43":{"tf":1.0},"53":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":2,"docs":{"223":{"tf":1.0},"224":{"tf":1.0}}}}}},"v":{"0":{".":{"8":{".":{"0":{"df":1,"docs":{"236":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"4":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":38,"docs":{"107":{"tf":1.0},"120":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"189":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.4142135623730951},"199":{"tf":1.7320508075688772},"216":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}},"1":{".":{"0":{".":{"0":{"df":1,"docs":{"236":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":72,"docs":{"107":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.4142135623730951},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.4142135623730951},"129":{"tf":1.4142135623730951},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"159":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.4142135623730951},"190":{"tf":1.0},"193":{"tf":1.7320508075688772},"195":{"tf":1.4142135623730951},"198":{"tf":1.4142135623730951},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.4142135623730951},"209":{"tf":1.0},"210":{"tf":1.0},"216":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}},"2":{"df":50,"docs":{"107":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"135":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":1.0},"178":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"193":{"tf":1.7320508075688772},"194":{"tf":1.0},"195":{"tf":1.0},"199":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0}}},"3":{"df":18,"docs":{"108":{"tf":1.0},"117":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"179":{"tf":1.0},"184":{"tf":1.0},"189":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.4142135623730951},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0}}},"4":{"df":7,"docs":{"174":{"tf":1.0},"189":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0}}},"5":{"df":10,"docs":{"108":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"189":{"tf":1.0},"193":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"206":{"tf":1.0}}},"6":{"df":3,"docs":{"193":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0}}},"7":{"df":3,"docs":{"193":{"tf":1.4142135623730951},"203":{"tf":1.0},"204":{"tf":1.0}}},"8":{"df":2,"docs":{"201":{"tf":1.0},"202":{"tf":1.0}}},"<":{"df":0,"docs":{},"i":{"d":{"df":3,"docs":{"100":{"tf":1.0},"108":{"tf":1.7320508075688772},"189":{"tf":1.0}}},"df":0,"docs":{}}},"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":11,"docs":{"12":{"tf":1.0},"156":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"219":{"tf":1.4142135623730951},"39":{"tf":1.0},"48":{"tf":1.0},"75":{"tf":1.4142135623730951},"79":{"tf":1.4142135623730951},"91":{"tf":1.0},"93":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"u":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"180":{"tf":1.0}}}},"df":0,"docs":{}},"df":66,"docs":{"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.7320508075688772},"104":{"tf":1.0},"106":{"tf":1.4142135623730951},"107":{"tf":1.4142135623730951},"108":{"tf":1.4142135623730951},"120":{"tf":1.7320508075688772},"121":{"tf":1.7320508075688772},"122":{"tf":2.23606797749979},"128":{"tf":1.0},"129":{"tf":1.7320508075688772},"13":{"tf":1.4142135623730951},"132":{"tf":1.0},"134":{"tf":1.4142135623730951},"135":{"tf":1.4142135623730951},"136":{"tf":1.4142135623730951},"137":{"tf":1.7320508075688772},"14":{"tf":1.4142135623730951},"142":{"tf":1.0},"151":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"172":{"tf":1.0},"174":{"tf":1.4142135623730951},"176":{"tf":1.7320508075688772},"177":{"tf":2.0},"179":{"tf":1.7320508075688772},"180":{"tf":1.4142135623730951},"181":{"tf":2.23606797749979},"188":{"tf":1.0},"189":{"tf":2.449489742783178},"190":{"tf":1.7320508075688772},"191":{"tf":1.7320508075688772},"192":{"tf":1.4142135623730951},"193":{"tf":2.449489742783178},"194":{"tf":3.0},"195":{"tf":3.0},"196":{"tf":1.7320508075688772},"197":{"tf":1.7320508075688772},"198":{"tf":1.4142135623730951},"201":{"tf":1.7320508075688772},"202":{"tf":1.0},"203":{"tf":2.0},"204":{"tf":1.4142135623730951},"205":{"tf":1.4142135623730951},"207":{"tf":1.0},"216":{"tf":1.4142135623730951},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"29":{"tf":1.0},"39":{"tf":1.0},"45":{"tf":1.0},"47":{"tf":1.0},"75":{"tf":1.7320508075688772},"76":{"tf":2.23606797749979},"78":{"tf":1.7320508075688772},"79":{"tf":2.0},"81":{"tf":1.4142135623730951},"82":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0},"87":{"tf":1.0},"89":{"tf":1.4142135623730951},"98":{"tf":1.7320508075688772},"99":{"tf":2.449489742783178}},"e":{"_":{"0":{"df":1,"docs":{"198":{"tf":1.0}}},"1":{"df":1,"docs":{"198":{"tf":1.0}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"d":{"(":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"57":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}},"y":{"df":0,"docs":{},"p":{"df":1,"docs":{"107":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{},"’":{"df":3,"docs":{"108":{"tf":1.0},"78":{"tf":1.0},"99":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":16,"docs":{"100":{"tf":1.0},"116":{"tf":1.0},"13":{"tf":1.0},"172":{"tf":1.0},"191":{"tf":1.0},"195":{"tf":2.0},"196":{"tf":1.0},"197":{"tf":1.0},"226":{"tf":1.0},"51":{"tf":1.4142135623730951},"55":{"tf":1.0},"64":{"tf":1.0},"73":{"tf":1.0},"80":{"tf":1.4142135623730951},"93":{"tf":1.4142135623730951},"94":{"tf":2.0}},"e":{"_":{"0":{"df":1,"docs":{"195":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":11,"docs":{"102":{"tf":1.4142135623730951},"103":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"138":{"tf":1.0},"190":{"tf":1.4142135623730951},"208":{"tf":1.0},"219":{"tf":1.0},"93":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}}}}},"df":2,"docs":{"12":{"tf":1.0},"40":{"tf":1.0}},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"223":{"tf":1.0}}}}}}},"df":11,"docs":{"106":{"tf":1.0},"108":{"tf":1.4142135623730951},"176":{"tf":1.0},"219":{"tf":1.4142135623730951},"52":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"99":{"tf":1.0}},"e":{"c":{"<":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"215":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"195":{"tf":1.0}}}},"df":0,"docs":{}},"w":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"h":{"c":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"194":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":8,"docs":{"174":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"198":{"tf":1.0},"207":{"tf":1.0},"216":{"tf":1.0}},"e":{"df":0,"docs":{},"i":{"d":{"df":2,"docs":{"189":{"tf":1.0},"195":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"98":{"tf":1.0}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}}}}},"df":0,"docs":{},"r":{"b":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"99":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":2,"docs":{"219":{"tf":1.0},"223":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":3,"docs":{"52":{"tf":1.0},"82":{"tf":1.0},"93":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":8,"docs":{"155":{"tf":1.0},"229":{"tf":2.0},"23":{"tf":1.0},"232":{"tf":2.0},"61":{"tf":1.0},"68":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.0}}}}}}}},"i":{"a":{"df":19,"docs":{"108":{"tf":1.0},"172":{"tf":1.0},"174":{"tf":1.4142135623730951},"191":{"tf":1.0},"194":{"tf":1.4142135623730951},"195":{"tf":1.0},"198":{"tf":1.0},"217":{"tf":1.0},"224":{"tf":1.0},"226":{"tf":1.4142135623730951},"50":{"tf":1.0},"51":{"tf":1.0},"63":{"tf":1.0},"68":{"tf":1.4142135623730951},"7":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"79":{"tf":1.0},"82":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"51":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"51":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"195":{"tf":1.0},"199":{"tf":1.0}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"235":{"tf":1.0}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"69":{"tf":1.0}}}},"df":1,"docs":{"69":{"tf":1.4142135623730951}}}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"67":{"tf":1.0}}}},"df":0,"docs":{}}}},"m":{"df":3,"docs":{"219":{"tf":1.4142135623730951},"43":{"tf":1.0},"52":{"tf":1.4142135623730951}}},"o":{"df":0,"docs":{},"i":{"d":{"df":2,"docs":{"102":{"tf":1.7320508075688772},"198":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"s":{"df":3,"docs":{"35":{"tf":1.0},"5":{"tf":1.0},"76":{"tf":1.0}}}},"w":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"97":{"tf":1.0}}}}}}}}}}},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"57":{"tf":1.0},"69":{"tf":1.0},"71":{"tf":1.0}}}},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"0":{"tf":1.0}}},"n":{"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"18":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":1.0}}}},"s":{"df":0,"docs":{},"m":{"df":4,"docs":{"219":{"tf":2.8284271247461903},"225":{"tf":1.0},"226":{"tf":1.7320508075688772},"7":{"tf":1.0}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"219":{"tf":1.4142135623730951}}}}}}},"y":{"df":4,"docs":{"194":{"tf":1.0},"221":{"tf":1.0},"227":{"tf":1.0},"32":{"tf":1.0}}}},"df":0,"docs":{},"e":{"b":{"3":{"df":1,"docs":{"235":{"tf":1.0}}},"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"219":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":1,"docs":{"235":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":5,"docs":{"142":{"tf":1.0},"157":{"tf":1.0},"165":{"tf":1.0},"201":{"tf":1.0},"205":{"tf":1.4142135623730951}},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}},"l":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"0":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"l":{"df":7,"docs":{"1":{"tf":1.0},"223":{"tf":1.0},"34":{"tf":1.0},"75":{"tf":1.0},"92":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.0}}}},"’":{"d":{"df":2,"docs":{"52":{"tf":1.0},"65":{"tf":1.0}}},"df":0,"docs":{}}},"h":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":5,"docs":{"167":{"tf":1.0},"179":{"tf":1.0},"62":{"tf":1.0},"82":{"tf":1.0},"94":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":1,"docs":{"32":{"tf":1.0}}},"df":0,"docs":{},"v":{"df":1,"docs":{"222":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"5":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":4,"docs":{"169":{"tf":1.0},"181":{"tf":1.0},"184":{"tf":1.0},"190":{"tf":1.4142135623730951}}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":1,"docs":{"135":{"tf":1.0}},"n":{"_":{"b":{"df":0,"docs":{},"y":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"(":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"x":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"109":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":11,"docs":{"136":{"tf":1.0},"138":{"tf":1.4142135623730951},"155":{"tf":1.0},"156":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"93":{"tf":1.0}}},"r":{"df":5,"docs":{"109":{"tf":1.0},"111":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.4142135623730951},"137":{"tf":1.4142135623730951}}}},"t":{"df":0,"docs":{},"h":{"(":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":4,"docs":{"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0}}}},"r":{"df":0,"docs":{},"h":{"df":7,"docs":{"109":{"tf":1.0},"111":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0}}}}},"df":24,"docs":{"100":{"tf":1.0},"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":2.23606797749979},"107":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"120":{"tf":1.0},"129":{"tf":1.4142135623730951},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":2.23606797749979},"136":{"tf":1.4142135623730951},"137":{"tf":2.0},"166":{"tf":1.0},"174":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951},"76":{"tf":1.0},"78":{"tf":1.4142135623730951},"82":{"tf":1.0},"95":{"tf":1.0},"98":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"12":{"tf":1.0}}}}},"df":0,"docs":{}},"l":{"d":{"c":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"32":{"tf":2.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":2,"docs":{"65":{"tf":1.0},"7":{"tf":1.0}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"e":{"df":2,"docs":{"168":{"tf":1.0},"180":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"104":{"tf":1.0},"93":{"tf":1.0}}}},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"170":{"tf":1.0},"171":{"tf":1.0},"178":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":11,"docs":{"104":{"tf":1.0},"105":{"tf":1.0},"106":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"180":{"tf":1.0},"192":{"tf":1.0},"199":{"tf":1.0},"76":{"tf":1.0},"90":{"tf":1.0},"93":{"tf":1.0}}}}}}},"z":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"’":{"df":1,"docs":{"235":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"d":{"0":{"df":2,"docs":{"139":{"tf":1.4142135623730951},"140":{"tf":1.4142135623730951}}},"1":{"df":1,"docs":{"139":{"tf":1.7320508075688772}}},"df":19,"docs":{"103":{"tf":1.0},"128":{"tf":1.7320508075688772},"129":{"tf":1.0},"133":{"tf":1.0},"139":{"tf":1.7320508075688772},"140":{"tf":1.4142135623730951},"166":{"tf":1.7320508075688772},"167":{"tf":1.0},"168":{"tf":1.0},"176":{"tf":1.7320508075688772},"179":{"tf":1.4142135623730951},"180":{"tf":1.4142135623730951},"215":{"tf":2.0},"5":{"tf":1.0},"64":{"tf":1.0},"74":{"tf":1.0},"78":{"tf":1.0},"82":{"tf":1.4142135623730951},"87":{"tf":1.0}}},"df":0,"docs":{},"k":{"df":9,"docs":{"0":{"tf":1.4142135623730951},"18":{"tf":1.4142135623730951},"234":{"tf":1.0},"43":{"tf":1.4142135623730951},"52":{"tf":1.0},"69":{"tf":1.0},"90":{"tf":1.0},"92":{"tf":1.0},"93":{"tf":1.0}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"219":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":1,"docs":{"62":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"l":{"d":{"df":3,"docs":{"11":{"tf":1.0},"74":{"tf":1.0},"90":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"39":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"98":{"tf":1.0}},"w":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"11":{"tf":1.0}}}}}}}}}},"r":{"a":{"df":0,"docs":{},"p":{"df":4,"docs":{"106":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"190":{"tf":1.0}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":6,"docs":{"100":{"tf":1.0},"188":{"tf":1.0},"190":{"tf":1.0},"223":{"tf":1.0},"71":{"tf":1.0},"87":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":25,"docs":{"100":{"tf":1.0},"138":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.4142135623730951},"175":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.4142135623730951},"179":{"tf":1.4142135623730951},"180":{"tf":1.0},"188":{"tf":1.0},"191":{"tf":1.0},"201":{"tf":1.0},"204":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"219":{"tf":1.0},"223":{"tf":1.0},"232":{"tf":1.0},"40":{"tf":1.0},"41":{"tf":1.0},"46":{"tf":1.0},"64":{"tf":1.0},"82":{"tf":1.0},"94":{"tf":1.4142135623730951},"97":{"tf":1.0}},"r":{"df":2,"docs":{"81":{"tf":1.0},"82":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":5,"docs":{"172":{"tf":1.0},"191":{"tf":1.0},"52":{"tf":1.4142135623730951},"66":{"tf":1.0},"80":{"tf":1.0}}}}}}}}},"x":{"8":{"6":{"df":1,"docs":{"219":{"tf":1.0}}},"df":0,"docs":{}},"df":2,"docs":{"128":{"tf":1.4142135623730951},"129":{"tf":1.4142135623730951}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"103":{"tf":1.0},"78":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"r":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"119":{"tf":1.0}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"133":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"v":{"0":{"df":1,"docs":{"119":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"119":{"tf":1.4142135623730951},"78":{"tf":1.0}}}},"y":{"df":2,"docs":{"231":{"tf":1.0},"233":{"tf":1.0}}}},"y":{"df":0,"docs":{},"e":{"df":1,"docs":{"230":{"tf":1.0}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"d":{"df":19,"docs":{"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"128":{"tf":1.0},"130":{"tf":1.4142135623730951},"131":{"tf":1.4142135623730951},"183":{"tf":1.0},"184":{"tf":1.4142135623730951},"187":{"tf":1.0},"189":{"tf":1.4142135623730951},"192":{"tf":1.0},"193":{"tf":2.6457513110645907},"194":{"tf":1.4142135623730951},"195":{"tf":2.449489742783178},"75":{"tf":1.0},"76":{"tf":1.0},"95":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"’":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"61":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"l":{"df":24,"docs":{"134":{"tf":1.4142135623730951},"16":{"tf":1.0},"174":{"tf":1.0},"178":{"tf":1.0},"190":{"tf":1.0},"198":{"tf":1.0},"22":{"tf":1.0},"230":{"tf":1.0},"34":{"tf":1.0},"39":{"tf":1.4142135623730951},"5":{"tf":1.0},"50":{"tf":1.0},"6":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.4142135623730951},"69":{"tf":1.7320508075688772},"72":{"tf":1.0},"73":{"tf":1.0},"74":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.4142135623730951},"95":{"tf":1.0}}}}},"z":{"df":1,"docs":{"12":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":19,"docs":{"103":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"121":{"tf":1.0},"134":{"tf":1.4142135623730951},"136":{"tf":1.0},"159":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.4142135623730951},"187":{"tf":1.0},"193":{"tf":1.4142135623730951},"195":{"tf":1.7320508075688772},"207":{"tf":1.0},"214":{"tf":1.4142135623730951},"216":{"tf":1.0},"82":{"tf":1.7320508075688772},"87":{"tf":1.0}}}},"x":{"df":0,"docs":{},"t":{"<":{"df":0,"docs":{},"i":{"2":{"5":{"6":{">":{"(":{"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"136":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"<":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"100":{"tf":1.0},"136":{"tf":1.0}},"s":{">":{">":{"(":{"$":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"136":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":1,"docs":{"81":{"tf":1.0}}}}},"k":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"breadcrumbs":{"root":{"0":{".":{"8":{".":{"0":{"df":1,"docs":{"229":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":28,"docs":{"112":{"tf":2.0},"113":{"tf":2.0},"114":{"tf":2.0},"115":{"tf":2.0},"12":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":2.0},"130":{"tf":2.0},"131":{"tf":2.0},"132":{"tf":1.4142135623730951},"134":{"tf":1.0},"156":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"201":{"tf":1.0},"205":{"tf":1.4142135623730951},"206":{"tf":1.0},"207":{"tf":1.0},"216":{"tf":1.0},"223":{"tf":1.0},"41":{"tf":1.0},"51":{"tf":1.4142135623730951},"57":{"tf":3.4641016151377544}},"x":{"0":{"0":{".":{".":{"0":{"df":0,"docs":{},"x":{"3":{"df":0,"docs":{},"f":{"df":1,"docs":{"176":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"105":{"tf":1.0}}},"1":{"df":1,"docs":{"214":{"tf":1.0}}},"8":{"c":{"3":{"7":{"9":{"a":{"0":{"df":1,"docs":{"215":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":4,"docs":{"167":{"tf":1.0},"179":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0}}},"1":{"1":{"df":1,"docs":{"214":{"tf":1.0}}},"2":{"df":1,"docs":{"214":{"tf":1.0}}},"df":4,"docs":{"107":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0}}},"2":{"1":{"df":1,"docs":{"82":{"tf":1.0}}},"a":{"df":1,"docs":{"107":{"tf":1.0}}},"df":0,"docs":{}},"3":{"2":{"df":1,"docs":{"214":{"tf":1.0}}},"df":0,"docs":{},"f":{"df":2,"docs":{"105":{"tf":1.0},"82":{"tf":1.0}}}},"4":{"0":{"df":3,"docs":{"105":{"tf":1.0},"176":{"tf":1.0},"82":{"tf":1.4142135623730951}}},"1":{"df":2,"docs":{"105":{"tf":1.0},"214":{"tf":1.0}}},"2":{"df":1,"docs":{"82":{"tf":1.0}}},"df":0,"docs":{},"e":{"4":{"8":{"7":{"b":{"7":{"1":{"df":2,"docs":{"214":{"tf":1.0},"86":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"7":{"df":0,"docs":{},"f":{"df":1,"docs":{"105":{"tf":1.0}}}},"8":{"0":{"df":2,"docs":{"105":{"tf":1.0},"107":{"tf":1.0}}},"df":0,"docs":{}},"<":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":6,"docs":{"100":{"tf":1.0},"107":{"tf":2.0},"167":{"tf":1.4142135623730951},"179":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"214":{"tf":1.0}}}}}},"a":{"df":1,"docs":{"195":{"tf":1.0}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":1,"docs":{"117":{"tf":1.0}}}}},"–":{"3":{"1":{"df":1,"docs":{"129":{"tf":1.0}}},"df":1,"docs":{"216":{"tf":1.0}}},"df":0,"docs":{}}},"1":{",":{"1":{"2":{"3":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"7":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"3":{"7":{"6":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{"2":{"7":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"6":{"2":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},".":{"2":{"df":1,"docs":{"18":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"14":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"/":{"1":{"0":{"0":{"df":1,"docs":{"219":{"tf":1.0}}},"df":1,"docs":{"219":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"0":{",":{"1":{"3":{"8":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"75":{"tf":1.0}}},"1":{"df":1,"docs":{"75":{"tf":1.4142135623730951}}},"2":{"8":{"df":0,"docs":{},"k":{"b":{"df":3,"docs":{"40":{"tf":1.4142135623730951},"41":{"tf":1.0},"46":{"tf":1.0}}},"df":0,"docs":{}}},"df":1,"docs":{"215":{"tf":1.0}}},"3":{"1":{",":{"0":{"7":{"2":{"df":1,"docs":{"81":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"0":{"7":{"2":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}},"df":0,"docs":{}},"8":{"8":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"1":{"6":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"5":{"5":{"9":{"df":1,"docs":{"153":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"87":{"tf":1.0}}},"6":{"df":1,"docs":{"78":{"tf":1.0}}},"7":{",":{"0":{"2":{"4":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"1":{"6":{"0":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"81":{"tf":1.0}}},"_":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"215":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":18,"docs":{"12":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"127":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"201":{"tf":1.0},"219":{"tf":1.0},"39":{"tf":1.0},"51":{"tf":1.4142135623730951},"57":{"tf":1.4142135623730951},"75":{"tf":2.0},"78":{"tf":1.0},"79":{"tf":1.4142135623730951},"81":{"tf":1.0},"90":{"tf":1.0},"91":{"tf":1.0}},"f":{"d":{"6":{"0":{"6":{"3":{"c":{"df":1,"docs":{"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"m":{"b":{"df":1,"docs":{"233":{"tf":1.0}}},"df":0,"docs":{}},"–":{"4":{"df":1,"docs":{"215":{"tf":1.0}}},"df":0,"docs":{}}},"2":{",":{"2":{"4":{"0":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{"1":{"8":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"0":{"2":{"6":{"df":1,"docs":{"91":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":2,"docs":{"78":{"tf":1.0},"87":{"tf":1.0}}},"1":{".":{"5":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"90":{"tf":1.0}}},"2":{".":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"4":{"df":1,"docs":{"216":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"3":{".":{"0":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{"5":{"6":{"6":{"6":{"9":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"9":{"/":{"2":{"5":{"1":{"df":1,"docs":{"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"k":{"b":{"df":1,"docs":{"233":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"5":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"0":{"df":1,"docs":{"47":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"df":19,"docs":{"103":{"tf":1.0},"104":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.7320508075688772},"122":{"tf":1.0},"128":{"tf":1.0},"134":{"tf":1.4142135623730951},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"156":{"tf":1.0},"164":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.4142135623730951},"75":{"tf":1.0},"78":{"tf":1.4142135623730951},"81":{"tf":1.0}}},"df":0,"docs":{}},"9":{"3":{"7":{"6":{"3":{"4":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"^":{"1":{"6":{"0":{"df":1,"docs":{"79":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"5":{"6":{"df":4,"docs":{"110":{"tf":1.0},"111":{"tf":1.0},"116":{"tf":1.0},"133":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"3":{"2":{"df":1,"docs":{"39":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{},"n":{"df":2,"docs":{"109":{"tf":1.0},"79":{"tf":1.0}}}},"df":6,"docs":{"12":{"tf":1.0},"219":{"tf":1.0},"32":{"tf":1.0},"75":{"tf":2.449489742783178},"78":{"tf":1.0},"91":{"tf":1.0}}},"3":{",":{"7":{"4":{"8":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},".":{"0":{"df":1,"docs":{"235":{"tf":1.0}}},"df":0,"docs":{}},"2":{"/":{"6":{"4":{"df":1,"docs":{"78":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"0":{",":{"6":{"6":{"9":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":17,"docs":{"128":{"tf":1.4142135623730951},"139":{"tf":1.4142135623730951},"140":{"tf":1.0},"147":{"tf":1.0},"159":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"176":{"tf":1.4142135623730951},"179":{"tf":1.0},"180":{"tf":1.0},"215":{"tf":1.7320508075688772},"39":{"tf":1.0},"45":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.7320508075688772}}},"3":{",":{"0":{"8":{"7":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},".":{"5":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":4,"docs":{"12":{"tf":1.0},"18":{"tf":1.4142135623730951},"75":{"tf":1.7320508075688772},"91":{"tf":1.0}},"f":{"a":{"4":{"df":0,"docs":{},"f":{"2":{"4":{"5":{"df":1,"docs":{"223":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}},"4":{"0":{".":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"8":{"4":{"4":{"8":{"3":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"1":{",":{"5":{"8":{"1":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"9":{"4":{"8":{"3":{"6":{"0":{"9":{"6":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"107":{"tf":1.0}}},"3":{".":{"1":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"90":{"tf":1.0}}},"4":{".":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"5":{",":{"0":{"5":{"2":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"7":{"0":{"3":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"7":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"8":{"4":{"4":{"df":1,"docs":{"154":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"9":{".":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":6,"docs":{"207":{"tf":1.0},"216":{"tf":1.0},"75":{"tf":2.0},"82":{"tf":1.0},"85":{"tf":1.0},"91":{"tf":1.0}},"x":{"df":1,"docs":{"92":{"tf":1.0}}}},"5":{"0":{"df":1,"docs":{"90":{"tf":1.0}}},"2":{",":{"6":{"3":{"4":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"5":{"1":{"0":{"6":{"1":{"5":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"3":{",":{"5":{"2":{"6":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"75":{"tf":1.0}}},"6":{",":{"2":{"8":{"6":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"df":1,"docs":{"92":{"tf":1.0}}},"3":{"/":{"6":{"4":{"df":2,"docs":{"0":{"tf":1.0},"37":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{"df":5,"docs":{"139":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"74":{"tf":1.0},"78":{"tf":1.0}}},"df":1,"docs":{"75":{"tf":1.0}}},"7":{",":{"1":{"9":{"2":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"75":{"tf":1.0}}},"8":{",":{"0":{"0":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"1":{",":{"8":{"4":{"0":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"7":{"0":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":2,"docs":{"177":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951}}},"9":{",":{"3":{"2":{"7":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{"9":{"df":1,"docs":{"89":{"tf":1.0}}},"df":0,"docs":{}},"8":{"5":{"2":{"0":{"9":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":2,"docs":{"75":{"tf":1.4142135623730951},"78":{"tf":1.0}}},"_":{"_":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"n":{"df":1,"docs":{"87":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"_":{"c":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"87":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"87":{"tf":1.0}},"e":{"_":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":1,"docs":{"87":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"_":{"df":0,"docs":{},"n":{"df":1,"docs":{"87":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"n":{"df":1,"docs":{"87":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"_":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"87":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"92":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"k":{"df":0,"docs":{},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"87":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"m":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":2,"docs":{"84":{"tf":1.0},"87":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"84":{"tf":1.0},"87":{"tf":1.0}}}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"87":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"_":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"87":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"87":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"_":{"b":{"df":0,"docs":{},"s":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"87":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"a":{"b":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}},"df":0,"docs":{}}},"b":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":1,"docs":{"64":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"_":{"d":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"2":{"5":{"6":{"(":{"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"174":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":4,"docs":{"103":{"tf":1.0},"214":{"tf":1.0},"33":{"tf":1.4142135623730951},"86":{"tf":1.0}}},"o":{"df":0,"docs":{},"v":{"df":5,"docs":{"105":{"tf":1.0},"109":{"tf":1.0},"223":{"tf":1.0},"231":{"tf":1.0},"39":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"179":{"tf":1.0},"193":{"tf":1.0}}}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":3,"docs":{"106":{"tf":1.0},"194":{"tf":1.0},"59":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"df":11,"docs":{"147":{"tf":1.0},"182":{"tf":1.0},"40":{"tf":1.0},"70":{"tf":1.0},"75":{"tf":1.4142135623730951},"80":{"tf":3.1622776601683795},"81":{"tf":1.0},"82":{"tf":1.0},"84":{"tf":1.7320508075688772},"90":{"tf":1.0},"95":{"tf":1.4142135623730951}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":6,"docs":{"109":{"tf":1.0},"143":{"tf":1.0},"163":{"tf":1.4142135623730951},"164":{"tf":1.4142135623730951},"165":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"20":{"tf":1.0}}}}}},"k":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"t":{"df":2,"docs":{"182":{"tf":1.0},"200":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"223":{"tf":1.7320508075688772}}}},"v":{"df":2,"docs":{"18":{"tf":1.0},"23":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":6,"docs":{"18":{"tf":1.0},"215":{"tf":1.0},"219":{"tf":1.0},"224":{"tf":1.0},"35":{"tf":1.0},"98":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"93":{"tf":1.0}}}}},"d":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"109":{"tf":1.0}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":1,"docs":{"81":{"tf":1.0}}}}},"i":{"6":{"4":{"df":1,"docs":{"78":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"v":{"0":{"df":2,"docs":{"109":{"tf":1.0},"189":{"tf":1.0}}},"1":{"df":2,"docs":{"195":{"tf":1.0},"199":{"tf":1.0}}},"2":{"df":1,"docs":{"193":{"tf":1.0}}},"df":0,"docs":{}}},"df":7,"docs":{"100":{"tf":1.0},"109":{"tf":1.4142135623730951},"62":{"tf":1.4142135623730951},"64":{"tf":1.0},"78":{"tf":1.0},"97":{"tf":1.0},"99":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"130":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"i":{"df":0,"docs":{},"t":{"df":7,"docs":{"109":{"tf":1.0},"130":{"tf":1.0},"206":{"tf":1.0},"24":{"tf":1.0},"4":{"tf":1.0},"64":{"tf":1.4142135623730951},"73":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":3,"docs":{"33":{"tf":1.0},"87":{"tf":1.0},"94":{"tf":1.0}}}}}}},"m":{"df":0,"docs":{},"o":{"d":{"(":{"$":{"a":{"df":1,"docs":{"130":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"130":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"130":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{".":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"38":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":29,"docs":{"100":{"tf":1.0},"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.4142135623730951},"141":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":2.23606797749979},"148":{"tf":1.0},"163":{"tf":1.7320508075688772},"164":{"tf":1.7320508075688772},"165":{"tf":1.7320508075688772},"169":{"tf":1.0},"173":{"tf":1.0},"18":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"201":{"tf":1.7320508075688772},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.7320508075688772},"206":{"tf":1.7320508075688772},"213":{"tf":1.4142135623730951},"74":{"tf":1.0},"76":{"tf":1.4142135623730951},"79":{"tf":1.4142135623730951},"80":{"tf":1.0}},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":2,"docs":{"102":{"tf":1.0},"104":{"tf":1.4142135623730951}},"e":{":":{":":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"105":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":4,"docs":{"33":{"tf":1.4142135623730951},"62":{"tf":1.0},"82":{"tf":1.4142135623730951},"91":{"tf":1.0}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}},"v":{"a":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"12":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"37":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"81":{"tf":1.0},"94":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"172":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"g":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"64":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"df":9,"docs":{"194":{"tf":1.0},"219":{"tf":1.0},"223":{"tf":1.4142135623730951},"52":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"90":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.0}}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"12":{"tf":1.4142135623730951},"91":{"tf":1.0}}}}}}}},"i":{"df":4,"docs":{"52":{"tf":1.4142135623730951},"64":{"tf":1.0},"65":{"tf":2.8284271247461903},"91":{"tf":1.0}},"m":{"df":4,"docs":{"11":{"tf":1.0},"222":{"tf":1.0},"234":{"tf":1.0},"236":{"tf":1.0}}}},"l":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"r":{"a":{"df":3,"docs":{"75":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"df":1,"docs":{"52":{"tf":1.0}}}}}}}}},"i":{"a":{"df":2,"docs":{"104":{"tf":1.0},"179":{"tf":1.4142135623730951}},"s":{"df":3,"docs":{"64":{"tf":1.0},"78":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":3,"docs":{"75":{"tf":1.4142135623730951},"80":{"tf":1.0},"95":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"n":{"df":1,"docs":{"80":{"tf":1.0}}},"o":{"c":{"df":4,"docs":{"104":{"tf":1.0},"105":{"tf":1.0},"219":{"tf":1.0},"82":{"tf":1.0}}},"df":0,"docs":{},"w":{"df":9,"docs":{"219":{"tf":1.0},"223":{"tf":1.0},"224":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"30":{"tf":1.0},"70":{"tf":1.0},"78":{"tf":1.0},"93":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"74":{"tf":1.0}}}},"p":{"df":0,"docs":{},"h":{"a":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"97":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"e":{"a":{"d":{"df":0,"docs":{},"i":{"df":1,"docs":{"78":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"w":{"a":{"df":0,"docs":{},"y":{"df":13,"docs":{"18":{"tf":1.0},"188":{"tf":1.0},"222":{"tf":1.0},"232":{"tf":1.0},"39":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":1.0},"50":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.0},"71":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":7,"docs":{"0":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"37":{"tf":1.0}}}}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":3,"docs":{"175":{"tf":1.0},"179":{"tf":1.4142135623730951},"200":{"tf":1.0}},"i":{"df":19,"docs":{"104":{"tf":1.0},"117":{"tf":1.0},"138":{"tf":1.4142135623730951},"155":{"tf":1.0},"156":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.0},"95":{"tf":1.0}}}},"z":{"df":2,"docs":{"75":{"tf":1.0},"80":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"97":{"tf":1.0}}}}}},"d":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"117":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"117":{"tf":1.4142135623730951}}},"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"75":{"tf":1.0},"79":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":1,"docs":{"135":{"tf":1.0}}}},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":109,"docs":{"107":{"tf":1.4142135623730951},"108":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.4142135623730951},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.7320508075688772},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.4142135623730951},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.7320508075688772},"180":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"76":{"tf":1.0},"96":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.7320508075688772},"99":{"tf":1.7320508075688772}}},"u":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":4,"docs":{"190":{"tf":1.0},"219":{"tf":1.0},"71":{"tf":1.0},"82":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"59":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"98":{"tf":1.0},"99":{"tf":1.0}}}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"43":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"220":{"tf":1.4142135623730951},"70":{"tf":1.0}}},"p":{"df":1,"docs":{"235":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"r":{"df":6,"docs":{"106":{"tf":1.0},"188":{"tf":1.0},"86":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}}},"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"18":{"tf":1.0},"94":{"tf":1.0}},"i":{"df":0,"docs":{},"x":{"df":1,"docs":{"97":{"tf":1.4142135623730951}},"’":{"df":1,"docs":{"188":{"tf":1.0}}}}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"5":{"tf":1.0},"52":{"tf":1.4142135623730951}}},"df":7,"docs":{"12":{"tf":1.4142135623730951},"231":{"tf":1.0},"27":{"tf":1.0},"37":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"68":{"tf":1.0}}}},"r":{"df":0,"docs":{},"o":{"a":{"c":{"df":0,"docs":{},"h":{"df":4,"docs":{"224":{"tf":1.0},"66":{"tf":1.0},"91":{"tf":1.7320508075688772},"92":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"221":{"tf":1.0}}}}},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"87":{"tf":1.0}}}}}}}}},"r":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"179":{"tf":1.0},"30":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":9,"docs":{"43":{"tf":1.0},"66":{"tf":1.7320508075688772},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"g":{"_":{"0":{"df":2,"docs":{"216":{"tf":1.0},"99":{"tf":1.0}}},"1":{"df":2,"docs":{"216":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"86":{"tf":1.0}},"s":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":4,"docs":{"201":{"tf":1.7320508075688772},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0}}}}}}}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":4,"docs":{"201":{"tf":1.7320508075688772},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0}}}}}}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"_":{"1":{"df":1,"docs":{"174":{"tf":1.0}}},"df":0,"docs":{}},"df":8,"docs":{"174":{"tf":1.4142135623730951},"216":{"tf":1.7320508075688772},"30":{"tf":1.0},"39":{"tf":1.0},"43":{"tf":1.7320508075688772},"56":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":7,"docs":{"100":{"tf":1.0},"103":{"tf":1.0},"116":{"tf":1.0},"122":{"tf":1.0},"214":{"tf":1.4142135623730951},"78":{"tf":1.7320508075688772},"79":{"tf":1.0}}}}}}}},"m":{"df":1,"docs":{"219":{"tf":1.0}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":3,"docs":{"219":{"tf":1.4142135623730951},"233":{"tf":1.0},"52":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"y":{"df":2,"docs":{"179":{"tf":1.0},"214":{"tf":1.0}}}},"df":0,"docs":{}},"t":{"df":1,"docs":{"219":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"58":{"tf":1.0},"61":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"l":{"df":6,"docs":{"16":{"tf":1.0},"230":{"tf":1.7320508075688772},"39":{"tf":1.0},"4":{"tf":1.0},"43":{"tf":1.7320508075688772},"82":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"212":{"tf":1.0},"214":{"tf":1.0},"223":{"tf":1.0},"71":{"tf":1.0}}}},"t":{"df":1,"docs":{"220":{"tf":1.0}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":1,"docs":{"176":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"64":{"tf":1.0},"65":{"tf":1.4142135623730951},"91":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"m":{"df":2,"docs":{"43":{"tf":1.0},"50":{"tf":1.0}},"p":{"df":0,"docs":{},"t":{"df":2,"docs":{"179":{"tf":1.0},"219":{"tf":1.0}}}}}}},"t":{"df":4,"docs":{"33":{"tf":1.7320508075688772},"69":{"tf":1.0},"75":{"tf":1.0},"95":{"tf":1.0}}}},"t":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"h":{"df":3,"docs":{"107":{"tf":1.0},"142":{"tf":1.0},"99":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"u":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"1":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"28":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"148":{"tf":1.0},"39":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":3,"docs":{"33":{"tf":1.4142135623730951},"56":{"tf":1.7320508075688772},"62":{"tf":1.0}}}},"df":0,"docs":{}}}}},"v":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":6,"docs":{"14":{"tf":1.0},"21":{"tf":1.0},"219":{"tf":1.0},"22":{"tf":1.0},"50":{"tf":1.0},"81":{"tf":1.0}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"d":{"df":3,"docs":{"56":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}},"w":{"a":{"df":0,"docs":{},"r":{"df":3,"docs":{"180":{"tf":1.0},"36":{"tf":1.0},"93":{"tf":1.0}}},"y":{"df":1,"docs":{"90":{"tf":1.0}}}},"df":0,"docs":{}}},"b":{"a":{"c":{"df":0,"docs":{},"k":{"df":4,"docs":{"122":{"tf":1.0},"174":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"d":{"df":4,"docs":{"12":{"tf":1.0},"66":{"tf":1.0},"80":{"tf":1.0},"87":{"tf":1.0}}},"df":0,"docs":{}}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":4,"docs":{"220":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.4142135623730951},"91":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"n":{"c":{"df":6,"docs":{"100":{"tf":1.0},"157":{"tf":1.0},"165":{"tf":1.7320508075688772},"213":{"tf":1.4142135623730951},"223":{"tf":1.0},"66":{"tf":1.0}},"e":{"(":{"$":{"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"165":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"157":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"165":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"219":{"tf":1.0}}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"99":{"tf":1.0}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"146":{"tf":1.0},"182":{"tf":1.0},"200":{"tf":1.0},"235":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"e":{"df":14,"docs":{"116":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"17":{"tf":1.0},"219":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.0},"52":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.4142135623730951},"78":{"tf":1.4142135623730951},"79":{"tf":1.4142135623730951},"80":{"tf":1.0},"91":{"tf":1.4142135623730951}},"f":{"df":0,"docs":{},"e":{"df":2,"docs":{"100":{"tf":1.0},"153":{"tf":2.0}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"89":{"tf":1.0},"91":{"tf":1.0}},"e":{"=":{"1":{"0":{"3":{"0":{"6":{"3":{"/":{"1":{"5":{"7":{"2":{"8":{"6":{"4":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"i":{"c":{"df":2,"docs":{"12":{"tf":1.0},"87":{"tf":1.0}}},"df":0,"docs":{}}}},"df":3,"docs":{"129":{"tf":1.0},"130":{"tf":1.7320508075688772},"131":{"tf":1.7320508075688772}},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":2,"docs":{"196":{"tf":1.0},"91":{"tf":1.0}}}}},"df":1,"docs":{"128":{"tf":1.0}},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":7,"docs":{"108":{"tf":1.0},"195":{"tf":1.0},"51":{"tf":1.0},"56":{"tf":1.0},"75":{"tf":1.0},"94":{"tf":1.0},"98":{"tf":1.0}}}}},"h":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":4,"docs":{"199":{"tf":1.0},"50":{"tf":1.0},"64":{"tf":1.0},"98":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"195":{"tf":1.0},"73":{"tf":1.0}}},"df":0,"docs":{}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":2,"docs":{"219":{"tf":1.0},"235":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"w":{"df":7,"docs":{"101":{"tf":1.0},"138":{"tf":1.0},"18":{"tf":1.0},"236":{"tf":1.0},"39":{"tf":1.0},"90":{"tf":1.0},"97":{"tf":1.0}}}}},"n":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":2,"docs":{"219":{"tf":1.4142135623730951},"61":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"52":{"tf":1.0},"92":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":11,"docs":{"12":{"tf":1.0},"146":{"tf":1.0},"35":{"tf":1.0},"50":{"tf":1.0},"66":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.0},"74":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.0},"82":{"tf":1.4142135623730951}}}}}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":3,"docs":{"184":{"tf":1.0},"221":{"tf":1.0},"52":{"tf":1.0}}},"df":0,"docs":{}}}}},"i":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"78":{"tf":1.0},"95":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"g":{"df":8,"docs":{"104":{"tf":1.7320508075688772},"166":{"tf":1.0},"176":{"tf":1.0},"70":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.4142135623730951},"80":{"tf":1.0},"81":{"tf":1.0}},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"107":{"tf":1.0},"194":{"tf":1.0},"216":{"tf":1.0}}}}}}},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":7,"docs":{"225":{"tf":1.0},"5":{"tf":1.0},"53":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.4142135623730951},"7":{"tf":1.7320508075688772},"71":{"tf":1.0}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"a":{"d":{"d":{"df":1,"docs":{"109":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"130":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"117":{"tf":1.0}}},"df":0,"docs":{}}},"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":1,"docs":{"128":{"tf":1.0}}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"112":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"q":{"df":1,"docs":{"127":{"tf":1.0}}},"x":{"df":0,"docs":{},"p":{"df":1,"docs":{"116":{"tf":1.0}}}}},"g":{"df":0,"docs":{},"t":{"df":1,"docs":{"124":{"tf":1.0}}}},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"123":{"tf":1.0}}}},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"114":{"tf":1.0}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"111":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"131":{"tf":1.0}}},"df":0,"docs":{}}}}}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"118":{"tf":1.0}}}},"s":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"122":{"tf":1.0}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"113":{"tf":1.0}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":1,"docs":{"126":{"tf":1.0}}}},"h":{"df":0,"docs":{},"l":{"df":1,"docs":{"120":{"tf":1.0}}},"r":{"df":1,"docs":{"121":{"tf":1.0}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"129":{"tf":1.0}}},"df":0,"docs":{}}}}}}}}},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"125":{"tf":1.0}}}},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"115":{"tf":1.0}}},"df":0,"docs":{}}},"u":{"b":{"df":1,"docs":{"110":{"tf":1.0}}},"df":0,"docs":{}}},"x":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"119":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}}},"d":{"df":12,"docs":{"100":{"tf":1.0},"106":{"tf":1.0},"147":{"tf":1.0},"174":{"tf":1.4142135623730951},"188":{"tf":1.7320508075688772},"189":{"tf":2.449489742783178},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"199":{"tf":1.0},"93":{"tf":1.0},"98":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"0":{"df":1,"docs":{"189":{"tf":1.0}}},"1":{"df":1,"docs":{"189":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":1,"docs":{"19":{"tf":1.0}}},"t":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"93":{"tf":1.0}}},"df":0,"docs":{}}},"df":35,"docs":{"100":{"tf":1.0},"103":{"tf":1.4142135623730951},"104":{"tf":1.0},"107":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"117":{"tf":1.0},"120":{"tf":1.7320508075688772},"121":{"tf":1.4142135623730951},"122":{"tf":1.7320508075688772},"128":{"tf":1.0},"129":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.4142135623730951},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"177":{"tf":1.7320508075688772},"179":{"tf":1.0},"180":{"tf":1.0},"216":{"tf":1.4142135623730951},"39":{"tf":1.0},"62":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.7320508075688772},"75":{"tf":1.4142135623730951},"76":{"tf":1.0},"78":{"tf":2.0},"79":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.4142135623730951},"99":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"93":{"tf":1.0}}}},"s":{"(":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"s":{"df":1,"docs":{"81":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":5,"docs":{"102":{"tf":1.0},"103":{"tf":1.4142135623730951},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":6,"docs":{"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"133":{"tf":1.0},"223":{"tf":1.7320508075688772},"93":{"tf":1.0}}}}},"x":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"93":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}},"o":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"92":{"tf":1.0}}}},"b":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":3,"docs":{"100":{"tf":1.0},"154":{"tf":2.0},"49":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}},"df":9,"docs":{"154":{"tf":1.0},"155":{"tf":1.7320508075688772},"18":{"tf":1.7320508075688772},"236":{"tf":1.0},"35":{"tf":1.4142135623730951},"49":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"94":{"tf":1.0}},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"(":{"$":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":1,"docs":{"155":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"155":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"155":{"tf":1.4142135623730951},"49":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"k":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":5,"docs":{"219":{"tf":1.0},"220":{"tf":1.0},"224":{"tf":1.0},"52":{"tf":1.0},"53":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":16,"docs":{"100":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"156":{"tf":1.7320508075688772},"192":{"tf":1.0},"195":{"tf":1.0},"199":{"tf":1.4142135623730951},"43":{"tf":1.7320508075688772},"82":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.0},"92":{"tf":1.0},"99":{"tf":1.0}},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"(":{"$":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"b":{"df":1,"docs":{"156":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"156":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"156":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"’":{"df":4,"docs":{"148":{"tf":1.0},"151":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0}}}}},"df":0,"docs":{}}},"o":{"d":{"df":0,"docs":{},"i":{"df":6,"docs":{"174":{"tf":1.0},"195":{"tf":2.449489742783178},"199":{"tf":1.4142135623730951},"78":{"tf":1.0},"91":{"tf":1.0},"99":{"tf":1.0}}},"y":{"df":0,"docs":{},"’":{"df":2,"docs":{"195":{"tf":1.0},"199":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"219":{"tf":1.0}}}},"o":{"df":0,"docs":{},"k":{"df":2,"docs":{"0":{"tf":1.0},"3":{"tf":1.4142135623730951}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":1,"docs":{"180":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":6,"docs":{"103":{"tf":1.0},"107":{"tf":1.4142135623730951},"132":{"tf":1.0},"201":{"tf":1.0},"26":{"tf":1.0},"87":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"110":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"h":{"df":4,"docs":{"105":{"tf":1.0},"18":{"tf":1.0},"193":{"tf":1.4142135623730951},"35":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":7,"docs":{"147":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"200":{"tf":1.0},"204":{"tf":1.0},"79":{"tf":1.0},"93":{"tf":1.0}}}}},"df":11,"docs":{"106":{"tf":1.0},"178":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.4142135623730951},"193":{"tf":1.0},"199":{"tf":1.0},"214":{"tf":1.0},"70":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.7320508075688772},"82":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"r":{"a":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":3,"docs":{"135":{"tf":1.0},"193":{"tf":1.0},"99":{"tf":1.0}}}}}},"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":5,"docs":{"193":{"tf":1.0},"212":{"tf":1.0},"63":{"tf":1.7320508075688772},"89":{"tf":1.0},"93":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"k":{"df":6,"docs":{"100":{"tf":1.0},"192":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":2.23606797749979},"197":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"d":{"df":0,"docs":{},"g":{"df":1,"docs":{"72":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"225":{"tf":1.0}}}}}}}},"s":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"p":{".":{"df":0,"docs":{},"i":{"2":{"5":{"6":{"df":1,"docs":{"92":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"4":{"df":1,"docs":{"92":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":1,"docs":{"92":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":8,"docs":{"14":{"tf":1.0},"161":{"tf":1.0},"185":{"tf":1.0},"39":{"tf":1.4142135623730951},"40":{"tf":1.4142135623730951},"43":{"tf":1.4142135623730951},"70":{"tf":1.4142135623730951},"80":{"tf":1.0}}}}}},"g":{"df":6,"docs":{"221":{"tf":1.0},"222":{"tf":1.7320508075688772},"223":{"tf":1.0},"224":{"tf":1.0},"23":{"tf":1.0},"82":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":1,"docs":{"232":{"tf":1.0}}}}}},"i":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"10":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"l":{"d":{"df":9,"docs":{"10":{"tf":1.0},"221":{"tf":1.0},"226":{"tf":2.449489742783178},"6":{"tf":1.0},"60":{"tf":1.0},"61":{"tf":1.0},"68":{"tf":2.0},"71":{"tf":2.0},"90":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"69":{"tf":1.0},"71":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"71":{"tf":1.0}}}},"t":{"df":1,"docs":{"71":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"134":{"tf":1.0},"178":{"tf":1.0},"71":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"k":{"df":3,"docs":{"100":{"tf":1.0},"182":{"tf":1.4142135623730951},"90":{"tf":1.0}}}},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"82":{"tf":1.0}}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"e":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"128":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":1,"docs":{"128":{"tf":1.0}}},"v":{"0":{"df":1,"docs":{"128":{"tf":1.0}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"d":{"df":6,"docs":{"18":{"tf":1.0},"186":{"tf":1.0},"219":{"tf":2.23606797749979},"33":{"tf":1.4142135623730951},"38":{"tf":1.0},"94":{"tf":1.0}}},"df":0,"docs":{}}},"df":48,"docs":{"100":{"tf":1.0},"103":{"tf":1.0},"105":{"tf":1.0},"116":{"tf":1.0},"128":{"tf":2.8284271247461903},"129":{"tf":2.6457513110645907},"137":{"tf":1.0},"138":{"tf":1.7320508075688772},"139":{"tf":1.4142135623730951},"147":{"tf":1.4142135623730951},"159":{"tf":1.7320508075688772},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"166":{"tf":1.4142135623730951},"167":{"tf":1.0},"168":{"tf":1.0},"171":{"tf":1.0},"176":{"tf":2.23606797749979},"177":{"tf":1.7320508075688772},"178":{"tf":2.0},"179":{"tf":1.0},"180":{"tf":1.0},"182":{"tf":1.4142135623730951},"183":{"tf":2.23606797749979},"184":{"tf":2.23606797749979},"185":{"tf":2.0},"186":{"tf":2.0},"187":{"tf":2.23606797749979},"201":{"tf":1.7320508075688772},"205":{"tf":1.4142135623730951},"207":{"tf":1.4142135623730951},"209":{"tf":1.0},"210":{"tf":1.0},"215":{"tf":2.23606797749979},"216":{"tf":1.0},"40":{"tf":1.0},"70":{"tf":1.4142135623730951},"75":{"tf":1.0},"80":{"tf":2.449489742783178},"81":{"tf":2.0},"82":{"tf":2.6457513110645907},"84":{"tf":1.0},"87":{"tf":1.0},"89":{"tf":1.4142135623730951},"90":{"tf":1.4142135623730951},"95":{"tf":1.0}},"s":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"p":{"df":2,"docs":{"80":{"tf":1.0},"81":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"c":{"a":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"180":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"(":{"$":{"df":0,"docs":{},"g":{"a":{"df":1,"docs":{"201":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"201":{"tf":1.0}}},"df":0,"docs":{}}},"_":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"_":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"y":{"(":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"57":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"s":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"d":{"df":2,"docs":{"100":{"tf":1.0},"202":{"tf":1.4142135623730951}},"e":{"(":{"$":{"df":0,"docs":{},"g":{"a":{"df":1,"docs":{"202":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"202":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":4,"docs":{"100":{"tf":1.0},"187":{"tf":1.4142135623730951},"41":{"tf":1.4142135623730951},"80":{"tf":1.0}}},"y":{"(":{"$":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"187":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"187":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":8,"docs":{"100":{"tf":1.0},"159":{"tf":1.7320508075688772},"160":{"tf":1.0},"182":{"tf":1.0},"187":{"tf":1.7320508075688772},"201":{"tf":1.7320508075688772},"223":{"tf":1.0},"41":{"tf":1.0}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"159":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"159":{"tf":1.0}}},"df":0,"docs":{}}},"df":4,"docs":{"100":{"tf":1.0},"159":{"tf":1.4142135623730951},"41":{"tf":1.4142135623730951},"87":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":2,"docs":{"100":{"tf":1.0},"160":{"tf":2.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":38,"docs":{"0":{"tf":1.0},"100":{"tf":1.4142135623730951},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"144":{"tf":1.0},"157":{"tf":1.0},"161":{"tf":1.0},"165":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":2.23606797749979},"179":{"tf":1.0},"18":{"tf":1.0},"190":{"tf":1.7320508075688772},"200":{"tf":1.0},"201":{"tf":2.0},"202":{"tf":1.0},"203":{"tf":2.0},"204":{"tf":2.0},"208":{"tf":1.4142135623730951},"209":{"tf":1.4142135623730951},"210":{"tf":1.7320508075688772},"211":{"tf":1.4142135623730951},"212":{"tf":1.0},"213":{"tf":1.4142135623730951},"214":{"tf":1.4142135623730951},"215":{"tf":1.0},"216":{"tf":1.0},"223":{"tf":1.4142135623730951},"35":{"tf":1.0},"37":{"tf":1.0},"56":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":1.0},"85":{"tf":1.0},"87":{"tf":1.4142135623730951},"92":{"tf":1.0}},"e":{"df":3,"docs":{"174":{"tf":1.4142135623730951},"201":{"tf":1.0},"204":{"tf":1.0}},"e":{"df":0,"docs":{},"’":{"df":3,"docs":{"174":{"tf":1.7320508075688772},"202":{"tf":1.4142135623730951},"203":{"tf":1.0}}}},"r":{"df":7,"docs":{"100":{"tf":1.0},"103":{"tf":1.0},"141":{"tf":2.23606797749979},"205":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"91":{"tf":1.0}},"’":{"df":4,"docs":{"202":{"tf":1.0},"203":{"tf":1.4142135623730951},"205":{"tf":1.0},"206":{"tf":1.0}}}}},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"d":{":":{":":{"c":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"201":{"tf":1.0}},"l":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"202":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"203":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"c":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"204":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":5,"docs":{"100":{"tf":1.0},"142":{"tf":2.0},"75":{"tf":1.0},"87":{"tf":1.0},"95":{"tf":1.0}}}}},"df":0,"docs":{}},"’":{"df":4,"docs":{"159":{"tf":1.0},"160":{"tf":1.0},"185":{"tf":1.0},"187":{"tf":1.0}}}}},"n":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"(":{"0":{"df":0,"docs":{},"x":{"4":{"0":{"df":1,"docs":{"81":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":1,"docs":{"213":{"tf":1.0}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"97":{"tf":1.0}},"i":{"c":{"df":3,"docs":{"167":{"tf":1.0},"179":{"tf":1.0},"75":{"tf":1.0}}},"df":0,"docs":{}}}},"’":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}},"p":{"df":1,"docs":{"40":{"tf":1.0}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":2,"docs":{"65":{"tf":1.4142135623730951},"72":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"18":{"tf":1.0},"66":{"tf":1.0}},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"0":{"tf":1.0},"82":{"tf":1.0}}}}}}}},"g":{"df":0,"docs":{},"o":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":2,"docs":{"62":{"tf":1.0},"89":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"df":24,"docs":{"101":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"109":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"170":{"tf":1.0},"174":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.4142135623730951},"181":{"tf":1.0},"189":{"tf":1.0},"192":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":2.6457513110645907},"196":{"tf":2.0},"197":{"tf":2.0},"76":{"tf":1.7320508075688772},"80":{"tf":1.0},"82":{"tf":1.0},"93":{"tf":1.0},"94":{"tf":1.4142135623730951},"98":{"tf":1.0}}}}},"s":{"c":{"a":{"d":{"df":3,"docs":{"75":{"tf":1.0},"79":{"tf":1.0},"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":7,"docs":{"18":{"tf":2.0},"194":{"tf":3.0},"223":{"tf":1.4142135623730951},"224":{"tf":1.4142135623730951},"48":{"tf":1.0},"49":{"tf":1.0},"99":{"tf":1.0}}}},"t":{"c":{"df":0,"docs":{},"h":{"df":3,"docs":{"194":{"tf":1.0},"75":{"tf":1.0},"82":{"tf":1.7320508075688772}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"78":{"tf":1.7320508075688772}},"s":{"df":1,"docs":{"78":{"tf":1.0}}}}}}}}},"u":{"df":0,"docs":{},"s":{"df":5,"docs":{"204":{"tf":1.0},"224":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.0},"92":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"40":{"tf":1.0}}}},"df":0,"docs":{}}}},"c":{"c":{"a":{"3":{"8":{"d":{"df":0,"docs":{},"f":{"df":2,"docs":{"78":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"d":{"df":1,"docs":{"221":{"tf":1.0}}},"df":1,"docs":{"52":{"tf":1.0}},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"103":{"tf":1.0}}}},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"223":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"99":{"tf":1.0}}}}},"df":0,"docs":{}}}},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":6,"docs":{"145":{"tf":1.0},"151":{"tf":1.0},"219":{"tf":1.4142135623730951},"35":{"tf":1.0},"68":{"tf":1.0},"81":{"tf":1.0}},"i":{"d":{"df":2,"docs":{"100":{"tf":1.0},"145":{"tf":2.0}}},"df":0,"docs":{}}}},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"91":{"tf":1.4142135623730951}}}}}}},"n":{"c":{"df":2,"docs":{"52":{"tf":1.0},"61":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":12,"docs":{"146":{"tf":1.0},"147":{"tf":1.0},"18":{"tf":1.0},"192":{"tf":1.0},"210":{"tf":1.0},"223":{"tf":1.4142135623730951},"3":{"tf":1.0},"37":{"tf":1.0},"62":{"tf":1.0},"63":{"tf":1.4142135623730951},"82":{"tf":1.0},"97":{"tf":1.0}}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"11":{"tf":1.0},"221":{"tf":1.0},"230":{"tf":1.0},"58":{"tf":1.0}}}}}},"r":{"df":1,"docs":{"29":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"157":{"tf":1.0},"165":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"k":{"df":10,"docs":{"232":{"tf":1.0},"70":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.4142135623730951},"82":{"tf":1.4142135623730951},"87":{"tf":1.0},"92":{"tf":1.0},"93":{"tf":1.4142135623730951},"95":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"52":{"tf":1.0},"76":{"tf":1.0}}},"df":0,"docs":{}}}},"i":{"df":2,"docs":{"61":{"tf":1.0},"63":{"tf":1.4142135623730951}},"r":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"v":{"df":1,"docs":{"68":{"tf":1.0}}}}}},"df":0,"docs":{}}},"l":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":1,"docs":{"78":{"tf":1.0}}}},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"5":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"81":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"df":1,"docs":{"177":{"tf":1.0}},"i":{"df":3,"docs":{"147":{"tf":1.0},"78":{"tf":1.0},"82":{"tf":1.0}}}}}}},"u":{"d":{"df":1,"docs":{"91":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"75":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"105":{"tf":1.0}}}}},"r":{"df":2,"docs":{"117":{"tf":1.0},"93":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"df":4,"docs":{"11":{"tf":2.23606797749979},"18":{"tf":1.0},"73":{"tf":1.0},"94":{"tf":1.0}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"64":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"221":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":3,"docs":{"11":{"tf":1.0},"219":{"tf":1.0},"222":{"tf":1.0}}}}},"z":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"134":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"134":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"134":{"tf":1.4142135623730951}}}},"o":{"d":{"df":0,"docs":{},"e":{"/":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"104":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"b":{"a":{"df":0,"docs":{},"s":{"df":6,"docs":{"58":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.7320508075688772},"65":{"tf":1.7320508075688772},"82":{"tf":1.0},"97":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":4,"docs":{"100":{"tf":1.0},"183":{"tf":1.4142135623730951},"42":{"tf":1.4142135623730951},"80":{"tf":1.0}}},"y":{"(":{"$":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"183":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"183":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":53,"docs":{"0":{"tf":1.0},"100":{"tf":1.0},"104":{"tf":1.0},"12":{"tf":1.4142135623730951},"13":{"tf":1.0},"14":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.4142135623730951},"164":{"tf":1.0},"17":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"18":{"tf":1.4142135623730951},"182":{"tf":1.4142135623730951},"183":{"tf":1.7320508075688772},"184":{"tf":2.0},"19":{"tf":1.0},"190":{"tf":1.0},"202":{"tf":1.4142135623730951},"203":{"tf":1.0},"205":{"tf":1.7320508075688772},"206":{"tf":1.0},"214":{"tf":2.23606797749979},"219":{"tf":2.0},"221":{"tf":1.0},"222":{"tf":1.0},"223":{"tf":1.4142135623730951},"233":{"tf":1.0},"236":{"tf":1.4142135623730951},"33":{"tf":1.4142135623730951},"35":{"tf":3.3166247903554},"36":{"tf":1.0},"37":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":2.23606797749979},"5":{"tf":1.0},"53":{"tf":1.4142135623730951},"6":{"tf":1.0},"64":{"tf":1.4142135623730951},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.4142135623730951},"68":{"tf":1.7320508075688772},"69":{"tf":1.4142135623730951},"70":{"tf":1.0},"75":{"tf":1.7320508075688772},"76":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"86":{"tf":1.7320508075688772}},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":11,"docs":{"104":{"tf":1.0},"176":{"tf":1.4142135623730951},"195":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.7320508075688772},"87":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.0},"95":{"tf":1.0}}}}},"s":{"df":5,"docs":{"100":{"tf":1.0},"162":{"tf":2.0},"35":{"tf":1.0},"88":{"tf":1.4142135623730951},"89":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"b":{"a":{"df":0,"docs":{},"s":{"df":2,"docs":{"100":{"tf":1.0},"148":{"tf":2.23606797749979}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":2,"docs":{"108":{"tf":1.0},"86":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"223":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"91":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"n":{"df":1,"docs":{"89":{"tf":1.4142135623730951}}}}}},"m":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":5,"docs":{"223":{"tf":1.4142135623730951},"5":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"84":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":2,"docs":{"221":{"tf":1.0},"53":{"tf":1.0}}},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":11,"docs":{"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.0},"19":{"tf":1.0},"30":{"tf":1.0},"94":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"107":{"tf":1.0},"170":{"tf":1.0},"195":{"tf":1.0},"64":{"tf":2.0},"98":{"tf":1.4142135623730951}}}}},"i":{"df":0,"docs":{},"t":{"df":4,"docs":{"78":{"tf":1.0},"89":{"tf":1.4142135623730951},"90":{"tf":1.0},"91":{"tf":1.0}}}},"o":{"df":0,"docs":{},"n":{"df":9,"docs":{"117":{"tf":1.0},"138":{"tf":1.0},"208":{"tf":1.0},"214":{"tf":1.0},"52":{"tf":1.0},"79":{"tf":1.0},"83":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.4142135623730951}}}}},"p":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"86":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"138":{"tf":1.0}}}}}},"df":0,"docs":{},"r":{"df":10,"docs":{"123":{"tf":1.4142135623730951},"124":{"tf":1.4142135623730951},"125":{"tf":1.4142135623730951},"126":{"tf":1.4142135623730951},"194":{"tf":1.0},"34":{"tf":1.0},"40":{"tf":1.0},"91":{"tf":1.0},"93":{"tf":1.0},"94":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":11,"docs":{"0":{"tf":1.0},"103":{"tf":1.0},"107":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"78":{"tf":1.7320508075688772},"79":{"tf":1.0},"90":{"tf":1.0}}}}}}},"t":{"df":11,"docs":{"202":{"tf":1.0},"213":{"tf":1.0},"220":{"tf":1.0},"222":{"tf":1.7320508075688772},"223":{"tf":1.0},"226":{"tf":1.0},"235":{"tf":1.0},"24":{"tf":1.0},"66":{"tf":1.0},"70":{"tf":1.0},"80":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":63,"docs":{"0":{"tf":1.0},"107":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"16":{"tf":1.0},"169":{"tf":1.0},"18":{"tf":2.23606797749979},"181":{"tf":1.0},"186":{"tf":1.0},"19":{"tf":1.0},"215":{"tf":1.4142135623730951},"216":{"tf":1.0},"217":{"tf":1.0},"219":{"tf":2.23606797749979},"22":{"tf":1.4142135623730951},"220":{"tf":1.0},"221":{"tf":1.0},"222":{"tf":1.4142135623730951},"223":{"tf":1.0},"224":{"tf":1.0},"225":{"tf":2.0},"226":{"tf":1.0},"227":{"tf":1.4142135623730951},"235":{"tf":1.4142135623730951},"236":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"3":{"tf":1.0},"33":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.7320508075688772},"40":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":2.0},"50":{"tf":1.7320508075688772},"52":{"tf":1.0},"57":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.0},"6":{"tf":1.7320508075688772},"60":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":2.449489742783178},"67":{"tf":2.0},"68":{"tf":1.7320508075688772},"69":{"tf":2.23606797749979},"70":{"tf":1.4142135623730951},"71":{"tf":1.7320508075688772},"72":{"tf":1.0},"73":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"8":{"tf":1.0},"80":{"tf":1.0},"83":{"tf":1.4142135623730951},"9":{"tf":1.0},"94":{"tf":1.4142135623730951},"99":{"tf":1.0}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"83":{"tf":1.0}}}}},"df":4,"docs":{"113":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"133":{"tf":1.4142135623730951}}}}}},"t":{"df":4,"docs":{"11":{"tf":1.0},"199":{"tf":1.0},"219":{"tf":1.0},"236":{"tf":1.0}}},"x":{"df":2,"docs":{"224":{"tf":1.4142135623730951},"52":{"tf":1.0}}}},"i":{"c":{"df":1,"docs":{"62":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"5":{"tf":1.4142135623730951}}},"s":{"df":1,"docs":{"52":{"tf":1.0}}},"u":{"df":0,"docs":{},"n":{"d":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"169":{"tf":1.0},"181":{"tf":1.0},"75":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}}}}},"df":6,"docs":{"139":{"tf":1.0},"140":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"75":{"tf":1.7320508075688772},"84":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":2,"docs":{"224":{"tf":1.0},"61":{"tf":1.0}}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"4":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}}}},"df":13,"docs":{"120":{"tf":1.0},"121":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"138":{"tf":1.0},"181":{"tf":1.0},"190":{"tf":1.0},"219":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0},"83":{"tf":1.4142135623730951},"84":{"tf":1.0},"89":{"tf":1.0}}}}}},"n":{"c":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"43":{"tf":1.0}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"61":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"170":{"tf":1.0},"99":{"tf":1.0}}}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":4,"docs":{"193":{"tf":2.23606797749979},"195":{"tf":2.449489742783178},"199":{"tf":1.0},"99":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"195":{"tf":2.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":1,"docs":{"94":{"tf":1.4142135623730951}},"u":{"df":0,"docs":{},"r":{"df":9,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"218":{"tf":1.7320508075688772},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.7320508075688772},"29":{"tf":1.0},"33":{"tf":1.0},"95":{"tf":1.0}}}}}},"l":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":2,"docs":{"18":{"tf":1.0},"190":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"14":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"v":{"df":11,"docs":{"103":{"tf":1.0},"105":{"tf":1.0},"110":{"tf":1.0},"116":{"tf":1.0},"120":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"179":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.0},"93":{"tf":1.4142135623730951}}}}},"i":{"d":{"df":6,"docs":{"220":{"tf":1.0},"234":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"93":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":5,"docs":{"219":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0},"82":{"tf":1.0},"93":{"tf":1.0}}}}},"t":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":25,"docs":{"100":{"tf":1.0},"105":{"tf":1.7320508075688772},"107":{"tf":1.7320508075688772},"117":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.4142135623730951},"14":{"tf":1.0},"169":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"179":{"tf":1.0},"181":{"tf":1.4142135623730951},"186":{"tf":1.0},"194":{"tf":1.4142135623730951},"43":{"tf":1.0},"45":{"tf":1.0},"47":{"tf":1.0},"64":{"tf":1.0},"75":{"tf":2.449489742783178},"80":{"tf":1.7320508075688772},"83":{"tf":1.4142135623730951},"85":{"tf":1.0},"87":{"tf":1.4142135623730951},"93":{"tf":1.0},"95":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"56":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"172":{"tf":1.0},"191":{"tf":1.0},"192":{"tf":1.0},"95":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":7,"docs":{"191":{"tf":1.0},"35":{"tf":1.4142135623730951},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.7320508075688772},"51":{"tf":1.7320508075688772},"56":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"105":{"tf":1.0}}}},"m":{"df":8,"docs":{"106":{"tf":1.0},"108":{"tf":1.0},"161":{"tf":1.0},"169":{"tf":1.0},"176":{"tf":1.0},"179":{"tf":1.0},"181":{"tf":1.0},"212":{"tf":1.0}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"39":{"tf":1.0},"43":{"tf":1.0},"5":{"tf":1.0},"97":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"138":{"tf":1.0},"199":{"tf":1.0},"3":{"tf":1.0}}}},"x":{"df":0,"docs":{},"t":{"df":6,"docs":{"202":{"tf":1.0},"203":{"tf":1.0},"65":{"tf":1.0},"69":{"tf":2.0},"75":{"tf":1.0},"78":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":4,"docs":{"100":{"tf":1.0},"192":{"tf":1.0},"195":{"tf":2.0},"197":{"tf":2.0}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":59,"docs":{"0":{"tf":2.0},"104":{"tf":1.4142135623730951},"12":{"tf":1.0},"13":{"tf":1.7320508075688772},"14":{"tf":2.0},"144":{"tf":1.0},"145":{"tf":1.0},"157":{"tf":1.0},"165":{"tf":1.0},"167":{"tf":1.0},"172":{"tf":1.0},"174":{"tf":1.0},"179":{"tf":1.4142135623730951},"18":{"tf":2.0},"190":{"tf":1.0},"191":{"tf":1.0},"2":{"tf":1.7320508075688772},"200":{"tf":1.4142135623730951},"205":{"tf":1.4142135623730951},"206":{"tf":1.0},"213":{"tf":1.0},"219":{"tf":2.23606797749979},"220":{"tf":1.0},"222":{"tf":1.4142135623730951},"223":{"tf":2.0},"233":{"tf":1.4142135623730951},"235":{"tf":1.4142135623730951},"27":{"tf":1.4142135623730951},"32":{"tf":2.449489742783178},"33":{"tf":2.23606797749979},"35":{"tf":1.4142135623730951},"37":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.4142135623730951},"40":{"tf":1.7320508075688772},"43":{"tf":2.0},"44":{"tf":1.0},"45":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.4142135623730951},"52":{"tf":2.0},"53":{"tf":1.4142135623730951},"55":{"tf":1.0},"56":{"tf":1.7320508075688772},"57":{"tf":1.4142135623730951},"6":{"tf":1.0},"66":{"tf":1.4142135623730951},"68":{"tf":2.23606797749979},"70":{"tf":1.0},"75":{"tf":1.0},"81":{"tf":1.7320508075688772},"82":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.0},"89":{"tf":1.7320508075688772},"90":{"tf":2.449489742783178},"91":{"tf":1.0},"92":{"tf":1.0},"93":{"tf":1.4142135623730951}},"s":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"’":{"df":4,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"205":{"tf":1.0},"213":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":5,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"59":{"tf":1.0},"63":{"tf":1.7320508075688772},"65":{"tf":2.0}},"o":{"df":0,"docs":{},"r":{"df":11,"docs":{"1":{"tf":1.0},"221":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.7320508075688772},"60":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.4142135623730951},"81":{"tf":1.0}}}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"l":{"df":19,"docs":{"100":{"tf":1.0},"13":{"tf":1.0},"189":{"tf":1.4142135623730951},"192":{"tf":2.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"226":{"tf":1.0},"55":{"tf":1.0},"70":{"tf":1.0},"76":{"tf":2.0},"93":{"tf":1.0},"94":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":3,"docs":{"52":{"tf":1.0},"53":{"tf":1.0},"55":{"tf":1.0}}},"t":{"df":2,"docs":{"74":{"tf":1.0},"99":{"tf":1.0}}}},"r":{"df":0,"docs":{},"s":{"df":2,"docs":{"100":{"tf":1.0},"129":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"i":{"df":13,"docs":{"100":{"tf":1.0},"108":{"tf":1.4142135623730951},"178":{"tf":1.7320508075688772},"182":{"tf":1.7320508075688772},"183":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"185":{"tf":1.4142135623730951},"186":{"tf":1.4142135623730951},"187":{"tf":1.4142135623730951},"75":{"tf":1.0},"85":{"tf":1.0},"87":{"tf":1.0},"95":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"91":{"tf":1.0},"95":{"tf":1.0}}},"p":{"df":0,"docs":{},"u":{"df":2,"docs":{"82":{"tf":1.0},"90":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":6,"docs":{"221":{"tf":1.4142135623730951},"223":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0},"91":{"tf":1.0},"93":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"82":{"tf":1.0}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":5,"docs":{"18":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"29":{"tf":1.0},"98":{"tf":1.0}}},"df":0,"docs":{}}}}}},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":2,"docs":{"81":{"tf":1.0},"82":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":7,"docs":{"116":{"tf":1.0},"13":{"tf":1.4142135623730951},"14":{"tf":1.7320508075688772},"180":{"tf":1.0},"43":{"tf":1.0},"74":{"tf":1.0},"92":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"134":{"tf":1.0},"75":{"tf":1.0},"87":{"tf":1.0},"99":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"64":{"tf":1.0},"93":{"tf":1.0}},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"179":{"tf":1.0},"223":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"52":{"tf":1.0}}}},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"52":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"82":{"tf":1.0}}}},"df":2,"docs":{"138":{"tf":1.0},"58":{"tf":1.0}}}}}},"p":{"df":0,"docs":{},"u":{"df":2,"docs":{"218":{"tf":1.7320508075688772},"219":{"tf":1.4142135623730951}}}},"r":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"43":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":4,"docs":{"62":{"tf":2.449489742783178},"69":{"tf":1.7320508075688772},"71":{"tf":1.4142135623730951},"73":{"tf":1.0}},"s":{"/":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"/":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"j":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"89":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"r":{"c":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"82":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"r":{"c":{"/":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"b":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"94":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":1,"docs":{"73":{"tf":1.0}}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"r":{"c":{"/":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"b":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"94":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"94":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":11,"docs":{"100":{"tf":1.0},"161":{"tf":1.0},"190":{"tf":1.0},"192":{"tf":1.0},"205":{"tf":1.7320508075688772},"206":{"tf":1.7320508075688772},"224":{"tf":1.0},"43":{"tf":2.0},"62":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0}},"e":{"(":{"$":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"205":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"205":{"tf":1.0}}},"df":0,"docs":{}}},"2":{"(":{"$":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"206":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"206":{"tf":1.0}}},"df":0,"docs":{}}},"df":4,"docs":{"100":{"tf":1.0},"190":{"tf":1.0},"206":{"tf":1.4142135623730951},"43":{"tf":1.4142135623730951}}},"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"d":{":":{":":{"c":{"df":0,"docs":{},"r":{"df":1,"docs":{"205":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"2":{"df":1,"docs":{"206":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":3,"docs":{"190":{"tf":1.0},"200":{"tf":1.0},"224":{"tf":1.0}}}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"92":{"tf":1.0}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":9,"docs":{"174":{"tf":1.0},"200":{"tf":1.0},"225":{"tf":2.0},"226":{"tf":1.0},"227":{"tf":1.7320508075688772},"61":{"tf":1.0},"71":{"tf":1.4142135623730951},"73":{"tf":1.0},"93":{"tf":1.0}}}}},"u":{"c":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":2,"docs":{"75":{"tf":1.0},"95":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":30,"docs":{"141":{"tf":1.0},"142":{"tf":1.0},"144":{"tf":1.0},"150":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"162":{"tf":1.0},"165":{"tf":1.0},"167":{"tf":1.0},"179":{"tf":1.0},"183":{"tf":1.0},"187":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"208":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"213":{"tf":1.0},"233":{"tf":1.0},"33":{"tf":1.0},"89":{"tf":1.0},"93":{"tf":1.4142135623730951}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"(":{"0":{"df":0,"docs":{},"x":{"<":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":1,"docs":{"216":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":2,"docs":{"100":{"tf":1.0},"216":{"tf":1.4142135623730951}}}}}}}}},"df":0,"docs":{}}}}}}},"df":6,"docs":{"216":{"tf":1.0},"236":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.7320508075688772},"75":{"tf":1.4142135623730951},"86":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"86":{"tf":1.0}}}}}}}}}}}}}}}}}}},"d":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":7,"docs":{"1":{"tf":1.0},"18":{"tf":1.0},"232":{"tf":1.4142135623730951},"235":{"tf":1.4142135623730951},"34":{"tf":1.0},"39":{"tf":1.0},"52":{"tf":1.4142135623730951}}}},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"98":{"tf":1.0}}}},"t":{"a":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":2,"docs":{"100":{"tf":1.0},"186":{"tf":1.4142135623730951}}},"y":{"(":{"$":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"186":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"186":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":21,"docs":{"161":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"18":{"tf":1.0},"182":{"tf":1.0},"185":{"tf":1.4142135623730951},"186":{"tf":1.4142135623730951},"201":{"tf":1.7320508075688772},"207":{"tf":1.7320508075688772},"209":{"tf":1.7320508075688772},"210":{"tf":1.7320508075688772},"211":{"tf":1.0},"215":{"tf":2.449489742783178},"223":{"tf":1.4142135623730951},"35":{"tf":1.0},"49":{"tf":1.0},"57":{"tf":2.0},"70":{"tf":1.0},"87":{"tf":1.0},"91":{"tf":1.0},"95":{"tf":1.0}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"(":{"\\"":{"<":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"170":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"170":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":4,"docs":{"100":{"tf":1.0},"170":{"tf":1.4142135623730951},"43":{"tf":1.0},"44":{"tf":1.4142135623730951}}}}}}}},"s":{"df":4,"docs":{"100":{"tf":1.0},"171":{"tf":1.4142135623730951},"43":{"tf":1.0},"45":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"(":{"\\"":{"<":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"171":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"171":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"’":{"df":1,"docs":{"185":{"tf":1.0}}}},"df":0,"docs":{}},"y":{"df":2,"docs":{"167":{"tf":1.0},"179":{"tf":1.0}}}},"b":{"c":{"df":0,"docs":{},"f":{"c":{"9":{"2":{"1":{"df":1,"docs":{"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"95":{"tf":1.0}},"’":{"d":{"df":1,"docs":{"174":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":3,"docs":{"52":{"tf":1.0},"75":{"tf":1.4142135623730951},"92":{"tf":1.0}}},"df":0,"docs":{},"l":{"df":1,"docs":{"39":{"tf":1.0}}}},"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":11,"docs":{"135":{"tf":1.0},"16":{"tf":2.0},"17":{"tf":2.0},"26":{"tf":1.0},"30":{"tf":1.0},"53":{"tf":1.0},"57":{"tf":1.0},"94":{"tf":2.0},"97":{"tf":1.4142135623730951},"98":{"tf":1.4142135623730951},"99":{"tf":1.0}}}}},"c":{"df":0,"docs":{},"i":{"d":{"df":2,"docs":{"18":{"tf":1.0},"224":{"tf":1.0}}},"df":0,"docs":{},"m":{"df":1,"docs":{"99":{"tf":1.0}}},"s":{"df":5,"docs":{"219":{"tf":1.0},"235":{"tf":1.0},"64":{"tf":1.0},"74":{"tf":1.0},"93":{"tf":1.0}}}},"l":{"a":{"df":0,"docs":{},"r":{"df":6,"docs":{"107":{"tf":1.0},"169":{"tf":1.4142135623730951},"174":{"tf":1.7320508075688772},"181":{"tf":1.7320508075688772},"198":{"tf":1.0},"223":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"92":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":2,"docs":{"69":{"tf":1.0},"81":{"tf":1.0}}}}}}},"d":{"df":0,"docs":{},"i":{"c":{"df":5,"docs":{"190":{"tf":1.4142135623730951},"62":{"tf":1.0},"69":{"tf":1.0},"82":{"tf":1.0},"83":{"tf":1.0}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"p":{"df":3,"docs":{"138":{"tf":1.0},"179":{"tf":1.0},"75":{"tf":1.7320508075688772}},"l":{"df":12,"docs":{"106":{"tf":1.0},"146":{"tf":1.0},"175":{"tf":1.0},"208":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":1.4142135623730951},"85":{"tf":1.7320508075688772},"87":{"tf":1.0},"91":{"tf":1.0},"93":{"tf":1.4142135623730951},"95":{"tf":1.0},"98":{"tf":1.0}},"i":{"c":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"’":{"df":2,"docs":{"167":{"tf":1.0},"179":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":13,"docs":{"103":{"tf":1.4142135623730951},"107":{"tf":1.7320508075688772},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"17":{"tf":1.0},"194":{"tf":2.23606797749979},"73":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.0},"98":{"tf":1.4142135623730951},"99":{"tf":1.0}}}}}},"df":1,"docs":{"75":{"tf":1.0}},"i":{"df":1,"docs":{"52":{"tf":1.0}},"n":{"df":5,"docs":{"174":{"tf":1.0},"178":{"tf":1.0},"190":{"tf":1.0},"221":{"tf":1.0},"223":{"tf":2.0}},"i":{"df":0,"docs":{},"t":{"df":3,"docs":{"75":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"64":{"tf":1.0},"65":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"a":{"df":0,"docs":{},"l":{"df":5,"docs":{"100":{"tf":1.0},"18":{"tf":1.0},"190":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.4142135623730951}},"l":{"(":{"$":{"df":0,"docs":{},"g":{"a":{"df":1,"docs":{"203":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"203":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"t":{"df":2,"docs":{"213":{"tf":1.0},"64":{"tf":1.0}}}},"i":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"181":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"df":1,"docs":{"236":{"tf":1.0}}}}},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":4,"docs":{"75":{"tf":1.4142135623730951},"78":{"tf":2.23606797749979},"91":{"tf":1.0},"95":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"63":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":9,"docs":{"147":{"tf":1.0},"166":{"tf":1.0},"18":{"tf":1.4142135623730951},"226":{"tf":1.7320508075688772},"62":{"tf":3.0},"68":{"tf":1.0},"71":{"tf":2.0},"8":{"tf":1.4142135623730951},"99":{"tf":1.0}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":12,"docs":{"163":{"tf":1.4142135623730951},"164":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"18":{"tf":3.3166247903554},"205":{"tf":1.0},"206":{"tf":1.0},"233":{"tf":1.4142135623730951},"34":{"tf":1.0},"35":{"tf":2.0},"43":{"tf":2.23606797749979},"75":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"c":{"df":3,"docs":{"202":{"tf":1.0},"213":{"tf":1.0},"52":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":5,"docs":{"179":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"51":{"tf":1.0},"81":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":2,"docs":{"98":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":106,"docs":{"102":{"tf":1.0},"107":{"tf":1.0},"108":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.4142135623730951},"147":{"tf":1.4142135623730951},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.4142135623730951},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.4142135623730951},"167":{"tf":1.4142135623730951},"168":{"tf":1.4142135623730951},"169":{"tf":1.4142135623730951},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"98":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":4,"docs":{"219":{"tf":1.4142135623730951},"52":{"tf":1.0},"64":{"tf":1.0},"76":{"tf":1.7320508075688772}}}},"r":{"df":2,"docs":{"31":{"tf":1.0},"53":{"tf":1.0}}}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"81":{"tf":1.0}}}}},"t":{"df":7,"docs":{"178":{"tf":1.7320508075688772},"183":{"tf":1.4142135623730951},"184":{"tf":1.7320508075688772},"185":{"tf":1.4142135623730951},"186":{"tf":1.4142135623730951},"187":{"tf":1.4142135623730951},"223":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":11,"docs":{"135":{"tf":2.23606797749979},"136":{"tf":1.7320508075688772},"137":{"tf":2.0},"178":{"tf":1.7320508075688772},"182":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"201":{"tf":1.0}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":5,"docs":{"11":{"tf":1.0},"224":{"tf":1.0},"76":{"tf":1.0},"94":{"tf":1.0},"97":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":6,"docs":{"40":{"tf":1.0},"75":{"tf":1.7320508075688772},"79":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":1.0},"95":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"166":{"tf":1.0},"207":{"tf":1.4142135623730951},"75":{"tf":1.0},"80":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"138":{"tf":1.0},"206":{"tf":1.0},"68":{"tf":1.0}}}}}}}}}}},"v":{"df":2,"docs":{"53":{"tf":1.0},"62":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":178,"docs":{"1":{"tf":1.4142135623730951},"100":{"tf":1.0},"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"106":{"tf":1.0},"107":{"tf":1.0},"108":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"16":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"17":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"182":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"192":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"20":{"tf":1.0},"200":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"208":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"217":{"tf":1.0},"218":{"tf":1.0},"219":{"tf":1.0},"220":{"tf":1.0},"221":{"tf":1.0},"222":{"tf":1.0},"223":{"tf":1.0},"224":{"tf":1.0},"225":{"tf":1.0},"226":{"tf":1.0},"227":{"tf":1.0},"236":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0},"52":{"tf":1.0},"58":{"tf":1.7320508075688772},"59":{"tf":1.0},"60":{"tf":1.0},"61":{"tf":1.7320508075688772},"62":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"77":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0},"85":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.0},"88":{"tf":1.0},"89":{"tf":1.0},"90":{"tf":1.4142135623730951},"91":{"tf":2.23606797749979},"92":{"tf":1.0},"93":{"tf":1.0},"94":{"tf":1.0},"95":{"tf":1.0},"96":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}}}}}}},"i":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"34":{"tf":1.0},"76":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":27,"docs":{"0":{"tf":2.23606797749979},"1":{"tf":1.0},"12":{"tf":1.0},"222":{"tf":1.0},"230":{"tf":1.0},"24":{"tf":1.0},"34":{"tf":2.0},"35":{"tf":1.0},"36":{"tf":1.4142135623730951},"37":{"tf":1.0},"38":{"tf":1.0},"39":{"tf":1.4142135623730951},"40":{"tf":1.4142135623730951},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.7320508075688772},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"50":{"tf":2.23606797749979},"51":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.4142135623730951},"85":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":5,"docs":{"223":{"tf":3.1622776601683795},"224":{"tf":2.23606797749979},"35":{"tf":1.0},"68":{"tf":1.0},"91":{"tf":1.0}}}}}}}},"i":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"100":{"tf":1.0},"151":{"tf":2.23606797749979},"47":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"214":{"tf":1.0}}}}},"r":{"df":2,"docs":{"16":{"tf":1.0},"62":{"tf":1.0}},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":8,"docs":{"107":{"tf":1.0},"134":{"tf":1.0},"137":{"tf":1.0},"178":{"tf":1.0},"189":{"tf":1.0},"19":{"tf":1.0},"198":{"tf":1.0},"78":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":5,"docs":{"16":{"tf":1.0},"18":{"tf":1.4142135623730951},"54":{"tf":1.0},"62":{"tf":1.0},"94":{"tf":2.0}}}}}}},"df":0,"docs":{}}},"s":{"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"17":{"tf":1.0},"18":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"a":{"df":0,"docs":{},"r":{"d":{"df":2,"docs":{"135":{"tf":1.0},"190":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"43":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"63":{"tf":1.0},"65":{"tf":1.0}}}}}},"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"h":{"df":3,"docs":{"194":{"tf":1.0},"87":{"tf":1.0},"90":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"137":{"tf":1.0},"174":{"tf":1.0},"91":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"82":{"tf":1.0}}}}}}}}},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":2,"docs":{"71":{"tf":1.0},"9":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"v":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"112":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"112":{"tf":1.0}}},"df":0,"docs":{}},"x":{"df":1,"docs":{"112":{"tf":1.0}}}},"df":2,"docs":{"100":{"tf":1.0},"112":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"93":{"tf":1.0}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":4,"docs":{"112":{"tf":1.4142135623730951},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{},"s":{"df":3,"docs":{"112":{"tf":1.4142135623730951},"113":{"tf":1.0},"214":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"89":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"r":{"df":4,"docs":{"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0}}}}}}}},"o":{"c":{"df":1,"docs":{"64":{"tf":1.0}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"227":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"3":{"tf":1.0},"8":{"tf":1.0}}}}}}}},"df":1,"docs":{"0":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":9,"docs":{"103":{"tf":1.0},"105":{"tf":1.0},"19":{"tf":1.0},"37":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.0},"70":{"tf":1.0},"80":{"tf":1.0},"82":{"tf":1.0}}}}}}},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"72":{"tf":1.0},"73":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.0}}},"’":{"df":0,"docs":{},"t":{"df":5,"docs":{"229":{"tf":1.0},"39":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.4142135623730951},"71":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"167":{"tf":1.0},"179":{"tf":1.0}}}}},"df":0,"docs":{}}},"u":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"x":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"111":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"w":{"df":0,"docs":{},"n":{"df":3,"docs":{"103":{"tf":1.0},"219":{"tf":1.0},"53":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"m":{"df":2,"docs":{"79":{"tf":1.0},"92":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"86":{"tf":1.0}}}}}},"r":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"91":{"tf":1.0}}}}},"df":1,"docs":{"235":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"90":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"df":2,"docs":{"105":{"tf":1.0},"82":{"tf":1.0}},"n":{"df":2,"docs":{"78":{"tf":1.4142135623730951},"91":{"tf":1.0}}},"r":{"df":3,"docs":{"19":{"tf":1.0},"5":{"tf":1.0},"67":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"p":{"df":3,"docs":{"181":{"tf":1.0},"234":{"tf":1.7320508075688772},"81":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"e":{"df":6,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"18":{"tf":1.7320508075688772},"222":{"tf":1.0},"43":{"tf":1.0},"68":{"tf":1.0}}},"m":{"df":0,"docs":{},"p":{"df":9,"docs":{"108":{"tf":1.4142135623730951},"16":{"tf":1.0},"167":{"tf":1.0},"179":{"tf":1.0},"189":{"tf":1.0},"94":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"75":{"tf":1.0},"86":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"179":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":6,"docs":{"172":{"tf":1.0},"18":{"tf":1.4142135623730951},"191":{"tf":1.0},"210":{"tf":1.0},"71":{"tf":1.0},"8":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"m":{"df":11,"docs":{"105":{"tf":1.4142135623730951},"14":{"tf":1.0},"166":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"179":{"tf":1.0},"68":{"tf":1.0},"76":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"94":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"g":{"df":6,"docs":{"107":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"81":{"tf":1.0},"85":{"tf":1.0},"98":{"tf":1.4142135623730951}}}},"a":{"c":{"df":0,"docs":{},"h":{"df":13,"docs":{"106":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"192":{"tf":1.0},"194":{"tf":1.7320508075688772},"195":{"tf":2.23606797749979},"223":{"tf":1.4142135623730951},"52":{"tf":1.0},"78":{"tf":1.0},"91":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"224":{"tf":1.0},"91":{"tf":2.0}},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"174":{"tf":1.0},"188":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"i":{"df":2,"docs":{"5":{"tf":1.0},"82":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"52":{"tf":1.0},"64":{"tf":1.0}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"235":{"tf":1.0}}}}}}}}}},"d":{"df":1,"docs":{"94":{"tf":1.0}},"g":{"df":2,"docs":{"235":{"tf":1.0},"76":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":50,"docs":{"106":{"tf":1.4142135623730951},"147":{"tf":1.4142135623730951},"158":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":1.4142135623730951},"175":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.4142135623730951},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.4142135623730951},"182":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.4142135623730951},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"219":{"tf":1.0},"223":{"tf":1.0},"76":{"tf":1.7320508075688772},"81":{"tf":1.0},"94":{"tf":1.4142135623730951},"98":{"tf":2.0}}}},"df":0,"docs":{}},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"219":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"235":{"tf":1.0},"52":{"tf":1.0},"64":{"tf":1.0},"66":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"p":{"df":2,"docs":{"153":{"tf":1.0},"154":{"tf":1.0}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"169":{"tf":1.0},"181":{"tf":1.0}}}}}}},"f":{"df":5,"docs":{"16":{"tf":1.0},"18":{"tf":1.4142135623730951},"218":{"tf":1.0},"225":{"tf":1.0},"67":{"tf":1.4142135623730951}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":17,"docs":{"105":{"tf":1.0},"106":{"tf":1.0},"108":{"tf":1.0},"147":{"tf":1.0},"198":{"tf":1.0},"224":{"tf":1.0},"235":{"tf":1.0},"75":{"tf":1.7320508075688772},"78":{"tf":1.0},"81":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":1.0},"92":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.7320508075688772},"98":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"193":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"w":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"106":{"tf":1.0}}}}}}}}},"m":{"b":{"df":0,"docs":{},"e":{"d":{"df":3,"docs":{"182":{"tf":1.0},"186":{"tf":1.0},"219":{"tf":1.0}}},"df":0,"docs":{}}},"df":1,"docs":{"98":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"200":{"tf":1.0}}}},"t":{"df":19,"docs":{"139":{"tf":1.0},"140":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":1.0},"18":{"tf":1.0},"181":{"tf":1.0},"195":{"tf":1.0},"207":{"tf":1.0},"214":{"tf":1.0},"236":{"tf":1.4142135623730951},"35":{"tf":1.0},"39":{"tf":1.0},"67":{"tf":1.0},"69":{"tf":1.0},"70":{"tf":1.4142135623730951},"78":{"tf":1.0},"79":{"tf":1.0},"81":{"tf":1.0},"99":{"tf":1.0}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"68":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"i":{"df":5,"docs":{"193":{"tf":1.0},"195":{"tf":1.0},"198":{"tf":1.0},"211":{"tf":1.0},"57":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":3,"docs":{"226":{"tf":1.7320508075688772},"7":{"tf":1.0},"71":{"tf":1.0}}}}}}}}},"d":{"df":0,"docs":{},"k":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"s":{"d":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"226":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":1,"docs":{"226":{"tf":1.0}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"l":{"df":26,"docs":{"103":{"tf":1.0},"104":{"tf":1.0},"138":{"tf":1.0},"14":{"tf":1.0},"147":{"tf":1.0},"166":{"tf":1.0},"175":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"182":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"201":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"40":{"tf":1.0},"70":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.0}}}}},"n":{"a":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"26":{"tf":1.0},"73":{"tf":1.4142135623730951},"78":{"tf":1.0},"79":{"tf":1.0},"93":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":2,"docs":{"61":{"tf":1.0},"69":{"tf":1.0}}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":3,"docs":{"192":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0}}}}},"o":{"d":{"df":6,"docs":{"173":{"tf":1.0},"208":{"tf":1.0},"214":{"tf":1.0},"216":{"tf":1.4142135623730951},"82":{"tf":1.0},"86":{"tf":1.4142135623730951}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"221":{"tf":1.0}}}},"df":0,"docs":{}}}}},"d":{"df":12,"docs":{"159":{"tf":1.0},"168":{"tf":1.0},"180":{"tf":1.0},"183":{"tf":1.0},"185":{"tf":1.0},"187":{"tf":1.0},"208":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"213":{"tf":1.0},"52":{"tf":1.4142135623730951}},"i":{"a":{"df":0,"docs":{},"n":{"df":9,"docs":{"104":{"tf":2.23606797749979},"166":{"tf":1.0},"176":{"tf":1.4142135623730951},"70":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":2.0},"75":{"tf":1.0},"80":{"tf":1.4142135623730951},"81":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"81":{"tf":1.0}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"52":{"tf":1.0},"66":{"tf":1.0}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"64":{"tf":1.0}}}}}}},"j":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":1,"docs":{"65":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":3,"docs":{"64":{"tf":1.0},"65":{"tf":1.0},"74":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"223":{"tf":1.4142135623730951},"63":{"tf":1.0},"68":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"189":{"tf":1.0}}}},"i":{"df":0,"docs":{},"r":{"df":2,"docs":{"108":{"tf":1.0},"219":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"df":8,"docs":{"101":{"tf":1.0},"189":{"tf":1.4142135623730951},"198":{"tf":1.0},"207":{"tf":1.0},"235":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":2.23606797749979},"99":{"tf":1.7320508075688772}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}}}},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"102":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"97":{"tf":1.0},"99":{"tf":1.0}}}}}},"v":{"df":1,"docs":{"226":{"tf":1.0}},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":10,"docs":{"100":{"tf":1.0},"220":{"tf":2.0},"225":{"tf":1.0},"226":{"tf":1.4142135623730951},"53":{"tf":1.0},"55":{"tf":1.0},"73":{"tf":1.0},"75":{"tf":1.0},"94":{"tf":1.7320508075688772},"95":{"tf":1.0}}}}}}}},"p":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"149":{"tf":1.0}}}},"df":0,"docs":{}}},"q":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"127":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"127":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"127":{"tf":1.4142135623730951},"79":{"tf":1.0}},"u":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"127":{"tf":1.0},"135":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":11,"docs":{"133":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"219":{"tf":1.0},"4":{"tf":1.0},"90":{"tf":1.0},"94":{"tf":1.0}}}},"df":0,"docs":{}}}}},"r":{"c":{"1":{"1":{"5":{"5":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"0":{"df":2,"docs":{"89":{"tf":1.0},"90":{"tf":1.0}}},"df":0,"docs":{}},"7":{"2":{"1":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"r":{"(":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"(":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"(":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"215":{"tf":1.0}}}}}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"(":{"1":{"2":{"df":1,"docs":{"215":{"tf":1.0}}},"df":0,"docs":{}},"<":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"215":{"tf":1.0}}}}}}}}},"df":0,"docs":{}},"df":2,"docs":{"100":{"tf":1.0},"215":{"tf":1.4142135623730951}}}}}}}}},"df":0,"docs":{}}}}}}}},"df":13,"docs":{"208":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.7320508075688772},"223":{"tf":1.0},"39":{"tf":1.0},"40":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"75":{"tf":1.0},"85":{"tf":1.0},"86":{"tf":1.4142135623730951},"87":{"tf":1.0},"93":{"tf":1.0}}}}}},"s":{"c":{"a":{"df":0,"docs":{},"p":{"df":3,"docs":{"75":{"tf":1.0},"80":{"tf":1.0},"94":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":2,"docs":{"189":{"tf":1.0},"91":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"t":{"c":{"df":4,"docs":{"101":{"tf":1.4142135623730951},"190":{"tf":1.0},"75":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"/":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"d":{"/":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"/":{":":{"$":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"221":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":14,"docs":{"0":{"tf":1.0},"103":{"tf":1.0},"11":{"tf":1.0},"221":{"tf":1.7320508075688772},"222":{"tf":1.7320508075688772},"223":{"tf":2.23606797749979},"235":{"tf":1.0},"34":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"49":{"tf":1.0},"6":{"tf":1.0},"66":{"tf":1.4142135623730951},"8":{"tf":1.0}}}}}}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":6,"docs":{"138":{"tf":1.0},"146":{"tf":1.4142135623730951},"188":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"195":{"tf":1.7320508075688772}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":5,"docs":{"219":{"tf":1.0},"235":{"tf":1.0},"52":{"tf":1.0},"65":{"tf":1.0},"82":{"tf":1.4142135623730951}},"t":{"df":3,"docs":{"200":{"tf":1.0},"207":{"tf":1.0},"89":{"tf":1.0}},"u":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"105":{"tf":1.0}}}}}}},"m":{".":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":79,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"103":{"tf":1.0},"104":{"tf":1.4142135623730951},"105":{"tf":1.0},"109":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"134":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"14":{"tf":1.4142135623730951},"147":{"tf":1.0},"156":{"tf":1.0},"166":{"tf":1.4142135623730951},"174":{"tf":1.0},"175":{"tf":1.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.0},"178":{"tf":1.4142135623730951},"180":{"tf":1.0},"182":{"tf":1.4142135623730951},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.7320508075688772},"186":{"tf":1.0},"187":{"tf":1.0},"190":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"219":{"tf":2.23606797749979},"221":{"tf":1.0},"222":{"tf":1.0},"223":{"tf":2.6457513110645907},"229":{"tf":1.7320508075688772},"233":{"tf":1.0},"33":{"tf":1.7320508075688772},"34":{"tf":2.0},"35":{"tf":1.4142135623730951},"36":{"tf":1.0},"37":{"tf":1.0},"38":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.7320508075688772},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.7320508075688772},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.4142135623730951},"49":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.4142135623730951},"52":{"tf":1.7320508075688772},"70":{"tf":2.23606797749979},"72":{"tf":1.4142135623730951},"73":{"tf":1.0},"74":{"tf":2.0},"78":{"tf":1.0},"80":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.0}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":1,"docs":{"90":{"tf":1.0}}}}}},"x":{"a":{"c":{"df":0,"docs":{},"t":{"df":5,"docs":{"18":{"tf":1.0},"218":{"tf":1.0},"224":{"tf":1.0},"75":{"tf":1.7320508075688772},"95":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":4,"docs":{"105":{"tf":1.0},"176":{"tf":1.0},"223":{"tf":1.0},"68":{"tf":1.0}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":120,"docs":{"0":{"tf":1.0},"106":{"tf":1.0},"107":{"tf":1.0},"108":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"18":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"223":{"tf":1.4142135623730951},"224":{"tf":1.0},"226":{"tf":1.0},"227":{"tf":1.0},"5":{"tf":1.0},"51":{"tf":1.4142135623730951},"52":{"tf":1.4142135623730951},"57":{"tf":1.4142135623730951},"61":{"tf":1.0},"63":{"tf":1.0},"68":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":2,"docs":{"112":{"tf":1.0},"92":{"tf":1.0}},"l":{"df":1,"docs":{"52":{"tf":1.0}}},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"63":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"169":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":26,"docs":{"12":{"tf":1.7320508075688772},"13":{"tf":1.0},"14":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"15":{"tf":1.0},"157":{"tf":1.0},"162":{"tf":1.0},"165":{"tf":1.0},"183":{"tf":1.4142135623730951},"193":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"219":{"tf":1.4142135623730951},"223":{"tf":2.449489742783178},"224":{"tf":1.0},"225":{"tf":1.0},"226":{"tf":1.0},"227":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951},"55":{"tf":1.4142135623730951},"57":{"tf":1.0},"91":{"tf":1.0}}}}},"df":0,"docs":{}},"h":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":7,"docs":{"108":{"tf":1.0},"11":{"tf":1.0},"164":{"tf":1.0},"184":{"tf":1.0},"213":{"tf":1.0},"233":{"tf":1.0},"93":{"tf":1.0}}}},"t":{"df":4,"docs":{"195":{"tf":1.7320508075688772},"196":{"tf":1.0},"198":{"tf":1.4142135623730951},"87":{"tf":1.0}}}},"p":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"116":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"116":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"116":{"tf":1.4142135623730951}},"e":{"c":{"df":0,"docs":{},"t":{"df":5,"docs":{"108":{"tf":1.0},"223":{"tf":1.4142135623730951},"43":{"tf":1.4142135623730951},"52":{"tf":1.0},"64":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":4,"docs":{"116":{"tf":1.0},"219":{"tf":1.7320508075688772},"52":{"tf":1.0},"78":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"72":{"tf":1.0},"73":{"tf":1.0}}}}}}}}},"l":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":5,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"221":{"tf":1.0},"64":{"tf":1.0},"77":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":5,"docs":{"18":{"tf":1.0},"192":{"tf":1.0},"195":{"tf":1.0},"76":{"tf":1.4142135623730951},"79":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.0}}}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"78":{"tf":1.0}}}},"r":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"116":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":2,"docs":{"116":{"tf":1.4142135623730951},"14":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"221":{"tf":1.0},"226":{"tf":1.4142135623730951}}}},"s":{"df":5,"docs":{"12":{"tf":1.0},"19":{"tf":1.0},"220":{"tf":1.0},"75":{"tf":1.4142135623730951},"81":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":19,"docs":{"100":{"tf":1.4142135623730951},"106":{"tf":2.449489742783178},"107":{"tf":1.0},"108":{"tf":1.0},"146":{"tf":1.4142135623730951},"170":{"tf":1.0},"172":{"tf":1.0},"175":{"tf":1.0},"179":{"tf":1.0},"188":{"tf":1.4142135623730951},"189":{"tf":2.449489742783178},"190":{"tf":2.8284271247461903},"195":{"tf":1.4142135623730951},"64":{"tf":1.7320508075688772},"75":{"tf":1.0},"76":{"tf":1.4142135623730951},"95":{"tf":1.0},"97":{"tf":1.4142135623730951},"98":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"144":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"b":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"165":{"tf":1.0}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":1,"docs":{"153":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":22,"docs":{"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"137":{"tf":1.0}}}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"b":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":1,"docs":{"154":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"155":{"tf":1.0}}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"156":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"141":{"tf":1.0},"174":{"tf":1.0},"190":{"tf":1.0}},"l":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"159":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":1,"docs":{"160":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"142":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"145":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"o":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":1,"docs":{"162":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"b":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"148":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"170":{"tf":1.0}}}}}}}},"s":{"df":1,"docs":{"171":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"151":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"164":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":1,"docs":{"163":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"g":{"a":{"df":1,"docs":{"146":{"tf":1.0}},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"152":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"158":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"k":{"df":0,"docs":{},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"df":1,"docs":{"138":{"tf":1.0}},"p":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"139":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":1,"docs":{"140":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"173":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"107":{"tf":1.0}}}}}},"o":{"a":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"172":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"m":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"169":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"166":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":1,"docs":{"147":{"tf":1.0}}}},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"b":{"df":1,"docs":{"150":{"tf":1.0}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"143":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"161":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"b":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"157":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":2,"docs":{"129":{"tf":1.0},"137":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"167":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"130":{"tf":1.0},"131":{"tf":1.0}}}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":1,"docs":{"149":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"168":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"135":{"tf":1.0}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":3,"docs":{"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0}}}}},"df":0,"docs":{}}},"v":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"108":{"tf":1.0}}}},"df":0,"docs":{}},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"136":{"tf":1.0}}},"df":0,"docs":{}}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"’":{"df":1,"docs":{"189":{"tf":1.0}}}}}}}}}}},"t":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":3,"docs":{"100":{"tf":1.0},"184":{"tf":1.4142135623730951},"48":{"tf":1.4142135623730951}}},"y":{"(":{"$":{"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"184":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"184":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"(":{"$":{"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"164":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"164":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"164":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"s":{"df":2,"docs":{"100":{"tf":1.0},"163":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"(":{"$":{"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"163":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"163":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":5,"docs":{"129":{"tf":1.7320508075688772},"137":{"tf":1.4142135623730951},"176":{"tf":1.0},"81":{"tf":1.0},"93":{"tf":1.4142135623730951}}},"df":0,"docs":{},"s":{"df":1,"docs":{"129":{"tf":1.0}}}},"r":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"l":{"c":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"161":{"tf":1.0},"78":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":12,"docs":{"100":{"tf":1.0},"143":{"tf":1.0},"173":{"tf":1.0},"175":{"tf":1.0},"18":{"tf":1.4142135623730951},"182":{"tf":1.0},"184":{"tf":1.0},"190":{"tf":1.0},"200":{"tf":2.0},"201":{"tf":1.0},"204":{"tf":1.4142135623730951},"80":{"tf":1.4142135623730951}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"128":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"f":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"5":{"tf":1.0}}},"t":{"df":3,"docs":{"18":{"tf":1.0},"219":{"tf":1.0},"65":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"131":{"tf":1.4142135623730951}},"i":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":3,"docs":{"18":{"tf":1.4142135623730951},"233":{"tf":1.4142135623730951},"65":{"tf":1.0}},"u":{"df":0,"docs":{},"r":{"df":5,"docs":{"205":{"tf":1.4142135623730951},"206":{"tf":1.0},"212":{"tf":1.0},"214":{"tf":1.0},"82":{"tf":1.0}}}}}},"l":{"df":0,"docs":{},"l":{"b":{"a":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"105":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":8,"docs":{"122":{"tf":1.0},"174":{"tf":1.0},"179":{"tf":1.0},"194":{"tf":1.0},"199":{"tf":1.0},"219":{"tf":1.0},"43":{"tf":1.0},"93":{"tf":1.0}}},"s":{"df":1,"docs":{"80":{"tf":1.0}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"43":{"tf":1.0},"79":{"tf":1.0}}}}}},"q":{"df":7,"docs":{"228":{"tf":1.7320508075688772},"229":{"tf":1.0},"230":{"tf":1.0},"231":{"tf":1.0},"232":{"tf":1.0},"233":{"tf":1.0},"234":{"tf":1.0}}},"r":{"df":2,"docs":{"219":{"tf":1.0},"52":{"tf":1.0}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"219":{"tf":1.0},"4":{"tf":1.0}}}}}}},"df":1,"docs":{"57":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"66":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":6,"docs":{"18":{"tf":1.0},"221":{"tf":1.0},"230":{"tf":1.0},"232":{"tf":1.0},"236":{"tf":1.0},"4":{"tf":1.0}}}}}},"b":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"91":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":2,"docs":{"153":{"tf":1.0},"154":{"tf":1.0}}},"w":{"df":4,"docs":{"11":{"tf":1.0},"24":{"tf":1.0},"40":{"tf":1.0},"64":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"75":{"tf":1.0},"79":{"tf":1.0}}}}}},"i":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"a":{"c":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"89":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"d":{"df":25,"docs":{"107":{"tf":1.0},"135":{"tf":1.4142135623730951},"136":{"tf":1.4142135623730951},"137":{"tf":1.4142135623730951},"166":{"tf":1.0},"167":{"tf":1.4142135623730951},"170":{"tf":1.4142135623730951},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"179":{"tf":1.4142135623730951},"191":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"207":{"tf":1.0},"214":{"tf":1.4142135623730951},"215":{"tf":1.7320508075688772},"216":{"tf":1.4142135623730951},"32":{"tf":2.0},"33":{"tf":1.4142135623730951},"98":{"tf":2.0},"99":{"tf":1.0}}},"df":0,"docs":{}}},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"90":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":8,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"32":{"tf":2.8284271247461903},"33":{"tf":1.4142135623730951},"57":{"tf":1.0},"62":{"tf":1.4142135623730951},"67":{"tf":1.0},"90":{"tf":1.0}}},"l":{"df":4,"docs":{"116":{"tf":1.0},"121":{"tf":1.0},"133":{"tf":1.0},"136":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"55":{"tf":1.0}}}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"195":{"tf":1.0},"223":{"tf":1.0},"226":{"tf":1.4142135623730951},"67":{"tf":1.0}}}},"d":{"df":4,"docs":{"1":{"tf":1.0},"232":{"tf":1.0},"7":{"tf":1.0},"93":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"55":{"tf":1.0},"61":{"tf":1.0},"68":{"tf":1.0}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}},"t":{"df":1,"docs":{"14":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"94":{"tf":1.0}}},"s":{"df":0,"docs":{},"t":{"df":9,"docs":{"106":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"139":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"236":{"tf":1.0},"32":{"tf":1.0},"91":{"tf":1.0}}}}},"t":{"df":7,"docs":{"117":{"tf":1.0},"134":{"tf":1.0},"166":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.4142135623730951},"81":{"tf":1.0}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"182":{"tf":1.4142135623730951}}}},"x":{"df":7,"docs":{"0":{"tf":1.4142135623730951},"221":{"tf":1.0},"40":{"tf":1.4142135623730951},"63":{"tf":1.0},"65":{"tf":1.0},"82":{"tf":2.0},"93":{"tf":1.0}}}},"l":{"a":{"df":0,"docs":{},"g":{"df":10,"docs":{"18":{"tf":1.0},"198":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"57":{"tf":2.0},"70":{"tf":1.0},"73":{"tf":1.0},"94":{"tf":1.0}}},"t":{"df":1,"docs":{"74":{"tf":1.0}}},"w":{"df":1,"docs":{"219":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":1,"docs":{"94":{"tf":1.0}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}}},"df":2,"docs":{"89":{"tf":1.0},"90":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"w":{"df":13,"docs":{"100":{"tf":1.0},"189":{"tf":1.4142135623730951},"192":{"tf":2.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"76":{"tf":2.0},"93":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}}}}},"m":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"f":{"df":1,"docs":{"81":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"75":{"tf":1.0}}}}}}},"df":7,"docs":{"166":{"tf":1.0},"176":{"tf":1.0},"216":{"tf":1.0},"81":{"tf":2.0},"82":{"tf":3.0},"92":{"tf":1.0},"95":{"tf":1.0}}}},"o":{"c":{"df":0,"docs":{},"u":{"df":1,"docs":{"236":{"tf":1.0}},"s":{"df":1,"docs":{"91":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"d":{"df":3,"docs":{"75":{"tf":1.7320508075688772},"83":{"tf":1.7320508075688772},"95":{"tf":1.4142135623730951}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":25,"docs":{"10":{"tf":1.0},"12":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"169":{"tf":1.0},"178":{"tf":1.0},"181":{"tf":1.0},"195":{"tf":1.0},"222":{"tf":1.0},"223":{"tf":1.0},"224":{"tf":1.0},"36":{"tf":1.0},"52":{"tf":1.0},"6":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"67":{"tf":1.4142135623730951},"68":{"tf":1.0},"7":{"tf":1.0},"75":{"tf":1.0},"84":{"tf":1.4142135623730951},"93":{"tf":1.0},"98":{"tf":1.4142135623730951},"99":{"tf":1.4142135623730951}}}}}},"r":{"c":{"df":1,"docs":{"63":{"tf":1.0}}},"df":0,"docs":{},"k":{"df":2,"docs":{"21":{"tf":1.7320508075688772},"23":{"tf":1.0}}},"m":{"a":{"df":0,"docs":{},"t":{"df":4,"docs":{"18":{"tf":1.0},"223":{"tf":1.0},"224":{"tf":1.0},"98":{"tf":1.4142135623730951}},"t":{"df":1,"docs":{"64":{"tf":1.0}}}}},"df":11,"docs":{"101":{"tf":1.0},"193":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"195":{"tf":1.4142135623730951},"196":{"tf":1.0},"197":{"tf":1.0},"208":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"76":{"tf":1.0},"98":{"tf":1.0}},"e":{"d":{"df":3,"docs":{"75":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.0}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.0}}}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":15,"docs":{"117":{"tf":1.0},"122":{"tf":1.0},"138":{"tf":1.4142135623730951},"155":{"tf":1.0},"156":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"201":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.4142135623730951},"95":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"n":{"d":{"df":6,"docs":{"18":{"tf":1.0},"218":{"tf":1.0},"219":{"tf":1.0},"3":{"tf":1.0},"62":{"tf":1.0},"82":{"tf":1.0}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"r":{"df":5,"docs":{"200":{"tf":1.0},"207":{"tf":1.0},"215":{"tf":1.0},"78":{"tf":1.4142135623730951},"80":{"tf":1.0}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"219":{"tf":1.0}}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":14,"docs":{"141":{"tf":1.0},"144":{"tf":1.0},"157":{"tf":1.0},"165":{"tf":1.0},"208":{"tf":1.0},"209":{"tf":1.4142135623730951},"210":{"tf":1.4142135623730951},"211":{"tf":1.4142135623730951},"212":{"tf":1.0},"213":{"tf":1.4142135623730951},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"57":{"tf":1.4142135623730951}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"66":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":4,"docs":{"105":{"tf":1.0},"166":{"tf":1.4142135623730951},"176":{"tf":1.4142135623730951},"177":{"tf":1.0}}}}}},"df":4,"docs":{"105":{"tf":1.7320508075688772},"74":{"tf":1.0},"75":{"tf":1.0},"81":{"tf":1.7320508075688772}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"106":{"tf":1.0}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":3,"docs":{"105":{"tf":1.0},"166":{"tf":1.4142135623730951},"76":{"tf":1.0}}}}}}}}}}}}}},"s":{"df":0,"docs":{},"h":{"df":2,"docs":{"189":{"tf":1.4142135623730951},"90":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"y":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":1,"docs":{"75":{"tf":1.0}}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":5,"docs":{"225":{"tf":1.0},"226":{"tf":1.0},"5":{"tf":1.0},"6":{"tf":1.0},"66":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":8,"docs":{"103":{"tf":1.0},"129":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"33":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.4142135623730951},"82":{"tf":1.4142135623730951}},"i":{"df":4,"docs":{"218":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.4142135623730951}}}}},"n":{"c":{"_":{"<":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"174":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"m":{"df":3,"docs":{"100":{"tf":1.0},"174":{"tf":1.4142135623730951},"99":{"tf":1.0}},"e":{">":{"(":{"[":{"$":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"_":{"0":{"df":1,"docs":{"174":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":1,"docs":{"78":{"tf":1.0}}}}},"df":26,"docs":{"100":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.0},"138":{"tf":1.0},"174":{"tf":2.0},"189":{"tf":1.0},"190":{"tf":1.0},"198":{"tf":2.23606797749979},"236":{"tf":1.0},"39":{"tf":2.0},"40":{"tf":1.4142135623730951},"51":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951},"71":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":2.0},"78":{"tf":1.4142135623730951},"80":{"tf":1.0},"84":{"tf":1.0},"85":{"tf":1.7320508075688772},"86":{"tf":1.0},"87":{"tf":1.7320508075688772},"91":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":2.0},"97":{"tf":1.0}},"i":{"d":{"df":1,"docs":{"174":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{":":{":":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"z":{"df":1,"docs":{"134":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"78":{"tf":1.0}}}}}}}},"’":{"df":2,"docs":{"174":{"tf":1.0},"198":{"tf":1.0}}}}}}}},"d":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"74":{"tf":1.0}}}}}}},"df":1,"docs":{"65":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"134":{"tf":1.0},"223":{"tf":1.0},"224":{"tf":1.0},"233":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"71":{"tf":1.0}}}}}}}}}},"s":{"df":0,"docs":{},"e":{"df":5,"docs":{"169":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"75":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0}}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":8,"docs":{"139":{"tf":1.0},"140":{"tf":1.0},"169":{"tf":1.0},"179":{"tf":1.0},"75":{"tf":1.0},"83":{"tf":1.7320508075688772},"91":{"tf":1.0},"95":{"tf":1.4142135623730951}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"43":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":4,"docs":{"18":{"tf":1.0},"233":{"tf":1.0},"65":{"tf":1.0},"93":{"tf":1.4142135623730951}}}}},"z":{"df":0,"docs":{},"z":{"df":0,"docs":{},"i":{"df":4,"docs":{"75":{"tf":1.7320508075688772},"85":{"tf":1.7320508075688772},"93":{"tf":1.0},"95":{"tf":1.0}}}}}}},"g":{"a":{"df":21,"docs":{"0":{"tf":1.7320508075688772},"100":{"tf":1.0},"116":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.4142135623730951},"146":{"tf":2.449489742783178},"147":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"158":{"tf":1.0},"180":{"tf":1.0},"201":{"tf":1.4142135623730951},"212":{"tf":1.0},"37":{"tf":2.0},"40":{"tf":1.0},"43":{"tf":1.4142135623730951},"70":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.0},"82":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"219":{"tf":1.0}}}},"p":{"df":1,"docs":{"72":{"tf":1.0}}},"s":{"_":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"100":{"tf":1.0},"152":{"tf":2.0}}}}}}},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"100":{"tf":1.0},"158":{"tf":2.0}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"e":{"df":3,"docs":{"73":{"tf":1.0},"81":{"tf":1.7320508075688772},"94":{"tf":1.0}}}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"235":{"tf":1.0}}}}}},"c":{"d":{"df":2,"docs":{"75":{"tf":1.0},"80":{"tf":1.0}}},"df":0,"docs":{}},"df":2,"docs":{"17":{"tf":1.0},"26":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":23,"docs":{"138":{"tf":1.0},"17":{"tf":1.0},"2":{"tf":1.0},"219":{"tf":1.0},"221":{"tf":1.0},"232":{"tf":1.0},"33":{"tf":2.0},"40":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.0},"6":{"tf":1.0},"61":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":2.0},"66":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.4142135623730951},"78":{"tf":1.0},"82":{"tf":1.0},"85":{"tf":1.0},"87":{"tf":1.0},"90":{"tf":1.0},"94":{"tf":1.0}}}}},"t":{"df":5,"docs":{"1":{"tf":1.0},"52":{"tf":1.0},"58":{"tf":1.0},"60":{"tf":1.4142135623730951},"91":{"tf":1.0}}}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"221":{"tf":1.0}},"h":{"df":0,"docs":{},"u":{"b":{"df":1,"docs":{"63":{"tf":1.0}}},"df":0,"docs":{}}}},"v":{"df":0,"docs":{},"e":{"df":4,"docs":{"106":{"tf":1.0},"236":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.0}},"n":{"df":13,"docs":{"155":{"tf":1.0},"156":{"tf":1.0},"159":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"205":{"tf":1.0},"236":{"tf":1.0},"65":{"tf":1.0},"68":{"tf":1.0},"99":{"tf":1.0}}}}}},"l":{"a":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"59":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":2,"docs":{"221":{"tf":1.4142135623730951},"223":{"tf":1.4142135623730951}},"e":{"df":2,"docs":{"221":{"tf":1.0},"82":{"tf":1.4142135623730951}}},"o":{"d":{"df":2,"docs":{"61":{"tf":1.0},"66":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"55":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"124":{"tf":1.0},"126":{"tf":1.0},"135":{"tf":1.0}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"61":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":2,"docs":{"85":{"tf":1.0},"97":{"tf":1.0}}}},"w":{"df":1,"docs":{"14":{"tf":1.0}}}}},"t":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"124":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"124":{"tf":1.0}}},"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"75":{"tf":1.0},"79":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"124":{"tf":1.4142135623730951},"79":{"tf":1.0}}},"u":{"a":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":2,"docs":{"219":{"tf":1.0},"98":{"tf":1.0}}}}}},"d":{"_":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":1,"docs":{"75":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":4,"docs":{"180":{"tf":1.0},"75":{"tf":1.7320508075688772},"79":{"tf":2.8284271247461903},"95":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"d":{"df":220,"docs":{"1":{"tf":1.4142135623730951},"10":{"tf":1.0},"100":{"tf":1.0},"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"106":{"tf":1.0},"107":{"tf":1.0},"108":{"tf":1.0},"109":{"tf":1.0},"11":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"12":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"13":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"14":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"15":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"16":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"17":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"18":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"182":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.0},"19":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"192":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"20":{"tf":1.0},"200":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"208":{"tf":1.0},"209":{"tf":1.0},"21":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"217":{"tf":1.0},"218":{"tf":1.0},"219":{"tf":1.0},"22":{"tf":1.0},"220":{"tf":1.0},"221":{"tf":1.0},"222":{"tf":1.4142135623730951},"223":{"tf":1.0},"224":{"tf":1.0},"225":{"tf":1.0},"226":{"tf":1.0},"227":{"tf":1.0},"23":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0},"38":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.7320508075688772},"40":{"tf":1.0},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.0},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":1.0},"50":{"tf":1.0},"51":{"tf":1.0},"52":{"tf":1.0},"58":{"tf":1.7320508075688772},"59":{"tf":2.0},"6":{"tf":1.0},"60":{"tf":1.4142135623730951},"61":{"tf":1.4142135623730951},"62":{"tf":1.4142135623730951},"63":{"tf":1.4142135623730951},"64":{"tf":2.0},"65":{"tf":1.4142135623730951},"66":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.0},"7":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"77":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"8":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0},"85":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.0},"88":{"tf":1.0},"89":{"tf":1.0},"9":{"tf":1.0},"90":{"tf":1.0},"91":{"tf":1.0},"92":{"tf":1.0},"93":{"tf":1.4142135623730951},"94":{"tf":1.0},"95":{"tf":1.0},"96":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{}}}},"h":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"219":{"tf":1.0}}},"l":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}}},"n":{"d":{"df":6,"docs":{"106":{"tf":1.0},"108":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.4142135623730951},"219":{"tf":1.0},"74":{"tf":1.0}},"i":{"df":1,"docs":{"53":{"tf":1.0}}},"l":{"df":4,"docs":{"176":{"tf":1.0},"80":{"tf":1.0},"87":{"tf":1.0},"92":{"tf":1.0}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"67":{"tf":1.0}}}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"91":{"tf":1.0}}}},"h":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"219":{"tf":1.0}}}},"df":0,"docs":{}}},"df":1,"docs":{"94":{"tf":1.0}}},"s":{"_":{"d":{"df":0,"docs":{},"y":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"c":{"_":{"a":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"82":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{},"h":{"df":21,"docs":{"0":{"tf":1.0},"100":{"tf":1.0},"138":{"tf":2.0},"139":{"tf":1.7320508075688772},"140":{"tf":1.4142135623730951},"155":{"tf":1.0},"156":{"tf":1.0},"164":{"tf":1.0},"169":{"tf":1.4142135623730951},"18":{"tf":1.0},"181":{"tf":1.4142135623730951},"190":{"tf":1.0},"206":{"tf":1.0},"38":{"tf":1.0},"43":{"tf":2.0},"44":{"tf":1.0},"45":{"tf":1.0},"68":{"tf":1.0},"75":{"tf":1.4142135623730951},"83":{"tf":1.4142135623730951},"84":{"tf":1.4142135623730951}},"m":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"68":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":2,"docs":{"2":{"tf":1.0},"98":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"195":{"tf":1.0}}}}},"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":1,"docs":{"75":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":3,"docs":{"14":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0}}}}}},"df":13,"docs":{"0":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.4142135623730951},"14":{"tf":2.6457513110645907},"27":{"tf":1.4142135623730951},"40":{"tf":1.0},"70":{"tf":2.23606797749979},"75":{"tf":1.0},"76":{"tf":1.0},"80":{"tf":1.7320508075688772},"81":{"tf":1.0},"94":{"tf":1.0},"95":{"tf":1.0}}},"v":{"df":0,"docs":{},"i":{"df":1,"docs":{"66":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":1,"docs":{"0":{"tf":1.0}}}},"p":{"df":4,"docs":{"1":{"tf":1.0},"11":{"tf":1.7320508075688772},"54":{"tf":1.4142135623730951},"58":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":7,"docs":{"214":{"tf":1.0},"223":{"tf":1.0},"80":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.7320508075688772},"95":{"tf":1.4142135623730951}}}}}},"n":{"c":{"df":1,"docs":{"70":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"e":{"df":7,"docs":{"103":{"tf":1.0},"199":{"tf":1.0},"218":{"tf":1.0},"232":{"tf":1.0},"51":{"tf":1.0},"65":{"tf":1.0},"98":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"75":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.0}}}}}}},"x":{"df":3,"docs":{"214":{"tf":1.0},"216":{"tf":1.0},"99":{"tf":1.4142135623730951}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":9,"docs":{"137":{"tf":1.0},"139":{"tf":1.0},"223":{"tf":1.0},"235":{"tf":1.0},"4":{"tf":1.0},"66":{"tf":1.0},"74":{"tf":1.0},"76":{"tf":1.0},"82":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"147":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":4,"docs":{"222":{"tf":1.0},"34":{"tf":1.0},"64":{"tf":1.0},"92":{"tf":1.0}}}}}}}}},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"169":{"tf":1.0},"178":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"69":{"tf":1.0}},"i":{"df":2,"docs":{"147":{"tf":1.0},"91":{"tf":1.4142135623730951}}}}}}},"t":{"df":1,"docs":{"105":{"tf":1.0}}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"138":{"tf":1.0},"95":{"tf":1.0}}}}},"l":{"d":{"df":4,"docs":{"111":{"tf":1.0},"121":{"tf":1.0},"188":{"tf":1.0},"81":{"tf":1.0}}},"df":0,"docs":{}},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"65":{"tf":1.0}}}},"o":{"d":{"df":1,"docs":{"67":{"tf":1.0}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"220":{"tf":1.7320508075688772},"226":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{":":{"/":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"u":{"b":{".":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":1,"docs":{"221":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"u":{"b":{"df":1,"docs":{"220":{"tf":1.0}}},"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"df":2,"docs":{"65":{"tf":1.0},"95":{"tf":1.0}}}},"df":0,"docs":{}},"n":{"d":{"df":0,"docs":{},"r":{"df":1,"docs":{"87":{"tf":1.0}}}},"df":0,"docs":{}}}},"i":{".":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}},"1":{"2":{"8":{"df":5,"docs":{"103":{"tf":1.4142135623730951},"111":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0}}},"df":0,"docs":{}},"6":{"0":{"df":23,"docs":{"103":{"tf":1.4142135623730951},"111":{"tf":1.0},"141":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"148":{"tf":1.0},"163":{"tf":1.4142135623730951},"164":{"tf":1.4142135623730951},"165":{"tf":1.4142135623730951},"169":{"tf":1.4142135623730951},"173":{"tf":1.0},"181":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"191":{"tf":1.0},"201":{"tf":1.4142135623730951},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"213":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.0}}},"df":0,"docs":{}},"df":18,"docs":{"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.4142135623730951},"107":{"tf":1.0},"121":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"132":{"tf":1.0},"193":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0}}},"2":{"5":{"6":{"df":86,"docs":{"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.7320508075688772},"107":{"tf":1.0},"109":{"tf":1.4142135623730951},"110":{"tf":1.7320508075688772},"111":{"tf":1.7320508075688772},"112":{"tf":1.4142135623730951},"113":{"tf":1.4142135623730951},"114":{"tf":1.4142135623730951},"115":{"tf":1.4142135623730951},"116":{"tf":1.7320508075688772},"117":{"tf":1.4142135623730951},"118":{"tf":1.4142135623730951},"119":{"tf":1.4142135623730951},"120":{"tf":1.7320508075688772},"121":{"tf":1.4142135623730951},"122":{"tf":1.4142135623730951},"123":{"tf":1.4142135623730951},"124":{"tf":1.4142135623730951},"125":{"tf":1.4142135623730951},"126":{"tf":1.4142135623730951},"127":{"tf":1.4142135623730951},"128":{"tf":1.4142135623730951},"129":{"tf":1.7320508075688772},"130":{"tf":2.0},"131":{"tf":2.0},"132":{"tf":1.0},"133":{"tf":1.4142135623730951},"134":{"tf":1.4142135623730951},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.7320508075688772},"139":{"tf":1.7320508075688772},"140":{"tf":1.4142135623730951},"142":{"tf":1.0},"145":{"tf":1.0},"151":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.4142135623730951},"156":{"tf":1.4142135623730951},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.4142135623730951},"163":{"tf":1.0},"164":{"tf":1.4142135623730951},"165":{"tf":1.4142135623730951},"166":{"tf":1.4142135623730951},"167":{"tf":1.4142135623730951},"168":{"tf":1.4142135623730951},"169":{"tf":1.7320508075688772},"170":{"tf":1.0},"172":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"178":{"tf":1.7320508075688772},"179":{"tf":1.4142135623730951},"180":{"tf":1.4142135623730951},"181":{"tf":1.7320508075688772},"183":{"tf":1.7320508075688772},"184":{"tf":2.0},"185":{"tf":1.7320508075688772},"186":{"tf":1.7320508075688772},"187":{"tf":1.7320508075688772},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"201":{"tf":2.8284271247461903},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":2.0},"206":{"tf":1.4142135623730951},"207":{"tf":1.4142135623730951},"209":{"tf":1.4142135623730951},"210":{"tf":1.4142135623730951},"213":{"tf":1.0},"76":{"tf":1.4142135623730951},"78":{"tf":1.4142135623730951},"82":{"tf":1.0},"93":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"3":{"2":{"df":7,"docs":{"103":{"tf":1.4142135623730951},"166":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0},"82":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{}},"6":{"4":{"df":22,"docs":{"103":{"tf":1.7320508075688772},"107":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.4142135623730951},"146":{"tf":1.0},"147":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"152":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"166":{"tf":1.0},"171":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0}}},"5":{"df":1,"docs":{"78":{"tf":1.0}}},"df":0,"docs":{}},"8":{"df":9,"docs":{"102":{"tf":1.0},"103":{"tf":1.4142135623730951},"117":{"tf":1.0},"128":{"tf":1.0},"136":{"tf":1.0},"177":{"tf":1.7320508075688772},"75":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0}}},"d":{"df":7,"docs":{"170":{"tf":1.4142135623730951},"171":{"tf":1.0},"189":{"tf":1.7320508075688772},"195":{"tf":1.4142135623730951},"23":{"tf":1.7320508075688772},"33":{"tf":1.0},"99":{"tf":1.4142135623730951}},"e":{"a":{"df":1,"docs":{"52":{"tf":1.0}},"l":{"df":1,"docs":{"219":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"177":{"tf":1.0},"75":{"tf":1.0},"85":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.0}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":11,"docs":{"145":{"tf":1.0},"170":{"tf":1.7320508075688772},"171":{"tf":1.7320508075688772},"172":{"tf":1.0},"173":{"tf":1.0},"191":{"tf":1.4142135623730951},"224":{"tf":1.0},"68":{"tf":1.0},"85":{"tf":1.0},"93":{"tf":1.0},"99":{"tf":1.4142135623730951}}}}}}}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":2,"docs":{"117":{"tf":1.0},"139":{"tf":1.0}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":4,"docs":{"0":{"tf":1.0},"177":{"tf":1.0},"219":{"tf":1.4142135623730951},"41":{"tf":1.0}}}}}},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"df":1,"docs":{"141":{"tf":1.0}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"t":{"df":3,"docs":{"172":{"tf":1.4142135623730951},"188":{"tf":1.0},"191":{"tf":1.4142135623730951}}}}},"p":{"a":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"75":{"tf":1.0},"91":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":13,"docs":{"0":{"tf":1.4142135623730951},"219":{"tf":1.0},"221":{"tf":1.7320508075688772},"222":{"tf":1.0},"223":{"tf":1.7320508075688772},"224":{"tf":1.4142135623730951},"4":{"tf":1.0},"52":{"tf":2.449489742783178},"6":{"tf":1.0},"62":{"tf":1.0},"69":{"tf":2.23606797749979},"85":{"tf":1.0},"93":{"tf":1.0}}}}}}},"i":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"193":{"tf":1.0}}}}}}},"df":2,"docs":{"18":{"tf":1.0},"40":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"1":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":4,"docs":{"232":{"tf":1.0},"236":{"tf":1.0},"92":{"tf":1.0},"93":{"tf":1.0}}}}}}},"n":{"a":{"d":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"92":{"tf":1.0}}}}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":2,"docs":{"13":{"tf":1.0},"14":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"u":{"d":{"df":10,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"16":{"tf":1.0},"204":{"tf":1.0},"33":{"tf":1.0},"4":{"tf":1.0},"52":{"tf":1.0},"55":{"tf":1.0},"62":{"tf":1.0},"98":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":3,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":1.0},"233":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"220":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":3,"docs":{"189":{"tf":1.0},"81":{"tf":1.0},"94":{"tf":1.0}}},"df":0,"docs":{}}}},"x":{"df":5,"docs":{"100":{"tf":1.4142135623730951},"128":{"tf":1.0},"155":{"tf":1.7320508075688772},"207":{"tf":1.4142135623730951},"97":{"tf":1.0}}}},"i":{"c":{"df":1,"docs":{"201":{"tf":1.0}}},"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"u":{"df":1,"docs":{"92":{"tf":1.0}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"219":{"tf":1.0},"52":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":2,"docs":{"219":{"tf":1.0},"52":{"tf":1.0}}}},"df":0,"docs":{}}}}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":13,"docs":{"103":{"tf":1.0},"107":{"tf":1.0},"117":{"tf":1.0},"122":{"tf":1.0},"134":{"tf":1.0},"174":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951},"76":{"tf":1.0},"78":{"tf":1.4142135623730951},"79":{"tf":1.0},"91":{"tf":2.0},"98":{"tf":1.0}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"14":{"tf":1.0}}}}}},"o":{"df":1,"docs":{"17":{"tf":1.4142135623730951}},"r":{"df":0,"docs":{},"m":{"df":7,"docs":{"17":{"tf":1.0},"2":{"tf":1.0},"26":{"tf":1.0},"74":{"tf":1.0},"76":{"tf":1.4142135623730951},"80":{"tf":1.0},"98":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"52":{"tf":1.0},"65":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"203":{"tf":1.0},"51":{"tf":1.4142135623730951}}}}}},"i":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"92":{"tf":1.0}}}}},"df":0,"docs":{}}},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"205":{"tf":1.7320508075688772},"206":{"tf":1.0}},"i":{"a":{"df":0,"docs":{},"l":{"_":{"0":{"df":1,"docs":{"195":{"tf":1.0}}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"195":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":6,"docs":{"143":{"tf":1.0},"220":{"tf":1.0},"30":{"tf":1.0},"51":{"tf":1.7320508075688772},"82":{"tf":1.0},"91":{"tf":1.0}}}}},"k":{"df":0,"docs":{},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"71":{"tf":1.0}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":12,"docs":{"18":{"tf":2.23606797749979},"198":{"tf":1.0},"230":{"tf":1.7320508075688772},"4":{"tf":1.0},"64":{"tf":1.0},"75":{"tf":1.4142135623730951},"80":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.0},"92":{"tf":1.4142135623730951},"93":{"tf":1.0},"95":{"tf":1.0}},"e":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"80":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{},"n":{"df":2,"docs":{"80":{"tf":1.0},"81":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"51":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":2,"docs":{"199":{"tf":1.0},"90":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"196":{"tf":1.0},"197":{"tf":1.0}}}}}}}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"0":{"df":2,"docs":{"193":{"tf":1.0},"194":{"tf":1.0}}},"1":{"df":1,"docs":{"193":{"tf":1.0}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":12,"docs":{"139":{"tf":1.4142135623730951},"18":{"tf":1.4142135623730951},"192":{"tf":1.0},"193":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"195":{"tf":1.0},"22":{"tf":1.0},"24":{"tf":1.0},"75":{"tf":1.0},"83":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"75":{"tf":1.0},"79":{"tf":1.0},"95":{"tf":1.0}}}}},"i":{"d":{"df":11,"docs":{"135":{"tf":1.0},"18":{"tf":1.0},"195":{"tf":1.0},"224":{"tf":1.0},"43":{"tf":1.0},"54":{"tf":1.0},"70":{"tf":1.0},"93":{"tf":1.0},"94":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"55":{"tf":1.0}}}}}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"94":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"76":{"tf":1.0}}}}},"t":{"a":{"df":0,"docs":{},"l":{"df":9,"docs":{"10":{"tf":1.0},"221":{"tf":1.0},"226":{"tf":1.4142135623730951},"54":{"tf":2.449489742783178},"6":{"tf":2.0},"61":{"tf":1.0},"7":{"tf":1.4142135623730951},"8":{"tf":2.0},"9":{"tf":1.0}}},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":4,"docs":{"0":{"tf":1.0},"223":{"tf":1.7320508075688772},"43":{"tf":1.0},"56":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":12,"docs":{"0":{"tf":1.4142135623730951},"14":{"tf":1.0},"18":{"tf":1.0},"223":{"tf":1.0},"35":{"tf":1.4142135623730951},"38":{"tf":1.0},"43":{"tf":1.4142135623730951},"53":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"78":{"tf":1.0},"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":9,"docs":{"10":{"tf":1.0},"18":{"tf":1.0},"219":{"tf":1.0},"35":{"tf":1.0},"43":{"tf":1.0},"55":{"tf":1.0},"78":{"tf":1.7320508075688772},"8":{"tf":1.0},"87":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"(":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"102":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"i":{"2":{"5":{"6":{"df":1,"docs":{"107":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":10,"docs":{"102":{"tf":1.0},"103":{"tf":1.4142135623730951},"112":{"tf":1.0},"113":{"tf":1.0},"129":{"tf":1.4142135623730951},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"95":{"tf":1.0},"99":{"tf":1.4142135623730951}},"r":{"df":9,"docs":{"20":{"tf":2.0},"21":{"tf":1.0},"22":{"tf":1.0},"221":{"tf":1.7320508075688772},"223":{"tf":2.23606797749979},"23":{"tf":1.0},"52":{"tf":1.0},"89":{"tf":1.7320508075688772},"90":{"tf":1.0}}}},"n":{"d":{"df":1,"docs":{"97":{"tf":1.0}}},"df":0,"docs":{},"t":{"df":1,"docs":{"74":{"tf":1.0}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"100":{"tf":1.0},"200":{"tf":1.4142135623730951},"220":{"tf":1.0},"92":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"f":{"a":{"c":{"df":22,"docs":{"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.0},"220":{"tf":1.0},"24":{"tf":2.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"52":{"tf":1.0},"69":{"tf":1.0},"71":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}},"m":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}},"df":10,"docs":{"130":{"tf":1.0},"131":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"73":{"tf":1.0},"75":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":8,"docs":{"174":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.4142135623730951},"51":{"tf":1.4142135623730951},"58":{"tf":1.0},"66":{"tf":1.4142135623730951},"68":{"tf":1.0},"87":{"tf":1.4142135623730951}}},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"219":{"tf":1.4142135623730951}}}},"o":{"c":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"174":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"138":{"tf":1.0}}}}}}},"r":{"a":{"df":1,"docs":{"198":{"tf":1.0}}},"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":6,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"137":{"tf":1.0},"52":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}}}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":5,"docs":{"100":{"tf":1.0},"194":{"tf":1.0},"208":{"tf":1.0},"212":{"tf":2.23606797749979},"68":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"81":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"133":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"174":{"tf":1.0}}},"l":{"df":0,"docs":{},"v":{"df":2,"docs":{"18":{"tf":1.0},"65":{"tf":1.4142135623730951}}}}}}},"p":{"df":0,"docs":{},"s":{"c":{"c":{"df":0,"docs":{},"p":{"df":1,"docs":{"81":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{".":{"df":0,"docs":{},"r":{"df":3,"docs":{"95":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}}}},"df":139,"docs":{"100":{"tf":1.0},"101":{"tf":1.4142135623730951},"102":{"tf":1.0},"103":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"106":{"tf":1.0},"107":{"tf":1.0},"108":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.7320508075688772},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"16":{"tf":1.4142135623730951},"160":{"tf":1.0},"161":{"tf":1.7320508075688772},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.7320508075688772},"167":{"tf":1.7320508075688772},"168":{"tf":1.7320508075688772},"169":{"tf":1.4142135623730951},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.4142135623730951},"175":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.4142135623730951},"181":{"tf":1.0},"182":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"192":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"200":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"208":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.4142135623730951},"215":{"tf":1.0},"216":{"tf":1.0},"50":{"tf":2.0},"51":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"69":{"tf":1.0},"72":{"tf":1.7320508075688772},"73":{"tf":1.4142135623730951},"74":{"tf":1.7320508075688772},"75":{"tf":1.7320508075688772},"76":{"tf":2.0},"83":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":1.0},"91":{"tf":1.4142135623730951},"92":{"tf":1.0},"94":{"tf":1.7320508075688772},"95":{"tf":2.449489742783178},"96":{"tf":2.0},"97":{"tf":1.4142135623730951},"98":{"tf":1.0},"99":{"tf":1.0}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"33":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"127":{"tf":1.0}}}}}}},"’":{"df":8,"docs":{"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"170":{"tf":1.0},"192":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"207":{"tf":1.0}}}},"s":{"a":{"df":1,"docs":{"219":{"tf":1.0}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":0,"docs":{},"t":{"df":5,"docs":{"0":{"tf":1.0},"105":{"tf":1.0},"18":{"tf":1.0},"219":{"tf":1.0},"222":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"u":{"df":2,"docs":{"63":{"tf":1.0},"81":{"tf":1.0}}}},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"132":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"q":{"(":{"df":0,"docs":{},"v":{"df":2,"docs":{"75":{"tf":1.0},"79":{"tf":1.0}}}},"df":0,"docs":{}}},"v":{"0":{"df":1,"docs":{"132":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"103":{"tf":1.0},"132":{"tf":1.4142135623730951}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"64":{"tf":1.0}}},"r":{"df":7,"docs":{"195":{"tf":2.23606797749979},"199":{"tf":1.0},"68":{"tf":1.0},"75":{"tf":1.4142135623730951},"78":{"tf":1.0},"91":{"tf":1.4142135623730951},"93":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":10,"docs":{"105":{"tf":1.0},"107":{"tf":1.0},"108":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.0},"63":{"tf":1.0},"71":{"tf":1.0},"98":{"tf":1.0}}}}}},"’":{"d":{"df":1,"docs":{"51":{"tf":1.0}}},"df":6,"docs":{"18":{"tf":1.0},"19":{"tf":1.0},"234":{"tf":1.0},"52":{"tf":1.0},"53":{"tf":1.0},"55":{"tf":1.0}}}}},"j":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"219":{"tf":2.23606797749979},"4":{"tf":1.0}}}},"s":{"df":1,"docs":{"19":{"tf":1.7320508075688772}},"o":{"df":0,"docs":{},"n":{"df":12,"docs":{"18":{"tf":1.4142135623730951},"24":{"tf":2.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.7320508075688772},"73":{"tf":1.0}}}}},"u":{"d":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":3,"docs":{"192":{"tf":1.0},"195":{"tf":1.0},"97":{"tf":1.0}}}}}},"k":{"b":{"df":1,"docs":{"57":{"tf":1.0}}},"df":2,"docs":{"121":{"tf":1.7320508075688772},"81":{"tf":1.0}},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"138":{"tf":1.0}}}}}}}}},"0":{"df":2,"docs":{"139":{"tf":1.0},"140":{"tf":1.0}}},"df":0,"docs":{},"v":{"0":{"df":2,"docs":{"138":{"tf":1.0},"190":{"tf":1.0}}},"df":0,"docs":{}}},"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"(":{"$":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"0":{"df":1,"docs":{"139":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"84":{"tf":1.0}}}}},"v":{"0":{"df":1,"docs":{"139":{"tf":1.0}}},"df":0,"docs":{}}},"df":6,"docs":{"100":{"tf":1.0},"139":{"tf":1.4142135623730951},"169":{"tf":1.0},"181":{"tf":1.0},"75":{"tf":1.0},"95":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":2,"docs":{"100":{"tf":1.0},"140":{"tf":1.4142135623730951}},"e":{"(":{"$":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"0":{"df":1,"docs":{"140":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"140":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"df":8,"docs":{"100":{"tf":1.0},"138":{"tf":1.4142135623730951},"38":{"tf":1.0},"75":{"tf":1.7320508075688772},"83":{"tf":2.0},"87":{"tf":1.0},"91":{"tf":1.0},"95":{"tf":1.0}},"p":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":2,"docs":{"75":{"tf":1.0},"83":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":2,"docs":{"75":{"tf":1.0},"83":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"75":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":10,"docs":{"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"164":{"tf":1.0},"169":{"tf":1.4142135623730951},"179":{"tf":1.0},"181":{"tf":1.0},"75":{"tf":1.0},"87":{"tf":1.0},"95":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":6,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"235":{"tf":1.0},"65":{"tf":1.0},"81":{"tf":1.0}}}},"p":{"df":0,"docs":{},"t":{"df":2,"docs":{"61":{"tf":1.0},"70":{"tf":1.0}}}},"y":{"/":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"104":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":16,"docs":{"103":{"tf":1.0},"139":{"tf":1.0},"167":{"tf":1.4142135623730951},"168":{"tf":1.4142135623730951},"169":{"tf":2.449489742783178},"172":{"tf":1.4142135623730951},"179":{"tf":1.4142135623730951},"180":{"tf":1.4142135623730951},"181":{"tf":2.6457513110645907},"191":{"tf":1.7320508075688772},"223":{"tf":1.0},"32":{"tf":1.7320508075688772},"76":{"tf":1.0},"77":{"tf":1.4142135623730951},"84":{"tf":1.0},"99":{"tf":1.0}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":3,"docs":{"198":{"tf":1.0},"43":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{}}}}}},"i":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"105":{"tf":1.0},"200":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"o":{"b":{"df":1,"docs":{"94":{"tf":1.0}}},"df":0,"docs":{},"w":{"df":4,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"52":{"tf":1.0},"98":{"tf":1.0}},"l":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"g":{"df":2,"docs":{"72":{"tf":1.0},"73":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":7,"docs":{"121":{"tf":1.0},"137":{"tf":1.0},"18":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"86":{"tf":1.0},"93":{"tf":1.4142135623730951}}}}}}},"l":{"a":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"98":{"tf":1.0}}}}},"c":{"df":0,"docs":{},"k":{"df":3,"docs":{"14":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.0}}}},"df":0,"docs":{},"n":{"d":{"df":3,"docs":{"103":{"tf":1.0},"106":{"tf":1.0},"176":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"g":{"df":5,"docs":{"22":{"tf":1.0},"235":{"tf":1.0},"52":{"tf":2.6457513110645907},"64":{"tf":1.0},"97":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"g":{"df":5,"docs":{"224":{"tf":1.0},"65":{"tf":1.0},"87":{"tf":1.0},"91":{"tf":1.0},"92":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"233":{"tf":1.4142135623730951},"40":{"tf":1.0}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"81":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"161":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"105":{"tf":1.0},"191":{"tf":1.0}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"232":{"tf":1.7320508075688772}}}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"220":{"tf":1.0}}}},"df":0,"docs":{}}},"y":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"72":{"tf":1.0},"73":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":3,"docs":{"40":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":5,"docs":{"0":{"tf":1.0},"134":{"tf":1.4142135623730951},"39":{"tf":1.0},"40":{"tf":1.0},"65":{"tf":1.0}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"61":{"tf":1.0}}}},"v":{"df":7,"docs":{"100":{"tf":1.0},"107":{"tf":1.0},"192":{"tf":1.0},"198":{"tf":2.6457513110645907},"71":{"tf":1.0},"75":{"tf":1.0},"95":{"tf":1.0}}}},"df":1,"docs":{"82":{"tf":1.0}},"f":{"df":0,"docs":{},"t":{"df":3,"docs":{"120":{"tf":1.4142135623730951},"121":{"tf":1.0},"216":{"tf":1.4142135623730951}}}},"g":{"a":{"c":{"df":0,"docs":{},"i":{"df":2,"docs":{"213":{"tf":1.0},"51":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":20,"docs":{"116":{"tf":1.0},"138":{"tf":2.0},"160":{"tf":1.0},"161":{"tf":1.0},"178":{"tf":2.0},"182":{"tf":1.0},"183":{"tf":1.7320508075688772},"184":{"tf":1.7320508075688772},"185":{"tf":1.7320508075688772},"186":{"tf":1.7320508075688772},"187":{"tf":1.7320508075688772},"201":{"tf":1.4142135623730951},"205":{"tf":1.7320508075688772},"206":{"tf":1.0},"207":{"tf":2.449489742783178},"209":{"tf":2.0},"210":{"tf":2.0},"215":{"tf":2.23606797749979},"87":{"tf":1.0},"99":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"s":{"df":4,"docs":{"123":{"tf":1.0},"125":{"tf":1.0},"180":{"tf":1.0},"219":{"tf":1.0}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"82":{"tf":1.0}}}}}},"t":{"df":1,"docs":{"117":{"tf":1.0}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":15,"docs":{"12":{"tf":2.23606797749979},"174":{"tf":1.4142135623730951},"198":{"tf":1.0},"223":{"tf":1.0},"32":{"tf":3.1622776601683795},"33":{"tf":1.7320508075688772},"39":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.7320508075688772},"55":{"tf":1.0},"66":{"tf":1.0},"74":{"tf":1.4142135623730951},"76":{"tf":1.0},"92":{"tf":1.0}}}}},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"69":{"tf":1.0}}}},"i":{"c":{"df":2,"docs":{"192":{"tf":1.0},"199":{"tf":1.0}}},"df":0,"docs":{}}}},"h":{"df":22,"docs":{"109":{"tf":1.4142135623730951},"110":{"tf":1.4142135623730951},"111":{"tf":1.4142135623730951},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.4142135623730951},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.4142135623730951},"122":{"tf":1.0},"123":{"tf":1.4142135623730951},"124":{"tf":1.4142135623730951},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.4142135623730951},"128":{"tf":1.0},"129":{"tf":1.0},"99":{"tf":1.0}}},"i":{"b":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"c":{"df":1,"docs":{"227":{"tf":1.4142135623730951}}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":11,"docs":{"173":{"tf":1.0},"18":{"tf":3.4641016151377544},"203":{"tf":1.0},"220":{"tf":1.0},"223":{"tf":1.7320508075688772},"5":{"tf":1.0},"52":{"tf":2.449489742783178},"62":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":2.0}}},"y":{"df":0,"docs":{},"’":{"df":1,"docs":{"173":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":2,"docs":{"235":{"tf":1.0},"65":{"tf":1.0}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"180":{"tf":1.0}}}}}},"t":{"df":1,"docs":{"66":{"tf":1.0}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":5,"docs":{"152":{"tf":1.0},"233":{"tf":1.0},"37":{"tf":1.0},"40":{"tf":1.0},"93":{"tf":1.4142135623730951}}}}},"n":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":26,"docs":{"104":{"tf":1.0},"138":{"tf":1.4142135623730951},"147":{"tf":1.0},"166":{"tf":1.4142135623730951},"175":{"tf":1.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"178":{"tf":1.7320508075688772},"182":{"tf":1.0},"183":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"185":{"tf":1.4142135623730951},"186":{"tf":1.4142135623730951},"187":{"tf":1.4142135623730951},"201":{"tf":2.0},"205":{"tf":1.0},"207":{"tf":1.4142135623730951},"209":{"tf":1.0},"210":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"219":{"tf":1.0},"40":{"tf":1.0},"70":{"tf":1.0},"74":{"tf":1.0},"80":{"tf":1.0}}}},"df":13,"docs":{"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":1.0},"19":{"tf":1.0},"30":{"tf":1.0},"64":{"tf":1.0},"94":{"tf":1.0},"99":{"tf":1.0}}},"k":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":5,"docs":{"18":{"tf":3.7416573867739413},"225":{"tf":1.0},"52":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"r":{"df":10,"docs":{"100":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"173":{"tf":1.0},"18":{"tf":1.4142135623730951},"186":{"tf":1.0},"191":{"tf":1.0},"218":{"tf":1.0},"67":{"tf":1.0},"71":{"tf":1.0}},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"(":{"\\"":{"<":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"173":{"tf":1.0}}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"/":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{":":{"df":0,"docs":{},"l":{"df":1,"docs":{"173":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":2,"docs":{"100":{"tf":1.0},"173":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"64":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"x":{"df":2,"docs":{"225":{"tf":1.0},"7":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":6,"docs":{"155":{"tf":1.0},"189":{"tf":1.0},"198":{"tf":1.0},"39":{"tf":1.0},"98":{"tf":1.7320508075688772},"99":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"’":{"df":1,"docs":{"107":{"tf":1.0}}}}},"df":15,"docs":{"107":{"tf":1.4142135623730951},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"191":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.0},"83":{"tf":1.0},"85":{"tf":1.4142135623730951},"93":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}}},"t":{"df":0,"docs":{},"l":{"df":8,"docs":{"104":{"tf":1.0},"176":{"tf":1.0},"62":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.0},"90":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":4,"docs":{"180":{"tf":1.0},"219":{"tf":1.0},"35":{"tf":1.0},"62":{"tf":1.0}}}}},"l":{"d":{"df":3,"docs":{"226":{"tf":1.0},"67":{"tf":1.0},"71":{"tf":1.4142135623730951}}},"df":1,"docs":{"69":{"tf":1.0}},"m":{"df":1,"docs":{"65":{"tf":1.0}}},"v":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"226":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"226":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"_":{"2":{"2":{"1":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"=":{"$":{"df":0,"docs":{},"{":{"df":0,"docs":{},"p":{"df":0,"docs":{},"w":{"d":{"df":0,"docs":{},"}":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"226":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":23,"docs":{"12":{"tf":1.7320508075688772},"16":{"tf":1.0},"195":{"tf":1.0},"226":{"tf":3.0},"236":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"69":{"tf":2.449489742783178},"71":{"tf":2.6457513110645907},"72":{"tf":1.7320508075688772},"73":{"tf":1.4142135623730951},"74":{"tf":1.4142135623730951},"75":{"tf":1.0},"78":{"tf":1.0},"87":{"tf":1.4142135623730951},"91":{"tf":1.0},"92":{"tf":1.4142135623730951},"94":{"tf":1.0},"95":{"tf":1.0}},"’":{"df":2,"docs":{"81":{"tf":1.0},"92":{"tf":1.4142135623730951}}}}}},"o":{"a":{"d":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"84":{"tf":1.0}}}}}}},"df":10,"docs":{"100":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"166":{"tf":1.0},"169":{"tf":1.4142135623730951},"216":{"tf":1.0},"75":{"tf":1.0},"81":{"tf":1.4142135623730951},"93":{"tf":1.0},"95":{"tf":1.0}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"(":{"\\"":{"<":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"172":{"tf":1.0}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"n":{"df":1,"docs":{"172":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":3,"docs":{"100":{"tf":1.0},"172":{"tf":1.4142135623730951},"191":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"c":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"13":{"tf":1.0},"53":{"tf":1.0},"61":{"tf":1.0},"63":{"tf":1.0}}},"t":{"df":4,"docs":{"173":{"tf":1.0},"181":{"tf":1.0},"62":{"tf":1.0},"80":{"tf":1.0}}}},"df":0,"docs":{},"k":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"g":{"0":{"(":{"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"207":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"2":{"(":{"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"207":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"<":{"df":0,"docs":{},"n":{">":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"207":{"tf":1.0}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":2,"docs":{"100":{"tf":1.0},"207":{"tf":1.4142135623730951}}}},"df":4,"docs":{"200":{"tf":1.0},"207":{"tf":1.0},"55":{"tf":2.449489742783178},"93":{"tf":1.0}},"i":{"c":{"df":7,"docs":{"120":{"tf":1.0},"121":{"tf":1.0},"132":{"tf":1.0},"221":{"tf":1.0},"223":{"tf":1.0},"52":{"tf":1.0},"69":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"199":{"tf":1.0},"23":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"235":{"tf":1.0}},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"97":{"tf":1.0}}}}},"p":{"_":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"195":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":6,"docs":{"195":{"tf":3.4641016151377544},"196":{"tf":1.7320508075688772},"197":{"tf":1.7320508075688772},"80":{"tf":1.0},"90":{"tf":1.0},"93":{"tf":1.7320508075688772}},"’":{"df":1,"docs":{"196":{"tf":1.0}}}},"s":{"df":1,"docs":{"188":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"219":{"tf":1.0}}},"s":{"df":1,"docs":{"65":{"tf":1.0}}},"t":{"df":1,"docs":{"74":{"tf":1.0}}}},"t":{"df":2,"docs":{"223":{"tf":1.0},"224":{"tf":1.0}}},"w":{"df":9,"docs":{"139":{"tf":1.0},"177":{"tf":1.4142135623730951},"235":{"tf":1.0},"39":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"55":{"tf":1.0},"74":{"tf":1.0},"82":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"c":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"99":{"tf":1.0}}}},"df":0,"docs":{}},"df":10,"docs":{"103":{"tf":1.0},"104":{"tf":1.0},"214":{"tf":1.0},"52":{"tf":1.4142135623730951},"66":{"tf":1.0},"67":{"tf":1.4142135623730951},"69":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":1.0},"94":{"tf":1.0}}}}}},"t":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"123":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"123":{"tf":1.0}}},"1":{"df":1,"docs":{"195":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"123":{"tf":1.4142135623730951}}}},"m":{"a":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"13":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.7320508075688772}}}}},"o":{"df":1,"docs":{"7":{"tf":1.0}}},"r":{"df":0,"docs":{},"o":{"df":1,"docs":{"64":{"tf":1.4142135623730951}}}}},"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"210":{"tf":1.0},"63":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"64":{"tf":1.0}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"d":{"df":1,"docs":{"219":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}}},"i":{"df":0,"docs":{},"n":{"df":5,"docs":{"219":{"tf":1.0},"236":{"tf":1.0},"63":{"tf":1.0},"69":{"tf":1.0},"89":{"tf":1.7320508075688772}},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"18":{"tf":1.0},"30":{"tf":1.0},"66":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"m":{"df":1,"docs":{"52":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":7,"docs":{"23":{"tf":1.0},"60":{"tf":1.0},"63":{"tf":1.0},"65":{"tf":1.7320508075688772},"66":{"tf":1.0},"68":{"tf":1.0},"71":{"tf":1.0}}}}},"df":0,"docs":{}}}},"j":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"236":{"tf":1.4142135623730951},"7":{"tf":1.0}}}}},"k":{"df":0,"docs":{},"e":{"df":16,"docs":{"18":{"tf":1.4142135623730951},"180":{"tf":1.0},"19":{"tf":1.0},"221":{"tf":1.0},"226":{"tf":1.7320508075688772},"3":{"tf":1.0},"43":{"tf":1.0},"52":{"tf":1.0},"54":{"tf":1.0},"61":{"tf":1.0},"63":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"70":{"tf":1.0},"74":{"tf":1.4142135623730951},"81":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"61":{"tf":1.7320508075688772}}}}}}},"n":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"221":{"tf":1.0},"95":{"tf":1.0}}}},"d":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"193":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":3,"docs":{"39":{"tf":1.0},"5":{"tf":1.4142135623730951},"85":{"tf":1.0}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":1,"docs":{"235":{"tf":1.0}}}}}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"223":{"tf":1.0},"43":{"tf":1.0}}}},"df":0,"docs":{}}},"p":{"df":10,"docs":{"103":{"tf":1.0},"139":{"tf":1.0},"169":{"tf":1.4142135623730951},"178":{"tf":1.0},"179":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"219":{"tf":1.0},"84":{"tf":1.7320508075688772},"87":{"tf":1.0},"95":{"tf":1.0}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"(":{"$":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"169":{"tf":1.0}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"169":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"139":{"tf":1.0},"169":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"100":{"tf":1.0},"181":{"tf":1.7320508075688772}},"e":{"(":{"$":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"181":{"tf":1.0}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"181":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":2,"docs":{"75":{"tf":1.0},"84":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"75":{"tf":1.0},"84":{"tf":1.0}}}}}}},"’":{"df":2,"docs":{"169":{"tf":1.0},"181":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"k":{"df":2,"docs":{"80":{"tf":1.0},"98":{"tf":1.0}}}},"s":{"df":0,"docs":{},"k":{"df":4,"docs":{"117":{"tf":1.0},"75":{"tf":1.7320508075688772},"79":{"tf":2.0},"95":{"tf":1.0}}}},"t":{"c":{"df":0,"docs":{},"h":{"df":4,"docs":{"176":{"tf":1.0},"194":{"tf":1.4142135623730951},"223":{"tf":1.0},"75":{"tf":1.0}}}},"df":0,"docs":{}},"x":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":2,"docs":{"118":{"tf":1.0},"119":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":1,"docs":{"134":{"tf":1.0}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":2,"docs":{"201":{"tf":1.0},"40":{"tf":1.0}}}}}}},"y":{"b":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":3,"docs":{"100":{"tf":1.0},"178":{"tf":2.0},"40":{"tf":1.4142135623730951}}},"y":{"(":{"$":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"178":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"178":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"3":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":4,"docs":{"105":{"tf":1.0},"40":{"tf":1.0},"64":{"tf":1.0},"99":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":2,"docs":{"103":{"tf":1.0},"64":{"tf":1.7320508075688772}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"68":{"tf":1.0},"90":{"tf":1.4142135623730951},"91":{"tf":1.4142135623730951}}}}}},"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":3,"docs":{"18":{"tf":1.0},"189":{"tf":1.0},"203":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":2,"docs":{"176":{"tf":1.0},"75":{"tf":1.0}},"’":{"df":1,"docs":{"169":{"tf":1.0}}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":1,"docs":{"178":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":50,"docs":{"100":{"tf":1.4142135623730951},"101":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":2.0},"13":{"tf":1.7320508075688772},"138":{"tf":2.0},"14":{"tf":2.449489742783178},"147":{"tf":1.4142135623730951},"166":{"tf":1.7320508075688772},"175":{"tf":2.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"178":{"tf":1.7320508075688772},"182":{"tf":2.0},"183":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"185":{"tf":1.7320508075688772},"186":{"tf":1.7320508075688772},"187":{"tf":1.4142135623730951},"200":{"tf":1.0},"201":{"tf":2.0},"205":{"tf":1.0},"207":{"tf":1.4142135623730951},"209":{"tf":1.0},"210":{"tf":1.0},"214":{"tf":1.4142135623730951},"215":{"tf":1.0},"216":{"tf":1.0},"27":{"tf":1.0},"39":{"tf":1.7320508075688772},"40":{"tf":3.0},"57":{"tf":1.0},"70":{"tf":2.0},"72":{"tf":1.4142135623730951},"74":{"tf":1.4142135623730951},"75":{"tf":2.0},"76":{"tf":1.4142135623730951},"78":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":2.0},"81":{"tf":2.23606797749979},"82":{"tf":1.0},"83":{"tf":1.0},"87":{"tf":1.0},"91":{"tf":1.0},"92":{"tf":1.0},"93":{"tf":1.4142135623730951},"97":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"78":{"tf":1.0},"82":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":4,"docs":{"105":{"tf":1.4142135623730951},"166":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0}}}}}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"78":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"r":{"df":0,"docs":{},"g":{"df":5,"docs":{"151":{"tf":1.4142135623730951},"195":{"tf":1.0},"63":{"tf":1.0},"75":{"tf":1.0},"95":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"11":{"tf":1.0},"64":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"a":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"99":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"14":{"tf":1.0},"70":{"tf":1.0}}}}}},"i":{"d":{"df":1,"docs":{"94":{"tf":1.0}}},"df":1,"docs":{"82":{"tf":1.0}},"n":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"117":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":1,"docs":{"75":{"tf":1.0}},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"98":{"tf":1.0}},"u":{"df":0,"docs":{},"m":{"df":2,"docs":{"103":{"tf":1.0},"78":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}},"t":{"df":2,"docs":{"103":{"tf":1.0},"107":{"tf":1.0}}},"u":{"df":2,"docs":{"203":{"tf":1.0},"204":{"tf":1.0}}}},"s":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"80":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"s":{"df":1,"docs":{"18":{"tf":1.4142135623730951}}},"t":{"a":{"df":0,"docs":{},"k":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}},"x":{"df":3,"docs":{"52":{"tf":1.0},"81":{"tf":1.0},"92":{"tf":1.4142135623730951}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"’":{"df":1,"docs":{"76":{"tf":1.0}}}}},"o":{"a":{"d":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"166":{"tf":1.0}}}}}}}}},"0":{"df":2,"docs":{"78":{"tf":1.0},"82":{"tf":1.0}},"x":{"4":{"0":{"df":3,"docs":{"75":{"tf":1.0},"81":{"tf":1.4142135623730951},"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"2":{"^":{"1":{"2":{"8":{"df":2,"docs":{"78":{"tf":1.0},"82":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"5":{"5":{"df":1,"docs":{"82":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"166":{"tf":1.0}}},"3":{"df":1,"docs":{"166":{"tf":1.0}}},"df":0,"docs":{}}},"_":{"a":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"f":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"82":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}}},"df":6,"docs":{"100":{"tf":1.0},"104":{"tf":1.0},"166":{"tf":1.4142135623730951},"40":{"tf":1.4142135623730951},"82":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":3,"docs":{"135":{"tf":1.0},"174":{"tf":1.0},"207":{"tf":1.4142135623730951}}}}}}},"o":{"d":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"114":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"114":{"tf":1.0}}},"df":0,"docs":{}},"x":{"df":1,"docs":{"114":{"tf":1.0}}}},"df":8,"docs":{"100":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"114":{"tf":1.4142135623730951},"116":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0}},"e":{"df":7,"docs":{"176":{"tf":1.0},"18":{"tf":1.4142135623730951},"50":{"tf":1.4142135623730951},"73":{"tf":1.0},"80":{"tf":1.4142135623730951},"81":{"tf":1.7320508075688772},"82":{"tf":1.0}},"l":{"df":9,"docs":{"0":{"tf":1.0},"146":{"tf":1.0},"161":{"tf":1.0},"43":{"tf":1.4142135623730951},"49":{"tf":1.4142135623730951},"52":{"tf":1.0},"65":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0}}}},"i":{"df":0,"docs":{},"f":{"df":1,"docs":{"204":{"tf":1.0}},"i":{"df":1,"docs":{"175":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":7,"docs":{"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"116":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"78":{"tf":1.0}}}},"df":3,"docs":{"64":{"tf":1.0},"9":{"tf":1.0},"95":{"tf":1.7320508075688772}},"o":{"df":2,"docs":{"114":{"tf":1.0},"115":{"tf":1.0}}},"u":{"df":2,"docs":{"130":{"tf":1.0},"131":{"tf":1.0}}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"91":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":17,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"138":{"tf":1.0},"14":{"tf":1.0},"174":{"tf":1.4142135623730951},"189":{"tf":1.0},"2":{"tf":1.0},"219":{"tf":1.4142135623730951},"224":{"tf":1.7320508075688772},"33":{"tf":1.0},"5":{"tf":1.7320508075688772},"53":{"tf":1.0},"55":{"tf":1.0},"72":{"tf":1.0},"76":{"tf":1.0},"93":{"tf":1.4142135623730951},"99":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"219":{"tf":1.0},"236":{"tf":1.0},"24":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":2,"docs":{"235":{"tf":1.0},"74":{"tf":1.4142135623730951}}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"219":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":3,"docs":{"100":{"tf":1.0},"147":{"tf":2.23606797749979},"40":{"tf":1.7320508075688772}}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"176":{"tf":1.0}}}}}}}}},"0":{"df":4,"docs":{"139":{"tf":1.0},"140":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0}},"x":{"4":{"0":{"df":1,"docs":{"82":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}},"3":{"2":{"df":3,"docs":{"139":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"176":{"tf":1.0}}},"2":{"df":1,"docs":{"176":{"tf":1.0}}},"4":{"df":1,"docs":{"176":{"tf":1.0}}},"df":0,"docs":{}}},"8":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"177":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"177":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"177":{"tf":1.7320508075688772}}},"df":12,"docs":{"100":{"tf":1.0},"104":{"tf":1.0},"166":{"tf":1.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"178":{"tf":1.0},"179":{"tf":1.0},"40":{"tf":1.4142135623730951},"75":{"tf":1.0},"83":{"tf":1.0},"93":{"tf":1.0},"98":{"tf":1.0}}}}}}},"u":{"c":{"df":0,"docs":{},"h":{"df":4,"docs":{"219":{"tf":1.0},"224":{"tf":1.4142135623730951},"4":{"tf":1.0},"53":{"tf":1.0}}}},"df":0,"docs":{},"l":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"111":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"111":{"tf":1.0}}},"df":0,"docs":{}}},"df":4,"docs":{"100":{"tf":1.0},"111":{"tf":1.4142135623730951},"75":{"tf":1.0},"78":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"d":{"(":{"$":{"a":{"df":1,"docs":{"131":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"131":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"131":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":6,"docs":{"174":{"tf":1.4142135623730951},"182":{"tf":1.0},"189":{"tf":1.0},"194":{"tf":1.0},"78":{"tf":1.0},"99":{"tf":1.0}},"p":{"df":0,"docs":{},"l":{"df":8,"docs":{"111":{"tf":1.0},"131":{"tf":1.0},"178":{"tf":1.4142135623730951},"5":{"tf":1.0},"52":{"tf":1.0},"75":{"tf":1.0},"81":{"tf":1.0},"91":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"l":{"df":4,"docs":{"225":{"tf":1.0},"227":{"tf":2.0},"7":{"tf":1.0},"71":{"tf":1.0}}}}}},"n":{">":{"_":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"215":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":78,"docs":{"101":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.4142135623730951},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"159":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"174":{"tf":2.449489742783178},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"198":{"tf":1.0},"201":{"tf":1.0},"205":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"213":{"tf":1.0},"216":{"tf":1.0},"32":{"tf":1.0},"5":{"tf":1.4142135623730951},"62":{"tf":1.0},"64":{"tf":1.0},"98":{"tf":1.4142135623730951},"99":{"tf":1.0}},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":2,"docs":{"189":{"tf":1.0},"91":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":33,"docs":{"103":{"tf":1.4142135623730951},"107":{"tf":1.7320508075688772},"110":{"tf":1.0},"117":{"tf":1.7320508075688772},"122":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.4142135623730951},"136":{"tf":1.0},"137":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.4142135623730951},"181":{"tf":1.0},"184":{"tf":1.0},"193":{"tf":1.0},"201":{"tf":1.4142135623730951},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"213":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":2.449489742783178},"76":{"tf":1.0},"78":{"tf":3.3166247903554},"79":{"tf":2.449489742783178},"82":{"tf":1.4142135623730951},"91":{"tf":1.7320508075688772},"93":{"tf":1.4142135623730951},"95":{"tf":1.7320508075688772},"98":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"103":{"tf":1.0},"98":{"tf":1.0}}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":10,"docs":{"103":{"tf":1.0},"104":{"tf":1.0},"219":{"tf":1.4142135623730951},"4":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.7320508075688772},"82":{"tf":1.4142135623730951},"92":{"tf":1.4142135623730951},"94":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":2,"docs":{"52":{"tf":1.0},"98":{"tf":1.0}}}}}},"df":8,"docs":{"109":{"tf":1.0},"130":{"tf":2.0},"131":{"tf":2.0},"207":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.4142135623730951},"82":{"tf":1.0},"99":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"82":{"tf":1.0},"85":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"192":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"90":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"235":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"d":{"df":12,"docs":{"103":{"tf":1.0},"18":{"tf":1.7320508075688772},"216":{"tf":1.0},"219":{"tf":1.0},"235":{"tf":1.0},"33":{"tf":1.4142135623730951},"39":{"tf":1.0},"52":{"tf":1.0},"62":{"tf":1.4142135623730951},"64":{"tf":1.0},"71":{"tf":1.0},"94":{"tf":1.0}}},"df":0,"docs":{}},"g":{"df":1,"docs":{"122":{"tf":1.4142135623730951}}},"s":{"df":0,"docs":{},"t":{"df":5,"docs":{"100":{"tf":1.0},"192":{"tf":1.4142135623730951},"199":{"tf":1.4142135623730951},"204":{"tf":1.0},"98":{"tf":1.0}}}},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"145":{"tf":1.0}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"169":{"tf":1.0},"175":{"tf":1.4142135623730951},"18":{"tf":1.0},"181":{"tf":1.0},"223":{"tf":1.0}}}}},"w":{"df":13,"docs":{"107":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"202":{"tf":1.0},"205":{"tf":1.7320508075688772},"206":{"tf":1.0},"221":{"tf":1.0},"43":{"tf":1.0},"62":{"tf":1.0},"75":{"tf":1.4142135623730951},"82":{"tf":1.0},"91":{"tf":1.0},"97":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"103":{"tf":1.0}}}},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"_":{"d":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"94":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":145,"docs":{"100":{"tf":1.0},"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"106":{"tf":1.0},"107":{"tf":1.0},"108":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.7320508075688772},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"182":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"192":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"200":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"208":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"72":{"tf":1.4142135623730951},"73":{"tf":2.449489742783178},"74":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951},"76":{"tf":1.7320508075688772},"77":{"tf":1.0},"78":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0},"85":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.0},"88":{"tf":1.0},"89":{"tf":1.7320508075688772},"90":{"tf":1.7320508075688772},"91":{"tf":1.4142135623730951},"92":{"tf":1.0},"93":{"tf":1.0},"94":{"tf":2.449489742783178},"95":{"tf":1.7320508075688772},"96":{"tf":2.0},"97":{"tf":1.4142135623730951},"98":{"tf":1.0},"99":{"tf":1.0}}}}}}},"x":{"df":0,"docs":{},"t":{"df":1,"docs":{"147":{"tf":1.0}}}}},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"134":{"tf":1.0}}}}},"o":{"d":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"j":{"df":3,"docs":{"19":{"tf":1.0},"225":{"tf":1.0},"9":{"tf":1.0}}}},"df":10,"docs":{"195":{"tf":1.0},"208":{"tf":1.0},"224":{"tf":1.0},"53":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951},"76":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":1.7320508075688772},"95":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"87":{"tf":1.0},"92":{"tf":1.0}}}}}}},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"n":{"c":{"df":1,"docs":{"205":{"tf":1.0}}},"df":17,"docs":{"105":{"tf":1.0},"122":{"tf":1.4142135623730951},"164":{"tf":1.0},"18":{"tf":1.0},"184":{"tf":1.0},"193":{"tf":1.7320508075688772},"194":{"tf":1.0},"195":{"tf":1.7320508075688772},"62":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"80":{"tf":1.0},"82":{"tf":1.4142135623730951},"87":{"tf":1.0},"98":{"tf":1.4142135623730951}},"e":{"df":101,"docs":{"107":{"tf":1.0},"108":{"tf":1.4142135623730951},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.4142135623730951},"142":{"tf":1.4142135623730951},"143":{"tf":1.4142135623730951},"144":{"tf":1.4142135623730951},"145":{"tf":1.4142135623730951},"146":{"tf":1.4142135623730951},"147":{"tf":1.4142135623730951},"148":{"tf":1.4142135623730951},"149":{"tf":1.4142135623730951},"150":{"tf":1.4142135623730951},"151":{"tf":1.4142135623730951},"152":{"tf":1.4142135623730951},"153":{"tf":1.4142135623730951},"154":{"tf":1.4142135623730951},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.4142135623730951},"158":{"tf":1.4142135623730951},"159":{"tf":1.0},"160":{"tf":1.4142135623730951},"161":{"tf":1.4142135623730951},"162":{"tf":1.4142135623730951},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.4142135623730951},"179":{"tf":1.0},"180":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"183":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"185":{"tf":1.4142135623730951},"186":{"tf":1.4142135623730951},"187":{"tf":1.4142135623730951},"189":{"tf":1.4142135623730951},"190":{"tf":1.4142135623730951},"191":{"tf":1.0},"193":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"195":{"tf":1.4142135623730951},"196":{"tf":1.7320508075688772},"197":{"tf":1.7320508075688772},"198":{"tf":1.4142135623730951},"199":{"tf":1.7320508075688772},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.4142135623730951},"209":{"tf":1.4142135623730951},"210":{"tf":1.4142135623730951},"211":{"tf":1.7320508075688772},"212":{"tf":1.7320508075688772},"213":{"tf":1.4142135623730951},"214":{"tf":1.4142135623730951},"215":{"tf":1.4142135623730951},"216":{"tf":1.0},"98":{"tf":1.0}}}},"t":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"133":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"133":{"tf":1.0}}},"df":0,"docs":{}}},"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"0":{"tf":1.0},"235":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":1,"docs":{"99":{"tf":1.7320508075688772}}}},"df":0,"docs":{},"e":{"df":78,"docs":{"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"159":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"18":{"tf":1.4142135623730951},"180":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"19":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"198":{"tf":1.0},"201":{"tf":1.0},"205":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"213":{"tf":1.0},"216":{"tf":1.0},"218":{"tf":1.0},"219":{"tf":1.0},"223":{"tf":1.0},"33":{"tf":1.0},"39":{"tf":1.0},"52":{"tf":1.0},"73":{"tf":1.0},"98":{"tf":1.4142135623730951}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":1,"docs":{"39":{"tf":1.0}}}}}}}}},"h":{"df":1,"docs":{"198":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"m":{"df":2,"docs":{"19":{"tf":2.23606797749979},"9":{"tf":1.4142135623730951}}},"x":{"df":1,"docs":{"19":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"n":{"c":{"df":2,"docs":{"224":{"tf":1.0},"65":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"219":{"tf":1.0}}}}}}},"m":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":16,"docs":{"100":{"tf":1.0},"134":{"tf":1.0},"150":{"tf":2.23606797749979},"156":{"tf":1.7320508075688772},"178":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"193":{"tf":1.0},"207":{"tf":1.0},"215":{"tf":1.0},"219":{"tf":1.0},"64":{"tf":1.0},"90":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"27":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":2,"docs":{"43":{"tf":1.0},"53":{"tf":1.0}}}}}}}}},"o":{"(":{"df":0,"docs":{},"n":{"df":1,"docs":{"219":{"tf":1.0}}}},"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":13,"docs":{"16":{"tf":1.0},"174":{"tf":1.0},"18":{"tf":1.0},"218":{"tf":1.0},"25":{"tf":1.4142135623730951},"27":{"tf":1.4142135623730951},"28":{"tf":1.7320508075688772},"31":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"75":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.7320508075688772},"95":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":7,"docs":{"0":{"tf":1.0},"179":{"tf":1.0},"181":{"tf":1.0},"190":{"tf":1.0},"223":{"tf":1.4142135623730951},"3":{"tf":1.0},"34":{"tf":1.0}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"225":{"tf":1.0},"226":{"tf":1.0}}}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":1,"docs":{"64":{"tf":1.0}}}}}}},"c":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"129":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":3,"docs":{"12":{"tf":1.0},"19":{"tf":1.0},"29":{"tf":1.0}},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"4":{"tf":1.0},"49":{"tf":1.0},"70":{"tf":1.0},"90":{"tf":1.0}}}},"i":{"c":{"df":0,"docs":{},"i":{"df":3,"docs":{"18":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":34,"docs":{"105":{"tf":1.7320508075688772},"138":{"tf":1.7320508075688772},"147":{"tf":1.0},"159":{"tf":1.7320508075688772},"166":{"tf":1.7320508075688772},"170":{"tf":1.4142135623730951},"176":{"tf":2.449489742783178},"177":{"tf":2.0},"178":{"tf":1.4142135623730951},"182":{"tf":1.4142135623730951},"183":{"tf":2.23606797749979},"184":{"tf":2.23606797749979},"185":{"tf":2.23606797749979},"186":{"tf":2.23606797749979},"187":{"tf":2.23606797749979},"201":{"tf":1.4142135623730951},"205":{"tf":1.7320508075688772},"206":{"tf":1.0},"207":{"tf":1.7320508075688772},"209":{"tf":1.7320508075688772},"210":{"tf":1.7320508075688772},"215":{"tf":1.0},"216":{"tf":1.0},"39":{"tf":1.4142135623730951},"40":{"tf":1.0},"41":{"tf":1.0},"57":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":2.0},"81":{"tf":1.4142135623730951},"82":{"tf":1.4142135623730951},"85":{"tf":1.0},"99":{"tf":1.0}}}}}}},"k":{"(":{"0":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":1,"docs":{"57":{"tf":1.4142135623730951}}},"n":{"c":{"df":3,"docs":{"172":{"tf":1.0},"191":{"tf":1.0},"91":{"tf":1.0}}},"df":26,"docs":{"102":{"tf":1.0},"103":{"tf":1.0},"107":{"tf":1.0},"109":{"tf":1.0},"122":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.4142135623730951},"15":{"tf":1.0},"174":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.4142135623730951},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.4142135623730951},"198":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"219":{"tf":1.0},"235":{"tf":1.0},"33":{"tf":1.0},"65":{"tf":1.0},"82":{"tf":1.0},"87":{"tf":1.4142135623730951},"92":{"tf":1.0},"98":{"tf":1.4142135623730951}},"t":{"df":0,"docs":{},"o":{"df":1,"docs":{"178":{"tf":1.0}}}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"229":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"p":{"(":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"(":{"a":{",":{"df":0,"docs":{},"n":{"df":1,"docs":{"78":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"a":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":1,"docs":{"182":{"tf":1.0}}}}},"c":{"df":0,"docs":{},"o":{"d":{"df":9,"docs":{"116":{"tf":1.0},"134":{"tf":1.0},"174":{"tf":1.0},"202":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"231":{"tf":1.4142135623730951},"43":{"tf":1.0},"49":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"81":{"tf":1.0},"98":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"59":{"tf":1.0},"63":{"tf":1.0}},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"90":{"tf":1.7320508075688772},"91":{"tf":1.0}}}}}}}}}}},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":110,"docs":{"106":{"tf":1.4142135623730951},"107":{"tf":1.0},"108":{"tf":1.0},"109":{"tf":1.7320508075688772},"110":{"tf":1.7320508075688772},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.4142135623730951},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.4142135623730951},"121":{"tf":1.4142135623730951},"122":{"tf":1.4142135623730951},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.4142135623730951},"126":{"tf":1.4142135623730951},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.7320508075688772},"133":{"tf":1.7320508075688772},"134":{"tf":1.7320508075688772},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.4142135623730951},"171":{"tf":1.4142135623730951},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.4142135623730951},"176":{"tf":1.0},"177":{"tf":1.4142135623730951},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.4142135623730951},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.7320508075688772},"204":{"tf":1.7320508075688772},"205":{"tf":1.0},"206":{"tf":1.4142135623730951},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.4142135623730951},"215":{"tf":1.7320508075688772},"216":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":2.0},"99":{"tf":1.0}},"’":{"df":1,"docs":{"111":{"tf":1.0}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":1,"docs":{"99":{"tf":1.0}}}}}}}},"df":24,"docs":{"100":{"tf":1.4142135623730951},"101":{"tf":1.0},"129":{"tf":1.0},"135":{"tf":1.0},"175":{"tf":1.0},"177":{"tf":1.0},"179":{"tf":1.0},"181":{"tf":1.0},"40":{"tf":1.0},"68":{"tf":1.0},"7":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":1.7320508075688772},"78":{"tf":1.7320508075688772},"79":{"tf":1.0},"80":{"tf":1.0},"84":{"tf":1.0},"87":{"tf":1.0},"93":{"tf":1.0},"96":{"tf":1.0},"97":{"tf":2.23606797749979},"98":{"tf":2.8284271247461903},"99":{"tf":1.0}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":3,"docs":{"72":{"tf":1.0},"75":{"tf":1.0},"93":{"tf":1.4142135623730951}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":156,"docs":{"100":{"tf":1.0},"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"106":{"tf":1.0},"107":{"tf":1.0},"108":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"12":{"tf":3.4641016151377544},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"16":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"18":{"tf":1.7320508075688772},"180":{"tf":1.4142135623730951},"181":{"tf":1.0},"182":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"192":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"200":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"208":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"236":{"tf":1.4142135623730951},"28":{"tf":1.0},"29":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"67":{"tf":1.0},"70":{"tf":1.0},"72":{"tf":2.449489742783178},"73":{"tf":2.23606797749979},"74":{"tf":1.7320508075688772},"75":{"tf":2.23606797749979},"76":{"tf":1.0},"77":{"tf":1.7320508075688772},"78":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.7320508075688772},"81":{"tf":1.4142135623730951},"82":{"tf":2.449489742783178},"83":{"tf":1.4142135623730951},"84":{"tf":1.0},"85":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.4142135623730951},"88":{"tf":1.0},"89":{"tf":1.0},"90":{"tf":1.7320508075688772},"91":{"tf":2.449489742783178},"92":{"tf":1.7320508075688772},"93":{"tf":1.4142135623730951},"94":{"tf":1.4142135623730951},"95":{"tf":1.0},"96":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"90":{"tf":1.4142135623730951}}},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"’":{"df":1,"docs":{"81":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"66":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"n":{"<":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"167":{"tf":1.0},"179":{"tf":1.0}}}}}}}}},"df":0,"docs":{}},"df":6,"docs":{"11":{"tf":1.4142135623730951},"19":{"tf":1.4142135623730951},"193":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"98":{"tf":1.0},"99":{"tf":1.4142135623730951}}}}}}},"r":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"118":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"118":{"tf":1.0}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}}}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":10,"docs":{"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"161":{"tf":1.0},"174":{"tf":1.0},"219":{"tf":1.4142135623730951},"51":{"tf":1.4142135623730951},"75":{"tf":1.0},"81":{"tf":1.7320508075688772},"82":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":5,"docs":{"100":{"tf":1.0},"103":{"tf":1.0},"143":{"tf":2.23606797749979},"181":{"tf":1.0},"75":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"94":{"tf":1.0}},"w":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":11,"docs":{"107":{"tf":1.0},"121":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"177":{"tf":1.0},"179":{"tf":1.0},"18":{"tf":1.0},"192":{"tf":1.0},"193":{"tf":1.0},"198":{"tf":1.0},"99":{"tf":1.0}}}}}}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":2,"docs":{"34":{"tf":1.0},"39":{"tf":1.0}}}}},"t":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"57":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":2,"docs":{"223":{"tf":1.4142135623730951},"92":{"tf":1.0}}}}},"d":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"23":{"tf":1.0}}}},"df":0,"docs":{}},"df":5,"docs":{"185":{"tf":1.0},"214":{"tf":1.0},"232":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":14,"docs":{"139":{"tf":1.0},"140":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"208":{"tf":1.0},"214":{"tf":1.4142135623730951},"215":{"tf":1.0},"216":{"tf":1.0},"64":{"tf":1.0},"75":{"tf":2.0},"84":{"tf":2.0},"86":{"tf":1.7320508075688772},"87":{"tf":2.0},"95":{"tf":1.4142135623730951}}}}},"o":{"df":0,"docs":{},"f":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"40":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"g":{"a":{"df":1,"docs":{"39":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{">":{"/":{"<":{"df":0,"docs":{},"o":{"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{">":{".":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":1,"docs":{"94":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{"_":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"_":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":1,"docs":{"94":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":14,"docs":{"16":{"tf":1.0},"17":{"tf":1.0},"192":{"tf":1.0},"193":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"195":{"tf":1.4142135623730951},"196":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":2.23606797749979},"33":{"tf":3.1622776601683795},"55":{"tf":1.0},"94":{"tf":1.7320508075688772},"95":{"tf":1.0},"98":{"tf":1.0}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"32":{"tf":1.4142135623730951},"33":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}},"s":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"156":{"tf":1.0}}},"df":0,"docs":{}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"5":{"tf":1.0},"67":{"tf":1.0}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"219":{"tf":1.0}}}}},"df":3,"docs":{"235":{"tf":1.0},"68":{"tf":1.0},"91":{"tf":1.0}},"f":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":9,"docs":{"103":{"tf":1.0},"109":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"214":{"tf":1.7320508075688772},"70":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.0},"92":{"tf":1.4142135623730951}}}}}},"h":{"df":0,"docs":{},"e":{"a":{"d":{"df":3,"docs":{"219":{"tf":1.7320508075688772},"75":{"tf":1.4142135623730951},"92":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"l":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"178":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":1,"docs":{"91":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.0}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":2,"docs":{"236":{"tf":1.0},"75":{"tf":1.4142135623730951}}}}}}}}},"w":{"df":0,"docs":{},"n":{"df":1,"docs":{"143":{"tf":1.0}}}},"z":{"_":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":1,"docs":{"90":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"w":{"a":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"c":{"2":{"0":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"90":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":3,"docs":{"12":{"tf":1.0},"81":{"tf":1.0},"90":{"tf":1.0}}}},"p":{"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":4,"docs":{"19":{"tf":2.23606797749979},"221":{"tf":1.0},"89":{"tf":1.0},"9":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"d":{"df":1,"docs":{"214":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":3,"docs":{"168":{"tf":1.0},"224":{"tf":1.0},"91":{"tf":1.0}}}},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":14,"docs":{"0":{"tf":1.7320508075688772},"180":{"tf":1.0},"217":{"tf":2.0},"218":{"tf":1.0},"219":{"tf":1.4142135623730951},"220":{"tf":2.23606797749979},"223":{"tf":1.4142135623730951},"224":{"tf":1.0},"34":{"tf":1.0},"37":{"tf":1.0},"41":{"tf":1.0},"46":{"tf":1.0},"53":{"tf":1.0},"55":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"i":{"c":{"(":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"2":{"5":{"6":{"df":2,"docs":{"214":{"tf":1.0},"86":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"(":{"0":{"df":0,"docs":{},"x":{"1":{"1":{"df":1,"docs":{"214":{"tf":1.0}}},"df":0,"docs":{}},"<":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":1,"docs":{"214":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":2,"docs":{"100":{"tf":1.0},"214":{"tf":1.4142135623730951}}}}}}}}},"df":4,"docs":{"214":{"tf":2.23606797749979},"64":{"tf":1.0},"75":{"tf":1.0},"86":{"tf":1.4142135623730951}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"86":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}},"r":{"a":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"235":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":4,"docs":{"103":{"tf":1.0},"189":{"tf":1.0},"78":{"tf":2.0},"91":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"/":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"75":{"tf":1.0}}}}}}}}},"df":2,"docs":{"75":{"tf":1.0},"85":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"64":{"tf":1.0}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"98":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}},"y":{"/":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{"@":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"19":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"5":{"tf":1.0},"69":{"tf":1.4142135623730951},"97":{"tf":1.0}}}}},"t":{"df":6,"docs":{"135":{"tf":1.0},"179":{"tf":1.0},"62":{"tf":1.0},"82":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}},"i":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":1,"docs":{"98":{"tf":1.4142135623730951}}}}},"df":2,"docs":{"20":{"tf":1.0},"64":{"tf":1.0}},"t":{"df":1,"docs":{"167":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"s":{"df":33,"docs":{"104":{"tf":1.0},"105":{"tf":1.0},"107":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"179":{"tf":1.0},"181":{"tf":1.0},"182":{"tf":1.0},"185":{"tf":1.0},"195":{"tf":1.0},"198":{"tf":1.0},"219":{"tf":1.0},"63":{"tf":1.4142135623730951},"72":{"tf":1.0},"75":{"tf":3.0},"78":{"tf":1.0},"79":{"tf":1.0},"80":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":1.0},"91":{"tf":1.7320508075688772},"92":{"tf":1.4142135623730951},"93":{"tf":1.0},"94":{"tf":1.0},"95":{"tf":1.4142135623730951},"97":{"tf":1.0}}},"t":{"df":4,"docs":{"159":{"tf":1.0},"183":{"tf":1.0},"185":{"tf":1.0},"187":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"/":{"df":0,"docs":{},"m":{"df":0,"docs":{},"y":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"1":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}},"2":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"=":{"/":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"/":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":1,"docs":{"221":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":6,"docs":{"15":{"tf":1.4142135623730951},"173":{"tf":2.0},"221":{"tf":1.0},"64":{"tf":1.0},"82":{"tf":1.0},"94":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":18,"docs":{"138":{"tf":1.0},"139":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"203":{"tf":1.0},"208":{"tf":1.0},"52":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.7320508075688772},"79":{"tf":1.7320508075688772},"80":{"tf":1.4142135623730951},"83":{"tf":1.0},"84":{"tf":1.0},"86":{"tf":2.0},"87":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.7320508075688772}}}}}}},"y":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"87":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"c":{"df":1,"docs":{"48":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":33,"docs":{"109":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"146":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"156":{"tf":1.0},"161":{"tf":1.4142135623730951},"166":{"tf":1.7320508075688772},"167":{"tf":1.4142135623730951},"168":{"tf":1.0},"169":{"tf":1.0},"180":{"tf":1.0},"185":{"tf":1.4142135623730951},"190":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.4142135623730951},"198":{"tf":1.0},"199":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"87":{"tf":1.4142135623730951},"90":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":1.0}},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":8,"docs":{"12":{"tf":1.0},"232":{"tf":1.0},"66":{"tf":1.0},"73":{"tf":1.0},"76":{"tf":1.0},"78":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":3,"docs":{"167":{"tf":1.0},"175":{"tf":1.0},"179":{"tf":1.0}}}}}}}},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":2,"docs":{"78":{"tf":1.0},"91":{"tf":2.23606797749979}}}}},"df":0,"docs":{},"i":{"df":2,"docs":{"195":{"tf":1.0},"95":{"tf":1.0}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":1,"docs":{"222":{"tf":1.0}}}}}}}}}}},"i":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"117":{"tf":1.0}}}},"df":0,"docs":{},"e":{"c":{"df":1,"docs":{"52":{"tf":1.0}}},"df":0,"docs":{}},"n":{"df":1,"docs":{"62":{"tf":1.0}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":7,"docs":{"236":{"tf":1.0},"50":{"tf":1.0},"61":{"tf":1.0},"75":{"tf":1.4142135623730951},"91":{"tf":1.0},"94":{"tf":1.4142135623730951},"95":{"tf":1.0}}}}}}}},"l":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"97":{"tf":1.0}},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"99":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"208":{"tf":1.0}}}},"t":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":4,"docs":{"235":{"tf":1.0},"68":{"tf":1.0},"7":{"tf":1.0},"71":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":8,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"61":{"tf":1.0},"62":{"tf":1.7320508075688772},"64":{"tf":1.4142135623730951},"65":{"tf":1.0},"7":{"tf":1.0},"8":{"tf":1.0}}}},"df":0,"docs":{}},"u":{"df":3,"docs":{"105":{"tf":1.0},"206":{"tf":1.4142135623730951},"214":{"tf":1.0}}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"104":{"tf":1.4142135623730951},"146":{"tf":1.0},"196":{"tf":1.0},"93":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":11,"docs":{"102":{"tf":1.0},"103":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.7320508075688772},"166":{"tf":1.0},"39":{"tf":1.4142135623730951},"43":{"tf":1.4142135623730951},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"81":{"tf":1.7320508075688772}}}}}}},"l":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":1,"docs":{"4":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":6,"docs":{"2":{"tf":1.7320508075688772},"217":{"tf":1.0},"220":{"tf":1.0},"4":{"tf":1.0},"49":{"tf":1.0},"52":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":16,"docs":{"1":{"tf":1.0},"103":{"tf":1.4142135623730951},"104":{"tf":1.0},"180":{"tf":1.0},"217":{"tf":1.0},"226":{"tf":1.4142135623730951},"5":{"tf":1.0},"55":{"tf":1.0},"6":{"tf":1.4142135623730951},"67":{"tf":1.4142135623730951},"73":{"tf":1.0},"74":{"tf":1.4142135623730951},"75":{"tf":1.0},"78":{"tf":1.0},"92":{"tf":1.0},"95":{"tf":1.0}},"’":{"df":1,"docs":{"176":{"tf":1.0}}}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"91":{"tf":1.0}}}}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"18":{"tf":1.0},"66":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"207":{"tf":1.0},"65":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":16,"docs":{"106":{"tf":1.0},"107":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.7320508075688772},"137":{"tf":1.0},"170":{"tf":1.4142135623730951},"171":{"tf":1.4142135623730951},"172":{"tf":1.4142135623730951},"173":{"tf":1.4142135623730951},"174":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.4142135623730951},"215":{"tf":1.4142135623730951},"216":{"tf":1.0},"75":{"tf":1.0},"85":{"tf":1.0}}}},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":6,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"198":{"tf":1.0},"222":{"tf":1.7320508075688772},"235":{"tf":1.0},"62":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"t":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"195":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":5,"docs":{"151":{"tf":1.0},"195":{"tf":2.6457513110645907},"197":{"tf":1.0},"213":{"tf":1.0},"22":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":4,"docs":{"0":{"tf":1.0},"185":{"tf":1.0},"34":{"tf":1.0},"68":{"tf":1.0}}}}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"224":{"tf":1.0},"66":{"tf":1.0},"75":{"tf":1.0}}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":6,"docs":{"134":{"tf":1.0},"146":{"tf":1.0},"177":{"tf":1.0},"219":{"tf":1.0},"52":{"tf":1.0},"78":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":3,"docs":{"62":{"tf":1.4142135623730951},"63":{"tf":1.7320508075688772},"65":{"tf":1.0}},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.0}}}}}}}},"d":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"84":{"tf":1.0}}}},"df":0,"docs":{}}},"df":1,"docs":{"151":{"tf":1.0}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"62":{"tf":1.0}}}},"i":{"df":0,"docs":{},"x":{"df":2,"docs":{"62":{"tf":1.4142135623730951},"99":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{"/":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"94":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"t":{"df":3,"docs":{"167":{"tf":1.0},"179":{"tf":1.0},"99":{"tf":1.0}}}},"r":{"df":0,"docs":{},"v":{"df":6,"docs":{"122":{"tf":1.0},"202":{"tf":1.0},"222":{"tf":1.0},"40":{"tf":1.0},"76":{"tf":1.0},"93":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"95":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"68":{"tf":1.0},"70":{"tf":1.0},"80":{"tf":1.4142135623730951},"92":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"82":{"tf":1.0}}}}}},"r":{"a":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"o":{"df":2,"docs":{"151":{"tf":1.0},"47":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"158":{"tf":1.0}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":5,"docs":{"129":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"180":{"tf":1.0},"52":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"t":{"df":28,"docs":{"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"107":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.0},"179":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.7320508075688772},"216":{"tf":1.4142135623730951},"76":{"tf":1.0},"94":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":2.0}},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"r":{"df":2,"docs":{"95":{"tf":1.0},"97":{"tf":1.0}}}},"df":8,"docs":{"135":{"tf":1.0},"167":{"tf":1.0},"174":{"tf":1.7320508075688772},"179":{"tf":1.0},"95":{"tf":1.0},"97":{"tf":1.4142135623730951},"98":{"tf":1.4142135623730951},"99":{"tf":2.0}},"’":{"df":1,"docs":{"98":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"219":{"tf":1.0},"65":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"236":{"tf":1.0}}}}}}}},"o":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}}},"df":1,"docs":{"219":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":7,"docs":{"33":{"tf":1.0},"50":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"71":{"tf":1.0},"8":{"tf":1.0}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":20,"docs":{"102":{"tf":1.0},"106":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"137":{"tf":1.0},"166":{"tf":1.0},"169":{"tf":1.0},"18":{"tf":1.0},"180":{"tf":1.0},"189":{"tf":1.7320508075688772},"200":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.0},"78":{"tf":1.0},"89":{"tf":1.0},"90":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}},"t":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"93":{"tf":1.0}}},"t":{"df":1,"docs":{"232":{"tf":1.0}}}}},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"m":{"df":3,"docs":{"235":{"tf":1.0},"52":{"tf":1.0},"91":{"tf":1.0}},"’":{"df":1,"docs":{"147":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"91":{"tf":1.0}}}}}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":6,"docs":{"226":{"tf":1.0},"235":{"tf":1.0},"3":{"tf":1.0},"5":{"tf":1.0},"59":{"tf":1.0},"65":{"tf":1.4142135623730951}},"’":{"df":2,"docs":{"236":{"tf":1.0},"60":{"tf":1.0}}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"f":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}},"df":5,"docs":{"52":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0},"79":{"tf":1.0},"81":{"tf":2.0}}}},"p":{"a":{"df":0,"docs":{},"g":{"df":8,"docs":{"105":{"tf":1.0},"108":{"tf":1.0},"176":{"tf":1.0},"75":{"tf":2.449489742783178},"78":{"tf":1.4142135623730951},"80":{"tf":1.7320508075688772},"81":{"tf":1.0},"95":{"tf":1.7320508075688772}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"68":{"tf":1.0},"74":{"tf":1.0},"78":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"116":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"98":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"81":{"tf":1.0}}}},"df":0,"docs":{}}},"v":{"a":{"b":{"df":0,"docs":{},"l":{"df":3,"docs":{"75":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":4,"docs":{"103":{"tf":1.0},"177":{"tf":1.0},"223":{"tf":1.0},"79":{"tf":1.0}},"n":{"df":1,"docs":{"176":{"tf":1.0}}}},"i":{"d":{"df":10,"docs":{"18":{"tf":2.23606797749979},"180":{"tf":1.0},"220":{"tf":1.0},"223":{"tf":1.4142135623730951},"235":{"tf":1.4142135623730951},"52":{"tf":1.0},"56":{"tf":1.0},"64":{"tf":1.7320508075688772},"66":{"tf":1.0},"80":{"tf":1.0}}},"df":0,"docs":{}}},"x":{"df":0,"docs":{},"i":{"df":2,"docs":{"203":{"tf":1.0},"90":{"tf":1.0}},"m":{"df":1,"docs":{"219":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"r":{"(":{"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":1,"docs":{"102":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"<":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"102":{"tf":1.0},"104":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":4,"docs":{"101":{"tf":1.0},"102":{"tf":1.0},"104":{"tf":1.0},"99":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"102":{"tf":1.0},"104":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"102":{"tf":1.0},"104":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":1,"docs":{"104":{"tf":1.0}}}},"u":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"51":{"tf":1.4142135623730951},"64":{"tf":1.0}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"19":{"tf":1.0}}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":2,"docs":{"186":{"tf":1.0},"63":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"e":{"df":74,"docs":{"100":{"tf":1.0},"106":{"tf":2.0},"107":{"tf":1.0},"108":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.7320508075688772},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.4142135623730951},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.4142135623730951},"167":{"tf":1.4142135623730951},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"175":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.4142135623730951},"76":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.4142135623730951}}},"g":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"=":{"6":{"1":{"4":{"4":{"/":{"3":{"1":{"4":{"5":{"7":{"2":{"8":{"df":1,"docs":{"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":106,"docs":{"107":{"tf":1.4142135623730951},"108":{"tf":1.4142135623730951},"109":{"tf":1.4142135623730951},"110":{"tf":1.4142135623730951},"111":{"tf":1.4142135623730951},"112":{"tf":1.4142135623730951},"113":{"tf":1.4142135623730951},"114":{"tf":1.4142135623730951},"115":{"tf":1.4142135623730951},"116":{"tf":1.4142135623730951},"117":{"tf":1.4142135623730951},"118":{"tf":1.4142135623730951},"119":{"tf":1.4142135623730951},"120":{"tf":1.4142135623730951},"121":{"tf":1.4142135623730951},"122":{"tf":1.4142135623730951},"123":{"tf":1.4142135623730951},"124":{"tf":1.4142135623730951},"125":{"tf":1.4142135623730951},"126":{"tf":1.4142135623730951},"127":{"tf":1.4142135623730951},"128":{"tf":1.4142135623730951},"129":{"tf":1.4142135623730951},"130":{"tf":1.4142135623730951},"131":{"tf":1.4142135623730951},"132":{"tf":1.4142135623730951},"133":{"tf":1.4142135623730951},"134":{"tf":1.4142135623730951},"135":{"tf":1.4142135623730951},"136":{"tf":1.4142135623730951},"137":{"tf":1.4142135623730951},"138":{"tf":1.4142135623730951},"139":{"tf":1.4142135623730951},"140":{"tf":1.4142135623730951},"141":{"tf":1.4142135623730951},"142":{"tf":1.4142135623730951},"143":{"tf":1.4142135623730951},"144":{"tf":1.4142135623730951},"145":{"tf":1.4142135623730951},"146":{"tf":1.4142135623730951},"147":{"tf":1.4142135623730951},"148":{"tf":1.4142135623730951},"149":{"tf":1.4142135623730951},"150":{"tf":1.4142135623730951},"151":{"tf":1.4142135623730951},"152":{"tf":1.4142135623730951},"153":{"tf":1.4142135623730951},"154":{"tf":1.4142135623730951},"155":{"tf":1.4142135623730951},"156":{"tf":1.4142135623730951},"157":{"tf":1.4142135623730951},"158":{"tf":1.4142135623730951},"159":{"tf":1.4142135623730951},"160":{"tf":1.4142135623730951},"161":{"tf":1.4142135623730951},"162":{"tf":1.4142135623730951},"163":{"tf":1.4142135623730951},"164":{"tf":1.4142135623730951},"165":{"tf":1.4142135623730951},"166":{"tf":1.4142135623730951},"167":{"tf":1.4142135623730951},"168":{"tf":1.4142135623730951},"169":{"tf":1.4142135623730951},"170":{"tf":1.4142135623730951},"171":{"tf":1.4142135623730951},"172":{"tf":1.4142135623730951},"173":{"tf":1.4142135623730951},"174":{"tf":1.7320508075688772},"176":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"178":{"tf":1.4142135623730951},"179":{"tf":1.4142135623730951},"180":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"183":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"185":{"tf":1.4142135623730951},"186":{"tf":1.4142135623730951},"187":{"tf":1.4142135623730951},"189":{"tf":1.7320508075688772},"190":{"tf":1.4142135623730951},"191":{"tf":1.4142135623730951},"193":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"195":{"tf":1.4142135623730951},"196":{"tf":1.4142135623730951},"197":{"tf":1.4142135623730951},"198":{"tf":1.4142135623730951},"199":{"tf":1.4142135623730951},"201":{"tf":1.4142135623730951},"202":{"tf":1.4142135623730951},"203":{"tf":1.4142135623730951},"204":{"tf":1.4142135623730951},"205":{"tf":1.4142135623730951},"206":{"tf":1.4142135623730951},"207":{"tf":1.4142135623730951},"209":{"tf":1.4142135623730951},"210":{"tf":1.4142135623730951},"211":{"tf":1.4142135623730951},"212":{"tf":1.4142135623730951},"213":{"tf":1.4142135623730951},"214":{"tf":1.4142135623730951},"215":{"tf":1.4142135623730951},"216":{"tf":1.4142135623730951},"96":{"tf":1.0},"98":{"tf":1.4142135623730951}}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":9,"docs":{"138":{"tf":1.0},"146":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"219":{"tf":1.0},"30":{"tf":1.0},"52":{"tf":1.0},"82":{"tf":1.0},"95":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"63":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"m":{"df":27,"docs":{"0":{"tf":1.4142135623730951},"13":{"tf":1.0},"14":{"tf":1.4142135623730951},"16":{"tf":1.0},"18":{"tf":1.0},"217":{"tf":2.0},"218":{"tf":1.4142135623730951},"219":{"tf":3.0},"220":{"tf":1.0},"223":{"tf":1.4142135623730951},"235":{"tf":1.0},"236":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"35":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.4142135623730951},"48":{"tf":1.0},"52":{"tf":1.0},"55":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"80":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.0}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}}}}},"q":{"df":0,"docs":{},"u":{"a":{"d":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"64":{"tf":1.0}}}},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"59":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"60":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"t":{"df":5,"docs":{"170":{"tf":1.4142135623730951},"171":{"tf":1.4142135623730951},"172":{"tf":1.4142135623730951},"173":{"tf":1.4142135623730951},"191":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"112":{"tf":1.0},"113":{"tf":1.0}}}}}}}}}},"r":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"78":{"tf":1.0}},"g":{"df":9,"docs":{"105":{"tf":1.0},"156":{"tf":1.0},"178":{"tf":1.7320508075688772},"185":{"tf":1.0},"79":{"tf":1.0},"81":{"tf":2.23606797749979},"82":{"tf":1.0},"90":{"tf":1.0},"94":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"108":{"tf":1.0},"18":{"tf":1.4142135623730951}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}}}},"w":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"97":{"tf":1.0}}}},"df":0,"docs":{}},"df":3,"docs":{"134":{"tf":1.0},"74":{"tf":1.0},"93":{"tf":1.0}}}},"d":{"/":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"166":{"tf":1.0}}}}}}},"a":{"b":{"df":0,"docs":{},"l":{"df":3,"docs":{"61":{"tf":1.0},"64":{"tf":1.0},"95":{"tf":1.0}}}},"df":0,"docs":{}},"df":26,"docs":{"1":{"tf":1.0},"100":{"tf":1.0},"104":{"tf":1.0},"159":{"tf":1.4142135623730951},"166":{"tf":1.7320508075688772},"167":{"tf":1.4142135623730951},"168":{"tf":1.0},"172":{"tf":1.4142135623730951},"183":{"tf":1.0},"184":{"tf":1.4142135623730951},"185":{"tf":1.4142135623730951},"187":{"tf":1.0},"191":{"tf":1.0},"201":{"tf":1.0},"204":{"tf":1.0},"207":{"tf":1.0},"34":{"tf":1.0},"40":{"tf":1.0},"61":{"tf":1.0},"65":{"tf":1.0},"75":{"tf":1.0},"82":{"tf":1.0},"94":{"tf":1.0},"95":{"tf":1.0},"97":{"tf":1.4142135623730951},"98":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"81":{"tf":1.0},"82":{"tf":1.0}}}},"m":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"m":{"d":{"df":2,"docs":{"10":{"tf":1.0},"60":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"df":2,"docs":{"105":{"tf":1.0},"90":{"tf":1.0}},"i":{"df":0,"docs":{},"z":{"df":2,"docs":{"235":{"tf":1.0},"72":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":8,"docs":{"18":{"tf":1.0},"235":{"tf":1.0},"32":{"tf":1.0},"43":{"tf":1.0},"52":{"tf":1.0},"69":{"tf":1.0},"70":{"tf":1.0},"81":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":2,"docs":{"195":{"tf":1.0},"39":{"tf":1.0}}}},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"156":{"tf":1.0},"161":{"tf":1.0},"185":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"213":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":5,"docs":{"139":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"79":{"tf":1.0},"83":{"tf":1.0}}}},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"232":{"tf":1.0},"69":{"tf":1.0}}},"df":0,"docs":{}}}}},"v":{"df":1,"docs":{"74":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"92":{"tf":1.0}},"s":{"df":1,"docs":{"75":{"tf":1.7320508075688772}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":2,"docs":{"219":{"tf":1.0},"78":{"tf":1.0}},"t":{"df":5,"docs":{"75":{"tf":1.0},"81":{"tf":1.0},"89":{"tf":1.0},"90":{"tf":1.4142135623730951},"95":{"tf":1.0}}}},"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"84":{"tf":1.0}}},"df":0,"docs":{}}}},"df":2,"docs":{"195":{"tf":1.0},"78":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"180":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"f":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":131,"docs":{"100":{"tf":1.0},"101":{"tf":1.7320508075688772},"102":{"tf":1.0},"103":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"106":{"tf":1.4142135623730951},"107":{"tf":1.0},"108":{"tf":1.7320508075688772},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"182":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"192":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"200":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"208":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"222":{"tf":1.0},"223":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.0},"6":{"tf":1.0},"60":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"8":{"tf":1.0},"95":{"tf":2.0},"96":{"tf":2.0},"97":{"tf":1.7320508075688772},"98":{"tf":1.0},"99":{"tf":2.0}},"e":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"108":{"tf":1.0}}},"df":0,"docs":{}}}}},"i":{"df":0,"docs":{},"n":{"df":2,"docs":{"105":{"tf":1.0},"75":{"tf":1.0}}}},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"161":{"tf":1.0}}}},"df":0,"docs":{}}}},"g":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"50":{"tf":1.4142135623730951}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":5,"docs":{"110":{"tf":1.0},"133":{"tf":1.0},"174":{"tf":1.0},"18":{"tf":1.0},"81":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":20,"docs":{"101":{"tf":1.0},"104":{"tf":1.0},"138":{"tf":1.0},"166":{"tf":2.0},"176":{"tf":1.7320508075688772},"177":{"tf":2.0},"178":{"tf":2.0},"192":{"tf":1.0},"193":{"tf":2.449489742783178},"194":{"tf":2.23606797749979},"195":{"tf":2.6457513110645907},"197":{"tf":1.0},"199":{"tf":1.4142135623730951},"216":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":1.4142135623730951},"82":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":1.7320508075688772},"99":{"tf":1.4142135623730951}},"s":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"94":{"tf":1.0}}}}}}}}},"df":0,"docs":{}},"’":{"df":1,"docs":{"199":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":5,"docs":{"103":{"tf":1.4142135623730951},"13":{"tf":1.0},"174":{"tf":1.7320508075688772},"219":{"tf":1.4142135623730951},"74":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":3,"docs":{"82":{"tf":1.4142135623730951},"91":{"tf":1.0},"92":{"tf":2.0}}}}}},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"52":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":3,"docs":{"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0}}}}}}}}}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}}},"l":{"a":{"df":0,"docs":{},"t":{"df":4,"docs":{"24":{"tf":1.0},"40":{"tf":1.4142135623730951},"49":{"tf":1.4142135623730951},"82":{"tf":1.0}}},"x":{"df":1,"docs":{"78":{"tf":1.0}}}},"df":1,"docs":{"18":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"s":{"df":4,"docs":{"236":{"tf":1.7320508075688772},"68":{"tf":1.4142135623730951},"7":{"tf":1.7320508075688772},"71":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"i":{"df":3,"docs":{"200":{"tf":1.0},"236":{"tf":1.0},"66":{"tf":1.0}}},"o":{"c":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"218":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"146":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"23":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":1,"docs":{"23":{"tf":1.7320508075688772}}}},"o":{"df":0,"docs":{},"v":{"df":4,"docs":{"219":{"tf":1.0},"223":{"tf":1.0},"49":{"tf":1.0},"82":{"tf":1.0}}}}},"n":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"135":{"tf":1.0},"167":{"tf":1.0},"179":{"tf":1.0},"97":{"tf":1.0},"99":{"tf":1.0}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"106":{"tf":1.0},"147":{"tf":1.0},"175":{"tf":1.0},"98":{"tf":1.0}}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"99":{"tf":1.0}}}}}},"l":{"a":{"c":{"df":6,"docs":{"234":{"tf":1.7320508075688772},"75":{"tf":1.0},"83":{"tf":1.0},"85":{"tf":1.0},"86":{"tf":1.0},"91":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"df":1,"docs":{"90":{"tf":1.0}},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"224":{"tf":1.0}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"54":{"tf":1.0},"63":{"tf":1.0}}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":1,"docs":{"52":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"66":{"tf":1.0},"67":{"tf":1.0},"73":{"tf":1.0}}}}}}},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":2,"docs":{"68":{"tf":2.0},"89":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"q":{"df":0,"docs":{},"u":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":4,"docs":{"18":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.7320508075688772},"63":{"tf":1.7320508075688772}}}}},"i":{"df":0,"docs":{},"r":{"df":13,"docs":{"18":{"tf":1.0},"218":{"tf":1.0},"219":{"tf":1.0},"221":{"tf":1.0},"226":{"tf":1.0},"53":{"tf":1.0},"54":{"tf":1.0},"6":{"tf":1.0},"64":{"tf":1.0},"65":{"tf":1.0},"71":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":1,"docs":{"90":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{".":{"df":0,"docs":{},"j":{"df":1,"docs":{"225":{"tf":1.0}}}},"_":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"_":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"b":{"df":1,"docs":{"94":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"94":{"tf":1.0}}}},"df":0,"docs":{}}},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"94":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"=":{"1":{"df":3,"docs":{"73":{"tf":1.0},"89":{"tf":1.0},"94":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"94":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}}}}},"df":57,"docs":{"10":{"tf":1.7320508075688772},"11":{"tf":2.0},"12":{"tf":1.4142135623730951},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":2.23606797749979},"19":{"tf":1.4142135623730951},"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":1.4142135623730951},"226":{"tf":1.0},"23":{"tf":1.7320508075688772},"232":{"tf":1.0},"234":{"tf":1.7320508075688772},"236":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.4142135623730951},"27":{"tf":1.7320508075688772},"28":{"tf":1.0},"29":{"tf":1.4142135623730951},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.4142135623730951},"33":{"tf":1.7320508075688772},"34":{"tf":1.0},"35":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0},"38":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":2.449489742783178},"40":{"tf":1.0},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.0},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":2.449489742783178},"50":{"tf":1.4142135623730951},"51":{"tf":1.0},"52":{"tf":1.0},"6":{"tf":1.4142135623730951},"61":{"tf":1.4142135623730951},"67":{"tf":2.0},"68":{"tf":1.4142135623730951},"7":{"tf":2.0},"71":{"tf":1.0},"8":{"tf":1.4142135623730951},"9":{"tf":1.0}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}},"v":{"df":6,"docs":{"170":{"tf":1.0},"171":{"tf":1.0},"173":{"tf":1.0},"18":{"tf":1.0},"186":{"tf":1.0},"191":{"tf":1.0}},"e":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"94":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"138":{"tf":1.0},"146":{"tf":1.0},"161":{"tf":1.0},"175":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"t":{"df":2,"docs":{"32":{"tf":1.0},"98":{"tf":1.0}},"r":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"233":{"tf":1.0},"41":{"tf":1.0},"46":{"tf":1.0}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"(":{"df":1,"docs":{"189":{"tf":1.4142135623730951}}},"df":113,"docs":{"103":{"tf":1.4142135623730951},"107":{"tf":1.4142135623730951},"108":{"tf":1.4142135623730951},"109":{"tf":1.7320508075688772},"110":{"tf":1.7320508075688772},"111":{"tf":1.7320508075688772},"112":{"tf":1.7320508075688772},"113":{"tf":1.4142135623730951},"114":{"tf":1.4142135623730951},"115":{"tf":1.7320508075688772},"116":{"tf":1.4142135623730951},"117":{"tf":2.23606797749979},"118":{"tf":1.4142135623730951},"119":{"tf":1.4142135623730951},"120":{"tf":1.4142135623730951},"121":{"tf":1.4142135623730951},"122":{"tf":1.7320508075688772},"123":{"tf":1.4142135623730951},"124":{"tf":1.4142135623730951},"125":{"tf":1.4142135623730951},"126":{"tf":1.4142135623730951},"127":{"tf":1.4142135623730951},"128":{"tf":1.7320508075688772},"129":{"tf":1.4142135623730951},"130":{"tf":1.4142135623730951},"131":{"tf":1.4142135623730951},"132":{"tf":1.4142135623730951},"133":{"tf":1.4142135623730951},"134":{"tf":1.4142135623730951},"135":{"tf":1.4142135623730951},"136":{"tf":1.4142135623730951},"137":{"tf":1.4142135623730951},"138":{"tf":1.4142135623730951},"139":{"tf":1.4142135623730951},"140":{"tf":1.4142135623730951},"141":{"tf":1.4142135623730951},"142":{"tf":1.4142135623730951},"143":{"tf":1.4142135623730951},"144":{"tf":1.4142135623730951},"145":{"tf":1.4142135623730951},"146":{"tf":1.4142135623730951},"147":{"tf":1.7320508075688772},"148":{"tf":1.4142135623730951},"149":{"tf":1.4142135623730951},"150":{"tf":1.4142135623730951},"151":{"tf":1.4142135623730951},"152":{"tf":1.4142135623730951},"153":{"tf":1.4142135623730951},"154":{"tf":1.4142135623730951},"155":{"tf":1.4142135623730951},"156":{"tf":1.7320508075688772},"157":{"tf":1.4142135623730951},"158":{"tf":1.4142135623730951},"159":{"tf":1.4142135623730951},"160":{"tf":1.4142135623730951},"161":{"tf":1.7320508075688772},"162":{"tf":1.4142135623730951},"163":{"tf":1.4142135623730951},"164":{"tf":1.4142135623730951},"165":{"tf":1.4142135623730951},"166":{"tf":1.7320508075688772},"167":{"tf":1.4142135623730951},"168":{"tf":1.4142135623730951},"169":{"tf":1.4142135623730951},"170":{"tf":1.4142135623730951},"171":{"tf":1.4142135623730951},"172":{"tf":1.4142135623730951},"173":{"tf":1.4142135623730951},"174":{"tf":1.4142135623730951},"176":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"178":{"tf":1.4142135623730951},"179":{"tf":1.4142135623730951},"180":{"tf":1.7320508075688772},"181":{"tf":1.4142135623730951},"183":{"tf":1.4142135623730951},"184":{"tf":1.4142135623730951},"185":{"tf":1.4142135623730951},"186":{"tf":1.4142135623730951},"187":{"tf":1.4142135623730951},"189":{"tf":1.4142135623730951},"190":{"tf":1.7320508075688772},"191":{"tf":1.4142135623730951},"193":{"tf":1.4142135623730951},"194":{"tf":1.4142135623730951},"195":{"tf":1.4142135623730951},"196":{"tf":1.4142135623730951},"197":{"tf":1.4142135623730951},"198":{"tf":1.4142135623730951},"199":{"tf":1.4142135623730951},"201":{"tf":2.0},"202":{"tf":1.7320508075688772},"203":{"tf":1.7320508075688772},"204":{"tf":1.7320508075688772},"205":{"tf":2.0},"206":{"tf":1.7320508075688772},"207":{"tf":1.4142135623730951},"209":{"tf":1.4142135623730951},"210":{"tf":1.4142135623730951},"211":{"tf":1.4142135623730951},"212":{"tf":1.4142135623730951},"213":{"tf":1.4142135623730951},"214":{"tf":1.4142135623730951},"215":{"tf":1.4142135623730951},"216":{"tf":1.4142135623730951},"223":{"tf":1.7320508075688772},"69":{"tf":1.0},"76":{"tf":1.0},"84":{"tf":1.0},"88":{"tf":1.4142135623730951},"92":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":1.0}}}}}},"t":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":4,"docs":{"201":{"tf":1.7320508075688772},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0}}}}}}}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":4,"docs":{"201":{"tf":1.7320508075688772},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0}}}}}}}}},"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"235":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.4142135623730951}}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"209":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"209":{"tf":1.0}}},"df":0,"docs":{}}},"_":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"198":{"tf":1.0}}}}},"df":0,"docs":{}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":2,"docs":{"100":{"tf":1.0},"185":{"tf":1.4142135623730951}}},"y":{"(":{"$":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"185":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"185":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":3,"docs":{"100":{"tf":1.0},"182":{"tf":1.0},"46":{"tf":1.0}},"s":{"df":2,"docs":{"100":{"tf":1.0},"161":{"tf":2.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":34,"docs":{"100":{"tf":1.0},"102":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"132":{"tf":1.0},"134":{"tf":1.4142135623730951},"159":{"tf":1.0},"161":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"174":{"tf":2.0},"185":{"tf":1.7320508075688772},"190":{"tf":1.0},"198":{"tf":2.23606797749979},"201":{"tf":1.7320508075688772},"208":{"tf":1.0},"209":{"tf":2.449489742783178},"210":{"tf":1.0},"211":{"tf":1.0},"35":{"tf":1.0},"38":{"tf":1.0},"41":{"tf":1.0},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.4142135623730951},"51":{"tf":2.449489742783178},"78":{"tf":1.7320508075688772},"82":{"tf":1.0},"87":{"tf":1.0},"93":{"tf":1.0}},"s":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"(":{"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"174":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}},"v":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"91":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"(":{"$":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"210":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"210":{"tf":1.0}}},"df":0,"docs":{}}},"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"201":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"98":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":20,"docs":{"100":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"175":{"tf":1.0},"185":{"tf":1.4142135623730951},"204":{"tf":1.4142135623730951},"208":{"tf":1.4142135623730951},"210":{"tf":2.449489742783178},"212":{"tf":1.0},"214":{"tf":1.4142135623730951},"215":{"tf":1.4142135623730951},"216":{"tf":1.4142135623730951},"46":{"tf":1.4142135623730951},"57":{"tf":1.0},"75":{"tf":1.4142135623730951},"79":{"tf":1.0},"86":{"tf":2.449489742783178},"87":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"65":{"tf":1.0}}}},"v":{"df":40,"docs":{"0":{"tf":1.7320508075688772},"10":{"tf":1.0},"180":{"tf":1.0},"217":{"tf":2.23606797749979},"218":{"tf":1.0},"219":{"tf":1.4142135623730951},"220":{"tf":2.6457513110645907},"221":{"tf":1.0},"223":{"tf":2.8284271247461903},"224":{"tf":1.7320508075688772},"226":{"tf":1.7320508075688772},"235":{"tf":1.4142135623730951},"24":{"tf":1.0},"3":{"tf":1.0},"34":{"tf":1.0},"37":{"tf":1.0},"40":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":2.23606797749979},"46":{"tf":1.0},"5":{"tf":2.23606797749979},"50":{"tf":1.0},"52":{"tf":1.0},"53":{"tf":2.23606797749979},"54":{"tf":2.0},"55":{"tf":1.7320508075688772},"56":{"tf":1.4142135623730951},"57":{"tf":1.4142135623730951},"58":{"tf":1.0},"59":{"tf":1.0},"6":{"tf":1.0},"62":{"tf":1.4142135623730951},"65":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":2.449489742783178},"71":{"tf":1.0},"89":{"tf":1.0},"9":{"tf":1.7320508075688772}},"e":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"=":{"$":{"df":0,"docs":{},"{":{"df":0,"docs":{},"p":{"df":0,"docs":{},"w":{"d":{"df":0,"docs":{},"}":{"/":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"226":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":1,"docs":{"226":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"235":{"tf":1.0}}}}}}},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"91":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"235":{"tf":1.0},"76":{"tf":1.0}}}}}}},"h":{"df":22,"docs":{"109":{"tf":1.7320508075688772},"110":{"tf":1.7320508075688772},"111":{"tf":1.7320508075688772},"112":{"tf":1.4142135623730951},"113":{"tf":1.4142135623730951},"114":{"tf":1.4142135623730951},"115":{"tf":1.4142135623730951},"116":{"tf":2.0},"117":{"tf":1.4142135623730951},"118":{"tf":1.4142135623730951},"119":{"tf":1.4142135623730951},"120":{"tf":1.4142135623730951},"121":{"tf":1.4142135623730951},"122":{"tf":1.4142135623730951},"123":{"tf":1.7320508075688772},"124":{"tf":1.7320508075688772},"125":{"tf":1.4142135623730951},"126":{"tf":1.4142135623730951},"127":{"tf":1.7320508075688772},"128":{"tf":1.4142135623730951},"129":{"tf":1.4142135623730951},"99":{"tf":1.0}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":8,"docs":{"106":{"tf":1.0},"108":{"tf":1.0},"117":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.4142135623730951},"180":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.4142135623730951}}}}},"s":{"c":{"df":8,"docs":{"176":{"tf":1.0},"219":{"tf":1.4142135623730951},"52":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"a":{"d":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"p":{"df":3,"docs":{"235":{"tf":1.7320508075688772},"236":{"tf":2.0},"52":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"99":{"tf":1.0}}},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"49":{"tf":1.4142135623730951}}}}}},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"223":{"tf":1.0}}},"t":{"df":1,"docs":{"54":{"tf":1.0}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"236":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"90":{"tf":1.0},"91":{"tf":1.0}}}}}},"n":{"d":{"df":5,"docs":{"147":{"tf":1.0},"75":{"tf":1.4142135623730951},"78":{"tf":1.7320508075688772},"81":{"tf":1.0},"91":{"tf":1.0}}},"df":0,"docs":{}},"t":{"df":1,"docs":{"94":{"tf":1.0}}}},"w":{"df":1,"docs":{"98":{"tf":1.0}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":7,"docs":{"0":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"177":{"tf":1.0},"37":{"tf":1.7320508075688772},"61":{"tf":1.0},"63":{"tf":1.4142135623730951}}}},"n":{"df":18,"docs":{"0":{"tf":1.0},"108":{"tf":1.0},"193":{"tf":1.4142135623730951},"194":{"tf":1.0},"195":{"tf":1.7320508075688772},"221":{"tf":1.0},"225":{"tf":1.0},"232":{"tf":1.0},"3":{"tf":1.0},"51":{"tf":1.0},"53":{"tf":1.4142135623730951},"56":{"tf":1.0},"61":{"tf":1.4142135623730951},"62":{"tf":1.0},"75":{"tf":2.0},"78":{"tf":1.0},"90":{"tf":1.0},"94":{"tf":1.0}},"g":{"df":1,"docs":{"103":{"tf":1.4142135623730951}}},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":7,"docs":{"223":{"tf":2.449489742783178},"224":{"tf":1.4142135623730951},"53":{"tf":2.0},"54":{"tf":1.7320508075688772},"55":{"tf":1.0},"56":{"tf":1.4142135623730951},"57":{"tf":1.4142135623730951}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":16,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"186":{"tf":1.0},"217":{"tf":1.7320508075688772},"218":{"tf":1.0},"219":{"tf":1.0},"220":{"tf":2.0},"223":{"tf":1.0},"224":{"tf":1.0},"35":{"tf":2.23606797749979},"40":{"tf":1.0},"43":{"tf":1.4142135623730951},"53":{"tf":1.0},"55":{"tf":1.4142135623730951},"79":{"tf":1.0}},"e":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"57":{"tf":1.7320508075688772}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":1,"docs":{"57":{"tf":2.449489742783178}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"s":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"=":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"=":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":1,"docs":{"55":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"=":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":2,"docs":{"55":{"tf":1.0},"57":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}}},"df":1,"docs":{"55":{"tf":1.0}}}}}},"df":8,"docs":{"227":{"tf":1.4142135623730951},"235":{"tf":1.0},"52":{"tf":3.1622776601683795},"54":{"tf":1.0},"62":{"tf":1.7320508075688772},"64":{"tf":1.0},"71":{"tf":1.0},"97":{"tf":1.0}}}}},"v":{"6":{"4":{"df":0,"docs":{},"e":{"df":1,"docs":{"103":{"tf":1.0}},"m":{"a":{"c":{"b":{"df":1,"docs":{"71":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"x":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"81":{"tf":1.0},"82":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":4,"docs":{"105":{"tf":1.0},"236":{"tf":1.0},"52":{"tf":1.0},"91":{"tf":1.0}}}},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"206":{"tf":2.0}}}},"m":{"df":0,"docs":{},"e":{"df":26,"docs":{"107":{"tf":1.0},"108":{"tf":1.0},"122":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.4142135623730951},"174":{"tf":1.0},"177":{"tf":2.0},"18":{"tf":1.4142135623730951},"182":{"tf":1.0},"193":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":2.0},"204":{"tf":1.0},"206":{"tf":1.4142135623730951},"219":{"tf":1.0},"224":{"tf":1.0},"231":{"tf":1.0},"52":{"tf":1.0},"64":{"tf":1.0},"68":{"tf":1.0},"80":{"tf":1.0},"82":{"tf":1.0},"89":{"tf":1.0},"90":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}}},"n":{"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"x":{"df":7,"docs":{"219":{"tf":1.0},"223":{"tf":1.0},"53":{"tf":1.7320508075688772},"54":{"tf":1.0},"55":{"tf":1.0},"56":{"tf":1.0},"57":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"122":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"122":{"tf":1.0}}}}}}},"v":{"0":{"df":1,"docs":{"122":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"122":{"tf":1.4142135623730951}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"122":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":2,"docs":{"43":{"tf":1.0},"87":{"tf":1.0}}}}},"b":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":2,"docs":{"81":{"tf":1.0},"92":{"tf":1.4142135623730951}}}}},"c":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"d":{"df":2,"docs":{"90":{"tf":1.0},"91":{"tf":1.0}}},"df":0,"docs":{}}}}},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"235":{"tf":1.4142135623730951}}}}},"c":{"df":2,"docs":{"75":{"tf":1.0},"95":{"tf":1.0}}},"df":0,"docs":{},"f":{"df":1,"docs":{"76":{"tf":1.0}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":4,"docs":{"192":{"tf":1.4142135623730951},"199":{"tf":1.4142135623730951},"91":{"tf":1.0},"95":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"h":{"df":9,"docs":{"101":{"tf":1.0},"105":{"tf":1.7320508075688772},"138":{"tf":1.0},"166":{"tf":1.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.0},"216":{"tf":1.4142135623730951},"76":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":4,"docs":{"226":{"tf":1.0},"52":{"tf":1.0},"71":{"tf":1.0},"90":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":1,"docs":{"194":{"tf":1.7320508075688772}}}}}}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"113":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"113":{"tf":1.0}}},"df":0,"docs":{}},"x":{"df":1,"docs":{"113":{"tf":1.0}}}},"df":2,"docs":{"100":{"tf":1.0},"113":{"tf":1.4142135623730951}}}},"k":{"df":1,"docs":{"52":{"tf":1.4142135623730951}}}},"df":1,"docs":{"12":{"tf":1.0}},"e":{"a":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"(":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"57":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"m":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"52":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"43":{"tf":1.0}}}}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":7,"docs":{"130":{"tf":1.0},"131":{"tf":1.0},"139":{"tf":1.0},"149":{"tf":1.0},"215":{"tf":1.0},"236":{"tf":1.0},"32":{"tf":1.0}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":8,"docs":{"0":{"tf":1.0},"101":{"tf":1.0},"106":{"tf":1.0},"129":{"tf":1.0},"175":{"tf":1.0},"188":{"tf":1.0},"34":{"tf":1.4142135623730951},"99":{"tf":1.4142135623730951}}}}}},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"219":{"tf":1.0}}},"df":21,"docs":{"102":{"tf":1.4142135623730951},"108":{"tf":1.0},"11":{"tf":1.0},"129":{"tf":1.0},"139":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"161":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"189":{"tf":1.0},"22":{"tf":1.0},"230":{"tf":1.0},"231":{"tf":1.0},"40":{"tf":1.0},"52":{"tf":1.0},"54":{"tf":1.0},"69":{"tf":1.0},"76":{"tf":1.0}}},"g":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"104":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"186":{"tf":1.7320508075688772}}}}}}},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"176":{"tf":1.0},"31":{"tf":1.0},"33":{"tf":2.23606797749979},"78":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":8,"docs":{"193":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":2.0},"33":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951},"85":{"tf":1.0},"86":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{}},"f":{"b":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"100":{"tf":1.0},"157":{"tf":2.0},"165":{"tf":1.0}}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"(":{"$":{"a":{"d":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"213":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"213":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"208":{"tf":1.0},"213":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}}}}}},"df":1,"docs":{"97":{"tf":1.0}}}},"m":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":14,"docs":{"0":{"tf":1.0},"166":{"tf":1.0},"176":{"tf":1.0},"178":{"tf":1.0},"222":{"tf":1.0},"223":{"tf":1.0},"64":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.0},"74":{"tf":1.4142135623730951},"76":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.0},"98":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"203":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}}},"t":{"df":1,"docs":{"224":{"tf":1.0}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":5,"docs":{"104":{"tf":1.0},"129":{"tf":1.0},"166":{"tf":1.0},"215":{"tf":1.0},"76":{"tf":1.0}}}},"df":0,"docs":{}},"q":{"df":0,"docs":{},"u":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":6,"docs":{"181":{"tf":1.0},"75":{"tf":1.4142135623730951},"78":{"tf":1.0},"83":{"tf":1.0},"86":{"tf":1.0},"95":{"tf":1.0}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"v":{"df":1,"docs":{"132":{"tf":1.0}}}},"t":{"df":14,"docs":{"12":{"tf":1.0},"167":{"tf":1.0},"179":{"tf":1.0},"18":{"tf":1.0},"223":{"tf":1.4142135623730951},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"32":{"tf":1.4142135623730951},"33":{"tf":1.0},"70":{"tf":1.0},"89":{"tf":1.0},"94":{"tf":2.0}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"(":{"\\"":{"<":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"191":{"tf":1.0}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"n":{"df":1,"docs":{"191":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":3,"docs":{"100":{"tf":1.0},"172":{"tf":1.0},"191":{"tf":1.4142135623730951}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":1,"docs":{"30":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"28":{"tf":1.7320508075688772}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"29":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"31":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}}}}}}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{".":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"26":{"tf":1.4142135623730951}}}}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":1,"docs":{"27":{"tf":1.0}}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"s":{"df":1,"docs":{"27":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":1,"docs":{"27":{"tf":1.4142135623730951}}}}}}}},"df":0,"docs":{}}}}}}}},"df":1,"docs":{"25":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"102":{"tf":1.0},"103":{"tf":1.0}}},"r":{"df":3,"docs":{"189":{"tf":1.0},"82":{"tf":1.0},"91":{"tf":1.4142135623730951}}}}},"x":{"df":0,"docs":{},"t":{"<":{"df":0,"docs":{},"i":{"2":{"5":{"6":{">":{"(":{"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"137":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"<":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":3,"docs":{"100":{"tf":1.0},"129":{"tf":1.0},"137":{"tf":1.4142135623730951}},"s":{">":{">":{"(":{"$":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"137":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"t":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"126":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"126":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"126":{"tf":1.4142135623730951}}}},"h":{"a":{"1":{"df":2,"docs":{"89":{"tf":1.0},"90":{"tf":1.0}}},"df":1,"docs":{"90":{"tf":1.0}},"p":{"df":0,"docs":{},"e":{"df":9,"docs":{"122":{"tf":1.0},"177":{"tf":1.0},"182":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"206":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":5,"docs":{"67":{"tf":1.4142135623730951},"85":{"tf":1.0},"86":{"tf":1.4142135623730951},"87":{"tf":1.0},"92":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":4,"docs":{"120":{"tf":2.6457513110645907},"121":{"tf":2.23606797749979},"122":{"tf":2.6457513110645907},"216":{"tf":1.4142135623730951}}}}},"l":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"120":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"120":{"tf":1.0}}}}}}},"v":{"0":{"df":1,"docs":{"120":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"120":{"tf":1.4142135623730951},"75":{"tf":1.0}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}},"df":3,"docs":{"180":{"tf":1.0},"219":{"tf":1.0},"98":{"tf":1.0}}}},"w":{"df":3,"docs":{"219":{"tf":1.0},"65":{"tf":1.0},"98":{"tf":1.4142135623730951}},"n":{"df":1,"docs":{"215":{"tf":1.0}}}}},"r":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"121":{"tf":1.0}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":1,"docs":{"121":{"tf":1.0}}}}}}},"v":{"0":{"df":1,"docs":{"121":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"121":{"tf":1.4142135623730951},"122":{"tf":1.0}}}},"i":{"d":{"df":0,"docs":{},"e":{"b":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"97":{"tf":1.0}}}},"df":0,"docs":{}},"df":11,"docs":{"106":{"tf":1.4142135623730951},"108":{"tf":1.0},"147":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"177":{"tf":1.0},"188":{"tf":1.4142135623730951},"189":{"tf":1.0},"76":{"tf":1.0},"81":{"tf":1.7320508075688772},"98":{"tf":1.0}},"’":{"df":1,"docs":{"189":{"tf":1.0}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":2,"docs":{"167":{"tf":1.0},"179":{"tf":1.0}}}}}},"df":8,"docs":{"113":{"tf":1.7320508075688772},"115":{"tf":2.0},"122":{"tf":1.7320508075688772},"125":{"tf":1.7320508075688772},"126":{"tf":1.7320508075688772},"129":{"tf":2.23606797749979},"137":{"tf":1.7320508075688772},"65":{"tf":1.0}},"e":{"d":{"df":1,"docs":{"127":{"tf":1.0}}},"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"129":{"tf":1.0}}}}},"b":{"df":1,"docs":{"129":{"tf":1.0}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"129":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"129":{"tf":1.4142135623730951},"137":{"tf":1.0}}},"df":0,"docs":{}}}}}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"235":{"tf":1.0},"236":{"tf":1.0}}}}}}},"df":4,"docs":{"128":{"tf":1.4142135623730951},"129":{"tf":1.0},"235":{"tf":1.0},"86":{"tf":1.0}}},"df":0,"docs":{}}}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":4,"docs":{"18":{"tf":1.0},"219":{"tf":1.0},"33":{"tf":1.0},"70":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"234":{"tf":1.0}}}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"l":{"df":5,"docs":{"18":{"tf":1.0},"221":{"tf":1.0},"223":{"tf":1.0},"69":{"tf":1.0},"93":{"tf":1.4142135623730951}},"i":{"df":1,"docs":{"223":{"tf":1.0}},"f":{"df":4,"docs":{"108":{"tf":1.0},"175":{"tf":1.0},"91":{"tf":1.0},"93":{"tf":1.4142135623730951}},"i":{"df":11,"docs":{"106":{"tf":1.0},"108":{"tf":1.4142135623730951},"146":{"tf":1.0},"147":{"tf":1.0},"174":{"tf":1.0},"18":{"tf":1.0},"223":{"tf":1.0},"75":{"tf":2.449489742783178},"76":{"tf":1.0},"86":{"tf":1.0},"98":{"tf":1.0}}},"y":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"104":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":16,"docs":{"128":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.4142135623730951},"169":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"208":{"tf":1.0},"214":{"tf":1.0},"219":{"tf":1.0},"235":{"tf":1.0},"29":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.4142135623730951},"53":{"tf":1.0},"81":{"tf":1.4142135623730951},"85":{"tf":1.0}}}}},"t":{"df":2,"docs":{"219":{"tf":1.0},"74":{"tf":1.0}},"e":{"df":6,"docs":{"185":{"tf":1.0},"195":{"tf":1.0},"208":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":1.4142135623730951},"87":{"tf":1.0}}}},"x":{"df":1,"docs":{"175":{"tf":1.0}}},"z":{"df":0,"docs":{},"e":{"df":22,"docs":{"0":{"tf":1.4142135623730951},"12":{"tf":1.7320508075688772},"13":{"tf":2.6457513110645907},"14":{"tf":2.6457513110645907},"162":{"tf":1.0},"163":{"tf":1.0},"166":{"tf":1.0},"171":{"tf":1.0},"233":{"tf":1.7320508075688772},"236":{"tf":1.0},"27":{"tf":2.0},"35":{"tf":1.4142135623730951},"39":{"tf":1.7320508075688772},"40":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"70":{"tf":1.4142135623730951},"74":{"tf":1.0},"81":{"tf":1.0},"93":{"tf":1.4142135623730951}}}}},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":4,"docs":{"111":{"tf":1.0},"197":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"(":{"$":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"167":{"tf":1.0}}}}}},"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"(":{"0":{"df":1,"docs":{"169":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"v":{"0":{"df":1,"docs":{"167":{"tf":1.0}}},"3":{"df":1,"docs":{"167":{"tf":1.0}}},"df":0,"docs":{}}},"df":6,"docs":{"100":{"tf":1.0},"167":{"tf":1.4142135623730951},"169":{"tf":1.0},"75":{"tf":1.0},"84":{"tf":1.0},"95":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{},"p":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}},"t":{"df":19,"docs":{"104":{"tf":1.0},"105":{"tf":1.4142135623730951},"167":{"tf":2.449489742783178},"168":{"tf":1.4142135623730951},"169":{"tf":2.449489742783178},"178":{"tf":1.0},"179":{"tf":2.6457513110645907},"180":{"tf":1.7320508075688772},"181":{"tf":2.6457513110645907},"76":{"tf":1.0},"81":{"tf":1.0},"82":{"tf":2.0},"83":{"tf":1.0},"84":{"tf":1.4142135623730951},"85":{"tf":1.0},"87":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":1.4142135623730951},"99":{"tf":1.0}}},"w":{"df":1,"docs":{"219":{"tf":1.7320508075688772}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"219":{"tf":1.0}}}}}},"t":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"125":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"125":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"125":{"tf":1.4142135623730951}}}},"m":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":8,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"181":{"tf":1.0},"50":{"tf":1.0},"52":{"tf":1.0},"82":{"tf":1.0},"92":{"tf":1.0},"94":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"129":{"tf":1.0},"75":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"219":{"tf":1.0},"4":{"tf":1.0},"66":{"tf":1.0}}}}},"df":0,"docs":{},"o":{"d":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"115":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"115":{"tf":1.0}}},"df":0,"docs":{}},"x":{"df":1,"docs":{"115":{"tf":1.0}}}},"df":2,"docs":{"100":{"tf":1.0},"115":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"n":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"90":{"tf":1.4142135623730951}}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"98":{"tf":1.0}}}}}}}},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":4,"docs":{"52":{"tf":1.0},"59":{"tf":1.0},"65":{"tf":1.0},"78":{"tf":1.0}}}},"df":0,"docs":{}}}},"l":{"c":{"df":21,"docs":{"11":{"tf":1.0},"15":{"tf":2.23606797749979},"18":{"tf":2.23606797749979},"222":{"tf":1.0},"223":{"tf":1.0},"229":{"tf":1.0},"232":{"tf":1.0},"234":{"tf":1.7320508075688772},"236":{"tf":1.0},"24":{"tf":1.0},"33":{"tf":1.0},"39":{"tf":1.0},"50":{"tf":2.0},"6":{"tf":1.0},"66":{"tf":1.4142135623730951},"67":{"tf":1.0},"68":{"tf":1.4142135623730951},"72":{"tf":1.4142135623730951},"73":{"tf":1.0},"74":{"tf":1.0},"8":{"tf":1.7320508075688772}}},"df":0,"docs":{},"e":{"df":1,"docs":{"65":{"tf":1.0}}},"i":{"d":{"df":40,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.4142135623730951},"169":{"tf":1.0},"18":{"tf":2.23606797749979},"181":{"tf":1.0},"202":{"tf":1.0},"208":{"tf":1.0},"21":{"tf":1.7320508075688772},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"22":{"tf":1.0},"222":{"tf":2.0},"223":{"tf":1.7320508075688772},"229":{"tf":1.0},"232":{"tf":1.4142135623730951},"235":{"tf":2.0},"236":{"tf":1.4142135623730951},"3":{"tf":1.0},"34":{"tf":1.4142135623730951},"36":{"tf":1.7320508075688772},"39":{"tf":1.0},"4":{"tf":2.0},"43":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.7320508075688772},"6":{"tf":1.7320508075688772},"60":{"tf":1.0},"65":{"tf":1.0},"66":{"tf":1.7320508075688772},"67":{"tf":1.4142135623730951},"72":{"tf":1.0},"74":{"tf":1.0},"79":{"tf":1.0},"8":{"tf":1.0},"81":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0},"85":{"tf":1.0},"86":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"y":{"df":0,"docs":{},"’":{"df":2,"docs":{"79":{"tf":1.0},"90":{"tf":1.0}}}}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"52":{"tf":1.0}}},"i":{"df":0,"docs":{},"m":{"df":4,"docs":{"53":{"tf":1.0},"55":{"tf":1.0},"62":{"tf":1.0},"92":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"106":{"tf":1.0},"219":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"n":{"d":{"df":2,"docs":{"82":{"tf":1.7320508075688772},"91":{"tf":1.0}}},"df":0,"docs":{}},"r":{"c":{"df":44,"docs":{"10":{"tf":1.4142135623730951},"107":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"135":{"tf":1.4142135623730951},"136":{"tf":1.0},"137":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"17":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.4142135623730951},"174":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.7320508075688772},"179":{"tf":1.0},"18":{"tf":1.0},"182":{"tf":1.4142135623730951},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.4142135623730951},"187":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.0},"201":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"216":{"tf":1.0},"221":{"tf":1.0},"226":{"tf":1.0},"236":{"tf":1.0},"33":{"tf":1.4142135623730951},"54":{"tf":1.0},"59":{"tf":1.0},"67":{"tf":1.4142135623730951},"80":{"tf":1.0},"98":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"a":{"c":{"df":0,"docs":{},"e":{"df":8,"docs":{"101":{"tf":1.0},"102":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"13":{"tf":1.4142135623730951},"138":{"tf":1.0},"74":{"tf":1.0},"76":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"df":2,"docs":{"223":{"tf":1.4142135623730951},"224":{"tf":1.4142135623730951}},"i":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"138":{"tf":1.0},"71":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":13,"docs":{"194":{"tf":1.0},"219":{"tf":1.0},"223":{"tf":1.4142135623730951},"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"32":{"tf":2.449489742783178},"33":{"tf":1.0},"52":{"tf":1.0},"71":{"tf":1.0},"73":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}},"i":{"df":4,"docs":{"137":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"30":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"d":{"df":3,"docs":{"1":{"tf":1.0},"219":{"tf":1.4142135623730951},"235":{"tf":1.0}}},"df":0,"docs":{}}}},"q":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"193":{"tf":1.0}}}},"df":0,"docs":{}}},"r":{"c":{"/":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"/":{"b":{"a":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{":":{"b":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"18":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"18":{"tf":1.0}}}}}},"df":1,"docs":{"178":{"tf":2.0}}},"df":0,"docs":{}},"s":{"a":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":12,"docs":{"106":{"tf":1.0},"108":{"tf":1.0},"188":{"tf":1.0},"189":{"tf":1.4142135623730951},"195":{"tf":1.7320508075688772},"214":{"tf":1.0},"215":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.4142135623730951},"99":{"tf":1.4142135623730951}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"(":{"$":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"179":{"tf":1.0}}}}}},"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"(":{"0":{"df":1,"docs":{"181":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"v":{"0":{"df":1,"docs":{"179":{"tf":1.0}}},"1":{"df":3,"docs":{"193":{"tf":1.0},"194":{"tf":1.4142135623730951},"195":{"tf":1.0}}},"2":{"df":1,"docs":{"179":{"tf":1.0}}},"3":{"df":1,"docs":{"199":{"tf":1.0}}},"df":0,"docs":{}}},"df":8,"docs":{"100":{"tf":1.0},"167":{"tf":1.0},"179":{"tf":1.4142135623730951},"180":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"75":{"tf":1.0},"84":{"tf":1.0},"95":{"tf":1.0}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":3,"docs":{"220":{"tf":1.0},"91":{"tf":1.0},"97":{"tf":1.0}}}},"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"13":{"tf":1.0}}}}}},"df":9,"docs":{"0":{"tf":1.0},"104":{"tf":1.4142135623730951},"13":{"tf":2.8284271247461903},"222":{"tf":1.0},"223":{"tf":1.0},"27":{"tf":1.4142135623730951},"72":{"tf":1.0},"74":{"tf":1.4142135623730951},"76":{"tf":1.0}}}},"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"223":{"tf":1.0}}}}},"r":{"d":{"df":17,"docs":{"201":{"tf":1.0},"203":{"tf":1.0},"24":{"tf":2.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"55":{"tf":1.0},"62":{"tf":1.0},"68":{"tf":1.0},"73":{"tf":1.0},"80":{"tf":1.0}}},"df":0,"docs":{}}},"df":1,"docs":{"99":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"51":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":11,"docs":{"138":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"195":{"tf":1.0},"229":{"tf":1.0},"58":{"tf":1.0},"60":{"tf":1.4142135623730951},"76":{"tf":1.0},"94":{"tf":1.0}},"u":{"df":0,"docs":{},"p":{"df":3,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"219":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":10,"docs":{"175":{"tf":1.0},"200":{"tf":1.0},"204":{"tf":1.4142135623730951},"210":{"tf":1.0},"219":{"tf":1.0},"223":{"tf":1.4142135623730951},"51":{"tf":1.7320508075688772},"56":{"tf":1.0},"68":{"tf":1.0},"93":{"tf":1.4142135623730951}},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{":":{":":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"199":{"tf":1.0}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"k":{"df":1,"docs":{"196":{"tf":1.0}}}},"df":0,"docs":{}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"187":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"183":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":1,"docs":{"197":{"tf":1.0}}}}}}}},"r":{"df":3,"docs":{"190":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0}}},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"216":{"tf":1.0}}}}}}}}}}}}}}}}}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"186":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"215":{"tf":1.0}}}}}}}}}}}}}}}}}},"x":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"190":{"tf":1.0}}}}}}},"t":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"184":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"l":{"c":{"a":{"df":0,"docs":{},"l":{"df":5,"docs":{"190":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"195":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"f":{"df":1,"docs":{"193":{"tf":1.0}}},"n":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"212":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"l":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"v":{"df":1,"docs":{"198":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":1,"docs":{"189":{"tf":1.0}}}},"o":{"df":0,"docs":{},"g":{"df":1,"docs":{"207":{"tf":1.0}}}}},"m":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"181":{"tf":1.0}}}}}}}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"178":{"tf":1.0}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"176":{"tf":1.0}},"e":{"8":{"df":1,"docs":{"177":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"p":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"214":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"185":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":1,"docs":{"209":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"210":{"tf":1.0}}}}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"213":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"191":{"tf":1.0}}}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"179":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"211":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"194":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"180":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"df":25,"docs":{"100":{"tf":1.0},"102":{"tf":1.0},"106":{"tf":1.0},"147":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"178":{"tf":1.0},"181":{"tf":1.4142135623730951},"188":{"tf":1.4142135623730951},"189":{"tf":1.7320508075688772},"190":{"tf":2.23606797749979},"192":{"tf":1.4142135623730951},"193":{"tf":1.4142135623730951},"194":{"tf":1.0},"195":{"tf":1.4142135623730951},"198":{"tf":1.0},"199":{"tf":1.0},"200":{"tf":1.0},"208":{"tf":1.0},"214":{"tf":1.0},"76":{"tf":1.4142135623730951},"93":{"tf":1.0},"95":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.4142135623730951}},"’":{"df":2,"docs":{"169":{"tf":1.0},"181":{"tf":1.0}}}}}}}},"i":{"c":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":4,"docs":{"167":{"tf":1.0},"169":{"tf":1.0},"179":{"tf":1.0},"181":{"tf":1.0}}}}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"100":{"tf":1.0},"204":{"tf":1.4142135623730951}},"l":{"(":{"$":{"df":0,"docs":{},"g":{"a":{"df":1,"docs":{"204":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"204":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":14,"docs":{"14":{"tf":1.0},"168":{"tf":1.0},"178":{"tf":1.0},"180":{"tf":1.0},"225":{"tf":1.0},"68":{"tf":1.0},"70":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.0},"80":{"tf":1.0},"93":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":1.4142135623730951},"99":{"tf":1.0}}},"df":0,"docs":{}}}},"d":{"df":1,"docs":{"18":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":1,"docs":{"94":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":3,"docs":{"223":{"tf":1.0},"67":{"tf":1.0},"75":{"tf":1.4142135623730951}}}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":3,"docs":{"18":{"tf":1.0},"204":{"tf":1.0},"213":{"tf":1.0}}}}},"o":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"p":{"df":3,"docs":{"100":{"tf":1.0},"208":{"tf":1.0},"211":{"tf":2.0}}},"r":{"a":{"df":0,"docs":{},"g":{"df":25,"docs":{"100":{"tf":1.4142135623730951},"104":{"tf":1.4142135623730951},"167":{"tf":1.4142135623730951},"168":{"tf":1.7320508075688772},"169":{"tf":1.4142135623730951},"175":{"tf":2.0},"178":{"tf":1.0},"179":{"tf":1.4142135623730951},"180":{"tf":1.7320508075688772},"181":{"tf":1.4142135623730951},"188":{"tf":1.0},"200":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"213":{"tf":1.0},"223":{"tf":1.0},"76":{"tf":1.7320508075688772},"83":{"tf":1.0},"84":{"tf":1.4142135623730951},"85":{"tf":1.0},"87":{"tf":1.4142135623730951},"90":{"tf":1.0},"92":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}},"e":{"a":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"78":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"’":{"df":1,"docs":{"180":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":15,"docs":{"104":{"tf":1.0},"105":{"tf":1.4142135623730951},"176":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951},"179":{"tf":1.0},"180":{"tf":1.4142135623730951},"181":{"tf":1.4142135623730951},"191":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.4142135623730951},"75":{"tf":1.0},"81":{"tf":1.7320508075688772},"82":{"tf":1.7320508075688772},"93":{"tf":1.0},"95":{"tf":1.0}}}}},"r":{"a":{"d":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"178":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"65":{"tf":1.0}},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":2,"docs":{"227":{"tf":1.0},"7":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":5,"docs":{"221":{"tf":2.0},"222":{"tf":1.0},"223":{"tf":1.0},"224":{"tf":1.7320508075688772},"78":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":3,"docs":{"52":{"tf":1.0},"75":{"tf":1.0},"95":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":9,"docs":{"170":{"tf":2.0},"171":{"tf":1.4142135623730951},"172":{"tf":1.4142135623730951},"173":{"tf":1.4142135623730951},"18":{"tf":1.0},"191":{"tf":1.7320508075688772},"215":{"tf":2.23606797749979},"64":{"tf":1.0},"99":{"tf":1.0}}}},"p":{"df":2,"docs":{"53":{"tf":1.0},"90":{"tf":1.0}}}},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"37":{"tf":1.0},"43":{"tf":1.0},"69":{"tf":1.0}}}}}}},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":10,"docs":{"100":{"tf":1.0},"18":{"tf":1.0},"192":{"tf":1.7320508075688772},"195":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.7320508075688772},"91":{"tf":1.4142135623730951},"93":{"tf":1.4142135623730951},"95":{"tf":1.0},"98":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}},"u":{"d":{"df":0,"docs":{},"i":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}},"y":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":2,"docs":{"64":{"tf":1.4142135623730951},"65":{"tf":1.0}}}}}},"u":{"b":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"110":{"tf":1.0}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"110":{"tf":1.0}}},"df":0,"docs":{}}},"df":5,"docs":{"100":{"tf":1.0},"110":{"tf":1.4142135623730951},"161":{"tf":1.0},"185":{"tf":1.0},"78":{"tf":1.0}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"63":{"tf":1.4142135623730951},"65":{"tf":1.0}}}}},"o":{"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":2,"docs":{"75":{"tf":1.4142135623730951},"91":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":1,"docs":{"179":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"18":{"tf":1.0}}}}}}}},"t":{"df":0,"docs":{},"l":{"df":1,"docs":{"81":{"tf":1.0}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"110":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":7,"docs":{"20":{"tf":1.0},"201":{"tf":1.7320508075688772},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0}},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"209":{"tf":1.0},"211":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"219":{"tf":1.0}}}}}}}},"df":0,"docs":{},"h":{"df":5,"docs":{"33":{"tf":1.4142135623730951},"52":{"tf":1.0},"64":{"tf":1.0},"85":{"tf":1.0},"98":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":3,"docs":{"18":{"tf":1.0},"65":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{},"x":{"df":5,"docs":{"107":{"tf":1.0},"174":{"tf":1.0},"207":{"tf":1.4142135623730951},"98":{"tf":1.0},"99":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"224":{"tf":1.0},"90":{"tf":1.0}}}},"m":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"98":{"tf":1.0}}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"49":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":4,"docs":{"18":{"tf":1.0},"37":{"tf":1.0},"39":{"tf":1.0},"43":{"tf":1.4142135623730951}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":20,"docs":{"18":{"tf":1.0},"21":{"tf":1.0},"226":{"tf":1.4142135623730951},"229":{"tf":2.0},"23":{"tf":1.0},"230":{"tf":1.7320508075688772},"231":{"tf":1.4142135623730951},"232":{"tf":1.7320508075688772},"28":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"4":{"tf":1.0},"40":{"tf":1.0},"42":{"tf":1.0},"52":{"tf":1.4142135623730951},"68":{"tf":1.0},"7":{"tf":1.0},"80":{"tf":1.0},"95":{"tf":1.0},"97":{"tf":1.0}}}},"s":{"df":2,"docs":{"18":{"tf":1.0},"57":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":9,"docs":{"105":{"tf":1.0},"107":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"179":{"tf":1.0},"81":{"tf":1.0},"99":{"tf":1.0}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.0}}},"f":{"a":{"c":{"df":3,"docs":{"169":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"92":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"147":{"tf":1.0}}},"df":0,"docs":{}}}}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"179":{"tf":1.0}}}}}}},"w":{"a":{"df":0,"docs":{},"p":{"df":10,"docs":{"104":{"tf":1.0},"105":{"tf":1.0},"176":{"tf":1.4142135623730951},"224":{"tf":1.0},"75":{"tf":1.0},"80":{"tf":2.23606797749979},"82":{"tf":1.0},"84":{"tf":1.0},"87":{"tf":1.0},"95":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"h":{"df":5,"docs":{"100":{"tf":1.0},"192":{"tf":1.0},"194":{"tf":2.23606797749979},"76":{"tf":1.0},"93":{"tf":1.0}}}},"df":0,"docs":{}}}},"y":{"df":1,"docs":{"71":{"tf":1.0}},"m":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":2,"docs":{"18":{"tf":1.4142135623730951},"64":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"x":{"df":109,"docs":{"107":{"tf":1.4142135623730951},"108":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"159":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"170":{"tf":1.7320508075688772},"171":{"tf":1.7320508075688772},"172":{"tf":1.7320508075688772},"173":{"tf":1.7320508075688772},"174":{"tf":1.4142135623730951},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.7320508075688772},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.0},"199":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0},"209":{"tf":1.0},"210":{"tf":1.0},"211":{"tf":1.0},"212":{"tf":1.0},"213":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.7320508075688772},"216":{"tf":1.4142135623730951},"76":{"tf":1.0},"96":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.4142135623730951},"99":{"tf":1.7320508075688772}}}},"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":1,"docs":{"107":{"tf":1.0}}}}}}},"s":{"c":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"220":{"tf":1.0},"57":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"91":{"tf":1.0}}}},"df":3,"docs":{"101":{"tf":1.4142135623730951},"7":{"tf":1.0},"99":{"tf":1.0}}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"98":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":9,"docs":{"102":{"tf":1.0},"105":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"177":{"tf":1.4142135623730951},"178":{"tf":1.4142135623730951},"76":{"tf":1.0},"98":{"tf":1.4142135623730951},"99":{"tf":1.4142135623730951}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"75":{"tf":1.0}},"e":{"d":{"df":3,"docs":{"75":{"tf":1.0},"80":{"tf":1.0},"94":{"tf":1.0}}},"df":0,"docs":{}}}}},"k":{"df":0,"docs":{},"e":{"df":7,"docs":{"115":{"tf":1.0},"18":{"tf":1.0},"182":{"tf":1.0},"193":{"tf":1.0},"224":{"tf":1.0},"66":{"tf":1.0},"99":{"tf":1.0}},"n":{"df":3,"docs":{"108":{"tf":1.0},"174":{"tf":1.0},"193":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":17,"docs":{"1":{"tf":1.4142135623730951},"129":{"tf":1.0},"137":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"201":{"tf":1.4142135623730951},"217":{"tf":2.0},"218":{"tf":2.0},"219":{"tf":1.4142135623730951},"220":{"tf":1.4142135623730951},"222":{"tf":1.0},"225":{"tf":1.0},"226":{"tf":2.23606797749979},"4":{"tf":1.0},"68":{"tf":1.0},"71":{"tf":1.4142135623730951},"83":{"tf":1.0}}}}},"j":{"a":{"df":0,"docs":{},"n":{"df":2,"docs":{"75":{"tf":1.0},"95":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"52":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"105":{"tf":1.0}}}},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"99":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"66":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":12,"docs":{"100":{"tf":1.0},"208":{"tf":1.4142135623730951},"209":{"tf":1.4142135623730951},"210":{"tf":1.4142135623730951},"211":{"tf":1.4142135623730951},"212":{"tf":1.4142135623730951},"213":{"tf":1.4142135623730951},"214":{"tf":1.4142135623730951},"215":{"tf":1.4142135623730951},"216":{"tf":1.4142135623730951},"79":{"tf":1.0},"98":{"tf":1.0}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":1,"docs":{"35":{"tf":1.0}}}}}}}}},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"130":{"tf":1.0},"131":{"tf":1.0}}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":12,"docs":{"221":{"tf":3.0},"222":{"tf":1.0},"223":{"tf":3.7416573867739413},"224":{"tf":3.3166247903554},"226":{"tf":1.0},"51":{"tf":1.4142135623730951},"61":{"tf":1.4142135623730951},"63":{"tf":1.0},"82":{"tf":2.0},"89":{"tf":2.0},"91":{"tf":1.0},"94":{"tf":1.0}},"s":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"z":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"90":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"x":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"96":{"tf":1.0},"97":{"tf":1.0}}}},"df":0,"docs":{}}}}},"h":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"k":{"df":2,"docs":{"224":{"tf":1.0},"4":{"tf":1.0}}}}},"df":1,"docs":{"128":{"tf":1.0}},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"92":{"tf":1.0}}}},"n":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"193":{"tf":1.0}}}}}}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"35":{"tf":1.0},"40":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}}}},"’":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":5,"docs":{"11":{"tf":1.0},"18":{"tf":1.0},"5":{"tf":1.0},"62":{"tf":1.0},"64":{"tf":1.4142135623730951}}}},"r":{"d":{"df":2,"docs":{"20":{"tf":1.0},"64":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":3,"docs":{"101":{"tf":1.0},"11":{"tf":1.0},"18":{"tf":1.0}}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"82":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"a":{"d":{"df":2,"docs":{"193":{"tf":1.0},"194":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"df":6,"docs":{"102":{"tf":1.0},"181":{"tf":1.0},"192":{"tf":1.0},"208":{"tf":1.4142135623730951},"216":{"tf":1.0},"91":{"tf":1.0}}},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"93":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":14,"docs":{"129":{"tf":1.0},"190":{"tf":1.0},"194":{"tf":1.4142135623730951},"195":{"tf":1.0},"199":{"tf":1.0},"207":{"tf":1.0},"223":{"tf":1.0},"67":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.0},"81":{"tf":1.0},"91":{"tf":2.0},"93":{"tf":1.0},"94":{"tf":1.0}}}}}}},"u":{"df":5,"docs":{"18":{"tf":1.0},"224":{"tf":1.0},"32":{"tf":1.0},"40":{"tf":1.0},"43":{"tf":1.0}},"m":{"b":{"df":1,"docs":{"61":{"tf":1.0}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"109":{"tf":1.0},"111":{"tf":1.0},"121":{"tf":1.0}}}},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"117":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"52":{"tf":1.0}}}}}}},"m":{"df":0,"docs":{},"e":{"df":20,"docs":{"107":{"tf":1.0},"12":{"tf":1.7320508075688772},"138":{"tf":1.0},"169":{"tf":1.0},"176":{"tf":1.4142135623730951},"18":{"tf":3.0},"181":{"tf":1.0},"215":{"tf":1.4142135623730951},"216":{"tf":1.0},"219":{"tf":1.4142135623730951},"41":{"tf":1.0},"46":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"76":{"tf":1.0},"83":{"tf":1.4142135623730951},"86":{"tf":1.0},"99":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"236":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":2,"docs":{"100":{"tf":1.0},"149":{"tf":2.23606797749979}}}}},"df":0,"docs":{}}}}},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"224":{"tf":1.0}}}},"p":{"df":3,"docs":{"11":{"tf":1.0},"221":{"tf":1.0},"35":{"tf":1.0}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"(":{"$":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"168":{"tf":1.0}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"168":{"tf":1.0}}},"df":0,"docs":{}}},"df":2,"docs":{"100":{"tf":1.0},"168":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"p":{"/":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"_":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"b":{"_":{"<":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{">":{".":{"df":0,"docs":{},"p":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":1,"docs":{"94":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"94":{"tf":1.0}}}}}}}}},"y":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"94":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"_":{"<":{"df":0,"docs":{},"o":{"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{">":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":1,"docs":{"94":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}}},"o":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":1,"docs":{"75":{"tf":1.0}}}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"221":{"tf":1.0},"62":{"tf":1.0}}}}}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"99":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"l":{"df":10,"docs":{"18":{"tf":1.0},"20":{"tf":2.0},"21":{"tf":1.0},"22":{"tf":1.0},"221":{"tf":1.0},"223":{"tf":1.4142135623730951},"23":{"tf":1.0},"233":{"tf":1.4142135623730951},"52":{"tf":1.0},"65":{"tf":1.0}},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.7320508075688772}}}}}}},"p":{"df":1,"docs":{"105":{"tf":1.0}},"i":{"c":{"_":{"0":{"df":1,"docs":{"207":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"207":{"tf":2.23606797749979}}},"df":0,"docs":{}}},"t":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"13":{"tf":1.4142135623730951},"14":{"tf":1.0},"90":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"u":{"c":{"df":0,"docs":{},"h":{"df":3,"docs":{"105":{"tf":1.0},"147":{"tf":1.0},"82":{"tf":1.0}}}},"df":0,"docs":{}},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"113":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"r":{"a":{"c":{"df":0,"docs":{},"e":{"df":2,"docs":{"55":{"tf":2.23606797749979},"57":{"tf":3.0}}},"k":{"df":8,"docs":{"166":{"tf":1.0},"168":{"tf":1.0},"174":{"tf":1.0},"180":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"80":{"tf":1.4142135623730951},"95":{"tf":1.0}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"13":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"52":{"tf":1.0}}}}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"83":{"tf":1.0}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"81":{"tf":1.0}}},"t":{"df":1,"docs":{"69":{"tf":1.0}}}},"n":{"df":0,"docs":{},"s":{"a":{"c":{"df":0,"docs":{},"t":{"df":7,"docs":{"143":{"tf":1.0},"158":{"tf":1.0},"168":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.4142135623730951},"224":{"tf":1.0},"43":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"’":{"df":1,"docs":{"155":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"201":{"tf":1.4142135623730951},"205":{"tf":1.4142135623730951},"213":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"198":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"168":{"tf":1.7320508075688772},"175":{"tf":1.0},"180":{"tf":2.23606797749979}}}}},"t":{"df":2,"docs":{"111":{"tf":1.0},"174":{"tf":1.0}}}},"l":{"a":{"df":0,"docs":{},"t":{"df":17,"docs":{"107":{"tf":1.0},"134":{"tf":1.4142135623730951},"176":{"tf":1.0},"177":{"tf":1.0},"180":{"tf":1.0},"190":{"tf":1.0},"198":{"tf":1.0},"219":{"tf":1.0},"230":{"tf":1.0},"34":{"tf":1.0},"36":{"tf":1.0},"39":{"tf":1.0},"43":{"tf":1.0},"47":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.4142135623730951},"95":{"tf":1.0}},"e":{"_":{"df":0,"docs":{},"y":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"o":{"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"94":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"p":{"a":{"df":0,"docs":{},"r":{"df":3,"docs":{"75":{"tf":1.0},"78":{"tf":1.0},"95":{"tf":1.0}}}},"df":0,"docs":{}}}},"p":{"df":9,"docs":{"0":{"tf":1.0},"112":{"tf":1.4142135623730951},"185":{"tf":1.0},"208":{"tf":1.0},"212":{"tf":1.0},"39":{"tf":1.0},"40":{"tf":1.0},"82":{"tf":1.7320508075688772},"92":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":10,"docs":{"113":{"tf":1.4142135623730951},"115":{"tf":1.4142135623730951},"122":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"129":{"tf":1.0},"174":{"tf":1.0},"175":{"tf":1.0},"185":{"tf":1.0},"97":{"tf":1.0}}}},"df":0,"docs":{},"e":{"df":2,"docs":{"69":{"tf":1.0},"75":{"tf":1.0}}}},"i":{"df":2,"docs":{"62":{"tf":1.0},"64":{"tf":1.0}},"p":{"df":2,"docs":{"81":{"tf":1.0},"91":{"tf":1.0}}},"v":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"70":{"tf":1.0}}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"e":{"df":4,"docs":{"107":{"tf":1.0},"223":{"tf":1.4142135623730951},"235":{"tf":1.0},"82":{"tf":1.4142135623730951}}},"n":{"c":{"(":{"b":{",":{"df":0,"docs":{},"n":{"df":1,"docs":{"78":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"(":{"a":{",":{"b":{"df":1,"docs":{"78":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"a":{"df":0,"docs":{},"t":{"df":2,"docs":{"113":{"tf":1.0},"78":{"tf":1.0}},"e":{"<":{"df":0,"docs":{},"i":{"6":{"4":{">":{"(":{"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"135":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"8":{">":{"(":{"df":0,"docs":{},"v":{"1":{"df":1,"docs":{"135":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"<":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"100":{"tf":1.0},"135":{"tf":1.4142135623730951}},"s":{">":{">":{"(":{"$":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"135":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":1,"docs":{"81":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"(":{"$":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"180":{"tf":1.0}}}}}},"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"180":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"168":{"tf":1.0},"180":{"tf":2.0}}}}}}},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":3,"docs":{"75":{"tf":1.0},"91":{"tf":1.0},"95":{"tf":1.0}}}},"r":{"df":0,"docs":{},"n":{"df":2,"docs":{"219":{"tf":1.0},"91":{"tf":1.0}}}}},"w":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"111":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":16,"docs":{"103":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"200":{"tf":1.0},"207":{"tf":1.0},"208":{"tf":1.0},"214":{"tf":1.0},"43":{"tf":1.0},"50":{"tf":1.0},"6":{"tf":1.0},"74":{"tf":1.0},"79":{"tf":1.0},"81":{"tf":1.0},"83":{"tf":1.0},"95":{"tf":1.0},"97":{"tf":1.0}},"’":{"df":3,"docs":{"113":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"75":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}},"df":89,"docs":{"101":{"tf":1.7320508075688772},"102":{"tf":1.7320508075688772},"103":{"tf":1.4142135623730951},"107":{"tf":2.449489742783178},"108":{"tf":1.0},"109":{"tf":1.7320508075688772},"110":{"tf":1.7320508075688772},"111":{"tf":1.7320508075688772},"112":{"tf":1.7320508075688772},"113":{"tf":1.7320508075688772},"114":{"tf":1.7320508075688772},"115":{"tf":1.7320508075688772},"116":{"tf":1.7320508075688772},"117":{"tf":2.23606797749979},"118":{"tf":1.7320508075688772},"119":{"tf":1.7320508075688772},"120":{"tf":1.7320508075688772},"121":{"tf":1.7320508075688772},"122":{"tf":1.7320508075688772},"123":{"tf":1.7320508075688772},"124":{"tf":1.7320508075688772},"125":{"tf":1.7320508075688772},"126":{"tf":1.7320508075688772},"127":{"tf":1.7320508075688772},"128":{"tf":1.7320508075688772},"129":{"tf":1.7320508075688772},"130":{"tf":2.0},"131":{"tf":2.0},"132":{"tf":1.4142135623730951},"133":{"tf":1.4142135623730951},"134":{"tf":1.7320508075688772},"135":{"tf":1.4142135623730951},"136":{"tf":1.4142135623730951},"137":{"tf":1.4142135623730951},"138":{"tf":1.7320508075688772},"139":{"tf":1.7320508075688772},"140":{"tf":1.4142135623730951},"155":{"tf":1.4142135623730951},"156":{"tf":1.4142135623730951},"159":{"tf":1.4142135623730951},"163":{"tf":1.4142135623730951},"164":{"tf":1.4142135623730951},"165":{"tf":1.4142135623730951},"166":{"tf":1.4142135623730951},"167":{"tf":1.4142135623730951},"168":{"tf":1.4142135623730951},"169":{"tf":1.7320508075688772},"174":{"tf":2.449489742783178},"176":{"tf":1.7320508075688772},"177":{"tf":2.23606797749979},"178":{"tf":2.0},"179":{"tf":1.7320508075688772},"180":{"tf":1.7320508075688772},"181":{"tf":2.0},"183":{"tf":2.0},"184":{"tf":2.23606797749979},"185":{"tf":2.0},"186":{"tf":2.0},"187":{"tf":2.0},"189":{"tf":1.0},"190":{"tf":1.0},"191":{"tf":1.4142135623730951},"193":{"tf":1.7320508075688772},"194":{"tf":1.4142135623730951},"195":{"tf":1.0},"198":{"tf":1.7320508075688772},"201":{"tf":2.8284271247461903},"202":{"tf":2.6457513110645907},"203":{"tf":2.449489742783178},"204":{"tf":2.449489742783178},"205":{"tf":2.0},"206":{"tf":2.0},"207":{"tf":2.0},"209":{"tf":1.7320508075688772},"210":{"tf":1.7320508075688772},"213":{"tf":1.4142135623730951},"216":{"tf":1.0},"72":{"tf":1.0},"75":{"tf":1.4142135623730951},"76":{"tf":1.7320508075688772},"78":{"tf":2.0},"79":{"tf":1.0},"87":{"tf":1.0},"91":{"tf":1.7320508075688772},"93":{"tf":1.7320508075688772},"95":{"tf":1.0},"96":{"tf":1.0},"98":{"tf":2.449489742783178},"99":{"tf":2.449489742783178}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"93":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"i":{"c":{"df":8,"docs":{"103":{"tf":1.0},"108":{"tf":1.0},"177":{"tf":1.0},"181":{"tf":1.0},"186":{"tf":1.0},"190":{"tf":1.0},"219":{"tf":1.0},"86":{"tf":1.0}}},"df":0,"docs":{}}}}},"u":{"8":{"df":2,"docs":{"214":{"tf":1.4142135623730951},"215":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"51":{"tf":2.0}}}}},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"m":{"b":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"a":{"df":1,"docs":{"102":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"n":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":2,"docs":{"70":{"tf":1.0},"80":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"z":{"df":1,"docs":{"134":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":1,"docs":{"132":{"tf":1.0}}}}}}}},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"133":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}}},"c":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"193":{"tf":1.0}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"208":{"tf":1.0},"212":{"tf":1.0}}}}},"df":0,"docs":{}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"103":{"tf":1.0},"19":{"tf":1.0},"3":{"tf":1.0},"62":{"tf":1.0},"67":{"tf":1.0}},"f":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"110":{"tf":1.4142135623730951}}}}}},"l":{"df":0,"docs":{},"i":{"df":3,"docs":{"222":{"tf":1.0},"43":{"tf":1.0},"52":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"d":{"df":3,"docs":{"34":{"tf":1.0},"72":{"tf":1.0},"74":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"o":{"df":1,"docs":{"210":{"tf":1.0}}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"219":{"tf":1.0}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"235":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":1,"docs":{"23":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"224":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":2,"docs":{"102":{"tf":1.0},"221":{"tf":1.4142135623730951}},"i":{"df":1,"docs":{"56":{"tf":1.0}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"7":{"tf":1.0}}}}}},"x":{"df":1,"docs":{"149":{"tf":1.0}}}},"k":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"n":{"df":5,"docs":{"105":{"tf":1.0},"166":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.4142135623730951},"177":{"tf":1.4142135623730951}}}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"39":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"k":{"df":6,"docs":{"14":{"tf":1.0},"147":{"tf":1.0},"178":{"tf":1.0},"18":{"tf":1.0},"180":{"tf":1.0},"70":{"tf":1.0}}},"n":{"df":0,"docs":{},"k":{"df":1,"docs":{"18":{"tf":1.7320508075688772}}}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"r":{"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"212":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"l":{"df":1,"docs":{"81":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":4,"docs":{"112":{"tf":1.0},"114":{"tf":1.0},"123":{"tf":1.7320508075688772},"124":{"tf":1.7320508075688772}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"78":{"tf":1.0},"91":{"tf":1.0}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"63":{"tf":1.0}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"37":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"s":{"df":4,"docs":{"103":{"tf":1.0},"147":{"tf":1.0},"174":{"tf":1.0},"40":{"tf":1.0}}}},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"64":{"tf":1.0}}}},"df":0,"docs":{}}}},"p":{"d":{"a":{"df":0,"docs":{},"t":{"df":2,"docs":{"195":{"tf":1.0},"62":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"df":10,"docs":{"1":{"tf":1.0},"117":{"tf":1.0},"147":{"tf":1.0},"201":{"tf":1.0},"215":{"tf":1.0},"235":{"tf":1.0},"52":{"tf":1.0},"75":{"tf":1.7320508075688772},"78":{"tf":1.4142135623730951},"85":{"tf":1.0}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":6,"docs":{"103":{"tf":1.0},"110":{"tf":1.0},"129":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"177":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"m":{"df":3,"docs":{"63":{"tf":1.0},"71":{"tf":1.0},"98":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"s":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{},"g":{"df":4,"docs":{"11":{"tf":1.7320508075688772},"54":{"tf":1.7320508075688772},"57":{"tf":1.0},"70":{"tf":1.0}}}},"df":54,"docs":{"102":{"tf":1.0},"103":{"tf":1.0},"105":{"tf":1.0},"108":{"tf":1.0},"13":{"tf":1.7320508075688772},"14":{"tf":1.4142135623730951},"15":{"tf":1.0},"16":{"tf":1.0},"165":{"tf":1.0},"169":{"tf":1.0},"17":{"tf":1.0},"18":{"tf":2.0},"186":{"tf":1.0},"199":{"tf":1.0},"202":{"tf":1.0},"212":{"tf":1.0},"216":{"tf":1.0},"219":{"tf":1.0},"221":{"tf":1.0},"225":{"tf":1.0},"226":{"tf":1.0},"232":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"40":{"tf":1.4142135623730951},"43":{"tf":1.7320508075688772},"48":{"tf":1.4142135623730951},"49":{"tf":1.0},"5":{"tf":1.0},"52":{"tf":1.4142135623730951},"53":{"tf":1.0},"55":{"tf":1.0},"61":{"tf":1.7320508075688772},"64":{"tf":1.7320508075688772},"65":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"68":{"tf":1.0},"69":{"tf":1.4142135623730951},"70":{"tf":1.0},"71":{"tf":2.0},"75":{"tf":2.0},"78":{"tf":1.7320508075688772},"79":{"tf":1.0},"8":{"tf":1.0},"80":{"tf":2.449489742783178},"81":{"tf":1.4142135623730951},"82":{"tf":1.7320508075688772},"94":{"tf":1.4142135623730951},"97":{"tf":1.4142135623730951},"98":{"tf":1.0},"99":{"tf":1.4142135623730951}},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{":":{":":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"82":{"tf":1.0}}}}}}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"r":{"df":54,"docs":{"1":{"tf":1.0},"10":{"tf":1.0},"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"174":{"tf":1.0},"18":{"tf":1.0},"19":{"tf":1.0},"190":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"222":{"tf":1.0},"23":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"36":{"tf":1.0},"37":{"tf":1.0},"38":{"tf":1.0},"39":{"tf":1.0},"4":{"tf":1.7320508075688772},"40":{"tf":1.0},"41":{"tf":1.0},"42":{"tf":1.0},"43":{"tf":1.0},"44":{"tf":1.0},"45":{"tf":1.0},"46":{"tf":1.0},"47":{"tf":1.0},"48":{"tf":1.0},"49":{"tf":1.0},"5":{"tf":1.4142135623730951},"50":{"tf":1.0},"51":{"tf":1.0},"52":{"tf":1.4142135623730951},"6":{"tf":1.0},"7":{"tf":1.0},"70":{"tf":1.0},"8":{"tf":1.0},"9":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"108":{"tf":1.0},"18":{"tf":1.0},"43":{"tf":1.0},"53":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":2,"docs":{"223":{"tf":1.0},"224":{"tf":1.4142135623730951}}}}}},"v":{"0":{".":{"8":{".":{"0":{"df":1,"docs":{"236":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"4":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":38,"docs":{"107":{"tf":1.0},"120":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"141":{"tf":1.0},"142":{"tf":1.0},"143":{"tf":1.0},"144":{"tf":1.0},"145":{"tf":1.0},"146":{"tf":1.0},"147":{"tf":1.0},"148":{"tf":1.0},"149":{"tf":1.0},"150":{"tf":1.0},"151":{"tf":1.0},"152":{"tf":1.0},"153":{"tf":1.0},"154":{"tf":1.0},"157":{"tf":1.0},"158":{"tf":1.0},"160":{"tf":1.0},"161":{"tf":1.0},"162":{"tf":1.0},"170":{"tf":1.0},"171":{"tf":1.0},"172":{"tf":1.0},"173":{"tf":1.0},"189":{"tf":1.0},"191":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"196":{"tf":1.0},"197":{"tf":1.0},"198":{"tf":1.4142135623730951},"199":{"tf":1.7320508075688772},"216":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}},"1":{".":{"0":{".":{"0":{"df":1,"docs":{"236":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":72,"docs":{"107":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.4142135623730951},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.4142135623730951},"129":{"tf":1.4142135623730951},"130":{"tf":1.0},"131":{"tf":1.0},"132":{"tf":1.0},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.0},"137":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"140":{"tf":1.0},"155":{"tf":1.0},"156":{"tf":1.0},"159":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"168":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"178":{"tf":1.0},"179":{"tf":1.0},"180":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.4142135623730951},"190":{"tf":1.0},"193":{"tf":1.7320508075688772},"195":{"tf":1.4142135623730951},"198":{"tf":1.4142135623730951},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.4142135623730951},"209":{"tf":1.0},"210":{"tf":1.0},"216":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}},"2":{"df":50,"docs":{"107":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"111":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"120":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0},"123":{"tf":1.0},"124":{"tf":1.0},"125":{"tf":1.0},"126":{"tf":1.0},"127":{"tf":1.0},"128":{"tf":1.0},"129":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"135":{"tf":1.0},"138":{"tf":1.0},"139":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"169":{"tf":1.0},"174":{"tf":1.0},"178":{"tf":1.0},"181":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.0},"185":{"tf":1.0},"186":{"tf":1.0},"187":{"tf":1.0},"189":{"tf":1.0},"193":{"tf":1.7320508075688772},"194":{"tf":1.0},"195":{"tf":1.0},"199":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0}}},"3":{"df":18,"docs":{"108":{"tf":1.0},"117":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"179":{"tf":1.0},"184":{"tf":1.0},"189":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.4142135623730951},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"206":{"tf":1.0},"207":{"tf":1.0}}},"4":{"df":7,"docs":{"174":{"tf":1.0},"189":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"205":{"tf":1.0}}},"5":{"df":10,"docs":{"108":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"189":{"tf":1.0},"193":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0},"203":{"tf":1.0},"204":{"tf":1.0},"206":{"tf":1.0}}},"6":{"df":3,"docs":{"193":{"tf":1.0},"201":{"tf":1.0},"202":{"tf":1.0}}},"7":{"df":3,"docs":{"193":{"tf":1.4142135623730951},"203":{"tf":1.0},"204":{"tf":1.0}}},"8":{"df":2,"docs":{"201":{"tf":1.0},"202":{"tf":1.0}}},"<":{"df":0,"docs":{},"i":{"d":{"df":3,"docs":{"100":{"tf":1.0},"108":{"tf":2.0},"189":{"tf":1.0}}},"df":0,"docs":{}}},"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"95":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":11,"docs":{"12":{"tf":1.0},"156":{"tf":1.0},"169":{"tf":1.0},"181":{"tf":1.0},"219":{"tf":1.4142135623730951},"39":{"tf":1.0},"48":{"tf":1.0},"75":{"tf":1.4142135623730951},"79":{"tf":1.4142135623730951},"91":{"tf":1.0},"93":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"u":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"180":{"tf":1.0}}}},"df":0,"docs":{}},"df":66,"docs":{"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":1.7320508075688772},"104":{"tf":1.0},"106":{"tf":1.4142135623730951},"107":{"tf":1.4142135623730951},"108":{"tf":1.4142135623730951},"120":{"tf":1.7320508075688772},"121":{"tf":1.7320508075688772},"122":{"tf":2.23606797749979},"128":{"tf":1.0},"129":{"tf":1.7320508075688772},"13":{"tf":1.4142135623730951},"132":{"tf":1.0},"134":{"tf":1.4142135623730951},"135":{"tf":1.4142135623730951},"136":{"tf":1.4142135623730951},"137":{"tf":1.7320508075688772},"14":{"tf":1.4142135623730951},"142":{"tf":1.0},"151":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.0},"172":{"tf":1.0},"174":{"tf":1.4142135623730951},"176":{"tf":1.7320508075688772},"177":{"tf":2.0},"179":{"tf":1.7320508075688772},"180":{"tf":1.4142135623730951},"181":{"tf":2.23606797749979},"188":{"tf":1.0},"189":{"tf":2.449489742783178},"190":{"tf":1.7320508075688772},"191":{"tf":1.7320508075688772},"192":{"tf":1.4142135623730951},"193":{"tf":2.449489742783178},"194":{"tf":3.0},"195":{"tf":3.0},"196":{"tf":1.7320508075688772},"197":{"tf":1.7320508075688772},"198":{"tf":1.4142135623730951},"201":{"tf":1.7320508075688772},"202":{"tf":1.0},"203":{"tf":2.0},"204":{"tf":1.4142135623730951},"205":{"tf":1.4142135623730951},"207":{"tf":1.0},"216":{"tf":1.4142135623730951},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"29":{"tf":1.0},"39":{"tf":1.0},"45":{"tf":1.0},"47":{"tf":1.0},"75":{"tf":1.7320508075688772},"76":{"tf":2.23606797749979},"78":{"tf":1.7320508075688772},"79":{"tf":2.0},"81":{"tf":1.4142135623730951},"82":{"tf":1.0},"83":{"tf":1.0},"84":{"tf":1.0},"87":{"tf":1.0},"89":{"tf":1.4142135623730951},"98":{"tf":1.7320508075688772},"99":{"tf":2.449489742783178}},"e":{"_":{"0":{"df":1,"docs":{"198":{"tf":1.0}}},"1":{"df":1,"docs":{"198":{"tf":1.0}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"d":{"(":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":1,"docs":{"57":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}},"y":{"df":0,"docs":{},"p":{"df":1,"docs":{"107":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{},"’":{"df":3,"docs":{"108":{"tf":1.0},"78":{"tf":1.0},"99":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":16,"docs":{"100":{"tf":1.0},"116":{"tf":1.0},"13":{"tf":1.0},"172":{"tf":1.0},"191":{"tf":1.0},"195":{"tf":2.0},"196":{"tf":1.0},"197":{"tf":1.0},"226":{"tf":1.0},"51":{"tf":1.7320508075688772},"55":{"tf":1.0},"64":{"tf":1.0},"73":{"tf":1.0},"80":{"tf":1.4142135623730951},"93":{"tf":1.4142135623730951},"94":{"tf":2.23606797749979}},"e":{"_":{"0":{"df":1,"docs":{"195":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":11,"docs":{"102":{"tf":1.4142135623730951},"103":{"tf":1.0},"104":{"tf":1.0},"105":{"tf":1.0},"138":{"tf":1.0},"190":{"tf":1.4142135623730951},"208":{"tf":1.0},"219":{"tf":1.0},"93":{"tf":1.0},"97":{"tf":1.0},"98":{"tf":1.0}}}}},"df":2,"docs":{"12":{"tf":1.0},"40":{"tf":1.0}},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"223":{"tf":1.0}}}}}}},"df":11,"docs":{"106":{"tf":1.0},"108":{"tf":1.4142135623730951},"176":{"tf":1.0},"219":{"tf":1.4142135623730951},"52":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.0},"74":{"tf":1.0},"75":{"tf":1.0},"78":{"tf":1.0},"99":{"tf":1.0}},"e":{"c":{"<":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"215":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"195":{"tf":1.0}}}},"df":0,"docs":{}},"w":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"h":{"c":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"194":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":8,"docs":{"174":{"tf":1.0},"193":{"tf":1.0},"194":{"tf":1.0},"195":{"tf":1.0},"196":{"tf":1.0},"198":{"tf":1.0},"207":{"tf":1.0},"216":{"tf":1.0}},"e":{"df":0,"docs":{},"i":{"d":{"df":2,"docs":{"189":{"tf":1.0},"195":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"98":{"tf":1.0}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"98":{"tf":1.0},"99":{"tf":1.0}}}}}},"df":0,"docs":{},"r":{"b":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"99":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":2,"docs":{"219":{"tf":1.0},"223":{"tf":1.0}},"f":{"df":0,"docs":{},"i":{"df":3,"docs":{"52":{"tf":1.0},"82":{"tf":1.0},"93":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":8,"docs":{"155":{"tf":1.0},"229":{"tf":2.23606797749979},"23":{"tf":1.0},"232":{"tf":2.23606797749979},"61":{"tf":1.0},"68":{"tf":1.0},"78":{"tf":1.0},"81":{"tf":1.0}}}}}}}},"i":{"a":{"df":19,"docs":{"108":{"tf":1.0},"172":{"tf":1.0},"174":{"tf":1.4142135623730951},"191":{"tf":1.0},"194":{"tf":1.4142135623730951},"195":{"tf":1.0},"198":{"tf":1.0},"217":{"tf":1.0},"224":{"tf":1.0},"226":{"tf":1.7320508075688772},"50":{"tf":1.4142135623730951},"51":{"tf":1.0},"63":{"tf":1.0},"68":{"tf":1.4142135623730951},"7":{"tf":1.0},"70":{"tf":1.0},"71":{"tf":1.0},"79":{"tf":1.0},"82":{"tf":1.4142135623730951}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"51":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"51":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"195":{"tf":1.0},"199":{"tf":1.0}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"235":{"tf":1.7320508075688772},"236":{"tf":1.0}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"69":{"tf":1.0}}}},"df":1,"docs":{"69":{"tf":1.4142135623730951}}}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"67":{"tf":1.0}}}},"df":0,"docs":{}}}},"m":{"df":3,"docs":{"219":{"tf":1.4142135623730951},"43":{"tf":1.0},"52":{"tf":1.4142135623730951}}},"o":{"df":0,"docs":{},"i":{"d":{"df":2,"docs":{"102":{"tf":1.7320508075688772},"198":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"s":{"df":3,"docs":{"35":{"tf":1.4142135623730951},"5":{"tf":1.4142135623730951},"76":{"tf":1.0}}}},"w":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"97":{"tf":1.0}}}}}}}}}}},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"57":{"tf":1.0},"69":{"tf":1.0},"71":{"tf":1.0}}}},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"0":{"tf":1.0}}},"n":{"df":6,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"18":{"tf":1.0},"41":{"tf":1.0},"43":{"tf":1.0}}}},"s":{"df":0,"docs":{},"m":{"df":4,"docs":{"219":{"tf":2.8284271247461903},"225":{"tf":1.0},"226":{"tf":2.0},"7":{"tf":1.0}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"219":{"tf":1.4142135623730951}}}}}}},"y":{"df":4,"docs":{"194":{"tf":1.0},"221":{"tf":1.0},"227":{"tf":1.0},"32":{"tf":1.0}}}},"df":0,"docs":{},"e":{"b":{"3":{"df":1,"docs":{"235":{"tf":1.0}}},"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"219":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":1,"docs":{"235":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":5,"docs":{"142":{"tf":1.0},"157":{"tf":1.0},"165":{"tf":1.0},"201":{"tf":1.0},"205":{"tf":1.4142135623730951}},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"57":{"tf":2.449489742783178}}}}}},"l":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":4,"docs":{"0":{"tf":2.0},"1":{"tf":1.0},"2":{"tf":1.0},"3":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":7,"docs":{"1":{"tf":1.0},"223":{"tf":1.0},"34":{"tf":1.0},"75":{"tf":1.0},"92":{"tf":1.0},"93":{"tf":1.0},"95":{"tf":1.0}}}},"’":{"d":{"df":2,"docs":{"52":{"tf":1.0},"65":{"tf":1.0}}},"df":0,"docs":{}}},"h":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":5,"docs":{"167":{"tf":1.0},"179":{"tf":1.0},"62":{"tf":1.0},"82":{"tf":1.0},"94":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":1,"docs":{"32":{"tf":1.0}}},"df":0,"docs":{},"v":{"df":1,"docs":{"222":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"5":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":4,"docs":{"169":{"tf":1.0},"181":{"tf":1.0},"184":{"tf":1.0},"190":{"tf":1.4142135623730951}}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":1,"docs":{"135":{"tf":1.0}},"n":{"_":{"b":{"df":0,"docs":{},"y":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"(":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"x":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"109":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":11,"docs":{"136":{"tf":1.0},"138":{"tf":1.4142135623730951},"155":{"tf":1.0},"156":{"tf":1.0},"163":{"tf":1.0},"164":{"tf":1.0},"165":{"tf":1.0},"166":{"tf":1.0},"176":{"tf":1.0},"177":{"tf":1.0},"93":{"tf":1.0}}},"r":{"df":5,"docs":{"109":{"tf":1.0},"111":{"tf":1.0},"135":{"tf":1.0},"136":{"tf":1.4142135623730951},"137":{"tf":1.4142135623730951}}}},"t":{"df":0,"docs":{},"h":{"(":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":4,"docs":{"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0}}}},"r":{"df":0,"docs":{},"h":{"df":7,"docs":{"109":{"tf":1.0},"111":{"tf":1.0},"117":{"tf":1.0},"118":{"tf":1.0},"119":{"tf":1.0},"121":{"tf":1.0},"122":{"tf":1.0}}}}},"df":24,"docs":{"100":{"tf":1.0},"101":{"tf":1.0},"102":{"tf":1.0},"103":{"tf":2.23606797749979},"107":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"116":{"tf":1.0},"117":{"tf":1.0},"120":{"tf":1.0},"129":{"tf":1.4142135623730951},"133":{"tf":1.0},"134":{"tf":1.0},"135":{"tf":2.23606797749979},"136":{"tf":1.4142135623730951},"137":{"tf":2.0},"166":{"tf":1.0},"174":{"tf":1.4142135623730951},"75":{"tf":1.4142135623730951},"76":{"tf":1.0},"78":{"tf":1.4142135623730951},"82":{"tf":1.0},"95":{"tf":1.0},"98":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"12":{"tf":1.0}}}}},"df":0,"docs":{}},"l":{"d":{"c":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"32":{"tf":2.23606797749979}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":2,"docs":{"65":{"tf":1.0},"7":{"tf":1.0}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"e":{"df":2,"docs":{"168":{"tf":1.0},"180":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"104":{"tf":1.0},"93":{"tf":1.0}}}},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"65":{"tf":1.4142135623730951}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"170":{"tf":1.0},"171":{"tf":1.0},"178":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":11,"docs":{"104":{"tf":1.0},"105":{"tf":1.0},"106":{"tf":1.0},"130":{"tf":1.0},"131":{"tf":1.0},"180":{"tf":1.0},"192":{"tf":1.0},"199":{"tf":1.0},"76":{"tf":1.0},"90":{"tf":1.0},"93":{"tf":1.0}}}}}}},"z":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"90":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"’":{"df":1,"docs":{"235":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"d":{"0":{"df":2,"docs":{"139":{"tf":1.4142135623730951},"140":{"tf":1.4142135623730951}}},"1":{"df":1,"docs":{"139":{"tf":1.7320508075688772}}},"df":19,"docs":{"103":{"tf":1.0},"128":{"tf":1.7320508075688772},"129":{"tf":1.0},"133":{"tf":1.0},"139":{"tf":1.7320508075688772},"140":{"tf":1.4142135623730951},"166":{"tf":1.7320508075688772},"167":{"tf":1.0},"168":{"tf":1.0},"176":{"tf":1.7320508075688772},"179":{"tf":1.4142135623730951},"180":{"tf":1.4142135623730951},"215":{"tf":2.0},"5":{"tf":1.0},"64":{"tf":1.0},"74":{"tf":1.0},"78":{"tf":1.0},"82":{"tf":1.4142135623730951},"87":{"tf":1.0}}},"df":0,"docs":{},"k":{"df":9,"docs":{"0":{"tf":1.4142135623730951},"18":{"tf":1.4142135623730951},"234":{"tf":1.0},"43":{"tf":1.4142135623730951},"52":{"tf":1.0},"69":{"tf":1.0},"90":{"tf":1.0},"92":{"tf":1.4142135623730951},"93":{"tf":1.4142135623730951}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"219":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":1,"docs":{"62":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"l":{"d":{"df":3,"docs":{"11":{"tf":1.0},"74":{"tf":1.0},"90":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"39":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"98":{"tf":1.0}},"w":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"11":{"tf":1.0}}}}}}}}}},"r":{"a":{"df":0,"docs":{},"p":{"df":4,"docs":{"106":{"tf":1.0},"109":{"tf":1.0},"110":{"tf":1.0},"190":{"tf":1.0}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":6,"docs":{"100":{"tf":1.0},"188":{"tf":1.4142135623730951},"190":{"tf":1.0},"223":{"tf":1.0},"71":{"tf":1.0},"87":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":25,"docs":{"100":{"tf":1.0},"138":{"tf":1.0},"166":{"tf":1.0},"167":{"tf":1.4142135623730951},"175":{"tf":1.4142135623730951},"176":{"tf":1.0},"177":{"tf":1.4142135623730951},"179":{"tf":1.4142135623730951},"180":{"tf":1.0},"188":{"tf":1.0},"191":{"tf":1.0},"201":{"tf":1.0},"204":{"tf":1.0},"214":{"tf":1.0},"215":{"tf":1.0},"219":{"tf":1.0},"223":{"tf":1.0},"232":{"tf":1.4142135623730951},"40":{"tf":1.0},"41":{"tf":1.0},"46":{"tf":1.0},"64":{"tf":1.0},"82":{"tf":1.0},"94":{"tf":1.4142135623730951},"97":{"tf":1.0}},"r":{"df":2,"docs":{"81":{"tf":1.0},"82":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":5,"docs":{"172":{"tf":1.0},"191":{"tf":1.0},"52":{"tf":1.4142135623730951},"66":{"tf":1.0},"80":{"tf":1.0}}}}}}}}},"x":{"8":{"6":{"df":1,"docs":{"219":{"tf":1.0}}},"df":0,"docs":{}},"df":2,"docs":{"128":{"tf":1.4142135623730951},"129":{"tf":1.4142135623730951}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":2,"docs":{"103":{"tf":1.0},"78":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"r":{"(":{"$":{"df":0,"docs":{},"l":{"df":0,"docs":{},"h":{"df":1,"docs":{"119":{"tf":1.0}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"133":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"v":{"0":{"df":1,"docs":{"119":{"tf":1.0}}},"df":0,"docs":{}}},"df":3,"docs":{"100":{"tf":1.0},"119":{"tf":1.7320508075688772},"78":{"tf":1.0}}}},"y":{"df":2,"docs":{"231":{"tf":1.4142135623730951},"233":{"tf":1.4142135623730951}}}},"y":{"df":0,"docs":{},"e":{"df":1,"docs":{"230":{"tf":1.0}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"d":{"df":19,"docs":{"112":{"tf":1.0},"113":{"tf":1.0},"114":{"tf":1.0},"115":{"tf":1.0},"128":{"tf":1.0},"130":{"tf":1.4142135623730951},"131":{"tf":1.4142135623730951},"183":{"tf":1.0},"184":{"tf":1.4142135623730951},"187":{"tf":1.0},"189":{"tf":1.4142135623730951},"192":{"tf":1.0},"193":{"tf":2.6457513110645907},"194":{"tf":1.4142135623730951},"195":{"tf":2.449489742783178},"75":{"tf":1.0},"76":{"tf":1.0},"95":{"tf":1.0},"99":{"tf":1.0}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"65":{"tf":1.0}}}}}}},"’":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"61":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"l":{"df":24,"docs":{"134":{"tf":1.4142135623730951},"16":{"tf":1.0},"174":{"tf":1.0},"178":{"tf":1.0},"190":{"tf":1.0},"198":{"tf":1.0},"22":{"tf":1.0},"230":{"tf":1.0},"34":{"tf":1.0},"39":{"tf":1.7320508075688772},"5":{"tf":1.0},"50":{"tf":1.0},"6":{"tf":1.0},"66":{"tf":1.0},"67":{"tf":1.4142135623730951},"69":{"tf":1.7320508075688772},"72":{"tf":1.0},"73":{"tf":1.0},"74":{"tf":1.4142135623730951},"75":{"tf":1.0},"76":{"tf":1.0},"91":{"tf":1.0},"94":{"tf":1.4142135623730951},"95":{"tf":1.0}}}}},"z":{"df":1,"docs":{"12":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":19,"docs":{"103":{"tf":1.0},"112":{"tf":1.0},"113":{"tf":1.0},"121":{"tf":1.0},"134":{"tf":1.4142135623730951},"136":{"tf":1.0},"159":{"tf":1.0},"174":{"tf":1.0},"176":{"tf":1.0},"183":{"tf":1.0},"184":{"tf":1.4142135623730951},"187":{"tf":1.0},"193":{"tf":1.4142135623730951},"195":{"tf":1.7320508075688772},"207":{"tf":1.0},"214":{"tf":1.4142135623730951},"216":{"tf":1.0},"82":{"tf":1.7320508075688772},"87":{"tf":1.0}}}},"x":{"df":0,"docs":{},"t":{"<":{"df":0,"docs":{},"i":{"2":{"5":{"6":{">":{"(":{"df":0,"docs":{},"v":{"0":{"df":1,"docs":{"136":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"<":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"100":{"tf":1.0},"136":{"tf":1.4142135623730951}},"s":{">":{">":{"(":{"$":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"136":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":1,"docs":{"81":{"tf":1.0}}}}},"k":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"title":{"root":{"0":{"df":0,"docs":{},"x":{"<":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":1,"docs":{"107":{"tf":1.0}}}}}},"df":0,"docs":{}}},"2":{"4":{"df":0,"docs":{},"k":{"b":{"df":1,"docs":{"233":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"6":{"3":{"/":{"6":{"4":{"df":1,"docs":{"37":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"84":{"tf":1.0}}}}}},"df":0,"docs":{}},"d":{"d":{"df":1,"docs":{"109":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"130":{"tf":1.0}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{".":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"38":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":1,"docs":{"144":{"tf":1.0}},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":1,"docs":{"104":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"a":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"92":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"r":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"66":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"230":{"tf":1.0}}}},"df":0,"docs":{}}}}},"u":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"56":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"b":{"a":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"165":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":1,"docs":{"153":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"7":{"tf":1.0}}}}},"d":{"df":1,"docs":{"188":{"tf":1.0}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"103":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"l":{"df":0,"docs":{},"o":{"b":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":2,"docs":{"154":{"tf":1.0},"49":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":2,"docs":{"155":{"tf":1.0},"49":{"tf":1.0}}}}},"df":0,"docs":{}}},"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"199":{"tf":1.0}},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"156":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"k":{"df":1,"docs":{"196":{"tf":1.0}}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"g":{"df":1,"docs":{"222":{"tf":1.0}}},"i":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"10":{"tf":1.0}}}},"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"68":{"tf":1.0}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"k":{"df":1,"docs":{"182":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":1,"docs":{"128":{"tf":1.0}}}}}},"c":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"202":{"tf":1.0}}},"df":0,"docs":{}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":2,"docs":{"187":{"tf":1.0},"41":{"tf":1.0}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":2,"docs":{"159":{"tf":1.0},"41":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":1,"docs":{"160":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":1,"docs":{"201":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"141":{"tf":1.0}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"142":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"145":{"tf":1.0}}},"df":0,"docs":{}}}},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"91":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"11":{"tf":1.0}}},"z":{"df":1,"docs":{"134":{"tf":1.0}}}},"o":{"d":{"df":0,"docs":{},"e":{"b":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":2,"docs":{"183":{"tf":1.0},"42":{"tf":1.0}}}}}},"df":1,"docs":{"35":{"tf":1.4142135623730951}},"s":{"df":2,"docs":{"162":{"tf":1.0},"88":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"b":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"148":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"222":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":4,"docs":{"22":{"tf":1.0},"225":{"tf":1.0},"66":{"tf":1.0},"69":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"84":{"tf":1.0}}},"df":0,"docs":{}}}}}},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"218":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":1,"docs":{"197":{"tf":1.0}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":8,"docs":{"2":{"tf":1.0},"233":{"tf":1.0},"33":{"tf":1.0},"52":{"tf":1.0},"56":{"tf":1.0},"68":{"tf":1.0},"89":{"tf":1.0},"90":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"63":{"tf":1.0}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"59":{"tf":1.0}}}}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"192":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"182":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"u":{"df":1,"docs":{"218":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":2,"docs":{"205":{"tf":1.0},"43":{"tf":1.0}},"e":{"2":{"df":2,"docs":{"206":{"tf":1.0},"43":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"225":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"216":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}}}}},"df":1,"docs":{"72":{"tf":1.0}}}}}}}},"d":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":1,"docs":{"232":{"tf":1.0}}}},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"186":{"tf":1.0}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"170":{"tf":1.0},"44":{"tf":1.0}}}}}}}},"s":{"df":2,"docs":{"171":{"tf":1.0},"45":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":2,"docs":{"16":{"tf":1.0},"17":{"tf":1.0}}}}},"d":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"85":{"tf":1.0}}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"203":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"71":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"y":{"df":3,"docs":{"18":{"tf":1.0},"233":{"tf":1.0},"35":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":1,"docs":{"76":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":2,"docs":{"58":{"tf":1.0},"91":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"34":{"tf":1.0},"50":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":2,"docs":{"223":{"tf":1.0},"224":{"tf":1.0}}}}}}}},"i":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":2,"docs":{"151":{"tf":1.0},"47":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"v":{"df":1,"docs":{"112":{"tf":1.0}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"234":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"226":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"98":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"220":{"tf":1.0},"94":{"tf":1.0}}}}}}}},"q":{"df":1,"docs":{"127":{"tf":1.0}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"215":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"222":{"tf":1.0}}}}}}}}},"v":{"df":0,"docs":{},"m":{"df":4,"docs":{"229":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0},"70":{"tf":1.0}}}},"x":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":2,"docs":{"51":{"tf":1.0},"57":{"tf":1.0}}}}}},"df":0,"docs":{},"p":{"df":1,"docs":{"116":{"tf":1.0}},"l":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"77":{"tf":1.0}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"106":{"tf":1.0},"190":{"tf":1.0}}}}}}},"t":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":2,"docs":{"184":{"tf":1.0},"48":{"tf":1.0}}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"df":1,"docs":{"164":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":1,"docs":{"163":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"200":{"tf":1.0}}}}}}}},"f":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"233":{"tf":1.0}}}},"q":{"df":1,"docs":{"228":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"192":{"tf":1.0}}}}},"m":{"df":0,"docs":{},"p":{"df":1,"docs":{"82":{"tf":1.0}}}},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"83":{"tf":1.0}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"98":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":1,"docs":{"81":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"n":{"c":{"_":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"m":{"df":1,"docs":{"174":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":4,"docs":{"39":{"tf":1.0},"40":{"tf":1.0},"85":{"tf":1.0},"87":{"tf":1.0}}}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"83":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"93":{"tf":1.0}}}}},"z":{"df":0,"docs":{},"z":{"df":0,"docs":{},"i":{"df":1,"docs":{"85":{"tf":1.0}}}}}}},"g":{"a":{"df":2,"docs":{"146":{"tf":1.0},"37":{"tf":1.0}},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"152":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"158":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"60":{"tf":1.0}}}},"t":{"df":1,"docs":{"124":{"tf":1.0}}},"u":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"79":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"i":{"d":{"df":4,"docs":{"4":{"tf":1.0},"58":{"tf":1.0},"59":{"tf":1.0},"64":{"tf":1.0}}},"df":0,"docs":{}}}},"h":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"p":{"df":3,"docs":{"14":{"tf":1.0},"70":{"tf":1.0},"80":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"87":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"91":{"tf":1.0}}}}}}}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"220":{"tf":1.0}}}}}},"i":{"d":{"df":1,"docs":{"23":{"tf":1.0}}},"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":1,"docs":{"100":{"tf":1.0}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":1,"docs":{"17":{"tf":1.0}}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"51":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"51":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"230":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"54":{"tf":1.0},"6":{"tf":1.0},"8":{"tf":1.0}}},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"56":{"tf":1.0}}}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":3,"docs":{"20":{"tf":1.0},"223":{"tf":1.0},"89":{"tf":1.0}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"200":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"f":{"a":{"c":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"n":{"df":1,"docs":{"66":{"tf":1.0}}}}}},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"212":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"r":{"df":3,"docs":{"50":{"tf":1.0},"76":{"tf":1.0},"96":{"tf":1.0}}},"s":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":1,"docs":{"132":{"tf":1.0}}}}}}}},"j":{"df":0,"docs":{},"s":{"df":1,"docs":{"19":{"tf":1.0}},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"24":{"tf":1.0}}}}}},"k":{"df":0,"docs":{},"e":{"c":{"c":{"a":{"df":0,"docs":{},"k":{"2":{"5":{"6":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":1,"docs":{"139":{"tf":1.0}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":1,"docs":{"140":{"tf":1.0}}}}}}}},"df":2,"docs":{"138":{"tf":1.0},"83":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"y":{"df":1,"docs":{"77":{"tf":1.0}}}},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"n":{"df":1,"docs":{"93":{"tf":1.0}}}}}}},"l":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"233":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"v":{"df":1,"docs":{"198":{"tf":1.0}}}},"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":2,"docs":{"12":{"tf":1.0},"33":{"tf":1.0}}}}}},"i":{"b":{"c":{"df":1,"docs":{"227":{"tf":1.0}}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"52":{"tf":1.0},"69":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"93":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"k":{"df":1,"docs":{"18":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"173":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}}}},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":2,"docs":{"12":{"tf":1.0},"71":{"tf":1.0}}}}},"o":{"a":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"172":{"tf":1.0}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"g":{"<":{"df":0,"docs":{},"n":{"df":1,"docs":{"207":{"tf":1.0}}}},"df":1,"docs":{"55":{"tf":1.0}}}},"t":{"df":1,"docs":{"123":{"tf":1.0}}}},"m":{"a":{"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"61":{"tf":1.0}}}}}}},"p":{"df":1,"docs":{"84":{"tf":1.0}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"169":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"181":{"tf":1.0}}}}}}}},"df":0,"docs":{}}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":2,"docs":{"178":{"tf":1.0},"40":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":4,"docs":{"175":{"tf":1.0},"40":{"tf":1.0},"70":{"tf":1.0},"81":{"tf":1.0}}},"y":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"105":{"tf":1.0}}}}}}}}}}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":2,"docs":{"166":{"tf":1.0},"40":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"o":{"d":{"df":1,"docs":{"114":{"tf":1.0}},"e":{"df":1,"docs":{"50":{"tf":1.0}}},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"95":{"tf":1.0}}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"74":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":2,"docs":{"147":{"tf":1.0},"40":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"8":{"df":1,"docs":{"177":{"tf":1.0}}},"df":2,"docs":{"176":{"tf":1.0},"40":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"111":{"tf":1.0}},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"131":{"tf":1.0}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"l":{"df":1,"docs":{"227":{"tf":1.0}}}}}},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":2,"docs":{"78":{"tf":1.0},"79":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"199":{"tf":1.0}}}},"w":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":2,"docs":{"73":{"tf":1.0},"96":{"tf":1.0}}}}}}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"t":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"99":{"tf":1.0}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"m":{"df":2,"docs":{"19":{"tf":1.0},"9":{"tf":1.0}}}},"u":{"df":0,"docs":{},"m":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"150":{"tf":1.0}}}}},"df":0,"docs":{}}}},"o":{"b":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":4,"docs":{"25":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"31":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"p":{"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"231":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"90":{"tf":1.0}}}}}}}}}}},"r":{"df":1,"docs":{"100":{"tf":1.0}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":6,"docs":{"12":{"tf":1.0},"72":{"tf":1.0},"73":{"tf":1.0},"77":{"tf":1.0},"80":{"tf":1.0},"82":{"tf":1.0}}}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"51":{"tf":1.0}}}}},"df":0,"docs":{},"g":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"62":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"143":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"84":{"tf":1.0},"86":{"tf":1.0},"87":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"75":{"tf":1.0}}}}}}}}}},"p":{"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"19":{"tf":1.0},"9":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":2,"docs":{"217":{"tf":1.0},"220":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"i":{"c":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"214":{"tf":1.0}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"86":{"tf":1.0}}}}}}}},"c":{"df":1,"docs":{"48":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"75":{"tf":1.0}}}}}}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"81":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"65":{"tf":1.0}}}},"df":0,"docs":{}},"k":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"o":{"df":1,"docs":{"47":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{"df":1,"docs":{"81":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"106":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"m":{"df":2,"docs":{"217":{"tf":1.0},"219":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"81":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"a":{"d":{"df":1,"docs":{"97":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"95":{"tf":1.0},"96":{"tf":1.0},"97":{"tf":1.0}}}}},"g":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"50":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"l":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"40":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"s":{"df":1,"docs":{"7":{"tf":1.0}}}},"df":0,"docs":{}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":1,"docs":{"23":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"l":{"a":{"c":{"df":1,"docs":{"234":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":1,"docs":{"68":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{"df":6,"docs":{"10":{"tf":1.0},"234":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0},"67":{"tf":1.0},"7":{"tf":1.0}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"88":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"t":{"a":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"185":{"tf":1.0}}}}}},"df":0,"docs":{},"s":{"df":1,"docs":{"161":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":2,"docs":{"209":{"tf":1.0},"46":{"tf":1.0}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"210":{"tf":1.0},"46":{"tf":1.0},"86":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"v":{"df":6,"docs":{"217":{"tf":1.0},"220":{"tf":1.0},"5":{"tf":1.0},"53":{"tf":1.0},"69":{"tf":1.0},"9":{"tf":1.0}}}}}},"o":{"a":{"d":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"p":{"df":2,"docs":{"235":{"tf":1.0},"236":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":2,"docs":{"37":{"tf":1.0},"63":{"tf":1.0}}}},"n":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"53":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":2,"docs":{"217":{"tf":1.0},"35":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"52":{"tf":1.0}}}}}},"s":{"a":{"df":0,"docs":{},"n":{"d":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"x":{"df":1,"docs":{"53":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":1,"docs":{"122":{"tf":1.0}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"113":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}},"f":{"b":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"157":{"tf":1.0}}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"213":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"191":{"tf":1.0}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":1,"docs":{"30":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"28":{"tf":1.0}},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"29":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{".":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"26":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":1,"docs":{"27":{"tf":1.0}}}}}}}},"df":0,"docs":{}}}}}}}},"df":1,"docs":{"25":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}}},"x":{"df":0,"docs":{},"t":{"<":{"df":0,"docs":{},"i":{"<":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"137":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"g":{"df":0,"docs":{},"t":{"df":1,"docs":{"126":{"tf":1.0}}}},"h":{"df":0,"docs":{},"l":{"df":1,"docs":{"120":{"tf":1.0}}},"r":{"df":1,"docs":{"121":{"tf":1.0}}}},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"129":{"tf":1.0}}},"df":0,"docs":{}}}}}}}},"z":{"df":0,"docs":{},"e":{"df":3,"docs":{"13":{"tf":1.0},"14":{"tf":1.0},"233":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"167":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"t":{"df":1,"docs":{"125":{"tf":1.0}}}},"m":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"115":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"l":{"c":{"df":4,"docs":{"15":{"tf":1.0},"234":{"tf":1.0},"50":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{},"i":{"d":{"df":4,"docs":{"21":{"tf":1.0},"222":{"tf":1.0},"232":{"tf":1.0},"36":{"tf":1.0}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"82":{"tf":1.0}}},"df":0,"docs":{}},"r":{"c":{"df":1,"docs":{"10":{"tf":1.0}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"179":{"tf":1.0}}}}}}},"t":{"a":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"60":{"tf":1.0}}}},"t":{"df":0,"docs":{},"e":{"df":1,"docs":{"51":{"tf":1.0}},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"190":{"tf":1.0}}}}}}},"i":{"c":{"c":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"204":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"211":{"tf":1.0}}},"r":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"175":{"tf":1.0}}}},"df":0,"docs":{}}},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":1,"docs":{"221":{"tf":1.0}}}}}}},"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"192":{"tf":1.0}}}}}},"df":0,"docs":{}}},"y":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"64":{"tf":1.0}}}}}},"u":{"b":{"df":1,"docs":{"110":{"tf":1.0}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"229":{"tf":1.0},"230":{"tf":1.0},"231":{"tf":1.0}}}}}}}},"w":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"194":{"tf":1.0}}}},"df":0,"docs":{}}}},"y":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"x":{"df":1,"docs":{"99":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"101":{"tf":1.0}}}}}}}},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":3,"docs":{"1":{"tf":1.0},"217":{"tf":1.0},"218":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"208":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"t":{"df":4,"docs":{"221":{"tf":1.0},"223":{"tf":1.0},"224":{"tf":1.0},"89":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"18":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":1,"docs":{"149":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"168":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.0},"233":{"tf":1.0}},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.0}}}}}}}},"r":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"55":{"tf":1.0}}}},"df":0,"docs":{},"p":{"df":1,"docs":{"82":{"tf":1.0}}}},"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"<":{"df":0,"docs":{},"i":{"<":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"135":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":1,"docs":{"180":{"tf":1.0}}}}}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":3,"docs":{"101":{"tf":1.0},"102":{"tf":1.0},"78":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"11":{"tf":1.0},"54":{"tf":1.0}}}},"df":1,"docs":{"61":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"4":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"224":{"tf":1.0}}}}}},"v":{"<":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"108":{"tf":1.0}}},"df":0,"docs":{}}},"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"51":{"tf":1.0},"94":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":2,"docs":{"229":{"tf":1.0},"232":{"tf":1.0}}}}}}}},"i":{"a":{"df":2,"docs":{"226":{"tf":1.0},"50":{"tf":1.0}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"235":{"tf":1.0}}}}}}},"s":{"df":2,"docs":{"35":{"tf":1.0},"5":{"tf":1.0}}}},"w":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"m":{"df":1,"docs":{"226":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"0":{"tf":1.0}}}}},"df":0,"docs":{}}},"i":{"df":0,"docs":{},"l":{"d":{"c":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"32":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":2,"docs":{"92":{"tf":1.0},"93":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"188":{"tf":1.0}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":2,"docs":{"175":{"tf":1.0},"232":{"tf":1.0}}}}}}},"x":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"119":{"tf":1.0}}}},"y":{"df":2,"docs":{"231":{"tf":1.0},"233":{"tf":1.0}}}},"y":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"39":{"tf":1.0}}}}},"z":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"<":{"df":0,"docs":{},"i":{"<":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"136":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"lang":"English","pipeline":["trimmer","stopWordFilter","stemmer"],"ref":"id","version":"0.9.5"},"results_options":{"limit_results":30,"teaser_word_count":30},"search_options":{"bool":"OR","expand":true,"fields":{"body":{"boost":1},"breadcrumbs":{"boost":1},"title":{"boost":2}}}}')); \ No newline at end of file diff --git a/docs/toc-6f3f265e.js b/docs/toc-1290cc30.js similarity index 94% rename from docs/toc-6f3f265e.js rename to docs/toc-1290cc30.js index 86c1d5c05..3e153969f 100644 --- a/docs/toc-6f3f265e.js +++ b/docs/toc-1290cc30.js @@ -8,7 +8,7 @@ class MDBookSidebarScrollbox extends HTMLElement { super(); } connectedCallback() { - this.innerHTML = '
  1. Welcome
  2. resolc user guide
    1. Installation
    2. Command Line Interface
    3. JS NPM package
    4. Tooling integration
    5. Standard JSON interface
    6. Differences to EVM
    7. Rust contract libraries
  3. revive-runner sandbox
  4. Developer Guide
    1. Contributor guide
    2. Compiler architecture
    3. PVM and the pallet-revive runtime target
    4. Testing strategy
    5. Cross compilation
  5. FAQ
  6. Roadmap and Vision
'; + this.innerHTML = '
  1. Welcome
  2. resolc user guide
    1. Installation
    2. Command Line Interface
    3. JS NPM package
    4. Tooling integration
    5. Standard JSON interface
    6. Differences to EVM
    7. Rust contract libraries
  3. revive-runner sandbox
  4. Developer Guide
    1. Contributor guide
    2. Compiler architecture
    3. The newyork optimizer
      1. IR reference
    4. PVM and the pallet-revive runtime target
    5. Testing strategy
    6. Cross compilation
  5. FAQ
  6. Roadmap and Vision
'; // Set the current, active page, and reveal it if it's hidden let current_page = document.location.href.toString().split('#')[0].split('?')[0]; if (current_page.endsWith('/')) { diff --git a/docs/toc.html b/docs/toc.html index 05aa76a84..844e542a0 100644 --- a/docs/toc.html +++ b/docs/toc.html @@ -26,6 +26,6 @@ -
  1. Welcome
  2. resolc user guide
    1. Installation
    2. Command Line Interface
    3. JS NPM package
    4. Tooling integration
    5. Standard JSON interface
    6. Differences to EVM
    7. Rust contract libraries
  3. revive-runner sandbox
  4. Developer Guide
    1. Contributor guide
    2. Compiler architecture
    3. PVM and the pallet-revive runtime target
    4. Testing strategy
    5. Cross compilation
  5. FAQ
  6. Roadmap and Vision
+
  1. Welcome
  2. resolc user guide
    1. Installation
    2. Command Line Interface
    3. JS NPM package
    4. Tooling integration
    5. Standard JSON interface
    6. Differences to EVM
    7. Rust contract libraries
  3. revive-runner sandbox
  4. Developer Guide
    1. Contributor guide
    2. Compiler architecture
    3. The newyork optimizer
      1. IR reference
    4. PVM and the pallet-revive runtime target
    5. Testing strategy
    6. Cross compilation
  5. FAQ
  6. Roadmap and Vision
diff --git a/docs/user_guide.html b/docs/user_guide.html index 0cdb31216..f954a1fce 100644 --- a/docs/user_guide.html +++ b/docs/user_guide.html @@ -35,10 +35,10 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-79c091ca.js"; + window.path_to_searchindex_js = "searchindex-767b23cd.js"; - +
diff --git a/docs/user_guide/cli.html b/docs/user_guide/cli.html index 840676b2c..f9de541c9 100644 --- a/docs/user_guide/cli.html +++ b/docs/user_guide/cli.html @@ -35,10 +35,10 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-79c091ca.js"; + window.path_to_searchindex_js = "../searchindex-767b23cd.js"; - +
diff --git a/docs/user_guide/differences.html b/docs/user_guide/differences.html index 8ef5dcff8..18f42c791 100644 --- a/docs/user_guide/differences.html +++ b/docs/user_guide/differences.html @@ -35,10 +35,10 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-79c091ca.js"; + window.path_to_searchindex_js = "../searchindex-767b23cd.js"; - +
diff --git a/docs/user_guide/installation.html b/docs/user_guide/installation.html index a86f18d8c..f5ac93419 100644 --- a/docs/user_guide/installation.html +++ b/docs/user_guide/installation.html @@ -35,10 +35,10 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-79c091ca.js"; + window.path_to_searchindex_js = "../searchindex-767b23cd.js"; - +
diff --git a/docs/user_guide/js.html b/docs/user_guide/js.html index f664fb668..3eacb29d0 100644 --- a/docs/user_guide/js.html +++ b/docs/user_guide/js.html @@ -35,10 +35,10 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-79c091ca.js"; + window.path_to_searchindex_js = "../searchindex-767b23cd.js"; - +
diff --git a/docs/user_guide/rust_libraries.html b/docs/user_guide/rust_libraries.html index 8c165b140..689ab18e9 100644 --- a/docs/user_guide/rust_libraries.html +++ b/docs/user_guide/rust_libraries.html @@ -35,10 +35,10 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-79c091ca.js"; + window.path_to_searchindex_js = "../searchindex-767b23cd.js"; - +
diff --git a/docs/user_guide/std_json.html b/docs/user_guide/std_json.html index c1643baf1..3ac02d724 100644 --- a/docs/user_guide/std_json.html +++ b/docs/user_guide/std_json.html @@ -35,10 +35,10 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-79c091ca.js"; + window.path_to_searchindex_js = "../searchindex-767b23cd.js"; - +
diff --git a/docs/user_guide/tooling.html b/docs/user_guide/tooling.html index 053253ca7..f20b725a8 100644 --- a/docs/user_guide/tooling.html +++ b/docs/user_guide/tooling.html @@ -35,10 +35,10 @@ const path_to_root = "../"; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "../searchindex-79c091ca.js"; + window.path_to_searchindex_js = "../searchindex-767b23cd.js"; - +
diff --git a/docs/welcome.html b/docs/welcome.html index b4587ed06..cb7936b3d 100644 --- a/docs/welcome.html +++ b/docs/welcome.html @@ -35,10 +35,10 @@ const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; - window.path_to_searchindex_js = "searchindex-79c091ca.js"; + window.path_to_searchindex_js = "searchindex-767b23cd.js"; - +
diff --git a/retester.sh b/retester.sh new file mode 100644 index 000000000..44dfde528 --- /dev/null +++ b/retester.sh @@ -0,0 +1,18 @@ +WORKDIR=workdir +mkdir -p ${WORKDIR} + +retester test \ + --test revive-differential-tests/resolc-compiler-tests/fixtures/solidity/simple \ + --test revive-differential-tests/resolc-compiler-tests/fixtures/solidity/complex \ + --test revive-differential-tests/resolc-compiler-tests/fixtures/solidity/translated_semantic_tests \ + --platform revive-dev-node-polkavm-resolc \ + --report.file-name report.json \ + --concurrency.number-of-nodes 10 \ + --concurrency.number-of-threads 10 \ + --concurrency.number-of-concurrent-tasks 100 \ + --working-directory ${WORKDIR} \ + --revive-dev-node.consensus manual-seal-200 \ + --revive-dev-node.path revive-dev-node \ + --eth-rpc.path eth-rpc \ + --resolc.path "$(which resolc)" \ + --resolc.heap-size 500000