diff --git a/code/align/assets/tokenizer/goedel-prover-v2-8b/PROVENANCE.md b/code/align/assets/tokenizer/goedel-prover-v2-8b/PROVENANCE.md new file mode 100644 index 0000000000000000000000000000000000000000..2ca6ff52b0f0b5dd5b77803a45d4ab4007427936 --- /dev/null +++ b/code/align/assets/tokenizer/goedel-prover-v2-8b/PROVENANCE.md @@ -0,0 +1,7 @@ +Goedel-LM/Goedel-Prover-V2-8B tokenizer files (Qwen3 byte-level BPE; Apache-2.0), vendored so +P2 tokenisation does not need the vLLM venv or the 16 GB model snapshot. Copied byte-for-byte +from the HF snapshot dfd02e6271a58375dfbf3ece0175277cf6b6a89a. sha256: + tokenizer.json aeb13307a71acd8fe81861d94ad54ab689df773318809eed3cbe794b4492dae4 + tokenizer_config.json 5d27a191a7ba6f93bcc2a8e78bc633764bbaaee263e9f3d9225e2c8621a5dd72 + special_tokens_map.json 76862e765266b85aa9459767e33cbaf13970f327a0e88d1c65846c2ddd3a1ecd +Tokenizer only: no config.json, no weights, no vocab.json/merges.txt (redundant with tokenizer.json). diff --git a/code/align/assets/tokenizer/goedel-prover-v2-8b/special_tokens_map.json b/code/align/assets/tokenizer/goedel-prover-v2-8b/special_tokens_map.json new file mode 100644 index 0000000000000000000000000000000000000000..ac23c0aaa2434523c494330aeb79c58395378103 --- /dev/null +++ b/code/align/assets/tokenizer/goedel-prover-v2-8b/special_tokens_map.json @@ -0,0 +1,31 @@ +{ + "additional_special_tokens": [ + "<|im_start|>", + "<|im_end|>", + "<|object_ref_start|>", + "<|object_ref_end|>", + "<|box_start|>", + "<|box_end|>", + "<|quad_start|>", + "<|quad_end|>", + "<|vision_start|>", + "<|vision_end|>", + "<|vision_pad|>", + "<|image_pad|>", + "<|video_pad|>" + ], + "eos_token": { + "content": "<|im_end|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false + }, + "pad_token": { + "content": "<|endoftext|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false + } +} diff --git a/code/align/assets/tokenizer/goedel-prover-v2-8b/tokenizer_config.json b/code/align/assets/tokenizer/goedel-prover-v2-8b/tokenizer_config.json new file mode 100644 index 0000000000000000000000000000000000000000..e8bb905c2fb94a128cc19a801677504be2183910 --- /dev/null +++ b/code/align/assets/tokenizer/goedel-prover-v2-8b/tokenizer_config.json @@ -0,0 +1,241 @@ +{ + "add_bos_token": false, + "add_prefix_space": false, + "added_tokens_decoder": { + "151643": { + "content": "<|endoftext|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "151644": { + "content": "<|im_start|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "151645": { + "content": "<|im_end|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "151646": { + "content": "<|object_ref_start|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "151647": { + "content": "<|object_ref_end|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "151648": { + "content": "<|box_start|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "151649": { + "content": "<|box_end|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "151650": { + "content": "<|quad_start|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "151651": { + "content": "<|quad_end|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "151652": { + "content": "<|vision_start|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "151653": { + "content": "<|vision_end|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "151654": { + "content": "<|vision_pad|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "151655": { + "content": "<|image_pad|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "151656": { + "content": "<|video_pad|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "151657": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": false + }, + "151658": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": false + }, + "151659": { + "content": "<|fim_prefix|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": false + }, + "151660": { + "content": "<|fim_middle|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": false + }, + "151661": { + "content": "<|fim_suffix|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": false + }, + "151662": { + "content": "<|fim_pad|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": false + }, + "151663": { + "content": "<|repo_name|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": false + }, + "151664": { + "content": "<|file_sep|>", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": false + }, + "151665": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": false + }, + "151666": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": false + }, + "151667": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": false + }, + "151668": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": false + } + }, + "additional_special_tokens": [ + "<|im_start|>", + "<|im_end|>", + "<|object_ref_start|>", + "<|object_ref_end|>", + "<|box_start|>", + "<|box_end|>", + "<|quad_start|>", + "<|quad_end|>", + "<|vision_start|>", + "<|vision_end|>", + "<|vision_pad|>", + "<|image_pad|>", + "<|video_pad|>" + ], + "bos_token": null, + "chat_template": "{%- if tools %}\n {{- '<|im_start|>system\\n' }}\n {%- if messages[0].role == 'system' %}\n {{- messages[0].content + '\\n\\n' }}\n {%- endif %}\n {{- \"# Tools\\n\\nYou may call one or more functions to assist with the user query.\\n\\nYou are provided with function signatures within XML tags:\\n\" }}\n {%- for tool in tools %}\n {{- \"\\n\" }}\n {{- tool | tojson }}\n {%- endfor %}\n {{- \"\\n\\n\\nFor each function call, return a json object with function name and arguments within XML tags:\\n\\n{\\\"name\\\": , \\\"arguments\\\": }\\n<|im_end|>\\n\" }}\n{%- else %}\n {%- if messages[0].role == 'system' %}\n {{- '<|im_start|>system\\n' + messages[0].content + '<|im_end|>\\n' }}\n {%- endif %}\n{%- endif %}\n{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}\n{%- for message in messages[::-1] %}\n {%- set index = (messages|length - 1) - loop.index0 %}\n {%- if ns.multi_step_tool and message.role == \"user\" and message.content is string and not(message.content.startswith('') and message.content.endswith('')) %}\n {%- set ns.multi_step_tool = false %}\n {%- set ns.last_query_index = index %}\n {%- endif %}\n{%- endfor %}\n{%- for message in messages %}\n {%- if message.content is string %}\n {%- set content = message.content %}\n {%- else %}\n {%- set content = '' %}\n {%- endif %}\n {%- if (message.role == \"user\") or (message.role == \"system\" and not loop.first) %}\n {{- '<|im_start|>' + message.role + '\\n' + content + '<|im_end|>' + '\\n' }}\n {%- elif message.role == \"assistant\" %}\n {%- set reasoning_content = '' %}\n {%- if message.reasoning_content is string %}\n {%- set reasoning_content = message.reasoning_content %}\n {%- else %}\n {%- if '' in content %}\n {%- set reasoning_content = content.split('')[0].rstrip('\\n').split('')[-1].lstrip('\\n') %}\n {%- set content = content.split('')[-1].lstrip('\\n') %}\n {%- endif %}\n {%- endif %}\n {%- if loop.index0 > ns.last_query_index %}\n {%- if loop.last or (not loop.last and reasoning_content) %}\n {{- '<|im_start|>' + message.role + '\\n\\n' + reasoning_content.strip('\\n') + '\\n\\n\\n' + content.lstrip('\\n') }}\n {%- else %}\n {{- '<|im_start|>' + message.role + '\\n' + content }}\n {%- endif %}\n {%- else %}\n {{- '<|im_start|>' + message.role + '\\n' + content }}\n {%- endif %}\n {%- if message.tool_calls %}\n {%- for tool_call in message.tool_calls %}\n {%- if (loop.first and content) or (not loop.first) %}\n {{- '\\n' }}\n {%- endif %}\n {%- if tool_call.function %}\n {%- set tool_call = tool_call.function %}\n {%- endif %}\n {{- '\\n{\"name\": \"' }}\n {{- tool_call.name }}\n {{- '\", \"arguments\": ' }}\n {%- if tool_call.arguments is string %}\n {{- tool_call.arguments }}\n {%- else %}\n {{- tool_call.arguments | tojson }}\n {%- endif %}\n {{- '}\\n' }}\n {%- endfor %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n {%- elif message.role == \"tool\" %}\n {%- if loop.first or (messages[loop.index0 - 1].role != \"tool\") %}\n {{- '<|im_start|>user' }}\n {%- endif %}\n {{- '\\n\\n' }}\n {{- content }}\n {{- '\\n' }}\n {%- if loop.last or (messages[loop.index0 + 1].role != \"tool\") %}\n {{- '<|im_end|>\\n' }}\n {%- endif %}\n {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n {{- '<|im_start|>assistant\\n' }}\n {%- if enable_thinking is defined and enable_thinking is false %}\n {{- '\\n\\n\\n\\n' }}\n {%- endif %}\n{%- endif %}", + "clean_up_tokenization_spaces": false, + "eos_token": "<|im_end|>", + "errors": "replace", + "extra_special_tokens": {}, + "model_max_length": 131072, + "pad_token": "<|endoftext|>", + "padding_side": "right", + "split_special_tokens": false, + "tokenizer_class": "Qwen2Tokenizer", + "unk_token": null +} diff --git a/code/align/model/artifacts/logit_noise_floor.json b/code/align/model/artifacts/logit_noise_floor.json new file mode 100644 index 0000000000000000000000000000000000000000..8153dd90d553f9c0c027e793b6abc070c363cb89 --- /dev/null +++ b/code/align/model/artifacts/logit_noise_floor.json @@ -0,0 +1,20 @@ +{ + "2": { + "max_abs_dlogit": 0.75586, + "mean_abs_dlogit": 0.015027, + "argmax_flips": 1, + "positions": 794 + }, + "4": { + "max_abs_dlogit": 0.78516, + "mean_abs_dlogit": 0.01436, + "argmax_flips": 1, + "positions": 794 + }, + "8": { + "max_abs_dlogit": 0.78516, + "mean_abs_dlogit": 0.014431, + "argmax_flips": 1, + "positions": 794 + } +} \ No newline at end of file diff --git a/code/align/model/artifacts/sdpa_baseline.json b/code/align/model/artifacts/sdpa_baseline.json new file mode 100644 index 0000000000000000000000000000000000000000..b6d26c1841152ed68ea119be86bb3adf6671894f --- /dev/null +++ b/code/align/model/artifacts/sdpa_baseline.json @@ -0,0 +1,17 @@ +{ + "512": { + "FLASH_ATTENTION": 0.18939885194413364, + "EFFICIENT_ATTENTION": NaN, + "MATH": 4.349638050189242 + }, + "1024": { + "FLASH_ATTENTION": 0.6236543995328248, + "EFFICIENT_ATTENTION": NaN, + "MATH": 16.252079099649563 + }, + "2048": { + "FLASH_ATTENTION": 2.281787298852578, + "EFFICIENT_ATTENTION": NaN, + "MATH": 61.56193719943985 + } +} \ No newline at end of file diff --git a/code/align/model/artifacts/triton_fa2_equivalence.json b/code/align/model/artifacts/triton_fa2_equivalence.json new file mode 100644 index 0000000000000000000000000000000000000000..9f7fc5fa7f9880bd23f34053daa33cd0729e510b --- /dev/null +++ b/code/align/model/artifacts/triton_fa2_equivalence.json @@ -0,0 +1,25 @@ +{ + "environment": { + "compute_capability": "8.6", + "device_name": "NVIDIA A10G", + "torch": "2.11.0+cu128", + "triton": "3.6.0" + }, + "kernel_sha256": "5f2cbe2088a7e583895268c59895366e39a4eb79d4dc8b719cbca2e57c2eed4b", + "schema_version": 1, + "shapes_covered": [ + "gqa (n_q_heads, n_kv_heads) in [(8,2), (32,8)] plus MHA-degenerate (4,4)", + "head_dim in [64, 128]", + "seq in [192, 256, 512, 1000] (block-divisible AND non-divisible)", + "causal and non-causal", + "key_padding_mask, right-padded, non-block-aligned", + "every autotune config individually pinned (fwd + both bwd kernels)", + "dtype bfloat16 only (fp16/fp32 rejected)" + ], + "tolerances": { + "absolute_floor": 0.02, + "policy": "max |err| vs fp32 reference <= max(3.0 x torch-SDPA-bf16 error, 2e-2)", + "slack_over_sdpa": 3.0 + }, + "verified_at": "2026-08-18T13:18:04+00:00" +} diff --git a/code/align/rl/envs/__init__.py b/code/align/rl/envs/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..74cf3d4df8eec454e0a02b1f4915d93db7fe5712 --- /dev/null +++ b/code/align/rl/envs/__init__.py @@ -0,0 +1,35 @@ +"""RL environments (opt-in; nothing in `align.rl` imports this package). + + lean_multiturn.py multi-turn Lean prover episodes with Goedel correction feedback, + multi-turn loss masks and per-turn advantage assignment. +""" + +from .lean_multiturn import ( + EpisodeRecord, + EpisodeSpec, + GenRequest, + Generation, + LeanMultiTurnConfig, + LeanMultiTurnEnv, + PrefixBreak, + Problem, + SandboxNotWired, + TrainingRow, + TurnRecord, + assign_advantages, +) + +__all__ = [ + "EpisodeRecord", + "EpisodeSpec", + "GenRequest", + "Generation", + "LeanMultiTurnConfig", + "LeanMultiTurnEnv", + "PrefixBreak", + "Problem", + "SandboxNotWired", + "TrainingRow", + "TurnRecord", + "assign_advantages", +] diff --git a/code/align/rl/envs/lean_multiturn.py b/code/align/rl/envs/lean_multiturn.py new file mode 100644 index 0000000000000000000000000000000000000000..150b54b23ab7a68709433fef3cc8fa9bf42929f2 --- /dev/null +++ b/code/align/rl/envs/lean_multiturn.py @@ -0,0 +1,538 @@ +"""Multi-turn Lean prover environment (P4-B): proof attempt -> compiler feedback -> retry. + +An EPISODE is up to K turns on one formal statement. Turn 0 is the Goedel round-0 prompt. +If the verifier rejects the proof with compile errors, turn k+1's prompt is the Goedel +CORRECTION prompt: the history, the failed attempt as an assistant message, and a user +message carrying the ``-annotated compiler output. The episode ends at the +first verified turn, at K turns, or at the first rejection that feedback cannot repair. + +Everything below exists to prevent one named failure; each is pinned by a test. + +* PROMPT DRIFT. The prompts are NOT re-expressed here. `extras/vllm_rollout/lean_prompts.py` + (byte-faithful to Goedel-Prover-V2) is loaded BY FILE PATH, read-only, the way + tests/test_lean_gen_contract.py and scripts/p2/p2_common.py do. A second copy of the + correction template would drift by one newline and silently change the policy sampled. + +* LOSS ON FEEDBACK TOKENS. The compiler's error text is environment output, not policy + output. If it carried loss the model would be trained to *write* error messages, and the + gradient would reward predicting them. Rows carry `response_mask` that is 1 ONLY on tokens + the generator returned; prompt, chat-template glue and feedback are 0. `turn_ids` labels + each token with its turn (-1 unlabeled) so tests and the loss can audit it. + +* RE-TOKENIZATION DRIFT. Token ids are never re-derived from text for generated tokens. + layout="concatenated" builds ONE row per episode: context_k = context_{k-1} + generated_{k-1} + + encode(template delta). That is only valid when the chat template renders turn k's + prompt as a pure extension of (turn k-1's prompt + completion text); templates that rewrite + earlier assistant content (Qwen3 strips old blocks) break it. We CHECK the prefix + property and raise `PrefixBreak` rather than train on tokens the policy never saw. + layout="per_turn" (the default) emits one row per turn from that turn's exact prompt ids; + it is always exact, at the price of re-running the shared prefix. + +* STATEMENT REWRITING IS NOT A SOLVE. `problem_check` re-inserts the ORIGINAL statement over + whatever theorem the model displayed, so a model that states an easier theorem and proves + that is *accepted* if its tactics happen to close the original. Goedel's evaluation credits + it; a TRAINING reward must not (it teaches the model to misstate the problem). Before the + verifier is consulted, `scripts/p2/p2_common.displayed_statement_matches` (loaded by path) + must hold, else the turn is terminal with reason `statement_rewrite` and reward 0. + +* TRUNCATION IS NOT A SUBMISSION. A generation that hit the length limit is rejected + (`truncated`) even if its plan contains an earlier closed code fence; the final answer was + cut off, and verifying a stale fence rewards an accident. + +* SPARSE REWARD, NO LENGTH IN THE LOSS. Episode reward = turn_discount ** solved_turn + (0 if never solved) plus an optional DAPO soft-overlong term on TOTAL generated tokens, + weighted by `overlong_weight`. The penalty lives in reward composition (reusing + `align.rl.rewards.soft_overlong_punishment`), never in the loss. + +* CREDIT ASSIGNMENT. advantage_mode="episode": every generated token gets the Dr.GRPO + group-centered episode reward (the repo's `compute_group_advantages`, reused). + advantage_mode="per_turn": turn t gets G_t - mean_group(G_t) with + G_t = sum_{s>=t} credit_gamma^(s-t) * u_s, u_s the turn's own outcome reward. With + credit_gamma=0 a failed first attempt gets no credit for the repair that followed (the + failure mode of episode-level sharing: rewarding the bad first draft); with gamma>0 it + shares in it, because its error context is what made the repair possible. The baseline for + turn t averages only episodes that HAVE a turn t. + +* DEAD VERIFIER != ZERO REWARD. `LeanInfraError` from the verifier propagates unchanged. A + verifier that is dying SOFTLY (every proof comes back `crash`/`protocol`/`memory`/ + `output_too_large` instead of raising) would otherwise be turned by this env into + `rejected:crash`, reward 0, a batch of zeros that reads as "the model got worse". + `LeanReward.accuracy_batch` refuses that; the env bypasses `LeanReward`, so it carries the + same guard: once at least `min_infra_batch` verifications have run in a `run_group`, a + cumulative infra-failure share above `max_infra_fraction` raises `LeanInfraError`. + +* ENGINE FINISH REASONS. The P3 engine reports `eos|stop_token|stop_string|max_new_tokens| + max_seq_len`, the lean_gen contract reports `stop|length`. Only `length` used to count as + truncated, so an engine-capped generation (`max_new_tokens`/`max_seq_len`) was VERIFIED as + if it were a finished answer. Both vocabularies are accepted; an unknown reason raises + (a new engine reason must be classified by a human, not guessed). + +* CONTEXT BUDGET. Compiler feedback is unbounded and each repair turn re-sends the whole + history. With `max_prompt_tokens` set, a repair prompt over the budget ends the episode + (`context_overflow`, reward 0 for the unsolved episode) instead of being handed to an + engine that would refuse it (or silently truncate the prompt from the left). + +* EPISODE KEY COLLISIONS. `generate` adapters key seeds / KV state by `episode_key`; two + specs with the same (problem_id, sample_idx, statement) would share one stream. Refused. + +Sandbox: `LeanMultiTurnConfig.sandbox=True` is a pass-through request for the +`align/verify/lean/sandbox.py` REPL. The pool is not wired to it yet, so the env raises +`SandboxNotWired` unless the pool itself advertises a truthy `sandbox` attribute. + +Error positions: the Goedel format needs REPL message dicts (`pos`, `endPos`, `data`) +indexing `compile_view(code)`. `StrictResult.diagnostics["repl_errors"]` is the contract for +those; `StrictVerifier` does not populate it yet (it keeps only 3 truncated message strings). +Absent positions the env degrades per `unpositioned_feedback` ("message_only" renders the +messages with no code excerpt; "raise" refuses) instead of inventing an `` location. + +stdlib-only (+ align.rl.rewards / align.rl.advantages); no torch tensors are built here. +""" + +from __future__ import annotations + +import hashlib +import importlib.util +import json +from dataclasses import asdict, dataclass, field +from pathlib import Path +from typing import Any, Callable, Optional, Sequence + +from align.rl.advantages import compute_group_advantages +from align.rl.rewards import soft_overlong_punishment + +_REPO = Path(__file__).resolve().parents[3] + +_MODS: dict[str, Any] = {} + + +def _load_by_path(key: str, rel: str): + if key not in _MODS: + spec = importlib.util.spec_from_file_location(key, _REPO / rel) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + _MODS[key] = mod + return _MODS[key] + + +def _lean_prompts(): + return _load_by_path("align_envs_lean_prompts", "extras/vllm_rollout/lean_prompts.py") + + +def _p2_common(): + return _load_by_path("align_envs_p2_common", "scripts/p2/p2_common.py") + + +#: finish reasons that mean "the generator ended on its own" / "the generator was cut off" +STOP_REASONS = frozenset({"stop", "eos", "stop_token", "stop_string"}) +TRUNCATED_REASONS = frozenset({"length", "max_new_tokens", "max_seq_len"}) + + +class SandboxNotWired(RuntimeError): + """sandbox=True was requested but the verifier pool has no sandboxed REPL.""" + + +class PrefixBreak(RuntimeError): + """The chat template did not render turn k's prompt as an extension of turn k-1's + prompt + completion, so one concatenated token row would not be what the policy saw.""" + + +@dataclass(frozen=True) +class Problem: + problem_id: str + formal_statement: str + + +@dataclass(frozen=True) +class EpisodeSpec: + problem: Problem + sample_idx: int = 0 + + +@dataclass(frozen=True) +class GenRequest: + episode_key: str + turn: int + prompt_ids: tuple + prompt_text: str + + +@dataclass(frozen=True) +class Generation: + """`token_ids`: exactly what the engine sampled (incl. a trailing EOS if sampled). + `text`: the decoded completion WITHOUT the EOS string. `logprobs`: per generated token.""" + + token_ids: tuple + text: str + logprobs: Optional[tuple] = None + finish_reason: str = "stop" + + +@dataclass(frozen=True) +class LeanMultiTurnConfig: + max_turns: int = 2 + layout: str = "per_turn" # "per_turn" | "concatenated" + turn_discount: float = 1.0 + overlong_max_len: Optional[int] = None + overlong_cache_len: Optional[int] = None + overlong_weight: float = 1.0 + advantage_mode: str = "episode" # "episode" | "per_turn" + credit_gamma: float = 0.0 + retry_reasons: tuple = ("compile_error",) + reject_truncated: bool = True + #: ABLATION ONLY: accept a proof whose displayed theorem differs from the statement. + allow_statement_rewrite: bool = False + error_thres: bool = True + unpositioned_feedback: str = "message_only" # "message_only" | "raise" + sandbox: bool = False + #: ceiling on the repair prompt length in tokens (None = unbounded, the old behaviour) + max_prompt_tokens: Optional[int] = None + #: soft-infra-failure guard (see module docstring); same defaults as LeanReward + max_infra_fraction: float = 0.5 + min_infra_batch: int = 8 + eos_token_id: Optional[int] = None + eos_text: str = "<|im_end|>" + + def __post_init__(self) -> None: + if self.max_turns < 1: + raise ValueError(f"max_turns must be >= 1, got {self.max_turns}") + if self.layout not in ("per_turn", "concatenated"): + raise ValueError(f"layout must be 'per_turn' or 'concatenated', got {self.layout!r}") + if not 0.0 < self.turn_discount <= 1.0: + raise ValueError(f"turn_discount must be in (0, 1], got {self.turn_discount}") + if self.advantage_mode not in ("episode", "per_turn"): + raise ValueError(f"advantage_mode must be 'episode' or 'per_turn', got {self.advantage_mode!r}") + if not 0.0 <= self.credit_gamma <= 1.0: + raise ValueError(f"credit_gamma must be in [0, 1], got {self.credit_gamma}") + if self.max_prompt_tokens is not None and self.max_prompt_tokens < 1: + raise ValueError(f"max_prompt_tokens must be None or >= 1, got {self.max_prompt_tokens}") + if not 0.0 <= self.max_infra_fraction <= 1.0: + raise ValueError(f"max_infra_fraction must be in [0, 1], got {self.max_infra_fraction}") + if self.min_infra_batch < 1: + raise ValueError(f"min_infra_batch must be >= 1, got {self.min_infra_batch}") + if self.unpositioned_feedback not in ("message_only", "raise"): + raise ValueError(f"unpositioned_feedback must be 'message_only' or 'raise'") + # same construction-time refusals as CompositeReward: a half-armed penalty is silently off + if self.overlong_max_len is None and self.overlong_cache_len is not None: + raise ValueError("overlong_cache_len given without overlong_max_len: penalty would be silently OFF") + if self.overlong_max_len is not None: + if self.overlong_cache_len is None or not 0 < self.overlong_cache_len < self.overlong_max_len: + raise ValueError("need 0 < overlong_cache_len < overlong_max_len") + + +@dataclass +class TurnRecord: + turn: int + prompt_text: str + prompt_ids: list + completion_ids: list + completion_text: str + finish_reason: str + lean_code: Optional[str] = None + code_error: Optional[str] = None + displayed_statement_ok: Optional[bool] = None + reasons: tuple = () + verified: bool = False + credited: bool = False + feedback_text: Optional[str] = None + feedback_positioned: Optional[bool] = None + + +@dataclass +class TrainingRow: + input_ids: list + #: 1 ONLY on tokens the generator returned (input space, like RolloutBatch.response_mask) + response_mask: list + #: turn index of each generated token, -1 elsewhere + turn_ids: list + #: per-token engine logprobs in input space (0.0 where unlabeled); None if not supplied + logprobs: Optional[list] = None + #: per-token advantage (0.0 where unlabeled); filled by `assign_advantages` + advantages: Optional[list] = None + + +@dataclass +class EpisodeRecord: + episode_key: str + problem_id: str + sample_idx: int + turns: list + rows: list + terminal: str = "" + solved_turn: Optional[int] = None + reward: dict = field(default_factory=dict) + turn_rewards: list = field(default_factory=list) # u_t, the per-turn outcome rewards + n_generated: int = 0 + + def to_json(self) -> str: + return json.dumps(asdict(self), sort_keys=True, ensure_ascii=False) + + +# ------------------------------------------------------------------------- reward composition + + +def compose_episode_reward(cfg: LeanMultiTurnConfig, solved_turn: Optional[int], n_turns: int, n_generated: int): + """(terms, u): itemised episode reward terms and the per-turn outcome rewards u_t. + The overlong term is attached to the LAST turn's u (the turn that ended the episode).""" + u = [0.0] * n_turns + acc = 0.0 + if solved_turn is not None: + acc = cfg.turn_discount ** solved_turn + u[solved_turn] = acc + ov = 0.0 + if cfg.overlong_max_len is not None: + ov = cfg.overlong_weight * soft_overlong_punishment(n_generated, cfg.overlong_max_len, cfg.overlong_cache_len) + u[-1] += ov + terms = { + "reward/accuracy": 1.0 if solved_turn is not None else 0.0, + "reward/turn_discount": acc, + "reward/overlong": ov, + "reward/total": acc + ov, + } + return terms, u + + +def assign_advantages(episodes: Sequence[EpisodeRecord], cfg: LeanMultiTurnConfig) -> None: + """Fill `row.advantages` in place. Episodes of one problem_id form a group (input order + preserved). Groups must be equal-sized in "episode" mode (the shared helper's layout).""" + groups: dict[str, list] = {} + for ep in episodes: + groups.setdefault(ep.problem_id, []).append(ep) + for eps in groups.values(): + n_turn_max = max(len(e.turns) for e in eps) + if cfg.advantage_mode == "episode": + import numpy as np + + adv = compute_group_advantages(np.array([e.reward["reward/total"] for e in eps]), len(eps), "centered") + per_turn = [[float(a)] * n_turn_max for a in adv] + else: + G = [] + for e in eps: + g, acc = [0.0] * len(e.turns), 0.0 + for t in range(len(e.turns) - 1, -1, -1): + acc = e.turn_rewards[t] + cfg.credit_gamma * acc + g[t] = acc + G.append(g) + per_turn = [[0.0] * n_turn_max for _ in eps] + for t in range(n_turn_max): + have = [i for i, e in enumerate(eps) if t < len(e.turns)] + base = sum(G[i][t] for i in have) / len(have) + for i in have: + per_turn[i][t] = G[i][t] - base + for e, adv_t in zip(eps, per_turn): + for row in e.rows: + row.advantages = [adv_t[tid] if tid >= 0 else 0.0 for tid in row.turn_ids] + + +# ------------------------------------------------------------------------- the environment + + +class _Ep: + def __init__(self, spec: EpisodeSpec, key: str): + self.spec, self.key = spec, key + self.turns: list[TurnRecord] = [] + self.messages: list[dict] = [] + self.prompt_text = "" + self.prompt_ids: list = [] + self.ctx_ids: list = [] # concatenated layout: running context + self.gens: list[Generation] = [] + self.done = False + self.terminal = "" + self.solved_turn: Optional[int] = None + self.pending: Optional[tuple] = None + + +class LeanMultiTurnEnv: + """`verifier`: anything with `verify(statement, code) -> StrictResult` (and optionally + `verify_batch(items)`), e.g. `StrictVerifier`. `tokenizer`: `apply_chat_template(messages, + tokenize=False, add_generation_prompt=True)`. `encode`: text -> ids.""" + + def __init__(self, verifier, tokenizer, encode: Callable[[str], list], cfg: LeanMultiTurnConfig = LeanMultiTurnConfig()): + if cfg.sandbox and not getattr(getattr(verifier, "pool", verifier), "sandbox", None): + raise SandboxNotWired( + "sandbox=True requested but the verifier pool exposes no sandboxed REPL " + "(align/verify/lean/sandbox.py is not wired into repl_pool yet)" + ) + self.verifier, self.tok, self.encode, self.cfg = verifier, tokenizer, encode, cfg + + # ---- public + def run_episode(self, spec: EpisodeSpec, generate: Callable[[list], list]) -> EpisodeRecord: + return self.run_group([spec], generate)[0] + + def run_group(self, specs: Sequence[EpisodeSpec], generate: Callable[[list], list]) -> list: + """Lockstep over episodes: each round, ONE `generate(list[GenRequest]) -> list[Generation]` + call for all active episodes, then one batched verification. Output order = input order.""" + eps = [_Ep(s, self._key(s)) for s in specs] + if len({e.key for e in eps}) != len(eps): + dup = sorted({e.key for e in eps if sum(x.key == e.key for x in eps) > 1}) + raise ValueError(f"duplicate episode keys {dup}: specs must differ in problem_id/sample_idx/statement") + n_ver = n_infra = 0 + for ep in eps: + self._start(ep) + active = list(eps) + while active: + reqs = [GenRequest(e.key, len(e.turns), tuple(e.prompt_ids), e.prompt_text) for e in active] + gens = generate(reqs) + if len(gens) != len(active): + raise ValueError(f"generate returned {len(gens)} generations for {len(active)} requests") + for e, g in zip(active, gens): + self._absorb(e, g) + todo = [e for e in active if not e.done] + if todo: + items = [e.pending for e in todo] + vb = getattr(self.verifier, "verify_batch", None) + results = vb(items) if vb is not None else [self.verifier.verify(s, c) for s, c in items] + if len(results) != len(todo): + raise ValueError(f"verifier returned {len(results)} results for {len(todo)} items") + n_ver += len(results) + n_infra += sum(1 for r in results if getattr(r, "infra_failure", False)) + self._check_infra(n_infra, n_ver) + for e, r in zip(todo, results): + self._judge(e, r) + active = [e for e in active if not e.done] + return [self._finish(e) for e in eps] + + # ---- internals + def _check_infra(self, n_infra: int, n_ver: int) -> None: + cfg = self.cfg + if n_ver >= cfg.min_infra_batch and n_infra / n_ver > cfg.max_infra_fraction: + from align.verify.lean.strict import LeanInfraError + + raise LeanInfraError( + f"{n_infra}/{n_ver} verifications died for infrastructure reasons: either the pool is " + f"dead or the policy is emitting REPL-killing proofs; refusing to emit episodes of " + f"reward 0 that read as 'model got worse'" + ) + + def _key(self, s: EpisodeSpec) -> str: + h = hashlib.sha256(f"{s.problem.problem_id}\0{s.sample_idx}\0{s.problem.formal_statement}".encode()).hexdigest() + return h[:16] + + def _render(self, messages: list) -> str: + return self.tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) + + def _start(self, ep: _Ep) -> None: + text, msgs = _lean_prompts().initial_prompt(ep.spec.problem.formal_statement, self.tok) + ep.messages, ep.prompt_text = list(msgs), text + ep.prompt_ids = list(self.encode(text)) + ep.ctx_ids = list(ep.prompt_ids) + + def _absorb(self, ep: _Ep, g: Generation) -> None: + cfg, lp = self.cfg, _lean_prompts() + if g.logprobs is not None and len(g.logprobs) != len(g.token_ids): + raise ValueError(f"{len(g.logprobs)} logprobs for {len(g.token_ids)} generated tokens") + t = TurnRecord(len(ep.turns), ep.prompt_text, list(ep.prompt_ids), list(g.token_ids), g.text, g.finish_reason) + ep.turns.append(t) + ep.gens.append(g) + stmt = ep.spec.problem.formal_statement + if g.finish_reason not in STOP_REASONS and g.finish_reason not in TRUNCATED_REASONS: + raise ValueError( + f"unknown finish_reason {g.finish_reason!r}; classify it in STOP_REASONS or TRUNCATED_REASONS" + ) + if cfg.reject_truncated and g.finish_reason in TRUNCATED_REASONS: + return self._end(ep, "truncated") + code, err = lp.lean_code_for_record(stmt, g.text) + t.lean_code, t.code_error = code, err + if code is None: + return self._end(ep, f"no_code:{err}") + if not cfg.allow_statement_rewrite: + t.displayed_statement_ok = bool(_p2_common().displayed_statement_matches(stmt, g.text)) + if not t.displayed_statement_ok: + return self._end(ep, "statement_rewrite") + ep.pending = (stmt, code) + + def _judge(self, ep: _Ep, r) -> None: + cfg, t = self.cfg, ep.turns[-1] + t.reasons, t.verified = tuple(r.reasons), bool(r.accepted) + if r.accepted: + t.credited, ep.solved_turn = True, t.turn + return self._end(ep, "verified") + if t.turn + 1 >= cfg.max_turns: + return self._end(ep, "max_turns") + if not all(x in cfg.retry_reasons for x in t.reasons): + return self._end(ep, f"rejected:{t.reasons[0] if t.reasons else 'unknown'}") + fb = self._feedback(ep, r) + if fb is None: + return self._end(ep, "no_feedback") + err_str, positioned = fb + t.feedback_text, t.feedback_positioned = err_str, positioned + lp = _lean_prompts() + text, msgs = lp.DeepSeekCoTHandler().generate_correction_prompt( + lp.goedel_statement(ep.spec.problem.formal_statement), ep.messages, t.completion_text, + err_str, self.tok, t.turn + 1, + ) + if cfg.max_prompt_tokens is not None and len(self.encode(text)) > cfg.max_prompt_tokens: + return self._end(ep, "context_overflow") + ep.messages = msgs + prev_end = ep.prompt_text + t.completion_text + if cfg.layout == "concatenated": + if not text.startswith(prev_end): + raise PrefixBreak( + f"turn {t.turn + 1} prompt does not extend turn {t.turn} prompt + completion " + f"(template rewrites earlier assistant content, e.g. Qwen3 stripping); " + f"use layout='per_turn'" + ) + delta = text[len(prev_end):] + gen = ep.gens[-1] + if (cfg.eos_token_id is not None and gen.token_ids and gen.token_ids[-1] == cfg.eos_token_id + and delta.startswith(cfg.eos_text)): + delta = delta[len(cfg.eos_text):] # the sampled EOS is already in the context + ep.ctx_ids = ep.ctx_ids + list(gen.token_ids) + list(self.encode(delta)) + ep.prompt_ids = list(ep.ctx_ids) + else: + ep.prompt_ids = list(self.encode(text)) + ep.prompt_text = text + + def _feedback(self, ep: _Ep, r) -> Optional[tuple]: + lp = _lean_prompts() + diag = r.diagnostics or {} + t = ep.turns[-1] + errs = diag.get("repl_errors") + if errs and all(isinstance(e, dict) and e.get("pos") and "data" in e for e in errs): + view = diag.get("error_code_view") or lp.compile_view(t.lean_code) + return lp.get_error_str(view, errs, self.cfg.error_thres), True + msgs = diag.get("errors") + if not msgs and not errs: + return None + if self.cfg.unpositioned_feedback == "raise": + raise ValueError("verifier result has no positioned REPL errors (diagnostics['repl_errors'])") + raw = [e["data"] if isinstance(e, dict) else str(e) for e in (errs or msgs)] + return "".join(f"\nError {i + 1}:\n\nError Message: {m}\n" for i, m in enumerate(raw)), False + + def _end(self, ep: _Ep, why: str) -> None: + ep.done, ep.terminal = True, why + + def _finish(self, ep: _Ep) -> EpisodeRecord: + n_gen = sum(len(g.token_ids) for g in ep.gens) + terms, u = compose_episode_reward(self.cfg, ep.solved_turn, len(ep.turns), n_gen) + rows = self._rows(ep) + s = ep.spec + return EpisodeRecord(ep.key, s.problem.problem_id, s.sample_idx, ep.turns, rows, ep.terminal, + ep.solved_turn, terms, u, n_gen) + + def _rows(self, ep: _Ep) -> list: + if self.cfg.layout == "per_turn": + out = [] + for t, g in zip(ep.turns, ep.gens): + n = len(g.token_ids) + out.append(TrainingRow( + list(t.prompt_ids) + list(g.token_ids), + [0] * len(t.prompt_ids) + [1] * n, + [-1] * len(t.prompt_ids) + [t.turn] * n, + ([0.0] * len(t.prompt_ids) + list(g.logprobs)) if g.logprobs is not None else None, + )) + return out + ids, mask, tids, lp, have_lp = [], [], [], [], all(g.logprobs is not None for g in ep.gens) + for t, g in zip(ep.turns, ep.gens): + n_ctx = len(t.prompt_ids) - len(ids) # new context tokens (prompt / feedback glue) + ids += list(t.prompt_ids[len(ids):]) + mask += [0] * n_ctx + tids += [-1] * n_ctx + lp += [0.0] * n_ctx + ids += list(g.token_ids) + mask += [1] * len(g.token_ids) + tids += [t.turn] * len(g.token_ids) + if have_lp: + lp += list(g.logprobs) + else: + lp += [0.0] * len(g.token_ids) + return [TrainingRow(ids, mask, tids, lp if have_lp else None)] diff --git a/code/align/rl/envs/subgoal_repair.py b/code/align/rl/envs/subgoal_repair.py new file mode 100644 index 0000000000000000000000000000000000000000..f4c4a414c8fc99d90b5cd71359250da488104436 --- /dev/null +++ b/code/align/rl/envs/subgoal_repair.py @@ -0,0 +1,694 @@ +"""APOLLO-style subgoal extraction and reassembly for failed Lean 4 proofs (K5 agentic arm, docs/K5_LEVERS.md). + +Pure Python (stdlib only) plus read-only Lean calls through the existing `align.verify.lean` API. Nothing here +changes the verifier: the reassembled proof is only a CANDIDATE; the strict verifier (`StrictVerifier`) is the sole +judge of acceptance, against the ORIGINAL statement. So a lemma that drifted from the goal it was cut from (the +pretty-printer is not a round trip) can cost a wasted attempt, never a false accept. + +Pipeline (APOLLO, arXiv 2505.05758, section 3; DeepSeek-Prover-V2, arXiv 2504.21801, section 2.1: "decompose, prove the +subgoals separately, recombine"): + + 1. `locate_targets` map every Lean error of a failed proof to the smallest repairable unit that contains it: + a failing `have name : T := ` (kind "have", innermost wins), a failing main-line tactic + (kind "tactic"), or "the proof ended with goals left" (kind "tail"). Errors on a `have` + HEADER (the statement itself does not elaborate) are not repairable and are reported. + 2. `build_skeleton` replace each target's text by `sorry` ("sorrifier"). Targets that contain another target are + dropped (the inner failure is the finer cut; the outer one is picked up by the next round). + 3. `plan_subgoals` run the skeleton in Lean once: its `sorries` carry the exact goal state (hypotheses and + goal) at each gap. Each state becomes a standalone `theorem k5_sg_ (hyps) : goal`, + which is checked to elaborate. These are ordinary problems for the prover. + 4. `reassemble` splice a prover-supplied tactic body back into the skeleton in place of the `sorry` + (inline: the lemma's hypotheses carry the context's names; inaccessible ones are + re-introduced with `rename_i`). Unproven gaps get their original text back. + +Coordinates. Lean errors index `compile_view(code)` (header lines removed, `p2_common.compile_view`), not the full +code. `view_line_map` translates; all text surgery happens on the FULL code so the result can be verified as is. +""" + +from __future__ import annotations + +import hashlib +import re +from dataclasses import dataclass, field +from typing import Any, Callable, Optional + +# --------------------------------------------------------------------------- lexical masking + +_OPEN = "([{⟨" +_CLOSE = ")]}⟩" + + +def mask(text: str) -> str: + """`text` with comments and string literals blanked (newlines kept), so indentation and bracket scans cannot be + fooled by prose. Same length as the input: offsets and (line, column) positions are preserved.""" + out = list(text) + i, n = 0, len(text) + while i < n: + c = text[i] + if c == "-" and text.startswith("--", i): + j = text.find("\n", i) + j = n if j < 0 else j + for k in range(i, j): + out[k] = " " + i = j + elif c == "/" and text.startswith("/-", i): + depth, j = 1, i + 2 + while j < n and depth: + if text.startswith("/-", j): + depth += 1 + j += 2 + elif text.startswith("-/", j): + depth -= 1 + j += 2 + else: + j += 1 + for k in range(i, min(j, n)): + if out[k] != "\n": + out[k] = " " + i = j + elif c == '"': + j = i + 1 + while j < n and text[j] != '"': + j += 2 if text[j] == "\\" else 1 + for k in range(i + 1, min(j, n)): + if out[k] != "\n": + out[k] = " " + i = j + 1 + else: + i += 1 + return "".join(out) + + +def strip_comments(text: str) -> str: + """`text` with block and line comments deleted (used on headers only, which hold no string literals).""" + text = re.sub(r"/-.*?-/", "", text, flags=re.S) + return re.sub(r"--[^\n]*", "", text) + + +def view_line_map(code: str) -> list[int]: + """`map[i]` = index in `code.split("\\n")` of line `i` of `compile_view(code)` (the REPL's coordinate system). + `compile_view` (the reference's `handle`) drops every line whose stripped text starts with import / set_option / + open, nothing else.""" + out = [] + for i, line in enumerate(code.split("\n")): + s = line.strip() + if s.startswith("import") or s.startswith("set_option") or s.startswith("open"): + continue + out.append(i) + return out + + +# --------------------------------------------------------------------------- proof structure + + +@dataclass +class _Lines: + """Masked, bullet-normalised working copy of the code.""" + + raw: list[str] + m: list[str] # masked lines (comments blanked); bullets `· ` replaced by two spaces + indent: list[int] + blank: list[bool] + depth_before: list[int] # open-bracket depth at the start of each line + cont: list[bool] # the line continues the previous statement at the same indent + ends: list[int] = field(default_factory=list) # extent end line of a statement starting here (-1: not a start) + + +_BULLET = re.compile(r"^(\s*)[·.](?=\s)") + + +def _analyse(code: str) -> _Lines: + raw = code.split("\n") + mk = mask(code).split("\n") + m = [] + for ln in mk: + mm = _BULLET.match(ln) + if mm: + ln = mm.group(1) + " " + ln[len(mm.group(1)) + 1:] + m.append(ln) + indent = [len(x) - len(x.lstrip(" ")) for x in m] + blank = [not x.strip() for x in m] + depth, db = 0, [] + for x in m: + db.append(depth) + for ch in x: + if ch in _OPEN: + depth += 1 + elif ch in _CLOSE: + depth = max(0, depth - 1) + cont = [False] * len(m) + prev = None + for i, x in enumerate(m): + if blank[i]: + continue + s = x.strip() + if prev is not None and (db[i] > 0 or s.startswith("<;>") or m[prev].rstrip().endswith("<;>")): + cont[i] = True + prev = i + L = _Lines(raw, m, indent, blank, db, cont) + L.ends = [-1] * len(m) + for i in range(len(m)): + if blank[i] or cont[i]: + continue + e = i + for j in range(i + 1, len(m)): + if blank[j]: + continue + if indent[j] > indent[i] or (indent[j] == indent[i] and cont[j]): + e = j + else: + break + L.ends[i] = e + return L + + +_THEOREM = re.compile(r"^\s*(?:theorem|lemma)\b") + + +@dataclass(frozen=True) +class Have: + start: int # first line + end: int # last line of the unit (inclusive) + name: str + assign_line: int # line holding the depth-0 `:=` + assign_col: int # column of that `:=` + + +def _first_assign(L: _Lines, s: int, e: int) -> Optional[tuple[int, int]]: + depth = 0 + for i in range(s, e + 1): + x = L.m[i] + for c, ch in enumerate(x): + if ch in _OPEN: + depth += 1 + elif ch in _CLOSE: + depth = max(0, depth - 1) + elif ch == ":" and depth == 0 and x.startswith(":=", c): + return i, c + return None + + +def find_haves(code: str, L: Optional[_Lines] = None) -> list[Have]: + """Every `have : T := ` unit (any nesting depth) that has a `:=`. Side-goal haves (no `:=`, closed by + following bullets) and `have ... from` are not units this module can cut.""" + L = L or _analyse(code) + out = [] + for i, x in enumerate(L.m): + if L.ends[i] < 0: + continue + s = x.strip() + if not (s.startswith("have ") or s.startswith("have:") or s.startswith("haveI ")): + continue + a = _first_assign(L, i, L.ends[i]) + if a is None: + continue + toks = s.split() + name = toks[1] if len(toks) > 1 and toks[1] not in (":", ":=") and not toks[1].startswith(("⟨", "(", ":")) else "_" + out.append(Have(i, L.ends[i], name, a[0], a[1])) + return out + + +def theorem_by_line(L: _Lines) -> Optional[tuple[int, int]]: + """(line, column just after `by`) of the main theorem's `:= by`; None when absent.""" + for i, x in enumerate(L.m): + if _THEOREM.match(x): + a = _first_assign(L, i, min(len(L.m) - 1, i + 12)) + if a is None: + return None + j = L.m[a[0]].find("by", a[1]) + return (a[0], j + 2) if j >= 0 else None + return None + + +# --------------------------------------------------------------------------- targets + + +@dataclass +class Target: + kind: str # have | tactic | tail + start: tuple[int, int] # (line, col) of the text to replace, 0-based, full-code coordinates + end: tuple[int, int] # exclusive end (line, col); for "tail" start == end (insertion point) + original: str # the replaced text, restorable verbatim + indent: int # indentation of the statement the gap lives in + name: str = "" + errors: list = field(default_factory=list) + + +def _cut(raw: list[str], a: tuple[int, int], b: tuple[int, int]) -> str: + if a[0] == b[0]: + return raw[a[0]][a[1]:b[1]] + parts = [raw[a[0]][a[1]:]] + raw[a[0] + 1:b[0]] + [raw[b[0]][:b[1]]] + return "\n".join(parts) + + +def tail_target(L: _Lines, tb: tuple[int, int]) -> Target: + """Insertion point for a `sorry` after the proof's last line: the proof ended with goals left.""" + body_lines = [i for i in range(tb[0] + 1, len(L.m)) if not L.blank[i]] + ind = min((L.indent[i] for i in body_lines), default=2) + last = max(body_lines, default=tb[0]) + pos = (last, len(L.raw[last])) + return Target("tail", pos, pos, "", ind) + + +def locate_targets(code: str, errors: list[dict], repl_code: Optional[str] = None) -> tuple[list[Target], list[dict]]: + """Map Lean errors (positions in `repl_code`, default `compile_view(code)`) to repairable targets. + + Returns (targets sorted by position, unrepairable errors with a `why`). Only severity-error messages are used. + Rules, in order, for an error at line l, column c: + * inside the rhs of a `have` -> kind "have" (innermost such have); target = text after its `:=` + * on the theorem's `:= by` line, or the proof ends with goals left -> kind "tail" + * on a `have` header (before its `:=`) -> unrepairable "have_header" (the statement itself is wrong) + * otherwise -> kind "tactic": the statement containing the error, as one unit + Targets that contain another target are dropped; the finer cut wins.""" + L = _analyse(code) + vmap = view_line_map(code) + if repl_code is not None and len(repl_code.split("\n")) != len(vmap): + raise ValueError("repl_code does not match compile_view(code): the error positions would index other lines") + haves = find_haves(code, L) + tb = theorem_by_line(L) + found: dict[tuple, Target] = {} + bad: list[dict] = [] + for e in errors: + if e.get("severity", "error") != "error" or not e.get("pos"): + continue + vl, c = int(e["pos"]["line"]) - 1, int(e["pos"]["column"]) + if not 0 <= vl < len(vmap): + bad.append({**e, "why": "position_outside_code"}) + continue + l = vmap[vl] + inside = [h for h in haves if h.start <= l <= h.end and (l, c) > (h.assign_line, h.assign_col + 1)] + if inside: + h = max(inside, key=lambda x: x.start) + rhs_start = (h.assign_line, h.assign_col + 2) + end = (h.end, len(L.raw[h.end])) + key = ("have", rhs_start) + t = found.setdefault(key, Target("have", rhs_start, end, _cut(L.raw, rhs_start, end), L.indent[h.start], h.name)) + t.errors.append(e) + continue + if tb is not None and l == tb[0]: + t = found.setdefault(("tail",), tail_target(L, tb)) + t.errors.append(e) + continue + if any(h.start <= l <= h.assign_line and (l, c) <= (h.assign_line, h.assign_col + 1) for h in haves): + bad.append({**e, "why": "have_header"}) + continue + starts = [i for i in range(l + 1) if L.ends[i] >= l and not L.blank[i]] + if not starts or (tb is not None and l < tb[0]): + bad.append({**e, "why": "no_statement"}) + continue + s = max(starts) + end = (L.ends[s], len(L.raw[L.ends[s]])) + st = (s, L.indent[s]) + t = found.setdefault(("tactic", st), Target("tactic", st, end, _cut(L.raw, st, end), L.indent[s])) + t.errors.append(e) + ts = sorted(found.values(), key=lambda t: (t.start, t.end)) + keep = [] + for t in ts: + if t.kind != "tail" and any(o is not t and o.kind != "tail" and t.start <= o.start and o.end <= t.end and (t.start, t.end) != (o.start, o.end) + for o in ts): + continue # contains a finer target + keep.append(t) + return keep, bad + + +# --------------------------------------------------------------------------- skeleton + + +GAP = "⟪K5GAP{}⟫" + + +def build_skeleton(code: str, targets: list[Target]) -> tuple[str, list[tuple[int, int]]]: + """(skeleton, [(line, col) of the i-th target's `sorry` in the skeleton]). Order of positions == order of + `targets` as given (they are applied bottom-up on a copy).""" + raw = code.split("\n") + order = sorted(range(len(targets)), key=lambda i: (targets[i].start, targets[i].end), reverse=True) + for i in order: + t = targets[i] + if t.kind == "have": + ins = " by " + GAP.format(i) + elif t.kind == "tactic": + ins = GAP.format(i) + else: # tail: a new line after the last proof line + raw.insert(t.start[0] + 1, " " * t.indent + GAP.format(i)) + continue + a, b = t.start, t.end + raw[a[0]:b[0] + 1] = [raw[a[0]][:a[1]] + ins + raw[b[0]][b[1]:]] + text = "\n".join(raw) + pos: dict[int, tuple[int, int]] = {} + out_lines = [] + for ln_no, ln in enumerate(text.split("\n")): + while True: + m = re.search(r"⟪K5GAP(\d+)⟫", ln) + if not m: + break + pos[int(m.group(1))] = (ln_no, m.start()) + ln = ln[:m.start()] + "sorry" + ln[m.end():] + out_lines.append(ln) + return "\n".join(out_lines), [pos[i] for i in range(len(targets))] + + +# --------------------------------------------------------------------------- goal state -> lemma + + +_INACC = re.compile(r"✝[⁰¹²³⁴⁵⁶⁷⁸⁹]*$") + + +@dataclass +class GoalState: + case: Optional[str] + hyps: list[tuple[list[str], str]] # (names, type) + goal: str + has_let: bool = False + + +def parse_goal_state(text: str) -> GoalState: + """Parse a Lean goal display (`case h` / `x y : T` / ... / `⊢ goal`). Wrapped lines (indented) are joined.""" + lines = text.split("\n") + case = None + blocks: list[str] = [] + goal_lines: list[str] = [] + in_goal = False + for ln in lines: + if in_goal: + goal_lines.append(ln.strip()) + elif ln.startswith("⊢"): + in_goal = True + goal_lines.append(ln[1:].strip()) + elif ln.startswith("case ") and not blocks: + case = ln[5:].strip() + elif ln.startswith((" ", "\t")) and blocks: + blocks[-1] += " " + ln.strip() + elif ln.strip(): + blocks.append(ln.strip()) + hyps, has_let = [], False + for b in blocks: + names, sep, typ = b.partition(" : ") + if not sep: + continue + if re.search(r"\s:=\s", typ): + has_let = True + hyps.append((names.split(), typ.strip())) + return GoalState(case, hyps, " ".join(goal_lines), has_let) + + +@dataclass +class Lemma: + name: str + statement: str # `theorem name (binders) :\n goal := by sorry` (no header) + rename: list[str] # `rename_i` argument list ("_" for instances); [] when no hypothesis is inaccessible + + +def lemma_from_goal(gs: GoalState, name: str) -> Optional[Lemma]: + """Standalone lemma for a goal state, or None when unsupported (let-bound hypotheses). + + Inaccessible hypotheses (`n✝`, shadowed or auto-named) get fresh names `k5h` and every later mention of the old name + in a type or the goal is rewritten, so the lemma is closed; `rename` lists them (and `_` for instances) in context order + for the `rename_i` that gives the inlined proof the same names.""" + if gs.has_let or not gs.goal: + return None + mp: dict[str, str] = {} + k = 0 + for names, _ in gs.hyps: + inst = all(_INACC.search(n) and n.startswith("inst") for n in names) + if inst: + continue + for n in names: + if _INACC.search(n): + k += 1 + mp[n] = f"k5h{k}" + pats = sorted(mp, key=len, reverse=True) + + def fix(text: str) -> str: + for old in pats: + text = re.sub(r"(? list[Gap]: + return [g for g in self.gaps if g.lemma is not None] + + @property + def complete(self) -> bool: + """Every gap has a lemma and the skeleton has no error of its own.""" + return bool(self.gaps) and all(g.lemma for g in self.gaps) and not self.residual_errors and not self.unrepairable + + +Probe = Callable[[str], dict] +"""`probe(code) -> {"errors": [...], "sorries": [{"pos": {"line","column"}, "goal": str}, ...], "view_lines": int}`: runs +`compile_view(code)` in the statement's header environment (one REPL command) and returns the error messages and the +`sorries` the REPL reports. `repl_probe` builds one from a pool worker.""" + +MAX_GAPS = 6 + + +def header_of(statement: str) -> str: + """Everything before the first `theorem`/`lemma`, comments removed: the header every derived lemma must carry.""" + m = re.search(r"\b(?:theorem|lemma)\b", statement) + head = statement[:m.start()] if m else statement + return strip_comments(head).rstrip() + "\n\n" + + +def _sorry_map(resp: dict, skeleton: str) -> dict: + vmap = view_line_map(skeleton) + out = {} + for s in resp.get("sorries", []): + p = s.get("pos") or {} + if "line" in p and 0 <= int(p["line"]) - 1 < len(vmap): + out[(vmap[int(p["line"]) - 1], int(p["column"]))] = s.get("goal", "") + return out + + +def plan_subgoals(statement: str, code: str, errors: list[dict], probe: Probe, parent_id: str = "p", + repl_code: Optional[str] = None, max_gaps: int = MAX_GAPS) -> SubgoalPlan: + """Cut a failed proof into gaps (see the module docstring). Two passes: the have / tactic cuts first; the "proof ended + with goals left" tail cut only when the skeleton still shows that error (after a parse error Lean reports a cascade + of `unsolved goals` at the theorem's `by` that vanishes once the broken step is cut).""" + targets, bad = locate_targets(code, errors, repl_code) + header = header_of(statement) + if not targets or len(targets) > max_gaps: + return SubgoalPlan(code, code, [], bad + ([{"why": f"too_many_gaps:{len(targets)}"}] if targets else []), [], header) + main = [t for t in targets if t.kind != "tail"] + tails = [t for t in targets if t.kind == "tail"] + first = main or tails + skeleton, pos = build_skeleton(code, first) + resp = probe(skeleton) + tail_gap = None + if main and tails: + L2 = _analyse(skeleton) + tb2 = theorem_by_line(L2) + vmap2 = view_line_map(skeleton) + at_by = [e for e in resp.get("errors", []) if e.get("pos") and tb2 is not None + and 0 <= int(e["pos"]["line"]) - 1 < len(vmap2) and vmap2[int(e["pos"]["line"]) - 1] == tb2[0]] + if at_by: + tt = tail_target(L2, tb2) + tt.errors = at_by + skeleton2, pos2 = build_skeleton(skeleton, [tt]) + tail_gap = (tt, pos2[0]) + skeleton = skeleton2 + resp = probe(skeleton) + sorries = _sorry_map(resp, skeleton) + gaps = [] + for i, t in enumerate(first): + gaps.append(_make_gap(t, pos[i], sorries, parent_id)) + if tail_gap is not None: + gaps.append(_make_gap(tail_gap[0], tail_gap[1], sorries, parent_id)) + resid = [e for e in resp.get("errors", []) if isinstance(e, dict)] + return SubgoalPlan(code, skeleton, gaps, bad, resid, header) + + +def _make_gap(t: Target, pos: tuple[int, int], sorries: dict, parent_id: str) -> Gap: + g = Gap(t, pos) + goal = sorries.get(pos) + if goal is None: + g.why_not = "no_sorry_reported" + return g + g.goal_state = goal + h = hashlib.sha256((parent_id + "|" + goal).encode()).hexdigest()[:10] + lem = lemma_from_goal(parse_goal_state(goal), f"k5_sg_{h}") + if lem is None: + g.why_not = "unsupported_goal_state" + else: + g.lemma = lem + return g + + +def lemma_problem_statement(plan: SubgoalPlan, gap: Gap) -> str: + """The reference statement for the prover: header + the lemma ending `:= by sorry` (what `lean_gen` problems carry).""" + assert gap.lemma is not None + return plan.header + gap.lemma.statement + + +# --------------------------------------------------------------------------- reassembly + + +_LEMMA_HEAD = re.compile(r"theorem\s+(\S+)[\s\S]*?:=\s*by", re.M) + + +def lemma_body(lemma_code: str, lemma_name: str) -> Optional[str]: + """The tactic text after the lemma's own `:= by` in a prover-produced code (`lean_code` of a record), or None when + the code is not a proof of exactly that lemma (another declaration, no body). Comments are masked for the search.""" + mk = mask(lemma_code) + m = None + for cand in re.finditer(r"theorem\s+" + re.escape(lemma_name) + r"\b[\s\S]*?:=\s*by", mk): + m = cand + break + if m is None: + return None + body = lemma_code[m.end():] + if re.search(r"^\s*(?:theorem|lemma)\s", mask(body), re.M): + return None # a second declaration: not an inline-able body + return body + + +def _indent_block(body: str, indent: int) -> list[str]: + ls = body.split("\n") + while ls and not ls[0].strip(): + ls.pop(0) + while ls and not ls[-1].strip(): + ls.pop() + if not ls: + return [] + first = ls[0] + # `:= by simp` leaves the first tactic on the lemma's line: its text starts after one space + if body[:1] not in ("\n", "\r") and body.strip(): + ls[0] = first.strip() + rest = [x for x in ls[1:]] + mi = min((len(x) - len(x.lstrip(" ")) for x in rest if x.strip()), default=0) + return [" " * indent + ls[0]] + [" " * indent + x[mi:] if x.strip() else "" for x in rest] + mi = min(len(x) - len(x.lstrip(" ")) for x in ls if x.strip()) + return [" " * indent + x[mi:] if x.strip() else "" for x in ls] + + +def reassemble(plan: SubgoalPlan, bodies: dict[int, str], restore_unproven: bool = True) -> Optional[str]: + """Full code with each proven gap's tactic body spliced in. + + `bodies[i]` = tactic text for `plan.gaps[i]` (from `lemma_body`). An unproven gap gets its original text back when + `restore_unproven` (the result is then still a failing proof, but with every proven cut fixed: a better parent for + the next round), else the function returns None as soon as one is missing.""" + raw = plan.skeleton.split("\n") + for i in sorted(range(len(plan.gaps)), key=lambda k: plan.gaps[k].sorry_pos, reverse=True): + g = plan.gaps[i] + ln, col = g.sorry_pos + line = raw[ln] + assert line[col:col + 5] == "sorry", "skeleton drifted from the plan" + body = bodies.get(i) + if body is None or not body.strip(): + if not restore_unproven: + return None + if g.target.kind == "have": # the skeleton holds `... := by sorry`: put the original rhs back + raw[ln] = line[:col - len(" by ")] + g.target.original + line[col + 5:] + elif g.target.kind == "tactic": + raw[ln] = line[:col] + g.target.original + line[col + 5:] + else: + del raw[ln] + continue + pre = ["rename_i " + " ".join(g.lemma.rename)] if g.lemma is not None and g.lemma.rename else [] + if g.target.kind == "have": + ind = g.target.indent + 2 + raw[ln:ln + 1] = [line[:col].rstrip()] + [" " * ind + p for p in pre] + _indent_block(body, ind) + elif g.target.kind == "tactic": + blk = [" " * g.target.indent + p for p in pre] + _indent_block(body, g.target.indent) + raw[ln:ln + 1] = [line[:col] + blk[0].lstrip()] + blk[1:] + else: # tail: the inserted line holds only the gap + raw[ln:ln + 1] = [" " * g.target.indent + p for p in pre] + _indent_block(body, g.target.indent) + return "\n".join(raw) + + +# --------------------------------------------------------------------------- Lean (read-only use of align.verify.lean) + + +def repl_probe(worker: Any, statement: str, timeout_s: float = 120.0) -> Probe: + """A `Probe` over one pool worker (a `Worker` from `ReplPool.acquire`/`map`): the statement's header environment is + built (cached by the worker) and `compile_view(code)` is run in it, exactly as `verify_generations.collect_feedback` + does. Read-only: no change to the verifier, the pool or its limits.""" + from align.verify.lean.strict import parse_statement + + ref = parse_statement(statement) + if not ref.ok: + raise ValueError(f"statement not supported by the strict parser: {ref.problem}") + + def probe(code: str) -> dict: + view = "\n".join(code.split("\n")[i] for i in view_line_map(code)) + env = worker.header_env(ref.header_text, "") + resp = worker.command(view, env, timeout_s) + errs = [{"severity": "error", "pos": m.get("pos"), "endPos": m.get("endPos"), "data": m.get("data", "")} + for m in resp.get("messages", []) if isinstance(m, dict) and m.get("severity") == "error"] + return {"errors": errs, "sorries": resp.get("sorries", []), "view": view} + + return probe + + +def check_lemma_elaborates(worker: Any, plan: SubgoalPlan, gap: Gap, timeout_s: float = 120.0) -> bool: + """True iff `lemma_problem_statement` elaborates (no error; the `sorry` warning is expected). Gaps whose lemma does + not elaborate (pretty-printer round-trip failures) are dropped by the caller, not sent to the prover.""" + from align.verify.lean.strict import parse_statement + + stmt = lemma_problem_statement(plan, gap) + ref = parse_statement(stmt) + if not ref.ok: + return False + env = worker.header_env(ref.header_text, "") + view = stmt[len(plan.header):] + resp = worker.command(view, env, timeout_s) + return not any(isinstance(m, dict) and m.get("severity") == "error" for m in resp.get("messages", [])) + + +# --------------------------------------------------------------------------- (de)serialisation (route -> assemble hand-off) + + +def plan_to_dict(plan: SubgoalPlan) -> dict: + return { + "code": plan.code, "skeleton": plan.skeleton, "header": plan.header, + "unrepairable": plan.unrepairable, "residual_errors": plan.residual_errors, + "gaps": [{ + "kind": g.target.kind, "start": list(g.target.start), "end": list(g.target.end), "original": g.target.original, + "indent": g.target.indent, "name": g.target.name, "sorry_pos": list(g.sorry_pos), "goal_state": g.goal_state, + "why_not": g.why_not, + "lemma": None if g.lemma is None else {"name": g.lemma.name, "statement": g.lemma.statement, "rename": g.lemma.rename}, + } for g in plan.gaps], + } + + +def plan_from_dict(d: dict) -> SubgoalPlan: + gaps = [] + for g in d["gaps"]: + t = Target(g["kind"], tuple(g["start"]), tuple(g["end"]), g["original"], g["indent"], g.get("name", "")) + lem = None if g["lemma"] is None else Lemma(g["lemma"]["name"], g["lemma"]["statement"], list(g["lemma"]["rename"])) + gaps.append(Gap(t, tuple(g["sorry_pos"]), g.get("goal_state"), lem, g.get("why_not"))) + return SubgoalPlan(d["code"], d["skeleton"], gaps, d.get("unrepairable", []), d.get("residual_errors", []), d["header"]) diff --git a/code/align/rl/lean_rl.py b/code/align/rl/lean_rl.py new file mode 100644 index 0000000000000000000000000000000000000000..8c27b3d1d5ef58be3590fed2aa2f7b81bfed7677 --- /dev/null +++ b/code/align/rl/lean_rl.py @@ -0,0 +1,659 @@ +"""Single-turn on-policy RL for Lean provers (lane R): config, rollout->batch, losses, gradient step. + +The run loop, checkpoints, ledger and PEFT export live in `align.rl.lean_rl_run`; the CLI is +`scripts/p2/rl_lean.py`. Nothing here imports vLLM or runs Lean: generation and verification are +file contracts (the P2 Generation / Verification JSONL records), so this module is testable on CPU +with a fake generator and a fake verifier. + +THREE LOGPROB BASES, kept apart and stamped (Codex P13-32, audit U04-3): + behaviour log pi_infer(token) recorded by the sampler at sampling time (`sampling_logprobs`). + Requires top_p == 1.0 and top_k disabled: under a truncated sampler the sampled + distribution is NOT softmax(logits/T), so no trainer-side ratio against it is meaningful. + old trainer logprobs at the rollout-time weights. Single optimizer step per iteration: this is + `current.detach()` (no extra forward); it is used ONLY for the engine-mismatch telemetry + |old - behaviour|, never as the importance denominator. + current the differentiable forward of the step. +The importance ratio is r = pi_current / pi_BEHAVIOUR, so the CISPO clamp (and the PPO clip of +`dr_grpo`) is a trust region against the policy that actually produced the tokens, including checkpoint +lag and the sampler/trainer kernel mismatch (U04-3). No separate rho factor exists to double count. + +LOSS MODES (all token-level, all normalised by an EXPLICIT global token count, see `norm_count`): + cispo -A * sg(min(r, 1+eps_high)[, floor 1-eps_low]) * log pi (MiniMax-M1 Eq. 4-5) + dr_grpo PPO clip max(-A r, -A clip(r, 1-lo, 1+hi)), centered advantages, no std, no length norm + ei -log pi on ACCEPTED samples only, weight 1: the same pipeline with negatives dropped + (K1: positive-only SFT vs signed updates on the SAME cached rollouts, Codex P13-12) +Optional `neg_seq_ratio_floor` (cispo / dr_grpo): a sequence with A < 0 whose geometric-mean ratio is below +the floor is masked whole (pushing down what the policy already made unlikely is the unstable direction). + +LOSS NORMALISATION (Codex P13-31). loss = sum_tokens(per-token loss) / N, N = the number of RESPONSE tokens +of every sample the batch builder kept, over ALL micro-batches of ALL ranks (each rank all-reduces its local +count and the result is checked against the count of the full list). Loss-time masks (negative-sequence +mask, ratio clamp) do not shrink N: a masked token still counts, exactly as a clipped token does in DAPO. +Consequence tested: the gradient is invariant to micro-batch partitioning and to the number of ranks. + +REWARDS. accepted -> 1.0, rejected -> 0.0. A verdict whose reason is in `no_signal_reasons` (timeout, and +infra deaths) is MASKED: dropped from the batch AND from its group's baseline, never scored 0. +Advantages are group-centered over the valid samples only (Dr.GRPO: no /std). +""" + +from __future__ import annotations + +import dataclasses +import hashlib +import json +import math +import random +from dataclasses import dataclass, field +from typing import Any, Optional, Sequence + +import numpy as np +import torch + +from align.rl.advantages import DEAD_ATOL, GroupFilterStats +from align.rl.cispo import cispo_policy_loss, fp32_head_forward +from align.rl.ops import log_softmax_and_gather + +LOSS_MODES = ("cispo", "dr_grpo", "ei") +NORMS = ("global_token_mean", "constant") +#: Verdict reasons that carry NO reward signal. `memory` / `output_too_large` are deliberately absent: a +#: proof that kills its REPL is the policy's doing and scores 0 (scripts/p2/verify_generations.py). +DEFAULT_NO_SIGNAL = ("timeout", "crash", "protocol") + + +class RLConfigError(ValueError): + """A config that cannot launch.""" + + +# ---------------------------------------------------------------------------------------- config + + +@dataclass +class LossCfg: + mode: str = "cispo" + eps_high: float = 4.0 # CISPO IS-weight clamp (pre-registered sweep knob; paper does not state it) + eps_low: Optional[float] = None # None = no lower clamp (the paper's setting) + clip_lower: float = 0.2 # dr_grpo PPO clip + clip_higher: float = 0.28 + neg_seq_ratio_floor: Optional[float] = None + norm: str = "global_token_mean" + constant: float = 0.0 # denominator when norm == "constant" + fp32_head: bool = False + fp32_head_chunk_tokens: int = 2048 + temperature: float = 1.0 + max_grad_norm: float = 1.0 + + def validate(self) -> None: + if self.mode not in LOSS_MODES: + raise RLConfigError(f"loss.mode={self.mode!r}: one of {LOSS_MODES}") + if self.norm not in NORMS: + raise RLConfigError(f"loss.norm={self.norm!r}: one of {NORMS}") + if self.norm == "constant" and not self.constant > 0: + raise RLConfigError("loss.norm=constant needs loss.constant > 0") + if not (self.eps_high > 0 and math.isfinite(self.eps_high)): + raise RLConfigError("loss.eps_high must be finite and > 0") + if self.eps_low is not None and not (self.eps_low > 0 and math.isfinite(self.eps_low)): + raise RLConfigError("loss.eps_low must be None or finite > 0") + if self.neg_seq_ratio_floor is not None and not (0 < self.neg_seq_ratio_floor < 1): + raise RLConfigError("loss.neg_seq_ratio_floor must be in (0, 1)") + if self.neg_seq_ratio_floor is not None and self.mode == "ei": + raise RLConfigError("neg_seq_ratio_floor is meaningless in ei mode (no negatives)") + if not self.temperature > 0: + raise RLConfigError("loss.temperature must be > 0") + + +@dataclass +class BatchCfg: + group_size: int = 8 # G rollouts per prompt + min_valid_per_group: int = 2 # after masking timeouts; fewer -> group dropped + no_signal_reasons: tuple = DEFAULT_NO_SIGNAL + #: ei only: keep the positives of all-solved groups (rejection-sampling FT keeps them); signed modes always + #: drop dead groups (zero advantage = zero gradient, wasted tokens). + ei_keep_all_solved: bool = True + micro_tokens: int = 16384 # padded tokens per micro-batch (rows x max len) + max_total_len: int = 0 # >0: drop samples whose prompt+completion exceeds this (counted) + + +@dataclass +class RolloutCfg: + top_p: float = 1.0 # REQUIRED 1.0 (Codex P13-32) + top_k: int = 0 + temperature: float = 1.0 + cap_tokens: int = 16384 + max_model_len: int = 20480 + tp: int = 4 + adapter_mode: str = "unmerged" # "unmerged" (vLLM LoRARequest) | "merged_export" (fallback) + rollout_python: str = ".venv-rollout/bin/python" + gen_extra_args: tuple = () + + def validate(self) -> None: + if self.top_p != 1.0: + raise RLConfigError(f"rollout.top_p={self.top_p}: RL rollouts need top_p == 1.0 (Codex P13-32)") + if self.top_k not in (0, -1): + raise RLConfigError(f"rollout.top_k={self.top_k}: must be 0/-1 (disabled)") + if self.adapter_mode not in ("unmerged", "merged_export"): + raise RLConfigError(f"rollout.adapter_mode={self.adapter_mode!r}") + + +@dataclass +class OptimCfg: + lr: float = 1e-5 + betas: tuple = (0.9, 0.95) + weight_decay: float = 0.0 + eps: float = 1e-8 + warmup_iters: int = 0 + steps_per_iteration: int = 1 # optimizer steps taken on one rollout batch + + +@dataclass +class LoraCfg: + r: int = 64 + alpha: float = 128.0 + rslora: bool = False + targets: tuple = ("q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj") + adapter: str = "policy" + param_dtype: str = "float32" + + +@dataclass +class RLConfig: + run_name: str = "p2-rl-lean" + run_dir: str = "" + model_snapshot: str = "" # HF snapshot dir of the base (Goedel-8B / Kimina-Distill-8B) + problems: str = "" # P2 problem jsonl (training pool) + iterations: int = 1 + prompts_per_iter: int = 8 + seed: int = 0 + keep_checkpoints: int = 2 + export_merged: bool = False + replay_from: str = "" + verify_workers: int = 8 + verify_budget_s: float = 180.0 + verify_python: str = ".venv/bin/python" + loss: LossCfg = field(default_factory=LossCfg) + batch: BatchCfg = field(default_factory=BatchCfg) + rollout: RolloutCfg = field(default_factory=RolloutCfg) + optim: OptimCfg = field(default_factory=OptimCfg) + lora: LoraCfg = field(default_factory=LoraCfg) + + def validate(self) -> None: + self.loss.validate() + self.rollout.validate() + if self.loss.temperature != self.rollout.temperature: + raise RLConfigError( + f"loss.temperature={self.loss.temperature} != rollout.temperature={self.rollout.temperature}: the " + "trainer must score tokens under the distribution that sampled them" + ) + if self.batch.group_size < 2: + raise RLConfigError("batch.group_size must be >= 2 (a group of 1 has no baseline)") + if self.batch.min_valid_per_group < 2: + raise RLConfigError("batch.min_valid_per_group must be >= 2") + if self.prompts_per_iter < 1 or self.iterations < 1: + raise RLConfigError("prompts_per_iter and iterations must be >= 1") + if self.optim.steps_per_iteration < 1: + raise RLConfigError("optim.steps_per_iteration must be >= 1") + if self.loss.mode == "cispo" and self.loss.fp32_head and self.loss.fp32_head_chunk_tokens < 1: + raise RLConfigError("fp32_head_chunk_tokens must be >= 1") + + def fingerprint(self) -> str: + """Hash of everything that changes the experiment (not paths of scratch). A resume under a different + fingerprint is a different run and is refused.""" + d = dataclasses.asdict(self) + for k in ("run_dir", "run_name", "iterations", "replay_from", "verify_workers", "keep_checkpoints", "export_merged"): + d.pop(k, None) + return hashlib.sha256(json.dumps(d, sort_keys=True, default=str).encode()).hexdigest() + + +_SECTIONS = {"loss": LossCfg, "batch": BatchCfg, "rollout": RolloutCfg, "optim": OptimCfg, "lora": LoraCfg} + + +def config_from_dict(d: dict) -> RLConfig: + """Strict: an unknown key anywhere is an error (a typo'd knob silently keeping its default is how a + pre-registered setting gets lost).""" + d = dict(d) + kw: dict[str, Any] = {} + for name, cls in _SECTIONS.items(): + sec = dict(d.pop(name, {})) + names = {f.name for f in dataclasses.fields(cls)} + bad = sorted(set(sec) - names) + if bad: + raise RLConfigError(f"[{name}] unknown keys {bad}") + for k, v in list(sec.items()): + if isinstance(v, list): + sec[k] = tuple(v) + kw[name] = cls(**sec) + names = {f.name for f in dataclasses.fields(RLConfig)} - set(_SECTIONS) + bad = sorted(set(d) - names) + if bad: + raise RLConfigError(f"unknown top-level keys {bad}") + cfg = RLConfig(**d, **kw) + cfg.validate() + return cfg + + +def load_config(path: str, overrides: Sequence[str] = ()) -> RLConfig: + import tomllib + + with open(path, "rb") as f: + d = tomllib.load(f) + for ov in overrides: + key, _, raw = ov.partition("=") + try: + val = tomllib.loads(f"v = {raw}")["v"] + except tomllib.TOMLDecodeError: + val = raw + cur = d + parts = key.split(".") + for p in parts[:-1]: + cur = cur.setdefault(p, {}) + cur[parts[-1]] = val + return config_from_dict(d) + + +# ------------------------------------------------------------------------- prompt stream (U04-2) + + +def prompt_block(ids: Sequence[str], seed: int, per_iter: int, k: int) -> list[str]: + """The prompt ids of iteration `k`: a PURE function of (ids, seed, per_iter, k). + + Replays the stream from the start (cheap: id lists). Each pass over the set is an independent shuffle + seeded by (seed, pass index) -- epoch-indexed, so passes differ -- and the tail of one pass is carried + into the next block (nothing is dropped, every prompt is drawn once per pass). A block never repeats a + prompt unless it is larger than the pool. + """ + n = len(ids) + if n == 0: + raise ValueError("empty prompt pool") + order: list[int] = [] + cursor = 0 + passes = 0 + out: list[str] = [] + for it in range(k + 1): + block: list[int] = [] + while len(block) < per_iter: + if cursor >= len(order): + order = list(range(n)) + random.Random(seed * 1000003 + passes * 7919 + 11).shuffle(order) + passes += 1 + cursor = 0 + i = order[cursor] + if per_iter <= n and i in block: + for j in range(cursor + 1, len(order)): + if order[j] not in block: + order[cursor], order[j] = order[j], order[cursor] + i = order[cursor] + break + cursor += 1 + block.append(i) + out = [ids[i] for i in block] + return out + + +def stream_position(n_pool: int, per_iter: int, k: int) -> dict: + """Position stored in the checkpoint (draws made, pass index); recomputable, kept as a cross-check.""" + draws = k * per_iter + return {"draws": draws, "pass": draws // n_pool, "offset": draws % n_pool} + + +# -------------------------------------------------------------------------------- rollout -> batch + + +@dataclass +class Sample: + key: tuple # (problem_id, sample_idx, round, cap_tokens) + group: str # problem_id + prompt_ids: list + completion_ids: list + behaviour_lp: list # one per completion token + reward: float + adv: float = 0.0 + + @property + def n_resp(self) -> int: + return len(self.completion_ids) + + @property + def total_len(self) -> int: + return len(self.prompt_ids) + len(self.completion_ids) + + +def validate_rl_generation(rec: dict) -> None: + """The rollout-time contract an RL record must meet (raises with the key named).""" + key = (rec.get("problem_id"), rec.get("sample_idx")) + s = rec.get("sampling") or {} + if s.get("top_p") != 1.0: + raise RLConfigError(f"{key}: sampling.top_p={s.get('top_p')!r}; RL rollouts require top_p == 1.0") + if s.get("top_k") not in (0, -1, None): + raise RLConfigError(f"{key}: sampling.top_k={s.get('top_k')!r}; RL rollouts require top_k disabled") + lp = rec.get("sampling_logprobs") + comp = rec.get("completion_ids") + if not isinstance(lp, list) or not isinstance(comp, list) or len(lp) != len(comp) or not comp: + raise RLConfigError(f"{key}: sampling_logprobs must be a list aligned with completion_ids") + arr = np.asarray(lp, dtype=np.float64) + if not np.all(np.isfinite(arr)) or np.any(arr > 1e-4): + raise RLConfigError(f"{key}: sampling_logprobs must be finite and <= 0") + + +def reward_of(ver: dict, no_signal: Sequence[str]) -> tuple[Optional[float], Optional[str]]: + """(reward, None) or (None, why-masked). Timeouts / infra deaths carry NO signal.""" + reasons = list(ver.get("reasons") or []) + if ver.get("accepted"): + return 1.0, None + hit = [r for r in reasons if r in no_signal] + if hit: + return None, hit[0] + return 0.0, None + + +def build_samples(gens: Sequence[dict], vers: dict, cfg: RLConfig) -> tuple[list[Sample], dict]: + """Join generations with verdicts -> trainable samples + telemetry. + + Dead groups (all-rewards-equal over the VALID samples) are dropped in signed modes; `ei` keeps the + positives of all-solved groups when `batch.ei_keep_all_solved`. Masked (no-signal) samples are removed + before the baseline is computed. + """ + b = cfg.batch + stats = {"samples": len(gens), "masked": collections_counter(), "groups": 0, "groups_too_few_valid": 0, + "dropped_overlength": 0, "accepted": 0, "valid": 0} + by_group: dict[str, list[Sample]] = {} + for g in gens: + validate_rl_generation(g) + key = (g["problem_id"], g["sample_idx"], g["round"], g["cap_tokens"]) + v = vers.get(key) + if v is None: + raise RLConfigError(f"{key}: generation has no verification record (verify before training)") + r, why = reward_of(v, b.no_signal_reasons) + if r is None: + stats["masked"][why] += 1 + continue + s = Sample(key, g["problem_id"], list(g["prompt_ids"]), list(g["completion_ids"]), + [float(x) for x in g["sampling_logprobs"]], r) + if b.max_total_len and s.total_len > b.max_total_len: + stats["dropped_overlength"] += 1 + continue + stats["valid"] += 1 + stats["accepted"] += int(r == 1.0) + by_group.setdefault(g["problem_id"], []).append(s) + fstats = GroupFilterStats(max_possible_score=1.0) + out: list[Sample] = [] + for pid in sorted(by_group): + grp = sorted(by_group[pid], key=lambda s: s.key) + stats["groups"] += 1 + if len(grp) < b.min_valid_per_group: + stats["groups_too_few_valid"] += 1 + continue + rewards = np.array([s.reward for s in grp]) + dead = fstats.observe(rewards) + if cfg.loss.mode == "ei": + keep = [s for s in grp if s.reward == 1.0] + all_solved = bool(np.all(rewards == 1.0)) + if not keep or (all_solved and not b.ei_keep_all_solved): + continue + for s in keep: + s.adv = 1.0 + out.extend(keep) + continue + if dead: + continue + mean = float(rewards.mean()) + for s in grp: + s.adv = s.reward - mean + out.extend(grp) + stats["masked"] = dict(stats["masked"]) + stats["group_filter"] = fstats.as_log_dict() + stats["kept_samples"] = len(out) + stats["kept_resp_tokens"] = sum(s.n_resp for s in out) + return out, stats + + +def collections_counter(): + import collections + + return collections.Counter() + + +# ------------------------------------------------------------------------------- sharding / packing + + +def shard_samples(samples: Sequence[Sample], world: int) -> list[list[Sample]]: + """Deterministic length-balanced split (longest-first onto the lightest rank).""" + order = sorted(samples, key=lambda s: (-s.total_len, s.key)) + loads = [0] * world + shards: list[list[Sample]] = [[] for _ in range(world)] + for s in order: + r = min(range(world), key=lambda i: (loads[i], i)) + shards[r].append(s) + loads[r] += s.total_len + return shards + + +@dataclass +class Micro: + input_ids: torch.Tensor # [B, T] + attention_mask: torch.Tensor # [B, T] + resp: torch.Tensor # [B, T-1] bool, label space + behaviour: torch.Tensor # [B, T-1] + adv: torch.Tensor # [B] + dummy: bool = False + + @property + def n_resp(self) -> int: + return 0 if self.dummy else int(self.resp.sum()) + + +def pack_micros(samples: Sequence[Sample], micro_tokens: int, pad_id: int = 0, dtype=torch.float32) -> list[Micro]: + """Token-budget micro-batches (rows x padded max length <= micro_tokens; a longer lone row gets its own).""" + rows = sorted(samples, key=lambda s: (s.total_len, s.key)) + micros: list[Micro] = [] + cur: list[Sample] = [] + cur_max = 0 + for s in rows: + m = max(cur_max, s.total_len) + if cur and m * (len(cur) + 1) > micro_tokens: + micros.append(_collate(cur, pad_id, dtype)) + cur, m = [], s.total_len + cur.append(s) + cur_max = m + if cur: + micros.append(_collate(cur, pad_id, dtype)) + return micros + + +def _collate(rows: Sequence[Sample], pad_id: int, dtype) -> Micro: + T = max(s.total_len for s in rows) + B = len(rows) + ids = torch.full((B, T), pad_id, dtype=torch.int64) + att = torch.zeros((B, T), dtype=torch.int64) + resp = torch.zeros((B, T - 1), dtype=torch.bool) + beh = torch.zeros((B, T - 1), dtype=dtype) + adv = torch.zeros(B, dtype=dtype) + for i, s in enumerate(rows): + n = s.total_len + ids[i, :n] = torch.tensor(s.prompt_ids + s.completion_ids) + att[i, :n] = 1 + p = len(s.prompt_ids) + resp[i, p - 1 : n - 1] = True # label t+1 in the completion + beh[i, p - 1 : n - 1] = torch.tensor(s.behaviour_lp, dtype=dtype) + adv[i] = s.adv + return Micro(ids, att, resp, beh, adv) + + +def dummy_micro(like: Optional[Micro], pad_id: int = 0, dtype=torch.float32) -> Micro: + """A micro that trains on nothing but runs the same forward/backward (so every rank issues the same + collectives): one row, empty response mask, zero advantage.""" + if like is not None: + n = int(like.attention_mask[0].sum()) + ids = like.input_ids[:1, :n].clone() + else: + ids = torch.full((1, 2), pad_id, dtype=torch.int64) + T = ids.shape[1] + return Micro(ids, torch.ones_like(ids), torch.zeros((1, T - 1), dtype=torch.bool), + torch.zeros((1, T - 1), dtype=dtype), torch.zeros(1, dtype=dtype), dummy=True) + + +# ---------------------------------------------------------------------------------------- the loss + + +def token_loss(new_lp: torch.Tensor, behaviour: torch.Tensor, adv: torch.Tensor, resp: torch.Tensor, + cfg: LossCfg) -> tuple[torch.Tensor, dict]: + """Unreduced per-token loss [B, T-1] (zero off the response mask) + diagnostic tensors. + + ratio = exp(new - behaviour): importance weight against the BEHAVIOUR policy (U04-3). + """ + m = resp.to(new_lp.dtype) + A = adv.to(new_lp.dtype).unsqueeze(-1).expand_as(new_lp) + diff = (new_lp - behaviour).clamp(-20.0, 20.0) + ratio = torch.exp(diff) + clipfrac = torch.zeros_like(new_lp) + row_w = torch.ones(new_lp.shape[0], dtype=new_lp.dtype, device=new_lp.device) + if cfg.mode == "ei": + loss = -new_lp + else: + if cfg.mode == "cispo": + loss, clipfrac = cispo_policy_loss(new_lp, ratio, A, cfg.eps_high, cfg.eps_low) + else: # dr_grpo + l1 = -A * ratio + l2 = -A * torch.clamp(ratio, 1.0 - cfg.clip_lower, 1.0 + cfg.clip_higher) + loss = torch.max(l1, l2) + clipfrac = (l2 > l1).to(new_lp.dtype) + if cfg.neg_seq_ratio_floor is not None: + n = m.sum(-1).clamp_min(1.0) + geo = torch.exp((diff.detach() * m).sum(-1) / n) + drop = (adv < 0) & (geo < cfg.neg_seq_ratio_floor) + row_w = (~drop).to(new_lp.dtype) + loss = loss * m * row_w.unsqueeze(-1) + return loss, {"ratio": ratio.detach(), "clipfrac": clipfrac.detach() * m, "row_w": row_w.detach()} + + +def policy_logprobs(model, mb: Micro, cfg: LossCfg) -> torch.Tensor: + """Label-aligned [B, T-1] logprobs of the batch's own tokens under the CURRENT policy.""" + if cfg.fp32_head: + return fp32_head_forward(model, mb.input_ids, mb.attention_mask, cfg.temperature, cfg.fp32_head_chunk_tokens) + out = model(input_ids=mb.input_ids, attention_mask=mb.attention_mask) + logits = getattr(out, "logits", out) + if cfg.temperature != 1.0: + logits = logits / cfg.temperature + return log_softmax_and_gather(logits[:, :-1], mb.input_ids[:, 1:]) + + +# ------------------------------------------------------------------------------- distributed bits + + +def _dist_on() -> bool: + import torch.distributed as dist + + return dist.is_available() and dist.is_initialized() + + +def world_size() -> int: + import torch.distributed as dist + + return dist.get_world_size() if _dist_on() else 1 + + +def all_reduce_ints(vals: list[int], op: str = "sum") -> list[int]: + if not _dist_on(): + return [int(v) for v in vals] + import torch.distributed as dist + + from align.utils.dist import gloo_group + + g = gloo_group() or dist.group.WORLD + t = torch.tensor([int(v) for v in vals], dtype=torch.int64) + dist.all_reduce(t, op=dist.ReduceOp.SUM if op == "sum" else dist.ReduceOp.MAX, group=g) + return [int(v) for v in t.tolist()] + + +def all_reduce_floats(vals: list[float]) -> list[float]: + if not _dist_on(): + return [float(v) for v in vals] + import torch.distributed as dist + + from align.utils.dist import gloo_group + + g = gloo_group() or dist.group.WORLD + t = torch.tensor([float(v) for v in vals], dtype=torch.float64) + dist.all_reduce(t, op=dist.ReduceOp.SUM, group=g) + return [float(v) for v in t.tolist()] + + +def norm_count(local_resp_tokens: int, cfg: LossCfg, expect_total: Optional[int] = None) -> float: + """The explicit loss denominator N (module docstring). Global = SUM over ranks of the local response-token + counts, verified against the full-list count when the caller can supply it.""" + if cfg.norm == "constant": + return float(cfg.constant) + total = all_reduce_ints([local_resp_tokens])[0] + if expect_total is not None and total != expect_total: + raise RuntimeError(f"global token count {total} != full-batch count {expect_total}: ranks hold different data") + if total <= 0: + raise RuntimeError("global response-token count is 0") + return float(total) + + +def _is_sharded(params: Sequence[torch.nn.Parameter]) -> bool: + return any(hasattr(p, "to_local") for p in params) + + +def accumulate_gradients(model, micros: Sequence[Micro], cfg: LossCfg, denom: float, + params: Sequence[torch.nn.Parameter], pad_id: int = 0) -> dict: + """Forward+backward over this rank's micro-batches with the GLOBAL denominator; returns summed stats. + + Every rank runs the same number of micro-steps (agreed by MAX; short ranks run zero-weight dummies). + Gradient scale: loss_i / N. FSDP2 reduce-scatter AVERAGES over ranks, so a sharded model multiplies by the + world size; a replicated model (CPU tests, single GPU) sums gradients explicitly with an all-reduce SUM. + Either way grad = d/dtheta [ sum over ALL ranks/micros/tokens of per-token loss / N ]. + """ + world = world_size() + n_agreed = all_reduce_ints([len(micros)], "max")[0] + sharded = _is_sharded(params) + scale = float(world) if (sharded and world > 1) else 1.0 + like = micros[0] if micros else None + dtype = like.behaviour.dtype if like is not None else torch.float32 + acc = {"loss_sum": 0.0, "resp_tokens": 0.0, "clip_tokens": 0.0, "ratio_sum": 0.0, "rows": 0.0, + "rows_masked_negseq": 0.0, "mismatch_abs_sum": 0.0, "adv_pos_rows": 0.0, "entropy_proxy": 0.0} + for i in range(n_agreed): + mb = micros[i] if i < len(micros) else dummy_micro(like, pad_id, dtype) + new_lp = policy_logprobs(model, mb, cfg) + tok, d = token_loss(new_lp, mb.behaviour.to(new_lp.dtype), mb.adv, mb.resp, cfg) + loss = tok.sum() / denom * scale + loss.backward() + with torch.no_grad(): + m = mb.resp.to(torch.float64) + acc["loss_sum"] += float(tok.detach().double().sum()) + acc["resp_tokens"] += float(m.sum()) + acc["clip_tokens"] += float((d["clipfrac"].double() * m).sum()) + acc["ratio_sum"] += float((d["ratio"].double() * m).sum()) + acc["mismatch_abs_sum"] += float(((new_lp.detach() - mb.behaviour.to(new_lp.dtype)).abs().double() * m).sum()) + if not mb.dummy: + acc["rows"] += float(mb.input_ids.shape[0]) + acc["rows_masked_negseq"] += float((d["row_w"] == 0).sum()) + acc["adv_pos_rows"] += float((mb.adv > 0).sum()) + if world > 1 and not sharded: + import torch.distributed as dist + + from align.utils.dist import gloo_group + + g = gloo_group() or dist.group.WORLD + for p in params: + if p.grad is None: + p.grad = torch.zeros_like(p) + dist.all_reduce(p.grad, op=dist.ReduceOp.SUM, group=g) + keys = sorted(acc) + red = all_reduce_floats([acc[k] for k in keys]) + return dict(zip(keys, red)) + + +def summarize(stats: dict, denom: float, grad_norm: float, cfg: LossCfg) -> dict: + t = max(stats["resp_tokens"], 1.0) + return { + "loss": stats["loss_sum"] / denom, + "denominator": denom, + "resp_tokens": stats["resp_tokens"], + "rows": stats["rows"], + "clipfrac": stats["clip_tokens"] / t, + "ratio_mean": stats["ratio_sum"] / t, + # engine mismatch |log pi_current(=old at step 0) - log pi_behaviour|, mean over response tokens + "old_vs_behaviour_abs_logratio": stats["mismatch_abs_sum"] / t, + "negseq_masked_rows": stats["rows_masked_negseq"], + "grad_norm": grad_norm, + "loss_mode": cfg.mode, + } diff --git a/code/align/rl/lean_rl_run.py b/code/align/rl/lean_rl_run.py new file mode 100644 index 0000000000000000000000000000000000000000..22f40080d62ee4ae27f5d434af70438d65d09495 --- /dev/null +++ b/code/align/rl/lean_rl_run.py @@ -0,0 +1,716 @@ +"""Lean RL run loop: iteration stages, atomic checkpoints, PEFT export, budget ledger, backends. + + iteration k (policy = ckpt/iter_k's adapter): + gen generator.generate -> iters/iter_k/gens.jsonl (CURRENT policy; behaviour logprobs recorded) + verify verifier.verify -> iters/iter_k/ver.jsonl + train trainer.train(k) -> ckpt/iter_{k+1}/ (adapter, optimizer, RNG, stream, ledger) + +Every stage is idempotent and commits with a marker (`gen.done`, `ver.done`) or a directory rename +(checkpoints), so a kill at any point resumes into the same state: a killed `train` leaves only a `.tmp_*` +directory, which is deleted, and the stage re-runs from the same gens/ver files and the same ckpt k. + +GPU HANDOFF. The default real flow keeps the loop process CPU-only: generation (vLLM, tp=4) and training +(torchrun, FSDP2) are separate child processes that run one after the other, so neither holds the GPUs while the +other runs; the loop itself never imports a model. `InProcessTrainer` (tests, single-device runs) calls +`train_iteration` directly. This module imports torch/numpy/safetensors/stdlib/align only. +""" + +from __future__ import annotations + +import contextlib +import hashlib +import json +import os +import shutil +import subprocess +import sys +import time +from typing import Callable, Optional + +import torch + +from align.rl import lean_rl as L +from align.utils.dist import capture_rng_state, restore_rng_state + +ADAPTER_NAME_PEFT = "adapter_model.safetensors" + + +# ------------------------------------------------------------------------------------ fs helpers + + +def fsync_dir(path: str) -> None: + fd = os.open(path, os.O_RDONLY) + try: + os.fsync(fd) + finally: + os.close(fd) + + +def atomic_write_text(path: str, text: str) -> None: + tmp = path + ".partial" + with open(tmp, "w") as f: + f.write(text) + f.flush() + os.fsync(f.fileno()) + os.replace(tmp, path) + + +def read_jsonl(path: str) -> list[dict]: + out = [] + with open(path, encoding="utf-8") as f: + for n, line in enumerate(f, 1): + if line.strip(): + try: + out.append(json.loads(line)) + except json.JSONDecodeError as e: + raise ValueError(f"{path}:{n}: {e}") from e + return out + + +def write_jsonl_atomic(path: str, rows) -> None: + atomic_write_text(path, "".join(json.dumps(r, sort_keys=True) + "\n" for r in rows)) + + +def sha256_file(path: str) -> str: + h = hashlib.sha256() + with open(path, "rb") as f: + for c in iter(lambda: f.read(1 << 20), b""): + h.update(c) + return h.hexdigest() + + +# --------------------------------------------------------------------------------- PEFT export + + +def peft_key_map(qcfg) -> dict[str, str]: + """align module path -> HF module path, for every projection LoRA can target.""" + from align.model.qwen3_checkpoint import _table + + out = {} + for hf_w, al_w in _table(qcfg).items(): + if hf_w.endswith(".weight") and ".layers." in hf_w: + out[al_w[: -len(".weight")]] = hf_w[: -len(".weight")] + return out + + +def lora_to_peft_tensors(lora_state: dict, qcfg) -> dict[str, torch.Tensor]: + m = peft_key_map(qcfg) + out = {} + for k, v in lora_state.items(): + path, ab = k.rsplit(".", 1) + if path not in m: + raise KeyError(f"adapter path {path!r} has no HF counterpart") + out[f"base_model.model.{m[path]}.lora_{ab}.weight"] = v.detach().to("cpu").contiguous() + return out + + +def peft_to_lora_state(tensors: dict, qcfg) -> dict[str, torch.Tensor]: + inv = {v: k for k, v in peft_key_map(qcfg).items()} + out = {} + for k, v in tensors.items(): + assert k.startswith("base_model.model.") + body = k[len("base_model.model."):] + hf_path, lora_ab = body.rsplit(".lora_", 1) + out[f"{inv[hf_path]}.{lora_ab.split('.')[0]}"] = v + return out + + +def write_peft_dir(out_dir: str, lora_state: dict, qcfg, lcfg: L.LoraCfg, base_name: str, dtype=torch.float32) -> None: + """A PEFT adapter directory (adapter_config.json + adapter_model.safetensors), written to a sibling temp dir + and renamed in, so a reader (vLLM) never sees half of it.""" + import safetensors.torch as st + + tmp = out_dir.rstrip("/") + ".partial" + shutil.rmtree(tmp, ignore_errors=True) + os.makedirs(tmp) + tens = {k: v.to(dtype) for k, v in lora_to_peft_tensors(lora_state, qcfg).items()} + st.save_file(tens, os.path.join(tmp, ADAPTER_NAME_PEFT), metadata={"format": "pt"}) + cfg = { + "peft_type": "LORA", "task_type": "CAUSAL_LM", "r": lcfg.r, "lora_alpha": lcfg.alpha, "lora_dropout": 0.0, + "bias": "none", "use_rslora": bool(lcfg.rslora), "target_modules": list(lcfg.targets), + "base_model_name_or_path": base_name, "inference_mode": True, "fan_in_fan_out": False, + "init_lora_weights": True, "modules_to_save": None, + } + with open(os.path.join(tmp, "adapter_config.json"), "w") as f: + json.dump(cfg, f, indent=1, sort_keys=True) + f.flush() + os.fsync(f.fileno()) + if os.path.isdir(out_dir): + shutil.rmtree(out_dir) + os.replace(tmp, out_dir) + + +def read_peft_dir(path: str, qcfg) -> dict[str, torch.Tensor]: + import safetensors.torch as st + + return peft_to_lora_state(st.load_file(os.path.join(path, ADAPTER_NAME_PEFT)), qcfg) + + +def export_merged_checkpoint(model, adapter: str, qcfg, out_dir: str, tokenizer_dir: Optional[str] = None, + dtype=torch.bfloat16) -> dict: + """FALLBACK for serving without un-merged LoRA: base+adapter folded into an HF checkpoint. Lossy by + construction (bf16 cast drops small delta elements; the fidelity report is returned). Collective under FSDP: + every rank must call; rank 0 writes.""" + from align.model.qwen3_checkpoint import save_hf_qwen3 + from align.ppo.lora import export_merged_state_dict + from align.utils.dist import is_rank0 + + if L._is_sharded(list(model.parameters())): + from torch.distributed.checkpoint.state_dict import StateDictOptions, get_model_state_dict + + sd = get_model_state_dict(model, options=StateDictOptions(full_state_dict=True, cpu_offload=True)) + else: + sd = {k: v.detach().to("cpu") for k, v in model.state_dict().items()} + report: dict = {} + if sd: + merged = export_merged_state_dict(model, sd, adapter, report=report) + if is_rank0(): + tmp = out_dir.rstrip("/") + ".partial" + shutil.rmtree(tmp, ignore_errors=True) + save_hf_qwen3(merged, tmp, cfg=qcfg, dtype=dtype, tokenizer_dir=tokenizer_dir) + if os.path.isdir(out_dir): + shutil.rmtree(out_dir) + os.replace(tmp, out_dir) + return report + + +# --------------------------------------------------------------------------------- checkpoints + + +def ckpt_path(run_dir: str, k: int) -> str: + return os.path.join(run_dir, "ckpt", f"iter_{k:06d}") + + +def latest_complete(run_dir: str) -> Optional[int]: + root = os.path.join(run_dir, "ckpt") + if not os.path.isdir(root): + return None + best = None + for name in os.listdir(root): + if name.startswith("iter_") and os.path.isfile(os.path.join(root, name, "COMPLETE")): + k = int(name[5:]) + best = k if best is None else max(best, k) + return best + + +def clean_partial(run_dir: str) -> list[str]: + """Delete half-written checkpoints (`.tmp_*`) and incomplete `iter_*` dirs: they look resumable and are not.""" + root = os.path.join(run_dir, "ckpt") + gone = [] + if not os.path.isdir(root): + return gone + for name in sorted(os.listdir(root)): + p = os.path.join(root, name) + if name.startswith(".tmp_") or (name.startswith("iter_") and not os.path.isfile(os.path.join(p, "COMPLETE"))): + shutil.rmtree(p, ignore_errors=True) + gone.append(name) + return gone + + +def _rank() -> int: + import torch.distributed as dist + + return dist.get_rank() if L._dist_on() else 0 + + +def _barrier() -> None: + import torch.distributed as dist + + if L._dist_on(): + dist.barrier() + + +def save_checkpoint(run_dir: str, k: int, *, model, optimizer, lora_state: dict, qcfg, cfg: L.RLConfig, ledger: list, + bases: dict, base_name: str, base_fingerprint: Optional[str]) -> str: + """Commit checkpoint k atomically: write everything into `.tmp_iter_k`, then rename. `COMPLETE` is the + last file written inside; the rename is the commit. `lora_state` must already be gathered (collective done + by the caller on every rank).""" + final = ckpt_path(run_dir, k) + tmp = os.path.join(run_dir, "ckpt", f".tmp_iter_{k:06d}") + r = _rank() + if r == 0: + os.makedirs(os.path.join(run_dir, "ckpt"), exist_ok=True) + shutil.rmtree(tmp, ignore_errors=True) + os.makedirs(tmp) + _barrier() + optim_sd = optimizer_state_for_save(model, optimizer) # collective on every rank + if r == 0: + torch.save(_cpu_tree(optim_sd), os.path.join(tmp, "optim.pt")) + state = { + "iteration": k, "cfg_fingerprint": cfg.fingerprint(), "world_size": L.world_size(), + "adapter": {a: t.detach().cpu() for a, t in lora_state.items()}, "rng": capture_rng_state(), + "stream": L.stream_position(_pool_size(cfg), cfg.prompts_per_iter, k), "ledger": ledger, + "bases": bases, "base_fingerprint": base_fingerprint, + } + torch.save(state, os.path.join(tmp, "state.pt")) + write_peft_dir(os.path.join(tmp, "adapter"), lora_state, qcfg, cfg.lora, base_name) + write_jsonl_atomic(os.path.join(tmp, "ledger.jsonl"), ledger) + atomic_write_text(os.path.join(tmp, "COMPLETE"), json.dumps({"iteration": k, "t": time.time()})) + _barrier() + if r == 0: + if os.path.isdir(final): + shutil.rmtree(final) + fsync_dir(tmp) + os.replace(tmp, final) + fsync_dir(os.path.dirname(final)) + write_jsonl_atomic(os.path.join(run_dir, "ledger.jsonl"), ledger) + _prune(run_dir, cfg.keep_checkpoints) + _barrier() + return final + + +def _prune(run_dir: str, keep: int) -> None: + root = os.path.join(run_dir, "ckpt") + done = sorted(n for n in os.listdir(root) if n.startswith("iter_") and os.path.isfile(os.path.join(root, n, "COMPLETE"))) + for n in done[:-max(keep, 1)]: + shutil.rmtree(os.path.join(root, n), ignore_errors=True) + + +def load_checkpoint_state(run_dir: str, k: int, cfg: L.RLConfig) -> dict: + d = ckpt_path(run_dir, k) + if not os.path.isfile(os.path.join(d, "COMPLETE")): + raise FileNotFoundError(f"no complete checkpoint {d}") + st = torch.load(os.path.join(d, "state.pt"), weights_only=True) + if st["cfg_fingerprint"] != cfg.fingerprint(): + raise RuntimeError("checkpoint was written under a different config fingerprint; refusing to resume") + return st + + +def optimizer_state_for_save(model, optimizer) -> dict: + """Optimizer state in a world-size-independent form. Replicated model: the local state (identical on every + rank). FSDP2-sharded: the FULL state via DCP (a collective; rank 0 receives it, the others {}).""" + if L._is_sharded(list(model.parameters())): + from torch.distributed.checkpoint.state_dict import StateDictOptions, get_optimizer_state_dict + + return get_optimizer_state_dict(model, optimizer, options=StateDictOptions(full_state_dict=True, cpu_offload=True)) + return optimizer.state_dict() + + +def load_optimizer(run_dir: str, k: int, model, optimizer) -> None: + p = os.path.join(ckpt_path(run_dir, k), "optim.pt") + sd = torch.load(p, weights_only=True) + if L._is_sharded(list(model.parameters())): + from torch.distributed.checkpoint.state_dict import StateDictOptions, set_optimizer_state_dict + + set_optimizer_state_dict(model, optimizer, optim_state_dict=sd, + options=StateDictOptions(full_state_dict=True, broadcast_from_rank0=False)) + else: + optimizer.load_state_dict(sd) + + +def _cpu_tree(x): + if isinstance(x, torch.Tensor): + return x.detach().cpu() + if isinstance(x, dict): + return {k: _cpu_tree(v) for k, v in x.items()} + if isinstance(x, (list, tuple)): + return type(x)(_cpu_tree(v) for v in x) + return x + + +def _pool_size(cfg: L.RLConfig) -> int: + return len(read_jsonl(cfg.problems)) + + +def load_problems(path: str) -> list[dict]: + rows = read_jsonl(path) + ids = [r["problem_id"] for r in rows] + if len(set(ids)) != len(ids): + raise ValueError(f"{path}: duplicate problem_id") + return rows + + +# ------------------------------------------------------------------------------- iteration files + + +def iter_dir(run_dir: str, k: int) -> str: + return os.path.join(run_dir, "iters", f"iter_{k:04d}") + + +def stage_marker(d: str, name: str) -> str: + return os.path.join(d, f"{name}.done") + + +def add_stage_time(d: str, stage: str, wall_s: float) -> None: + p = os.path.join(d, "stage_times.json") + cur = json.load(open(p)) if os.path.exists(p) else {} + cur[f"{stage}_wall_s"] = cur.get(f"{stage}_wall_s", 0.0) + wall_s + cur[f"{stage}_attempts"] = cur.get(f"{stage}_attempts", 0) + 1 + atomic_write_text(p, json.dumps(cur, sort_keys=True)) + + +def ledger_entry(cfg: L.RLConfig, k: int, d: str, bstats: dict, metrics: dict, train_wall_s: float, + padded_tokens: float, prev: list) -> dict: + gens = read_jsonl(os.path.join(d, "gens.jsonl")) + vers = read_jsonl(os.path.join(d, "ver.jsonl")) + st = json.load(open(os.path.join(d, "stage_times.json"))) if os.path.exists(os.path.join(d, "stage_times.json")) else {} + gen_tokens = sum(len(g["completion_ids"]) for g in gens) + ver_s = sum(float(v.get("verify_s", 0.0)) for v in vers) + e = { + "iteration": k, "loss_mode": cfg.loss.mode, "prompts": cfg.prompts_per_iter, "samples": len(gens), + "generated_tokens": gen_tokens, "prompt_tokens": sum(len(g["prompt_ids"]) for g in gens), + "verifier_seconds": ver_s, "verifier_wall_s": st.get("verify_wall_s", 0.0), + "generate_wall_s": st.get("gen_wall_s", 0.0), "train_wall_s": train_wall_s, + "train_tokens": metrics.get("resp_tokens_total", 0.0), "train_padded_tokens": padded_tokens, + "stage_attempts": {s: st.get(f"{s}_attempts", 0) for s in ("gen", "verify")}, + "updated": bool(metrics.get("updated", False)), "batch": bstats, "metrics": metrics, + "bases": metrics.get("bases", {}), + } + e["wall_s"] = e["generate_wall_s"] + e["verifier_wall_s"] + train_wall_s + keys = ("generated_tokens", "verifier_seconds", "train_tokens", "train_padded_tokens", "wall_s") + e["cumulative"] = {c: (prev[-1]["cumulative"][c] if prev else 0.0) + e[c] for c in keys} + return e + + +# ---------------------------------------------------------------------------- the train iteration + + +def bases_stamp(cfg: L.RLConfig, gens: list) -> dict: + g0 = gens[0] if gens else {} + s = g0.get("sampling", {}) + return { + "behaviour": {"source": "sampler", "field": "sampling_logprobs", "temperature": s.get("temperature"), + "top_p": s.get("top_p"), "top_k": s.get("top_k"), "model_rev": g0.get("model_rev"), + "serving": (g0.get("adapter") or {}).get("serving", "merged_or_base")}, + "old": {"source": "trainer", "weights": "rollout-time (= current at the first optimizer step)", + "role": "mismatch telemetry only; NOT the importance denominator", "fp32_head": cfg.loss.fp32_head}, + "current": {"source": "trainer", "differentiable": True, "fp32_head": cfg.loss.fp32_head, + "temperature": cfg.loss.temperature}, + "importance_ratio": "pi_current / pi_behaviour", + } + + +def lr_at(cfg: L.RLConfig, k: int) -> float: + w = cfg.optim.warmup_iters + return cfg.optim.lr * (min(1.0, (k + 1) / w) if w > 0 else 1.0) + + +def train_iteration(cfg: L.RLConfig, k: int, *, model, params, optimizer, qcfg, pad_id: int, base_name: str, + base_fingerprint: Optional[str] = None, tokenizer_dir: Optional[str] = None) -> dict: + """One training iteration on iteration k's cached gens/ver, committing checkpoint k+1. + + `model` carries the injected LoRA adapter `cfg.lora.adapter`; `params` are its trainable parameters; + `optimizer` is built over them. State is loaded from checkpoint k (adapter, optimizer, RNG).""" + from align.ppo.lora import load_lora_state_dict, lora_state_dict + + run = cfg.run_dir + d = iter_dir(run, k) + st = load_checkpoint_state(run, k, cfg) + load_lora_state_dict(model, cfg.lora.adapter, st["adapter"], strict=True) + load_optimizer(run, k, model, optimizer) + restore_rng_state(st["rng"]) + ledger = list(st["ledger"]) + if len(ledger) != k: + raise RuntimeError(f"checkpoint {k} carries {len(ledger)} ledger rows") + pos = L.stream_position(_pool_size(cfg), cfg.prompts_per_iter, k) + if st["stream"] != pos: + raise RuntimeError(f"prompt stream position {st['stream']} != recomputed {pos}") + + gens = read_jsonl(os.path.join(d, "gens.jsonl")) + vers = {(v["problem_id"], v["sample_idx"], v["round"], v["cap_tokens"]): v for v in read_jsonl(os.path.join(d, "ver.jsonl"))} + samples, bstats = L.build_samples(gens, vers, cfg) + world = L.world_size() + r = _rank() + t0 = time.perf_counter() + metrics: dict = {"updated": False, "bases": bases_stamp(cfg, gens), "resp_tokens_total": 0.0} + padded = 0.0 + if samples: + dtype = next(iter(params)).dtype + steps = cfg.optim.steps_per_iteration + groups = sorted({s.group for s in samples}) + chunks = [[s for s in samples if groups.index(s.group) % steps == i] for i in range(steps)] + step_metrics = [] + for i, chunk in enumerate(chunks): + if not chunk: + continue + mine = L.shard_samples(chunk, world)[r] + micros = L.pack_micros(mine, cfg.batch.micro_tokens, pad_id, dtype) + expect = sum(s.n_resp for s in chunk) + denom = L.norm_count(sum(m.n_resp for m in micros), cfg.loss, expect) + for p in params: + p.grad = None + t_step = time.perf_counter() + acc = L.accumulate_gradients(model, micros, cfg.loss, denom, params, pad_id) + total = torch.nn.utils.clip_grad_norm_(list(params), cfg.loss.max_grad_norm) + if hasattr(total, "full_tensor"): + total = total.full_tensor() + for g in optimizer.param_groups: + g["lr"] = lr_at(cfg, k) + optimizer.step() + if torch.cuda.is_available() and torch.cuda.is_initialized(): + torch.cuda.synchronize() + for p in params: + p.grad = None + padded += L.all_reduce_floats([float(sum(m.input_ids.numel() for m in micros))])[0] + sm = L.summarize(acc, denom, float(total), cfg.loss) + sm["step_wall_s"] = time.perf_counter() - t_step + sm["n_micro_this_rank"] = len(micros) + if torch.cuda.is_available() and torch.cuda.is_initialized(): + sm["cuda_peak_alloc_gb"] = torch.cuda.max_memory_allocated() / 2**30 + sm["cuda_peak_reserved_gb"] = torch.cuda.max_memory_reserved() / 2**30 + step_metrics.append(sm) + metrics.update(step_metrics[-1]) + metrics["steps"] = step_metrics + metrics["updated"] = True + metrics["resp_tokens_total"] = float(sum(m["resp_tokens"] for m in step_metrics)) + train_wall = time.perf_counter() - t0 + lora = lora_state_dict(model, cfg.lora.adapter) # collective under FSDP + entry = ledger_entry(cfg, k, d, bstats, metrics, train_wall, padded, ledger) + ledger.append(entry) + if cfg.export_merged: + entry["merged_export"] = export_merged_checkpoint(model, cfg.lora.adapter, qcfg, + os.path.join(ckpt_path(run, k + 1) + ".merged_tmp"), tokenizer_dir) + save_checkpoint(run, k + 1, model=model, optimizer=optimizer, lora_state=lora, qcfg=qcfg, cfg=cfg, ledger=ledger, + bases=metrics["bases"], base_name=base_name, base_fingerprint=base_fingerprint) + if cfg.export_merged and _rank() == 0: + src = ckpt_path(run, k + 1) + ".merged_tmp" + if os.path.isdir(src): + os.replace(src, os.path.join(ckpt_path(run, k + 1), "merged")) + _barrier() + return entry + + +def init_checkpoint(cfg: L.RLConfig, *, model, optimizer, qcfg, base_name: str, base_fingerprint: Optional[str] = None) -> None: + """Checkpoint 0 = the freshly initialised adapter (B = 0, so it IS the base policy) and a fresh optimizer.""" + from align.ppo.lora import lora_state_dict + + if latest_complete(cfg.run_dir) is not None: + return + save_checkpoint(cfg.run_dir, 0, model=model, optimizer=optimizer, lora_state=lora_state_dict(model, cfg.lora.adapter), qcfg=qcfg, + cfg=cfg, ledger=[], bases={}, base_fingerprint=base_fingerprint, base_name=base_name) + + +def make_optimizer(cfg: L.RLConfig, params): + return torch.optim.AdamW(list(params), lr=cfg.optim.lr, betas=tuple(cfg.optim.betas), eps=cfg.optim.eps, + weight_decay=cfg.optim.weight_decay) + + +# ----------------------------------------------------------------------------- real policy build + + +def build_real_policy(cfg: L.RLConfig) -> tuple: + """Rank-serial load of the frozen bf16 base -> GPU -> LoRA (identical init on every rank, B = 0) -> adapter-only + trainable -> activation checkpointing -> FSDP2 (world > 1). Same recipe as `align.train.qwen3_stage`, without + its RunConfig. Returns the tuple `InProcessTrainer` expects.""" + import gc + + from align.model import qwen3 as q3 + from align.model.checkpoint import load_hf_safetensors, resolve_snapshot_dir + from align.model.qwen3_checkpoint import hf_to_align, read_qwen3_config + from align.ppo.lora import LoRAConfig, inject_lora, mark_only_adapter_trainable + from align.train import fsdp + from align.train.qwen3_stage import base_fingerprint + from align.utils.dist import barrier, local_rank, rank, world_size + + snapshot = resolve_snapshot_dir(cfg.model_snapshot) + qcfg = read_qwen3_config(snapshot).replace(attn_implementation="sdpa") + device = torch.device("cuda", local_rank()) + torch.cuda.set_device(device) + model = None + for r in range(world_size()): + if rank() == r: + sd = hf_to_align(load_hf_safetensors(snapshot, dtype=torch.bfloat16), qcfg) + model = q3.Qwen3ForCausalLM.from_state_dict(qcfg, sd, device="cuda").to(device) + del sd + gc.collect() + barrier() + fp = base_fingerprint(model.state_dict()) # whole tensors, before inject/FSDP + lc = cfg.lora + gen = torch.Generator().manual_seed(cfg.seed) # identical A on every rank: FSDP2 shards, never broadcasts + hit = inject_lora(model, LoRAConfig(r=lc.r, alpha=lc.alpha, target_modules=tuple(lc.targets), rslora=lc.rslora), + adapter=lc.adapter, generator=gen) + expected = len(lc.targets) * qcfg.n_layers + if len(hit) != expected: + raise RuntimeError(f"LoRA hit {len(hit)} layers, expected {expected}") + mark_only_adapter_trainable(model, lc.adapter) + fsdp.apply_activation_checkpointing(model) + if world_size() > 1: + fsdp.apply_fsdp(model) + params = [p for p in model.parameters() if p.requires_grad] + pad = qcfg.pad_token_id if qcfg.pad_token_id is not None else (qcfg.eos_token_id or 0) + return model, params, qcfg, pad, snapshot, fp, snapshot + + +# --------------------------------------------------------------------------------------- backends + + +class InProcessTrainer: + """Trainer backend that runs `train_iteration` in this process. `builder()` -> (model, params, qcfg, pad_id, + base_name, base_fp, tokenizer_dir).""" + + def __init__(self, cfg: L.RLConfig, builder: Callable[[], tuple]): + self.cfg, self.builder = cfg, builder + + def _build(self): + model, params, qcfg, pad_id, base_name, base_fp, tok = self.builder() + return model, params, make_optimizer(self.cfg, params), qcfg, pad_id, base_name, base_fp, tok + + def init(self) -> None: + model, params, opt, qcfg, pad_id, base_name, base_fp, _ = self._build() + init_checkpoint(self.cfg, model=model, optimizer=opt, qcfg=qcfg, base_name=base_name, base_fingerprint=base_fp) + + def train(self, k: int) -> dict: + model, params, opt, qcfg, pad_id, base_name, base_fp, tok = self._build() + return train_iteration(self.cfg, k, model=model, params=params, optimizer=opt, qcfg=qcfg, pad_id=pad_id, + base_name=base_name, base_fingerprint=base_fp, tokenizer_dir=tok) + + +def repo_root() -> str: + return os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + + +class LeanGenCliGenerator: + """Real generator: `extras/vllm_rollout/lean_gen.py` as a child process (needs the genharness flags + `--lora-adapter`, `--top-p`, `--temperature` and `--record-logprobs`).""" + + def __init__(self, cfg: L.RLConfig, config_path: str = ""): + self.cfg = cfg + + def command(self, k: int, d: str, problems_path: str, adapter_dir: str, merged_dir: Optional[str], seed: int) -> list[str]: + c, ro = self.cfg, self.cfg.rollout + root = repo_root() + py = ro.rollout_python if os.path.isabs(ro.rollout_python) else os.path.join(root, ro.rollout_python) + model = c.model_snapshot + cmd = [py, os.path.join(root, "extras", "vllm_rollout", "lean_gen.py"), "--problems", problems_path, + "--out", os.path.join(d, "gens.jsonl"), "--n", str(c.batch.group_size), "--cap-tokens", str(ro.cap_tokens), + "--round", "0", "--tp", str(ro.tp), "--wait-lock", "--seed", str(seed), "--max-model-len", str(ro.max_model_len), + "--temperature", str(ro.temperature), "--top-p", "1.0", "--record-logprobs", + "--label", f"rl-lean-gen-{k}"] + if ro.adapter_mode == "unmerged": + cmd += ["--model", model, "--lora-adapter", adapter_dir] + else: + if not merged_dir: + raise L.RLConfigError("adapter_mode=merged_export needs export_merged=true") + cmd += ["--model", merged_dir] + return cmd + list(ro.gen_extra_args) + + def generate(self, k: int, d: str, problems_path: str, adapter_dir: str, merged_dir: Optional[str], seed: int) -> None: + subprocess.run(self.command(k, d, problems_path, adapter_dir, merged_dir, seed), check=True) + + +class VerifyCliVerifier: + def __init__(self, cfg: L.RLConfig): + self.cfg = cfg + + def command(self, d: str, problems_path: str) -> list[str]: + c, root = self.cfg, repo_root() + py = c.verify_python if os.path.isabs(c.verify_python) else os.path.join(root, c.verify_python) + return [py, os.path.join(root, "scripts", "p2", "verify_generations.py"), "--generations", os.path.join(d, "gens.jsonl"), + "--problems", problems_path, "--out", os.path.join(d, "ver.jsonl"), "--workers", str(c.verify_workers), + "--budget-s", str(c.verify_budget_s)] + + def verify(self, d: str, problems_path: str) -> None: + subprocess.run(self.command(d, problems_path), check=True) + + +class ReplayBackend: + """Replay cached rollouts + verdicts of another run (K1: positive-only vs signed on the SAME rollouts). + Rollouts beyond iteration 0 were sampled by the SOURCE arm's policy, so they are off-policy for this arm; + the importance ratio against the recorded behaviour logprobs keeps the update well defined.""" + + def __init__(self, src_run_dir: str): + self.src = src_run_dir + + def generate(self, k, d, problems_path, adapter_dir, merged_dir, seed) -> None: + shutil.copyfile(os.path.join(iter_dir(self.src, k), "gens.jsonl"), os.path.join(d, "gens.jsonl")) + + def verify(self, d, problems_path) -> None: + # k is encoded in d's name; copy the sibling verdicts + k = int(os.path.basename(d).split("_")[1]) + shutil.copyfile(os.path.join(iter_dir(self.src, k), "ver.jsonl"), os.path.join(d, "ver.jsonl")) + + +def torchrun_command(cfg_path: str, k: int, nproc: int, overrides=()) -> list[str]: + return ["torchrun", "--standalone", f"--nproc_per_node={nproc}", os.path.join(repo_root(), "scripts", "p2", "rl_lean.py"), + "train-iter", cfg_path, "--iteration", str(k), *[f"--set={o}" for o in overrides]] + + +class TorchrunTrainer: + def __init__(self, cfg: L.RLConfig, cfg_path: str, nproc: int, overrides=()): + self.cfg, self.cfg_path, self.nproc, self.overrides = cfg, cfg_path, nproc, tuple(overrides) + + def init(self) -> None: + subprocess.run(torchrun_command(self.cfg_path, -1, self.nproc, self.overrides), check=True) + + def train(self, k: int) -> dict: + subprocess.run(torchrun_command(self.cfg_path, k, self.nproc, self.overrides), check=True) + return {} + + +# ------------------------------------------------------------------------------------- the loop + + +def derive_seed(seed: int, k: int) -> int: + return int.from_bytes(hashlib.sha256(f"rl|{seed}|{k}".encode()).digest()[:8], "big") % (2**31) + + +def run_loop(cfg: L.RLConfig, generator, verifier, trainer, hook: Optional[Callable[[str, int], None]] = None, + until: Optional[int] = None) -> list[dict]: + """Run (or resume) iterations up to `until` (default cfg.iterations). `hook(stage, k)` fires after each + committed stage (tests inject crashes there). Returns the committed ledger.""" + run = cfg.run_dir + os.makedirs(run, exist_ok=True) + cfg_json = os.path.join(run, "run_config.json") + import dataclasses + + fp = cfg.fingerprint() + if os.path.exists(cfg_json): + old = json.load(open(cfg_json))["fingerprint"] + if old != fp: + raise RuntimeError(f"{run} was started under config {old[:12]}, this is {fp[:12]}: refusing to mix runs") + else: + atomic_write_text(cfg_json, json.dumps({"fingerprint": fp, "config": dataclasses.asdict(cfg)}, sort_keys=True, default=str, indent=1)) + clean_partial(run) + problems = load_problems(cfg.problems) + by_id = {p["problem_id"]: p for p in problems} + ids = [p["problem_id"] for p in problems] + if latest_complete(run) is None: + trainer.init() + k0 = latest_complete(run) + if k0 is None: + raise RuntimeError("no checkpoint after init") + hook = hook or (lambda stage, k: None) + end = cfg.iterations if until is None else min(until, cfg.iterations) + for k in range(k0, end): + d = iter_dir(run, k) + os.makedirs(d, exist_ok=True) + probs_path = os.path.join(d, "problems.jsonl") + if not os.path.exists(probs_path): + block = L.prompt_block(ids, cfg.seed, cfg.prompts_per_iter, k) + write_jsonl_atomic(probs_path, [by_id[i] for i in block]) + if not os.path.exists(stage_marker(d, "gen")): + gp = os.path.join(d, "gens.jsonl") + adapter_dir = os.path.join(ckpt_path(run, k), "adapter") + merged = os.path.join(ckpt_path(run, k), "merged") if cfg.export_merged else None + t0 = time.perf_counter() + gen = ReplayBackend(cfg.replay_from) if cfg.replay_from else generator + gen.generate(k, d, probs_path, adapter_dir, merged, derive_seed(cfg.seed, k)) + add_stage_time(d, "gen", time.perf_counter() - t0) + _check_generations(gp, cfg, [by_id_id["problem_id"] for by_id_id in read_jsonl(probs_path)]) + atomic_write_text(stage_marker(d, "gen"), json.dumps({"sha256": sha256_file(gp)})) + hook("gen", k) + if not os.path.exists(stage_marker(d, "verify")): + vp = os.path.join(d, "ver.jsonl") + t0 = time.perf_counter() + (ReplayBackend(cfg.replay_from) if cfg.replay_from else verifier).verify(d, probs_path) + add_stage_time(d, "verify", time.perf_counter() - t0) + n_g, n_v = len(read_jsonl(os.path.join(d, "gens.jsonl"))), len(read_jsonl(vp)) + if n_g != n_v: + raise RuntimeError(f"{n_v} verdicts for {n_g} generations") + atomic_write_text(stage_marker(d, "verify"), json.dumps({"sha256": sha256_file(vp)})) + hook("verify", k) + t0 = time.perf_counter() + trainer.train(k) + add_stage_time(d, "train_proc", time.perf_counter() - t0) # whole child: model load + step + commit + hook("train", k) + last = latest_complete(run) + return read_jsonl(os.path.join(run, "ledger.jsonl")) if last else [] + + +def _check_generations(path: str, cfg: L.RLConfig, expect_ids: list[str]) -> None: + gens = read_jsonl(path) + want = len(expect_ids) * cfg.batch.group_size + if len(gens) != want: + raise RuntimeError(f"{path}: {len(gens)} generations, expected {want} ({len(expect_ids)} prompts x G={cfg.batch.group_size})") + for g in gens: + L.validate_rl_generation(g) diff --git a/code/align/rl/lean_rl_testing.py b/code/align/rl/lean_rl_testing.py new file mode 100644 index 0000000000000000000000000000000000000000..be2ec91ac8beec75aaefbe827c9bec4bfb7d5136 --- /dev/null +++ b/code/align/rl/lean_rl_testing.py @@ -0,0 +1,174 @@ +"""TEST SUPPORT for the Lean RL loop (CPU only): a tiny Qwen3-shaped model, a FAKE generator that really +samples from it (so the loop is genuinely on-policy), and a FAKE verifier. No vLLM, no Lean. + +Not used by any real run; it lives in the package so the tests and `scripts/p2/rl_lean.py --selftest` share it. +""" + +from __future__ import annotations + +import hashlib +import json +import os +import random + +import torch + +from align.model.qwen3 import Qwen3Config, Qwen3ForCausalLM +from align.ppo.lora import LoRAConfig, inject_lora, lora_modules, mark_only_adapter_trainable +from align.rl import lean_rl as L +from align.rl import lean_rl_run as R + +TINY = Qwen3Config(name="tiny", vocab_size=48, hidden_size=32, intermediate_size=64, n_layers=2, n_heads=4, + n_kv_heads=2, head_dim=8, max_position_embeddings=256, bos_token_id=1, eos_token_id=2, + pad_token_id=0) +EOS = 2 + + +def tiny_base(seed: int = 0, dtype=torch.float32) -> Qwen3ForCausalLM: + torch.manual_seed(seed) + m = Qwen3ForCausalLM(TINY, attn_implementation="eager", device="cpu") + return m.to(dtype) + + +def tiny_policy(lcfg: L.LoraCfg, seed: int = 0, dtype=torch.float32, adapter_seed: int = 1234): + """(model, params) with LoRA injected (B = 0 unless randomised) and only the adapter trainable.""" + m = tiny_base(seed, torch.float32) + gen = torch.Generator().manual_seed(adapter_seed) + inject_lora(m, LoRAConfig(r=lcfg.r, alpha=lcfg.alpha, target_modules=tuple(lcfg.targets), rslora=lcfg.rslora), + adapter=lcfg.adapter, generator=gen) + mark_only_adapter_trainable(m, lcfg.adapter) + m = m.to(dtype) + params = [p for p in m.parameters() if p.requires_grad] + return m, params + + +def randomize_adapter(model, adapter: str, seed: int, std: float = 0.05) -> None: + g = torch.Generator().manual_seed(seed) + with torch.no_grad(): + for _, mod in lora_modules(model): + a = mod.adapters[adapter] + a.A.copy_(torch.randn(a.A.shape, generator=g) * std) + a.B.copy_(torch.randn(a.B.shape, generator=g) * std) + + +def tiny_builder(cfg: L.RLConfig, dtype=torch.float32): + def build(): + model, params = tiny_policy(cfg.lora, dtype=dtype) + return model, params, TINY, 0, "tiny-base", None, None + + return build + + +def synthetic_problems(n: int) -> list[dict]: + rows = [] + for i in range(n): + fs = f"theorem t{i} : {i} = {i} := by" + rows.append({"problem_id": f"p{i:03d}", "source": "synthetic", "split": "train", "formal_statement": fs, + "informal_prefix": "", "statement_sha": hashlib.sha256(fs.encode()).hexdigest()}) + return rows + + +def prompt_ids_for(pid: str) -> list[int]: + h = int.from_bytes(hashlib.sha256(pid.encode()).digest()[:4], "big") + rng = random.Random(h) + return [1] + [rng.randrange(3, TINY.vocab_size) for _ in range(rng.randrange(2, 6))] + + +def _key_hash(*parts) -> int: + return int.from_bytes(hashlib.sha256("|".join(map(str, parts)).encode()).digest()[:8], "big") + + +class FakeGenerator: + """Samples from the tiny model + the adapter in `adapter_dir` (the CURRENT policy), temperature 1, top_p 1, + recording the sampled-token logprobs. A real on-policy rollout, CPU-sized. `crash_in_gen` (set by a test) + kills the process mid-stage after writing nothing, like a vLLM crash before the output is complete.""" + + def __init__(self, cfg: L.RLConfig, max_new: int = 8, base_seed: int = 0, dtype=torch.float32): + self.cfg, self.max_new, self.base_seed, self.dtype = cfg, max_new, base_seed, dtype + self.calls = 0 + + def generate(self, k, d, problems_path, adapter_dir, merged_dir, seed) -> None: + from align.ppo.lora import load_lora_state_dict + + self.calls += 1 + model, _ = tiny_policy(self.cfg.lora, seed=self.base_seed, dtype=self.dtype) + load_lora_state_dict(model, self.cfg.lora.adapter, R.read_peft_dir(adapter_dir, TINY), strict=True) + model.eval() + recs = [] + for prob in R.read_jsonl(problems_path): + pid = prob["problem_id"] + prompt = prompt_ids_for(pid) + for si in range(self.cfg.batch.group_size): + g = torch.Generator().manual_seed(_key_hash(seed, pid, si)) + ids = list(prompt) + lps = [] + finish = "length" + for _ in range(self.max_new): + with torch.no_grad(): + logits = model(input_ids=torch.tensor([ids]))[0, -1].double() + lp = torch.log_softmax(logits, -1) + tok = int(torch.multinomial(lp.exp(), 1, generator=g)) + ids.append(tok) + lps.append(float(lp[tok])) + if tok == EOS: + finish = "stop" + break + comp = ids[len(prompt):] + recs.append({ + "problem_id": pid, "sample_idx": si, "round": 0, "cap_tokens": self.cfg.rollout.cap_tokens, + "prompt_ids": prompt, "completion_ids": comp, "prompt_text": "", "completion_text": " ".join(map(str, comp)), + "finish_reason": finish, "lean_code": "theorem x := by\n trivial", "messages": [], + "model_path": "tiny", "model_rev": "tiny+adapter", + "sampling": {"temperature": 1.0, "top_p": 1.0, "top_k": 0, "n": 1, "max_tokens": self.max_new, "seed": seed}, + "context_clipped": False, "parent": None, "sampling_logprobs": lps, + "adapter": {"serving": "unmerged_vllm_lora"}, + }) + R.write_jsonl_atomic(os.path.join(d, "gens.jsonl"), recs) + + +class FakeVerifier: + """accepted iff the completion contains an even token > 10 in its first 3 tokens (learnable, ~50% under a + random policy); every 9th sample by key hash is a TIMEOUT (no signal).""" + + def __init__(self, timeout_mod: int = 9): + self.timeout_mod = timeout_mod + self.calls = 0 + + def verify(self, d, problems_path) -> None: + self.calls += 1 + out = [] + for g in R.read_jsonl(os.path.join(d, "gens.jsonl")): + key = (g["problem_id"], g["sample_idx"], g["round"], g["cap_tokens"]) + timeout = self.timeout_mod and _key_hash(*key) % self.timeout_mod == 0 + ok = any(t % 2 == 0 and t > 10 for t in g["completion_ids"][:3]) + out.append({"problem_id": key[0], "sample_idx": key[1], "round": key[2], "cap_tokens": key[3], + "accepted": bool(ok and not timeout), "reasons": ["timeout"] if timeout else ([] if ok else ["compile_error"]), + "verify_s": 0.25, "budget_s": 1.0, "verifier": {"fake": True}, + "code_sha256": hashlib.sha256(g["lean_code"].encode()).hexdigest(), "stage": "fake", "diagnostics": {}}) + R.write_jsonl_atomic(os.path.join(d, "ver.jsonl"), out) + + +def synthetic_rollouts(n_prompts: int, G: int, seed: int, timeouts: int = 0, dead_prompts: int = 0, + cap: int = 64) -> tuple[list[dict], dict]: + """Random gens + verdicts with UNEVEN lengths, behaviour logprobs unrelated to any model (so the importance + ratio spans well below 1 and above the clamp), `dead_prompts` all-equal groups and `timeouts` masked samples.""" + rng = random.Random(seed) + gens, vers = [], {} + for pi in range(n_prompts): + pid = f"p{pi:03d}" + prompt = prompt_ids_for(pid) + dead = pi < dead_prompts + for si in range(G): + n = rng.randrange(1, 10) + comp = [rng.randrange(3, TINY.vocab_size) for _ in range(n)] + lps = [-rng.uniform(0.05, 4.0) for _ in range(n)] + gens.append({"problem_id": pid, "sample_idx": si, "round": 0, "cap_tokens": cap, "prompt_ids": prompt, + "completion_ids": comp, "finish_reason": "stop", "lean_code": "x", + "sampling": {"temperature": 1.0, "top_p": 1.0, "top_k": 0}, "sampling_logprobs": lps}) + acc = False if dead else (rng.random() < 0.5) + reasons = [] if acc else ["compile_error"] + vers[(pid, si, 0, cap)] = {"accepted": acc, "reasons": reasons, "verify_s": 0.1} + keys = list(vers) + for key in rng.sample([k for k in keys if int(k[0][1:]) >= dead_prompts], timeouts): + vers[key] = {"accepted": False, "reasons": ["timeout"], "verify_s": 5.0} + return gens, vers diff --git a/code/align/rl/multiturn_source.py b/code/align/rl/multiturn_source.py new file mode 100644 index 0000000000000000000000000000000000000000..9c2814a74a8fa8febd4389ce71665f7cfe0a3f50 --- /dev/null +++ b/code/align/rl/multiturn_source.py @@ -0,0 +1,454 @@ +"""Multi-turn Lean rollouts -> GRPO rows with PER-TOKEN advantages (opt-in). + +`GRPOTrainModule` used to see one scalar advantage per row, so the credit the +multi-turn env computes per turn could not reach the loss. This module is the +producer side of the fix (the consumer side is `expand_advantages` in +grpo_loss.py): it runs `align/rl/envs/lean_multiturn.py` episodes, assigns +advantages, and emits rows whose ``advantages`` is [B, T] in INPUT space, +nonzero only on tokens the policy generated. + +Every design choice below names the failure it prevents. + +ROW LAYOUT: one row per TURN (the env's ``layout="per_turn"``, the default). + * A packed row per episode is valid only when the chat template renders + turn k's prompt as an exact extension of turn k-1's prompt + completion. + Qwen3-family templates (Goedel-Prover-V2 is one) strip earlier + blocks, so the env raises `PrefixBreak` on them; per-turn rows are exact on + every template because each row carries the exact prompt ids the policy + saw at that turn. + * Memory: a per-turn row is bounded by one turn's prompt + completion, so + micro-batch padding is bounded by the single longest TURN. A packed row is + the SUM of all turns' context and pads every micro-batch row to that sum. + Per-turn rows pay for it by re-running the shared prefix (~K/2 x extra + forward tokens at K turns) -- accepted: it is bounded and the alternative + cannot always be built. + * Rows are independent in the loss. The Dr.GRPO denominator is a constant + and advantages are already per-token, so no statistic crosses rows: a + micro-slice or rank boundary that splits one episode's rows changes + nothing (a test pins that the summed loss is invariant to row order and + split). The packed layout is still accepted (the env's ``layout= + "concatenated"``) when the template permits it; the same masks and + advantages come out. + * DENOMINATOR: the constant D is per OPTIMIZER STEP. A multi-turn episode + can generate max_turns x max_response_len tokens, so D should be sized + prompts_per_step x G x max_turns x max_response_len + (`recommended_loss_denominator`); sizing it for one turn silently scales + every gradient by up to max_turns. The A3 gate still only requires a + positive finite float; the value is the caller's pre-registered choice. + +CREDIT (`MultiTurnCreditConfig`): + mode="episode" (DEFAULT): one number per episode, A_ep = R_ep - mean_group(R), + the Dr.GRPO centered advantage over the episode's TOTAL reward, broadcast + to EVERY generated token of EVERY turn. Prevents: a baseline computed on a + thinned sample (see below) and the variance of fitting a per-turn value + function from G <= 16 episodes. It is the exact single-turn algebra, so + group centering, dead-group semantics and A3 all carry over unchanged. + Its cost is credit blur: a failed first draft is rewarded for the repair + that followed. That is wrong only if the draft did not make the repair + possible; with turn_discount < 1 the solved-late episode already scores + lower than a solved-first one, which is the ordering we want taught. + mode="per_turn_loo": turn t gets G_t - b_t, G_t = sum_{s>=t} gamma^(s-t) u_s + (the env's return; gamma=0 -> each turn judged on its own outcome). + turn 0 : b_0 = mean over the WHOLE group. Every episode has a turn 0, + so this is the ordinary group baseline and the turn-0 + advantages are exactly centered. + turn t>=1: b_t = mean over the OTHER episodes of the group that reached + turn t (leave-one-out). The old rule averaged over ALL + episodes that reached turn t INCLUDING self; with one repair + in the group the baseline was the sample's own return, so the + lone repair that SOLVED the problem got advantage exactly 0 + (and one that failed also 0). LOO removes self-inclusion, and + the LOO advantages of a cell sum to exactly 0 (x_i - mean_{-i} + = n/(n-1) (x_i - mean)). + lone cell: if no other episode of the group reached turn t there is no + within-group peer. The baseline is then the mean of the other + episodes at turn t POOLED across the other groups of the same + rollout step (>= ``min_pool_peers`` of them; still leave-one- + out and independent of the sample's own action, so the + estimator stays unbiased). With fewer, the cell's advantage + is 0 and counted (`credit/cells_no_baseline`) -- a baseline + invented from nothing would be a made-up gradient. + Pooled cells trade within-group centering for a baseline that exists; the + telemetry counts how many cells took each path. + +DEAD GROUPS. "episode": dead iff the group's episode rewards have zero +variance, classified all_zero / all_solved / nonzero_std0 by the shared +`GroupFilterStats` (max_possible_score=1.0: the best episode reward). "per_turn +_loo": dead iff EVERY token advantage of the group is exactly 0 -- the group +contributes no gradient, so keeping it only spends compute; classified from +the rewards the same way. Dead groups are dropped whole, as in single-turn +assembly; an all-dead step returns None (the driver resamples). + +No CUDA, no Lean here: the env, generator and verifier are injected. +""" + +from __future__ import annotations + +import hashlib +from collections import OrderedDict +from dataclasses import dataclass, field +from typing import Any, Callable, Optional, Sequence + +import numpy as np +import torch + +from align.rl.advantages import GroupFilterStats, compute_group_advantages +from align.rl.batch_source import GrpoBatchSource +from align.rl.envs.lean_multiturn import ( + EpisodeRecord, + EpisodeSpec, + LeanMultiTurnEnv, + Problem, +) + +CREDIT_MODES = ("episode", "per_turn_loo") + + +@dataclass(frozen=True) +class MultiTurnCreditConfig: + mode: str = "episode" + #: per-turn return discount (per_turn_loo only): 0 = a turn is judged on its own outcome, + #: >0 = an earlier turn shares in the later turns' outcomes + gamma: float = 0.0 + #: pooled-baseline floor for a turn no group-mate reached (per_turn_loo only) + min_pool_peers: int = 2 + + def __post_init__(self) -> None: + if self.mode not in CREDIT_MODES: + raise ValueError(f"mode must be one of {CREDIT_MODES}, got {self.mode!r}") + if not 0.0 <= self.gamma <= 1.0: + raise ValueError(f"gamma must be in [0, 1], got {self.gamma}") + if self.min_pool_peers < 1: + raise ValueError(f"min_pool_peers must be >= 1, got {self.min_pool_peers}") + if self.mode == "episode" and self.gamma != 0.0: + raise ValueError("gamma is read only by mode='per_turn_loo'; it would be silently ignored") + + +def recommended_loss_denominator( + prompts_per_step: int, n_samples: int, max_turns: int, max_response_len: int +) -> float: + """Dr.GRPO constant sized for the worst-case GENERATED tokens of one optimizer step.""" + return float(prompts_per_step * n_samples * max_turns * max_response_len) + + +# ---------------------------------------------------------------------------- credit + + +def turn_returns(u: Sequence[float], gamma: float) -> list[float]: + """G_t = sum_{s>=t} gamma^(s-t) u_s (the env's definition).""" + out, acc = [0.0] * len(u), 0.0 + for t in range(len(u) - 1, -1, -1): + acc = u[t] + gamma * acc + out[t] = acc + return out + + +@dataclass +class CreditResult: + #: per episode (input order), per turn advantage + turn_adv: list + #: path taken per (episode, turn) cell: "episode" | "group_mean" | "group_loo" | "pooled" | "none" + cell_path: list + counts: dict = field(default_factory=dict) + + +def compute_turn_credit(episodes: Sequence[EpisodeRecord], credit: MultiTurnCreditConfig) -> CreditResult: + """Advantage per (episode, turn). Episodes of one problem_id form a group.""" + n = len(episodes) + groups: "OrderedDict[str, list[int]]" = OrderedDict() + for i, e in enumerate(episodes): + groups.setdefault(e.problem_id, []).append(i) + + ep_adv = [0.0] * n + for idx in groups.values(): + a = compute_group_advantages( + np.array([episodes[i].reward["reward/total"] for i in idx]), len(idx), "centered" + ) + for i, v in zip(idx, a): + ep_adv[i] = float(v) + + n_turns = [len(e.turns) for e in episodes] + if credit.mode == "episode": + return CreditResult( + [[ep_adv[i]] * n_turns[i] for i in range(n)], + [["episode"] * n_turns[i] for i in range(n)], + {"credit/cells_episode": sum(n_turns)}, + ) + + G = [turn_returns(e.turn_rewards, credit.gamma) for e in episodes] + turn_adv = [[0.0] * n_turns[i] for i in range(n)] + path = [[""] * n_turns[i] for i in range(n)] + counts = {"credit/cells_group_mean": 0, "credit/cells_group_loo": 0, + "credit/cells_pooled": 0, "credit/cells_no_baseline": 0} + for idx in groups.values(): + for i in idx: # turn 0: the ordinary group baseline (every episode has a turn 0) + base = sum(G[j][0] for j in idx) / len(idx) + turn_adv[i][0] = G[i][0] - base + path[i][0] = "group_mean" + counts["credit/cells_group_mean"] += 1 + for gidx in groups.values(): + for i in gidx: + for t in range(1, n_turns[i]): + peers = [G[j][t] for j in gidx if j != i and n_turns[j] > t] + if peers: + turn_adv[i][t] = G[i][t] - sum(peers) / len(peers) + path[i][t] = "group_loo" + counts["credit/cells_group_loo"] += 1 + continue + pool = [G[j][t] for j in range(n) if j != i and n_turns[j] > t and j not in gidx] + if len(pool) >= credit.min_pool_peers: + turn_adv[i][t] = G[i][t] - sum(pool) / len(pool) + path[i][t] = "pooled" + counts["credit/cells_pooled"] += 1 + else: + path[i][t] = "none" + counts["credit/cells_no_baseline"] += 1 + return CreditResult(turn_adv, path, counts) + + +# ---------------------------------------------------------------------------- assembly + + +@dataclass +class AssembledMultiTurn: + """Duck-types `AssembledRollout` (the fields `GrpoBatchSource._produce_step` reads), + except ``advantages`` is [B, T] in input space.""" + + input_ids: torch.Tensor + attention_mask: torch.Tensor + response_mask: torch.Tensor + advantages: torch.Tensor + vllm_logprobs: torch.Tensor + group_ids: torch.Tensor + rewards: dict + turn_ids: torch.Tensor + stats: dict = field(default_factory=dict) + kept_groups: int = 0 + dropped_groups: int = 0 + + +#: A group is dead below this spread. `np.std(...) == 0` (the single-turn rule) is an EXACT test, and +#: with discounted multi-turn rewards it misfires: seven episodes that all solved on turn 1 at +#: discount 0.9 have std 1.1e-16, not 0, because ``mean(x, x, ..., x) != x`` in float64. Such a group +#: was kept with advantages of +-1e-16 (a zero-gradient group paid for in full, and counted as +#: ``groups/kept``). Rewards live in [-1, 1] and real differences are >= ~1e-3, so 1e-9 separates +#: rounding noise from signal by six orders of magnitude on each side. +DEAD_ATOL = 1e-9 + + +def _observe_group(stats: GroupFilterStats, rewards: np.ndarray, live: bool) -> None: + """Record one group in the three-way telemetry with an externally decided liveness.""" + if live: + stats.kept += 1 + return + if np.all(np.abs(rewards) <= DEAD_ATOL): + stats.all_zero += 1 + elif np.all(np.abs(rewards - stats.max_possible_score) <= DEAD_ATOL): + stats.all_solved += 1 + else: + stats.nonzero_std0 += 1 + + +def assemble_multiturn( + episodes: Sequence[EpisodeRecord], + credit: MultiTurnCreditConfig, + pad_token_id: int, + filter_stats: Optional[GroupFilterStats] = None, +) -> Optional[AssembledMultiTurn]: + """Episodes -> one training batch with per-token advantages; None if every group is dead.""" + if not episodes: + raise ValueError("no episodes") + stats = filter_stats if filter_stats is not None else GroupFilterStats(max_possible_score=1.0) + res = compute_turn_credit(episodes, credit) + + groups: "OrderedDict[str, list[int]]" = OrderedDict() + for i, e in enumerate(episodes): + groups.setdefault(e.problem_id, []).append(i) + + keep: list[list[int]] = [] + for idx in groups.values(): + rewards = np.array([episodes[i].reward["reward/total"] for i in idx], dtype=np.float64) + if credit.mode == "episode": + # the single-turn rule (zero reward variance) with a rounding tolerance, see DEAD_ATOL + dead = float(np.ptp(rewards)) <= DEAD_ATOL + else: + dead = not any(abs(a) > DEAD_ATOL for i in idx for a in res.turn_adv[i]) + _observe_group(stats, rewards, live=not dead) + if not dead: + keep.append(idx) + if not keep: + return None + + rows = [] # (group_index, episode, row, per-token adv) + for gi, idx in enumerate(keep): + for i in idx: + ep = episodes[i] + for row in ep.rows: + if row.logprobs is None: + raise ValueError( + f"episode {ep.episode_key}: generation carries no logprobs; the rho " + "correction cannot align without the engine's per-token logprobs" + ) + adv = [res.turn_adv[i][tid] if tid >= 0 else 0.0 for tid in row.turn_ids] + rows.append((gi, ep, row, adv)) + B = len(rows) + T = max(len(r.input_ids) for _, _, r, _ in rows) + input_ids = torch.full((B, T), pad_token_id, dtype=torch.int64) + attention_mask = torch.zeros((B, T), dtype=torch.int64) + response_mask = torch.zeros((B, T), dtype=torch.int64) + turn_ids = torch.full((B, T), -1, dtype=torch.int64) + advantages = torch.zeros((B, T), dtype=torch.float32) + vllm_lp = torch.zeros((B, T - 1), dtype=torch.float32) + group_ids = torch.zeros((B,), dtype=torch.int64) + term_names = list(rows[0][1].reward) + reward_tensors = {k: torch.zeros(B, dtype=torch.float32) for k in term_names} + for b, (gi, ep, row, adv) in enumerate(rows): + L = len(row.input_ids) + if not (len(row.response_mask) == len(row.turn_ids) == len(row.logprobs) == L): + raise ValueError(f"row {b} of episode {ep.episode_key} is ragged across ids/mask/turn_ids/logprobs") + # Credit is placed by ``turn_ids`` and trained on by ``response_mask``. If the two disagree + # by even one position, the loss-side stray check (`expand_advantages`) catches it only + # when the misplaced credit lands on an excluded position that exists: a row whose last + # generated token is its last column (every micro-batch's longest per-turn row) has no + # position past it, so a right-shifted span slips through. Refuse here, where it is exact. + if [int(t >= 0) for t in row.turn_ids] != [int(m) for m in row.response_mask]: + raise ValueError( + f"row {b} of episode {ep.episode_key}: turn_ids >= 0 does not coincide with " + f"response_mask; per-token credit would be misaligned with the trained tokens" + ) + input_ids[b, :L] = torch.tensor(row.input_ids, dtype=torch.int64) + attention_mask[b, :L] = 1 + response_mask[b, :L] = torch.tensor(row.response_mask, dtype=torch.int64) + turn_ids[b, :L] = torch.tensor(row.turn_ids, dtype=torch.int64) + advantages[b, :L] = torch.tensor(adv, dtype=torch.float32) + # label position j <-> input token j+1 + vllm_lp[b, : L - 1] = torch.tensor(row.logprobs[1:], dtype=torch.float32) + group_ids[b] = gi + for k in term_names: + reward_tensors[k][b] = float(ep.reward[k]) + + kept_eps = [episodes[i] for idx in keep for i in idx] + gsz = [len(idx) for idx in keep] + first = [e.solved_turn == 0 for e in kept_eps] + failed_first = [e for e in kept_eps if e.solved_turn != 0] + stat = { + "multiturn/episodes": float(len(kept_eps)), + "multiturn/rows": float(B), + "multiturn/turns_mean": float(np.mean([len(e.turns) for e in kept_eps])), + "multiturn/solved_turn0": float(np.mean(first)), + "multiturn/solved": float(np.mean([e.solved_turn is not None for e in kept_eps])), + "multiturn/repair_rate": ( + float(np.mean([e.solved_turn is not None for e in failed_first])) if failed_first else float("nan") + ), + "multiturn/generated_tokens_mean": float(np.mean([e.n_generated for e in kept_eps])), + "multiturn/group_size_min": float(min(gsz)), + "multiturn/group_size_max": float(max(gsz)), + **{k: float(v) for k, v in res.counts.items()}, + **{k: float(v) for k, v in stats.as_log_dict().items()}, + } + return AssembledMultiTurn( + input_ids, attention_mask, response_mask, advantages, vllm_lp, group_ids, reward_tensors, + turn_ids, stat, kept_groups=len(keep), dropped_groups=len(groups) - len(keep), + ) + + +# ---------------------------------------------------------------------------- the batch source + + +class MultiTurnBatchSource(GrpoBatchSource): + """`GrpoBatchSource` whose rollout is a batch of multi-turn Lean episodes. + + Everything downstream of rollout production (rank-0 produce + broadcast, + row slicing, no-grad old_logprobs, the validated batch, the collapse + tripwire, the draw-position resume state) is inherited unchanged; only + `_rollout_once` differs. Rows are sliced along dim 0 and the [B, T] + advantages slice with them. + + ``prompt_rows``: dicts with ``formal_statement`` (or ``problem``) and a + UNIQUE ``problem_id`` (the group key; duplicates are refused -- two + problems sharing an id would be centered against each other). + ``generate_factory(seed=..., weights_dir=...)`` returns the env's + ``generate(list[GenRequest]) -> list[Generation]`` for this step. + """ + + def __init__( + self, + prompt_rows: Sequence[dict[str, Any]], + *, + env: LeanMultiTurnEnv, + credit: MultiTurnCreditConfig = MultiTurnCreditConfig(), + prompts_per_step: int, + n_samples_per_prompt: int, + max_response_len: int, + temperature: float, + optimizer_steps: int, + grad_accum: int, + seed: int, + dead_group_retries: int = 5, + ): + rows, seen = [], set() + for i, r in enumerate(prompt_rows): + stmt = r.get("formal_statement", r.get("problem")) + if not isinstance(stmt, str) or not stmt: + raise ValueError(f"prompt row {i} lacks formal_statement/problem: {sorted(r)}") + pid = str(r.get("problem_id") or hashlib.sha256(stmt.encode()).hexdigest()[:12]) + if pid in seen: + raise ValueError(f"duplicate problem_id {pid!r}: it is the advantage group key") + seen.add(pid) + rows.append({"problem": stmt, "answer": "", "problem_id": pid}) + super().__init__( + rows, + prompts_per_step=prompts_per_step, + n_samples_per_prompt=n_samples_per_prompt, + max_response_len=max_response_len, + temperature=temperature, + optimizer_steps=optimizer_steps, + grad_accum=grad_accum, + seed=seed, + prompt_builder=lambda p: p, # unused: the env builds the Goedel prompts + dead_group_retries=dead_group_retries, + ) + self.env = env + self.credit = credit + # Multi-turn episode reward is <= 1.0 (turn_discount ** 0); the single-turn + # source's 1.1 (accuracy + format bonus) would misfile all-solved groups. + self.filter_stats.max_possible_score = 1.0 + self.last_rollout_stats: dict[str, float] = {} + + def bind( # noqa: D401 - deliberately narrower than the parent's (no client/reward/verifier) + self, + *, + generate_factory: Callable[..., Callable[[list], list]], + old_logprob_fn, + weights_dir_fn, + rank: int, + world_size: int, + device: str = "cpu", + canary=None, + canary_generate_fn=None, + collapse_tripwire=None, + trainer=None, + canary_log_path=None, + ) -> None: + self.generate_factory = generate_factory + super().bind( + client=None, reward=None, verifier=None, old_logprob_fn=old_logprob_fn, + weights_dir_fn=weights_dir_fn, rank=rank, world_size=world_size, device=device, + canary=canary, canary_generate_fn=canary_generate_fn, collapse_tripwire=collapse_tripwire, + trainer=trainer, canary_log_path=canary_log_path, + ) + + def _rollout_once(self, indices: list[int], optimizer_step: int = 0) -> Optional[AssembledMultiTurn]: + specs = [ + EpisodeSpec(Problem(self.prompt_rows[i]["problem_id"], self.prompt_rows[i]["problem"]), s) + for i in indices + for s in range(self.n_samples_per_prompt) + ] + generate = self.generate_factory( + seed=self.rollout_seed(optimizer_step), weights_dir=self.weights_dir_fn() + ) + episodes = self.env.run_group(specs, generate) + assembled = assemble_multiturn(episodes, self.credit, self.pad_token_id, self.filter_stats) + if assembled is not None: + self.last_rollout_stats = assembled.stats + return assembled diff --git a/code/align/rl/ops.py b/code/align/rl/ops.py new file mode 100644 index 0000000000000000000000000000000000000000..afa012c67f8c38c164f0f13326bc03451723b028 --- /dev/null +++ b/code/align/rl/ops.py @@ -0,0 +1,99 @@ +"""Pure tensor ops for the GRPO layer. + +Vendored from allenai/open-instruct @ 8759c91: + masked_mean <- open_instruct/rl_utils.py:426-448 + entropy_from_logits <- open_instruct/model_utils.py:326-334 + log_softmax_and_gather <- open_instruct/model_utils.py:588-601 + estimate_kl <- open_instruct/model_utils.py:793-819 + +Bodies are verbatim; only the module docstrings/imports differ. Any edit to +these functions breaks parity with the upstream line citations in +docs/research/nmo-research/docs/04_ALLENAI_CODEBASE_MAP.md and must be +recorded as a deliberate divergence, not slipped in. +""" + +from __future__ import annotations + +from typing import Optional, Union + +import torch + + +def masked_mean( + values: torch.Tensor, + mask: torch.Tensor, + axis: Optional[int] = None, + denominator: Optional[float] = None, +) -> torch.Tensor: + """Compute mean of tensor with masked values. + + Returns 0 if mask is empty (no valid elements) to avoid division by zero. + This can happen with sequence parallel when a chunk contains only + query/padding tokens. + + A3 note: passing a constant float ``denominator`` is what realises the + Dr.GRPO constant-global-denominator form; leaving it None realises the + DAPO token-mean. align's conformance gate requires the float. + """ + extra_dims = values.ndim - mask.ndim + if axis is None: + sum_dims: int | tuple[int, ...] = tuple(range(extra_dims, values.ndim)) + elif axis >= 0: + sum_dims = axis + extra_dims + else: + sum_dims = axis + numerator = (values * mask).sum(dim=sum_dims) + denom = mask.sum(dim=axis) if denominator is None else denominator + if isinstance(denom, torch.Tensor): + result = torch.where(denom > 0, numerator / denom, torch.zeros_like(numerator)) + else: + result = numerator / denom if denom > 0 else torch.zeros_like(numerator) + return result.flatten(extra_dims).mean(-1) if result.ndim > extra_dims else result + + +def entropy_from_logits(logits: torch.Tensor) -> torch.Tensor: + """Compute the entropy of the logits. + + Upstream credit chain: open-instruct borrowed this from verl + (verl/utils/torch_functional.py). logsumexp form avoids materialising + log-probabilities next to probabilities. + """ + pd = torch.nn.functional.softmax(logits, dim=-1) + entropy = torch.logsumexp(logits, dim=-1) - torch.sum(pd * logits, dim=-1) + return entropy + + +def log_softmax_and_gather(logits: torch.Tensor, index: torch.Tensor) -> torch.Tensor: + """`log_softmax -> gather` without allocating a [B, T, V] logprob tensor. + + Upstream compiles this (open-instruct PR #584); align leaves compilation to + the caller because torch.compile on this box requires the vendored-header + toolchain fix (align/kernels/_toolchain.py) and is opted into per-site. + """ + logprobs = logits.log_softmax(dim=-1) + return torch.gather(logprobs, dim=-1, index=index.unsqueeze(-1)).squeeze(-1) + + +def estimate_kl(ref_logprobs_diff: torch.Tensor, ratio: torch.Tensor) -> torch.Tensor: + """Compute 4 KL divergence estimators between current and reference policies. + + Args: + ref_logprobs_diff: (new_logprobs - ref_logprobs), pre-clamped to + [-40, 40] by the caller for numerical stability. + ratio: exp(new_logprobs - old_logprobs) vs the step-start policy. + + Returns: + Tensor of shape [4, *ref_logprobs_diff.shape]: + [0] linear approximation + [1] quadratic approximation (diff^2 / 2) + [2] numerically stable form (expm1(-diff) + diff) -- default + [3] importance-weighted (ratio * diff) + """ + return torch.stack( + [ + ref_logprobs_diff, + (ref_logprobs_diff) ** 2 / 2, + torch.expm1(-ref_logprobs_diff) + ref_logprobs_diff, + ratio * ref_logprobs_diff, + ] + ) diff --git a/code/align/rl/rewards.py b/code/align/rl/rewards.py new file mode 100644 index 0000000000000000000000000000000000000000..d80a4d5eda41b185cd14dc95e3fce16813c3c5ac --- /dev/null +++ b/code/align/rl/rewards.py @@ -0,0 +1,98 @@ +"""Reward composition -- the ONE genuinely net-new A3 piece. + +The corpus's conformance table (04_ALLENAI_CODEBASE_MAP.md item 9) found soft +overlong punishment absent from open-instruct entirely (its +``mask_truncated_completions`` is DAPO's HARD binary filter, a different +mechanism). Per the same table's architectural note: this lives in the +REWARD-COMPOSITION layer, never in the loss -- keeping compute_grpo_loss +provably unmodified from upstream is an auditability property of the +pre-registration, not a style preference. + +soft_overlong_punishment implements DAPO eq. (arXiv:2503.14476, "Soft +Overlong Punishment"): zero inside the budget, linear ramp to -1 across the +final ``cache`` tokens, -1 beyond max length. +""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Optional, Sequence + + +def soft_overlong_punishment(response_len: int, max_len: int, cache_len: int) -> float: + """DAPO soft length penalty in [-1, 0]. + + 0 for len <= max_len - cache_len + ((max_len - cache_len) - len)/cache_len inside the buffer (linear to -1) + -1 for len > max_len + """ + if cache_len <= 0 or cache_len >= max_len: + raise ValueError(f"need 0 < cache_len < max_len, got cache={cache_len} max={max_len}") + soft_start = max_len - cache_len + if response_len <= soft_start: + return 0.0 + if response_len > max_len: + return -1.0 + return (soft_start - response_len) / cache_len + + +@dataclass +class CompositeReward: + """A3 reward: verifier accuracy + soft format term + soft overlong penalty. + + ``accuracy`` and ``format_score`` arrive from the verifier layer (rule + verifier only -- no PRM/neural RM, A3's hardest lock and the field's + strongest cross-lab consensus per doc 08). This class only composes and + itemises them so history.jsonl can log each term separately -- the + format/structural-consistency instrument (doc 09 amendment) reads the + per-term stream, not the sum. + """ + + format_weight: float = 0.1 + overlong_max_len: Optional[int] = None + overlong_cache_len: Optional[int] = None + + def __post_init__(self) -> None: + # Fail at CONSTRUCTION, not at the first rollout. The dangerous half is + # cache_len set with max_len unset: __call__ takes the "overlong off" + # branch and the soft length penalty silently never applies while the + # config reads as if it were armed (a disarmed-instrument shape). + if self.overlong_max_len is None and self.overlong_cache_len is not None: + raise ValueError( + f"overlong_cache_len={self.overlong_cache_len} given without overlong_max_len: " + "the soft overlong penalty would be silently OFF" + ) + if self.overlong_max_len is not None: + if self.overlong_cache_len is None: + raise ValueError("overlong_cache_len required when overlong_max_len is set") + if not 0 < self.overlong_cache_len < self.overlong_max_len: + raise ValueError( + f"need 0 < overlong_cache_len < overlong_max_len, got " + f"cache={self.overlong_cache_len} max={self.overlong_max_len}" + ) + + def __call__(self, accuracy: float, format_score: float, response_len: int) -> dict[str, float]: + terms: dict[str, float] = { + "reward/accuracy": float(accuracy), + "reward/format": self.format_weight * float(format_score), + } + if self.overlong_max_len is not None: + if self.overlong_cache_len is None: + raise ValueError("overlong_cache_len required when overlong_max_len is set") + terms["reward/overlong"] = soft_overlong_punishment( + response_len, self.overlong_max_len, self.overlong_cache_len + ) + else: + terms["reward/overlong"] = 0.0 + terms["reward/total"] = ( + terms["reward/accuracy"] + terms["reward/format"] + terms["reward/overlong"] + ) + return terms + + def batch( + self, accuracies: Sequence[float], format_scores: Sequence[float], lengths: Sequence[int] + ) -> list[float]: + return [ + self(a, f, n)["reward/total"] + for a, f, n in zip(accuracies, format_scores, lengths, strict=True) + ] diff --git a/code/align/rl/stage_config.py b/code/align/rl/stage_config.py new file mode 100644 index 0000000000000000000000000000000000000000..eb0d477d4f0e3dcb8711d008283fd46b1e61ea13 --- /dev/null +++ b/code/align/rl/stage_config.py @@ -0,0 +1,253 @@ +"""Typed stage-b config: configs/grpo_stageb.toml -> dataclasses + launch refusals. + +Deliberately NOT align.config.RunConfig: that is the trainer's surface, this is +the stage's pre-registration. Collapsing them would let a trainer default +silently become an experimental parameter (the same separation dpo_stage +draws). The trainer still gets a RunConfig -- built FROM this, explicitly, +in scripts/grpo.py. + +Every check in `validate()` is a launch refusal for a failure phase-1 paid +for: the denominator arithmetic (obligation a's config half), the +save-cadence/weight-sync alignment (a drifted engine trains against stale +rho baselines silently), the ceiling receipt (the 0/100-perfect-policy +trap), max_grad_norm (R3), a live canary cadence (R4). +""" + +from __future__ import annotations + +import json +import os +from dataclasses import dataclass, field + +from align.rl.grpo_loss import GRPOLossConfig, GRPOLossType + + +@dataclass +class RolloutShape: + prompts_per_step: int + max_response_len: int + temperature: float = 1.0 + overlong_cache_len: int = 128 + #: Where completions come from. "spool" = the external vLLM worker (own venv, + #: extras/vllm_rollout; the backend the pre-registration describes) and is + #: the default so an existing config keeps its generation engine. "native" = + #: the in-repo torch sampler on a STANDALONE engine copy on a dedicated GPU + #: (NMO_ROLLOUT_GPU), synced by reloading the latest checkpoint; GPU-unverified + #: at 7B at the time of the port, so it is opt-in. A silent switch changes + #: throughput by an order of magnitude and the logprob basis (native logprobs + #: are of the temperature-scaled distribution), hence never inferred. + backend: str = "spool" + #: INFORMATIONAL ONLY: configs/grpo_stageb.toml carries `vllm_env` as a note of the + #: worker environment the pre-registration ran under. Nothing reads it -- the env is + #: pinned in code (align/rollout/client.py) -- so it is declared here, rather than + #: left to the unknown-key refusal, purely so that refusal can be strict for every + #: OTHER key. A value here does NOT change the worker environment. + vllm_env: str = "" + + +@dataclass +class RewardCfg: + format_weight: float = 0.1 + + +@dataclass +class DataCfg: + band_file: str + banding_manifest: str + + +@dataclass +class TrainCfg: + lr: float + optimizer_steps: int + warmup_frac: float = 0.03 + micro_batch_size: int = 1 + save_every_micro_steps: int = 100 + keep_checkpoints: int = 2 + #: Per-rank optimizer shards (TrainConfig.per_rank_optimizer_state); forwarded + #: by scripts/grpo.py::_run_config. Default False = gathered layout. + per_rank_optimizer_state: bool = False + max_grad_norm: float | None = None + seed: int = 41 + optimizer_name: str = "adamw8bit" + grad_accum: int = 8 + attn_implementation: str = "sdpa" + + # -- run-health bounds (G0), forwarded to TrainConfig by the stage script's + # _run_config: a field that is not copied trains at the default while the + # TOML says otherwise. Semantics: align/config.py::TrainConfig. + max_wall_seconds: float | None = None + max_consecutive_skipped_steps: int = 3 + max_skipped_fraction: float = 0.05 + + +@dataclass +class CanaryCfg: + every: int + n_problems: int + source: str = "gsm8k" + + +@dataclass +class GrpoStageConfig: + sft_checkpoint: str + run_dir: str + grpo: GRPOLossConfig + rollout: RolloutShape + reward: RewardCfg + data: DataCfg + train: TrainCfg + canary: CanaryCfg + armed_tripwires: tuple[str, ...] = ("grad_norm",) + ceiling_receipt: str = "outputs/eval/ceiling_test.json" + rollout_timeout_s: float = 1800.0 + dead_group_retries: int = 5 + extras: dict = field(default_factory=dict) + + def validate(self) -> None: + g = self.grpo + if self.rollout.backend not in ("spool", "native"): + raise ValueError( + f"rollout.backend {self.rollout.backend!r}: choose 'spool' (external vLLM " + "worker) or 'native' (in-repo torch sampler)" + ) + expected = float( + self.rollout.prompts_per_step + * g.num_samples_per_prompt_rollout + * self.rollout.max_response_len + ) + if not isinstance(g.loss_denominator, float) or g.loss_denominator != expected: + raise ValueError( + f"loss_denominator {g.loss_denominator!r} != prompts_per_step x G x " + f"max_response_len = {self.rollout.prompts_per_step} x " + f"{g.num_samples_per_prompt_rollout} x {self.rollout.max_response_len} " + f"= {expected}. The Dr.GRPO constant is DERIVED, never hand-typed." + ) + if not os.path.isfile(self.data.band_file): + raise FileNotFoundError( + f"band file missing: {self.data.band_file}. Run " + "scripts/build_stageb_data.py first; the driver never builds data." + ) + if self.train.save_every_micro_steps % self.train.grad_accum != 0: + raise ValueError( + f"save_every_micro_steps={self.train.save_every_micro_steps} is not a " + f"multiple of grad_accum={self.train.grad_accum}: checkpoint saves ARE " + "the weight sync (the engine reloads the latest checkpoint), so a save " + "landing mid-accumulation would sync half-stepped weights." + ) + if self.train.max_grad_norm is None or self.train.max_grad_norm <= 0: + raise ValueError( + "train.max_grad_norm must be a positive float: R3 (2026-08-23 audit) " + "-- the recorded phase-1 rerun blew up to grad_norm 355,830 with no " + "clipping anywhere. Unclipped RL is not a configuration this stage " + "accepts." + ) + if self.canary.every <= 0 or self.canary.n_problems <= 0: + raise ValueError( + "canary cadence/n must be positive: R4 -- 727 optimizer steps of " + "phase-1 preference training ran with zero task-accuracy signal." + ) + if "grad_norm" not in self.armed_tripwires: + raise ValueError("stage-b requires the grad_norm HALT tripwire armed (R3)") + if not g.record_entropy: + raise ValueError("record_entropy must be true: the collapse tripwire reads entropy") + + def validate_ceiling_receipt(self) -> dict: + """Separate from validate(): tests exercise config logic without a receipt.""" + if not os.path.isfile(self.ceiling_receipt): + raise FileNotFoundError( + f"ceiling receipt missing: {self.ceiling_receipt}. No GRPO rollout " + "launches until the reward path is certified (the 0/100-perfect-policy " + "incident, mistral-prm-ppo 2026-08-14)." + ) + with open(self.ceiling_receipt) as f: + receipt = json.load(f) + if not receipt.get("overall_pass"): + raise RuntimeError(f"ceiling receipt {self.ceiling_receipt} is not a PASS") + return receipt + + def validate_world(self, world_size: int) -> None: + """Checks that need the launch topology.""" + rows_per_step = self.rollout.prompts_per_step * self.grpo.num_samples_per_prompt_rollout + per_micro = rows_per_step // (world_size * self.train.grad_accum) + if per_micro < 1: + raise ValueError( + f"rollout shape too small for the topology: {rows_per_step} completions " + f"per step cannot fill world_size({world_size}) x " + f"grad_accum({self.train.grad_accum}) micro-slices" + ) + + +def load_stage_config(path: str, smoke: bool = False) -> GrpoStageConfig: + from align.config import load_toml + + raw = load_toml(path) + g = dict(raw["grpo"]) + g["loss_fn"] = GRPOLossType(g.get("loss_fn", "dapo")) + # TOML floats survive; TOML ints for float fields do not -- coerce the one + # field whose TYPE is load-bearing (the conformance gate refuses non-float). + if "loss_denominator" in g: + g["loss_denominator"] = float(g["loss_denominator"]) + t = dict(raw["train"]) + t["optimizer_name"] = raw.get("optimizer", {}).get("name", t.pop("optimizer_name", "adamw8bit")) + t["grad_accum"] = raw.get("optimizer", {}).get("grad_accum", t.pop("grad_accum", 8)) + # STRUCT MODE for [train]. This used to filter through + # TrainCfg.__dataclass_fields__, which made a typo'd or not-yet-plumbed key + # (e.g. per_rank_optimizer_state before TrainCfg had it) ACCEPTED AND + # SILENTLY IGNORED: the TOML looked armed and the run was not. Raise at + # launch, naming the key, like DpoStageConfig's struct-mode loader. + unknown = sorted(k for k in t if k not in TrainCfg.__dataclass_fields__) + if unknown: + raise ValueError( + f"unknown key(s) {unknown} in [train] are not fields of TrainCfg " + f"(struct mode: a silently ignored key is a disarmed config). " + f"Known fields: {sorted(TrainCfg.__dataclass_fields__)}" + ) + # STRUCT MODE for [rollout] too. The same filter-through-__dataclass_fields__ + # idiom that [train] shed above survived here: `[rollout] max_reponse_len = 512` + # (typo) or a not-yet-plumbed `top_p = 0.9` was DROPPED, the shape kept its + # default, and `validate()` then checked the loss denominator against the + # default -- the pre-registered rollout looked armed and was not. + r = dict(raw["rollout"]) + unknown_rollout = sorted(k for k in r if k not in RolloutShape.__dataclass_fields__) + if unknown_rollout: + raise ValueError( + f"unknown key(s) {unknown_rollout} in [rollout] are not fields of RolloutShape " + f"(struct mode: a silently ignored key is a disarmed config). " + f"Known fields: {sorted(RolloutShape.__dataclass_fields__)}" + ) + cfg = GrpoStageConfig( + sft_checkpoint=raw["sft_checkpoint"], + run_dir=raw["run_dir"], + grpo=GRPOLossConfig(**g), + rollout=RolloutShape(**r), + reward=RewardCfg(**raw.get("reward", {})), + data=DataCfg(**raw["data"]), + train=TrainCfg(**t), + canary=CanaryCfg(**raw["canary"]), + armed_tripwires=tuple(raw.get("tripwires", {}).get("armed", ("grad_norm",))), + ) + if smoke: + cfg = _smokeify(cfg) + cfg.validate() + return cfg + + +def _smokeify(cfg: GrpoStageConfig) -> GrpoStageConfig: + """Tiny everything; the derived denominator is recomputed, not hand-edited.""" + cfg.rollout.prompts_per_step = 2 + cfg.grpo.num_samples_per_prompt_rollout = 8 # A3 floor is G >= 8, smoke included + # 256 tokens, not 32: the sixth smoke run proved a cap real answers + # cannot fit under produces zero reward variance -> every group dead -> + # the (correct) band-mischosen refusal. The smoke needs a policy with + # SOME task signal (the real SFT substrate) and room to finish answers. + cfg.rollout.max_response_len = 256 + cfg.rollout.overlong_cache_len = 64 + cfg.grpo.loss_denominator = float(2 * 8 * 256) + cfg.train.optimizer_steps = 10 + cfg.train.grad_accum = 2 + cfg.train.save_every_micro_steps = 10 # sync twice in a 20-micro smoke + cfg.canary.every = 5 + cfg.canary.n_problems = 4 + cfg.run_dir = cfg.run_dir + "_smoke" + return cfg diff --git a/code/align/rl/tripwire.py b/code/align/rl/tripwire.py new file mode 100644 index 0000000000000000000000000000000000000000..6910bf78b74805d8e7a014eb815161e8fc8c217d --- /dev/null +++ b/code/align/rl/tripwire.py @@ -0,0 +1,202 @@ +"""Entropy/length collapse tripwire -- the second net-new A3 piece. + +Upstream has the loggable INPUTS (record_entropy=True) but no tripwire logic +(corpus conformance table item 7: "the knob exists, the tripwire mechanism +does not"). This is the GRPO sibling of the DPO chosen-logprob tripwire that +fired -- and autonomously launched its pre-registered response -- on Arm B +(2026-08-22, runs/dpo_arm_b_response/). + +Design contract, identical to the DPO one: + * The tripwire DETECTS and RECORDS. The stage script owns the response, + and the only admissible response is the pre-registered one + (KL=0 collapse -> ONE rerun with beta=1e-4, recorded AS the result; + no third configuration). No improvisation lives here by construction. + * Fed from the same metrics stream that history.jsonl records, so a fire + is always reproducible from the run's own log after the fact. + +Signals (cross-lab consensus per doc 08: entropy collapse is the 2025 +field-wide GRPO failure mode; length collapse is its usual companion): + E: policy entropy trend -- median over the trailing window falls below + ``entropy_floor_frac`` x the median over the baseline window. + L: mean response length trend -- same construction, lengths shrinking + below ``length_floor_frac`` of baseline (degenerate short answers). +Either alone fires; both are cheap medians over deques, no model access. + +Resume (2026-10-12 review). The instrument is STATEFUL -- a baseline measured +over the first ``baseline_steps`` observations, a trailing window, a step +counter and a latch -- so a resume that rebuilds it fresh silently changes the +experiment: the baseline is re-measured on the POST-resume (possibly already +collapsed) policy, which makes the collapse the new "normal", and +``min_steps_before_fire`` restarts at 0, blinding the guard for ~100 steps. +``state_dict()`` / ``load_state_dict()`` carry all of it through the Trainer's +``extra_state`` slot in resume.pt (``GRPOTrainModule.extra_state``). +""" + +from __future__ import annotations + +import logging +import math +from collections import deque +from dataclasses import dataclass, field +from statistics import median +from typing import Optional + +logger = logging.getLogger(__name__) + + +@dataclass +class CollapseTripwire: + baseline_steps: int = 50 + window_steps: int = 50 + entropy_floor_frac: float = 0.2 + length_floor_frac: float = 0.4 + min_steps_before_fire: int = 100 + + _baseline_entropy: list[float] = field(default_factory=list) + _baseline_length: list[float] = field(default_factory=list) + _entropy: deque = field(default_factory=deque) + _length: deque = field(default_factory=deque) + _steps: int = 0 + fired: bool = False + fire_reason: Optional[str] = None + fire_step: Optional[int] = None + + def __post_init__(self) -> None: + self._entropy = deque(maxlen=self.window_steps) + self._length = deque(maxlen=self.window_steps) + + def observe(self, step: int, entropy: float, mean_response_len: float) -> bool: + """Feed one optimizer step's metrics; returns True the step it fires. + + Once fired it stays fired (a latched instrument, like the DPO one) -- + the stage script reads ``fired``/``fire_reason`` and executes the + pre-registered response exactly once. + """ + if not (math.isfinite(entropy) and math.isfinite(mean_response_len)): + # NaN compares False against every threshold below (`nan > 0`, + # `nan < x`), so a NaN entropy stream would leave the entropy arm + # permanently inert while the object reads as armed -- the + # disarmed-tripwire shape (audit D1). `_on_step_boundary` feeds NaN + # when a metric key is missing. Refuse loudly instead. + raise ValueError( + f"CollapseTripwire.observe(step={step}): non-finite input " + f"(entropy={entropy}, mean_response_len={mean_response_len}); a guard " + "fed NaN can never fire" + ) + self._steps += 1 + if len(self._baseline_entropy) < self.baseline_steps: + self._baseline_entropy.append(entropy) + self._baseline_length.append(mean_response_len) + return False + self._entropy.append(entropy) + self._length.append(mean_response_len) + + if ( + self.fired + or self._steps < self.min_steps_before_fire + or len(self._entropy) < self.window_steps + ): + return False + + base_e = median(self._baseline_entropy) + base_l = median(self._baseline_length) + cur_e = median(self._entropy) + cur_l = median(self._length) + reasons = [] + if base_e > 0 and cur_e < self.entropy_floor_frac * base_e: + reasons.append( + f"entropy collapse: trailing median {cur_e:.4f} < {self.entropy_floor_frac} x baseline {base_e:.4f}" + ) + if base_l > 0 and cur_l < self.length_floor_frac * base_l: + reasons.append( + f"length collapse: trailing median {cur_l:.1f} < {self.length_floor_frac} x baseline {base_l:.1f}" + ) + if reasons: + self.fired = True + self.fire_step = step + self.fire_reason = "; ".join(reasons) + logger.error( + "TRIPWIRE (GRPO collapse) at step %d: %s -- pre-registered response: ONE beta=1e-4 " + "rerun recorded AS the result; no third configuration.", + step, + self.fire_reason, + ) + return True + return False + + #: Bump on any change to the persisted layout; a mismatch refuses to load. + STATE_VERSION = 1 + + def _config_dict(self) -> dict: + return { + "baseline_steps": self.baseline_steps, + "window_steps": self.window_steps, + "entropy_floor_frac": self.entropy_floor_frac, + "length_floor_frac": self.length_floor_frac, + "min_steps_before_fire": self.min_steps_before_fire, + } + + def state_dict(self) -> dict: + """Everything `observe` reads, as primitives only. + + Plain dict/list/float/int/bool/None/str so it survives the Trainer's + ``torch.load(weights_only=True)`` of resume.pt -- unpickling arbitrary + objects to restore a counter would be a code-execution path for nothing. + The thresholds are included so `load_state_dict` can refuse a state cut + for a different configuration. + """ + return { + "version": self.STATE_VERSION, + "config": self._config_dict(), + "baseline_entropy": [float(x) for x in self._baseline_entropy], + "baseline_length": [float(x) for x in self._baseline_length], + "entropy": [float(x) for x in self._entropy], + "length": [float(x) for x in self._length], + "steps": int(self._steps), + "fired": bool(self.fired), + "fire_reason": self.fire_reason, + "fire_step": self.fire_step, + } + + def load_state_dict(self, sd: dict) -> None: + """Restore `state_dict()` output; refuse anything that is not exactly it. + + A silently half-restored tripwire is the disarmed-instrument shape, so + every inconsistency raises: wrong version, thresholds that differ from + this instance's (a different experiment -- rebuild it deliberately), + or windows longer than the configured sizes. Validation happens BEFORE + any field is assigned, so a refused load leaves the instance untouched. + """ + if sd.get("version") != self.STATE_VERSION: + raise ValueError( + f"CollapseTripwire state version {sd.get('version')!r} != {self.STATE_VERSION}" + ) + if sd.get("config") != self._config_dict(): + raise ValueError( + f"CollapseTripwire state was saved under {sd.get('config')!r} but this " + f"instance is configured {self._config_dict()!r}; resuming under different " + "thresholds is a different experiment." + ) + base_e, base_l = list(sd["baseline_entropy"]), list(sd["baseline_length"]) + ent, length = list(sd["entropy"]), list(sd["length"]) + if len(base_e) != len(base_l) or len(ent) != len(length): + raise ValueError("CollapseTripwire state has mismatched entropy/length series") + if len(base_e) > self.baseline_steps or len(ent) > self.window_steps: + raise ValueError("CollapseTripwire state windows exceed the configured sizes") + if not all(math.isfinite(x) for x in base_e + base_l + ent + length): + raise ValueError("CollapseTripwire state contains non-finite observations") + self._baseline_entropy = [float(x) for x in base_e] + self._baseline_length = [float(x) for x in base_l] + self._entropy = deque((float(x) for x in ent), maxlen=self.window_steps) + self._length = deque((float(x) for x in length), maxlen=self.window_steps) + self._steps = int(sd["steps"]) + self.fired = bool(sd["fired"]) + self.fire_reason = sd["fire_reason"] + self.fire_step = sd["fire_step"] + + def as_log_dict(self) -> dict: + return { + "tripwire/fired": self.fired, + "tripwire/fire_step": self.fire_step, + "tripwire/fire_reason": self.fire_reason, + } diff --git a/code/align/rl/types.py b/code/align/rl/types.py new file mode 100644 index 0000000000000000000000000000000000000000..1830c133c566445997d5445fca608b8d9c0f8c49 --- /dev/null +++ b/code/align/rl/types.py @@ -0,0 +1,84 @@ +"""Rollout data types for stage-b GRPO. + +The rollout ORCHESTRATOR (M-D, separate build) produces these; the +GRPOTrainModule consumes them. Alignment convention, stated once: per-token +logprob tensors are LABEL-ALIGNED -- position t holds the logprob of +input_ids[:, t+1], so they have length T-1 and pair with +`shifted_response_mask`. Getting this half-open boundary wrong is the same +off-by-one family as the decode-position incident (section-09) and the +completion-mask defect (audit R1); the validating constructor exists so the +mismatch fails at batch construction, not as a silently shifted objective. +""" + +from __future__ import annotations + +from dataclasses import dataclass, field + +import torch + + +@dataclass +class RolloutBatch: + """One training micro-batch of rollout data. + + Shapes (B = completions in the batch, T = padded sequence length): + input_ids [B, T] int64 prompt + completion, right-padded + attention_mask [B, T] int64 1 on real tokens + response_mask [B, T] int64 1 on COMPLETION tokens only (input space) + advantages [B] float per-sequence Dr.GRPO centered advantage + old_logprobs [B, T-1] policy-at-rollout logprobs (label-aligned) + vllm_logprobs [B, T-1] inference-engine logprobs (label-aligned) + ref_logprobs [B, T-1]? reference-policy logprobs; REQUIRED iff + the loss config has beta > 0 (the KL + ablation), absent otherwise + rewards {name: [B]} per-completion reward terms (reward/total, + reward/accuracy, ... -- itemised so the + format-consistency instrument reads terms, + not sums) + group_ids [B] int64 prompt-group id of each completion + """ + + input_ids: torch.Tensor + attention_mask: torch.Tensor + response_mask: torch.Tensor + advantages: torch.Tensor + old_logprobs: torch.Tensor + vllm_logprobs: torch.Tensor + group_ids: torch.Tensor + rewards: dict[str, torch.Tensor] = field(default_factory=dict) + ref_logprobs: torch.Tensor | None = None + + def __post_init__(self) -> None: + B, T = self.input_ids.shape + for name, t, shape in ( + ("attention_mask", self.attention_mask, (B, T)), + ("response_mask", self.response_mask, (B, T)), + ("advantages", self.advantages, (B,)), + ("old_logprobs", self.old_logprobs, (B, T - 1)), + ("vllm_logprobs", self.vllm_logprobs, (B, T - 1)), + ("group_ids", self.group_ids, (B,)), + ): + if tuple(t.shape) != shape: + raise ValueError( + f"RolloutBatch.{name} has shape {tuple(t.shape)}, expected {shape} " + f"(B={B}, T={T}; logprob tensors are label-aligned, length T-1)" + ) + if self.ref_logprobs is not None and tuple(self.ref_logprobs.shape) != (B, T - 1): + raise ValueError( + f"RolloutBatch.ref_logprobs has shape {tuple(self.ref_logprobs.shape)}, " + f"expected {(B, T - 1)}" + ) + for name, t in self.rewards.items(): + if tuple(t.shape) != (B,): + raise ValueError( + f"RolloutBatch.rewards[{name!r}] has shape {tuple(t.shape)}, expected {(B,)}" + ) + + @property + def shifted_response_mask(self) -> torch.Tensor: + """Response mask in LABEL space [B, T-1], pairing with the logprobs.""" + return self.response_mask[:, 1:] + + @property + def n_response_tokens(self) -> int: + return int(self.shifted_response_mask.sum()) diff --git a/code/align/rollout/__init__.py b/code/align/rollout/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..ecfbb6eca6c640d93736a8ec532b215f1c902c03 --- /dev/null +++ b/code/align/rollout/__init__.py @@ -0,0 +1,74 @@ +"""Rollout: request/result shapes, the native sampler, and the optional spool client. + +Backends (selected by `align.rollout.client.make_rollout_client`): + + 'native' (default) `native.NativeRolloutBackend` -- in-process torch KV-cache + sampler; zero dependencies beyond torch. + 'spool' `client.RolloutClient` -- file protocol to the optional + vLLM worker in extras/vllm_rollout/ (its own venv). + +Nothing under align/ imports vllm or ray, and nothing under align/ imports +extras/ (tests/test_dependency_firewall.py enforces both). The extras worker +imports `align.rollout.protocol`, which is stdlib-only BY CONTRACT; this +package `__init__` therefore imports ONLY that module eagerly. The torch-using +pieces (`NativeRolloutBackend`, `make_rollout_client`) resolve lazily so the +worker's venv never pays for, or is constrained by, them. + +Per the 2026-08-22 sovereignty amendment (RESULTS.md dated entry): vLLM is +permitted for GENERATION only, in an isolated venv (.venv-rollout), behind a +process boundary. The v1 topology (DESIGN v3 section B.1b, decided 2026-08-24): +3 FSDP train ranks + 1 dedicated engine GPU; weight handoff via checkpoint +directory + engine reload every `sync_every` optimizer steps; +use_rho_correction=True absorbs the resulting off-policyness -- that is the +term's entire purpose. The native backend honours the same contract +(`load_weights_fn` on a changed weights_dir). +""" + +from align.rollout.protocol import ( + RolloutBackend, + RolloutRequest, + RolloutResult, + read_request, + read_result, + write_request, + write_result, +) + +__all__ = [ + "PagedEngine", + "PagedEngineConfig", + "PagedResult", + "SamplingParams", + "NativeRolloutBackend", + "NativeRolloutConfig", + "RolloutBackend", + "RolloutRequest", + "RolloutResult", + "checkpoint_weight_loader", + "make_rollout_client", + "read_request", + "read_result", + "write_request", + "write_result", +] + +_LAZY = { + # P3 opt-in paged continuous-batching sampler (docs/P3_ENGINE.md). Nothing + # in the default GRPO/rollout path imports these. + "PagedEngine": "align.rollout.engine", + "PagedEngineConfig": "align.rollout.engine", + "PagedResult": "align.rollout.engine", + "SamplingParams": "align.rollout.engine", + "NativeRolloutBackend": "align.rollout.native", + "NativeRolloutConfig": "align.rollout.native", + "checkpoint_weight_loader": "align.rollout.native", + "make_rollout_client": "align.rollout.client", +} + + +def __getattr__(name): + if name in _LAZY: + import importlib + + return getattr(importlib.import_module(_LAZY[name]), name) + raise AttributeError(f"module 'align.rollout' has no attribute {name!r}") diff --git a/code/align/rollout/client.py b/code/align/rollout/client.py new file mode 100644 index 0000000000000000000000000000000000000000..6d003cc38cf6676e0d9964a8f791a1e52b3e4a32 --- /dev/null +++ b/code/align/rollout/client.py @@ -0,0 +1,234 @@ +"""Trainer-side rollout clients and the backend selector. + +Two backends serve the same `RolloutRequest -> RolloutResult` contract +(align/rollout/protocol.py), chosen by `make_rollout_client(backend=...)`: + + 'native' (DEFAULT) -- `native.NativeRolloutBackend`: in-process torch + KV-cache sampler on the training/passed model. Zero extra dependencies; + this is what makes GRPO runnable on torch + triton + numpy + safetensors. + 'spool' -- `RolloutClient` below: file protocol to the optional + vLLM worker (extras/vllm_rollout/rollout_worker.py) running in its OWN + venv. A throughput option, never a requirement. + +This module lives in the TRAINING venv and imports nothing from vLLM -- the +process boundary is the sovereignty line. `spawn_worker` launches the extras +worker under the ISOLATED rollout venv with the full required environment +baked in, so a caller cannot forget the flashinfer workaround or point a cache +at the 13GB root filesystem. +""" + +from __future__ import annotations + +import os +import subprocess +from typing import Optional + +from align.rollout.protocol import ( + RolloutBackend, + RolloutRequest, + RolloutResult, + wait_for_result, + write_request, +) + +#: The selectable backends. Data, so error messages and CLIs iterate it. +BACKENDS: tuple[str, ...] = ("native", "spool") +DEFAULT_BACKEND = "native" + +#: Repo root, derived from this file's location -- the client and the worker +#: script it spawns always come from the same checkout. +REPO_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +ROLLOUT_PYTHON = os.path.join(REPO_ROOT, ".venv-rollout", "bin", "python") +#: The vLLM worker is an EXTRA (own venv, see extras/vllm_rollout/README.md), +#: not part of the align package: nothing under align/ may import it, but a +#: path string to launch it as a subprocess is the intended coupling. +WORKER_SCRIPT = os.path.join(REPO_ROOT, "extras", "vllm_rollout", "rollout_worker.py") + + +class RolloutClient: + """The 'spool' backend: submit rollout requests and block on their results. + + Timeouts are the caller's budget decision (stage-b sets them from the + measured pilot throughput); the stale-heartbeat threshold distinguishes + a slow request from a dead worker -- see protocol.wait_for_result. + """ + + def __init__(self, spool: str, timeout_s: float, stale_heartbeat_s: float = 600.0): + self.spool = spool + self.timeout_s = float(timeout_s) + self.stale_heartbeat_s = float(stale_heartbeat_s) + + def submit(self, request: RolloutRequest) -> str: + write_request(self.spool, request) + return request.request_id + + def collect(self, request_id: str) -> RolloutResult: + return wait_for_result( + self.spool, + request_id, + timeout_s=self.timeout_s, + stale_heartbeat_s=self.stale_heartbeat_s, + ) + + +#: torchrun/torchelastic variables that MUST NOT reach the worker: vLLM's +#: engine initialises torch.distributed internally, and a child that inherits +#: the trainer's rendezvous (MASTER_ADDR/RANK/WORLD_SIZE/...) tries to JOIN +#: the trainer's process group -- observed on the 2026-08-24 smoke as the +#: engine core dialing torchrun's TCP store while ranks 1-2 timed out waiting +#: for rank 0. The worker is a separate world of size 1, always. +_POISON_ENV_KEYS = ( + "MASTER_ADDR", + "MASTER_PORT", + "RANK", + "WORLD_SIZE", + "LOCAL_RANK", + "LOCAL_WORLD_SIZE", + "GROUP_RANK", + "GROUP_WORLD_SIZE", + "ROLE_RANK", + "ROLE_WORLD_SIZE", + "ROLE_NAME", + "NODE_RANK", +) +_POISON_ENV_PREFIXES = ("TORCHELASTIC_", "PET_", "TORCH_NCCL_") + + +def _worker_env() -> dict: + """A copy of os.environ with every trainer-distributed variable scrubbed.""" + return { + k: v + for k, v in os.environ.items() + if k not in _POISON_ENV_KEYS and not k.startswith(_POISON_ENV_PREFIXES) + } + + +def spawn_worker( + spool: str, + gpu: int, + log_path: str, + gpu_mem_util: float = 0.85, + tp: int = 1, + idle_exit_s: float = 0.0, + rollout_python: Optional[str] = None, +) -> subprocess.Popen: + """Launch the vLLM worker on ONE dedicated GPU with the required env. + + The env block is the launch checklist, encoded: the flashinfer sampler + is disabled (its JIT ninja build fails on this box's toolchain, measured + 2026-08-23), every cache/tmp path lands on /apps, and the HF hub cache is + the rlhf one the stage-b snapshots live in. + """ + python = rollout_python or ROLLOUT_PYTHON + if not os.path.isfile(python): + raise FileNotFoundError( + f"rollout venv python not found at {python}; build .venv-rollout first " + "(uv venv + torch==2.11.0 triton==3.6.0 vllm==0.26.0 ray pyarrow)." + ) + env = _worker_env() + env.update( + { + "CUDA_VISIBLE_DEVICES": str(gpu), + "VLLM_USE_FLASHINFER_SAMPLER": "0", + "TMPDIR": os.path.join(REPO_ROOT, ".tmp"), + "XDG_CACHE_HOME": os.path.join(REPO_ROOT, ".cache"), + "HF_HUB_CACHE": "/apps/development/rlhf/hf_cache/hub", + # worker logs must flush per line or a killed worker leaves an + # empty log (first smoke run, 2026-08-24) + "PYTHONUNBUFFERED": "1", + } + ) + os.makedirs(os.path.dirname(os.path.abspath(log_path)), exist_ok=True) + log = open(log_path, "a") + return subprocess.Popen( + [ + python, + WORKER_SCRIPT, + "--spool", + spool, + "--gpu-mem-util", + str(gpu_mem_util), + "--tp", + str(tp), + "--idle-exit-s", + str(idle_exit_s), + ], + stdout=log, + stderr=subprocess.STDOUT, + env=env, + cwd=REPO_ROOT, + # own process GROUP so teardown can reap vLLM's EngineCore child -- + # terminating only the parent orphaned a 19.6GB engine core on GPU 3 + # (fifth smoke run, 2026-08-24) + start_new_session=True, + ) + + +def terminate_worker(proc: subprocess.Popen, timeout_s: float = 30.0) -> None: + """Kill the worker's WHOLE process group (worker + vLLM engine core). + + proc.terminate() reaches only the parent; the engine core reparents to + init and keeps its VRAM. Group-SIGTERM, grace, then group-SIGKILL. + """ + import signal + + try: + pgid = os.getpgid(proc.pid) + except ProcessLookupError: + return + try: + os.killpg(pgid, signal.SIGTERM) + proc.wait(timeout=timeout_s) + except subprocess.TimeoutExpired: + os.killpg(pgid, signal.SIGKILL) + proc.wait(timeout=10) + except ProcessLookupError: + pass + + +#: Explicit name for the spool backend; `RolloutClient` is kept as the +#: original spelling because existing callers and tests import it. +SpoolRolloutClient = RolloutClient + + +def make_rollout_client( + backend: str = DEFAULT_BACKEND, + *, + # -- native ----------------------------------------------------------------- + model=None, + tokenizer=None, + native_config=None, + load_weights_fn=None, + device=None, + # -- spool ------------------------------------------------------------------ + spool: Optional[str] = None, + timeout_s: float = 3600.0, + stale_heartbeat_s: float = 600.0, +) -> RolloutBackend: + """Build the selected rollout backend. + + Each backend REFUSES the other's arguments' absence loudly instead of + falling back: 'native' without a model is not "spool by default", and + 'spool' without a spool dir is not "native by default". A silent switch of + generation backend changes throughput by an order of magnitude and + off-policyness by a sync interval, and would show up first as a mystery in + the step time. + """ + if backend == "native": + if model is None or tokenizer is None: + raise ValueError( + "backend='native' needs model= and tokenizer= (the in-process sampler runs " + "on the model it is given); pass backend='spool' to use the external worker" + ) + # lazy: keeps `import align.rollout.client` free of torch/engine for + # spool-only callers + from align.rollout.native import NativeRolloutBackend + + return NativeRolloutBackend( + model, tokenizer, native_config, load_weights_fn=load_weights_fn, device=device + ) + if backend == "spool": + if not spool: + raise ValueError("backend='spool' needs spool= (the request/result spool directory)") + return RolloutClient(spool, timeout_s=timeout_s, stale_heartbeat_s=stale_heartbeat_s) + raise ValueError(f"unknown rollout backend {backend!r}; choose one of {BACKENDS}") diff --git a/code/align/rollout/engine.py b/code/align/rollout/engine.py new file mode 100644 index 0000000000000000000000000000000000000000..22fbe0311f4a7ff8f039b25aabedfba45b1cbfbf --- /dev/null +++ b/code/align/rollout/engine.py @@ -0,0 +1,674 @@ +"""Continuous-batching sampler over a paged KV cache (P3, opt-in). + +This is the native-engine step ROADMAP Track L calls P3: many sequences of very +different lengths in flight at once, admitted and retired independently, +backed by `align.rollout.paged`'s block tables. It is model-agnostic over +align's causal LMs (Mistral, Qwen3, OLMoE) WITHOUT touching them: the engine +drives the model's own submodules (`embed_tokens`, per-block `attn_norm` / +`attn.{q,k,v,o}_proj` / optional `q_norm`,`k_norm` / `mlp_norm` / `mlp`, +`norm`, `lm_head`, `rope`) layer by layer and replaces only the attention +kernel, which is the one thing a paged cache changes. Qwen3's per-head QK-norm +and OLMoE's full-width QK-norm (+ `clip_qkv`) are told apart by the norm weight +width, the same distinction the model files' docstrings warn about. + +THE SCHEDULER, in one paragraph. Every sequence is `tokens` (prompt + sampled) +and `num_computed` (how many have KV in the cache). A step schedules, per +sequence, the next `n_new = min(len(tokens) - num_computed, chunk_size, +budget)` tokens. Prefill, chunked prefill, decode and post-preemption +recompute are therefore ONE code path; a sequence samples exactly when its +scheduled tokens reach the end of `tokens`. Mixed prefill chunks and decode +tokens share a step (one flat ragged batch), so a long prompt cannot stall +the decoders behind it (the head-of-line blocking a prefill-then-decode engine +has). + +MEMORY PRESSURE. Blocks are allocated lazily as sequences grow. When a running +sequence cannot get its next block the YOUNGEST unscheduled running sequence is +preempted by RECOMPUTE: its blocks are freed, `num_computed` returns to 0, and +it re-enters the front of the waiting queue with its tokens (and its sampler +state) intact, so it re-prefills and carries on. Recompute rather than swap +because there is no host swap space on this box by design. The generator is +only advanced when a token is actually sampled, so a preemption changes WHEN a +token is drawn, never WHICH. + +BATCH INVARIANCE (the property RL rollouts care about). A sequence's tokens +and logprobs should not depend on who else is in the batch, when it was +admitted, how its prompt was chunked, or whether it was preempted: otherwise +`pi_infer_old` (the logprobs that feed the rho correction) is a function of the +scheduler's mood, and two reruns of the same rollout seed disagree. Floating +point breaks this through (a) GEMM kernels whose reduction order depends on the +number of rows, and (b) attention whose reduction length depends on padding or +chunk size. `numerics='invariant'` removes both by construction: every +row-wise module call (projections, norms, MLP, lm_head) is issued on one row +at a time, and attention is one SDPA call per query row over exactly its own +keys. Every operand the kernel sees then depends only on the sequence itself. +It is slow and is the reference/RL-safe mode. `numerics='fast'` batches rows +and pads decode attention: faster, equal to 'invariant' to rounding only +(fp64: ~1e-15 on logits and tokens identical; bf16: expect occasional +argmax/sample flips on near-ties -- docs/P3_ENGINE.md has the measured rate). + +SAMPLING. One `torch.Generator` PER SEQUENCE, seeded from `SamplingParams.seed` +(or a stable hash of the request id), advanced only by that sequence's own +draws. A shared engine generator (what `align.inference.Engine` uses) makes a +sampled token depend on how many other rows drew before it in the step, i.e. on +batch composition. Temperature, top-k, then top-p (minimal nucleus) are applied +to the fp32 logits; the RETURNED logprob is `log_softmax(logits/T)[token]` +UNTRUNCATED, the same basis as `align.rollout.native.LOGPROB_BASIS`, so the +rho correction contract is unchanged. + +PREFIX SHARING (opt-in). Requests whose prompts share leading FULL blocks with +a running sequence adopt that sequence's blocks by reference instead of +recomputing them (GRPO: G samples of one prompt prefill it once). A follower +waits until the leader has computed the shared region, never shares a partial +block, and always recomputes at least its last prompt token (it needs that +row's logits). The allocator's refcounts keep shared blocks alive until the +last owner leaves; `PagedKVCache.slots` refuses writes into a shared block. +""" + +from __future__ import annotations + +import hashlib +import math +import time +from dataclasses import dataclass, field +from typing import Callable, Optional, Sequence + +import torch +import torch.nn as nn + +from align.inference.engine import _sampling_distribution, find_stop +from align.model.mistral import apply_rotary, kv_head_index_map +from align.rollout.paged import ( + OutOfBlocks, + PagedAttention, + PagedKVCache, + Segment, + StepBatch, + TorchPagedAttention, +) + +FINISH_REASONS = ("eos", "stop_token", "stop_string", "max_new_tokens", "max_seq_len") + + +# --------------------------------------------------------------------------- +# Public dataclasses +# --------------------------------------------------------------------------- + + +@dataclass +class SamplingParams: + """Per-sequence sampling. `temperature` 0/None = greedy.""" + + max_tokens: int = 64 + temperature: Optional[float] = 0.0 + top_p: float = 1.0 + #: 0 disables. Applied BEFORE top-p (vLLM's order). + top_k: int = 0 + #: None -> stable hash of the request id (NOT admission order, which would + #: make "unseeded" depend on batch composition). + seed: Optional[int] = None + stop_token_ids: tuple[int, ...] = () + #: text stops need a tokenizer; the completion keeps the token that + #: completed the stop string (token ids and logprobs stay aligned). + stop: tuple[str, ...] = () + + def validate(self) -> None: + if self.max_tokens < 1: + raise ValueError(f"max_tokens={self.max_tokens} must be >= 1") + t = self.temperature + if t is not None and (math.isnan(t) or t < 0): + raise ValueError(f"temperature={t} must be >= 0") + if math.isnan(self.top_p) or not (0.0 < self.top_p <= 1.0): + raise ValueError(f"top_p={self.top_p} must be in (0, 1]") + if self.top_k < 0: + raise ValueError(f"top_k={self.top_k} must be >= 0") + + @property + def greedy(self) -> bool: + return self.temperature is None or self.temperature == 0.0 + + +@dataclass +class PagedEngineConfig: + #: Tokens per KV block. 16 is vLLM's default; smaller wastes less tail, + #: larger gathers fewer indices. + block_size: int = 16 + num_blocks: int = 256 + #: Max sequences resident (admitted) at once. + max_num_seqs: int = 32 + #: Per-step token budget across all segments (decode tokens + prefill chunks). + max_num_batched_tokens: int = 512 + #: Max prompt tokens one sequence contributes to a step. None -> the budget. + chunk_size: Optional[int] = None + #: Hard cap on prompt + completion. None -> the model's max_position_embeddings. + max_seq_len: Optional[int] = None + #: 'invariant' (bit-reproducible across batch compositions; slow) or 'fast'. + numerics: str = "invariant" + prefix_sharing: bool = False + eos_token_id: Optional[int] = None + #: KV dtype. None -> the model's parameter dtype. + kv_dtype: Optional[torch.dtype] = None + #: Replace the attention backend (e.g. a future Triton kernel). + attention: Optional[PagedAttention] = None + + def validate(self) -> None: + if self.numerics not in ("invariant", "fast"): + raise ValueError(f"numerics={self.numerics!r}; expected 'invariant' or 'fast'") + if min(self.block_size, self.num_blocks, self.max_num_seqs, self.max_num_batched_tokens) < 1: + raise ValueError(f"bad PagedEngineConfig: {self}") + if self.chunk_size is not None and self.chunk_size < 1: + raise ValueError(f"chunk_size={self.chunk_size} must be >= 1") + + +@dataclass +class PagedResult: + rid: str + prompt_ids: list[int] + token_ids: list[int] + logprobs: list[float] + finish_reason: str + preemptions: int = 0 + shared_prefix_tokens: int = 0 + text: Optional[str] = None + step_logits: Optional[list[torch.Tensor]] = None + + +@dataclass +class _Seq: + rid: str + prompt: list[int] + params: SamplingParams + order: int # monotonically increasing arrival index (age for preemption) + generator: torch.Generator + tokens: list[int] = field(default_factory=list) + num_computed: int = 0 + logprobs: list[float] = field(default_factory=list) + finish: Optional[str] = None + preemptions: int = 0 + shared_tokens: int = 0 + logits_log: Optional[list[torch.Tensor]] = None + + @property + def remaining(self) -> int: + return len(self.tokens) - self.num_computed + + @property + def n_generated(self) -> int: + return len(self.tokens) - len(self.prompt) + + +# --------------------------------------------------------------------------- +# Sampling +# --------------------------------------------------------------------------- + + +def top_k_filter(logits: torch.Tensor, k: int) -> torch.Tensor: + """Keep the k largest logits of a [V] / [B,V] tensor, others -> -inf. + + Ties at the k-th value are resolved by `torch.topk`'s index order, which is + deterministic; the cut is by COUNT, never by value, so exactly k survive.""" + if k <= 0 or k >= logits.shape[-1]: + return logits + idx = torch.topk(logits, k, dim=-1).indices + out = torch.full_like(logits, float("-inf")) + return out.scatter(-1, idx, logits.gather(-1, idx)) + + +def row_distribution(logits: torch.Tensor, p: SamplingParams) -> torch.Tensor: + """The distribution a non-greedy draw is made from: softmax(logits/T) over the + top-k survivors, truncated to the minimal top-p nucleus, renormalised. [V] fp32. + Split out so tests can compare it with an independent fp64 reference instead + of inferring it from draw frequencies.""" + masked = top_k_filter(logits.float(), p.top_k) + return _sampling_distribution(masked.unsqueeze(0), float(p.temperature), p.top_p)[0] + + +def sample_row( + logits: torch.Tensor, p: SamplingParams, gen: torch.Generator +) -> tuple[int, float]: + """One row [V] -> (token, logprob). Greedy = argmax. The logprob is of the + UNTRUNCATED tempered distribution (T=1 for greedy): top-k/top-p decide which + token is drawn, they are not part of the distribution the training objective + models (see align.rollout.native for why folding them in breaks rho).""" + x = logits.float() + if p.greedy: + tok = int(x.argmax()) + return tok, float(torch.log_softmax(x, dim=-1)[tok]) + lp = torch.log_softmax(x / float(p.temperature), dim=-1) + probs = row_distribution(logits, p) + tok = int(torch.multinomial(probs.unsqueeze(0), 1, generator=gen)[0, 0]) + return tok, float(lp[tok]) + + +def _stable_seed(rid: str) -> int: + return int.from_bytes(hashlib.sha256(rid.encode()).digest()[:8], "little") & ((1 << 62) - 1) + + +# --------------------------------------------------------------------------- +# Model adapter +# --------------------------------------------------------------------------- + + +class _ModelView: + """Reads align's causal-LM structure and runs it layer by layer on a flat + token batch. Raises at construction on anything it does not recognise, so a + new architecture fails at build, not as wrong logits.""" + + def __init__(self, model: nn.Module): + try: + inner = model.model + self.embed, self.layers, self.final_norm, self.rope = ( + inner.embed_tokens, list(inner.layers), inner.norm, inner.rope, + ) + self.lm_head = model.lm_head + except AttributeError as e: + raise TypeError( + f"{type(model).__name__} does not look like an align causal LM " + f"(needs .model.{{embed_tokens,layers,norm,rope}} and .lm_head): {e}" + ) from None + a0 = self.layers[0].attn + for attr in ("n_heads", "n_kv_heads", "head_dim", "scale", "q_proj", "k_proj", "v_proj", "o_proj"): + if not hasattr(a0, attr): + raise TypeError(f"attention module lacks `{attr}`; unsupported architecture") + self.n_layers = len(self.layers) + self.n_heads, self.n_kv_heads, self.head_dim, self.scale = ( + a0.n_heads, a0.n_kv_heads, a0.head_dim, a0.scale, + ) + # The paged backends use SDPA's enable_gqa, i.e. the canonical BLOCKED map + # q_head // group -> kv_head. Anything else would be silently wrong. + group = self.n_heads // self.n_kv_heads + idx = kv_head_index_map(self.n_heads, self.n_kv_heads, device=torch.device("cpu")) + if not torch.equal(idx, torch.arange(self.n_heads) // group): + raise NotImplementedError("non-canonical kv-head map is not supported by the paged engine") + self.qk_norm = self._qk_norm_kind(a0) + self.clip = getattr(a0, "clip_qkv", None) + + def _qk_norm_kind(self, attn) -> Optional[str]: + if not hasattr(attn, "q_norm"): + return None + w = attn.q_norm.weight.numel() + if w == self.head_dim: + return "head" # Qwen3 + if w == self.n_heads * self.head_dim: + return "full" # OLMoE + raise NotImplementedError(f"q_norm width {w} matches neither head_dim nor n_heads*head_dim") + + def qkv(self, attn, h: torch.Tensor): + """h [1,t,D] -> q [1,t,H,Dh], k/v [1,t,Hkv,Dh] BEFORE RoPE.""" + b, t, _ = h.shape + q, k, v = attn.q_proj(h), attn.k_proj(h), attn.v_proj(h) + if self.qk_norm == "full": + q, k = attn.q_norm(q), attn.k_norm(k) + if self.clip is not None: + c = self.clip + q, k, v = q.clamp(-c, c), k.clamp(-c, c), v.clamp(-c, c) + q = q.view(b, t, self.n_heads, self.head_dim) + k = k.view(b, t, self.n_kv_heads, self.head_dim) + v = v.view(b, t, self.n_kv_heads, self.head_dim) + if self.qk_norm == "head": + q, k = attn.q_norm(q), attn.k_norm(k) + return q, k, v + + +def _assert_finite_logits(logits: torch.Tensor, rids: list[str]) -> None: + """Raise FloatingPointError if any sampled row holds NaN or +inf. + + Sampled rows would fail loudly inside torch.multinomial, but GREEDY rows do not: + argmax of a row containing NaN returns the NaN's index and `log_softmax` returns + NaN, so a bf16 overflow silently becomes a plausible-looking token with a NaN + logprob that then poisons the rho correction. -inf is allowed (a masked vocab). + Called BEFORE `num_computed` advances, so the step is retryable and no sequence has + consumed a draw from its generator.""" + ok = (logits == logits) & (logits != float("inf")) + if logits.numel() and not bool(ok.all()): + bad = [rids[i] for i in range(len(rids)) if not bool(ok[i].all())] + raise FloatingPointError(f"non-finite logits (NaN/+inf) for request(s) {bad}") + + +def _rows(fn: Callable, x: torch.Tensor, rowwise: bool): + """Apply `fn` to x [1,T,D]; if `rowwise`, once per row [1,1,D] and re-join. + + This is the whole invariance trick for non-attention ops: a GEMM with M=1 + runs the same kernel on the same operands whatever the step contains.""" + if not rowwise or x.shape[1] == 1: + return fn(x) + outs = [fn(x[:, i : i + 1]) for i in range(x.shape[1])] + if isinstance(outs[0], tuple): + return tuple(torch.cat([o[j] for o in outs], dim=1) for j in range(len(outs[0]))) + return torch.cat(outs, dim=1) + + +# --------------------------------------------------------------------------- +# Engine +# --------------------------------------------------------------------------- + + +class PagedEngine: + """Continuous-batching sampler. Usage: + + eng = PagedEngine(model, PagedEngineConfig(num_blocks=64)) + eng.add_request("a", prompt_ids, SamplingParams(max_tokens=32, seed=1)) + while eng.has_unfinished(): + eng.step() # may add_request between steps + res = eng.results["a"] + """ + + def __init__(self, model: nn.Module, cfg: Optional[PagedEngineConfig] = None, *, + tokenizer=None, return_logits: bool = False): + self.cfg = cfg if cfg is not None else PagedEngineConfig() + self.cfg.validate() + self.model = model + self.view = _ModelView(model) + self.tokenizer = tokenizer + self.return_logits = return_logits + p0 = next(model.parameters()) + self.device = p0.device + kv_dtype = self.cfg.kv_dtype or p0.dtype + mcfg = getattr(model, "cfg", None) + self.max_seq_len = self.cfg.max_seq_len or getattr(mcfg, "max_position_embeddings", 2048) + self.cache = PagedKVCache( + self.view.n_layers, self.cfg.num_blocks, self.cfg.block_size, + self.view.n_kv_heads, self.view.head_dim, kv_dtype, self.device, + ) + self.rowwise = self.cfg.numerics == "invariant" + self.attention: PagedAttention = self.cfg.attention or TorchPagedAttention( + "row" if self.rowwise else "segment" + ) + self.waiting: list[_Seq] = [] + self.running: list[_Seq] = [] + self.results: dict[str, PagedResult] = {} + self._known: set[str] = set() + self._arrivals = 0 + self.stats = dict(steps=0, tokens_forward=0, preemptions=0, prefix_tokens_shared=0, + peak_blocks_used=0, tokens_sampled=0, forward_seconds=0.0) + + # -- requests --------------------------------------------------------------- + + def add_request(self, rid: str, prompt_ids: Sequence[int], params: Optional[SamplingParams] = None) -> None: + params = params if params is not None else SamplingParams() + params.validate() + if rid in self._known: + raise ValueError(f"duplicate request id {rid!r}") + prompt = [int(t) for t in prompt_ids] + if not prompt: + raise ValueError(f"{rid!r}: empty prompt") + # An out-of-range id fails INSIDE the embedding lookup during `step()`, long after + # add_request returned: on CPU it is an IndexError that re-fires on every later step + # (the poisoned request stays in `running`, so one bad prompt wedges every other + # request), on CUDA a device-side assert that corrupts the whole context. Refuse it here. + vocab = self.view.embed.weight.shape[0] + bad = next((t for t in prompt if not 0 <= t < vocab), None) + if bad is not None: + raise ValueError(f"{rid!r}: token id {bad} outside the model vocabulary [0, {vocab})") + if len(prompt) >= self.max_seq_len: + raise ValueError(f"{rid!r}: prompt of {len(prompt)} tokens reaches max_seq_len={self.max_seq_len}") + if params.stop and self.tokenizer is None: + raise ValueError("text stop sequences need a tokenizer") + # The LAST sampled token is never fed back, so it never gets KV: a request + # that ends with `worst` tokens holds `worst - 1` in the cache. Sizing the guard + # on `worst` refuses a request that fits exactly (prompt 3 + 6 new, block 4 -> + # 8 cached tokens = 2 blocks, yet a 2-block pool was rejected as needing 3). + worst = min(len(prompt) + params.max_tokens, self.max_seq_len) - 1 + if self.cache.blocks_needed(worst) > self.cache.num_blocks: + raise ValueError( + f"{rid!r} can need {self.cache.blocks_needed(worst)} blocks but the pool has " + f"{self.cache.num_blocks}: it could never finish even running alone" + ) + seed = params.seed if params.seed is not None else _stable_seed(rid) + gen = torch.Generator(device=self.device) + gen.manual_seed(int(seed)) + seq = _Seq(rid=rid, prompt=prompt, params=params, order=self._arrivals, generator=gen, + tokens=list(prompt), logits_log=[] if self.return_logits else None) + self._arrivals += 1 + self._known.add(rid) + self.waiting.append(seq) + + def has_unfinished(self) -> bool: + return bool(self.waiting or self.running) + + # -- scheduling ------------------------------------------------------------- + + def _lcp(self, a: list[int], b: list[int]) -> int: + n = min(len(a), len(b)) + i = 0 + while i < n and a[i] == b[i]: + i += 1 + return i + + def _find_share(self, seq: _Seq) -> Optional[tuple[list[int], bool]]: + """-> (blocks to adopt, defer?) for the best leader among running seqs.""" + bs = self.cfg.block_size + cap_blocks = (len(seq.tokens) - 1) // bs # always recompute the last token + best: list[int] = [] + defer = False + for src in self.running: + lcp_blocks = min(self._lcp(seq.tokens, src.tokens), len(src.prompt)) // bs + lcp_blocks = min(lcp_blocks, cap_blocks) + if lcp_blocks == 0: + continue + ready = min(lcp_blocks, src.num_computed // bs) + if ready < lcp_blocks and src.num_computed < len(src.prompt): + defer = True # the leader is still computing blocks we could adopt + if ready > len(best): + best = list(self.cache.tables[src.rid][:ready]) + return best, defer + + @staticmethod + def _pick_victim(victims: list[_Seq]) -> _Seq: + """The YOUNGEST (latest arrival): it has the least computed work to throw + away, and older sequences keep making progress, so the oldest request is + never starved by newer ones.""" + return max(victims, key=lambda s: s.order) + + def _preempt(self, seq: _Seq) -> None: + self.cache.free_seq(seq.rid) + self.running.remove(seq) + seq.num_computed = 0 + seq.shared_tokens = 0 + seq.preemptions += 1 + self.stats["preemptions"] += 1 + self.waiting.append(seq) + self.waiting.sort(key=lambda s: s.order) + + def _schedule(self) -> list[tuple[_Seq, int]]: + cfg = self.cfg + chunk = cfg.chunk_size or cfg.max_num_batched_tokens + budget = cfg.max_num_batched_tokens + sched: list[tuple[_Seq, int]] = [] + scheduled: set[str] = set() + + # 1) resident sequences: decodes first, then prefill chunks, oldest first + for seq in sorted(self.running, key=lambda s: (s.remaining > 1, s.order)): + if seq not in self.running or budget <= 0: + continue + n = min(seq.remaining, chunk, budget) + while True: + try: + self.cache.ensure_capacity(seq.rid, seq.num_computed + n) + break + except OutOfBlocks: + victims = [s for s in self.running if s is not seq and s.rid not in scheduled] + if not victims: + n = 0 + break + self._preempt(self._pick_victim(victims)) + if n == 0: + continue + sched.append((seq, n)) + scheduled.add(seq.rid) + budget -= n + + # 2) admit waiting sequences (FIFO, deferred followers skipped) + for seq in list(self.waiting): + if budget <= 0 or len(self.running) >= cfg.max_num_seqs: + break + shared: list[int] = [] + if cfg.prefix_sharing: + got = self._find_share(seq) + shared, defer = got + if defer: + continue + start = len(shared) * cfg.block_size + n = min(len(seq.tokens) - start, chunk, budget) + need = self.cache.blocks_needed(len(seq.tokens)) - len(shared) + if not self.cache.allocator.can_allocate(need): + break # keep FIFO: do not let a small request leapfrog a starving big one + self.waiting.remove(seq) + self.cache.add_seq(seq.rid, shared) + seq.num_computed = start + seq.shared_tokens = start + self.stats["prefix_tokens_shared"] += start + self.cache.ensure_capacity(seq.rid, start + n) + self.running.append(seq) + sched.append((seq, n)) + scheduled.add(seq.rid) + budget -= n + return sched + + # -- one step --------------------------------------------------------------- + + def step(self) -> list[tuple[str, int, Optional[str]]]: + """Run one scheduler step. Returns [(rid, token, finish_reason|None)] for + every token sampled this step.""" + sched = self._schedule() + if not sched: + if self.running or self.waiting: + raise RuntimeError( + "scheduler made no progress: no sequence can get the blocks it needs " + f"(free={self.cache.allocator.num_free}, running={len(self.running)}, " + f"waiting={len(self.waiting)})" + ) + return [] + batch = StepBatch() + toks: list[int] = [] + pos: list[int] = [] + off = 0 + for seq, n in sched: + batch.segments.append(Segment(seq.rid, off, n, seq.num_computed)) + toks.extend(seq.tokens[seq.num_computed : seq.num_computed + n]) + pos.extend(range(seq.num_computed, seq.num_computed + n)) + off += n + # rows whose logits we need: the last row of every segment that reaches + # the end of its sequence's tokens + sample_rows = [ + (seq, seg.offset + seg.n_new - 1) + for (seq, n), seg in zip(sched, batch.segments) + if seq.num_computed + n == len(seq.tokens) + ] + t0 = time.perf_counter() + with torch.no_grad(): + logits = self._forward( + torch.tensor(toks, dtype=torch.long, device=self.device), + torch.tensor(pos, dtype=torch.long, device=self.device), + batch, + [r for _, r in sample_rows], + ) + # The finiteness check reads a device scalar, i.e. it synchronises: placing it BEFORE + # the timer stops makes `forward_seconds` include the GPU work (CUDA launches are + # async, so without a sync here the stat measured kernel-launch time only). + _assert_finite_logits(logits, [seq.rid for seq, _ in sample_rows]) + self.stats["forward_seconds"] += time.perf_counter() - t0 + self.stats["steps"] += 1 + self.stats["tokens_forward"] += off + self.stats["peak_blocks_used"] = max(self.stats["peak_blocks_used"], self.cache.allocator.num_used) + + for seq, n in sched: + seq.num_computed += n + self.cache.lengths[seq.rid] = seq.num_computed + + events = [] + for i, (seq, _) in enumerate(sample_rows): + row = logits[i] + tok, lp = sample_row(row, seq.params, seq.generator) + if seq.logits_log is not None: + seq.logits_log.append(row.detach().float().cpu()) + seq.tokens.append(tok) + seq.logprobs.append(lp) + self.stats["tokens_sampled"] += 1 + reason = self._finish_reason(seq) + events.append((seq.rid, tok, reason)) + if reason is not None: + self._retire(seq, reason) + return events + + def _finish_reason(self, seq: _Seq) -> Optional[str]: + p, gen = seq.params, seq.tokens[len(seq.prompt):] + last = gen[-1] + if self.cfg.eos_token_id is not None and last == self.cfg.eos_token_id: + return "eos" + if last in p.stop_token_ids: + return "stop_token" + if p.stop: + text = self.tokenizer.decode(gen, skip_special_tokens=True) + if find_stop(text, p.stop) is not None: + return "stop_string" + if len(gen) >= p.max_tokens: + return "max_new_tokens" + if len(seq.tokens) >= self.max_seq_len: + return "max_seq_len" + return None + + def _retire(self, seq: _Seq, reason: str) -> None: + seq.finish = reason + self.cache.free_seq(seq.rid) + self.running.remove(seq) + gen = seq.tokens[len(seq.prompt):] + text = self.tokenizer.decode(gen, skip_special_tokens=True) if self.tokenizer is not None else None + self.results[seq.rid] = PagedResult( + rid=seq.rid, prompt_ids=list(seq.prompt), token_ids=list(gen), logprobs=list(seq.logprobs), + finish_reason=reason, preemptions=seq.preemptions, shared_prefix_tokens=seq.shared_tokens, + text=text, step_logits=seq.logits_log, + ) + + # -- the model, layer by layer ------------------------------------------------- + + def _forward(self, tokens: torch.Tensor, positions: torch.Tensor, batch: StepBatch, + sample_row_ids: list[int]) -> torch.Tensor: + v, rw = self.view, self.rowwise + x = v.embed(tokens).unsqueeze(0) # [1, T, D] + cos, sin = v.rope(positions.unsqueeze(0)) + for li, blk in enumerate(v.layers): + attn = blk.attn + h = _rows(blk.attn_norm, x, rw) + q, k, val = _rows(lambda z: v.qkv(attn, z), h, rw) + qh, kh = apply_rotary(q.transpose(1, 2), k.transpose(1, 2), cos, sin) # [1,H,T,Dh] + out = self.attention( + li, qh[0].transpose(0, 1), kh[0].transpose(0, 1), val[0], + self.cache, batch, v.scale, + ) # [T, H, Dh] + x = x + _rows(attn.o_proj, out.reshape(1, out.shape[0], -1), rw) + + def mlp(z, blk=blk): + o = blk.mlp(blk.mlp_norm(z)) + return o[0] if isinstance(o, tuple) else o + + x = x + _rows(mlp, x, rw) + if not sample_row_ids: + return x.new_zeros((0, 1)) + sel = x[:, torch.tensor(sample_row_ids, device=x.device)] + sel = _rows(v.final_norm, sel, rw) + return _rows(v.lm_head, sel, rw)[0] + + # -- convenience ---------------------------------------------------------------- + + def generate( + self, + requests: Sequence[tuple[str, Sequence[int], SamplingParams]], + arrival_step: Optional[dict[str, int]] = None, + max_steps: int = 1_000_000, + ) -> dict[str, PagedResult]: + """Run `requests` to completion. `arrival_step[rid] = s` admits that + request to the queue just before step s (0 = immediately), which is how + tests stage 'admitted at different steps'.""" + arrival_step = arrival_step or {} + pending = sorted(requests, key=lambda r: arrival_step.get(r[0], 0)) + i, s = 0, 0 + while i < len(pending) or self.has_unfinished(): + while i < len(pending) and arrival_step.get(pending[i][0], 0) <= s: + self.add_request(*pending[i]) + i += 1 + if self.has_unfinished(): + self.step() + s += 1 + if s > max_steps: + raise RuntimeError("generate exceeded max_steps") + return {r[0]: self.results[r[0]] for r in requests} diff --git a/code/align/rollout/native.py b/code/align/rollout/native.py new file mode 100644 index 0000000000000000000000000000000000000000..1434abc453a679dd39902b671cb7b2e21c4d36e1 --- /dev/null +++ b/code/align/rollout/native.py @@ -0,0 +1,372 @@ +"""Native rollout: GRPO generation on torch alone, in-process, zero extra deps. + +This is the CORE rollout backend. vLLM (extras/vllm_rollout/) is an optional +throughput upgrade behind a process boundary; this module is what makes the +GRPO stage runnable with exactly torch + triton + numpy + safetensors. It +satisfies the same `RolloutBackend` surface (submit/collect) and returns the +same `RolloutResult` the spool client returns, so `align.rl.batch_source` +cannot tell which backend served it. + +What it does, in one paragraph: tokenize each prompt ONCE (those ids are +returned in `extras["prompt_token_ids"]` and are what assembly concatenates -- +prompts are never re-tokenized), expand to P x G `GenerationRequest`s, run +them through `align.inference.engine.Engine` (varlen batched prefill, +contiguous per-slot KV, completion-based refill) with +`return_logprobs=True`, and regroup into completions[i][j] / logprobs[i][j] / +texts[i][j]. The per-token logprobs are captured AT SAMPLING TIME from the +very logits the token was drawn from; they are never recomputed from text. + +THE RHO-CORRECTION CONTRACT (the reason logprobs travel with the rollout). +The GRPO module's `old_logprobs` is a teacher-forced pass over +(prompt + completion): `log_softmax(logits / T)` gathered at the label. +`vllm_logprobs` (pi^infer_old) must be the same quantity as seen by the +sampler. With the native engine they differ only by floating-point noise +(KV-cache decode vs full-sequence forward), so rho = exp(old - infer) == 1 up +to ~1e-6 in fp32 -- which `tests/test_rollout_native.py` pins by recomputing +the teacher-forced gather on the same model. The basis is therefore +log_softmax(logits / T), UNTRUNCATED: top-p shapes which token gets drawn but +is not a part of the distribution the training objective models, and folding +it into the logprob would make rho != 1 on-policy for every top_p < 1. + +TOPOLOGY CAVEAT. The backend drives a model it can call standalone on its own +device. That is a dedicated engine copy (the v1 topology: one engine GPU +beside the FSDP train ranks) or a single-process run (CPU tests, 1-GPU +smoke). It is NOT valid to point it at an FSDP2-sharded module from one rank: +the decode loop's forwards are collectives and the other ranks would never +join them. `GrpoBatchSource` only generates on rank 0, which is exactly why the +sharded case needs a separate engine-side copy plus `load_weights_fn`. + +WEIGHT SYNC. `request.weights_dir` is provenance, not an input, unless the +caller supplies `load_weights_fn`: then a CHANGED weights_dir triggers +`load_weights_fn(weights_dir)` (and `engine_reloaded=True`), mirroring the +spool worker's "checkpoint saves ARE the weight sync" contract. With no hook +the model is assumed live (shared parameters), so there is nothing to sync. +""" + +from __future__ import annotations + +import inspect +import logging +import time +from dataclasses import dataclass +from typing import Callable, Optional + +import torch + +from align.inference.engine import Engine, GenerationRequest, InferenceConfig +from align.rollout.protocol import RolloutRequest, RolloutResult + +logger = logging.getLogger(__name__) + +#: How the returned logprobs are defined; stamped into `extras` so a result +#: file is self-describing about the one thing the rho correction depends on. +LOGPROB_BASIS = "log_softmax(logits/T)[token], fp32, no top-p truncation (T=1 for greedy)" + + +def checkpoint_weight_loader(model, dtype: Optional[torch.dtype] = None) -> Callable[[str], None]: + """A `load_weights_fn` that refreshes a STANDALONE engine model from a + trainer checkpoint directory ("checkpoint saves ARE the weight sync"). + + Reads the HF-layout safetensors the Trainer wrote (single file or sharded + snapshot), converts to the align key layout and copies INTO the model's + existing parameters (`assign=False`): the Engine and any CUDA graphs hold + references to those tensors, so rebinding them would silently leave the + sampler on stale weights. `strict=True`: a checkpoint that does not cover + every parameter is a wrong sync, not a partial one. + """ + from align.model import checkpoint as ckpt + + def _load(weights_dir: str) -> None: + if dtype is None: + target = next(model.parameters()).dtype + else: + target = dtype + state = ckpt.hf_to_nmo(ckpt.load_hf_safetensors(weights_dir, dtype=target)) + with torch.no_grad(): + model.load_state_dict(state, strict=True) + + return _load + + +@dataclass +class NativeRolloutConfig: + """Knobs of the native backend, one docstring per field.""" + + #: Concurrent sequences = KV slots. Each slot owns `max_seq_len` tokens of + #: KV for the engine's life (128 KiB/token at 7B bf16), so this multiplies + #: the cache budget directly. The engine is built with + #: min(n_slots, sequences-in-the-request) so a small request does not pay + #: for a big cache. + n_slots: int = 32 + #: HARD cap on per-slot sequence length (prompt + completion). The engine + #: is sized to the request's actual need (longest prompt + max_tokens) + #: rounded up to `seq_len_granularity` and never above this; a sequence + #: that reaches the cap ends with finish_reason 'max_seq_len' (recorded in + #: extras), while a PROMPT that alone reaches it is refused loudly -- the + #: truncation of a prompt must be visible upstream, not done here. + max_seq_len_cap: int = 2048 + #: Engine rebuilds are expensive (the KV is preallocated), so the length is + #: rounded up to a multiple of this to make growth rare. + seq_len_granularity: int = 64 + #: Passed to the tokenizer when encoding prompts. True matches what vLLM's + #: `LLM.generate(prompts)` does (prepends BOS for Mistral), which keeps the + #: native and spool backends token-identical on the same prompt text. + add_special_tokens: bool = True + #: Used when a request carries `seed=None`: the n-th unseeded request gets + #: default_seed + n, so even "unseeded" rollouts are reproducible per run. + default_seed: int = 0 + #: Ends a sequence when sampled. None -> take it from the tokenizer. + eos_token_id: Optional[int] = None + #: Filler for right-padded prefill rows; never read back. + pad_token_id: int = 0 + #: 'length' admits shortest-first (measured default, see InferenceConfig). + admission_order: str = "length" + #: Run the engine's VRAM preflight when the KV cache is allocated on CUDA. + preflight: bool = True + + +def _make_encoder(tokenizer, add_special_tokens: bool) -> Callable[[str], list[int]]: + """prompt text -> token ids, over the minimal tokenizer contract. + + The contract is `encode(text) -> list[int]` and + `decode(ids, skip_special_tokens=True) -> str`. If `encode` takes an + `add_special_tokens` keyword it is passed; otherwise the tokenizer is + taken to apply its own convention and the flag is not forwarded. Decided + once from the signature, not by catching TypeError per call -- a TypeError + raised INSIDE a tokenizer must surface, not be mistaken for "no such kwarg". + """ + enc = tokenizer.encode + try: + params = inspect.signature(enc).parameters + except (TypeError, ValueError): # builtins / odd callables + params = {} + accepts = "add_special_tokens" in params or any( + p.kind is inspect.Parameter.VAR_KEYWORD for p in params.values() + ) + + def encode(text: str) -> list[int]: + out = enc(text, add_special_tokens=add_special_tokens) if accepts else enc(text) + ids = getattr(out, "ids", out) # tolerate an Encoding-like return + return [int(t) for t in ids] + + return encode + + +class NativeRolloutBackend: + """In-process rollout on a torch model via the repo's own KV-cache engine. + + `submit(request)` runs the whole request synchronously and parks the + result; `collect(request_id)` hands it over. That keeps the two-call + surface of the spool client (so `GrpoBatchSource` is backend-agnostic) + while being honest that there is no worker to wait on. + """ + + def __init__( + self, + model, + tokenizer, + cfg: Optional[NativeRolloutConfig] = None, + *, + load_weights_fn: Optional[Callable[[str], None]] = None, + device: Optional[torch.device] = None, + ): + if tokenizer is None: + raise ValueError( + "native rollout needs a tokenizer: prompts must be encoded here (and their " + "ids returned) and completions decoded to the exact text the reward path scores" + ) + self.model = model + self.tokenizer = tokenizer + self.cfg = cfg if cfg is not None else NativeRolloutConfig() + if self.cfg.n_slots < 1 or self.cfg.max_seq_len_cap < 2 or self.cfg.seq_len_granularity < 1: + raise ValueError(f"bad NativeRolloutConfig: {self.cfg}") + self.load_weights_fn = load_weights_fn + self.device = device + eos = self.cfg.eos_token_id + self.eos_token_id = eos if eos is not None else getattr(tokenizer, "eos_token_id", None) + self._encode = _make_encoder(tokenizer, self.cfg.add_special_tokens) + + self._engine: Optional[Engine] = None + self._results: dict[str, RolloutResult] = {} + self._loaded_weights_dir: Optional[str] = None + self._unseeded = 0 + + # -- the RolloutBackend surface -------------------------------------------- + + def submit(self, request: RolloutRequest) -> str: + if request.request_id in self._results: + # same refusal as the spool protocol's write_request + raise FileExistsError(f"duplicate request_id {request.request_id!r}") + self._results[request.request_id] = self.generate(request) + return request.request_id + + def collect(self, request_id: str) -> RolloutResult: + try: + return self._results.pop(request_id) + except KeyError: + raise KeyError( + f"no pending native result for {request_id!r} (never submitted, or already " + "collected: results are single-use, as the spool's consumed files are)" + ) from None + + # -- core ------------------------------------------------------------------- + + def generate(self, request: RolloutRequest) -> RolloutResult: + """One request -> one RolloutResult. Exceptions propagate directly: there + is no worker boundary to convert them into an `error` result across.""" + request.validate(check_weights_dir=False) + reloaded = self._maybe_sync_weights(request.weights_dir) + + prompt_ids = [self._encode(p) for p in request.prompts] + n, g = len(request.prompts), request.n_samples_per_prompt + engine = self._engine_for( + need_len=max(len(p) for p in prompt_ids) + request.max_tokens, n_sequences=n * g + ) + + seed = request.seed + if seed is None: + seed = self.cfg.default_seed + self._unseeded + self._unseeded += 1 + # Re-seed per request: the sample stream is a pure function of + # (weights, prompts, seed), not of how many requests came before. + engine.generator.manual_seed(int(seed)) + + gen_requests = [ + GenerationRequest( + rid=f"{request.request_id}:{i}:{j}", + prompt_ids=prompt_ids[i], + max_new_tokens=request.max_tokens, + temperature=request.temperature, + top_p=request.top_p, + ) + for i in range(n) + for j in range(g) + ] + + t0 = time.perf_counter() + with _rollout_mode(self.model): + results = engine.generate(gen_requests, return_logprobs=True) + gen_s = time.perf_counter() - t0 + + completions, logprobs, texts, finish = [], [], [], [] + for i in range(n): + row = results[i * g : (i + 1) * g] + for r in row: + if r.logprobs is None or len(r.logprobs) != len(r.token_ids): + raise RuntimeError( + f"{r.rid}: engine returned {None if r.logprobs is None else len(r.logprobs)}" + f" logprobs for {len(r.token_ids)} tokens; the rho correction cannot run" + ) + if r.text is None: # unreachable with a tokenizer; cheap to keep honest + raise RuntimeError(f"{r.rid}: engine returned no decoded text") + completions.append([r.token_ids for r in row]) + logprobs.append([r.logprobs for r in row]) + texts.append([r.text for r in row]) + finish.append([r.finish_reason for r in row]) + + return RolloutResult( + request_id=request.request_id, + completions=completions, + logprobs=logprobs, + texts=texts, + weights_dir=request.weights_dir, + engine_reloaded=reloaded, + generate_seconds=gen_s, + extras={ + # THE tokenization of each prompt that the completions continue + # from; assembly forbids re-deriving it (audit R1 class). + "prompt_token_ids": [list(p) for p in prompt_ids], + "finish_reasons": finish, + "backend": "native", + "seed": int(seed), + "logprob_basis": LOGPROB_BASIS, + "engine_max_seq_len": engine.cfg.max_seq_len, + "engine_n_slots": engine.cfg.n_slots, + }, + ) + + # -- internals ---------------------------------------------------------------- + + def _maybe_sync_weights(self, weights_dir: str) -> bool: + if self.load_weights_fn is None or not weights_dir: + return False + if weights_dir == self._loaded_weights_dir: + return False + t0 = time.perf_counter() + self.load_weights_fn(weights_dir) + self._loaded_weights_dir = weights_dir + logger.info("native rollout: weights synced from %s in %.1fs", weights_dir, + time.perf_counter() - t0) + return True + + def _engine_for(self, need_len: int, n_sequences: int) -> Engine: + """The cached engine if it is big enough, else a (re)built one. + + Grows only: a shorter later request reuses the bigger cache, so a run + converges to one engine after a few steps instead of thrashing on + prompt-length variance. The old engine's KV is freed BEFORE the new + one is allocated -- both alive at once would double the cache. + """ + gran = self.cfg.seq_len_granularity + want_len = min(self.cfg.max_seq_len_cap, -(-need_len // gran) * gran) + want_slots = min(self.cfg.n_slots, n_sequences) + eng = self._engine + if eng is not None and eng.cfg.max_seq_len >= want_len and eng.cfg.n_slots >= want_slots: + return eng + if eng is not None: + want_len = max(want_len, eng.cfg.max_seq_len) + want_slots = max(want_slots, eng.cfg.n_slots) + self._engine = None + del eng + if torch.cuda.is_available(): + torch.cuda.empty_cache() + icfg = InferenceConfig( + n_slots=want_slots, + max_seq_len=want_len, + max_new_tokens=1, # always overridden per request + temperature=1.0, + top_p=1.0, + seed=self.cfg.default_seed, + eos_token_id=self.eos_token_id, + pad_token_id=self.cfg.pad_token_id, + admission_order=self.cfg.admission_order, + ) + self._engine = Engine( + self.model, + icfg, + tokenizer=self.tokenizer, + device=self.device, + preflight=self.cfg.preflight, + ) + return self._engine + + +class _rollout_mode: + """Borrow a TRAINING model for sampling, then give it back untouched. + + The engine flips every attention module's backend per phase (prefill vs + decode) and runs the model as-is; on a model that is also being trained + that would leak: a decode-phase 'sdpa' left on a `triton_fa2` model would + silently change the next TRAIN step's kernel, and a model left in eval() + would stay there. Both are restored in `__exit__`, including on error. + """ + + def __init__(self, model): + self.model = model + + def __enter__(self): + m = self.model + self.was_training = m.training + layers = getattr(getattr(m, "model", None), "layers", None) + self.backends = ( + [(blk.attn, blk.attn.attn_implementation) for blk in layers] if layers else [] + ) + m.eval() + return m + + def __exit__(self, *exc): + for attn, impl in self.backends: + attn.attn_implementation = impl + if self.was_training: + self.model.train() + return False diff --git a/code/align/rollout/paged.py b/code/align/rollout/paged.py new file mode 100644 index 0000000000000000000000000000000000000000..43089b005604153192a58045716bc5f49e0300d7 --- /dev/null +++ b/code/align/rollout/paged.py @@ -0,0 +1,494 @@ +"""Paged KV cache for the native continuous-batching sampler (P3). + +WHY PAGING (the failure mode this replaces). `align.inference.engine.Engine` +gives every slot a CONTIGUOUS `max_seq_len` strip of KV for the engine's whole +life. For a prover-RL rollout the length distribution is brutal: most +completions stop at a few thousand tokens, a few run to the 16k/40k cap. A +strip sized for the cap wastes ~all of it on the short ones, so concurrency is +`budget / cap` regardless of what is actually in flight. On the 23 GB A10G +that is the difference between "a handful of sequences" and "as many as the +live tokens allow" (numbers: `plan_capacity`, docs/P3_ENGINE.md). Paging cuts +the cache into fixed `block_size`-token blocks handed out on demand from a +free list; a sequence owns a *block table* (list of block ids) and the waste +is bounded by one partially filled block per sequence. + +What lives here: + + * `BlockAllocator` free-list allocator with refcounts. The refcount is what + makes prefix sharing safe: a block returns to the free + list only when its LAST owner releases it. + * `PagedKVCache` per-layer `[num_blocks, block_size, Hkv, D]` tensors + + block tables. Append is COPY-FREE: the new token's K/V is + written in place at (block, offset); nothing is moved or + re-concatenated when a sequence grows (the dense-cache + `torch.cat` path is O(L) per token per layer). + * `StepBatch` the flat, ragged description of one engine step. + * `TorchPagedAttention` the pure-torch attention backend (gather from the + block table, SDPA on the gathered K/V). Correctness + first. Three granularities, see its docstring. + * `TritonPagedAttention` INTERFACE ONLY (raises NotImplementedError): the + signature a fused kernel must satisfy, so the engine + does not change when the kernel lands. + * `kv_bytes_per_token`, `plan_capacity` the memory accounting. + +Nothing here imports anything outside torch + stdlib (+ `align.model` for the +GQA map check), so the dependency firewall is untouched. +""" + +from __future__ import annotations + +import math +from dataclasses import dataclass, field +from typing import Optional, Protocol, Sequence + +import torch +import torch.nn.functional as F + + +class OutOfBlocks(RuntimeError): + """The free list cannot satisfy an allocation. The engine catches exactly this + to decide on preemption; any other error is a bug and must propagate.""" + + +# --------------------------------------------------------------------------- +# Allocator +# --------------------------------------------------------------------------- + + +class BlockAllocator: + """Free-list block allocator with reference counts. + + LIFO free list: a just-freed block is the next one handed out, which keeps + the working set of block ids small and -- more usefully for tests -- + deterministic, so a failing property run replays exactly. + + Failure modes each check prevents: + * double free -> the block would sit on the free list TWICE and be handed + to two sequences at once; their KV would silently overwrite each other. + `free` raises on refcount 0. + * free of an out-of-range / never-issued id -> same corruption, one hop + later. + * leaks -> `check_consistent` proves `free + referenced == total` and that + the free list has no duplicates; the property test calls it after every + event. + """ + + def __init__(self, num_blocks: int): + if num_blocks < 1: + raise ValueError(f"num_blocks={num_blocks} must be >= 1") + self.num_blocks = int(num_blocks) + # reversed so pop() yields block 0 first + self._free: list[int] = list(range(self.num_blocks - 1, -1, -1)) + self._ref: list[int] = [0] * self.num_blocks + + @property + def num_free(self) -> int: + return len(self._free) + + @property + def num_used(self) -> int: + return self.num_blocks - len(self._free) + + def refcount(self, block: int) -> int: + return self._ref[block] + + def can_allocate(self, n: int) -> bool: + return n <= len(self._free) + + def allocate(self) -> int: + if not self._free: + raise OutOfBlocks("no free KV blocks") + b = self._free.pop() + self._ref[b] = 1 + return b + + def incref(self, block: int) -> None: + if not (0 <= block < self.num_blocks) or self._ref[block] <= 0: + raise ValueError(f"incref of block {block} which is not allocated") + self._ref[block] += 1 + + def free(self, block: int) -> None: + if not (0 <= block < self.num_blocks): + raise ValueError(f"free of out-of-range block {block}") + if self._ref[block] <= 0: + raise ValueError(f"double free of block {block}") + self._ref[block] -= 1 + if self._ref[block] == 0: + self._free.append(block) + + def check_consistent(self) -> None: + """Raise AssertionError unless the books balance. O(num_blocks).""" + free = self._free + assert len(set(free)) == len(free), "duplicate block on the free list" + for b in free: + assert self._ref[b] == 0, f"block {b} is free but has refcount {self._ref[b]}" + referenced = sum(1 for r in self._ref if r > 0) + assert referenced + len(free) == self.num_blocks, ( + f"leak: {referenced} referenced + {len(free)} free != {self.num_blocks}" + ) + assert all(r >= 0 for r in self._ref), "negative refcount" + + +# --------------------------------------------------------------------------- +# KV cache +# --------------------------------------------------------------------------- + + +class PagedKVCache: + """Block-table KV cache. One K and one V tensor per layer, each + `[num_blocks, block_size, n_kv_heads, head_dim]`. + + A sequence is `(block_table, length)`. Token `p` of a sequence lives at + block `table[p // block_size]`, offset `p % block_size`. Block 0 is NOT + reserved: nothing pads a table with a sentinel, because every reader slices + by `length` instead. + """ + + def __init__( + self, + n_layers: int, + num_blocks: int, + block_size: int, + n_kv_heads: int, + head_dim: int, + dtype: torch.dtype = torch.float32, + device: Optional[torch.device | str] = None, + ): + if block_size < 1: + raise ValueError(f"block_size={block_size} must be >= 1") + self.n_layers, self.block_size = n_layers, int(block_size) + self.n_kv_heads, self.head_dim = n_kv_heads, head_dim + self.dtype, self.device = dtype, torch.device(device) if device is not None else torch.device("cpu") + self.allocator = BlockAllocator(num_blocks) + shape = (num_blocks, self.block_size, n_kv_heads, head_dim) + self.k = [torch.zeros(shape, dtype=dtype, device=self.device) for _ in range(n_layers)] + self.v = [torch.zeros(shape, dtype=dtype, device=self.device) for _ in range(n_layers)] + self.tables: dict[str, list[int]] = {} + self.lengths: dict[str, int] = {} + + # -- accounting ----------------------------------------------------------- + + @property + def num_blocks(self) -> int: + return self.allocator.num_blocks + + def blocks_needed(self, n_tokens: int) -> int: + return -(-n_tokens // self.block_size) + + def bytes_total(self) -> int: + itemsize = torch.empty((), dtype=self.dtype).element_size() + return self.n_layers * 2 * self.num_blocks * self.block_size * self.n_kv_heads * self.head_dim * itemsize + + # -- sequence lifecycle ---------------------------------------------------- + + def add_seq(self, seq_id: str, shared_blocks: Sequence[int] = ()) -> None: + """Register a sequence, optionally adopting FULL blocks of another one. + + Only whole blocks can be shared: a partially filled tail block is still + being appended to by its owner, and a second writer (or even a reader + racing the owner's append) would see/clobber tokens that are not part + of the shared prefix. The shared blocks are incref'd, and the length + starts at the end of the last shared block. + """ + if seq_id in self.tables: + raise ValueError(f"sequence {seq_id!r} already registered") + for b in shared_blocks: + self.allocator.incref(b) + self.tables[seq_id] = list(shared_blocks) + self.lengths[seq_id] = len(shared_blocks) * self.block_size + + def free_seq(self, seq_id: str) -> int: + """Release every block of a sequence (shared blocks only drop a ref).""" + table = self.tables.pop(seq_id) + self.lengths.pop(seq_id) + for b in table: + self.allocator.free(b) + return len(table) + + def ensure_capacity(self, seq_id: str, total_tokens: int) -> None: + """Grow the table to hold `total_tokens`. ALL-OR-NOTHING: if the free + list cannot cover the whole growth nothing is allocated, so a failed + reservation never strands blocks on a sequence that is about to be + preempted (which would make the preemption free them again -- fine -- + but a *skipped* sequence would hold them forever).""" + table = self.tables[seq_id] + need = self.blocks_needed(total_tokens) - len(table) + if need <= 0: + return + if not self.allocator.can_allocate(need): + raise OutOfBlocks(f"need {need} blocks for {seq_id!r}, {self.allocator.num_free} free") + for _ in range(need): + table.append(self.allocator.allocate()) + + def slots(self, seq_id: str, start: int, n: int) -> torch.Tensor: + """Flat slot ids (block * block_size + offset) for positions [start, start+n). + + Refuses to hand out a slot inside a block somebody else also references: + a write there would corrupt the sharer's KV with no error anywhere. + """ + table = self.tables[seq_id] + bs = self.block_size + if start + n > len(table) * bs: + raise ValueError(f"{seq_id!r}: positions up to {start + n} exceed reserved {len(table) * bs}") + pos = torch.arange(start, start + n) + blocks = torch.tensor(table, dtype=torch.long)[pos // bs] + for b in set(blocks.tolist()): + if self.allocator.refcount(b) != 1: + raise RuntimeError( + f"{seq_id!r}: write into shared block {b} (refcount {self.allocator.refcount(b)})" + ) + return (blocks * bs + pos % bs).to(self.device) + + # -- data movement ---------------------------------------------------------- + + def write(self, layer: int, slots: torch.Tensor, k: torch.Tensor, v: torch.Tensor) -> None: + """In-place scatter of `k`,`v` [n, Hkv, D] at flat `slots`. No allocation, + no copy of existing KV (the 'copy-free append').""" + self.k[layer].view(-1, self.n_kv_heads, self.head_dim)[slots] = k.to(self.dtype) + self.v[layer].view(-1, self.n_kv_heads, self.head_dim)[slots] = v.to(self.dtype) + + def gather(self, layer: int, seq_id: str, length: int) -> tuple[torch.Tensor, torch.Tensor]: + """K, V of the first `length` tokens as contiguous `[1, Hkv, length, D]`. + + Contiguity is deliberate: SDPA can pick different kernels / reduction + orders for strided inputs, and the batch-invariance guarantee needs the + SAME bytes in the SAME layout whatever else is in the batch.""" + table = self.tables[seq_id] + idx = torch.tensor(table[: self.blocks_needed(length)], dtype=torch.long, device=self.device) + k = self.k[layer][idx].reshape(-1, self.n_kv_heads, self.head_dim)[:length] + v = self.v[layer][idx].reshape(-1, self.n_kv_heads, self.head_dim)[:length] + return ( + k.permute(1, 0, 2).unsqueeze(0).contiguous(), + v.permute(1, 0, 2).unsqueeze(0).contiguous(), + ) + + def block_table_tensor(self, seq_ids: Sequence[str], pad: int = 0) -> torch.Tensor: + """`[B, max_blocks]` int32 table (padded with `pad`; readers slice by + context length). This is the argument a fused kernel consumes.""" + width = max((len(self.tables[s]) for s in seq_ids), default=0) + out = torch.full((len(seq_ids), max(width, 1)), pad, dtype=torch.int32) + for i, s in enumerate(seq_ids): + t = self.tables[s] + if t: + out[i, : len(t)] = torch.tensor(t, dtype=torch.int32) + return out.to(self.device) + + +# --------------------------------------------------------------------------- +# One engine step, flat and ragged +# --------------------------------------------------------------------------- + + +@dataclass +class Segment: + """`n_new` consecutive tokens of one sequence in the flat batch. + + `ctx` is the number of tokens of this sequence whose KV is ALREADY in the + cache before this step; the segment's token j sits at position `ctx + j` + and attends to positions `[0, ctx + j]`. A decode token is a segment with + n_new == 1; a prefill chunk is n_new > 1; they coexist in one step. + """ + + seq_id: str + offset: int # row of the segment's first token in the flat batch + n_new: int + ctx: int + + +@dataclass +class StepBatch: + segments: list[Segment] = field(default_factory=list) + + @property + def n_tokens(self) -> int: + return sum(s.n_new for s in self.segments) + + +# --------------------------------------------------------------------------- +# Attention backends +# --------------------------------------------------------------------------- + + +class PagedAttention(Protocol): + """The seam between the engine and an attention implementation. + + `q` is `[T, H, D]` (flat rows, RoPE already applied), `k_new`/`v_new` are + `[T, Hkv, D]` for the same rows. The backend must (1) write the new K/V into + `cache` for `layer` at the segments' positions, then (2) return the + attention output `[T, H, D]` where row r attends to the cache contents + `[0, position(r)]` of its own sequence. Splitting write from read inside the + backend lets a fused kernel do both in one launch. + """ + + def __call__( + self, layer: int, q: torch.Tensor, k_new: torch.Tensor, v_new: torch.Tensor, + cache: PagedKVCache, batch: StepBatch, scale: float, + ) -> torch.Tensor: ... + + +class TorchPagedAttention: + """Pure-torch paged attention: gather K/V from the block table, run SDPA. + + `mode`: + 'row' one SDPA call per QUERY ROW, over exactly that row's keys + `[0, pos]`, no mask. The operands of every call depend only on + the sequence's own tokens, never on what else is in the step or + how the prompt was chunked, so the output bits are identical + across batch compositions and chunk schedules. Slow; it is the + correctness/invariance reference and the mode RL rollouts that + need bit-reproducible logprobs should use. + 'segment' one SDPA per segment (a prefill chunk is one causal call with + an explicit bool mask; a decode token is mask-free) -- but all + decode segments of a step are *padded and batched* into one + call. Faster; the softmax/matmul reduction length now depends on + the longest sequence in the batch (padding) or the chunk size, + so results match 'row' to rounding only (see docs/P3_ENGINE.md + for the measured bf16 expectation). + """ + + def __init__(self, mode: str = "row"): + if mode not in ("row", "segment"): + raise ValueError(f"mode={mode!r}; expected 'row' or 'segment'") + self.mode = mode + + def __call__(self, layer, q, k_new, v_new, cache, batch, scale): + group = q.shape[1] // k_new.shape[1] + gqa = group > 1 + out = torch.empty_like(q) + # 1) copy-free append of every segment's new K/V + for s in batch.segments: + sl = slice(s.offset, s.offset + s.n_new) + cache.write(layer, cache.slots(s.seq_id, s.ctx, s.n_new), k_new[sl], v_new[sl]) + # 2) read + decode = [s for s in batch.segments if s.n_new == 1] if self.mode == "segment" else [] + decode_ids = {id(s) for s in decode} + for s in batch.segments: + if id(s) in decode_ids: + continue + total = s.ctx + s.n_new + kk, vv = cache.gather(layer, s.seq_id, total) + if kk.dtype != q.dtype: # a cache stored narrower than the model (kv_dtype=bf16/fp8): SDPA + kk, vv = kk.to(q.dtype), vv.to(q.dtype) # insists on one dtype, so dequantise on read + if self.mode == "row": + for j in range(s.n_new): + ln = s.ctx + j + 1 + qj = q[s.offset + j].view(1, q.shape[1], 1, q.shape[2]) + o = F.scaled_dot_product_attention( + qj, kk[:, :, :ln].contiguous(), vv[:, :, :ln].contiguous(), + enable_gqa=gqa, scale=scale, + ) + out[s.offset + j] = o[0, :, 0] + else: + qs = q[s.offset : s.offset + s.n_new].permute(1, 0, 2).unsqueeze(0) + qpos = torch.arange(s.ctx, total, device=q.device)[:, None] + keep = qpos >= torch.arange(total, device=q.device)[None, :] + o = F.scaled_dot_product_attention(qs, kk, vv, attn_mask=keep, enable_gqa=gqa, scale=scale) + out[s.offset : s.offset + s.n_new] = o[0].permute(1, 0, 2) + if decode: + lens = [s.ctx + 1 for s in decode] + lmax = max(lens) + kp = q.new_zeros(len(decode), k_new.shape[1], lmax, q.shape[2]) + vp = torch.zeros_like(kp) + keep = torch.zeros(len(decode), 1, 1, lmax, dtype=torch.bool, device=q.device) + for i, s in enumerate(decode): + kk, vv = cache.gather(layer, s.seq_id, lens[i]) + kp[i, :, : lens[i]] = kk[0] + vp[i, :, : lens[i]] = vv[0] + keep[i, ..., : lens[i]] = True + rows = torch.tensor([s.offset for s in decode], device=q.device) + qd = q[rows].unsqueeze(2) # [B, H, 1, D] + o = F.scaled_dot_product_attention(qd, kp, vp, attn_mask=keep, enable_gqa=gqa, scale=scale) + out[rows] = o[:, :, 0] + return out + + +class TritonPagedAttention: + """INTERFACE ONLY. A later step replaces `TorchPagedAttention` with a fused + kernel; this class pins what that kernel receives so the engine is untouched. + + Kernel contract (vLLM-style "paged attention v1/v2" over a ragged batch): + + q [T, H, D] flat query rows (RoPE applied) + k_cache [NB, BS, Hkv, D] this layer's K blocks + v_cache [NB, BS, Hkv, D] + block_tables [B, max_blocks] i32 from `PagedKVCache.block_table_tensor` + cu_seqlens_q [B+1] i32 row offsets of each segment in q + ctx_lens [B] i32 tokens already cached BEFORE this step + scale float + out [T, H, D] + + Row r of segment b (position ctx_lens[b] + j) attends to cached positions + [0, ctx_lens[b] + j]; the new K/V for the step must be written to the cache + BEFORE the launch (or fused in the same kernel via `slot_mapping` + [T] i64 = block * BS + offset). Bit-invariance requirement for RL use: the + reduction over keys for a given row must not depend on B, T or on other + segments (fixed KV-split count per context length, no atomics). + """ + + def __call__(self, layer, q, k_new, v_new, cache, batch, scale): # pragma: no cover + raise NotImplementedError( + "TritonPagedAttention is an interface placeholder; use TorchPagedAttention. " + "See the class docstring for the kernel contract." + ) + + +# --------------------------------------------------------------------------- +# Memory accounting +# --------------------------------------------------------------------------- + + +def kv_bytes_per_token(n_layers: int, n_kv_heads: int, head_dim: int, dtype: torch.dtype = torch.bfloat16, + tp_degree: int = 1) -> int: + """Bytes of KV one token costs on ONE device: layers x 2 (K,V) x kv-heads/tp x head_dim x itemsize. + + `tp_degree` shards the KV heads (vLLM's tensor parallelism does exactly this), + which is why a TP=4 probe's "tokens in cache" is not comparable to a + single-device engine's without it. Qwen3-8B (36, 8, 128, bf16) -> 147456 B + = 144 KiB = the '147 KB/token' figure. + """ + if n_kv_heads % tp_degree: + raise ValueError(f"n_kv_heads={n_kv_heads} not divisible by tp_degree={tp_degree}") + itemsize = torch.empty((), dtype=dtype).element_size() + return n_layers * 2 * (n_kv_heads // tp_degree) * head_dim * itemsize + + +@dataclass(frozen=True) +class CapacityPlan: + kv_bytes_per_token: int + kv_budget_bytes: int + num_blocks: int + block_size: int + kv_tokens: int + max_concurrent_at_cap: int # sequences that can each hold `cap` tokens simultaneously + cap: int + + +def plan_capacity( + device_total_bytes: int, + weights_bytes: int, + kv_bytes_per_tok: int, + *, + utilization: float = 0.9, + activation_bytes: int = 0, + other_bytes: int = 0, + block_size: int = 16, + cap: int = 16384, +) -> CapacityPlan: + """How much KV fits, and how many `cap`-token sequences that sustains. + + budget = utilization * device_total - weights - activation peak - other. + Paging rounds each sequence up to whole blocks, so `max_concurrent_at_cap` + = num_blocks // ceil(cap / block_size) (a dense per-slot strip would give + the same number for sequences that all reach the cap; paging's advantage is + for the ones that do not, which is why the engine also reports live usage). + """ + budget = int(utilization * device_total_bytes) - weights_bytes - activation_bytes - other_bytes + budget = max(budget, 0) + per_block = kv_bytes_per_tok * block_size + nb = budget // per_block + per_seq_blocks = math.ceil(cap / block_size) + return CapacityPlan( + kv_bytes_per_token=kv_bytes_per_tok, kv_budget_bytes=budget, num_blocks=int(nb), + block_size=block_size, kv_tokens=int(nb * block_size), + max_concurrent_at_cap=int(nb // per_seq_blocks), cap=cap, + ) diff --git a/code/align/rollout/protocol.py b/code/align/rollout/protocol.py new file mode 100644 index 0000000000000000000000000000000000000000..7c4d93b26cdf1da363ea0569fbc31e6927649d99 --- /dev/null +++ b/code/align/rollout/protocol.py @@ -0,0 +1,227 @@ +"""Request/result shapes for rollout, plus the file protocol the spool worker speaks. + +DEPENDENCY-FREE ON PURPOSE: this module is imported by the training venv +(torch 2.11/cu128), by the native in-process backend (`native.py`), AND by the +optional vLLM worker in extras/vllm_rollout/ (its own venv, vllm/cu130); it +may import nothing beyond the standard library, or the environments' pin sets +start constraining each other -- the exact coupling the isolated-venv +design exists to prevent. + +`RolloutRequest` / `RolloutResult` are the backend-neutral contract. The +default backend (`native.NativeRolloutBackend`) fills them in-process with no +file I/O; the 'spool' backend moves the SAME dataclasses through the files +described below. The trainer cannot tell which one served it, by design. + +Mechanics: one JSON file per message, written atomically (.partial -> +os.replace) into a spool directory. The worker polls `requests/`, writes +into `results/`, and touches `heartbeat` every poll so the trainer can +distinguish "generating" from "dead" (mtime-based liveness, per the house +monitor-mtime-not-PIDs rule). Completions travel as token id lists plus +the engine's per-token logprobs -- the trainer needs vllm_logprobs for the +rho correction and must NOT re-derive them from text (re-tokenization is +not identity). +""" + +from __future__ import annotations + +import json +import os +import time +from dataclasses import asdict, dataclass, field +from typing import Optional, Protocol, runtime_checkable + +PROTOCOL_VERSION = 1 + + +@dataclass +class RolloutRequest: + request_id: str + weights_dir: str # HF-loadable checkpoint dir; worker reloads on change + prompts: list[str] + n_samples_per_prompt: int + max_tokens: int + temperature: float = 1.0 + top_p: float = 1.0 + seed: Optional[int] = None + protocol_version: int = PROTOCOL_VERSION + + def validate(self, *, check_weights_dir: bool = True) -> None: + """Shape checks always; the weights_dir existence check only for + backends that LOAD from it. The native backend samples from a live + in-process model, where weights_dir is provenance, not an input -- a + step-0 request legitimately names a checkpoint that has not been + written yet.""" + if not self.prompts: + raise ValueError("empty prompt list") + if self.n_samples_per_prompt < 1 or self.max_tokens < 1: + raise ValueError( + f"bad shape: n={self.n_samples_per_prompt}, max_tokens={self.max_tokens}" + ) + if check_weights_dir and not os.path.isdir(self.weights_dir): + raise FileNotFoundError(f"weights_dir does not exist: {self.weights_dir}") + + +@dataclass +class RolloutResult: + """One request's samples, in the form `align.rl.assembly` consumes. + + Whatever the backend, the contract the trainer relies on is: + logprobs[i][j][t] is the logprob of completions[i][j][t] under the + SAMPLING-TEMPERATURE-scaled, untruncated policy distribution, so + rho = exp(old - infer) is ~1 when the weights agree. And + `extras["prompt_token_ids"]` (one id list per prompt, request order) is + REQUIRED: completions continue from exactly those ids, and assembly + refuses to re-tokenize prompt text. + """ + + request_id: str + #: completions[i][j] = j-th sample for prompt i: token ids WITHOUT the prompt. + completions: list[list[list[int]]] + #: logprobs[i][j][t] = engine logprob of completions[i][j][t] (the rho + #: correction's pi^infer_old side; label-aligned with the completion ids). + logprobs: list[list[list[float]]] + #: decoded completion texts, same nesting -- the reward path consumes text + #: and must see EXACTLY what the engine's tokenizer decodes, not a re-decode. + texts: list[list[str]] + weights_dir: str + engine_reloaded: bool + generate_seconds: float + error: Optional[str] = None + protocol_version: int = PROTOCOL_VERSION + extras: dict = field(default_factory=dict) + + +@runtime_checkable +class RolloutBackend(Protocol): + """What `GrpoBatchSource` consumes: submit a request, collect its result. + + Implemented by `native.NativeRolloutBackend` (in-process, synchronous: the + work happens in `submit`) and `client.RolloutClient` (file spool to an + external worker: the work happens between `submit` and `collect`). + """ + + def submit(self, request: RolloutRequest) -> str: ... + + def collect(self, request_id: str) -> RolloutResult: ... + + +def _atomic_write_json(payload: dict, path: str) -> None: + tmp = path + ".partial" + with open(tmp, "w") as f: + json.dump(payload, f) + os.replace(tmp, path) + + +def spool_dirs(spool: str) -> tuple[str, str]: + req = os.path.join(spool, "requests") + res = os.path.join(spool, "results") + os.makedirs(req, exist_ok=True) + os.makedirs(res, exist_ok=True) + return req, res + + +def write_request(spool: str, request: RolloutRequest) -> str: + request.validate() + req_dir, _ = spool_dirs(spool) + path = os.path.join(req_dir, f"{request.request_id}.json") + if os.path.exists(path): + raise FileExistsError(f"duplicate request_id {request.request_id!r}") + _atomic_write_json(asdict(request), path) + return path + + +def read_request(path: str) -> RolloutRequest: + with open(path) as f: + payload = json.load(f) + if payload.get("protocol_version") != PROTOCOL_VERSION: + raise RuntimeError( + f"protocol version mismatch: request carries " + f"{payload.get('protocol_version')!r}, this side speaks {PROTOCOL_VERSION}" + ) + return RolloutRequest(**payload) + + +def write_result(spool: str, result: RolloutResult) -> str: + _, res_dir = spool_dirs(spool) + path = os.path.join(res_dir, f"{result.request_id}.json") + _atomic_write_json(asdict(result), path) + return path + + +def read_result(spool: str, request_id: str) -> Optional[RolloutResult]: + """Non-blocking: None until the result file exists (atomically complete).""" + _, res_dir = spool_dirs(spool) + path = os.path.join(res_dir, f"{request_id}.json") + if not os.path.exists(path): + return None + with open(path) as f: + payload = json.load(f) + if payload.get("protocol_version") != PROTOCOL_VERSION: + raise RuntimeError( + f"protocol version mismatch on result {request_id!r}: " + f"{payload.get('protocol_version')!r} vs {PROTOCOL_VERSION}" + ) + return RolloutResult(**payload) + + +def touch_heartbeat(spool: str) -> None: + path = os.path.join(spool, "heartbeat") + with open(path, "a"): + os.utime(path, None) + + +def heartbeat_age_seconds(spool: str) -> float: + """Inf when no heartbeat exists yet (worker never started != worker slow).""" + path = os.path.join(spool, "heartbeat") + if not os.path.exists(path): + return float("inf") + return time.time() - os.path.getmtime(path) + + +def wait_for_result( + spool: str, + request_id: str, + timeout_s: float, + stale_heartbeat_s: float = 600.0, + poll_s: float = 2.0, + startup_grace_s: float = 300.0, +) -> RolloutResult: + """Block until the result lands; raise on timeout, dead worker, or error. + + THREE distinct failure signatures, kept distinct on purpose: a TIMEOUT + with a live heartbeat means the request is too big for the budget; a + STALE heartbeat means the worker died mid-service; and NO heartbeat at + all means the worker has not finished booting -- which is fatal only + after `startup_grace_s`, measured from this wait's start. The first + smoke run (2026-08-24) found the missing third case the hard way: a + step-0 canary raced the worker's ~30s vLLM import, age=inf compared + `> stale_heartbeat_s` as instantly dead, and the teardown killed a + perfectly healthy worker before its first log line flushed. + """ + start = time.time() + while True: + result = read_result(spool, request_id) + if result is not None: + if result.error: + raise RuntimeError(f"rollout worker reported error: {result.error}") + return result + age = heartbeat_age_seconds(spool) + if age == float("inf"): + if time.time() - start > startup_grace_s: + raise RuntimeError( + f"rollout worker produced NO heartbeat within {startup_grace_s:.0f}s " + f"of waiting on request {request_id!r}: it never started. Check its " + "log (spawn env, venv, import errors)." + ) + elif age > stale_heartbeat_s: + raise RuntimeError( + f"rollout worker heartbeat is {age:.0f}s stale " + f"(> {stale_heartbeat_s:.0f}s) while request {request_id!r} is pending: " + "worker presumed dead. Check its log; do not resubmit blindly." + ) + if time.time() - start > timeout_s: + raise TimeoutError( + f"rollout request {request_id!r} exceeded {timeout_s:.0f}s with a live " + "worker: the request shape is too big for the time budget." + ) + time.sleep(poll_s) diff --git a/code/align/rollout/tp_engine.py b/code/align/rollout/tp_engine.py new file mode 100644 index 0000000000000000000000000000000000000000..3b036bce230017e2c86852344453860886761ff6 --- /dev/null +++ b/code/align/rollout/tp_engine.py @@ -0,0 +1,169 @@ +"""Tensor-parallel driver for `PagedEngine` (P3, opt-in): same scheduler, same sampler, a TP-sharded model. + +WHAT CHANGES vs the single-device engine, and what deliberately does not. + + * The model is `align.model.tp`'s shard. `PagedEngine` drives it UNCHANGED through its own submodules, so the + paged KV cache is sharded by kv head for free: `_ModelView` reads the LOCAL `n_kv_heads` (Qwen3-8B at tp=4: + 8 -> 2) and sizes `PagedKVCache` with it. Per-rank KV bytes are exactly 1/tp (tested), the block tables, + refcounts, prefix sharing and preemption logic are the original code, and attention is purely local (a rank's + q heads read only kv heads it owns, see `align.model.tp`). + + * REPLICATED SCHEDULER, NOT A BROADCAST ONE. The task offered "scheduler on rank 0 broadcasting decisions". + Chosen instead: every rank runs the identical deterministic scheduler on identical inputs, and rank 0 is + authoritative for the INPUTS (the request stream, broadcast once by `generate`) and the VERIFIER of the + replication. Why: + - Broadcasting decisions means shipping a ragged object (segments, block tables, the sampled-row list) every + step: a pickle + host sync on the critical path, per step, for information every rank can recompute for + free from state it already holds. + - The scheduler is a pure function of (request stream, sampled tokens). Sampled tokens are identical on + every rank because the logits are: the lm_head ALL-GATHER hands every rank the same bytes, and sampling + (per-sequence seeded generators, `_stable_seed` = sha256 not `hash()`) is a deterministic function of the + logits row. So replicated sampling needs no extra collective; rank-0-only sampling would need a token + broadcast between every forward and the next (a serial hop) PLUS the full-logit row on rank 0 anyway. + - The one real risk of replication is SILENT DIVERGENCE (a single differing token or schedule makes ranks + issue different collectives: an NCCL hang for the timeout, or all-reduces of mismatched shapes). That is + closed by two tiny consensus all-gathers per step (8 bytes/rank each, vs 2*n_layers+1 all-reduces of + [rows, hidden]): `_schedule` checks a fingerprint of the step's schedule BEFORE any model collective, and + `has_unfinished` checks the previous step's events (tokens, finish reasons) and the loop + predicate. The check is SYMMETRIC (all-gather, every rank sees every fingerprint), so a divergence raises + `TPDesyncError` on ALL ranks instead of leaving the agreeing ones blocked in the next collective. + + * Residual rounding. Under bf16 the row-parallel all-reduce sums per-rank partials each rounded to bf16, so TP + logits differ from the unsharded model's by bf16 rounding (measured in docs/P3_ENGINE.md); in fp64 they agree + to ~1e-15. `numerics='invariant'` keeps its meaning under TP: row-wise calls keep every all-reduce the same + shape whatever the batch holds, so a sequence's bits do not depend on its companions (tested bitwise). + +Every rank must call the same methods with the same arguments in the same order (`add_request`, `step`, `generate`); +`generate` takes its requests from rank 0 and broadcasts them, so only rank 0 needs the real list. +""" + +from __future__ import annotations + +import hashlib +import struct +from typing import Optional, Sequence + +import torch + +from align.model.tp import TPGroup +from align.rollout.engine import PagedEngine, PagedEngineConfig, PagedResult, SamplingParams + + +class TPDesyncError(RuntimeError): + """Ranks disagree about the schedule, the sampled tokens or whether work remains. Raised on EVERY rank.""" + + +class _FullVocabEmbed: + """What `PagedEngine.add_request` sees as the embedding: a `.weight` whose shape[0] is the FULL vocabulary + (the real weight is this rank's shard, whose row count would reject every valid id >= V/tp), and the sharded + lookup as the call. The meta tensor allocates nothing.""" + + def __init__(self, emb): + self._emb = emb + self.weight = torch.empty((emb.full_vocab, emb.weight.shape[1]), device="meta") + + def __call__(self, ids): + return self._emb(ids) + + +def _digest(parts: Sequence[bytes]) -> int: + h = hashlib.sha256() + for p in parts: + h.update(struct.pack(" int: + """Hash of everything that decides the step's collectives and shapes: for each scheduled sequence its id, how + many tokens it already has computed, how many it adds, and the token ids it feeds. Module-level so a test can + substitute a constant (divergence then goes undetected until a collective hangs).""" + parts = [] + for seq, n in sched: + parts.append(f"{seq.rid}|{seq.num_computed}|{n}".encode()) + parts.append(struct.pack(f"<{n}q", *seq.tokens[seq.num_computed : seq.num_computed + n])) + return _digest(parts) + + +def events_fingerprint(events) -> int: + """Hash of a step's sampled events: request id, token and finish reason. (Logprobs need no hash of their own: they are + a deterministic function of the all-gathered logits row and the token, both already agreed.)""" + return _digest([f"{rid}|{tok}|{reason}".encode() for rid, tok, reason in events]) + + +class TPPagedEngine(PagedEngine): + """`PagedEngine` over a `align.model.tp` shard. `verify=False` drops the two consensus all-gathers (a + measured-cost opt-out for a job that has proven itself; the default keeps the hang-proofing).""" + + def __init__(self, model: torch.nn.Module, tp: Optional[TPGroup] = None, cfg: Optional[PagedEngineConfig] = None, *, + tokenizer=None, return_logits: bool = False, verify: bool = True): + tp = tp if tp is not None else getattr(model, "tp", None) + if tp is None: + raise ValueError("TPPagedEngine needs a TPGroup (or a model built by align.model.tp, which carries one)") + super().__init__(model, cfg, tokenizer=tokenizer, return_logits=return_logits) + self.tp, self.verify = tp, verify and tp.world_size > 1 + emb = self.view.embed + if not hasattr(emb, "full_vocab"): + raise TypeError("model is not a tensor-parallel shard (embed_tokens has no `full_vocab`)") + emb.check_range = False # add_request already validates ids; skip the per-step device sync + self.view.embed = _FullVocabEmbed(emb) + self._last_events = 0 + self.stats.update(consensus_checks=0) + + # -- replication guards ---------------------------------------------------------- + + def _agree(self, label: str, values: list[int]) -> None: + got = self.tp.all_gather_i64(values, self.device) + self.stats["consensus_checks"] += 1 + if any(g != got[0] for g in got): + raise TPDesyncError( + f"tensor-parallel ranks diverged at {label}: per-rank fingerprints {got} (this is rank {self.tp.rank}). " + "Every rank must see the same requests in the same order with the same config." + ) + + def has_unfinished(self) -> bool: + local = super().has_unfinished() + if self.verify: + self._agree("loop predicate / previous step's events", [int(local), self._last_events]) + return local + + def _schedule(self): + sched = super()._schedule() + if self.verify: + self._agree("the step schedule", [schedule_fingerprint(sched)]) + return sched + + def step(self): + events = super().step() + self._last_events = events_fingerprint(events) + return events + + # -- driver --------------------------------------------------------------------------- + + def generate(self, requests=None, arrival_step: Optional[dict[str, int]] = None, max_steps: int = 1_000_000 + ) -> dict[str, PagedResult]: + """As `PagedEngine.generate`, but rank 0's `requests`/`arrival_step` are broadcast to every rank (other + ranks may pass None): the request stream has exactly one author.""" + payload = None + if self.tp.rank == 0: + # Built BEFORE the broadcast, so a malformed stream would raise on rank 0 alone and leave every other + # rank blocked in the broadcast until the process-group timeout (minutes to hours on NCCL). The error + # is therefore shipped as data and re-raised everywhere. + try: + payload = ("ok", ([(rid, list(ids), p) for rid, ids, p in requests], dict(arrival_step or {}))) + except Exception as e: # noqa: BLE001 + payload = ("err", f"{type(e).__name__}: {e}") + tag, body = self.tp.broadcast_object(payload) + if tag == "err": + raise ValueError(f"rank 0 could not build the request stream: {body}") + reqs, arrivals = body + reqs = [(rid, ids, p if isinstance(p, SamplingParams) else SamplingParams(**p)) for rid, ids, p in reqs] + return super().generate(reqs, arrivals, max_steps) + + # -- accounting -------------------------------------------------------------------------- + + def kv_bytes_per_rank(self) -> int: + return self.cache.bytes_total() + + +__all__ = ["TPPagedEngine", "TPDesyncError", "schedule_fingerprint", "events_fingerprint"] diff --git a/code/align/tokenizer/__init__.py b/code/align/tokenizer/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8eb1a0a3412956b3efa957b75c8a7172b38e3a9d --- /dev/null +++ b/code/align/tokenizer/__init__.py @@ -0,0 +1,85 @@ +"""align.tokenizer -- pure-Python (stdlib-only) Mistral-7B-v0.3 BPE tokenizer. + + from align.tokenizer import Tokenizer, load_tokenizer + tok = load_tokenizer("/path/to/dir/with/tokenizer.json") + tok("a\\nb")["input_ids"] # [1, 1032, <0x0A id>, 29494] ( ▁a <0x0A> b) + tok.decode(ids, skip_special_tokens=True) + +It replaces `transformers.AutoTokenizer` for this codebase (dependency policy: +torch/triton/numpy/safetensors only). Parity is certified against the legacy +transformers tokenizer by the `oracle`-marked test in tests/test_tokenizer.py. + +Two places pure reimplementations usually get wrong -- both are load-bearing: + +1. Metaspace prepend_scheme="first". + The pre-tokenizer replaces ' ' with U+2581 and prepends U+2581 to split #0 of + the whole input -- and only if that split is NOT an added token. Added tokens + (, [INST], [control_N], ...) are carved out of the raw text before the + pre-tokenizer runs; they occupy a split index but skip the pre-tokenizer, so + "first" is neither "first character of the string" nor "first segment after + each special token" nor "first non-added segment": + "helloworld" -> ▁hello world (prefix on split 0 only) + "hello" -> hello (bare 'hello': the leading used + up split 0 -- measured, not guessed) + " hello" -> ▁hello (already starts with U+2581: no + second prefix) + With split=false the whole non-added segment is a single BPE "word", so + merges can run across spaces and newlines ('\\n' is not touched by Metaspace; + it has no vocab piece and falls back to the byte token <0x0A>, the id the vocab assigns it). + +2. Strip(" ", start=1) at the END of the decoder chain. + decode = Replace(U+2581 -> ' ') / ByteFallback / Fuse / Strip. Strip removes + at most ONE leading space from the FUSED string. Consequences: decode of the + ids for "hello" is "hello" (the prepended ▁ is stripped, round-trip exact), + but decoding a mid-sequence chunk [▁world] gives "world", not " world" -- so + decoding token deltas and concatenating drops spaces. Decode the whole + sequence and diff the TEXT (the inference engine does exactly that). Also: + ByteFallback decodes each maximal run of <0xNN> pieces as one UTF-8 unit, and + an invalid run yields one U+FFFD per byte (not Python's errors="replace"). + +The loader refuses (NotImplementedError) any tokenizer.json whose pipeline +differs from the one above, rather than silently producing wrong ids. + +Byte-level BPE (Qwen2/Qwen3, e.g. Goedel-Prover-V2-8B) lives in `.bytelevel` +(`ByteLevelTokenizer`); see that module's docstring. `load_tokenizer` dispatches on +tokenizer.json (model.type + pre_tokenizer): Metaspace -> the Mistral `Tokenizer` +above, completely unchanged; Split+ByteLevel -> `ByteLevelTokenizer`; anything else +-> NotImplementedError (never a guess). +""" +from __future__ import annotations + +import json +import os +from typing import Union + +from .bytelevel import ByteLevelTokenizer +from .core import Tokenizer, _resolve_dir + +__all__ = ["Tokenizer", "ByteLevelTokenizer", "load_tokenizer"] + + +def _pre_tokenizer_kinds(pt) -> set: + if not pt: + return set() + if pt.get("type") == "Sequence": + return {p.get("type") for p in pt.get("pretokenizers", [])} + return {pt.get("type")} + + +def load_tokenizer(path: Union[str, os.PathLike]): + """Local-only loader. Mistral (Metaspace) -> Tokenizer; Qwen (ByteLevel) -> + ByteLevelTokenizer. The choice is made from tokenizer.json, never from the + directory name, and every other family fails loudly instead of being fed to a + pipeline that would encode it wrong.""" + d = _resolve_dir(os.fspath(path)) + with open(os.path.join(d, "tokenizer.json"), "rb") as f: + tj = json.loads(f.read()) + kinds = _pre_tokenizer_kinds(tj.get("pre_tokenizer")) + if "ByteLevel" in kinds: + return ByteLevelTokenizer.from_pretrained(d) + if kinds == {"Metaspace"}: + return Tokenizer.from_pretrained(d) + raise NotImplementedError( + f"no tokenizer implementation for pre_tokenizer {sorted(k for k in kinds if k)!r} " + f"in {d!r}; supported: Metaspace (Mistral), Split+ByteLevel (Qwen2/3)" + ) diff --git a/code/align/tokenizer/_qwen2_unicode.py b/code/align/tokenizer/_qwen2_unicode.py new file mode 100644 index 0000000000000000000000000000000000000000..b6a7ca79a1641e93a0b07cb4c385d6dbad27d01e --- /dev/null +++ b/code/align/tokenizer/_qwen2_unicode.py @@ -0,0 +1,875 @@ +"""GENERATED by tests/data/make_qwen2_unicode_tables.py -- do not edit. + +Probed from transformers 5.19.0 / tokenizers 0.23.3 against Python unicodedata 15.0.0. +See that script for why these are frozen. +""" +PYTHON_UNIDATA_VERSION = '15.0.0' # the unicodedata these deltas were measured against + +#: \p{L} / \p{N} exactly as the Rust regex engine sees them (inclusive ranges). +L_RANGES = ( + (0x41, 0x5a), + (0x61, 0x7a), + (0xaa, 0xaa), + (0xb5, 0xb5), + (0xba, 0xba), + (0xc0, 0xd6), + (0xd8, 0xf6), + (0xf8, 0x2c1), + (0x2c6, 0x2d1), + (0x2e0, 0x2e4), + (0x2ec, 0x2ec), + (0x2ee, 0x2ee), + (0x370, 0x374), + (0x376, 0x377), + (0x37a, 0x37d), + (0x37f, 0x37f), + (0x386, 0x386), + (0x388, 0x38a), + (0x38c, 0x38c), + (0x38e, 0x3a1), + (0x3a3, 0x3f5), + (0x3f7, 0x481), + (0x48a, 0x52f), + (0x531, 0x556), + (0x559, 0x559), + (0x560, 0x588), + (0x5d0, 0x5ea), + (0x5ef, 0x5f2), + (0x620, 0x64a), + (0x66e, 0x66f), + (0x671, 0x6d3), + (0x6d5, 0x6d5), + (0x6e5, 0x6e6), + (0x6ee, 0x6ef), + (0x6fa, 0x6fc), + (0x6ff, 0x6ff), + (0x710, 0x710), + (0x712, 0x72f), + (0x74d, 0x7a5), + (0x7b1, 0x7b1), + (0x7ca, 0x7ea), + (0x7f4, 0x7f5), + (0x7fa, 0x7fa), + (0x800, 0x815), + (0x81a, 0x81a), + (0x824, 0x824), + (0x828, 0x828), + (0x840, 0x858), + (0x860, 0x86a), + (0x870, 0x887), + (0x889, 0x88e), + (0x8a0, 0x8c9), + (0x904, 0x939), + (0x93d, 0x93d), + (0x950, 0x950), + (0x958, 0x961), + (0x971, 0x980), + (0x985, 0x98c), + (0x98f, 0x990), + (0x993, 0x9a8), + (0x9aa, 0x9b0), + (0x9b2, 0x9b2), + (0x9b6, 0x9b9), + (0x9bd, 0x9bd), + (0x9ce, 0x9ce), + (0x9dc, 0x9dd), + (0x9df, 0x9e1), + (0x9f0, 0x9f1), + (0x9fc, 0x9fc), + (0xa05, 0xa0a), + (0xa0f, 0xa10), + (0xa13, 0xa28), + (0xa2a, 0xa30), + (0xa32, 0xa33), + (0xa35, 0xa36), + (0xa38, 0xa39), + (0xa59, 0xa5c), + (0xa5e, 0xa5e), + (0xa72, 0xa74), + (0xa85, 0xa8d), + (0xa8f, 0xa91), + (0xa93, 0xaa8), + (0xaaa, 0xab0), + (0xab2, 0xab3), + (0xab5, 0xab9), + (0xabd, 0xabd), + (0xad0, 0xad0), + (0xae0, 0xae1), + (0xaf9, 0xaf9), + (0xb05, 0xb0c), + (0xb0f, 0xb10), + (0xb13, 0xb28), + (0xb2a, 0xb30), + (0xb32, 0xb33), + (0xb35, 0xb39), + (0xb3d, 0xb3d), + (0xb5c, 0xb5d), + (0xb5f, 0xb61), + (0xb71, 0xb71), + (0xb83, 0xb83), + (0xb85, 0xb8a), + (0xb8e, 0xb90), + (0xb92, 0xb95), + (0xb99, 0xb9a), + (0xb9c, 0xb9c), + (0xb9e, 0xb9f), + (0xba3, 0xba4), + (0xba8, 0xbaa), + (0xbae, 0xbb9), + (0xbd0, 0xbd0), + (0xc05, 0xc0c), + (0xc0e, 0xc10), + (0xc12, 0xc28), + (0xc2a, 0xc39), + (0xc3d, 0xc3d), + (0xc58, 0xc5a), + (0xc5d, 0xc5d), + (0xc60, 0xc61), + (0xc80, 0xc80), + (0xc85, 0xc8c), + (0xc8e, 0xc90), + (0xc92, 0xca8), + (0xcaa, 0xcb3), + (0xcb5, 0xcb9), + (0xcbd, 0xcbd), + (0xcdd, 0xcde), + (0xce0, 0xce1), + (0xcf1, 0xcf2), + (0xd04, 0xd0c), + (0xd0e, 0xd10), + (0xd12, 0xd3a), + (0xd3d, 0xd3d), + (0xd4e, 0xd4e), + (0xd54, 0xd56), + (0xd5f, 0xd61), + (0xd7a, 0xd7f), + (0xd85, 0xd96), + (0xd9a, 0xdb1), + (0xdb3, 0xdbb), + (0xdbd, 0xdbd), + (0xdc0, 0xdc6), + (0xe01, 0xe30), + (0xe32, 0xe33), + (0xe40, 0xe46), + (0xe81, 0xe82), + (0xe84, 0xe84), + (0xe86, 0xe8a), + (0xe8c, 0xea3), + (0xea5, 0xea5), + (0xea7, 0xeb0), + (0xeb2, 0xeb3), + (0xebd, 0xebd), + (0xec0, 0xec4), + (0xec6, 0xec6), + (0xedc, 0xedf), + (0xf00, 0xf00), + (0xf40, 0xf47), + (0xf49, 0xf6c), + (0xf88, 0xf8c), + (0x1000, 0x102a), + (0x103f, 0x103f), + (0x1050, 0x1055), + (0x105a, 0x105d), + (0x1061, 0x1061), + (0x1065, 0x1066), + (0x106e, 0x1070), + (0x1075, 0x1081), + (0x108e, 0x108e), + (0x10a0, 0x10c5), + (0x10c7, 0x10c7), + (0x10cd, 0x10cd), + (0x10d0, 0x10fa), + (0x10fc, 0x1248), + (0x124a, 0x124d), + (0x1250, 0x1256), + (0x1258, 0x1258), + (0x125a, 0x125d), + (0x1260, 0x1288), + (0x128a, 0x128d), + (0x1290, 0x12b0), + (0x12b2, 0x12b5), + (0x12b8, 0x12be), + (0x12c0, 0x12c0), + (0x12c2, 0x12c5), + (0x12c8, 0x12d6), + (0x12d8, 0x1310), + (0x1312, 0x1315), + (0x1318, 0x135a), + (0x1380, 0x138f), + (0x13a0, 0x13f5), + (0x13f8, 0x13fd), + (0x1401, 0x166c), + (0x166f, 0x167f), + (0x1681, 0x169a), + (0x16a0, 0x16ea), + (0x16f1, 0x16f8), + (0x1700, 0x1711), + (0x171f, 0x1731), + (0x1740, 0x1751), + (0x1760, 0x176c), + (0x176e, 0x1770), + (0x1780, 0x17b3), + (0x17d7, 0x17d7), + (0x17dc, 0x17dc), + (0x1820, 0x1878), + (0x1880, 0x1884), + (0x1887, 0x18a8), + (0x18aa, 0x18aa), + (0x18b0, 0x18f5), + (0x1900, 0x191e), + (0x1950, 0x196d), + (0x1970, 0x1974), + (0x1980, 0x19ab), + (0x19b0, 0x19c9), + (0x1a00, 0x1a16), + (0x1a20, 0x1a54), + (0x1aa7, 0x1aa7), + (0x1b05, 0x1b33), + (0x1b45, 0x1b4c), + (0x1b83, 0x1ba0), + (0x1bae, 0x1baf), + (0x1bba, 0x1be5), + (0x1c00, 0x1c23), + (0x1c4d, 0x1c4f), + (0x1c5a, 0x1c7d), + (0x1c80, 0x1c8a), + (0x1c90, 0x1cba), + (0x1cbd, 0x1cbf), + (0x1ce9, 0x1cec), + (0x1cee, 0x1cf3), + (0x1cf5, 0x1cf6), + (0x1cfa, 0x1cfa), + (0x1d00, 0x1dbf), + (0x1e00, 0x1f15), + (0x1f18, 0x1f1d), + (0x1f20, 0x1f45), + (0x1f48, 0x1f4d), + (0x1f50, 0x1f57), + (0x1f59, 0x1f59), + (0x1f5b, 0x1f5b), + (0x1f5d, 0x1f5d), + (0x1f5f, 0x1f7d), + (0x1f80, 0x1fb4), + (0x1fb6, 0x1fbc), + (0x1fbe, 0x1fbe), + (0x1fc2, 0x1fc4), + (0x1fc6, 0x1fcc), + (0x1fd0, 0x1fd3), + (0x1fd6, 0x1fdb), + (0x1fe0, 0x1fec), + (0x1ff2, 0x1ff4), + (0x1ff6, 0x1ffc), + (0x2071, 0x2071), + (0x207f, 0x207f), + (0x2090, 0x209c), + (0x2102, 0x2102), + (0x2107, 0x2107), + (0x210a, 0x2113), + (0x2115, 0x2115), + (0x2119, 0x211d), + (0x2124, 0x2124), + (0x2126, 0x2126), + (0x2128, 0x2128), + (0x212a, 0x212d), + (0x212f, 0x2139), + (0x213c, 0x213f), + (0x2145, 0x2149), + (0x214e, 0x214e), + (0x2183, 0x2184), + (0x2c00, 0x2ce4), + (0x2ceb, 0x2cee), + (0x2cf2, 0x2cf3), + (0x2d00, 0x2d25), + (0x2d27, 0x2d27), + (0x2d2d, 0x2d2d), + (0x2d30, 0x2d67), + (0x2d6f, 0x2d6f), + (0x2d80, 0x2d96), + (0x2da0, 0x2da6), + (0x2da8, 0x2dae), + (0x2db0, 0x2db6), + (0x2db8, 0x2dbe), + (0x2dc0, 0x2dc6), + (0x2dc8, 0x2dce), + (0x2dd0, 0x2dd6), + (0x2dd8, 0x2dde), + (0x2e2f, 0x2e2f), + (0x3005, 0x3006), + (0x3031, 0x3035), + (0x303b, 0x303c), + (0x3041, 0x3096), + (0x309d, 0x309f), + (0x30a1, 0x30fa), + (0x30fc, 0x30ff), + (0x3105, 0x312f), + (0x3131, 0x318e), + (0x31a0, 0x31bf), + (0x31f0, 0x31ff), + (0x3400, 0x4dbf), + (0x4e00, 0xa48c), + (0xa4d0, 0xa4fd), + (0xa500, 0xa60c), + (0xa610, 0xa61f), + (0xa62a, 0xa62b), + (0xa640, 0xa66e), + (0xa67f, 0xa69d), + (0xa6a0, 0xa6e5), + (0xa717, 0xa71f), + (0xa722, 0xa788), + (0xa78b, 0xa7cd), + (0xa7d0, 0xa7d1), + (0xa7d3, 0xa7d3), + (0xa7d5, 0xa7dc), + (0xa7f2, 0xa801), + (0xa803, 0xa805), + (0xa807, 0xa80a), + (0xa80c, 0xa822), + (0xa840, 0xa873), + (0xa882, 0xa8b3), + (0xa8f2, 0xa8f7), + (0xa8fb, 0xa8fb), + (0xa8fd, 0xa8fe), + (0xa90a, 0xa925), + (0xa930, 0xa946), + (0xa960, 0xa97c), + (0xa984, 0xa9b2), + (0xa9cf, 0xa9cf), + (0xa9e0, 0xa9e4), + (0xa9e6, 0xa9ef), + (0xa9fa, 0xa9fe), + (0xaa00, 0xaa28), + (0xaa40, 0xaa42), + (0xaa44, 0xaa4b), + (0xaa60, 0xaa76), + (0xaa7a, 0xaa7a), + (0xaa7e, 0xaaaf), + (0xaab1, 0xaab1), + (0xaab5, 0xaab6), + (0xaab9, 0xaabd), + (0xaac0, 0xaac0), + (0xaac2, 0xaac2), + (0xaadb, 0xaadd), + (0xaae0, 0xaaea), + (0xaaf2, 0xaaf4), + (0xab01, 0xab06), + (0xab09, 0xab0e), + (0xab11, 0xab16), + (0xab20, 0xab26), + (0xab28, 0xab2e), + (0xab30, 0xab5a), + (0xab5c, 0xab69), + (0xab70, 0xabe2), + (0xac00, 0xd7a3), + (0xd7b0, 0xd7c6), + (0xd7cb, 0xd7fb), + (0xf900, 0xfa6d), + (0xfa70, 0xfad9), + (0xfb00, 0xfb06), + (0xfb13, 0xfb17), + (0xfb1d, 0xfb1d), + (0xfb1f, 0xfb28), + (0xfb2a, 0xfb36), + (0xfb38, 0xfb3c), + (0xfb3e, 0xfb3e), + (0xfb40, 0xfb41), + (0xfb43, 0xfb44), + (0xfb46, 0xfbb1), + (0xfbd3, 0xfd3d), + (0xfd50, 0xfd8f), + (0xfd92, 0xfdc7), + (0xfdf0, 0xfdfb), + (0xfe70, 0xfe74), + (0xfe76, 0xfefc), + (0xff21, 0xff3a), + (0xff41, 0xff5a), + (0xff66, 0xffbe), + (0xffc2, 0xffc7), + (0xffca, 0xffcf), + (0xffd2, 0xffd7), + (0xffda, 0xffdc), + (0x10000, 0x1000b), + (0x1000d, 0x10026), + (0x10028, 0x1003a), + (0x1003c, 0x1003d), + (0x1003f, 0x1004d), + (0x10050, 0x1005d), + (0x10080, 0x100fa), + (0x10280, 0x1029c), + (0x102a0, 0x102d0), + (0x10300, 0x1031f), + (0x1032d, 0x10340), + (0x10342, 0x10349), + (0x10350, 0x10375), + (0x10380, 0x1039d), + (0x103a0, 0x103c3), + (0x103c8, 0x103cf), + (0x10400, 0x1049d), + (0x104b0, 0x104d3), + (0x104d8, 0x104fb), + (0x10500, 0x10527), + (0x10530, 0x10563), + (0x10570, 0x1057a), + (0x1057c, 0x1058a), + (0x1058c, 0x10592), + (0x10594, 0x10595), + (0x10597, 0x105a1), + (0x105a3, 0x105b1), + (0x105b3, 0x105b9), + (0x105bb, 0x105bc), + (0x105c0, 0x105f3), + (0x10600, 0x10736), + (0x10740, 0x10755), + (0x10760, 0x10767), + (0x10780, 0x10785), + (0x10787, 0x107b0), + (0x107b2, 0x107ba), + (0x10800, 0x10805), + (0x10808, 0x10808), + (0x1080a, 0x10835), + (0x10837, 0x10838), + (0x1083c, 0x1083c), + (0x1083f, 0x10855), + (0x10860, 0x10876), + (0x10880, 0x1089e), + (0x108e0, 0x108f2), + (0x108f4, 0x108f5), + (0x10900, 0x10915), + (0x10920, 0x10939), + (0x10980, 0x109b7), + (0x109be, 0x109bf), + (0x10a00, 0x10a00), + (0x10a10, 0x10a13), + (0x10a15, 0x10a17), + (0x10a19, 0x10a35), + (0x10a60, 0x10a7c), + (0x10a80, 0x10a9c), + (0x10ac0, 0x10ac7), + (0x10ac9, 0x10ae4), + (0x10b00, 0x10b35), + (0x10b40, 0x10b55), + (0x10b60, 0x10b72), + (0x10b80, 0x10b91), + (0x10c00, 0x10c48), + (0x10c80, 0x10cb2), + (0x10cc0, 0x10cf2), + (0x10d00, 0x10d23), + (0x10d4a, 0x10d65), + (0x10d6f, 0x10d85), + (0x10e80, 0x10ea9), + (0x10eb0, 0x10eb1), + (0x10ec2, 0x10ec4), + (0x10f00, 0x10f1c), + (0x10f27, 0x10f27), + (0x10f30, 0x10f45), + (0x10f70, 0x10f81), + (0x10fb0, 0x10fc4), + (0x10fe0, 0x10ff6), + (0x11003, 0x11037), + (0x11071, 0x11072), + (0x11075, 0x11075), + (0x11083, 0x110af), + (0x110d0, 0x110e8), + (0x11103, 0x11126), + (0x11144, 0x11144), + (0x11147, 0x11147), + (0x11150, 0x11172), + (0x11176, 0x11176), + (0x11183, 0x111b2), + (0x111c1, 0x111c4), + (0x111da, 0x111da), + (0x111dc, 0x111dc), + (0x11200, 0x11211), + (0x11213, 0x1122b), + (0x1123f, 0x11240), + (0x11280, 0x11286), + (0x11288, 0x11288), + (0x1128a, 0x1128d), + (0x1128f, 0x1129d), + (0x1129f, 0x112a8), + (0x112b0, 0x112de), + (0x11305, 0x1130c), + (0x1130f, 0x11310), + (0x11313, 0x11328), + (0x1132a, 0x11330), + (0x11332, 0x11333), + (0x11335, 0x11339), + (0x1133d, 0x1133d), + (0x11350, 0x11350), + (0x1135d, 0x11361), + (0x11380, 0x11389), + (0x1138b, 0x1138b), + (0x1138e, 0x1138e), + (0x11390, 0x113b5), + (0x113b7, 0x113b7), + (0x113d1, 0x113d1), + (0x113d3, 0x113d3), + (0x11400, 0x11434), + (0x11447, 0x1144a), + (0x1145f, 0x11461), + (0x11480, 0x114af), + (0x114c4, 0x114c5), + (0x114c7, 0x114c7), + (0x11580, 0x115ae), + (0x115d8, 0x115db), + (0x11600, 0x1162f), + (0x11644, 0x11644), + (0x11680, 0x116aa), + (0x116b8, 0x116b8), + (0x11700, 0x1171a), + (0x11740, 0x11746), + (0x11800, 0x1182b), + (0x118a0, 0x118df), + (0x118ff, 0x11906), + (0x11909, 0x11909), + (0x1190c, 0x11913), + (0x11915, 0x11916), + (0x11918, 0x1192f), + (0x1193f, 0x1193f), + (0x11941, 0x11941), + (0x119a0, 0x119a7), + (0x119aa, 0x119d0), + (0x119e1, 0x119e1), + (0x119e3, 0x119e3), + (0x11a00, 0x11a00), + (0x11a0b, 0x11a32), + (0x11a3a, 0x11a3a), + (0x11a50, 0x11a50), + (0x11a5c, 0x11a89), + (0x11a9d, 0x11a9d), + (0x11ab0, 0x11af8), + (0x11bc0, 0x11be0), + (0x11c00, 0x11c08), + (0x11c0a, 0x11c2e), + (0x11c40, 0x11c40), + (0x11c72, 0x11c8f), + (0x11d00, 0x11d06), + (0x11d08, 0x11d09), + (0x11d0b, 0x11d30), + (0x11d46, 0x11d46), + (0x11d60, 0x11d65), + (0x11d67, 0x11d68), + (0x11d6a, 0x11d89), + (0x11d98, 0x11d98), + (0x11ee0, 0x11ef2), + (0x11f02, 0x11f02), + (0x11f04, 0x11f10), + (0x11f12, 0x11f33), + (0x11fb0, 0x11fb0), + (0x12000, 0x12399), + (0x12480, 0x12543), + (0x12f90, 0x12ff0), + (0x13000, 0x1342f), + (0x13441, 0x13446), + (0x13460, 0x143fa), + (0x14400, 0x14646), + (0x16100, 0x1611d), + (0x16800, 0x16a38), + (0x16a40, 0x16a5e), + (0x16a70, 0x16abe), + (0x16ad0, 0x16aed), + (0x16b00, 0x16b2f), + (0x16b40, 0x16b43), + (0x16b63, 0x16b77), + (0x16b7d, 0x16b8f), + (0x16d40, 0x16d6c), + (0x16e40, 0x16e7f), + (0x16f00, 0x16f4a), + (0x16f50, 0x16f50), + (0x16f93, 0x16f9f), + (0x16fe0, 0x16fe1), + (0x16fe3, 0x16fe3), + (0x17000, 0x187f7), + (0x18800, 0x18cd5), + (0x18cff, 0x18d08), + (0x1aff0, 0x1aff3), + (0x1aff5, 0x1affb), + (0x1affd, 0x1affe), + (0x1b000, 0x1b122), + (0x1b132, 0x1b132), + (0x1b150, 0x1b152), + (0x1b155, 0x1b155), + (0x1b164, 0x1b167), + (0x1b170, 0x1b2fb), + (0x1bc00, 0x1bc6a), + (0x1bc70, 0x1bc7c), + (0x1bc80, 0x1bc88), + (0x1bc90, 0x1bc99), + (0x1d400, 0x1d454), + (0x1d456, 0x1d49c), + (0x1d49e, 0x1d49f), + (0x1d4a2, 0x1d4a2), + (0x1d4a5, 0x1d4a6), + (0x1d4a9, 0x1d4ac), + (0x1d4ae, 0x1d4b9), + (0x1d4bb, 0x1d4bb), + (0x1d4bd, 0x1d4c3), + (0x1d4c5, 0x1d505), + (0x1d507, 0x1d50a), + (0x1d50d, 0x1d514), + (0x1d516, 0x1d51c), + (0x1d51e, 0x1d539), + (0x1d53b, 0x1d53e), + (0x1d540, 0x1d544), + (0x1d546, 0x1d546), + (0x1d54a, 0x1d550), + (0x1d552, 0x1d6a5), + (0x1d6a8, 0x1d6c0), + (0x1d6c2, 0x1d6da), + (0x1d6dc, 0x1d6fa), + (0x1d6fc, 0x1d714), + (0x1d716, 0x1d734), + (0x1d736, 0x1d74e), + (0x1d750, 0x1d76e), + (0x1d770, 0x1d788), + (0x1d78a, 0x1d7a8), + (0x1d7aa, 0x1d7c2), + (0x1d7c4, 0x1d7cb), + (0x1df00, 0x1df1e), + (0x1df25, 0x1df2a), + (0x1e030, 0x1e06d), + (0x1e100, 0x1e12c), + (0x1e137, 0x1e13d), + (0x1e14e, 0x1e14e), + (0x1e290, 0x1e2ad), + (0x1e2c0, 0x1e2eb), + (0x1e4d0, 0x1e4eb), + (0x1e5d0, 0x1e5ed), + (0x1e5f0, 0x1e5f0), + (0x1e7e0, 0x1e7e6), + (0x1e7e8, 0x1e7eb), + (0x1e7ed, 0x1e7ee), + (0x1e7f0, 0x1e7fe), + (0x1e800, 0x1e8c4), + (0x1e900, 0x1e943), + (0x1e94b, 0x1e94b), + (0x1ee00, 0x1ee03), + (0x1ee05, 0x1ee1f), + (0x1ee21, 0x1ee22), + (0x1ee24, 0x1ee24), + (0x1ee27, 0x1ee27), + (0x1ee29, 0x1ee32), + (0x1ee34, 0x1ee37), + (0x1ee39, 0x1ee39), + (0x1ee3b, 0x1ee3b), + (0x1ee42, 0x1ee42), + (0x1ee47, 0x1ee47), + (0x1ee49, 0x1ee49), + (0x1ee4b, 0x1ee4b), + (0x1ee4d, 0x1ee4f), + (0x1ee51, 0x1ee52), + (0x1ee54, 0x1ee54), + (0x1ee57, 0x1ee57), + (0x1ee59, 0x1ee59), + (0x1ee5b, 0x1ee5b), + (0x1ee5d, 0x1ee5d), + (0x1ee5f, 0x1ee5f), + (0x1ee61, 0x1ee62), + (0x1ee64, 0x1ee64), + (0x1ee67, 0x1ee6a), + (0x1ee6c, 0x1ee72), + (0x1ee74, 0x1ee77), + (0x1ee79, 0x1ee7c), + (0x1ee7e, 0x1ee7e), + (0x1ee80, 0x1ee89), + (0x1ee8b, 0x1ee9b), + (0x1eea1, 0x1eea3), + (0x1eea5, 0x1eea9), + (0x1eeab, 0x1eebb), + (0x20000, 0x2a6df), + (0x2a700, 0x2b739), + (0x2b740, 0x2b81d), + (0x2b820, 0x2cea1), + (0x2ceb0, 0x2ebe0), + (0x2ebf0, 0x2ee5d), + (0x2f800, 0x2fa1d), + (0x30000, 0x3134a), + (0x31350, 0x323af), +) +N_RANGES = ( + (0x30, 0x39), + (0xb2, 0xb3), + (0xb9, 0xb9), + (0xbc, 0xbe), + (0x660, 0x669), + (0x6f0, 0x6f9), + (0x7c0, 0x7c9), + (0x966, 0x96f), + (0x9e6, 0x9ef), + (0x9f4, 0x9f9), + (0xa66, 0xa6f), + (0xae6, 0xaef), + (0xb66, 0xb6f), + (0xb72, 0xb77), + (0xbe6, 0xbf2), + (0xc66, 0xc6f), + (0xc78, 0xc7e), + (0xce6, 0xcef), + (0xd58, 0xd5e), + (0xd66, 0xd78), + (0xde6, 0xdef), + (0xe50, 0xe59), + (0xed0, 0xed9), + (0xf20, 0xf33), + (0x1040, 0x1049), + (0x1090, 0x1099), + (0x1369, 0x137c), + (0x16ee, 0x16f0), + (0x17e0, 0x17e9), + (0x17f0, 0x17f9), + (0x1810, 0x1819), + (0x1946, 0x194f), + (0x19d0, 0x19da), + (0x1a80, 0x1a89), + (0x1a90, 0x1a99), + (0x1b50, 0x1b59), + (0x1bb0, 0x1bb9), + (0x1c40, 0x1c49), + (0x1c50, 0x1c59), + (0x2070, 0x2070), + (0x2074, 0x2079), + (0x2080, 0x2089), + (0x2150, 0x2182), + (0x2185, 0x2189), + (0x2460, 0x249b), + (0x24ea, 0x24ff), + (0x2776, 0x2793), + (0x2cfd, 0x2cfd), + (0x3007, 0x3007), + (0x3021, 0x3029), + (0x3038, 0x303a), + (0x3192, 0x3195), + (0x3220, 0x3229), + (0x3248, 0x324f), + (0x3251, 0x325f), + (0x3280, 0x3289), + (0x32b1, 0x32bf), + (0xa620, 0xa629), + (0xa6e6, 0xa6ef), + (0xa830, 0xa835), + (0xa8d0, 0xa8d9), + (0xa900, 0xa909), + (0xa9d0, 0xa9d9), + (0xa9f0, 0xa9f9), + (0xaa50, 0xaa59), + (0xabf0, 0xabf9), + (0xff10, 0xff19), + (0x10107, 0x10133), + (0x10140, 0x10178), + (0x1018a, 0x1018b), + (0x102e1, 0x102fb), + (0x10320, 0x10323), + (0x10341, 0x10341), + (0x1034a, 0x1034a), + (0x103d1, 0x103d5), + (0x104a0, 0x104a9), + (0x10858, 0x1085f), + (0x10879, 0x1087f), + (0x108a7, 0x108af), + (0x108fb, 0x108ff), + (0x10916, 0x1091b), + (0x109bc, 0x109bd), + (0x109c0, 0x109cf), + (0x109d2, 0x109ff), + (0x10a40, 0x10a48), + (0x10a7d, 0x10a7e), + (0x10a9d, 0x10a9f), + (0x10aeb, 0x10aef), + (0x10b58, 0x10b5f), + (0x10b78, 0x10b7f), + (0x10ba9, 0x10baf), + (0x10cfa, 0x10cff), + (0x10d30, 0x10d39), + (0x10d40, 0x10d49), + (0x10e60, 0x10e7e), + (0x10f1d, 0x10f26), + (0x10f51, 0x10f54), + (0x10fc5, 0x10fcb), + (0x11052, 0x1106f), + (0x110f0, 0x110f9), + (0x11136, 0x1113f), + (0x111d0, 0x111d9), + (0x111e1, 0x111f4), + (0x112f0, 0x112f9), + (0x11450, 0x11459), + (0x114d0, 0x114d9), + (0x11650, 0x11659), + (0x116c0, 0x116c9), + (0x116d0, 0x116e3), + (0x11730, 0x1173b), + (0x118e0, 0x118f2), + (0x11950, 0x11959), + (0x11bf0, 0x11bf9), + (0x11c50, 0x11c6c), + (0x11d50, 0x11d59), + (0x11da0, 0x11da9), + (0x11f50, 0x11f59), + (0x11fc0, 0x11fd4), + (0x12400, 0x1246e), + (0x16130, 0x16139), + (0x16a60, 0x16a69), + (0x16ac0, 0x16ac9), + (0x16b50, 0x16b59), + (0x16b5b, 0x16b61), + (0x16d70, 0x16d79), + (0x16e80, 0x16e96), + (0x1ccf0, 0x1ccf9), + (0x1d2c0, 0x1d2d3), + (0x1d2e0, 0x1d2f3), + (0x1d360, 0x1d378), + (0x1d7ce, 0x1d7ff), + (0x1e140, 0x1e149), + (0x1e2f0, 0x1e2f9), + (0x1e4f0, 0x1e4f9), + (0x1e5f1, 0x1e5fa), + (0x1e8c7, 0x1e8cf), + (0x1e950, 0x1e959), + (0x1ec71, 0x1ecab), + (0x1ecad, 0x1ecaf), + (0x1ecb1, 0x1ecb4), + (0x1ed01, 0x1ed2d), + (0x1ed2f, 0x1ed3d), + (0x1f100, 0x1f10c), + (0x1fbf0, 0x1fbf9), +) + +#: Code points the Rust NFC treats as combining-class 0 although unicodedata says otherwise, +#: plus second members of compositions the Rust side lacks. NFC is applied around them. +NFC_BARRIERS = ( + (0x7fd, 0x7fd), + (0x898, 0x89f), + (0x8ca, 0x8d3), + (0x9fe, 0x9fe), + (0xc3c, 0xc3c), + (0xd3b, 0xd3c), + (0xeba, 0xeba), + (0x1715, 0x1715), + (0x1abf, 0x1ace), + (0x1df6, 0x1dfa), + (0xa82c, 0xa82c), + (0x10d24, 0x10d27), + (0x10eab, 0x10eac), + (0x10efd, 0x10eff), + (0x10f46, 0x10f50), + (0x10f82, 0x10f85), + (0x11070, 0x11070), + (0x1133b, 0x1133b), + (0x1145e, 0x1145e), + (0x11839, 0x1183a), + (0x11930, 0x11930), + (0x1193d, 0x1193e), + (0x11943, 0x11943), + (0x119e0, 0x119e0), + (0x11a34, 0x11a34), + (0x11a47, 0x11a47), + (0x11a99, 0x11a99), + (0x11d42, 0x11d42), + (0x11d44, 0x11d45), + (0x11d97, 0x11d97), + (0x11f41, 0x11f42), + (0x16ff0, 0x16ff1), + (0x1e08f, 0x1e08f), + (0x1e130, 0x1e136), + (0x1e2ae, 0x1e2ae), + (0x1e2ec, 0x1e2ef), + (0x1e4ec, 0x1e4ef), +) diff --git a/code/align/tokenizer/bytelevel.py b/code/align/tokenizer/bytelevel.py new file mode 100644 index 0000000000000000000000000000000000000000..c0f768f93f9cdd8b56fc5ce67b82e5dcb8fc426f --- /dev/null +++ b/code/align/tokenizer/bytelevel.py @@ -0,0 +1,693 @@ +"""Pure-Python (stdlib only) byte-level BPE tokenizer for Qwen2/Qwen3 (Goedel-Prover-V2-8B). + +Why this exists. P2 (LoRA SFT on Goedel-Prover-V2-8B's own verified samples) needs +token ids for prompts and completions. Before this module the only way to get +them for a Qwen3 vocabulary was `transformers.AutoTokenizer`, i.e. the isolated +vLLM venv: the training process would have had to import (or shell out to) a +second Python environment just to turn text into ints, and a version skew +between that venv and the one that trained would silently change the ids +(measured elsewhere in this repo: transformers 5.x REBUILDS pipelines from the +config rather than from tokenizer.json). This module reads tokenizer.json +directly and is certified byte-identical (ids AND decode) against the HF tokenizer +on a frozen oracle corpus by tests/test_tokenizer_bytelevel.py. + +Pipeline (encode), exactly what tokenizer.json declares and nothing else: + + text + -> split on ADDED tokens (<|im_start|>, , ...), leftmost-longest, + on the RAW text (all are normalized=false) + -> per remaining segment: NFC normalizer + -> Split(Isolated) with the Qwen2 regex + -> ByteLevel: UTF-8 bytes of each piece mapped through GPT-2 bytes_to_unicode + -> BPE (rank-ordered merges) per piece + -> post-processor ByteLevel: adds nothing (no BOS/EOS) + +Decode: ids -> pieces (optionally drop special=true added tokens) -> join -> +byte-decode -> UTF-8 with U+FFFD replacement. + +The three places a reimplementation gets this wrong -- each has a mutant in the +test file that must make parity FAIL: + +1. NFC per SEGMENT, not per string. Added tokens are carved out first, so a + combining mark right after "<|im_end|>" has nothing to compose with. NFC on the + whole string would compose across the special token. Dropping NFC entirely + changes the ids of every decomposed-form string (e.g. "e" + U+0301). +2. The regex has `\\p{N}` (ONE digit per piece, so "2024" is four pieces) and + `\\p{L}+` / `[^\\r\\n\\p{L}\\p{N}]?` (a single non-letter prefix glues onto a word). + Python `re` has no \\p{..}: the classes are explicit ranges (_class_body) + built from the frozen Rust-side tables in _qwen2_unicode.py. A "\\d+" or "\\w+" shortcut is + not equivalent (superscripts are \\p{N} but not \\d; "_" is \\w but not \\p{L}). +3. BPE tie-break: lowest merge RANK wins, ties go to the LEFTMOST pair. Using + vocab id (or longest-match) instead of rank changes tokens inside long + identifiers and whitespace runs, silently. + +Unicode tables (measured, pinned in tests): the Rust tokenizer's Unicode tables are not +those of any one Python. \\p{L}/\\p{N} are NEWER than CPython 3.12's unicodedata (5004 +Unicode-16 code points are letters/digits there and unassigned here) and the NFC +normalizer is OLDER (108 combining marks of Unicode 10-15 keep combining class 0, and +U+11935 U+11930 does not compose). A unicodedata-derived translation therefore split +"X's" differently for those code points and canonically reordered marks HF leaves alone. +Both are now FROZEN from the real tokenizer (_qwen2_unicode.py, generated by +tests/data/make_qwen2_unicode_tables.py), so the result does not depend on the Python +version for the regex classes; NFC still uses unicodedata for everything else and is pinned +to the certified unicodedata version by a test. + +The loader VALIDATES the whole pipeline configuration and raises +NotImplementedError on anything not implemented (a different regex, a missing +NFC, ignore_merges, normalized added tokens, clean_up_tokenization_spaces, +an unknown chat template ...). A different tokenizer.json must fail loudly, not +silently encode wrong ids. +""" +from __future__ import annotations + +import hashlib +import heapq +import json +import os +import re +import unicodedata +from typing import Iterable, Optional, Sequence, Union + +from .core import _TOKENIZER_FILES, _as_list, _content, _expect, _resolve_dir +from ._qwen2_unicode import L_RANGES, N_RANGES, NFC_BARRIERS + +__all__ = ["ByteLevelTokenizer", "QWEN2_PRETOKENIZE_REGEX", "bytes_to_unicode", "render_qwen3_chat"] + +#: The pre_tokenizer Split pattern the Qwen2/Qwen2.5/Qwen3 tokenizer.json files ship. +#: The loader requires tokenizer.json to carry EXACTLY this string: the Python +#: translation below (_build_pattern) is only valid for it. +QWEN2_PRETOKENIZE_REGEX = ( + r"(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}| ?[^\s\p{L}\p{N}]+[\r\n]*" + r"|\s*[\r\n]+|\s+(?!\S)|\s+" +) + +#: sha256 of the Qwen3 chat_template string that render_qwen3_chat reimplements +#: (the subset without tools). A config carrying any other template makes +#: apply_chat_template raise instead of rendering with the wrong one. +QWEN3_CHAT_TEMPLATE_SHA256 = "a55ee1b1660128b7098723e0abcd92caa0788061051c62d51cbe87d9cf1974d8" + +_CACHE_MAX_ENTRIES = 200_000 + +# Unicode White_Space property (what the Rust regex `\s` means). NOT Python's +# str.isspace(): that also accepts U+001C..U+001F, which are not White_Space. +_WHITE_SPACE = ( + (0x09, 0x0D), (0x20, 0x20), (0x85, 0x85), (0xA0, 0xA0), (0x1680, 0x1680), + (0x2000, 0x200A), (0x2028, 0x2029), (0x202F, 0x202F), (0x205F, 0x205F), (0x3000, 0x3000), +) + + +def bytes_to_unicode() -> dict[int, str]: + """GPT-2 byte -> printable-char map (the ByteLevel alphabet): printable Latin-1 + bytes map to themselves, the other 68 bytes to U+0100 and up, in byte order.""" + keep = list(range(0x21, 0x7F)) + list(range(0xA1, 0xAD)) + list(range(0xAE, 0x100)) + out: dict[int, str] = {} + n = 0 + for b in range(256): + if b in keep: + out[b] = chr(b) + else: + out[b] = chr(256 + n) + n += 1 + return out + + +def _ranges(pred) -> list[tuple[int, int]]: + out: list[tuple[int, int]] = [] + start = None + for cp in range(0x110000): + ok = pred(cp) + if ok and start is None: + start = cp + elif not ok and start is not None: + out.append((start, cp - 1)) + start = None + if start is not None: + out.append((start, 0x10FFFF)) + return out + + +def _class_body(ranges: Iterable[tuple[int, int]]) -> str: + """Body of a regex character class (without the brackets) for explicit ranges.""" + parts = [] + for a, b in ranges: + parts.append(f"\\U{a:08x}" if a == b else f"\\U{a:08x}-\\U{b:08x}") + return "".join(parts) + + +_PATTERN: Optional[re.Pattern] = None +_BARRIER_RE: Optional[re.Pattern] = None + + +def _build_pattern() -> re.Pattern: + """Python-`re` translation of QWEN2_PRETOKENIZE_REGEX. \\p{L} / \\p{N} are the FROZEN + Rust-side tables (L_RANGES / N_RANGES), \\s = White_Space. The contraction group is + spelled out instead of (?i:...): Python's IGNORECASE is Unicode-aware and would also + accept U+017F (long s) for 's -- the oracle test pins what the reference does for it.""" + global _PATTERN + if _PATTERN is not None: + return _PATTERN + L = _class_body(L_RANGES) + N = _class_body(N_RANGES) + S = _class_body(_WHITE_SPACE) + pat = ( + r"'(?:[sS]|[tT]|[rR][eE]|[vV][eE]|[mM]|[lL][lL]|[dD])" + rf"|[^\r\n{L}{N}]?[{L}]+" + rf"|[{N}]" + rf"| ?[^{S}{L}{N}]+[\r\n]*" + rf"|[{S}]*[\r\n]+" + rf"|[{S}]+(?![^{S}])" + rf"|[{S}]+" + ) + _PATTERN = re.compile(pat) + return _PATTERN + + +def _barrier_re() -> re.Pattern: + global _BARRIER_RE + if _BARRIER_RE is None: + _BARRIER_RE = re.compile("([" + _class_body(NFC_BARRIERS) + "])") + return _BARRIER_RE + + +class ByteLevelTokenizer: + """Qwen2/Qwen3 byte-level BPE, API-compatible with align.tokenizer.Tokenizer + for the calls this repo makes (encode / __call__ / decode / ids / save). + + Build with `ByteLevelTokenizer.from_pretrained(dir)` or `load_tokenizer(dir)`. + """ + + def __init__( + self, + tokenizer_json: dict, + tokenizer_config: Optional[dict] = None, + special_tokens_map: Optional[dict] = None, + *, + files: Optional[dict] = None, + ): + self._files: dict[str, bytes] = dict(files or {}) + self._config = dict(tokenizer_config or {}) + self._special_map = dict(special_tokens_map or {}) + self._tokenizer_json = tokenizer_json + self._validate_pipeline(tokenizer_json, self._config) + + model = tokenizer_json["model"] + base_vocab: dict[str, int] = dict(model["vocab"]) + self._base_vocab = base_vocab + vocab = dict(base_vocab) + + self._added: dict[str, int] = {} + self._special_contents: set[str] = set() + for t in tokenizer_json.get("added_tokens", []): + _expect( + not (t.get("lstrip") or t.get("rstrip") or t.get("single_word")), + f"added token {t['content']!r} with lstrip/rstrip/single_word", + ) + _expect( + not t.get("normalized"), + f"added token {t['content']!r} with normalized=true (NFC-before-match not implemented)", + ) + vocab[t["content"]] = int(t["id"]) + self._added[t["content"]] = int(t["id"]) + if t.get("special"): + self._special_contents.add(t["content"]) + self._vocab = vocab + size = max(vocab.values()) + 1 + self._id_to_token: list[Optional[str]] = [None] * size + for tok, i in vocab.items(): + self._id_to_token[i] = tok + + self._b2u = bytes_to_unicode() + self._u2b = {c: b for b, c in self._b2u.items()} + missing = [b for b, c in self._b2u.items() if c not in base_vocab] + _expect(not missing, f"vocab lacks ByteLevel alphabet symbols for bytes {missing[:5]}") + + self._ranks: dict[tuple[str, str], int] = {} + for rank, m in enumerate(model["merges"]): + a, b = (m[0], m[1]) if isinstance(m, (list, tuple)) else m.split(" ") + if (a + b) not in base_vocab or a not in base_vocab or b not in base_vocab: + raise ValueError(f"merge #{rank} {a!r}+{b!r} references a token outside the vocab") + self._ranks[(a, b)] = rank # last duplicate wins (Rust HashMap semantics) + + if self._added: + alts = sorted(self._added, key=len, reverse=True) + self._added_re: Optional[re.Pattern] = re.compile("|".join(re.escape(a) for a in alts)) + else: + self._added_re = None + self._cache: dict[str, tuple[int, ...]] = {} + self._id_bytes: list[Optional[bytes]] = [None] * size + + def pick(name: str, default: Optional[str] = None) -> Optional[str]: + v = _content(self._config.get(f"{name}_token")) + if v is None: + v = _content(self._special_map.get(f"{name}_token")) + if v is None: + v = default + return v if (v is None or v in self._vocab) else None + + self.bos_token = pick("bos") + self.eos_token = pick("eos") + self.unk_token = pick("unk") + self.pad_token = pick("pad") + + # ------------------------------------------------------------------ config + + @staticmethod + def _validate_pipeline(tj: dict, cfg: dict) -> None: + model = tj["model"] + _expect(model.get("type") == "BPE", f"model.type={model.get('type')!r}") + _expect(not model.get("dropout"), "BPE dropout") + _expect(not model.get("continuing_subword_prefix"), "continuing_subword_prefix") + _expect(not model.get("end_of_word_suffix"), "end_of_word_suffix") + _expect(not model.get("byte_fallback"), "byte_fallback") + _expect(not model.get("ignore_merges"), "ignore_merges") + _expect(not model.get("fuse_unk"), "fuse_unk") + _expect(model.get("unk_token") is None, "an unk_token") + _expect(tj.get("normalizer") == {"type": "NFC"}, f"normalizer {tj.get('normalizer')!r} (only NFC)") + pt = tj.get("pre_tokenizer") or {} + _expect(pt.get("type") == "Sequence", f"pre_tokenizer {pt.get('type')!r}") + seq = pt.get("pretokenizers") or [] + _expect(len(seq) == 2, "pre_tokenizer Sequence other than [Split, ByteLevel]") + sp, bl = seq + _expect(sp.get("type") == "Split", f"pre_tokenizer[0] {sp.get('type')!r}") + _expect( + (sp.get("pattern") or {}).get("Regex") == QWEN2_PRETOKENIZE_REGEX, + "a Split regex other than the Qwen2 one", + ) + _expect(sp.get("behavior") == "Isolated", f"Split behavior {sp.get('behavior')!r}") + _expect(sp.get("invert") is False, "Split invert=true") + _expect(bl.get("type") == "ByteLevel", f"pre_tokenizer[1] {bl.get('type')!r}") + _expect(not bl.get("add_prefix_space"), "ByteLevel add_prefix_space=true") + _expect(bl.get("use_regex") is False, "ByteLevel use_regex=true (GPT-2 regex on top)") + dec = tj.get("decoder") or {} + _expect(dec.get("type") == "ByteLevel", f"decoder {dec.get('type')!r}") + pp = tj.get("post_processor") + if pp is not None: + _expect( + pp.get("type") == "ByteLevel" and not pp.get("add_prefix_space") and not pp.get("trim_offsets"), + f"post_processor {pp.get('type')!r} other than a no-op ByteLevel", + ) + # tokenizer.json can carry truncation/padding; the Rust encoder applies them + # (silently clipping every encode). Neither is implemented. + _expect(tj.get("truncation") is None, "a tokenizer.json truncation setting") + _expect(tj.get("padding") is None, "a tokenizer.json padding setting") + ByteLevelTokenizer._check_added_tokens_decoder(tj, cfg) + # transformers applies these from the CONFIG on top of tokenizer.json. + _expect(not cfg.get("add_prefix_space"), "tokenizer_config.json add_prefix_space=true") + _expect(not cfg.get("add_bos_token"), "tokenizer_config.json add_bos_token=true") + _expect( + not cfg.get("clean_up_tokenization_spaces"), + "tokenizer_config.json clean_up_tokenization_spaces=true", + ) + _expect(not cfg.get("split_special_tokens"), "tokenizer_config.json split_special_tokens=true") + _expect(cfg.get("errors", "replace") == "replace", f"decode errors={cfg.get('errors')!r}") + + @staticmethod + def _check_added_tokens_decoder(tj: dict, cfg: dict) -> None: + """tokenizer_config.json `added_tokens_decoder` must AGREE with tokenizer.json's + added_tokens (same ids, contents and lstrip/rstrip/single_word/normalized/special). + + Incident this prevents: transformers builds the added-token matcher from the + CONFIG as well as tokenizer.json. Measured (transformers 5.19.0, Goedel snapshot + with only `.lstrip=true` flipped in tokenizer_config.json): HF encodes + "a b" as [64, 151667, 293] (the space before the token is eaten) while a + reader of tokenizer.json alone gives [64, 220, 151667, 293]. A config/json pair + that disagrees must not load silently.""" + adt = cfg.get("added_tokens_decoder") + if adt is None: + return + declared = {int(k): v for k, v in adt.items()} + in_json = {int(t["id"]): t for t in tj.get("added_tokens", [])} + _expect( + set(declared) == set(in_json), + "tokenizer_config.json added_tokens_decoder ids differ from tokenizer.json added_tokens", + ) + for i, t in in_json.items(): + c = declared[i] + _expect(c.get("content") == t["content"], f"added token {i} content differs between config and json") + for flag in ("special", "normalized", "lstrip", "rstrip", "single_word"): + _expect( + bool(c.get(flag)) == bool(t.get(flag)), + f"added token {t['content']!r}: {flag} differs between tokenizer_config.json and tokenizer.json", + ) + + # ------------------------------------------------------------- vocabulary + + @property + def bos_token_id(self) -> Optional[int]: + return None if self.bos_token is None else self._vocab[self.bos_token] + + @property + def eos_token_id(self) -> Optional[int]: + return None if self.eos_token is None else self._vocab[self.eos_token] + + @property + def pad_token_id(self) -> Optional[int]: + return None if self.pad_token is None else self._vocab[self.pad_token] + + @property + def unk_token_id(self) -> Optional[int]: + return None + + @property + def vocab_size(self) -> int: + """BPE base vocabulary only (HF semantics): 151643 for Qwen3; len(tok) adds + the added tokens. The model's embedding rows (151936) are padding on top.""" + return len(self._base_vocab) + + @property + def all_special_tokens(self) -> list[str]: + return sorted(self._special_contents, key=lambda t: self._vocab[t]) + + @property + def all_special_ids(self) -> list[int]: + return [self._vocab[t] for t in self.all_special_tokens] + + def get_vocab(self) -> dict[str, int]: + return dict(self._vocab) + + def get_added_vocab(self) -> dict[str, int]: + return dict(self._added) + + def __len__(self) -> int: + return len(self._vocab) + + def __repr__(self) -> str: + return f"ByteLevelTokenizer(n={len(self)}, merges={len(self._ranks)}, added={len(self._added)})" + + def _piece(self, i: int) -> Optional[str]: + if i < 0: + raise ValueError(f"negative token id {i}: a label-mask value leaked into a token-id path") + return self._id_to_token[i] if i < len(self._id_to_token) else None + + def convert_ids_to_tokens(self, ids: Union[int, Iterable[int]]): + if isinstance(ids, int): + return self._piece(ids) + return [self._piece(int(i)) for i in _as_list(ids)] + + def convert_tokens_to_ids(self, tokens: Union[str, Iterable[str]]): + if isinstance(tokens, str): + return self._vocab.get(tokens) + return [self._vocab.get(t) for t in tokens] + + # ------------------------------------------------------------------ encode + + def __call__(self, text: Union[str, Sequence[str]], add_special_tokens: bool = True) -> dict: + if isinstance(text, str): + return {"input_ids": self.encode(text, add_special_tokens=add_special_tokens)} + return {"input_ids": [self.encode(t, add_special_tokens=add_special_tokens) for t in text]} + + def encode(self, text: str, add_special_tokens: bool = True) -> list[int]: + """`add_special_tokens` is accepted for API parity; Qwen3 adds none.""" + if not isinstance(text, str): + raise TypeError(f"encode() takes str, got {type(text).__name__}") + try: + text.encode("utf-8") + except UnicodeEncodeError as e: + raise ValueError(f"text is not valid Unicode (lone surrogate at index {e.start})") from e + ids: list[int] = [] + for is_added, seg in self._split_added(text): + if is_added: + ids.append(self._added[seg]) + else: + ids.extend(self._encode_segment(self._normalize(seg))) + return ids + + @staticmethod + def _normalize(seg: str) -> str: + """NFC as the Rust normalizer computes it. ASCII is NFC-invariant. A code point in + NFC_BARRIERS is a starter there (never reordered, never composed) but not in + Python's newer table, so the text is normalized AROUND it, never across it. + + Incident this prevents: "\\u0301\\U00011d45" (acute, then Masaram Gondi virama) is + kept in that order by HF, but unicodedata.normalize moves the virama (ccc 9) in + front of the acute (ccc 230): same text, different ids.""" + if seg.isascii(): + return seg + rx = _barrier_re() + if rx.search(seg) is None: + return unicodedata.normalize("NFC", seg) + parts = rx.split(seg) # [text, barrier, text, barrier, ..., text] + return "".join(p if k & 1 else unicodedata.normalize("NFC", p) for k, p in enumerate(parts)) + + def _split_added(self, text: str): + if self._added_re is None or not text: + if text: + yield False, text + return + pos = 0 + for m in self._added_re.finditer(text): + if m.start() > pos: + yield False, text[pos : m.start()] + yield True, m.group(0) + pos = m.end() + if pos < len(text): + yield False, text[pos:] + + def _pretokenize(self, seg: str): + """Split(Isolated): matches AND the gaps between them become pieces (the + regex's last alternatives cover every character, so gaps cannot occur for + the Qwen2 pattern; kept so a pattern change cannot silently drop text).""" + pos = 0 + for m in _build_pattern().finditer(seg): + if m.start() > pos: + yield seg[pos : m.start()] + yield m.group(0) + pos = m.end() + if pos < len(seg): + yield seg[pos:] + + def _encode_segment(self, seg: str) -> list[int]: + out: list[int] = [] + cache = self._cache + for piece in self._pretokenize(seg): + r = cache.get(piece) + if r is None: + r = self._bpe(piece) + if len(cache) >= _CACHE_MAX_ENTRIES: + cache.clear() + cache[piece] = r + out.extend(r) + return out + + def _bpe(self, piece: str) -> tuple[int, ...]: + b2u = self._b2u + syms = [b2u[b] for b in piece.encode("utf-8")] + return self._merge(syms) + + def _merge(self, syms: list[str]) -> tuple[int, ...]: + """Rank-ordered pair merging (linked list + lazy-deletion min-heap, O(n log n) + so a multi-thousand-char whitespace run is not quadratic). Tie-break: + lowest merge rank, then leftmost position.""" + n = len(syms) + vocab = self._base_vocab + if n < 2: + return tuple(vocab[s] for s in syms) + ranks = self._ranks + nxt = list(range(1, n + 1)) + nxt[-1] = -1 + prv = list(range(-1, n - 1)) + heap: list[tuple[int, int, str, str]] = [] + for i in range(n - 1): + r = ranks.get((syms[i], syms[i + 1])) + if r is not None: + heap.append((r, i, syms[i], syms[i + 1])) + heapq.heapify(heap) + pop, push = heapq.heappop, heapq.heappush + while heap: + _, i, left, right = pop(heap) + if syms[i] != left: + continue + j = nxt[i] + if j == -1 or syms[j] != right: + continue + new = left + right + syms[i] = new + syms[j] = None # type: ignore[call-overload] + nj = nxt[j] + nxt[i] = nj + if nj != -1: + prv[nj] = i + p = prv[i] + if p != -1: + r = ranks.get((syms[p], new)) + if r is not None: + push(heap, (r, p, syms[p], new)) + if nj != -1: + r = ranks.get((new, syms[nj])) + if r is not None: + push(heap, (r, i, new, syms[nj])) + return tuple(vocab[s] for s in syms if s is not None) + + # ------------------------------------------------------------------ decode + + def _bytes_of(self, i: int) -> Optional[bytes]: + b = self._id_bytes[i] + if b is None: + t = self._id_to_token[i] + u2b = self._u2b + # Same rule as the Rust ByteLevel decoder: a token whose every char is in + # the alphabet is byte-decoded; anything else passes through as literal text. + if all(c in u2b for c in t): # type: ignore[union-attr] + b = bytes(u2b[c] for c in t) # type: ignore[union-attr] + else: + b = t.encode("utf-8") # type: ignore[union-attr] + self._id_bytes[i] = b + return b + + def decode(self, ids, skip_special_tokens: bool = False) -> str: + """Join all tokens' bytes THEN decode UTF-8 once: a multi-byte character split + across tokens decodes correctly, a truncated one yields U+FFFD (never an + exception). Ids outside the vocab are skipped (HF behaviour). With + skip_special_tokens only added tokens flagged special=true are dropped + (// are special=false and stay).""" + special = self._special_contents + buf = bytearray() + for i in _as_list(ids): + i = int(i) + t = self._piece(i) + if t is None: + continue + if skip_special_tokens and t in special: + continue + buf += self._bytes_of(i) # type: ignore[arg-type] + return bytes(buf).decode("utf-8", errors="replace") + + # ------------------------------------------------------------ chat template + + def apply_chat_template( + self, + messages: Sequence[dict], + *, + tokenize: bool = False, + add_generation_prompt: bool = False, + enable_thinking: Optional[bool] = None, + tools=None, + ): + """Qwen3 chat template, the system/user/assistant subset. See render_qwen3_chat. + Raises NotImplementedError if the shipped chat_template is not the one this + implements (checked by sha256) or if tools are requested. + + `tokenize=True` returns a plain list[int]. transformers 5.x returns a BatchEncoding + ({"input_ids", "attention_mask"}) there (measured, 5.19.0), so code written against + HF's tokenize=True result must index ["input_ids"] on HF but not here; callers in + this repo use tokenize=False + encode().""" + tpl = self._config.get("chat_template") + _expect( + tpl is not None and hashlib.sha256(tpl.encode("utf-8")).hexdigest() == QWEN3_CHAT_TEMPLATE_SHA256, + "a chat_template other than the Qwen3 one (sha256 mismatch)", + ) + text = render_qwen3_chat( + messages, add_generation_prompt=add_generation_prompt, enable_thinking=enable_thinking, tools=tools + ) + return self.encode(text, add_special_tokens=False) if tokenize else text + + # -------------------------------------------------------------------- save + + def save_pretrained(self, save_directory: str) -> tuple[str, ...]: + """Copy-through of the source files (atomic tmp + os.replace per file).""" + os.makedirs(save_directory, exist_ok=True) + files = dict(self._files) + if "tokenizer.json" not in files: + files["tokenizer.json"] = json.dumps(self._tokenizer_json, ensure_ascii=False).encode("utf-8") + if "tokenizer_config.json" not in files and self._config: + files["tokenizer_config.json"] = json.dumps(self._config, indent=2).encode("utf-8") + if "special_tokens_map.json" not in files and self._special_map: + files["special_tokens_map.json"] = json.dumps(self._special_map, indent=2).encode("utf-8") + written = [] + for name, blob in files.items(): + dst = os.path.join(save_directory, name) + tmp = dst + f".tmp.{os.getpid()}" + with open(tmp, "wb") as f: + f.write(blob) + f.flush() + os.fsync(f.fileno()) + os.replace(tmp, dst) + written.append(dst) + return tuple(written) + + @classmethod + def from_pretrained(cls, path: Union[str, os.PathLike]) -> "ByteLevelTokenizer": + """LOCAL ONLY: a dir holding tokenizer.json, a tokenizer.json path, or an HF + cache model dir. Never touches the network.""" + d = _resolve_dir(os.fspath(path)) + files: dict[str, bytes] = {} + for name in _TOKENIZER_FILES: + p = os.path.join(d, name) + if os.path.isfile(p): + with open(p, "rb") as f: + files[name] = f.read() + tj = json.loads(files["tokenizer.json"]) + cfg = json.loads(files["tokenizer_config.json"]) if "tokenizer_config.json" in files else None + smap = json.loads(files["special_tokens_map.json"]) if "special_tokens_map.json" in files else None + return cls(tj, cfg, smap, files=files) + + +def render_qwen3_chat( + messages: Sequence[dict], + *, + add_generation_prompt: bool = False, + enable_thinking: Optional[bool] = None, + tools=None, +) -> str: + """Render the Qwen3 chat template for system/user/assistant messages. + + Incident this prevents: P2 trains on (prompt, completion) pairs whose prompt + bytes must equal what Goedel-Prover sampled under; correction rounds replay + earlier assistant turns, and the template REWRITES them (earlier turns lose + their block; only turns after the last user query keep + "\\n..\\n\\n\\n"). Hand-rolled "<|im_start|>" concatenation + gets the multi-turn case wrong without any error. Verified against the HF + template output in tests/test_tokenizer_bytelevel.py. + + Deliberate deviations from the Jinja (each raises instead of silently differing): + tools / role "tool" / tool_calls -> NotImplementedError; a role outside + system/user/assistant -> ValueError (Jinja drops the message); non-str content + -> TypeError (Jinja renders ''); empty messages -> ValueError. + """ + if tools: + raise NotImplementedError("Qwen3 chat template with tools is not implemented") + if not messages: + raise ValueError("messages is empty") + for k, m in enumerate(messages): + role = m.get("role") + if role == "tool" or m.get("tool_calls"): + raise NotImplementedError("tool messages / tool_calls are not implemented") + if role not in ("system", "user", "assistant"): + raise ValueError(f"message {k}: unsupported role {role!r}") + if not isinstance(m.get("content"), str): + raise TypeError(f"message {k}: content must be str, got {type(m.get('content')).__name__}") + out: list[str] = [] + if messages[0]["role"] == "system": + out.append("<|im_start|>system\n" + messages[0]["content"] + "<|im_end|>\n") + last_query_index = len(messages) - 1 + for idx in range(len(messages) - 1, -1, -1): + c = messages[idx]["content"] + if messages[idx]["role"] == "user" and not (c.startswith("") and c.endswith("")): + last_query_index = idx + break + n = len(messages) + for idx, m in enumerate(messages): + role, content = m["role"], m["content"] + if role == "user" or (role == "system" and idx != 0): + out.append("<|im_start|>" + role + "\n" + content + "<|im_end|>\n") + elif role == "assistant": + reasoning = "" + rc = m.get("reasoning_content") + if isinstance(rc, str): + reasoning = rc + elif "" in content: + reasoning = content.split("")[0].rstrip("\n").split("")[-1].lstrip("\n") + content = content.split("")[-1].lstrip("\n") + is_last = idx == n - 1 + if idx > last_query_index and (is_last or reasoning): + out.append( + "<|im_start|>assistant\n\n" + reasoning.strip("\n") + "\n\n\n" + content.lstrip("\n") + ) + else: + out.append("<|im_start|>assistant\n" + content) + out.append("<|im_end|>\n") + if add_generation_prompt: + out.append("<|im_start|>assistant\n") + if enable_thinking is False: + out.append("\n\n\n\n") + return "".join(out) diff --git a/code/align/tokenizer/core.py b/code/align/tokenizer/core.py new file mode 100644 index 0000000000000000000000000000000000000000..8ffa76bf71cae3341d49e12c6ce78a55fa57cec5 --- /dev/null +++ b/code/align/tokenizer/core.py @@ -0,0 +1,615 @@ +"""Pure-Python (stdlib only) BPE tokenizer for Mistral-7B-v0.3. + +This is a from-scratch reimplementation of exactly the pipeline that +`tokenizers`/`transformers` run for the v0.3 `tokenizer.json`, and nothing +else. It exists so the training stack has zero dependency on `transformers` +(see docs/DEPENDENCY_POLICY.md); parity with the legacy stack is certified by +the `oracle`-marked test in tests/test_tokenizer.py (hundreds of strings, +ids AND decode byte-identical). + +Pipeline (encode): + + text + -> split on ADDED tokens (771: [INST] ... [control_N]), + leftmost-longest, raw text, BEFORE any BPE (_split_added) + -> per non-added segment: Metaspace pre-tokenizer (_metaspace) + ' ' -> U+2581, prepend U+2581 per prepend_scheme + -> BPE over the WHOLE segment (split=false => ONE "word") (_bpe) + chars not in vocab -> <0xNN> byte-fallback pieces + -> post-processor: prepend (id 1) iff add_special_tokens + +Decode: ids -> pieces, optionally drop special pieces, then the decoder chain +Replace(U+2581 -> ' ') / ByteFallback / Fuse / Strip(' ', start=1). + +The loader VALIDATES the pipeline configuration and raises +NotImplementedError on anything this module does not implement. A different +tokenizer.json must fail loudly, not silently encode wrong ids. +""" +from __future__ import annotations + +import heapq +import json +import os +import re +from typing import Iterable, Optional, Sequence, Union + +__all__ = ["Tokenizer", "load_tokenizer"] + +#: U+2581 LOWER ONE EIGHTH BLOCK, the SentencePiece "space" glyph. +_SP = "▁" +_HEX = frozenset("0123456789abcdefABCDEF") +#: Cap on the per-segment encode cache. With split=false a "word" is a whole +#: text segment, so the cache only pays off for short, repeated strings +#: (stop strings, role tags, "\n"); long segments are never cached. +_CACHE_MAX_ENTRIES = 50_000 +_CACHE_MAX_SEGMENT_CHARS = 128 + +_TOKENIZER_FILES = ("tokenizer.json", "tokenizer_config.json", "special_tokens_map.json") +#: Optional passthrough: AutoTokenizer on a LlamaTokenizer-class config wants it. +_OPTIONAL_FILES = ("tokenizer.model",) + + +def _content(tok) -> Optional[str]: + """HF configs store a special token as either a bare string or a dict + {"content": ...}; None means 'unset'.""" + if tok is None: + return None + if isinstance(tok, dict): + return tok.get("content") + return str(tok) + + +def _expect(cond: bool, what: str) -> None: + if not cond: + raise NotImplementedError( + f"tokenizer.json uses a configuration this pure-Python tokenizer does not " + f"implement: {what}. Refusing to load rather than silently encode wrong ids." + ) + + +class Tokenizer: + """Drop-in for the subset of the HF tokenizer API this repo calls. + + Build with `Tokenizer.from_pretrained(dir)` / `load_tokenizer(dir)`. + """ + + def __init__( + self, + tokenizer_json: dict, + tokenizer_config: Optional[dict] = None, + special_tokens_map: Optional[dict] = None, + *, + files: Optional[dict] = None, + ): + #: raw bytes of the source files, kept so save_pretrained is a true + #: copy-through that survives the source dir being pruned/rotated. + self._files: dict[str, bytes] = dict(files or {}) + self._config = dict(tokenizer_config or {}) + self._special_map = dict(special_tokens_map or {}) + self._tokenizer_json = tokenizer_json + self._validate_pipeline(tokenizer_json) + # transformers REBUILDS the Metaspace pre-tokenizer from the config's + # add_prefix_space (measured on 5.15: False changes the ids, while + # add_bos_token/add_eos_token are ignored by the tokenizer.json path). The + # pure-Python pipeline follows tokenizer.json only, so refuse loudly rather + # than silently disagree with the legacy stack. Every v0.3 config has True. + _expect( + self._config.get("add_prefix_space") is not False, + "tokenizer_config.json add_prefix_space=false", + ) + + model = tokenizer_json["model"] + vocab: dict[str, int] = dict(model["vocab"]) + + # -- added tokens: override/extend the model vocab, and are matched first. + added = list(tokenizer_json.get("added_tokens", [])) + self._added: dict[str, int] = {} + self._special_contents: set[str] = set() + for t in added: + _expect( + not (t.get("lstrip") or t.get("rstrip") or t.get("single_word")), + f"added token {t['content']!r} with lstrip/rstrip/single_word", + ) + vocab[t["content"]] = int(t["id"]) + self._added[t["content"]] = int(t["id"]) + if t.get("special"): + self._special_contents.add(t["content"]) + self._vocab = vocab + + size = max(vocab.values()) + 1 + self._id_to_token: list[Optional[str]] = [None] * size + for tok, i in vocab.items(): + self._id_to_token[i] = tok + self._base_vocab = model["vocab"] # the BPE model's own vocab (ids for symbols) + + # -- BPE tables. Merges may be [a, b] pairs (older saves) or "a b" strings. + self._ranks: dict[tuple[str, str], int] = {} + for rank, m in enumerate(model["merges"]): + a, b = (m[0], m[1]) if isinstance(m, (list, tuple)) else m.split(" ") + # Rust's BPE builder errors if the merge result is not in the vocab. + if (a + b) not in self._base_vocab or a not in self._base_vocab or b not in self._base_vocab: + raise ValueError(f"merge #{rank} {a!r}+{b!r} references a token outside the vocab") + # LAST duplicate wins: Rust collects merges into a HashMap, so a repeated + # pair keeps its final rank (measured against tokenizers 0.22). v0.3 has none. + self._ranks[(a, b)] = rank + self._byte_fallback = bool(model.get("byte_fallback")) + self._byte_pieces: list[Optional[str]] = [ + (f"<0x{b:02X}>" if f"<0x{b:02X}>" in self._base_vocab else None) for b in range(256) + ] + self._fuse_unk = bool(model.get("fuse_unk")) + self._model_unk = model.get("unk_token") + self._ignore_merges = bool(model.get("ignore_merges")) + self._cache: dict[str, tuple[int, ...]] = {} + + # -- added-token splitter. Alternation sorted longest-first == leftmost-longest. + if self._added: + alts = sorted(self._added, key=len, reverse=True) + self._added_re: Optional[re.Pattern] = re.compile("|".join(re.escape(a) for a in alts)) + else: + self._added_re = None + + # -- Metaspace + pt = tokenizer_json["pre_tokenizer"] + self._prepend_scheme = pt.get("prepend_scheme", "always" if pt.get("add_prefix_space", True) else "never") + + # -- special tokens (strings), resolved config -> special_tokens_map -> defaults + def pick(name: str, default: Optional[str] = None) -> Optional[str]: + v = _content(self._config.get(f"{name}_token")) + if v is None: + v = _content(self._special_map.get(f"{name}_token")) + if v is None: + v = default + return v if (v is None or v in self._vocab) else None + + self.bos_token = pick("bos", "") + self.eos_token = pick("eos", "") + self.unk_token = pick("unk", self._model_unk) + self.pad_token = pick("pad") # v0.3 ships none; callers fall back to eos + self._post_bos = self._post_processor_bos(tokenizer_json.get("post_processor")) + + # ------------------------------------------------------------------ config + + @staticmethod + def _validate_pipeline(tj: dict) -> None: + model = tj["model"] + _expect(model.get("type") == "BPE", f"model.type={model.get('type')!r}") + _expect(not model.get("dropout"), "BPE dropout") + _expect(not model.get("continuing_subword_prefix"), "continuing_subword_prefix") + _expect(not model.get("end_of_word_suffix"), "end_of_word_suffix") + _expect(tj.get("normalizer") is None, "a non-null normalizer") + pt = tj.get("pre_tokenizer") or {} + _expect(pt.get("type") == "Metaspace", f"pre_tokenizer {pt.get('type')!r}") + _expect(pt.get("replacement") == _SP, "Metaspace replacement other than U+2581") + _expect(pt.get("split") is False, "Metaspace split=true") + _expect( + pt.get("prepend_scheme", "always") in ("first", "always", "never"), + f"Metaspace prepend_scheme {pt.get('prepend_scheme')!r}", + ) + dec = tj.get("decoder") or {} + chain = dec.get("decoders") if dec.get("type") == "Sequence" else None + _expect(chain is not None and len(chain) == 4, "decoder other than the 4-step Sequence") + r, bf, fu, st = chain + _expect( + r.get("type") == "Replace" + and r.get("pattern") == {"String": _SP} + and r.get("content") == " ", + "decoder[0] other than Replace(U+2581 -> ' ')", + ) + _expect(bf.get("type") == "ByteFallback", "decoder[1] other than ByteFallback") + _expect(fu.get("type") == "Fuse", "decoder[2] other than Fuse") + _expect( + st.get("type") == "Strip" + and st.get("content") == " " + and st.get("start") == 1 + and st.get("stop") == 0, + "decoder[3] other than Strip(' ', start=1, stop=0)", + ) + + @staticmethod + def _post_processor_bos(pp: Optional[dict]) -> Optional[str]: + """The single-sequence template must be exactly [, A]; returns + that special token's content (the BOS), or None if there is no post-processor.""" + if pp is None: + return None + _expect(pp.get("type") == "TemplateProcessing", f"post_processor {pp.get('type')!r}") + single = pp.get("single", []) + _expect( + len(single) == 2 and "SpecialToken" in single[0] and "Sequence" in single[1], + "post_processor single template other than [SpecialToken, Sequence]", + ) + return single[0]["SpecialToken"]["id"] + + # --------------------------------------------------------------- id access + + @property + def bos_token_id(self) -> Optional[int]: + return self._vocab.get(self.bos_token) if self.bos_token is not None else None + + @property + def eos_token_id(self) -> Optional[int]: + return self._vocab.get(self.eos_token) if self.eos_token is not None else None + + @property + def pad_token_id(self) -> Optional[int]: + """None on v0.3 -- callers (align.data.encoding.pad_token_id) fall back to eos.""" + return self._vocab.get(self.pad_token) if self.pad_token is not None else None + + @property + def unk_token_id(self) -> Optional[int]: + return self._vocab.get(self.unk_token) if self.unk_token is not None else None + + @property + def vocab_size(self) -> int: + return len(self._base_vocab) + + @property + def all_special_tokens(self) -> list[str]: + return sorted(self._special_contents, key=lambda t: self._vocab[t]) + + @property + def all_special_ids(self) -> list[int]: + return [self._vocab[t] for t in self.all_special_tokens] + + def get_vocab(self) -> dict[str, int]: + return dict(self._vocab) + + def get_added_vocab(self) -> dict[str, int]: + return dict(self._added) + + def __len__(self) -> int: + return len(self._vocab) + + def __repr__(self) -> str: + return f"Tokenizer(n={len(self)}, merges={len(self._ranks)}, added={len(self._added)})" + + def convert_ids_to_tokens(self, ids: Union[int, Iterable[int]]): + """Pieces for ids; None for ids outside the vocab (HF returns None too).""" + if isinstance(ids, int): + return self._piece(ids) + return [self._piece(int(i)) for i in _as_list(ids)] + + def convert_tokens_to_ids(self, tokens: Union[str, Iterable[str]]): + """Ids for pieces; unknown pieces map to the unk id (HF behaviour).""" + unk = self.unk_token_id + if isinstance(tokens, str): + return self._vocab.get(tokens, unk) + return [self._vocab.get(t, unk) for t in tokens] + + def _piece(self, i: int) -> Optional[str]: + if i < 0: + raise ValueError(f"negative token id {i}: a label-mask value leaked into a token-id path") + return self._id_to_token[i] if i < len(self._id_to_token) else None + + # ------------------------------------------------------------------ encode + + def __call__(self, text: Union[str, Sequence[str]], add_special_tokens: bool = True) -> dict: + """{"input_ids": ...}. A list of strings gives a list of id lists. + Padding/truncation/tensors are deliberately NOT supported (TypeError on + unknown kwargs) -- callers pad their own batches.""" + if isinstance(text, str): + return {"input_ids": self.encode(text, add_special_tokens=add_special_tokens)} + return {"input_ids": [self.encode(t, add_special_tokens=add_special_tokens) for t in text]} + + def encode(self, text: str, add_special_tokens: bool = True) -> list[int]: + if not isinstance(text, str): + raise TypeError(f"encode() takes str, got {type(text).__name__}") + try: + text.encode("utf-8") + except UnicodeEncodeError as e: # lone surrogate: Rust strings cannot hold one + raise ValueError(f"text is not valid Unicode (lone surrogate at index {e.start})") from e + ids: list[int] = [] + if add_special_tokens and self._post_bos is not None: + ids.append(self._vocab[self._post_bos]) + for k, (is_added, seg) in enumerate(self._split_added(text)): + if is_added: + ids.append(self._added[seg]) + continue + piece = self._metaspace(seg, k == 0) + if piece: + ids.extend(self._bpe(piece)) + return ids + + def _split_added(self, text: str): + """Yield (is_added, substring). Added tokens are matched on the RAW text, + leftmost-longest, and are never fed to BPE (so nothing merges across them). + No empty segments are produced (matches HF: "" encodes to no tokens).""" + if self._added_re is None or not text: + if text: + yield False, text + return + pos = 0 + for m in self._added_re.finditer(text): + if m.start() > pos: + yield False, text[pos : m.start()] + yield True, m.group(0) + pos = m.end() + if pos < len(text): + yield False, text[pos:] + + def _metaspace(self, seg: str, is_first_split: bool) -> str: + """Metaspace(replacement=U+2581, prepend_scheme=..., split=false). + + ' ' -> U+2581 (ONLY the space char; '\\n' and '\\t' stay literal and later + byte-fall-back). prepend_scheme="first" prepends U+2581 only when this + segment is split #0 of the WHOLE input, i.e. the text does not begin with + an added token. Added-token splits are counted (they occupy an index) + but skip the pre-tokenizer, so a leading special token CONSUMES the + 'first' slot and nothing after it is ever prefixed: + "helloworld" -> ▁hello world + "hello" -> hello (bare 'hello', NO ▁ -- measured + against the legacy tokenizer) + A segment that already starts with U+2581 (leading space / literal U+2581) + gets no second prefix. 'always' prefixes every such segment; 'never' none.""" + s = seg.replace(" ", _SP) + scheme = self._prepend_scheme + if scheme == "never" or s.startswith(_SP): + return s + if scheme == "always" or is_first_split: + return _SP + s + return s + + def _bpe(self, word: str) -> tuple[int, ...]: + cached = self._cache.get(word) + if cached is not None: + return cached + vocab = self._base_vocab + if self._ignore_merges and word in vocab: + res = (vocab[word],) + else: + res = self._merge(self._initial_symbols(word)) + if len(word) <= _CACHE_MAX_SEGMENT_CHARS: + if len(self._cache) >= _CACHE_MAX_ENTRIES: + self._cache.clear() + self._cache[word] = res + return res + + def _initial_symbols(self, word: str) -> list[str]: + """One symbol per char if the char is a vocab piece; else its UTF-8 bytes + as <0xNN> pieces (byte_fallback); else (consecutive unks fuse). + + Mirrors the Rust `BPE::merge_word` loop INCLUDING a quirk: an unknown char + only records a PENDING unk, and the pending unk is flushed solely by the + next in-vocab char (or end of word). A byte-fallback expansion in between + neither flushes nor resets it, so the unk lands AFTER those byte pieces + (and, with fuse_unk, unks on both sides of a byte-fallback char fuse into + one). Unreachable for v0.3 (all 256 <0xNN> pieces exist, so the unk path + never fires), but the loader accepts other byte_fallback tables.""" + vocab = self._base_vocab + syms: list[str] = [] + unk = self._model_unk + pending_unk = False + for ch in word: + if ch in vocab: + if pending_unk: + syms.append(unk) # type: ignore[arg-type] + pending_unk = False + syms.append(ch) + continue + if self._byte_fallback: + pieces = [self._byte_pieces[b] for b in ch.encode("utf-8")] + if None not in pieces: + syms.extend(pieces) # type: ignore[arg-type] + continue # pending unk is deliberately left untouched (Rust parity) + if unk is not None: + if pending_unk and not self._fuse_unk: + syms.append(unk) + pending_unk = True + if pending_unk: + syms.append(unk) # type: ignore[arg-type] + return syms + + def _merge(self, syms: list[str]) -> tuple[int, ...]: + """Rank-ordered pair merging over a doubly linked list with a lazy-deletion + min-heap: O(n log n), so a multi-thousand-char segment (split=false makes + every text segment ONE word) is not quadratic. Tie-break is lowest rank, + then leftmost position -- identical to the Rust implementation.""" + n = len(syms) + vocab = self._base_vocab + if n < 2: + return tuple(vocab[s] for s in syms) + ranks = self._ranks + nxt = list(range(1, n + 1)) + nxt[-1] = -1 + prv = list(range(-1, n - 1)) + heap: list[tuple[int, int, str, str]] = [] + for i in range(n - 1): + r = ranks.get((syms[i], syms[i + 1])) + if r is not None: + heap.append((r, i, syms[i], syms[i + 1])) + heapq.heapify(heap) + pop, push = heapq.heappop, heapq.heappush + while heap: + _, i, left, right = pop(heap) + if syms[i] != left: # stale: left side was merged or absorbed (None) + continue + j = nxt[i] + if j == -1 or syms[j] != right: # stale: right neighbour changed + continue + new = left + right + syms[i] = new + syms[j] = None # type: ignore[call-overload] + nj = nxt[j] + nxt[i] = nj + if nj != -1: + prv[nj] = i + p = prv[i] + if p != -1: + r = ranks.get((syms[p], new)) + if r is not None: + push(heap, (r, p, syms[p], new)) + if nj != -1: + r = ranks.get((new, syms[nj])) + if r is not None: + push(heap, (r, i, new, syms[nj])) + out = [] + i = 0 + while i != -1: + out.append(vocab[syms[i]]) + i = nxt[i] + return tuple(out) + + # ------------------------------------------------------------------ decode + + def decode(self, ids, skip_special_tokens: bool = False) -> str: + """ids -> text. Default skip_special_tokens=False matches HF (callers that + want specials dropped, e.g. the inference engine, pass True explicitly). + + Ids outside the vocab are silently dropped (HF/Rust behaviour); negative + ids raise (they are masks that leaked, never tokens). + + Decoder chain, applied to the list of pieces: + Replace(U+2581 -> ' ') per piece; + ByteFallback: each maximal run of <0xNN> pieces is UTF-8 decoded as ONE + unit; an INVALID run becomes one U+FFFD **per byte** (Rust semantics, + not Python errors='replace', which collapses ill-formed subparts); + Fuse: concatenate; + Strip(' ', start=1): drop at most ONE leading space of the fused text. + The Strip is why decode([id_of('▁hello')]) == 'hello', not ' hello': a + chunk decoded in isolation loses its leading space. Never decode token + deltas and concatenate -- decode the whole sequence (the engine does). + """ + pieces: list[str] = [] + special = self._special_contents + for i in _as_list(ids): + t = self._piece(int(i)) + if t is None: + continue + if skip_special_tokens and t in special: + continue + pieces.append(t) + return self._decode_pieces(pieces) + + @staticmethod + def _decode_pieces(pieces: list[str]) -> str: + out: list[str] = [] + run = bytearray() + + def flush() -> None: + if run: + try: + out.append(run.decode("utf-8")) + except UnicodeDecodeError: + out.append("�" * len(run)) + run.clear() + + for p in pieces: + p = p.replace(_SP, " ") + if len(p) == 6 and p.startswith("<0x") and p.endswith(">") and p[3] in _HEX and p[4] in _HEX: + run.append(int(p[3:5], 16)) + else: + flush() + out.append(p) + flush() + text = "".join(out) # Fuse + return text[1:] if text.startswith(" ") else text # Strip(' ', start=1) + + # -------------------------------------------------------------------- save + + def save_pretrained(self, save_directory: str) -> tuple[str, ...]: + """Write tokenizer.json, tokenizer_config.json, special_tokens_map.json + (+ tokenizer.model if the source had one). Copy-through of the source + bytes when loaded from a dir; synthesized (HF-shaped) otherwise. Each file + is written to a sibling temp name then os.replace()d, so a kill mid-save + leaves the old file or the new file, never a torn one.""" + os.makedirs(save_directory, exist_ok=True) + files = dict(self._files) + if "tokenizer.json" not in files: + files["tokenizer.json"] = json.dumps(self._tokenizer_json, ensure_ascii=False).encode("utf-8") + if "tokenizer_config.json" not in files: + files["tokenizer_config.json"] = json.dumps(self._synth_config(), indent=2).encode("utf-8") + if "special_tokens_map.json" not in files: + files["special_tokens_map.json"] = json.dumps(self._synth_special_map(), indent=2).encode("utf-8") + written = [] + for name, blob in files.items(): + dst = os.path.join(save_directory, name) + tmp = dst + f".tmp.{os.getpid()}" + with open(tmp, "wb") as f: + f.write(blob) + f.flush() + os.fsync(f.fileno()) + os.replace(tmp, dst) + written.append(dst) + return tuple(written) + + def _synth_config(self) -> dict: + return { + "add_bos_token": self._post_bos is not None, + "add_eos_token": False, + "bos_token": self.bos_token, + "eos_token": self.eos_token, + "unk_token": self.unk_token, + "pad_token": self.pad_token, + "clean_up_tokenization_spaces": False, + "legacy": False, + "model_max_length": int(1e30), + "tokenizer_class": "LlamaTokenizer", + } + + def _synth_special_map(self) -> dict: + d = {} + for name in ("bos", "eos", "unk", "pad"): + tok = getattr(self, f"{name}_token") + if tok is not None: + d[f"{name}_token"] = { + "content": tok, + "lstrip": False, + "normalized": False, + "rstrip": False, + "single_word": False, + } + return d + + # -------------------------------------------------------------------- load + + @classmethod + def from_pretrained(cls, path: Union[str, os.PathLike]) -> "Tokenizer": + """Load from a directory holding tokenizer.json (a checkpoint dir, or an HF + snapshot dir), a path to a tokenizer.json, or an HF cache model dir + (`models--org--name`, newest snapshot with a tokenizer.json). LOCAL ONLY: + never touches the network, never downloads.""" + d = _resolve_dir(os.fspath(path)) + files: dict[str, bytes] = {} + for name in _TOKENIZER_FILES + _OPTIONAL_FILES: + p = os.path.join(d, name) + if os.path.isfile(p): + with open(p, "rb") as f: + files[name] = f.read() + tj = json.loads(files["tokenizer.json"]) + cfg = json.loads(files["tokenizer_config.json"]) if "tokenizer_config.json" in files else None + smap = json.loads(files["special_tokens_map.json"]) if "special_tokens_map.json" in files else None + return cls(tj, cfg, smap, files=files) + + +def _as_list(ids) -> list: + """Accept list/tuple/iterable, numpy arrays and torch tensors (via .tolist()).""" + if hasattr(ids, "tolist"): + ids = ids.tolist() + if isinstance(ids, int): + return [ids] + return list(ids) + + +def _resolve_dir(path: str) -> str: + if os.path.isfile(path) and os.path.basename(path) == "tokenizer.json": + return os.path.dirname(os.path.abspath(path)) + if os.path.isfile(os.path.join(path, "tokenizer.json")): + return path + snaps = os.path.join(path, "snapshots") + if os.path.isdir(snaps): + cands = [ + os.path.join(snaps, s) + for s in os.listdir(snaps) + if os.path.isfile(os.path.join(snaps, s, "tokenizer.json")) + ] + if cands: + return max(cands, key=os.path.getmtime) + raise FileNotFoundError( + f"no tokenizer.json at {path!r} (also tried {snaps!r}). align.tokenizer is " + "local-only by design: it never downloads. Pass a checkpoint dir or an HF " + "snapshot dir containing tokenizer.json." + ) + + +def load_tokenizer(path: Union[str, os.PathLike]) -> Tokenizer: + """Load a Tokenizer from a local dir/file. See Tokenizer.from_pretrained.""" + return Tokenizer.from_pretrained(path) diff --git a/code/align/train/__init__.py b/code/align/train/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d02b4166304de506f2f266bb80025f31daab3373 --- /dev/null +++ b/code/align/train/__init__.py @@ -0,0 +1,16 @@ +"""The distributed training core (section-07). + + * `offload_adamw.py` -- optimizer-state-only CPU offload; params and grads + stay on the training device, moments and the fp32 master live in host RAM. + * `fsdp.py` -- FSDP2 wrapping + mixed-precision policy, called from + the launch scripts, never from the Trainer. + * `trainer.py` -- the one Trainer for SFT and DPO: micro-step loop, + seeded lossless resume, optimizer-step scheduler, checkpoint cadence. + * `probes.py` -- trunk-movement probe, run-health tripwires, the + 20-step throughput probe. + * `sft_loss.py` -- adapter from a collated batch to section-05's + chunked fused CE. + +Every module here imports torch at module scope, so nothing above the resource +guards may import this package. +""" diff --git a/code/align/train/adamw8bit.py b/code/align/train/adamw8bit.py new file mode 100644 index 0000000000000000000000000000000000000000..3537b404be950dc5b89d6e005f8fcde68b6bfc48 --- /dev/null +++ b/code/align/train/adamw8bit.py @@ -0,0 +1,630 @@ +"""Block-wise 8-bit AdamW in pure torch: the optimizer that lets full-FT 7B launch. + +WHY THIS EXISTS (the arithmetic, from .tmp/handoff/review_trainer.md): every +shipped full-FT config names `optimizer.name = "adamw8bit"`, and the two +alternatives are both unlaunchable on this box at 7.248B params / 4 ranks: + + * fp32 AdamW on the device needs 14.5GB/rank of moments on top of a 9.6GB + activation peak against a 23GB A10G. + * `OffloadAdamW` pins the WHOLE rank master (n/world*4 B) while its staging + cap is two layer-shards (n/layers/world*4*2 B): required/cap = layers / + (world * shards) = 4, so it refuses to construct. Past that, its host RSS + projects to ~105GB against ~85GB MemAvailable, and the checkpoint clones + master + both moments (12 B/param). + +This optimizer keeps both Adam moments as uint8 codes ON THE DEVICE and has no +master copy at all. + +MEMORY BUDGET, per rank-local parameter element (block_size B = 2048): + + exp_avg 1 byte code + 4/B byte absmax = 1.00195 B + exp_avg_sq 1 byte code + 4/B byte absmax = 1.00195 B + ------------------------------------------------------------ + total 2 + 8/B = 2.0039 B/param (fp32 AdamW: 8; OffloadAdamW: 12 host) + + 7.248e9 params / 4 ranks = 1.812e9 elements/rank -> 3.63 GB (3.38 GiB)/rank + 14.5 GB across the job, all on the GPU, ZERO host RSS (which is what + `guard.projected_full_ft_rss_gb` already assumes for non-offload). + + Tensors below `min_8bit_size` (4096) elements -- norm scales, biases -- keep + fp32 moments (8 B/param); there are ~65 of them in a 32-layer Mistral and + they total well under a megabyte. The step additionally holds one CHUNK of + fp32 transients (default 2**21 elements, < 100MB), never a whole tensor. + `projected_state_bytes` computes the exact figure from element counts and is + what the launch banner prints. + +THE STEP, per chunk of whole blocks: dequantize both moments -> fp32 AdamW +update (decoupled weight decay, bias correction; the same op order as +`torch.optim.AdamW`'s single-tensor path, so the fp32 fallback is BIT-EXACT +against it) -> requantize -> store. The update uses the freshly computed +fp32 moments, not the requantized ones: the quantization error only enters +through the NEXT step's decayed moment, which is the same order bitsandbytes' +fused kernel uses (quantization is a storage format, not part of the rule). + +KNOWN LIMITATION, measured and bounded (not a bug to chase): SECOND-MOMENT +UNDERFLOW. v is a square, so its dynamic range is the SQUARE of the +gradient's. The smallest nonzero unsigned code is 3.25e-7 of the block absmax, +so an element whose gradient is < ~5e-4 of its block's largest one stores v = 0. +The update never divides by that stored zero (it uses the fresh fp32 moment, +see above), but the decayed history of v is lost for those elements: right +after a cold start a tiny-gradient element sees only (1-beta2)*g^2 instead of +the running average, so its step is up to lr / sqrt(1 - beta2) (4.5 lr at +beta2 = 0.95) instead of ~lr. Measured on a Gaussian-gradient linear layer: a +handful of elements (~0.1%) are off by ~1-2 lr on the second step and the mean +error over all elements is ~1% of the travel -- and that is a COLD-START / +CHANGING-GRADIENT picture. It does NOT relax for an element whose gradient +stays below the threshold: v is re-floored to 0 every step, so the over-step is +PERMANENT, and it GROWS with beta2 (adversarial review, constant g = 1e-4 of the +block max, 300 steps, travel vs torch.optim.AdamW: 3.9x at beta2 = 0.95, 9.9x at +0.999 and still rising toward 1/sqrt(1-beta2) = 31.6x; g = 1e-3 of the max is +1.07x, g = 1e-2 is 1.00x). Clamping every positive v up to the smallest nonzero +code would turn that into a bounded UNDER-step (0.16x, independent of beta2) at +the price of freezing those elements; that is a different optimizer, so it is +the owner's call (`.tmp/review_adamw8bit/probe3.py`), not made here. +bitsandbytes has the same property +(same map, same nearest-code rounding); the alternative of storing sqrt(v) +doubles the relative error of the denominator in exchange for the range, which +is a different optimizer than the one specified, so it is not done here. +`tests/test_adamw8bit.py::test_second_moment_underflow_...` pins the bound. + +NO MASTER COPY, AND WHAT THAT COSTS. The parameters are bf16 and the update is +tiny: at lr 1e-5 an update is ~1e-5 against a bf16 weight of ~2e-2 whose +spacing is 1.2e-4, so round-to-nearest drops almost every update -- a run +whose loss curve is flat and whose weights "never move" (the same +silent-no-train class as the ZeRO-3 + Adafactor incident). The fp32 master that +`OffloadAdamW` pays 4 B/param for exists to prevent exactly this. Here the +write-back to a bf16 parameter is STOCHASTIC ROUNDING by default: the fp32 +result is rounded up or down with probability proportional to proximity, so the +parameter moves by the right amount IN EXPECTATION. It is deterministic given +the seed, and its generator state is checkpointed, so resume stays bit-exact. +Pass `stochastic_rounding=False` for round-to-nearest (what bnb does). + +FSDP2 / DTENSOR (mirrors `OffloadAdamW`, same defect history): under +`fully_shard` the parameters are DTensors. AdamW is elementwise, so stepping +`param.to_local()` against the grad's local shard is EXACT; every access goes +through `_localize` (a storage-sharing view, so in-place updates reach the +DTensor). Numels are THIS RANK'S, never the global count. + +GLOBAL GRAD NORM (mirrors `OffloadAdamW._grad_norm`): the sum of squares is +all-reduced across ranks before the root, so `last_grad_norm` is the true +global norm, identical on every rank, and is recorded BEFORE clipping -- +the tripwires that read it must see an explosion, not its clipped image. +The same all-reduced value is the finiteness gate: a non-finite gradient on +ANY rank makes the global sum non-finite on EVERY rank, so all ranks skip +together with one collective instead of two. (In float64 the sum of squares +of finite fp32 values cannot overflow, so non-finite sum <=> non-finite grad.) + +RESUME: `state_dict()` is a snapshot of the uint8 codes, the absmax, the step +counts, the hyper-parameters and the rounding RNG, all cloned to CPU. Reloading +copies them back byte for byte, so a resumed run is bit-identical to an +uninterrupted one. The state is SHARD-shaped: it records `world_size` and +every tensor's element count and REFUSES a mismatched resume rather than +aligning rank r's moments to a different slice of the parameter. +""" + +from __future__ import annotations + +import logging +import math +from typing import Iterable, Optional, Sequence + +import torch + +from ..utils.dist import rank, world_size +from .offload_adamw import OffloadAdamW +from .quant8 import ( + codebook, + dequantize_rows, + quantize_rows, + zero_code, +) + +logger = logging.getLogger(__name__) + +STATE_FORMAT = "adamw8bit-blockwise-v1" +DEFAULT_BLOCK_SIZE = 2048 +#: bnb's `min_8bit_size`: below this a tensor's moments stay fp32. +DEFAULT_MIN_8BIT_SIZE = 4096 +#: Elements processed per fused dequant/update/requant pass (rounded down to +#: whole blocks). Bounds the fp32 transients; see the module docstring. +DEFAULT_CHUNK_ELEMS = 2**21 +_FP32_MAX = float(torch.finfo(torch.float32).max) + + +def adamw_update_( + p: torch.Tensor, + g: torch.Tensor, + m: torch.Tensor, + v: torch.Tensor, + *, + lr: float, + beta1: float, + beta2: float, + eps: float, + weight_decay: float, + step: int, +) -> None: + """One AdamW update on fp32 tensors, IN PLACE on `p`, `m`, `v`. + + The op sequence is `torch.optim.AdamW._single_tensor_adamw` verbatim + (decoupled decay first, `lerp_` for the first moment, `addcmul_` for the + second, bias-correction folded into step_size and the denominator). That + is what makes "fp32 fallback == torch AdamW" a property of the + construction: a reordering that is algebraically identical is NOT + bit-identical in fp32, and a test that tolerates 1e-6 would hide the day + someone swaps `lerp_` for a hand-written EMA. + """ + if weight_decay != 0: + p.mul_(1 - lr * weight_decay) + m.lerp_(g, 1 - beta1) + v.mul_(beta2).addcmul_(g, g, value=1 - beta2) + bias_correction1 = 1 - beta1**step + bias_correction2 = 1 - beta2**step + step_size = lr / bias_correction1 + bias_correction2_sqrt = bias_correction2**0.5 + denom = (v.sqrt() / bias_correction2_sqrt).add_(eps) + p.addcdiv_(m, denom, value=-step_size) + + +def stochastic_round_to_bf16(x: torch.Tensor, generator: Optional[torch.Generator]) -> torch.Tensor: + """fp32 -> bf16 with stochastic rounding (unbiased: E[out] == x). + + bf16 is exactly the top 16 bits of an fp32. Adding a uniform random + integer in [0, 2**16) to the raw bit pattern and truncating the low 16 bits + rounds UP with probability (low16 / 2**16) -- i.e. in proportion to how + close x is to the next representable value -- and an already-representable + x (low16 == 0) is returned unchanged. The add acts on magnitude for both + signs, because the sign is the top bit and the carry never reaches it for + finite inputs. Truncation back to bf16 is then exact (`.to(bfloat16)` of a + value whose low 16 bits are zero). + """ + x = x.contiguous() + noise = torch.randint( + 0, 1 << 16, x.shape, dtype=torch.int32, device=x.device, generator=generator + ) + bits = (x.view(torch.int32) + noise) & -65536 + return bits.view(torch.float32).to(torch.bfloat16) + + +class BlockwiseAdamW8bit: + """AdamW with block-wise 8-bit moments, stepping each rank's LOCAL shard. + + `step()` returns False when the grad-skip gate refused the step (same + contract as `OffloadAdamW`), True when it applied. + + Args: + params: the parameters (plain tensors or FSDP2 DTensors). Floating + point, contiguous locally, no duplicates. + lr, betas, eps, weight_decay: AdamW; decay is DECOUPLED (applied to + the weight, not folded into the gradient). + max_grad_norm: if set, gradients are scaled by + `min(1, max_grad_norm / (norm + 1e-6))` -- `clip_grad_norm_`'s rule + -- using the GLOBAL norm. `last_grad_norm` is the pre-clip norm. + The scale is applied inside the fused update; `p.grad` itself is + not rewritten (it is about to be zeroed, and rewriting a bf16 grad + in place would only add rounding). + block_size: elements per absmax block (default 2048). + min_8bit_size: tensors with fewer local elements keep fp32 moments. + chunk_elems: fp32-transient bound for the fused update. + stochastic_rounding: stochastic (default) vs nearest rounding when the + fp32 result is written back to a bf16 parameter. See module doc. + seed: base seed of the rounding RNG (offset by rank). + """ + + def __init__( + self, + params: Iterable[torch.Tensor], + lr: float, + betas: tuple[float, float] = (0.9, 0.95), + eps: float = 1e-8, + weight_decay: float = 0.0, + max_grad_norm: Optional[float] = None, + block_size: int = DEFAULT_BLOCK_SIZE, + min_8bit_size: int = DEFAULT_MIN_8BIT_SIZE, + chunk_elems: int = DEFAULT_CHUNK_ELEMS, + stochastic_rounding: bool = True, + seed: int = 0, + ) -> None: + self.params: list[torch.Tensor] = list(params) + if not self.params: + raise ValueError("BlockwiseAdamW8bit got an empty parameter list") + if len({id(p) for p in self.params}) != len(self.params): + raise ValueError( + "BlockwiseAdamW8bit got the same parameter object twice (tied weights?): " + "it would be stepped twice per step with one shared state slot" + ) + if not (isinstance(block_size, int) and block_size >= 1): + raise ValueError(f"block_size must be a positive int, got {block_size!r}") + if min_8bit_size < 0 or chunk_elems < 1: + raise ValueError("min_8bit_size must be >= 0 and chunk_elems >= 1") + if lr < 0 or eps <= 0 or weight_decay < 0: + raise ValueError(f"invalid AdamW hyper-parameters lr={lr} eps={eps} wd={weight_decay}") + if not (0.0 <= betas[0] < 1.0 and 0.0 <= betas[1] < 1.0): + raise ValueError(f"betas must be in [0, 1), got {betas}") + if max_grad_norm is not None and not max_grad_norm > 0: + raise ValueError(f"max_grad_norm must be positive or None, got {max_grad_norm}") + + self.block_size = block_size + self.min_8bit_size = min_8bit_size + self.chunk_blocks = max(1, chunk_elems // block_size) + self.stochastic_rounding = bool(stochastic_rounding) + self.seed = int(seed) + self.banner_tag = "adamw8bit" + self.skipped_steps = 0 + self.last_grad_norm = float("nan") + #: One group, like OffloadAdamW: `Trainer._apply_scheduled_lr` writes + #: the scheduled lr into every group, and `step` reads it from here. + self.param_groups = [ + { + "params": self.params, + "lr": float(lr), + "betas": (float(betas[0]), float(betas[1])), + "eps": float(eps), + "weight_decay": float(weight_decay), + "max_grad_norm": None if max_grad_norm is None else float(max_grad_norm), + } + ] + self._generators: dict[str, torch.Generator] = {} + + self._state: list[dict] = [] + for i, p in enumerate(self.params): + if not p.dtype.is_floating_point: + raise ValueError(f"param {i} has non-floating dtype {p.dtype}") + local = self._localize(p) + if not local.is_contiguous(): + raise ValueError( + f"param {i} (local shape {tuple(local.shape)}) is not contiguous: the " + "blockwise state is laid out over the flat local shard. FSDP2 dim-0 " + "shards are contiguous; a transposed/strided view is not supported." + ) + self._state.append(self._init_slot(local)) + + logger.info( + "BlockwiseAdamW8bit: %d tensors, %.2fM local elements, state %.3fGiB " + "(block %d, min_8bit_size %d, stochastic_rounding=%s)", + len(self.params), + sum(s["numel"] for s in self._state) / 1e6, + self.state_bytes() / 2**30, + block_size, + min_8bit_size, + self.stochastic_rounding, + ) + + # -- layout -------------------------------------------------------------- + + @staticmethod + def _localize(t): + """This rank's local shard of an FSDP2 DTensor (a storage-sharing + view), or `t` itself. Identical contract to OffloadAdamW._localize.""" + return t.to_local() if hasattr(t, "to_local") else t + + def _is_quantized(self, numel: int) -> bool: + return numel >= self.min_8bit_size and numel > 0 + + def _init_slot(self, local: torch.Tensor) -> dict: + n = local.numel() + dev = local.device + slot: dict = {"numel": n, "step": 0, "quantized": self._is_quantized(n)} + if slot["quantized"]: + nb = -(-n // self.block_size) + # Codes are allocated in WHOLE blocks (the last block is padded with + # the zero code) so every chunk is a clean [blocks, block_size] row + # matrix; the pad costs < one block per tensor. + slot["m_codes"] = torch.full( + (nb, self.block_size), zero_code(True), dtype=torch.uint8, device=dev + ) + slot["v_codes"] = torch.full( + (nb, self.block_size), zero_code(False), dtype=torch.uint8, device=dev + ) + slot["m_absmax"] = torch.zeros(nb, dtype=torch.float32, device=dev) + slot["v_absmax"] = torch.zeros(nb, dtype=torch.float32, device=dev) + else: + slot["m"] = torch.zeros(n, dtype=torch.float32, device=dev) + slot["v"] = torch.zeros(n, dtype=torch.float32, device=dev) + return slot + + @staticmethod + def projected_state_bytes( + local_numels: Sequence[int], + block_size: int = DEFAULT_BLOCK_SIZE, + min_8bit_size: int = DEFAULT_MIN_8BIT_SIZE, + ) -> int: + """Exact optimizer-state bytes for these RANK-LOCAL element counts. + + Large tensors: `2*n + 8*n/block_size` (two uint8 code arrays plus two + fp32 absmax arrays), with `n` rounded up to whole blocks because that + is how the codes are allocated. Small tensors: 8*n (two fp32 moments). + Computable BEFORE construction, so a launch banner or preflight can + state the number without allocating it. + """ + total = 0 + for n in local_numels: + if n >= min_8bit_size and n > 0: + nb = -(-n // block_size) + total += 2 * nb * block_size + 8 * nb + else: + total += 8 * n + return int(total) + + def state_bytes(self) -> int: + """Bytes actually held by this optimizer's state tensors on this rank.""" + total = 0 + for s in self._state: + for k, v in s.items(): + if isinstance(v, torch.Tensor): + total += v.numel() * v.element_size() + return total + + def describe_placement(self) -> dict: + """Where the state lives (device/dtype/bytes), for the banner and the + placement test -- a 'the state is 8-bit' claim nobody checks is how it + quietly stops being true.""" + ents = [] + for s in self._state: + for k, v in s.items(): + if isinstance(v, torch.Tensor): + ents.append( + {"key": k, "device": v.device.type, "dtype": str(v.dtype), + "bytes": v.numel() * v.element_size()} + ) + return {"state": ents, "state_bytes": self.state_bytes()} + + # -- rounding RNG -------------------------------------------------------- + + def _generator(self, device: torch.device) -> torch.Generator: + key = device.type + gen = self._generators.get(key) + if gen is None: + gen = torch.Generator(device=device) + gen.manual_seed(self.seed + rank()) + self._generators[key] = gen + return gen + + def _write_param(self, dst: torch.Tensor, src32: torch.Tensor) -> None: + """Write the fp32 result into the (possibly bf16) parameter chunk.""" + if dst.dtype == torch.float32: + if dst.data_ptr() != src32.data_ptr(): + dst.copy_(src32) + elif dst.dtype == torch.bfloat16 and self.stochastic_rounding: + dst.copy_(stochastic_round_to_bf16(src32, self._generator(dst.device))) + else: + dst.copy_(src32) + + # -- the step ------------------------------------------------------------ + + @torch.no_grad() + def step(self) -> bool: + """One optimizer step, or a refusal. + + Order is load-bearing: the (global) norm / finiteness verdict is reached + BEFORE any moment is touched, so a skipped step leaves the state + byte-identical. A discovered-too-late NaN would already have poisoned + the second moment, and every later step is scaled by it. + """ + grads = [None if p.grad is None else self._localize(p.grad) for p in self.params] + present = [g for g in grads if g is not None] + if not present: + raise RuntimeError( + "BlockwiseAdamW8bit.step() called with no gradients on any parameter. " + "A step that silently does nothing is indistinguishable from a run " + "that trained." + ) + for i, (g, s) in enumerate(zip(grads, self._state)): + if g is not None and g.numel() != s["numel"]: + raise ValueError( + f"param {i}: local grad has {g.numel()} elements but the state was " + f"built for {s['numel']} (grad of a different shard layout?)" + ) + + norm = OffloadAdamW._grad_norm(present) + if not math.isfinite(norm): + self.skipped_steps += 1 + # NaN, not 0.0: a 0.0 in the log reads as 'perfectly converged'. + self.last_grad_norm = float("nan") + logger.warning( + "grad-skip gate: non-finite gradient, skipping optimizer step " + "(%d skipped so far). Moments and step counts left untouched.", + self.skipped_steps, + ) + return False + self.last_grad_norm = norm # PRE-clip, on purpose + + group = self.param_groups[0] + coef = 1.0 + max_norm = group["max_grad_norm"] + if max_norm is not None: + coef = min(1.0, max_norm / (norm + 1e-6)) + + for p, g, st in zip(self.params, grads, self._state): + if g is None or st["numel"] == 0: + continue + st["step"] += 1 + local = self._localize(p).detach().view(-1) + gflat = g.detach().reshape(-1) + if st["quantized"]: + self._step_quantized(local, gflat, st, group, coef) + else: + self._step_fp32(local, gflat, st, group, coef) + return True + + def _hyper(self, group: dict, st: dict) -> dict: + return dict( + lr=group["lr"], + beta1=group["betas"][0], + beta2=group["betas"][1], + eps=group["eps"], + weight_decay=group["weight_decay"], + step=st["step"], + ) + + def _step_fp32(self, pflat, gflat, st, group, coef) -> None: + g32 = gflat.to(torch.float32) + if coef < 1.0: + g32 = g32 * coef # out of place: g32 may alias the live .grad + p32 = pflat.to(torch.float32) # aliases pflat when it is already fp32 + adamw_update_(p32, g32, st["m"], st["v"], **self._hyper(group, st)) + self._write_param(pflat, p32) + + def _step_quantized(self, pflat, gflat, st, group, coef) -> None: + B = self.block_size + n = st["numel"] + n_blocks = st["m_codes"].shape[0] + cb_m = codebook(True, pflat.device) + cb_v = codebook(False, pflat.device) + hyper = self._hyper(group, st) + for b0 in range(0, n_blocks, self.chunk_blocks): + b1 = min(n_blocks, b0 + self.chunk_blocks) + lo, hi = b0 * B, min(n, b1 * B) + ln = hi - lo + g32 = gflat[lo:hi].to(torch.float32) + if coef < 1.0: + g32 = g32 * coef + m_full = dequantize_rows(st["m_codes"][b0:b1], st["m_absmax"][b0:b1], cb_m).view(-1) + v_full = dequantize_rows(st["v_codes"][b0:b1], st["v_absmax"][b0:b1], cb_v).view(-1) + pchunk = pflat[lo:hi] + p32 = pchunk.to(torch.float32) + # [:ln] are views of the block-padded buffers: the pad tail is never + # touched by the update (it stays exactly 0), then the whole padded + # rows are requantized. + adamw_update_(p32, g32, m_full[:ln], v_full[:ln], **hyper) + self._write_param(pchunk, p32) + # THE V-OVERFLOW POISON (adversarial review, 2026-10-12). The finiteness + # gate in `step` tests the NORM, which is accumulated in float64 and so + # stays finite for a gradient the fp32 SQUARE cannot hold: one element of + # 1e21 gives v = (1-beta2)*g^2 = inf. torch.optim.AdamW survives that + # (m / (inf + eps) == 0), but here inf becomes the block's absmax, the + # requantize divides inf/inf = NaN, the NaN lands in the uint8 codes, + # and the block's weights go NaN on the NEXT step, with the gate seeing + # only finite gradients. Clamping v to the largest finite fp32 keeps the + # update identical (m / 1.8e19 is still 0 for any sane m) and the stored + # state finite. Only v can overflow: m is a convex mix of finite values. + v_full.clamp_(max=_FP32_MAX) + codes, absmax = quantize_rows(m_full.view(-1, B), cb_m) + st["m_codes"][b0:b1] = codes + st["m_absmax"][b0:b1] = absmax + codes, absmax = quantize_rows(v_full.view(-1, B), cb_v) + st["v_codes"][b0:b1] = codes + st["v_absmax"][b0:b1] = absmax + + def zero_grad(self, set_to_none: bool = True) -> None: + for p in self.params: + if set_to_none: + p.grad = None + elif p.grad is not None: + p.grad.zero_() + + # -- resume -------------------------------------------------------------- + + def state_dict(self) -> dict: + """A DETACHED CPU COPY of everything the next step depends on. + + `.to("cpu", copy=True)`, not `.to("cpu")`: on a CPU tensor the latter + returns the SAME object, and a "snapshot" that aliases the live codes + is mutated by the very next step -- the shared-state aliasing incident + OffloadAdamW documents, here with uint8 codes that no comparison would + flag as drifting. Everything is copied so the dict is safe to pickle + straight into the checkpoint gather. + """ + slots = [] + for s in self._state: + slots.append( + { + k: (v.detach().to("cpu", copy=True) if isinstance(v, torch.Tensor) else v) + for k, v in s.items() + } + ) + group = self.param_groups[0] + return { + "format": STATE_FORMAT, + "world_size": world_size(), + "block_size": self.block_size, + "min_8bit_size": self.min_8bit_size, + "stochastic_rounding": self.stochastic_rounding, + "param_group": {k: v for k, v in group.items() if k != "params"}, + "state": slots, + "skipped_steps": self.skipped_steps, + "last_grad_norm": self.last_grad_norm, + "sr_rng": {k: g.get_state().clone() for k, g in self._generators.items()}, + } + + def load_state_dict(self, sd: dict) -> None: + """Restore the state byte for byte. Validates EVERYTHING before writing + anything, so a refused load leaves the optimizer exactly as it was.""" + if sd.get("format") != STATE_FORMAT: + raise ValueError( + f"optimizer state format {sd.get('format')!r} is not {STATE_FORMAT!r}; " + "refusing to interpret it (a 32-bit or bnb state is not loadable here)" + ) + saved_ws, now_ws = sd.get("world_size"), world_size() + if saved_ws is not None and saved_ws != now_ws: + raise ValueError( + f"this optimizer state was saved at world_size={saved_ws} but the current " + f"run has world_size={now_ws}. The 8-bit moments are SHARD-shaped: loading " + "them under a different world size would align each rank's state to a " + "different slice of the parameter, and training would continue plausibly " + "on corrupted state. Resume at the original world size, or start fresh." + ) + if sd["block_size"] != self.block_size or sd["min_8bit_size"] != self.min_8bit_size: + raise ValueError( + f"state was built with block_size={sd['block_size']}, min_8bit_size=" + f"{sd['min_8bit_size']} but this optimizer has {self.block_size}, " + f"{self.min_8bit_size}: the absmax blocks would not line up" + ) + saved = sd["state"] + if len(saved) != len(self._state): + raise ValueError( + f"checkpoint holds {len(saved)} tensors but this optimizer has {len(self._state)}" + ) + for i, (cur, new) in enumerate(zip(self._state, saved)): + if cur["numel"] != new["numel"] or cur["quantized"] != new["quantized"]: + raise ValueError( + f"tensor {i}: checkpoint has numel={new['numel']} quantized=" + f"{new['quantized']}, this optimizer has numel={cur['numel']} quantized=" + f"{cur['quantized']} (a different shard layout)" + ) + for k, v in cur.items(): + if isinstance(v, torch.Tensor): + nv = new.get(k) + if nv is None or nv.shape != v.shape or nv.dtype != v.dtype: + raise ValueError( + f"tensor {i} field {k!r}: checkpoint " + f"{None if nv is None else (tuple(nv.shape), nv.dtype)} vs " + f"expected {(tuple(v.shape), v.dtype)}" + ) + if bool(sd.get("stochastic_rounding", self.stochastic_rounding)) != self.stochastic_rounding: + logger.warning( + "resuming with stochastic_rounding=%s but the checkpoint was written with %s: " + "the trajectory will differ from an uninterrupted run", + self.stochastic_rounding, + sd.get("stochastic_rounding"), + ) + + # The rounding RNG is part of the state being restored. A generator that + # already exists here (this optimizer has stepped) and is ABSENT from `sd` + # (saved before any bf16 step, or from a fp32 run) would otherwise keep its + # advanced stream, and the rewound optimizer would round differently from an + # uninterrupted one -- "byte for byte" quietly untrue (adversarial review, + # 2026-10-12). Dropping them re-seeds lazily from `seed + rank`, which is + # exactly the state a never-stepped optimizer has. + self._generators.clear() + + # copy_ INTO the existing tensors: keeps their device, and means loading + # one checkpoint dict into two optimizers cannot make them share state. + for cur, new in zip(self._state, saved): + for k, v in cur.items(): + if isinstance(v, torch.Tensor): + v.copy_(new[k]) + cur["step"] = int(new["step"]) + group = self.param_groups[0] + for k, v in sd["param_group"].items(): + group[k] = tuple(v) if k == "betas" else v + self.skipped_steps = int(sd.get("skipped_steps", 0)) + self.last_grad_norm = float(sd.get("last_grad_norm", float("nan"))) + for key, st in sd.get("sr_rng", {}).items(): + first = self.params[0].device + gen = self._generator(first if first.type == key else torch.device(key)) + gen.set_state(st.detach().to("cpu", copy=True)) + + +#: The name the factory and docs use. +AdamW8bit = BlockwiseAdamW8bit diff --git a/code/align/train/ckpt_format.py b/code/align/train/ckpt_format.py new file mode 100644 index 0000000000000000000000000000000000000000..073e77124d29b0ec55cb3cd469d869fcb65b86a1 --- /dev/null +++ b/code/align/train/ckpt_format.py @@ -0,0 +1,124 @@ +"""Weight-file formats the Trainer can write and read: the model-family seam. + +Why this exists. `Trainer.save_checkpoint` / `resume_from` called the dense +Mistral converters (`save_nmo_as_hf`, `hf_to_nmo(expected_n_layers= +cfg.model.n_layers)`) directly. Those tables know the 7B dense key names and +nothing about routers or stacked 3-D expert tensors, so an OLMoE run could be +built and stepped but never checkpointed -- the first save would raise on a +key it cannot map (or, worse for a model family added later, silently drop +parameters if a converter ever became lenient). The seam makes the family an +explicit, injected choice with ONE contract: + + save_weights(align_state_dict, out_dir, dtype) -> writes model weights + + config.json, atomically + load_weights(path) -> align state dict + +and nothing else about the checkpoint changes: optimizer state, `resume.pt`, +fsync/rename/completeness all stay in the Trainer and are family-independent. + +The default is the dense format built from `cfg.model`, so every existing +caller is unchanged. A family is selected by construction (`Trainer(..., +weight_format=OlmoeFormat(olmoe_cfg))`), never sniffed from the state dict: +guessing the family from key names is how a misconfigured run loads the wrong +converter and half-works. +""" + +from __future__ import annotations + +from typing import Any, Mapping, Optional, Protocol + +import torch + + +class WeightFormat(Protocol): + def save_weights( + self, state: Mapping[str, torch.Tensor], out_dir: str, dtype: Optional[torch.dtype] + ) -> None: ... + + def load_weights(self, path: str) -> dict[str, torch.Tensor]: ... + + def copy_tokenizer(self, snapshot: str, dst_dir: str) -> list[str]: + """Copy the tokenizer files that belong to THIS family into `dst_dir`; + return the names copied (empty = weights-only checkpoint).""" + ... + + +class DenseFormat: + """The original behaviour: dense Mistral-family HF checkpoints.""" + + def __init__(self, model_cfg: Any): + self.model_cfg = model_cfg + + def save_weights(self, state, out_dir, dtype): + from ..model import checkpoint as ckpt + + ckpt.save_nmo_as_hf(dict(state), self.model_cfg, out_dir, dtype=dtype) + + def load_weights(self, path): + from ..model import checkpoint as ckpt + + return ckpt.hf_to_nmo( + ckpt.load_hf_safetensors(path), expected_n_layers=self.model_cfg.n_layers + ) + + def copy_tokenizer(self, snapshot, dst_dir): + from ..model import checkpoint as ckpt + + return ckpt.copy_tokenizer_files(snapshot, dst_dir) + + +#: Files that make up an HF tokenizer, in either of the layouts OLMoE-class +#: models ship (BPE `tokenizer.json`, or `vocab.json` + `merges.txt`). +OLMOE_TOKENIZER_FILES = ( + "tokenizer.json", + "tokenizer_config.json", + "special_tokens_map.json", + "vocab.json", + "merges.txt", + "tokenizer.model", + "generation_config.json", +) + + +class OlmoeFormat: + """OLMoE-architecture checkpoints (routers + stacked experts), HF-compatible. + + TOKENIZER. The dense path copies the pinned Mistral v0.3 tokenizer into + every checkpoint (same vocab by construction); doing that for an OLMoE + checkpoint would stamp a 32768-token tokenizer onto a 50304-token model -- + loads fine, tokenizes wrong. So this format copies tokenizer files only + from an EXPLICIT `tokenizer_dir`, and without one writes a weights-only + checkpoint (and says so), never a guess. + """ + + def __init__(self, olmoe_cfg: Any, tokenizer_dir: Optional[str] = None): + self.olmoe_cfg = olmoe_cfg + self.tokenizer_dir = tokenizer_dir + + def save_weights(self, state, out_dir, dtype): + from ..model.olmoe_checkpoint import save_olmoe_as_hf + + save_olmoe_as_hf(dict(state), self.olmoe_cfg, out_dir, dtype=dtype) + + def load_weights(self, path): + from ..model.olmoe_checkpoint import hf_to_align + from ..model.checkpoint import load_hf_safetensors + + return hf_to_align(load_hf_safetensors(path), self.olmoe_cfg) + + def copy_tokenizer(self, snapshot, dst_dir): # noqa: ARG002 -- the dense snapshot is not ours + import os + import shutil + + if not self.tokenizer_dir: + return [] + copied = [] + for name in OLMOE_TOKENIZER_FILES: + src = os.path.join(self.tokenizer_dir, name) + if os.path.isfile(src): + shutil.copyfile(src, os.path.join(dst_dir, name)) + copied.append(name) + return copied + + +__all__ = ["WeightFormat", "DenseFormat", "OlmoeFormat"] diff --git a/code/align/train/dpo_loss.py b/code/align/train/dpo_loss.py new file mode 100644 index 0000000000000000000000000000000000000000..e61d4c9e690b170a9d6b947677f8141ba8b711ab --- /dev/null +++ b/code/align/train/dpo_loss.py @@ -0,0 +1,237 @@ +"""DPO loss adapter: paired batch -> section-05's chunked fused DPO loss. + +Mirror of `sft_loss.py`: this module owns plumbing only -- unpacking the paired +batch, the caller-side label shift, and packaging metrics -- while the kernel in +`align.kernels.fused_dpo` owns the objective. + +The one thing worth stating here rather than in the kernel: the reference +log-probabilities arrive as PRECOMPUTED CONSTANTS, produced offline by +section-12 in a single no-grad pass over the SFT checkpoint. There is no +reference model resident at DPO time, which is what makes 7B DPO fit on 4x A10G +at all. The kernel detaches them on entry and a test proves no gradient path +survives; this adapter's job is simply never to build one, so it refuses a +batch that does not carry them rather than silently substituting zeros -- a +zero reference turns DPO into plain likelihood maximisation on the chosen side, +which trains, converges, and is not DPO. + +`DpoLossConfig` is the trainer-facing default surface. Note `token_chunk_size`: +the pre-registered config is micro_batch 1 x seq 1024, i.e. ONE pair per step, +and at one pair the pair-chunking does nothing at all. Leaving it None there +would silently restore the [1024, 32768] logit tensor the fused loss exists to +remove, so the trainer-facing default sets it. +""" + +from __future__ import annotations + +import logging +from dataclasses import dataclass +from typing import Any, Optional + +import torch + +from .trainer import LossOutput + +logger = logging.getLogger(__name__) + +#: Section-05's kernel module, named so the both-directions test can block the +#: import and exercise the refusal branch (same pattern as `sft_loss`). +FUSED_DPO_MODULE = "align.kernels.fused_dpo" + +#: Fallback only; the authority is the kernel's constant and section-03's +#: collator, which both use -100. +IGNORE_INDEX = -100 + + +@dataclass +class DpoLossConfig: + """Trainer-facing DPO loss settings. Section-12 nests this in its stage + config; every default that encodes a decision says why.""" + + #: Preference sharpness. 0.1 is the pre-registered value for both arms. + beta: float = 0.1 + #: One of align.kernels.fused_dpo.DPO_VARIANTS. `dpop` is the pre-registered + #: tripwire RESPONSE for logps/chosen declining while the margin rises; it + #: is not the primary configuration and switching to it is a documented + #: deviation, not a tuning knob. + variant: str = "sigmoid" + #: Pairs per chunk. + chunk_size: int = 1 + #: Tokens per inner chunk. NOT None: at micro_batch 1 there is one pair per + #: step and pair-chunking alone would materialise the full logit tensor. + #: 128 rather than 256, DERIVED from `fused_ce.chunked_peak_bound` at the + #: 7B shapes (V 32768, H 4096, 2x1024 rows): 256 predicts a 192 MiB peak + #: against a 256 MiB budget (0.75, too tight to survive an allocator + #: fluctuation in the M5 smoke), while 128 predicts 128 MiB (0.50). The + #: matmul is still large enough to be efficient at 128 x 32768. + token_chunk_size: Optional[int] = 128 + #: NLL auxiliary on the chosen completion. 0.0 is provably inert (the term + #: is skipped structurally, not multiplied by zero), so the primary + #: pre-registered run is unaffected by this field existing. + nll_coeff: float = 0.0 + #: DPO-Positive penalty weight; read only when variant == "dpop". + dpop_lambda: float = 50.0 + + +def _load_fused(): + try: + import importlib + + return importlib.import_module(FUSED_DPO_MODULE) + except Exception: # noqa: BLE001 + return None + + +def fused_dpo_available() -> bool: + return _load_fused() is not None + + +def _unpack(batch: Any): + """Accept a paired batch object or a mapping. Six tensors are mandatory and + none of them has a defensible default.""" + required = ( + "input_ids_chosen", + "labels_chosen", + "input_ids_rejected", + "labels_rejected", + "ref_logp_chosen", + "ref_logp_rejected", + ) + if isinstance(batch, dict): + got = {k: batch.get(k) for k in required} + else: + got = {k: getattr(batch, k, None) for k in required} + missing = [k for k, v in got.items() if v is None] + if missing: + raise TypeError( + f"DPO batch is missing {missing}. The reference log-probabilities " + "in particular have no default: substituting zeros would turn DPO " + "into likelihood maximisation on the chosen completion, which " + "trains and converges and is not DPO. Section-12's " + "precompute step produces them." + ) + return got + + +def make_dpo_loss_adapter( + config: Optional[DpoLossConfig] = None, + require_fused: bool = False, + decoupled_backward: bool = False, + grad_scale: float = 1.0, +): + """Build the DPO loss adapter the Trainer calls once per micro-step. + + `require_fused=True` refuses the reference path, which is what the 7B stage + scripts pass: the eager reference materialises BOTH [P, T, 32768] logit + tensors and is a memory profile no A10G survives at 7B. + + `decoupled_backward=True` (the 7B stage setting) backwards each side's + trunk separately so both checkpointed graphs are never resident at once; + `grad_scale` must then be 1/grad_accum, matching the scaling the Trainer + applies to the loss it backwards. + """ + cfg = config or DpoLossConfig() + module = _load_fused() + if module is None: + if require_fused: + raise RuntimeError( + f"the fused chunked DPO loss ({FUSED_DPO_MODULE}." + "fused_dpo_loss) is not importable. Refusing to fall back to " + "the reference path for a full-scale run: it materialises both " + "[P, T, 32768] logit tensors and their gradients." + ) + raise RuntimeError( + f"{FUSED_DPO_MODULE} is not importable and there is no reference " + "fallback worth offering for DPO at any useful scale." + ) + if cfg.variant not in module.DPO_VARIANTS: + raise ValueError(f"unknown DPO variant {cfg.variant!r}; known: {list(module.DPO_VARIANTS)}") + ignore_index = module.IGNORE_INDEX + + def _kernel(h_c, h_r, w, got, target_c, target_r): + return module.fused_dpo_loss( + h_c, + h_r, + w, + target_c, + target_r, + got["ref_logp_chosen"], + got["ref_logp_rejected"], + beta=cfg.beta, + variant=cfg.variant, + chunk_size=cfg.chunk_size, + nll_coeff=cfg.nll_coeff, + dpop_lambda=cfg.dpop_lambda, + ignore_index=ignore_index, + token_chunk_size=cfg.token_chunk_size, + ) + + def _full_w(model): + # FSDP2 params are sharded DTensors OUTSIDE a module __call__; passing + # one into the fused kernel's mm mixes Tensor and DTensor (the + # hook-bypass class, DPO edition). full_tensor() is the DIFFERENTIABLE + # all-gather: backward reduce-scatters d_weight onto the shards. + w = model.lm_head.weight + return w.full_tensor() if hasattr(w, "full_tensor") else w + + def adapter(model, batch) -> LossOutput: + got = _unpack(batch) + # Caller-shifted, exactly as in sft_loss: position t predicts t+1. + target_c = got["labels_chosen"][:, 1:] + target_r = got["labels_rejected"][:, 1:] + + if not decoupled_backward: + hidden_c = model.forward_hidden_states(input_ids=got["input_ids_chosen"])[:, :-1] + hidden_r = model.forward_hidden_states(input_ids=got["input_ids_rejected"])[:, :-1] + loss, metrics = _kernel(hidden_c, hidden_r, _full_w(model), got, target_c, target_r) + module.require_metrics(metrics) + n_tokens = int((target_c != ignore_index).sum() + (target_r != ignore_index).sum()) + return LossOutput(loss=loss, n_tokens=n_tokens, metrics=dict(metrics)) + + # DECOUPLED BACKWARD -- one trunk graph at a time. Holding BOTH + # sides' checkpointed 7B graphs plus fp32 shard gradients peaked at + # 21.5GB and OOM'd every rank (measured; batch-size independent). + # DPO's coupling between the sides is one scalar per pair, so: + # 1. no-grad trunk forwards; the kernel runs over LEAF copies of + # the hiddens plus the gathered lm_head, and one backward on + # that small graph yields d_hidden per side analytically and + # accumulates the lm_head shard grad; + # 2. each side then re-forwards WITH grad and backwards against + # its saved d_hidden -- never two trunk graphs at once. + # The re-forward recomputes hiddens that differ from the no-grad + # pass only by kernel-dispatch noise (~1e-7 relative, the same class + # the batch-invariance receipt records); act-ckpt already relies on + # this determinism. The trainer's `(loss/accum).backward()` contract + # is honoured with a detached leaf proxy; the REAL grads are scaled + # here by grad_scale (1/accum), so nothing is double-counted. + with torch.no_grad(): + h_c0 = model.forward_hidden_states(input_ids=got["input_ids_chosen"])[:, :-1] + h_r0 = model.forward_hidden_states(input_ids=got["input_ids_rejected"])[:, :-1] + h_c = h_c0.detach().requires_grad_(True) + h_r = h_r0.detach().requires_grad_(True) + loss, metrics = _kernel(h_c, h_r, _full_w(model), got, target_c, target_r) + module.require_metrics(metrics) + (loss * grad_scale).backward() + g_c, g_r = h_c.grad, h_r.grad + if g_c is None or g_r is None: + raise RuntimeError( + "decoupled DPO backward produced no hidden gradients; the " + "kernel did not differentiate w.r.t. the hidden leaves" + ) + del h_c, h_r, h_c0, h_r0 + + hc = model.forward_hidden_states(input_ids=got["input_ids_chosen"])[:, :-1] + hc.backward(gradient=g_c) + del hc, g_c + hr = model.forward_hidden_states(input_ids=got["input_ids_rejected"])[:, :-1] + hr.backward(gradient=g_r) + del hr, g_r + + n_tokens = int((target_c != ignore_index).sum() + (target_r != ignore_index).sum()) + # Leaf proxy: the trainer's (loss/accum).backward() runs on THIS and + # touches no model gradient; the value is the real loss for the log. + proxy = loss.detach().clone().requires_grad_(True) + return LossOutput(loss=proxy, n_tokens=n_tokens, metrics=dict(metrics)) + + adapter.uses_fused = True + adapter.config = cfg + return adapter diff --git a/code/align/train/dpo_stage.py b/code/align/train/dpo_stage.py new file mode 100644 index 0000000000000000000000000000000000000000..706d7d3fbd03b5b770f89ce88bd0dbb868a5e639 --- /dev/null +++ b/code/align/train/dpo_stage.py @@ -0,0 +1,1362 @@ +"""DPO stage: config, entry gates, banner, tripwire response, arm manifest. + +Section-12 is the second and last GPU training stage, run as TWO +pre-registered arms. Everything numerical belongs to other sections -- the +objective is section-05's `fused_dpo`, the loop is section-07's `Trainer`, the +tripwire DETECTORS are section-07's `probes.py`, the reference constants are +`ref_cache.py`. What lives here is the part that decides whether a run is +allowed to start and what its result is permitted to be. + +That sounds like bureaucracy and is not. The predecessor project's expensive +failures were never wrong arithmetic; they were runs that completed, produced +publishable-looking numbers, and measured something other than what was +claimed. So: + + * **Entry gates run in a fixed order and any failure blocks everything + after it, including the model load.** Ordered by cost, so a stage that was + never going to be valid dies in milliseconds instead of after putting + 14.5 GB onto a shared no-swap box. + * **The tripwire response is pre-registered.** `logps/chosen` declining + while the margin rises is the DPO chosen-likelihood-collapse mode, and it + is *maximal for Arm B by design*: pi_SFT already assigns the chosen + continuations high likelihood, so the optimizer's cheapest margin comes + from crushing both logprobs. The response -- rerun with `dpop` or the NLL + auxiliary, and record THAT as the arm's result -- was written down before + any run, and no third configuration is reachable without a new + pre-registration. + * **The primary metrics are margin and held-out preference accuracy**, not + benchmark accuracy. The pre-registered behavioural expectations are Arm A + within +-2 pp of SFT (below floor is the EXPECTED outcome) and Arm B's + honest range INCLUDING ZERO. Section-13 owns the paired benchmark + evaluation; a stage that graded itself on benchmarks would be choosing its + own success criterion after seeing the data. +""" + +from __future__ import annotations + +import collections +import json +import logging +import math +import os +from dataclasses import dataclass, field, fields, replace +from typing import Any, Callable, Mapping, Optional, Sequence + +logger = logging.getLogger(__name__) + +NAN = float("nan") + +#: Entry gates, in the order they run. Ordered by COST: the cheap file reads +#: come first so an invalid stage fails before it touches a GPU. Data, so the +#: test iterates it instead of copying a list. +GATE_ORDER: tuple[str, ...] = ( + "sft_quality_gate", # section-11 ran and passed its own gate + "build_manifest", # shard counts match the pinned values; Arm A DESCOPED + "ref_cache_key", # the reference constants belong to THIS run + "path_bias", # measured, and its decision honored + "throughput_probe", # 20 steps -> banner wall-clock (never asserted ahead) + "rss_preflight", # host RSS headroom for the full-FT job class +) + +#: Banner keys this stage adds on top of `registry.MANDATORY_BANNER_KEYS`. +#: +#: Deliberately NOT registered into the global registry at import time. +#: `registry.register_mandatory_key` mutates a module-level list shared by +#: every script in the process; importing this module would then make an +#: unrelated banner (trace, generate) incomplete. The contract is identical -- +#: a missing key raises, a partial banner never prints -- it is just enforced +#: without a global side effect. +DPO_BANNER_KEYS: tuple[str, ...] = ( + "arm", + "loss_type", + "beta", + "variant", + "lr", + "epochs", + "global_batch", + "grad_accum", + "expected_pairs", + "optimizer_step_formula", + "scheduler_horizon_optimizer_steps", + "dataset_hashes", + "ref_cache_key", + "path_bias", + "probe_step_time_s", + "probe_derived_wall_clock_h", + "rss_budget", + "attention_backend", + "length_drift_baseline", + "length_drift_baseline_source", + "sft_checkpoint", + "pre_registration", +) + +#: The only configurations the pre-registration permits when the +#: chosen-logprob tripwire fires. Anything else requires a new dated entry in +#: docs/RESULTS.md written BEFORE the rerun, not after seeing it. +#: +#: `dpop_nll_aux` is the default because it is what the frozen +#: pre-registration literally says: "rerun THAT arm once with dpop + NLL +#: auxiliary". The section-12 spec phrases the same response as "the `dpop` +#: variant OR the NLL auxiliary", so the two single-knob forms are kept +#: available -- but docs/RESULTS.md is the frozen document and the conjunction +#: is what it froze, so the conjunction is the default. (Discrepancy raised +#: with the lead rather than resolved silently in either direction.) +PRE_REGISTERED_RESPONSES: tuple[str, ...] = ("dpop_nll_aux", "dpop", "nll_aux") + +#: NLL auxiliary weight used when the response is `nll_aux`. Small: the term +#: exists to put a floor under the chosen logprob, not to turn DPO into SFT. +NLL_AUX_COEFF = 0.1 + + +# --------------------------------------------------------------------------- +# Config +# --------------------------------------------------------------------------- + + +@dataclass +class DpoStageConfig: + """Stage settings for one arm. Per-field docstrings, per repo convention: + the config file is where someone will try to change these at 2am.""" + + #: `arm_a` (argilla, response-level, 2,310 pairs) or `arm_b` (curated + #: PRM800K shared-prefix step-local pairs). Selects everything else. + arm: str = "arm_a" + #: Section-11's SFT checkpoint. Both arms fine-tune from the SAME one, so + #: any arm-vs-arm difference is the preference data, not the start point. + sft_checkpoint: str = "" + #: Section-11's quality-gate receipt. The stage refuses to launch unless + #: it exists AND records a pass. + sft_quality_gate_path: str = "" + #: Pair shards for this arm (train split) and the problem-level held-out + #: split used for preference accuracy. + shard_dir: str = "" + heldout_shard_dir: str = "" + #: Reference-logprob caches written by scripts/precompute_ref_logprobs.py. + ref_cache_path: str = "" + heldout_ref_cache_path: str = "" + #: The mandatory pre-launch path-bias measurement's report. + path_bias_report_path: str = "" + #: Section-03's build manifest. Its hash is part of the ref-cache key, so + #: a shard rebuild cannot leave a stale cache looking valid. + manifest_path: str = "/apps/development/rlhf/align/data/manifest.json" + #: docs/RESULTS.md must already carry this arm's pre-registration + #: (expectations + tripwire response) before the run starts. + #: The pre-registration is a FROZEN, dated document that lives with the + #: predecessor experiment record (read-only; the gate only greps it). + #: Copying it would fork the thing that is supposed to be frozen, so the + #: default stays on the original until it is migrated deliberately. + results_doc: str = "/apps/development/rlhf/nano-mistral-o1/docs/RESULTS.md" + run_dir: str = "" + + #: Post-filter pair count for this arm, from the build manifest. Drives + #: the optimizer-step horizon, so it is a measured number, never a guess. + expected_pairs: int = 2310 + + # -- objective --------------------------------------------------------- + #: Pre-registered for both arms. `dpop`/`nll_aux` are reachable only as + #: the tripwire RESPONSE, and switching is a recorded deviation. + variant: str = "sigmoid" + #: Preference sharpness. 0.1, both arms, pre-registered. + beta: float = 0.1 + #: NLL auxiliary weight. 0.0 is provably inert in section-05's kernel (the + #: term is skipped structurally, not multiplied by zero). + nll_coeff: float = 0.0 + dpop_lambda: float = 50.0 + #: Which pre-registered response to apply if the chosen-logprob tripwire + #: fires. Defaults to the conjunction docs/RESULTS.md froze; the two + #: single-knob forms are permitted, anything else raises. + tripwire_response: str = "dpop_nll_aux" + + # -- model ------------------------------------------------------------- + #: Attention backend for the policy model. NEVER handed raw to a + #: constructor: `NmoMistralForCausalLM.__init__` routes it through + #: `align.model.attention.select_attn_implementation`, which RAISES if the + #: request cannot be honoured -- for `triton_fa2` that means section-06's + #: equivalence-gate receipt must be valid for THIS kernel source on THIS + #: GPU. The pre-registered value for BOTH arms is `triton_fa2` + #: (docs/RESULTS.md dated entry, 2026-08-17); the neutral default here is + #: sdpa so the pin lives in the arm configs, where changing it is a + #: visible diff against the pre-registration. Membership is validated at + #: config load: a typo'd backend raises at launch, in milliseconds, not + #: as a selector error with four GPUs claimed. + attn_implementation: str = "sdpa" + + # -- optimization ------------------------------------------------------ + #: 5e-7, pre-registered. Two orders below SFT's: DPO moves a model that is + #: already where it should be. + lr: float = 5e-7 + #: 2 pre-registered, 3 maximum. + epochs: int = 2 + #: ~32 via gradient accumulation (e.g. 4 ranks x micro 2 x accum 4). + global_batch: int = 32 + #: >= 4 is MANDATORY for full-FT with offloaded AdamW (section-07 refuses + #: less): at accum 1 the CPU optimizer step dominates wall-clock. + grad_accum: int = 4 + micro_batch_size: int = 2 + num_workers: int = 2 + save_every_micro_steps: int = 100 + keep_checkpoints: int = 2 + #: Each rank writes its own optimizer_rank{r}.pt instead of gathering the + #: full optimizer state (see TrainConfig.per_rank_optimizer_state). Without + #: this field the key was REJECTED by struct mode in DPO TOMLs and, worse, + #: scripts/dpo.py built its RunConfig without ever setting it -- so the + #: trainer-level flag was unreachable from a DPO run. Default False keeps + #: the gathered layout; a resume at a different world_size is refused by + #: the trainer when True. + per_rank_optimizer_state: bool = False + + #: Global-norm gradient clip (OptimizerConfig.max_grad_norm), forwarded by + #: scripts/dpo.py::_run_config. Declared here because the DPO RunConfig is + #: built from defaults: before this field the clip could not be stated in a + #: DPO TOML at all, only inherited. The recorded grad norm stays PRE-clip. + max_grad_norm: Optional[float] = 1.0 + + # -- run-health bounds (G0), forwarded to TrainConfig by the stage script's + # _run_config: a field that is not copied trains at the default while the + # TOML says otherwise. Semantics: align/config.py::TrainConfig. + max_wall_seconds: Optional[float] = None + max_consecutive_skipped_steps: int = 3 + max_skipped_fraction: float = 0.05 + + # -- measurement ------------------------------------------------------- + #: Fires the path-bias rerun when max|delta ref-margin| exceeds this + #: fraction of the early-margin scale. 0.05 = a 5% perturbation of the + #: quantity DPO reads. Chosen as a threshold to MEASURE against, not a + #: tolerance to pass: the measured single-GPU-vs-sharded deltas are + #: expected orders below it, and if they are not, the cache is rebuilt + #: through the sharded forward rather than argued about. + path_bias_threshold: float = 0.05 + #: Denominator of that ratio: the typical magnitude of the implicit margin + #: early in the run, where the loss argument sits near zero and a + #: reference bias is least attenuated. + path_bias_early_margin_scale: float = 0.5 + #: Held-out preference accuracy cadence, in optimizer steps. + heldout_every_optimizer_steps: int = 50 + #: Pairs the chosen-longer fraction is computed over, as a ROLLING + #: WINDOW. Not per micro-batch, which is what the statistic naively is: + #: at the pre-registered micro_batch 2 the per-batch fraction can only be + #: 0, 0.5 or 1, so against a +-0.10 band it false-fires ~78% of the time. + #: + #: 512 is DERIVED, not chosen. SE of a fraction near the 0.5489 baseline + #: is sqrt(p(1-p)/k), so the band sits at 0.10/SE standard errors: + #: k=2 -> 0.28 SE (78% false-fire) k=128 -> 2.27 SE (2.3e-02) + #: k=32 -> 1.14 SE (26%) k=256 -> 3.22 SE (1.3e-03) + #: k=512 -> 4.55 SE (5.4e-06) + #: At 512 the per-check false-fire rate is 5e-06; over Arm B's ~3,000 + #: logged micro-steps that is ~1.6e-02 expected spurious alarms for the + #: whole run. 256 would give ~4 -- enough to bury a real one. + length_window_pairs: int = 512 + #: Which tripwires this arm ARMS, copied into `RunConfig.tripwires.armed`. + #: Both, for both arms: the collapse tripwire is the one with a + #: pre-registered response, and the length-drift one guards the 0.5489 + #: baseline. Section-07 halts at the first log step if an armed tripwire's + #: inputs are missing or NaN, so arming here is a commitment that this + #: stage's loss adapter emits them -- not a hopeful setting. + armed_tripwires: tuple[str, ...] = ("logps_chosen", "length_drift", "grad_norm") + #: Length-drift band around the arm's MEASURED chosen-longer baseline + #: (Arm A: 0.5489 from the build manifest -- never hardcoded here). + length_band: float = 0.10 + logps_window: int = 20 + + def __post_init__(self) -> None: + if self.arm not in ("arm_a", "arm_b"): + raise ValueError(f"arm={self.arm!r} must be 'arm_a' or 'arm_b'") + if self.tripwire_response not in PRE_REGISTERED_RESPONSES: + raise ValueError( + f"tripwire_response={self.tripwire_response!r} is not " + f"pre-registered; permitted: {list(PRE_REGISTERED_RESPONSES)}" + ) + # Imported here, not at module top: align.model.attention pulls torch, + # and this dataclass must stay constructible before the resource + # guards have configured the process. + from ..model.attention import NMO_IMPLEMENTED + + if self.attn_implementation not in NMO_IMPLEMENTED: + raise ValueError( + f"attn_implementation={self.attn_implementation!r} is not an " + f"align attention code path; permitted: {sorted(NMO_IMPLEMENTED)}. " + "A typo must raise at config load, never fall through to a " + "default backend -- a run that reports one backend while " + "executing another poisons every downstream comparison." + ) + + +def load_stage_config(path: str, overrides: Optional[Sequence[str]] = None) -> DpoStageConfig: + """TOML (+ dotted `key=value` overrides) -> DpoStageConfig, struct mode on: + a typo'd key raises at launch instead of silently training with the + default it failed to override.""" + from align.config import load_config + + return load_config(DpoStageConfig, path, list(overrides or [])) + + +def rotate_stale_checkpoints(ckpt_dir: str) -> Optional[str]: + """Move a previous run's checkpoint dir aside, ONCE, for a fresh arm. + + COLLECTIVE: every rank calls it. Only rank 0 touches the filesystem and + every rank then waits at a barrier, so all ranks proceed with the same + directory state. Run on every rank, the bare `os.rename` let exactly one + rank win and the other three die with FileNotFoundError (ranks straddling + a second boundary even computed different destinations); the survivors + had already entered Trainer construction. Returns the destination on + rank 0 when a rotation happened, else None. + """ + import time + + from ..utils.dist import barrier, is_rank0 + + dst = None + if is_rank0() and os.path.isdir(ckpt_dir) and os.listdir(ckpt_dir): + dst = f"{ckpt_dir}_stale_{time.strftime('%Y%m%d-%H%M%S')}" + os.rename(ckpt_dir, dst) + logger.warning("rotated stale checkpoints to %s", dst) + barrier() + return dst + + +def probe_micro_cap(micro_step: int, probe_steps: int) -> int: + """The `max_micro_steps` cap for the launch probe, on the ABSOLUTE counter. + + The Trainer tests `micro_step >= limit` against the absolute micro-step + count, which a resume restores. A bare `probe_steps` cap on a run resumed + at micro N >= probe_steps therefore trained exactly one micro-step and + left `throughput_probe` one time to aggregate (ValueError), so every + supervisor retry died here without a checkpoint. The probe is the first + `probe_steps` micro-steps of THIS process, wherever it starts. + """ + return int(micro_step) + int(probe_steps) + + +def reduce_tripwire_alarms(alarms: Sequence[Mapping]) -> list[dict]: + """Every rank's tripwire alarms, unioned: the same list on all ranks. + + The pre-registered rerun is a COLLECTIVE decision (a second model load, a + new FSDP wrap, a new Trainer). The trainer's alarms are built from + rank-local metrics over different pairs, and only HALT verdicts are + reduced inside the trainer, so a non-HALT alarm (the chosen-logprob + decline) can fire on some ranks only. Acting on the local list sends the + firing ranks into the rerun's collectives while the rest write the + manifest and exit. COLLECTIVE: every rank must call it. Each alarm gains + a `rank` key naming the rank that raised it. + """ + from ..utils.dist import all_gather_objects + + union: list[dict] = [] + for r, rank_alarms in enumerate(all_gather_objects([dict(a) for a in alarms])): + for a in rank_alarms: + union.append({**a, "rank": r}) + return union + + +def resolve_pair_split_dir(shard_dir: str, split: str) -> str: + """The directory holding `-NNNN.receipt.json`, found by DISCOVERY. + + THE HAND-COMPOSED-PATH DEFECT, DPO edition. The attempt-1 configs pointed + at `data/shards/arm_a-train`, composed from a naming convention; the store + actually writes `data/shards/arm_a/train/arm_a-train-0000.receipt.json`. + Section-11 hit the identical defect and fixed it with + `stage_smoke.resolve_split_dir`, which searches for the receipts the store + itself wrote; this delegates to that same function (read-only) rather than + growing a second, drifting copy. Accepts either the shard root or the + exact split directory -- both contain the split's receipts -- and a + missing split reports the splits that ARE present. + """ + from .stage_smoke import resolve_split_dir + + return str(resolve_split_dir(shard_dir, split)) + + +def is_hf_checkpoint(path: Optional[str]) -> bool: + """A directory is a loadable checkpoint iff it carries `config.json` -- + the file `AutoConfig.from_pretrained` reads first. A run dir that merely + CONTAINS checkpoints is not itself one.""" + return bool(path) and os.path.isfile(os.path.join(str(path), "config.json")) + + +def resolve_sft_checkpoint(configured: str, receipt_checkpoint: Optional[str]) -> tuple[str, str]: + """The policy's starting checkpoint: `(path, source)`, or a raise. + + Section-11's Trainer writes `/checkpoints/micro_NNNNNNNN` + (trainer.save_checkpoint) and there is NO stable `final` alias -- the + attempt-1 configs pointed at `checkpoints/sft/final`, a path nothing ever + writes, which would have failed at model load with the gates already + passed. What IS stable is the quality-gate receipt: section-11 records + WHICH micro-step checkpoint passed its gate in the receipt's `checkpoint` + field, so that is the discovery mechanism. A configured path that is + itself a checkpoint wins, as the explicit override for rerunning against + a pinned checkpoint. + """ + if is_hf_checkpoint(configured): + return configured, "config" + if is_hf_checkpoint(receipt_checkpoint): + return str(receipt_checkpoint), "sft_quality_gate_receipt" + raise FileNotFoundError( + f"no SFT checkpoint found. Configured sft_checkpoint={configured!r} " + "is not a checkpoint directory (no config.json), and the quality-gate " + f"receipt records checkpoint={receipt_checkpoint!r}, which is not one " + "either. Section-11's trainer writes " + "/checkpoints/micro_NNNNNNNN and its receipt names the one " + "that passed the gate; refusing to guess a starting point for a " + "full-FT arm." + ) + + +# --------------------------------------------------------------------------- +# Step arithmetic +# --------------------------------------------------------------------------- + + +def optimizer_steps(pairs: int, global_batch: int, epochs: int) -> int: + """epochs * ceil(pairs / global_batch). + + Written once, here, because the iterations-vs-steps confusion is a + documented predecessor incident: an LR horizon quoted in MICRO-steps + schedules the cosine over 4-8x the real run, so the LR never decays and + the run ends at nearly its peak rate with no sign anything was wrong. + Ceiling, not floor -- a trailing partial batch is still an optimizer step. + """ + if pairs < 1: + raise ValueError(f"pairs={pairs} must be >= 1") + if global_batch < 1: + raise ValueError(f"global_batch={global_batch} must be >= 1") + if epochs < 1: + raise ValueError(f"epochs={epochs} must be >= 1") + return epochs * math.ceil(pairs / global_batch) + + +# --------------------------------------------------------------------------- +# Entry gates +# --------------------------------------------------------------------------- + + +def run_entry_gates( + cfg: DpoStageConfig, gates: Mapping[str, Callable[[DpoStageConfig], dict]] +) -> list[dict]: + """Run every gate in `GATE_ORDER`, stopping at the first failure. + + Returns one record per gate that ran. A gate absent from `gates` RAISES: + an unimplemented gate treated as passed is how a run launches with an + unchecked reference cache, and the whole point of the ordered sequence is + that reaching gate N means gates 1..N-1 held. + """ + report: list[dict] = [] + for name in GATE_ORDER: + fn = gates.get(name) + if fn is None: + raise RuntimeError( + f"entry gate {name!r} has no implementation. A missing gate is " + "not a passed gate; refusing to launch." + ) + result = fn(cfg) + record = {"gate": name} + if isinstance(result, Mapping): + record.update(result) + report.append(record) + logger.info("entry gate ok: %s", name) + return report + + +#: The gate whose pass this stage depends on, named in section-11's own +#: `stage_gates.GATE_ORDER` rather than spelled here as a string this module +#: invented. +SFT_GATE_NAME = "quality_gate" + + +def read_sft_quality_gate(path: str) -> dict: + """Section-11's quality-gate verdict: exists, and records a PASS. + + Reads section-11's OWN artifact. `scripts/sft.py` records its gates + through `stage_gates.GateLedger`, which writes `stage_gates.json` as + `{"eval_source_hash": ..., "gates": {"quality_gate": {"passed": ...}}}`. + An earlier draft of this function read a standalone + `{"passed": true}` receipt that nothing writes -- the gate would have + raised FileNotFoundError with four GPUs already claimed. `path` may name + the ledger file or the run directory containing it. + + The comparison itself is NOT restated here. Section-11's + `stage_gates.quality_gate` delegates to section-10's `assert_meets_golden`, + which compares against the WILSON LOWER BOUND -- the golden anchors are + themselves measurements with sampling noise, so demanding the point + estimate meet them would fail correct runs about half the time. This stage + consumes that verdict; a second copy of the CI reasoning here would drift + from it, and the drift would be invisible. + + Three states, and the third is the one that gets skipped. Missing: section + 11 never ran, or ran and never recorded. Present and failed: obvious. + Present and SILENT on this gate: also a refusal, because an artifact that + does not answer the question is indistinguishable from one that answers + 'no', and defaulting to 'yes' would let a partial ledger authorise eight + GPU-hours. + """ + from .stage_gates import LEDGER_FILENAME, PENDING + + resolved = path + if path and os.path.isdir(path): + resolved = os.path.join(path, LEDGER_FILENAME) + if not resolved or not os.path.isfile(resolved): + raise FileNotFoundError( + f"SFT quality gate ledger {resolved!r} is missing. DPO fine-tunes " + "the SFT checkpoint, so an SFT run that never passed its own gate " + "makes both arms measurements of a broken starting point -- at " + "full GPU cost, with nothing downstream able to tell. Point " + "sft_quality_gate_path at section-11's run dir or its " + f"{LEDGER_FILENAME}." + ) + with open(resolved) as f: + blob = json.load(f) + + # Accept the ledger shape, and a bare {"passed": ...} object too: the + # latter is what a hand-written override looks like, and refusing it would + # push someone toward editing the ledger instead. + gates = blob.get("gates", blob if "passed" in blob else {}) + entry = gates.get(SFT_GATE_NAME, blob if "passed" in blob else PENDING) + if not isinstance(entry, dict) or "passed" not in entry: + raise RuntimeError( + f"{resolved!r} does not record whether the SFT {SFT_GATE_NAME!r} " + f"passed (it reads {entry!r}). An artifact that cannot answer the " + "question is not a pass." + ) + if not entry["passed"]: + raise RuntimeError( + f"the SFT quality gate did not pass: " + f"{entry.get('detail', '(no detail recorded)')}. Fix section-11 " + "before spending this stage's GPU budget." + ) + return { + "passed": True, + "detail": entry.get("detail", ""), + "recorded_at": entry.get("recorded_at"), + "eval_source_hash": blob.get("eval_source_hash"), + "checkpoint": blob.get("checkpoint", entry.get("checkpoint")), + "ledger": resolved, + } + + +def check_arm_descoped(arm: str, manifest: Mapping) -> dict: + """Honour section-03's Arm A DESCOPED marker (filter yield < 1,500). + + The failure this prevents is quiet and expensive: training Arm A on + whatever survived the filter and reporting it under the pre-registered + arm's name. A descoped arm is a RESULT -- it gets a manifest saying so -- + not an absence. + """ + descoped = bool(manifest.get("arm_a_descoped", False)) and arm == "arm_a" + return { + "arm": arm, + "descoped": descoped, + "train": not descoped, + "detail": ( + "section-03 marked Arm A descoped (filter yield below the " + "1,500 floor); refusing to train it and recording the " + "descope as this arm's result" + if descoped + else "arm is in scope" + ), + } + + +def build_manifest_gate(cfg: DpoStageConfig, manifest: Mapping) -> dict: + """Counts match the pinned values and the build verified its own pins.""" + if not manifest.get("pins_verified", False): + raise RuntimeError( + "the build manifest reports pins_verified=false: the corpus was " + "built in re-measurement mode and its counts were never checked " + "against the pinned values. Sections 11 and 12 refuse to launch " + f"against it. Violations: {manifest.get('pin_violations')}" + ) + counts = manifest.get("counts", {}) + key = "arm_a_pairs" if cfg.arm == "arm_a" else "arm_b_curated" + measured = counts.get(key) + if measured is None: + raise KeyError( + f"build manifest carries no {key!r} count, so the optimizer-step " + "horizon cannot be derived from a measured pair count." + ) + if int(measured) != int(cfg.expected_pairs): + raise RuntimeError( + f"{cfg.arm}: manifest reports {measured} pairs but the stage " + f"config expects {cfg.expected_pairs}. The horizon, the LR " + "schedule and the ref cache were all built for the config number; " + "one of the two is stale." + ) + return {"pairs": int(measured), **check_arm_descoped(cfg.arm, manifest)} + + +# --------------------------------------------------------------------------- +# Banner +# --------------------------------------------------------------------------- + + +def measure_chosen_longer_fraction(rows: Sequence[Any]) -> float: + """Fraction of pairs whose CHOSEN completion is longer, from the rows. + + Needed because section-03's build manifest records Arm A's baseline + (0.5489) and not Arm B's, while the length-drift tripwire needs one per + arm: `LengthDriftTripwire` refuses a NaN baseline outright, and borrowing + Arm A's would arm Arm B against a distribution it was never drawn from -- + a tripwire that then fires forever or never, both of which are worse than + no tripwire because they look like measurements. + + Completion length, not sequence length: Arm B's two sides share their + entire prefix, so total length is dominated by a term identical on both + sides and would compress the fraction toward 0.5 regardless of the data. + """ + import numpy as np + + longer = 0 + counted = 0 + for r in rows: + lc = len(np.asarray(r["chosen_input_ids"])) - int(r["chosen_prompt_len"]) + lr = len(np.asarray(r["rejected_input_ids"])) - int(r["rejected_prompt_len"]) + if lc <= 0 and lr <= 0: + continue # no completion on either side + counted += 1 + longer += int(lc > lr) + return longer / counted if counted else NAN + + +def dpo_banner( + *, + cfg: DpoStageConfig, + manifest: Mapping, + ref_cache_key, + path_bias: Mapping, + probe: Mapping, + rss: Mapping, + backend: str, + sft_gate: Mapping, + length_baseline: Optional[tuple[float, str]] = None, + pre_registration: str = "docs/RESULTS.md", +) -> dict: + """Everything this run depends on, or a raise. + + Two things are enforced here rather than merely reported. The length-drift + baseline is READ FROM THE MANIFEST (Arm A measured 0.5489; Arm B's is + different, so a constant would mis-arm the tripwire on one arm forever), + and a path-bias decision of 'rerun through the sharded forward' must + actually have been honoured -- a measurement taken, recorded, and ignored + is worse than one never taken, because it leaves evidence that the + question was considered. + """ + baseline_key = f"{cfg.arm}_chosen_longer_fraction" + baselines = manifest.get("length_bias_baseline", {}) + if length_baseline is not None: + baseline, baseline_source = length_baseline + if math.isnan(baseline): + raise ValueError( + f"{baseline_key}: the supplied baseline is NaN, which means " + "nobody measured it. The length-drift tripwire refuses a NaN " + "baseline, so this would disarm it silently." + ) + elif baseline_key in baselines: + baseline, baseline_source = baselines[baseline_key], "build_manifest" + else: + raise KeyError( + f"build manifest has no {baseline_key!r} and no measured baseline " + "was supplied. The length-drift tripwire needs THIS arm's " + "chosen-longer fraction; defaulting to the other arm's would " + "mis-arm it permanently. scripts/dpo.py measures it from the " + "arm's own shards when the manifest lacks it " + "(measure_chosen_longer_fraction)." + ) + + if path_bias.get("fired") and getattr(ref_cache_key, "forward_impl", None) != "fsdp2_sharded": + raise RuntimeError( + "the path-bias measurement fired (action=" + f"{path_bias.get('action')!r}, ratio={path_bias.get('ratio')}) but " + f"the reference cache is tagged " + f"{getattr(ref_cache_key, 'forward_impl', None)!r}, not " + "'fsdp2_sharded'. Re-run the precompute through the sharded " + "forward. A decision that was measured, recorded and then ignored " + "is worse than one never taken." + ) + + horizon = optimizer_steps(cfg.expected_pairs, cfg.global_batch, cfg.epochs) + return { + "arm": cfg.arm, + "loss_type": f"dpo_{cfg.variant}", + "variant": cfg.variant, + "beta": cfg.beta, + "lr": cfg.lr, + "epochs": cfg.epochs, + "global_batch": cfg.global_batch, + "grad_accum": cfg.grad_accum, + "expected_pairs": cfg.expected_pairs, + "optimizer_step_formula": f"{cfg.epochs} x ceil({cfg.expected_pairs}/{cfg.global_batch}) " + f"= {horizon}", + "scheduler_horizon_optimizer_steps": horizon, + "dataset_hashes": dict(manifest.get("hashes", {})), + "ref_cache_key": json.loads(ref_cache_key.to_json()), + "path_bias": dict(path_bias), + "probe_step_time_s": probe.get("step_time_s_median", NAN), + "probe_derived_wall_clock_h": probe.get("projected_wall_clock_h", NAN), + "rss_budget": dict(rss), + "attention_backend": backend, + "length_drift_baseline": baseline, + "length_drift_baseline_source": baseline_source, + "sft_checkpoint": sft_gate.get("checkpoint", cfg.sft_checkpoint), + "pre_registration": pre_registration, + } + + +def render_dpo_banner(resolved: Mapping, title: str = "align dpo") -> str: + """Render, or raise. Never a partial banner. + + Checks this stage's keys AND section-01's global mandatory set, without + mutating the global registry -- see DPO_BANNER_KEYS for why. + """ + from ..registry import MANDATORY_BANNER_KEYS + + required = list(DPO_BANNER_KEYS) + [ + k for k in MANDATORY_BANNER_KEYS if k not in DPO_BANNER_KEYS + ] + missing = [k for k in DPO_BANNER_KEYS if k not in resolved] + unresolved = [k for k in DPO_BANNER_KEYS if k in resolved and resolved[k] is None] + if missing or unresolved: + raise RuntimeError( + "DPO launch banner incomplete -- refusing to start. A run that " + f"cannot answer its question does not begin. missing={missing} " + f"unresolved(None)={unresolved}. Undefined values must be " + "EXPLICIT: float('nan') or 'PENDING', never absent." + ) + width = 78 + lines = ["=" * width, f"| {title} [{resolved['arm']}]", "=" * width] + for key in required: + if key in resolved: + lines.append(f"| {key:<36} {resolved[key]!r}") + for key in sorted(k for k in resolved if k not in required): + lines.append(f"| {key:<36} {resolved[key]!r} (extra)") + lines.append("=" * width) + return "\n".join(lines) + + +# --------------------------------------------------------------------------- +# Tripwire response +# --------------------------------------------------------------------------- + + +def apply_tripwire_response( + cfg: DpoStageConfig, alarms: Sequence[Mapping] +) -> tuple[DpoStageConfig, dict]: + """Map a fired chosen-logprob tripwire to the PRE-REGISTERED response. + + Returns `(config to rerun the arm with, record)`. The record goes into the + arm manifest, so the deviation is part of the result rather than a note + somebody remembers. + + The alarm being responded to: `logps/chosen` declining while the margin + improves. DPO's objective is satisfied by separating the two logprobs, and + crushing the rejected one separates them just as well as raising the + chosen one -- while degrading the policy. The mode is MAXIMAL FOR ARM B by + design, because pi_SFT already assigns those chosen continuations high + likelihood, so there is little headroom above and a great deal below. + + Every permitted response puts a floor under the chosen logprob: `dpop` + adds an explicit penalty when it falls below the reference, `nll_aux` adds + a likelihood term on the chosen completion, and `dpop_nll_aux` -- the + frozen pre-registration's wording -- does both. Beta is NOT changed, and + the arm re-runs ONCE: a second rerun would be a third configuration. + """ + # "logps_chosen" is the WIRE NAME the trainer records (trainer.py appends + # {"alarm": name} for the armed wire key). This filter matched a name + # nobody emits ("logps_chosen_decline") until 2026-08-17 -- a fired + # collapse tripwire could never trigger the pre-registered rerun, and the + # unit test asserted the filter against its own literal instead of the + # trainer's. Silent-failure trap #7's shape: armed-looking, disconnected. + fired = [a for a in alarms if a.get("alarm") == "logps_chosen"] + if not fired: + return cfg, { + "fired": False, + "rerun_required": False, + "pre_registered": True, + "configuration": f"{cfg.variant} beta={cfg.beta}", + "detail": "no chosen-logprob alarm; primary configuration stands as the arm's result", + } + + if cfg.tripwire_response not in PRE_REGISTERED_RESPONSES: + raise ValueError( + f"tripwire_response={cfg.tripwire_response!r} is outside the " + f"pre-registration ({list(PRE_REGISTERED_RESPONSES)}). A third " + "configuration requires a NEW pre-registration written before the " + "rerun -- choosing one after seeing the data is how a stage picks " + "its own success criterion." + ) + if cfg.tripwire_response == "dpop_nll_aux": + new = replace(cfg, variant="dpop", nll_coeff=NLL_AUX_COEFF) + elif cfg.tripwire_response == "dpop": + new = replace(cfg, variant="dpop") + else: + new = replace(cfg, variant="sigmoid", nll_coeff=NLL_AUX_COEFF) + record = { + "fired": True, + "rerun_required": True, + "pre_registered": True, + "alarms": [dict(a) for a in fired], + "response": cfg.tripwire_response, + "configuration": ( + f"{new.variant} beta={new.beta} nll_coeff={new.nll_coeff} dpop_lambda={new.dpop_lambda}" + ), + "detail": ( + "chosen-logprob collapse detected; the arm re-runs with the " + "pre-registered response and THAT configuration is recorded " + "as the arm's result" + ), + } + logger.error("tripwire response applied: %s", record["configuration"]) + return new, record + + +# --------------------------------------------------------------------------- +# Arm result manifest +# --------------------------------------------------------------------------- + + +def arm_result_manifest( + *, + cfg: DpoStageConfig, + descoped: bool, + summary: Mapping, + heldout: Mapping, + banner: Mapping, + checkpoint: Optional[str], + tripwire: Optional[Mapping] = None, +) -> dict: + """What section-13 reads to select an arm and run the paired evaluation. + + A descoped arm still produces a manifest. Its accuracy is NaN, not 0.0: + zero is a plausible catastrophic result and would read as one, while NaN + says nobody measured -- the distinction section-13's arm-selection rule + depends on. + """ + return { + "arm": cfg.arm, + "status": "descoped" if descoped else "trained", + "checkpoint": None if descoped else checkpoint, + "loss_variant_actually_used": None if descoped else cfg.variant, + "beta": cfg.beta, + "nll_coeff": cfg.nll_coeff, + "lr": cfg.lr, + "epochs": cfg.epochs, + "global_batch": cfg.global_batch, + "optimizer_steps_planned": optimizer_steps( + cfg.expected_pairs, cfg.global_batch, cfg.epochs + ), + "optimizer_steps_run": summary.get("optimizer_step", 0), + "heldout_preference_accuracy": heldout.get("accuracy", NAN), + "heldout_ci": [heldout.get("ci_low", NAN), heldout.get("ci_high", NAN)], + "heldout_n": heldout.get("n", 0), + "final_mean_margin": heldout.get("mean_margin", NAN), + "tripwire": dict(tripwire) if tripwire else {"fired": False}, + "tripwire_alarms": list(summary.get("tripwire_alarms", [])), + "trunk_report": dict(summary.get("trunk_report", {})), + "checkpoints_written": list(summary.get("checkpoints_written", [])), + "banner": dict(banner), + } + + +def write_arm_result(path: str, manifest: Mapping) -> str: + """Write the arm manifest: rank 0 only, atomically. + + COLLECTIVE (every rank calls it; the closing barrier keeps ranks together). + Run on all four torchrun ranks with a bare `open(path, "w")`, the ranks + truncated and wrote one path within a millisecond, with rank-local content + (`checkpoint` is "" off rank 0): the recorded Arm B manifest is + unparseable. Section-13 reads this file to select an arm, so it is written + once, via tmp + os.replace, and rank 0's `checkpoint` is the real one. + """ + from ..utils.dist import barrier, is_rank0 + from ..utils.guard import assert_paths_off_root + from .ref_cache import _atomic_write + + assert_paths_off_root([os.path.dirname(os.path.abspath(path))]) + if is_rank0(): + + def _dump(tmp: str) -> None: + with open(tmp, "w") as f: + # default=str: the manifest is assembled by the caller from eval + # output and this writes an ARM'S RESULT after its full DPO run -- + # the exact shape (harness-measured values serialized at the end) + # that killed SFT attempt 6 with a Tensor in a gate receipt. + json.dump(manifest, f, indent=2, default=str) + f.flush() + os.fsync(f.fileno()) + + _atomic_write(path, _dump) + logger.info("arm result manifest -> %s", path) + barrier() + return path + + +# --------------------------------------------------------------------------- +# Trainer-facing batch + loss adapter +# --------------------------------------------------------------------------- + + +class DpoBatch: + """A `Preference` batch, iterable over its pair ids. + + Section-07's `Trainer` iterates the object it is handed and logs + `list(batch)` as that step's identity -- its own tests pass samplers that + yield row-index lists, for which `list(batch)` is exactly right. A + `Preference` dataclass is not iterable, so a bare one would raise + TypeError at the first log step. + + Wrapping supplies the identity the log wants, and supplies a better one + than row indices: which PAIRS a step consumed. Row indices are meaningless + across a reshuffle or a rebuild; pair ids survive both, so a suspicious + step stays reproducible afterwards. + """ + + __slots__ = ("preference", "pair_ids") + + def __init__(self, preference): + self.preference = preference + self.pair_ids = [(m or {}).get("pair_id") for m in preference.metadata] + + def __iter__(self): + return iter(self.pair_ids) + + def __len__(self) -> int: + return len(self.pair_ids) + + def to(self, device) -> "DpoBatch": + return DpoBatch(self.preference.to(device)) + + +class PreferenceBatchSource: + """What section-07's `Trainer` iterates: `set_epoch` / `__iter__` / `__len__`. + + The Trainer walks a batch source directly rather than a `DataLoader`, and + that is a deliberate section-07 choice: batch order becomes a pure + function of (seed, epoch), which is what makes the seeded-resume contract + checkable. It also means there are no dataloader worker processes in this + loop at all -- the `<=2 workers per rank` rule that the /dev/shm SIGBUS + incident produced has nothing to bind to here, because nothing is forked. + Collation happens inline, in the training process. + + That is affordable for DPO specifically: pair shards are memory-mapped and + a micro-batch is two short sequences, so collation is microseconds against + a 7B forward. It would not be affordable for a tokenization-heavy loop. + """ + + def __init__(self, rows: Sequence[Any], sampler, pad_token_id: int): + self.rows = list(rows) + self.sampler = sampler + self.pad_token_id = int(pad_token_id) + + def set_epoch(self, epoch: int) -> None: + self.sampler.set_epoch(epoch) + + def __len__(self) -> int: + return len(self.sampler) + + def __iter__(self): + from ..data.loader import collate_preference + + for indices in self.sampler: + yield DpoBatch( + collate_preference([self.rows[i] for i in indices], pad_token_id=self.pad_token_id) + ) + + +def make_preference_sampler( + rows, *, max_tokens: int, max_rows: int, seed: int = 0, rank=None, world_size=None +): + """Section-03's length-grouped sampler, RANK-SHARDED. + + THE UNSHARDED-SAMPLER INCIDENT (~24 GPU-hours on Arm A). This used to + return the bare `LengthGroupedSampler`, so every rank walked the same + batch list in the same order and all four trained the SAME pair every + micro-step. The effective global batch was micro x accum (8), not + micro x accum x world (32) as pre-registered; one "epoch" therefore + consumed a quarter of the corpus; the horizon covered half an epoch; and + past it the cosine schedule clamps to lr=0, so the run kept stepping on + frozen weights for 287 more steps. Nothing failed -- the loss curve was + plausible and the manifest reported the intended batch size throughout. + + SHARDING THE BATCHES, NOT THE ROWS, and the choice matters twice over: + + * `PreferenceBatchSource` indexes the FULL row list with whatever + indices the sampler yields, so slicing batches keeps every index + valid and needs no remapping -- one seam instead of two that can + disagree. + * `DistributedBatchSampler` truncates the batch list to a multiple of + world_size so EVERY RANK RUNS THE SAME NUMBER OF STEPS. A rank that + finished early would leave its peers blocked inside a collective, + which surfaces hours later as an NCCL timeout rather than as an error + where it happened. Row-slicing (`rows[rank::world]` before batching) + cannot promise this: the sampler is token-budgeted, so different row + slices yield different batch counts. + + The cost is a bounded tail: up to (world_size - 1) batches are dropped per + epoch. Section-03 chose that over padding with repeats, which would + double-count rows and corrupt the epoch semantics the horizon is derived + from. + + `rank`/`world_size` default to the live environment but are explicit + parameters so four ranks can be simulated in one CPU process -- which is + how this contract is tested, since the incident is a property of the + relationship BETWEEN ranks and no single-process run can see it. + """ + from ..data.loader import ( + DistributedBatchSampler, + LengthGroupedSampler, + preference_length_key, + ) + from ..utils.dist import rank as env_rank + from ..utils.dist import world_size as env_world_size + + lengths = [preference_length_key(r) for r in rows] + base = LengthGroupedSampler(lengths, max_tokens=max_tokens, max_rows=max_rows, seed=seed) + + r = env_rank() if rank is None else int(rank) + ws = env_world_size() if world_size is None else int(world_size) + if ws <= 1: + return base + if not 0 <= r < ws: + raise ValueError(f"rank {r} is outside world_size {ws}") + return DistributedBatchSampler(base, rank=r, world_size=ws) + + +def _check_global_batch( + global_batch: int, world_size: int, micro_batch_size: int, grad_accum: int +) -> int: + """The arithmetic behind both launch refusals; returns the live global batch.""" + live = world_size * micro_batch_size * grad_accum + if global_batch != live: + raise RuntimeError( + f"global_batch={global_batch} (the pre-registered value the banner " + f"and horizon are quoted in) != world_size {world_size} x micro " + f"{micro_batch_size} x grad_accum {grad_accum} = {live}. The run " + "would consume a different number of pairs per optimizer step than " + "it reports. Launch with the pre-registered rank count or change " + "the config deliberately." + ) + return live + + +def live_world_size() -> int: + """The data-parallel width this process is ACTUALLY part of. + + The initialised process group wins over the environment: `WORLD_SIZE` is + what torchrun exported, the group is what the collectives will average + over, and a launch decision belongs to the latter. Falls back to the + environment before `init_process_group` (and to 1 outside torchrun). + """ + import torch.distributed as dist + + if dist.is_available() and dist.is_initialized(): + return int(dist.get_world_size()) + from ..utils.dist import world_size + + return int(world_size()) + + +def assert_launch_topology(cfg: "DpoStageConfig", *, world_size: Optional[int] = None) -> dict: + """LAUNCH REFUSAL: world_size x micro x grad_accum must equal the + pre-registered `global_batch` (2026-10-12 review). + + Nothing used to check it. `global_batch` is a config number that the + banner, `optimizer_steps()` and the arm manifest all quote, while what a + run really consumes per optimizer step is `world_size * micro_batch_size * + grad_accum`. A 2-rank launch of the 4-rank pre-registration therefore ran + 16 pairs per step under a banner that said 32 and a quoted horizon of 146 + (really 290): the experiment recorded as one thing and executed as + another, with every number finite. `assert_dpo_horizon_consistent` + carries the same check but sits AFTER the 14.5GB model load and was never + passed the pre-registered value by the launcher; this one runs before any + gate, in milliseconds, fed by the live topology. + + `world_size=None` reads it from the live process group (see + `live_world_size`); tests and tools pass it explicitly. + """ + ws = live_world_size() if world_size is None else int(world_size) + if ws < 1: + raise ValueError(f"world_size={ws} must be >= 1") + live = _check_global_batch(cfg.global_batch, ws, cfg.micro_batch_size, cfg.grad_accum) + return { + "world_size": ws, + "micro_batch_size": cfg.micro_batch_size, + "grad_accum": cfg.grad_accum, + "global_batch": live, + } + + +def expected_ref_cache_key(cfg: "DpoStageConfig", manifest: Mapping, sft_checkpoint: str): + """The key this run requires of its reference caches. + + Five components are EXPECTATIONS built from this run's own facts (content + hash of the SFT weights, tokenizer, shard manifest, max_length, truncation) + and one is a RECORD: `forward_impl`, how the cache's own pass ran. The + record is read from the cache itself, never from the path-bias report. + + WHY NOT THE REPORT (2026-10-12 review). The launcher used to take + forward_impl from the report's `cache_forward_impl`, which + precompute_ref_logprobs wrote as "fsdp2_sharded" whenever `--path-bias` + was passed -- but a `--path-bias` run does NOT recompute the caches, so the + field described the measuring run, not the cache. The documented happy + path (single-GPU precompute, then `--path-bias`, decision fired=False) + was refused at the cache gate: "Mismatched: forward_impl + (cache='single_gpu', run='fsdp2_sharded')". The rule that a FIRED decision + must be honoured by a sharded cache is enforced where it belongs, by + `dpo_banner`; here the held-out cache must agree with the train cache's + tag, and everything else is asserted by `load_ref_cache(expect=...)`. + """ + from .ref_cache import build_ref_cache_key, peek_ref_cache_key + + cache_key = peek_ref_cache_key(cfg.ref_cache_path) + forward_impl = cache_key.forward_impl if cache_key is not None else "single_gpu" + return build_ref_cache_key(sft_checkpoint, dict(manifest), forward_impl=forward_impl) + + +def load_run_ref_caches(cfg: "DpoStageConfig", manifest: Mapping, sft_checkpoint: str): + """Load (train, held-out) reference caches under `expected_ref_cache_key`. + + Both caches are loaded with `expect=`, so a missing file, a stale + checkpoint, a rebuilt shard set, a different tokenizer/max_length, or a + held-out cache computed through a different forward than the train cache + all raise here, at the gate, naming the guilty component. + """ + from .ref_cache import load_ref_cache + + key = expected_ref_cache_key(cfg, manifest, sft_checkpoint) + train = load_ref_cache(cfg.ref_cache_path, expect=key) + held = load_ref_cache(cfg.heldout_ref_cache_path, expect=key) + return train, held + + +def assert_dpo_horizon_consistent( + scheduler_total_steps: int, + *, + n_pairs: int, + world_size: int, + micro_batch_size: int, + grad_accum: int, + epochs: int, + slack: Optional[int] = None, + global_batch: Optional[int] = None, +) -> dict: + """Refuse to launch when the LR horizon disagrees with the corpus. + + `global_batch`, when given, is the PRE-REGISTERED number the banner and the + horizon formula (`optimizer_steps`) are quoted in; it must equal what the + live topology actually consumes per optimizer step, + `world_size * micro_batch_size * grad_accum`. Without this the banner can + say global_batch 32 / horizon 146 while a 2-rank launch really runs 16 / + 290: the scheduler-vs-corpus check below passes (it uses the live world + size) and the banner is simply wrong about what ran. + + THE ZOMBIE-RUN REFUSAL. Arm A ran a 146-step horizon over a corpus needing + ~289 per-rank steps, so the cosine finished at half an epoch; past it + `WarmupCosineSchedule` clamps to exactly 0 (min_lr_frac=0) and the loop + kept stepping on frozen weights for 287 more steps. The horizon is a + PRE-REGISTERED quantity: if it and the arithmetic disagree, one of them is + wrong and no amount of training will reconcile them. + + Computed from the SHARDED per-rank row count, because that is what a rank + actually walks. `slack` absorbs the token-budgeted sampler landing a batch + or two either side of the row-count arithmetic; it does not absorb a + factor. + """ + import math as _math + + if min(n_pairs, world_size, micro_batch_size, grad_accum, epochs) < 1: + raise ValueError("every horizon input must be >= 1") + + if global_batch is not None: + _check_global_batch(global_batch, world_size, micro_batch_size, grad_accum) + per_rank_rows = _math.ceil(n_pairs / world_size) + rows_per_step = micro_batch_size * grad_accum + expected = epochs * _math.ceil(per_rank_rows / rows_per_step) + if slack is None: + # PROPORTIONAL slack: the token-budgeted sampler legitimately cuts + # batches short of max_rows, so the sampler-true horizon runs a few + # PERCENT over the row arithmetic (Arm B: 728 vs 708, 2.8%, which a + # fixed slack of 2 wrongly refused). 5% absorbs batch-shortfall while + # still catching the zombie class (Arm A was 2.1x, far outside). + slack = max(2, _math.ceil(0.05 * expected)) + report = { + "scheduler_total_steps": int(scheduler_total_steps), + "expected_steps": expected, + "per_rank_rows": per_rank_rows, + "rows_per_optimizer_step_per_rank": rows_per_step, + "unique_rows_per_optimizer_step": rows_per_step * world_size, + "epochs_covered": (scheduler_total_steps / expected * epochs if expected else float("nan")), + } + if abs(int(scheduler_total_steps) - expected) > slack: + covered = report["epochs_covered"] + raise RuntimeError( + f"DPO horizon is inconsistent with the corpus: the scheduler will " + f"run {scheduler_total_steps} optimizer steps but " + f"{n_pairs} pairs / {world_size} ranks = {per_rank_rows} rows per " + f"rank at {rows_per_step} rows per step needs {expected} " + f"(epochs={epochs}, slack={slack}). That horizon covers " + f"{covered:.2f} epoch(s).\n\nA horizon shorter than the data is " + "not a shorter run -- past it the cosine schedule clamps the " + "learning rate to exactly 0 and the loop keeps stepping on frozen " + "weights, which is how Arm A spent ~24 GPU-hours training " + "nothing. Fix the horizon or the corpus arithmetic before " + "launching." + ) + return report + + +#: The canonical name for the implicit reward margin -- section-05's kernel +#: emits it and section-07's Trainer reads it. Imported from the Trainer +#: rather than spelled again here: a second copy of the string, asserting what +#: the Trainer reads, is precisely the drift that disarmed the tripwire the +#: first time. +from .trainer import MARGIN_KEY as KERNEL_MARGIN_KEY # noqa: E402 + + +def _arm_tripwire_metrics(metrics: dict, preference, window=None) -> dict: + """Assert this adapter supplies what the armed tripwires consume. + + THE DISARMED-TRIPWIRE INCIDENT, in its final form. Section-05's kernel + emits the implicit margin as `rewards/margins`; section-07's Trainer used + to seed a DIFFERENT key, `margin`, with NaN and feed the tripwire from + that. Nothing produced it, `_slope` returns NaN for any window containing + NaN, and the trip condition requires a non-NaN slope -- so the + chosen-likelihood-collapse tripwire, the one with a pre-registered + response and the one maximal for Arm B by design, could never fire while + appearing fully wired. + + The cure is section-07's, not this module's: the Trainer now reads + `MARGIN_KEY` directly, tripwires declare `INPUT_KEYS`, and + `assert_tripwires_armed` halts at the first log step if an armed guard's + inputs are missing or NaN. This function no longer bridges names -- an + alias here would write a key nothing reads. + + What remains is a PRESENCE check at the seam, which is still worth its + line: it catches a section-05 rename here, one function call after the + kernel returns, rather than at the first log step with the metric already + gone. `chosen_longer_fraction` is supplied for the same reason -- the + length-drift tripwire's only input, and this adapter is the only thing + that can compute it. + """ + if KERNEL_MARGIN_KEY not in metrics: + raise KeyError( + f"the DPO kernel did not emit {KERNEL_MARGIN_KEY!r} (present: " + f"{sorted(metrics)}). That is the canonical margin key the " + "chosen-logprob tripwire consumes; without it the armed tripwire " + "self-test halts the run, and this raise names the cause one call " + "after the kernel returned instead of at the first log step." + ) + if window is not None: + window.extend(_chosen_longer_flags(preference)) + metrics["chosen_longer_fraction"] = sum(window) / len(window) if window else NAN + metrics["chosen_longer_pairs"] = float(len(window)) + metrics.setdefault("chosen_longer_fraction", preference.stats()["chosen_longer_fraction"]) + metrics.setdefault("chosen_longer_fraction_batch", preference.stats()["chosen_longer_fraction"]) + return metrics + + +def _chosen_longer_flags(preference) -> list[int]: + """Per-pair `chosen completion is longer`, skipping pairs with no + completion on either side. + + Per PAIR, because the length-drift tripwire's input has to be a fraction + over a sample whose size we control; the batch-level statistic is that + same fraction over whatever happened to be in the micro-batch, which at + micro_batch 2 is three possible values. + + Completion tokens, not sequence tokens: Arm B's two sides share their + entire prefix, so a sequence-length comparison is dominated by a term + identical on both sides and would compress the fraction toward 0.5 + regardless of the data -- hiding exactly the drift being watched for. + """ + c = preference.chosen_completion_mask.sum(dim=1) + r = preference.rejected_completion_mask.sum(dim=1) + return [int(ci > ri) for ci, ri in zip(c.tolist(), r.tolist()) if (ci + ri) > 0] + + +def make_dpo_stage_adapter( + cache, cfg: Optional[DpoStageConfig] = None, require_fused: bool = False +): + """Trainer loss adapter: attach cached refs by pair_id, then delegate. + + Bridges three things section-05 and section-03 do not agree on, and does + it in one place so the disagreement cannot be re-resolved differently + somewhere else: + + * NAMES. Section-03's `Preference` carries `chosen_input_ids` / + `ref_chosen_logps`; section-05's adapter unpacks `input_ids_chosen` / + `ref_logp_chosen`. Neither is wrong; they were written to different + drafts. + * LABELS. `Preference` carries a completion MASK, `fused_dpo` wants + labels with IGNORE_INDEX outside the completion. The conversion is one + `masked_fill`, and getting it backwards would score the prompt -- which + cancels in the DPO difference while inflating both magnitudes. + * REFERENCES. They come from the cache, joined by pair_id, never from + batch order and never defaulted. + + The reference tensors enter as plain constants; section-05's kernel + detaches them and proves no gradient path survives. This adapter's only + obligation is never to build one, which it discharges by reading them out + of a dict of floats. + """ + from ..kernels.fused_dpo import IGNORE_INDEX + from .dpo_loss import DpoLossConfig, make_dpo_loss_adapter + from .ref_cache import attach_refs + + stage = cfg or DpoStageConfig() + #: Rolling per-PAIR history feeding the length-drift tripwire. Lives on + #: the adapter, not on the batch: the statistic the tripwire needs spans + #: batches, and computing it per batch is what makes it unusable. + length_window = collections.deque(maxlen=stage.length_window_pairs) + inner = make_dpo_loss_adapter( + DpoLossConfig( + beta=stage.beta, + variant=stage.variant, + nll_coeff=stage.nll_coeff, + dpop_lambda=stage.dpop_lambda, + ), + require_fused=require_fused, + # One trunk graph at a time: both sides' checkpointed 7B graphs plus + # fp32 shard grads measured 21.5GB and OOM'd (batch-size independent). + decoupled_backward=require_fused, + grad_scale=1.0 / max(1, stage.grad_accum), + ) + + def adapter(model, batch): + import torch + + pref = batch.preference if isinstance(batch, DpoBatch) else batch + pref = attach_refs(pref, cache) + # The WHOLE batch to the compute device, refs included. The model + # forward moves input_ids internally, which let CPU labels survive + # to the loss's gather ("index is on cpu") on the stage's first + # real step -- the SFT script moves its collated batch explicitly, + # and this adapter is the DPO stage's equivalent place. + # + # Follow the MODEL's device, not `cuda.is_available()`: on a box with + # visible GPUs a CPU-resident model (the unit-test tiny model) would + # otherwise get CUDA batches and die inside the embedding. Under FSDP2 + # the parameters are DTensors on this rank's cuda device, so the real + # path is unchanged. + param = next(iter(model.parameters()), None) + if param is not None and param.device.type == "cuda": + pref = pref.to(torch.device("cuda", torch.cuda.current_device())) + elif param is None and torch.cuda.is_available(): + pref = pref.to(torch.device("cuda", torch.cuda.current_device())) + bound = { + "input_ids_chosen": pref.chosen_input_ids, + "labels_chosen": pref.chosen_input_ids.masked_fill( + pref.chosen_completion_mask == 0, IGNORE_INDEX + ), + "input_ids_rejected": pref.rejected_input_ids, + "labels_rejected": pref.rejected_input_ids.masked_fill( + pref.rejected_completion_mask == 0, IGNORE_INDEX + ), + "ref_logp_chosen": pref.ref_chosen_logps, + "ref_logp_rejected": pref.ref_rejected_logps, + } + out = inner(model, bound) + _arm_tripwire_metrics(out.metrics, pref, window=length_window) + return out + + adapter.uses_fused = getattr(inner, "uses_fused", True) + adapter.config = inner.config + adapter.stage_config = stage + return adapter diff --git a/code/align/train/fsdp.py b/code/align/train/fsdp.py new file mode 100644 index 0000000000000000000000000000000000000000..5c65a3f7d05ab416a814e3037c4dc216526d6c42 --- /dev/null +++ b/code/align/train/fsdp.py @@ -0,0 +1,124 @@ +"""FSDP2 wrapping and activation checkpointing. + +Called from the LAUNCH SCRIPTS, never from the Trainer: the Trainer receives an +already-wrapped model, which is what keeps it identical between the SFT and DPO +stages and testable on CPU without a process group. + +Two policies here are not configurable, deliberately: + + * `use_reentrant=False`, hard-asserted. Reentrant activation checkpointing + silently ZEROES trunk gradients under sharding. The run trains -- loss + falls, throughput is normal -- while only the embeddings and the LM head + move. There is no knob to turn it back on, because the only reason anyone + would set it is not knowing this. The trunk-movement probe in `probes.py` + is the runtime backstop; this is the compile-time one. + * No `CPUOffloadPolicy`. FSDP's own CPU offload pays per-layer transfers on + every forward AND backward; our offload is optimizer-state-only and + happens once per optimizer step (see `offload_adamw.py`). Turning both on + would move the same bytes twice. + +Sharding is PER TRANSFORMER BLOCK, then the root. Per-block units are what +make the all-gather granularity match the compute granularity: one unit for +the whole model would gather all 7.25B parameters before the first matmul. +""" + +from __future__ import annotations + +import functools +import logging +from typing import Any, Optional + +import torch + +logger = logging.getLogger(__name__) + +#: bf16 compute, fp32 reduction. bf16 is mandatory (fp16 overflows the +#: 32768-vocab logits); the fp32 REDUCE matters independently -- gradient +#: all-reduce in bf16 loses small updates across 4 ranks precisely when they +#: are averaged, which is every step. +PARAM_DTYPE = torch.bfloat16 +REDUCE_DTYPE = torch.float32 + + +def transformer_blocks(model) -> list: + """The per-block FSDP units: every `DecoderBlock` in the stack. + + Found structurally rather than by isinstance so this module does not + import the model (and so a wrapped/compiled model still works). + """ + inner = getattr(model, "model", model) + layers = getattr(inner, "layers", None) + if layers is None: + raise ValueError( + "no `.layers` found on the model: FSDP2 here shards per " + "transformer block, and a model with no block list would be " + "wrapped as ONE unit -- gathering all 7.25B parameters before the " + "first matmul, which does not fit on a 23GB card." + ) + return list(layers) + + +def mixed_precision_policy(): + """`MixedPrecisionPolicy(param_dtype=bf16, reduce_dtype=fp32)`.""" + from torch.distributed.fsdp import MixedPrecisionPolicy + + return MixedPrecisionPolicy(param_dtype=PARAM_DTYPE, reduce_dtype=REDUCE_DTYPE) + + +def apply_fsdp(model, mesh: Optional[Any] = None, reshard_after_forward: bool = True): + """Shard per transformer block, then the root. + + Order is load-bearing: the root must be sharded LAST, after its children + are already units, or the root unit would own their parameters too. + """ + from torch.distributed.fsdp import fully_shard + + policy = mixed_precision_policy() + blocks = transformer_blocks(model) + for block in blocks: + fully_shard(block, mesh=mesh, mp_policy=policy, reshard_after_forward=reshard_after_forward) + fully_shard(model, mesh=mesh, mp_policy=policy, reshard_after_forward=reshard_after_forward) + logger.info( + "FSDP2: %d per-block units + root, param=%s reduce=%s", + len(blocks), + PARAM_DTYPE, + REDUCE_DTYPE, + ) + return model + + +def _checkpointed_forward(block, *args, **kwargs): + from torch.utils.checkpoint import checkpoint + + return checkpoint(block._nmo_inner_forward, *args, use_reentrant=False, **kwargs) + + +def apply_activation_checkpointing(model, use_reentrant: bool = False): + """Wrap every transformer block in non-reentrant activation checkpointing. + + Patches each block's `forward` rather than wrapping the block in a new + module: a wrapper module would insert a level into the module tree and + change every parameter name, which would silently break the HF checkpoint + mapping and the interp pillar that loads through it. + """ + if use_reentrant: + raise ValueError( + "use_reentrant=True is refused. Reentrant activation checkpointing " + "silently ZEROES trunk gradients under sharding: the run trains " + "the embeddings and the LM head, the loss falls, throughput looks " + "normal, and the body of the model never moves. This is a " + "documented predecessor failure and there is no configuration in " + "which we want it." + ) + blocks = transformer_blocks(model) + for block in blocks: + if hasattr(block, "_nmo_inner_forward"): + continue # idempotent: never double-wrap + block._nmo_inner_forward = block.forward + block.forward = functools.partial(_checkpointed_forward, block) + logger.info("activation checkpointing on %d blocks (use_reentrant=False)", len(blocks)) + return model + + +def is_checkpointed(block) -> bool: + return hasattr(block, "_nmo_inner_forward") diff --git a/code/align/train/lora_scale.py b/code/align/train/lora_scale.py new file mode 100644 index 0000000000000000000000000000000000000000..7409f8d6055448bbf8d7240d1f4754afd5685f55 --- /dev/null +++ b/code/align/train/lora_scale.py @@ -0,0 +1,110 @@ +"""LoRA scale sweep WITHOUT retraining (SOTA plan K4). + +A LoRA layer computes `W x + s * B A x` with s = alpha / r. Evaluating the SAME trained adapter at a +multiple `k` of that delta (k in {0.5, 0.7, 1.0}: "alpha curve") needs no optimisation: set s -> k*s. +k = 1 is the trained model, k = 0 is the base, and the curve between them tells whether a regression +is "too much adapter" (a smaller k recovers it) or "the wrong direction" (it does not). + +Two entry points, matching the two ways an adapter is evaluated: + + * `scaled_adapter(model, adapter, k)` -- a context manager over a LIVE model with the adapter attached + (the un-merged serving option); `sweep(...)` runs an eval callable at each k. + * `merged_state_dict_at_scale(model, full_state, adapter, k)` -- a BASE-keyed merged state dict at + scale k, for merged exports, with exactly the bf16-cast fidelity report of + `align.ppo.lora.export_merged_state_dict` (the delta is k times smaller, so MORE of it can fall into + the bf16 dead zone: read `report["cosine"]` before trusting a small-k merged eval). + +Refusals: a layer that has the adapter MERGED into its weight cannot be rescaled (the delta is already +inside W); the context manager raises instead of evaluating a polluted point. The model is never left +rescaled: the original scaling is restored in `finally`, on error and on KeyboardInterrupt alike. +""" + +from __future__ import annotations + +import contextlib +import math +from collections.abc import Callable, Iterable, Iterator +from typing import Any, Optional + +import torch +import torch.nn as nn + +from ..ppo.lora import export_merged_state_dict, lora_modules + +#: The plan's K4 grid: fractions of the TRAINED adapter delta. +DEFAULT_SCALES: tuple[float, ...] = (0.5, 0.7, 1.0) + + +def _check_scale(k: float) -> float: + k = float(k) + if not math.isfinite(k) or k < 0.0: + raise ValueError(f"LoRA delta scale must be a finite number >= 0, got {k!r}") + return k + + +@contextlib.contextmanager +def scaled_adapter(model: nn.Module, adapter: str, k: float) -> Iterator[int]: + """Within the block, every layer's `adapter` contributes `k` times its trained delta. + + Yields the number of layers rescaled. Raises (before changing anything) if no layer carries the + adapter or if any layer has it merged. + """ + k = _check_scale(k) + layers = [(p, m) for p, m in lora_modules(model) if adapter in m.adapters] + if not layers: + raise KeyError(f"no layer carries adapter {adapter!r}; nothing to scale") + merged = [p for p, m in layers if m._merged is not None] + if merged: + raise RuntimeError( + f"adapter {adapter!r} is merged into {len(merged)} layer(s) (first: {merged[0]}); the delta is " + "already inside the weight and cannot be rescaled. Unmerge first, or use " + "merged_state_dict_at_scale on the unmerged model." + ) + original = [(m.adapters[adapter], m.adapters[adapter].scaling) for _, m in layers] + try: + for ad, s in original: + ad.scaling = s * k + yield len(layers) + finally: + for ad, s in original: + ad.scaling = s + + +def sweep( + model: nn.Module, + adapter: str, + eval_fn: Callable[[nn.Module], Any], + scales: Iterable[float] = DEFAULT_SCALES, +) -> dict[float, Any]: + """`{k: eval_fn(model)}` with the adapter delta scaled to k each time. `eval_fn` sees the live model.""" + out: dict[float, Any] = {} + for k in scales: + k = _check_scale(k) + if k in out: + raise ValueError(f"duplicate scale {k} in the sweep") + with scaled_adapter(model, adapter, k): + out[k] = eval_fn(model) + return out + + +def merged_state_dict_at_scale( + model: nn.Module, + full_state: dict[str, torch.Tensor], + adapter: str, + k: float, + report: Optional[dict] = None, + min_cosine: Optional[float] = None, +) -> dict[str, torch.Tensor]: + """`export_merged_state_dict` with the adapter delta scaled by `k` (the model is not mutated). + + k = 1.0 is bit-identical to `export_merged_state_dict`. k = 0 returns the base weights (every nonzero + delta is zero, so `report` has cosine 1.0 and delta_norm 0). `report["scale"]` records k. + """ + k = _check_scale(k) + rep: dict = {} + with scaled_adapter(model, adapter, k): + out = export_merged_state_dict(model, full_state, adapter, report=rep, min_cosine=min_cosine) + rep["scale"] = k + if report is not None: + report.update(rep) + return out diff --git a/code/align/train/moe_module.py b/code/align/train/moe_module.py new file mode 100644 index 0000000000000000000000000000000000000000..47d60891564061dc10145bc7b21275c46a952cfb --- /dev/null +++ b/code/align/train/moe_module.py @@ -0,0 +1,691 @@ +"""MoE auxiliary losses on the training seam: `MoETrainModule`. + +The model (`align.model.olmoe`) adds NO aux loss: it RETURNS per-layer router +statistics (`RouterStats`) when asked. This module is where those become a +training objective, because only the TrainModule sees all three things the +objective depends on: the loss adapter's CE (an opaque scalar), the +gradient-accumulation window (`grad_accum`), and the data-parallel group. + +THE MATH, and the one approximation in it +----------------------------------------- +Switch/OLMoE load balance, per layer: `E * sum_i f_i * P_i` with `f_i` the hard +top-k hit fraction (no gradient) and `P_i` the mean router probability +(gradient). Which batch `f_i` and `P_i` are measured over is the whole question +(Qiu et al., "Demons in the Detail"): per-micro-batch statistics over-constrain +the router when micro-batches are domain-homogeneous, because a sequence of +code must be allowed to use the code experts heavily. The loss should balance +over the GLOBAL batch -- every rank, every micro-batch of the optimizer step. + +Exact global `f_i` is not available at micro-batch `m`: the window's later +micro-batches have not been run, and their backward cannot be deferred without +retaining every micro-batch's activations. Demons' Algorithm 1 resolves it with +a BUFFER: keep the window's running (all-reduced) counts, and take `f_i` from +the buffer as it stands when micro-batch `m` runs. The approximation is +therefore confined to `f_i` of micro-batches 1..accum-1; at the LAST micro-batch +`f_i` is exactly the global-batch fraction, and the logged `moe/lb_loss` (computed +from the full buffer at the optimizer-step boundary) is exact. + +SCALING (why `world * m`). The Trainer divides each micro loss by `grad_accum` +and the gradient reduction averages over `world` ranks, so micro-batch `m` on +rank `r` reaches the weights with weight `1/(world*accum)`. For the window's +gradient to equal the gradient of ONE global loss +`E * sum_i f_i * (sum_{r,m} prob_sum_{r,m,i}) / N`, each term must be multiplied +by `world * accum / N_window`, and `N_window` (all valid tokens of the window) is +unknown until the end; estimated as `n_buf * accum / m` it gives +`world * m / n_buf`. At `m = accum` the estimate is exact. The same factor +scales the z-loss. In "micro" scope (the per-rank formulation, kept for +ablations) the factor is 1 and everything is local. + +WHAT IS ALL-REDUCED, and when. One packed float64 tensor per micro-batch +[counts L*E | tokens L | prob_sum L*E | z_sum L | entropy_sum L]. DETACHED data +only: the gradient of the loss is each rank differentiating its own +`prob_sum`/`z_sum`, never a gradient crossing ranks here. Every rank calls the +collective the same number of times (the Trainer runs micro-steps in lockstep), +and the buffer is reset at `optim_step()`, which the Trainer calls on every +boundary whether or not the optimizer applied the step. + +DEFAULTS. Load balance and z-loss are OFF for post-training stages and +0.01 / 0.001 for `pretrain` / `proxy` (see `MoEAuxConfig`); telemetry +(MaxVio, utilization, dead experts, router entropy) is logged either way. + +LIMITS (stated, not hidden) + * Adapters that run their own backward and return a detached proxy (the DPO + decoupled-backward adapter) cannot carry an aux loss: the router graph is + consumed by the adapter's backward. With a nonzero weight this raises; with + zero weights telemetry still works (it reads detached data). + * Not validated under FSDP2 on GPU (no GPU in this lane): the stats ride out + of the wrapped forward as plain dataclass fields rather than pytree leaves. + * The returned `LossOutput.loss` is the CE alone (comparable with dense runs). + If an aux term is non-finite the returned loss is NaN, so the Trainer's + non-finite-loss accounting sees it. + +EXPERT PARALLELISM (opt-in: `ep_groups`, default None = nothing below applies) +----------------------------------------------------------------------------- +`align.model.moe_ep` shards the experts across an EP group. The caller applies it +(`apply_expert_parallel(model, groups)`) BEFORE the optimizer is built -- the +optimizer must hold the shard parameters, and sharding after construction would +leave it stepping tensors that are no longer in the model. This module then does +the three things only the TrainModule can: + * the aux losses need NO change: the router is replicated, `RouterStats` come from + local tokens exactly as without EP, and `MoEAux` all-reduces them over the + DATA-parallel group (`group`), which contains the EP group. + * `optim_step` puts expert-shard gradients on the replicated-gradient scale + (`finalize_expert_grads`: they arrive SUMMED over the EP group) and clips by the + EP-GLOBAL norm (`clip_grads_`). The wrapped optimizer must therefore NOT clip + itself (`max_grad_norm` must be None): its norm would be shard-local, ranks would + clip by different coefficients and the replicated parameters would drift apart. + Pass the clip value as `ep_max_grad_norm`; `last_grad_norm` is the PRE-clip global. + * `full_model_state_dict` / `load_model_state_dict` gather / slice the expert shards + (a collective over the EP group), so a checkpoint is the same file a non-EP run writes. +""" + +from __future__ import annotations + +import logging +import math +from dataclasses import dataclass +from typing import Any, Optional + +import torch + +from ..config import MoEAuxConfig +from ..model import moe +from .train_module import LossAdapter, LossOutput, TrainModule + +logger = logging.getLogger(__name__) + +NAN = float("nan") + +#: (lb_weight, z_weight) per stage when the config leaves a weight as None. +#: Stages that train a router FROM SCRATCH balance it; everything else leaves +#: the pretrained router alone. See MoEAuxConfig for the argument. +STAGE_AUX_DEFAULTS: dict[str, tuple[float, float]] = { + "pretrain": (0.01, 0.001), + "proxy": (0.01, 0.001), +} +POST_TRAINING_AUX_DEFAULT = (0.0, 0.0) +LB_SCOPES = ("global", "micro") + + +def resolve_aux_weights(aux: MoEAuxConfig, stage: str) -> tuple[float, float]: + """(lb_weight, z_weight) after applying the stage default to any `None`.""" + d_lb, d_z = STAGE_AUX_DEFAULTS.get(stage, POST_TRAINING_AUX_DEFAULT) + lb = d_lb if aux.lb_weight is None else float(aux.lb_weight) + z = d_z if aux.z_weight is None else float(aux.z_weight) + for name, v in (("lb_weight", lb), ("z_weight", z)): + if not (math.isfinite(v) and v >= 0.0): + raise ValueError(f"moe_aux.{name}={v!r} must be a finite number >= 0") + if aux.lb_scope not in LB_SCOPES: + raise ValueError(f"moe_aux.lb_scope={aux.lb_scope!r}; known: {LB_SCOPES}") + return lb, z + + +# --------------------------------------------------------------------------- +# the window buffer (Demons Alg. 1) +# --------------------------------------------------------------------------- + + +@dataclass +class WindowTotals: + """Detached sums over (ranks x micro-batches so far): everything the aux + losses and the telemetry need, nothing with a gradient.""" + + counts: torch.Tensor # [L, E] float64: top-k hits + n_tokens: torch.Tensor # [L] float64: valid tokens + prob_sum: torch.Tensor # [L, E] float64: sum of softmax probs + z_sum: torch.Tensor # [L] float64: sum of lse^2 + entropy_sum: torch.Tensor # [L] float64 + + def __add__(self, o: "WindowTotals") -> "WindowTotals": + return WindowTotals( + self.counts + o.counts, + self.n_tokens + o.n_tokens, + self.prob_sum + o.prob_sum, + self.z_sum + o.z_sum, + self.entropy_sum + o.entropy_sum, + ) + + @classmethod + def of(cls, stats: list[moe.RouterStats]) -> "WindowTotals": + d = torch.float64 + return cls( + counts=torch.stack([s.counts for s in stats]).to(d), + n_tokens=torch.stack([s.n_tokens for s in stats]).to(d), + prob_sum=torch.stack([s.prob_sum.detach() for s in stats]).to(d), + z_sum=torch.stack([s.z_sum.detach() for s in stats]).to(d), + entropy_sum=torch.stack([s.entropy_sum.detach() for s in stats]).to(d), + ) + + def all_reduce(self, group=None) -> "WindowTotals": + """Sum over a process group in ONE collective (packed).""" + import torch.distributed as dist + + n_layers, e = self.counts.shape + packed = torch.cat( + [ + self.counts.reshape(-1), + self.n_tokens, + self.prob_sum.reshape(-1), + self.z_sum, + self.entropy_sum, + ] + ).contiguous() + dist.all_reduce(packed, group=group) + le = n_layers * e + o = 0 + counts = packed[o : o + le].reshape(n_layers, e) + o += le + n = packed[o : o + n_layers] + o += n_layers + ps = packed[o : o + le].reshape(n_layers, e) + o += le + z = packed[o : o + n_layers] + o += n_layers + ent = packed[o : o + n_layers] + return WindowTotals(counts, n, ps, z, ent) + + +def merge_call_stats(calls: list[list[moe.RouterStats]]) -> list[moe.RouterStats]: + """Combine the stats of several grad-enabled forwards of ONE micro-batch. + + One call (SFT, pretrain) is the identity. Several (a DPO adapter that runs + chosen and rejected separately) are summed per layer: they are different + token populations of the same optimizer step, so counts, probability sums, + z sums and token counts all ADD, and the losses are then over their union. + """ + if not calls: + raise ValueError("no router stats captured") + if len(calls) == 1: + return calls[0] + n_layers = len(calls[0]) + if any(len(c) != n_layers for c in calls): + raise ValueError(f"forwards returned different layer counts: {[len(c) for c in calls]}") + out = [] + for layer in range(n_layers): + parts = [c[layer] for c in calls] + out.append( + moe.RouterStats( + counts=sum(p.counts for p in parts), + prob_sum=sum(p.prob_sum for p in parts), + n_tokens=sum(p.n_tokens for p in parts), + z_sum=sum(p.z_sum for p in parts), + entropy_sum=sum(p.entropy_sum for p in parts), + ) + ) + return out + + +class MoEAux: + """The aux-loss math and the window buffer, independent of any Trainer. + + `micro(stats)` is called once per micro-batch, in lockstep on every rank, + and returns `(lb_term, z_term)` ALREADY scaled for the Trainer's + `/grad_accum` and the gradient reduction's mean over ranks (see the module + docstring). `window_end()` returns the exact global-window telemetry and + resets the buffer. + """ + + def __init__( + self, + top_k: int, + grad_accum: int, + *, + scope: str = "global", + group=None, + world_size: Optional[int] = None, + ): + if scope not in LB_SCOPES: + raise ValueError(f"scope {scope!r}; known: {LB_SCOPES}") + if grad_accum < 1: + raise ValueError(f"grad_accum must be >= 1, got {grad_accum}") + self.top_k = int(top_k) + self.grad_accum = int(grad_accum) + self.scope = scope + self.group = group + self._world = world_size + self.m = 0 # micro-batches seen in the current window + self.buf: Optional[WindowTotals] = None + + # -- world ---------------------------------------------------------- + def world(self) -> int: + if self._world is not None: + return self._world + import torch.distributed as dist + + if dist.is_available() and dist.is_initialized(): + return dist.get_world_size(self.group) + return 1 + + def _distributed(self) -> bool: + import torch.distributed as dist + + return dist.is_available() and dist.is_initialized() and self.world() > 1 + + def reset(self) -> None: + self.m = 0 + self.buf = None + + # -- one micro-batch -------------------------------------------------- + def micro( + self, stats: list[moe.RouterStats], want_lb: bool = True, want_z: bool = True + ) -> tuple[Optional[torch.Tensor], Optional[torch.Tensor]]: + if self.m >= self.grad_accum: + raise RuntimeError( + f"{self.m + 1} micro-batches in one accumulation window (grad_accum=" + f"{self.grad_accum}): optim_step()/reset() was not called at the boundary" + ) + self.m += 1 + local = WindowTotals.of(stats) + glob = local.all_reduce(self.group) if self._distributed() else local + self.buf = glob if self.buf is None else self.buf + glob + buf = self.buf + if not bool((buf.n_tokens > 0).all()): + raise ValueError( + "a MoE layer has seen zero valid tokens in this window: every position was masked. " + "The balance and z-losses are undefined over zero tokens (and returning 0.0 would " + "report a perfectly balanced router)." + ) + lb = z = None + if self.scope == "global": + scale = float(self.world() * self.m) + if want_lb: + lb = scale * moe.load_balancing_loss( + stats, + self.top_k, + global_totals=moe.Totals(counts=buf.counts, n_tokens=buf.n_tokens), + ) + if want_z: + # n_tokens is identical across layers (every layer routes the + # same valid tokens); the scalar is what router_z_loss takes. + z = scale * moe.router_z_loss(stats, loss_div_factor=buf.n_tokens[0]) + else: + if want_lb: + lb = moe.load_balancing_loss(stats, self.top_k) + if want_z: + z = moe.router_z_loss(stats) + return lb, z + + # -- the boundary ----------------------------------------------------- + def window_values(self) -> dict[str, Any]: + """Exact global-window quantities (float64 tensors) from the buffer.""" + buf = self.buf + if buf is None: + raise RuntimeError("window_values() before any micro-batch") + n_layers, e = buf.counts.shape + n = buf.n_tokens.unsqueeze(1) + f = buf.counts / (self.top_k * n) + p = buf.prob_sum / n + lb = (e * (f * p).sum(dim=1)).mean() + z = (buf.z_sum / buf.n_tokens).mean() + ent = buf.entropy_sum / buf.n_tokens + per_layer = [moe.expert_load_metrics(buf.counts[i]) for i in range(n_layers)] + return { + "lb": lb, + "z": z, + "entropy": ent, + "f": f, + "max_vio": torch.stack([d["max_vio"] for d in per_layer]), + "utilization": torch.stack([d["utilization"] for d in per_layer]), + "frac_dead": torch.stack([d["frac_dead"] for d in per_layer]), + "load_entropy": torch.stack([d["load_entropy"] for d in per_layer]), + } + + +def window_metrics(values: dict[str, Any], per_layer: bool = False) -> dict[str, float]: + """The `moe/*` history keys from `MoEAux.window_values()`. ONE host sync.""" + n_layers = int(values["max_vio"].numel()) + flat = torch.cat( + [ + values["lb"].reshape(1), + values["z"].reshape(1), + values["entropy"], + values["max_vio"], + values["utilization"], + values["frac_dead"], + values["load_entropy"], + ] + ).tolist() + lb, z = flat[0], flat[1] + o = 2 + ent = flat[o : o + n_layers] + o += n_layers + vio = flat[o : o + n_layers] + o += n_layers + util = flat[o : o + n_layers] + o += n_layers + dead = flat[o : o + n_layers] + o += n_layers + lent = flat[o : o + n_layers] + out = { + "moe/lb_loss": lb, + "moe/z_loss": z, + "moe/max_vio": sum(vio) / n_layers, + "moe/max_vio_worst": max(vio), + "moe/utilization": sum(util) / n_layers, + "moe/utilization_worst": min(util), + "moe/frac_dead_worst": max(dead), + "moe/load_entropy": sum(lent) / n_layers, + "moe/router_entropy": sum(ent) / n_layers, + } + if per_layer: + for i in range(n_layers): + out[f"moe/l{i}/max_vio"] = vio[i] + out[f"moe/l{i}/utilization"] = util[i] + return out + + +#: The keys a MoE run logs, NaN until the first window completes. Fixed set so +#: every history.jsonl row has the same columns. +def undefined_window_metrics(n_layers: Optional[int] = None, per_layer: bool = False) -> dict[str, float]: + keys = [ + "moe/lb_loss", + "moe/z_loss", + "moe/max_vio", + "moe/max_vio_worst", + "moe/utilization", + "moe/utilization_worst", + "moe/frac_dead_worst", + "moe/load_entropy", + "moe/router_entropy", + ] + out = {k: NAN for k in keys} + if per_layer and n_layers: + for i in range(n_layers): + out[f"moe/l{i}/max_vio"] = NAN + out[f"moe/l{i}/utilization"] = NAN + return out + + +# --------------------------------------------------------------------------- +# the model proxy +# --------------------------------------------------------------------------- + + +class _StatsModel: + """What the loss adapter is handed instead of the model. + + Adapters call `model(input_ids=..., hidden_consumer=...)` and expect the + loss (or logits) back. The proxy adds `return_router_stats=True` (only when + gradients are enabled -- a reference-model forward under `no_grad` has + nothing to balance), unwraps the `(out, stats)` tuple, and stashes the + stats for the module. Every other attribute is delegated, so adapters that + read `model.lm_head` or `model.attn_implementation` are unaffected. + """ + + def __init__(self, owner: "MoETrainModule"): + object.__setattr__(self, "_owner", owner) + object.__setattr__(self, "calls", []) + object.__setattr__(self, "attention_mask", None) + + def __call__(self, *args, **kwargs): + owner = self._owner + model = owner.model + want = torch.is_grad_enabled() + if want: + kwargs["return_router_stats"] = True + if kwargs.get("attention_mask") is None and self.attention_mask is not None: + # The batch's real-token mask: padding must not vote in the + # balance loss. The model's attention applies it too (a no-op + # for valid tokens under right padding, identical outputs). + kwargs["attention_mask"] = self.attention_mask + try: + out = model(*args, **kwargs) + except TypeError as e: + if want and "return_router_stats" in str(e): + raise RuntimeError( + "MoETrainModule needs a model whose forward accepts return_router_stats=True " + f"(got {type(model).__name__}); a dense model has no router to balance. " + "Set moe_aux weights to 0 and use the plain TrainModule." + ) from e + raise + if not want: + return out + out, stats = out + self.calls.append(stats) + return out + + def forward_hidden_states(self, **kwargs): + """Route `forward_hidden_states` through THIS proxy's `__call__`. + + The DPO adapter (coupled AND decoupled) never calls `model(...)`: it + calls `model.forward_hidden_states(...)`. Without this method the + attribute falls through `__getattr__` to the REAL model's bound method, + which runs without `return_router_stats`, so the adapter "ran no + grad-enabled forward" as far as the module can tell and the first + micro-step raises -- with default settings (telemetry on) on a stage + whose docstring promises telemetry still works. Mirrors + `OlmoeForCausalLM.forward_hidden_states`, which is `self(..., + return_hidden_states=True)`. + """ + return self(**kwargs, return_hidden_states=True) + + def __getattr__(self, name): + return getattr(self._owner.model, name) + + +# --------------------------------------------------------------------------- +# the train module +# --------------------------------------------------------------------------- + + +class MoETrainModule(TrainModule): + """`TrainModule` + router aux losses + MoE telemetry. + + `train_batch` does what the base does -- forward through the loss adapter, + then `(loss / grad_accum).backward()` -- with `loss = CE + lb_weight * lb + + z_weight * z`. See the module docstring for the window buffer and scaling. + """ + + def __init__( + self, + model, + loss_adapter: LossAdapter, + optimizer, + grad_accum: int, + *, + aux: Optional[MoEAuxConfig] = None, + stage: str = "sft", + top_k: Optional[int] = None, + weight_format=None, + group=None, + world_size: Optional[int] = None, + ep_groups=None, + ep_max_grad_norm: Optional[float] = None, + ): + super().__init__(model, loss_adapter, optimizer, grad_accum) + self.ep_groups = ep_groups + self.ep_max_grad_norm = ep_max_grad_norm + self._ep_norm = float("nan") + if ep_groups is not None: + self._check_expert_parallel(model, optimizer, ep_groups) + self.aux_cfg = aux or MoEAuxConfig() + self.stage = stage + self.lb_weight, self.z_weight = resolve_aux_weights(self.aux_cfg, stage) + if top_k is None: + top_k = getattr(getattr(model, "cfg", None), "top_k", None) + if top_k is None: + raise ValueError("top_k not given and model.cfg.top_k not found") + self.top_k = int(top_k) + self.weight_format = weight_format + self.collect = bool(self.aux_cfg.telemetry or self.lb_weight > 0 or self.z_weight > 0) + self._aux = MoEAux( + self.top_k, grad_accum, scope=self.aux_cfg.lb_scope, group=group, world_size=world_size + ) + self._proxy = _StatsModel(self) + self._last_metrics: dict[str, float] = {} + logger.info( + "MoE aux: stage=%s lb_weight=%g z_weight=%g scope=%s telemetry=%s top_k=%d", + stage, + self.lb_weight, + self.z_weight, + self.aux_cfg.lb_scope, + self.aux_cfg.telemetry, + self.top_k, + ) + + # -- expert parallelism (opt-in) --------------------------------------- + @staticmethod + def _check_expert_parallel(model, optimizer, groups) -> None: + """Refuse the three silent EP misconfigurations instead of training through them.""" + from ..model import moe_ep + + blocks = moe_ep._moe_blocks(model) + if not blocks or any(b.ep is None for b in blocks): + raise ValueError( + "ep_groups was given but the model's MoE blocks are not expert-parallel: call " + "align.model.moe_ep.apply_expert_parallel(model, groups) BEFORE building the optimizer" + ) + if any(b.ep.groups is not groups for b in blocks): + raise ValueError("ep_groups is not the group set the model was sharded with") + if getattr(optimizer, "max_grad_norm", None) is not None: + raise ValueError( + "the optimizer clips by its own (shard-local) gradient norm; under expert parallelism " + "that clips every rank by a different coefficient. Build it with max_grad_norm=None and " + "pass ep_max_grad_norm to MoETrainModule" + ) + + def optim_step(self) -> bool: + if self.ep_groups is not None: + from ..model import moe_ep + + moe_ep.finalize_expert_grads(self.model, self.ep_groups) + if self.ep_max_grad_norm is not None: + norm = moe_ep.clip_grads_(self.model, self.ep_groups, self.ep_max_grad_norm) + else: + norm = moe_ep.global_grad_norm(self.model, self.ep_groups) + self._ep_norm = float(norm) + try: + return super().optim_step() + finally: + self._aux.reset() + + @property + def last_grad_norm(self) -> float: + return self._ep_norm if self.ep_groups is not None else super().last_grad_norm + + def full_model_state_dict(self): + sd = super().full_model_state_dict() + if self.ep_groups is not None: + from ..model import moe_ep + + # the gather is a collective (every rank calls it); like the base state dict (rank 0 only + # when nothing is a DTensor) the result is merged where the base returned something + gathered = moe_ep.gather_full_expert_state(self.model, self.ep_groups, offload_to_cpu=True) + if sd: + for k, v in gathered.items(): + sd[k] = v.cpu() + return sd + + def load_model_state_dict(self, nmo_state: dict) -> None: + if self.ep_groups is not None: + from ..model import moe_ep + + nmo_state = {**nmo_state, **moe_ep.local_expert_slices(self.model, self.ep_groups, nmo_state)} + super().load_model_state_dict(nmo_state) + + # -- the loop-facing call --------------------------------------------- + def train_batch(self, batch) -> LossOutput: + if not self.collect: + return super().train_batch(batch) + + proxy = self._proxy + proxy.calls.clear() + mask = getattr(batch, "attention_mask", None) + proxy.attention_mask = mask if isinstance(mask, torch.Tensor) else None + out = self.loss_adapter(proxy, batch) + calls = list(proxy.calls) + proxy.calls.clear() + if not calls: + raise RuntimeError( + "the loss adapter ran no grad-enabled forward through the model, so no router " + "statistics exist; MoE aux losses/telemetry cannot be computed" + ) + stats = merge_call_stats(calls) + want_lb, want_z = self.lb_weight > 0, self.z_weight > 0 + lb, z = self._aux.micro(stats, want_lb=want_lb, want_z=want_z) + + ce = out.loss + total = ce + decoupled = ce.grad_fn is None + if want_lb or want_z: + if decoupled: + raise NotImplementedError( + "the loss adapter returned a detached proxy (decoupled backward, e.g. DPO): " + "its backward already consumed the model graph, so a router aux loss cannot " + "be added. Set moe_aux.lb_weight = z_weight = 0 for this stage " + "(telemetry still works)." + ) + if want_lb: + total = total + self.lb_weight * lb + if want_z: + total = total + self.z_weight * z + (total / self.grad_accum).backward() + + metrics = dict(out.metrics) + if self._aux.m == self.grad_accum: + vals = self._aux.window_values() + self._last_metrics = window_metrics(vals, per_layer=self.aux_cfg.per_layer_metrics) + elif not self._last_metrics: + self._last_metrics = undefined_window_metrics( + len(stats), per_layer=self.aux_cfg.per_layer_metrics + ) + metrics.update(self._last_metrics) + + reported = ce.detach() + if want_lb or want_z: + # 0 * finite = 0 (loss stays exactly CE); 0 * NaN/inf = NaN, so a + # poisoned aux term cannot hide behind a healthy CE. + reported = reported + 0.0 * (total.detach() - ce.detach()) + return LossOutput(loss=reported, n_tokens=out.n_tokens, metrics=metrics) + + def zero_grads(self) -> None: + super().zero_grads() + self._aux.reset() + + +def build_moe_train_module( + cfg, + model, + loss_adapter: LossAdapter, + optimizer, + *, + stage: str, + olmoe_cfg, + group=None, + ep_groups=None, + ep_max_grad_norm: Optional[float] = None, +) -> MoETrainModule: + """The MoE module for an OLMoE-architecture model, wired from a RunConfig. + + Carries the OLMoE weight format (the Trainer picks it up from the module), + `cfg.moe_aux` and `cfg.optimizer.grad_accum`. + """ + from .ckpt_format import OlmoeFormat + + return MoETrainModule( + model, + loss_adapter, + optimizer, + cfg.optimizer.grad_accum, + aux=cfg.moe_aux, + stage=stage, + top_k=olmoe_cfg.top_k, + weight_format=OlmoeFormat(olmoe_cfg), + group=group, + ep_groups=ep_groups, + ep_max_grad_norm=ep_max_grad_norm, + ) + + +__all__ = [ + "STAGE_AUX_DEFAULTS", + "POST_TRAINING_AUX_DEFAULT", + "resolve_aux_weights", + "WindowTotals", + "merge_call_stats", + "MoEAux", + "window_metrics", + "undefined_window_metrics", + "MoETrainModule", + "build_moe_train_module", +] diff --git a/code/align/train/offload_adamw.py b/code/align/train/offload_adamw.py new file mode 100644 index 0000000000000000000000000000000000000000..34016984e666a558e3e7bfa002ea4356cd4683e0 --- /dev/null +++ b/code/align/train/offload_adamw.py @@ -0,0 +1,680 @@ +"""Optimizer-state-only CPU offload for AdamW. + +The arithmetic that forces this design (measured on this box, not re-derived): +full fine-tuning 7.25B params with AdamW needs ~116GB of optimizer state -- +~29GB per GPU even fully sharded across 4 ranks, against a 23GB A10G budget. +Moving the state to host RAM fits it. Moving anything ELSE to host RAM does +not pay: FSDP's own `CPUOffloadPolicy` transfers parameters every forward AND +backward, while this transfers once per optimizer step, which at grad-accum 4 +is a quarter as often and overlappable with the next accumulation window. + +Measured cost (tmp/offload_bench.json): torch CPU AdamW (foreach) 2.56s per +1.81B-param rank shard; PCIe 13.2GB/s solo scaling to 52.7/53.9GB/s aggregate +across 4 ranks, giving ~0.82s of transfer per rank per optimizer step. At +grad-accum >= 4 that is an estimated 20-30% step-time overhead; at accum 1 it +would be 50-100%. This is WHY accum >= 4 is mandatory for full-FT, and the +Trainer refuses less. + +Design note on the update rule: the CPU step is torch's own `AdamW` driven +over the offloaded fp32 master copies, not a reimplementation. Bitwise +equivalence with `torch.optim.AdamW` is then a property of the construction +rather than something a test has to keep rediscovering after every torch +release -- and the test still catches the failures that actually happen here, +which are plumbing failures: a dropped weight_decay, a mis-forwarded beta, a +master copy that round-trips through a narrower dtype. +""" + +from __future__ import annotations + +import logging +from typing import Iterable, Optional, Sequence + +import torch + +logger = logging.getLogger(__name__) + +#: Optimizer identities this repo KNOWS. Adafactor is deliberately absent +#: and refused BY NAME -- see `make_optimizer`. +#: +#: `adamw8bit` is BUILDABLE again: `align/train/adamw8bit.py` is a torch-only +#: block-wise 8-bit AdamW (the bitsandbytes dependency stays banned; see +#: docs/DEPENDENCY_POLICY.md). The distinction between "a typo'd optimizer +#: name" and "a known optimizer" must still survive in the error text: the +#: former is `ValueError("unknown optimizer")`. +KNOWN_OPTIMIZERS = ("offload_adamw", "adamw8bit") + +#: The default optimizer in `RunConfig` and the one the pinned-staging budget +#: and the RSS projection model. Every SHIPPED full-FT config overrides it to +#: `adamw8bit`, because at 7.25B params / 4 ranks the host cannot hold this +#: optimizer's state (see adamw8bit.py for the arithmetic). +OPTIMIZER_OF_RECORD = "offload_adamw" + + +def pinned_staging_bytes(cfg) -> float: + """Total pinned staging budget across all ranks, DERIVED from the config. + + One fp32 layer-shard is `n_params / n_layers / world_size` elements at 4 + bytes; each rank is allowed `pinned_staging_shards_per_rank` of them. + + Pinned memory is unswappable and unreclaimable, and this box has no swap, + so this is a hard budget rather than an estimate. It is the same formula + `guard.projected_full_ft_rss_gb` uses for the RSS projection -- deliberately + the same, so the launch banner and the preflight cannot disagree about how + much host RAM the job intends to lock down. + """ + if cfg.model.n_params <= 0: + raise ValueError( + f"model.n_params={cfg.model.n_params} is not a parameter count, so " + "there is no staging budget to derive. The tiny CI config sets it " + "to -1 deliberately (the 7B projection does not apply there); a " + "negative budget must raise rather than silently become a negative " + "cap that every allocation trivially satisfies." + ) + world = cfg.train.world_size + layer_shard_bytes = cfg.model.n_params / cfg.model.n_layers / world * 4.0 + return layer_shard_bytes * cfg.train.pinned_staging_shards_per_rank * world + + +class OffloadAdamW: + """AdamW whose state lives on the host; params and grads never move. + + `step()` returns False when the grad-skip gate refused the step. + """ + + def __init__( + self, + params: Iterable[torch.Tensor], + lr: float, + betas: tuple[float, float] = (0.9, 0.95), + eps: float = 1e-8, + weight_decay: float = 0.0, + pinned_staging_cap_bytes: Optional[float] = None, + overlap: bool = True, + state_device: str = "cpu", + max_grad_norm: Optional[float] = None, + ) -> None: + self.params: list[torch.Tensor] = list(params) + if not self.params: + raise ValueError("OffloadAdamW got an empty parameter list") + if max_grad_norm is not None and not (float(max_grad_norm) > 0.0): + raise ValueError( + f"max_grad_norm must be a positive float or None, got {max_grad_norm!r}" + ) + #: GLOBAL-norm clip (`clip_grad_norm_`'s rule, `min(1, c / (norm + 1e-6))`), + #: None = no clipping. THE SILENT-NO-CLIP DEFECT (H2 review, 2026-10-13): + #: `OptimizerConfig.max_grad_norm` defaults to 1.0 and every shipped TOML + #: states it, but this class had no such parameter and `make_optimizer` + #: never forwarded the field -- the one optimizer of record for full-FT + #: ran UNCLIPPED while `BlockwiseAdamW8bit` honoured the same config. + #: `last_grad_norm` stays the PRE-clip norm (the tripwires must see an + #: explosion, not its clipped image). + self.max_grad_norm = None if max_grad_norm is None else float(max_grad_norm) + self.state_device = torch.device(state_device) + self.overlap = bool(overlap) + self.banner_tag = "offload_adamw" + + # THIS RANK'S bytes, so the staging cap is a per-rank quantity. Under + # FSDP2 every parameter is a DTensor whose `.numel()` is the GLOBAL + # element count: a world-size-times overcount that would have refused + # (or, worse, mis-banner) any sharded job. + self.staging_bytes_required = float( + sum(self._localize(p).numel() * 4 for p in self.params) + ) + self.pinned_staging_cap_bytes = pinned_staging_cap_bytes + if ( + pinned_staging_cap_bytes is not None + and self.staging_bytes_required > pinned_staging_cap_bytes + ): + raise ValueError( + f"pinned staging would need " + f"{self.staging_bytes_required / 2**30:.2f}GiB but the cap is " + f"{pinned_staging_cap_bytes / 2**30:.2f}GiB. Pinned memory is " + "unswappable and this box has no swap: exceeding the budget " + "does not degrade, it wedges the host. Lower " + "train.pinned_staging_shards_per_rank or shard further." + ) + + # fp32 master copies on the host. These are the AUTHORITATIVE weights: + # the device params are a bf16 view of them, refreshed every step. + self._pin = torch.cuda.is_available() and self.state_device.type == "cpu" + # THE FSDP2 DTENSOR DEFECT (found in the align port review, 2026-10-12; + # the predecessor never hit it because the shard-local 8-bit optimizer + # was the one that actually ran on FSDP2 parameters). Under `fully_shard` + # `model.parameters()` yields DTensors, and OffloadAdamW died on them + # twice: `is_pinned()` has no DTensor sharding rule at construction, + # and the grad-norm accumulator mixed a DTensor into a plain tensor at + # the first step. Masters, grads and the H2D copy-back therefore all go + # through `_localize` -- this rank's shard, a storage-sharing view -- the + # same contract `ShardLocalAdamW8bit` documents (AdamW is elementwise, + # so stepping the local shard is exact). + self._master = [ + self._host_tensor(self._localize(p).detach().to(torch.float32)) for p in self.params + ] + self._inner = torch.optim.AdamW( + self._master, + lr=lr, + betas=betas, + eps=eps, + weight_decay=weight_decay, + ) + + self.skipped_steps = 0 + self.last_grad_norm = float("nan") + logger.info( + "OffloadAdamW: %d tensors, %.2fGiB fp32 master on %s (pinned=%s), " + "staging %.2fGiB, overlap=%s", + len(self.params), + sum(m.numel() * 4 for m in self._master) / 2**30, + self.state_device, + self._pin, + self.staging_bytes_required / 2**30, + self.overlap, + ) + + # -- host staging ------------------------------------------------------- + + @staticmethod + def _localize(t): + """This rank's local shard of an FSDP2 DTensor (a view sharing the + parameter's storage), or `t` itself for an ordinary tensor.""" + return t.to_local() if hasattr(t, "to_local") else t + + def _host_tensor(self, t: torch.Tensor) -> torch.Tensor: + out = t.to(self.state_device, copy=True) + if self._pin and not out.is_pinned(): + out = out.pin_memory() + return out + + # -- the step ----------------------------------------------------------- + + def step(self) -> bool: + """One optimizer step, or a refusal. + + Order matters and is load-bearing: finiteness is checked BEFORE any + state is touched. An implementation that discovers the NaN after + updating the moments has already poisoned the second-moment estimate, + and every subsequent step is scaled by it. + """ + grads = [None if p.grad is None else self._localize(p.grad) for p in self.params] + if all(g is None for g in grads): + raise RuntimeError( + "OffloadAdamW.step() called with no gradients on any parameter. " + "A step that silently does nothing is indistinguishable from a " + "run that trained." + ) + + if not self._all_finite(grads): + self.skipped_steps += 1 + # NaN, not 0.0: the norm of a non-finite gradient is undefined, and + # a 0.0 in the log reads as 'perfectly converged'. + self.last_grad_norm = float("nan") + logger.warning( + "grad-skip gate: non-finite gradient, skipping optimizer step " + "(%d skipped so far). Moments and step counts left untouched.", + self.skipped_steps, + ) + return False + + self.last_grad_norm = self._grad_norm(grads) # PRE-clip, on purpose + + # `_grad_norm` all-reduces the sum of squares, so `coef` is the same on + # every rank: each rank scales its own disjoint shard by the GLOBAL factor. + coef = 1.0 + if self.max_grad_norm is not None: + coef = min(1.0, self.max_grad_norm / (self.last_grad_norm + 1e-6)) + + # D2H: fp32 grads into the host staging that backs the master copies. + for master, g in zip(self._master, grads): + if g is None: + master.grad = None + continue + master.grad = self._host_tensor(g.detach().to(torch.float32)) + if coef != 1.0: + master.grad.mul_(coef) + + self._inner.step() + + # H2D: updated master back into the device params, in their own dtype. + # copy_ keeps the storage identity FSDP's shard views depend on. + with torch.no_grad(): + for p, master in zip(self.params, self._master): + local = self._localize(p).detach() + local.copy_(master.to(local.dtype)) + return True + + def zero_grad(self, set_to_none: bool = True) -> None: + for p in self.params: + if set_to_none: + p.grad = None + elif p.grad is not None: + p.grad.zero_() + for m in self._master: + m.grad = None + + def _all_finite(self, grads: Sequence[Optional[torch.Tensor]]) -> bool: + """Global finiteness. Under FSDP a rank whose shard is finite must not + step while a peer's is not: the peers would diverge silently and only + surface as an NCCL mismatch much later, if at all.""" + local = True + for g in grads: + if g is not None and not bool(torch.isfinite(g).all()): + local = False + break + return bool(self._all_reduce_flag(local)) + + @staticmethod + def _collective_device() -> torch.device: + """The device a tensor must live on to join a collective on the default + process group: this rank's OWN cuda device under NCCL (a bare .cuda() + would put every rank's tensor on device 0 and reduce the wrong ones), + CPU under gloo. Keyed on the group's backend, not on + `torch.cuda.is_available()`: a gloo group on a box that happens to have + GPUs would otherwise be handed a cuda tensor it cannot reduce.""" + import torch.distributed as dist + + if "nccl" in str(dist.get_backend()).lower() and torch.cuda.is_available(): + from ..utils.dist import local_rank + + return torch.device("cuda", local_rank()) + return torch.device("cpu") + + @staticmethod + def _all_reduce_flag(local: bool) -> bool: + import torch.distributed as dist + + if not dist.is_available() or not dist.is_initialized(): + return local + flag = torch.tensor([1.0 if local else 0.0], device=OffloadAdamW._collective_device()) + dist.all_reduce(flag, op=dist.ReduceOp.MIN) + return bool(flag.item() > 0.0) + + @staticmethod + def _grad_norm(grads: Sequence[Optional[torch.Tensor]]) -> float: + """The GLOBAL L2 norm of the gradient, identical on every rank. + + Accumulate on the GRADS' device, not on CPU: the accumulator used to be + a bare `torch.zeros((), dtype=float64)`, a CPU tensor, which broke the + moment the shard-local 8-bit optimizer called it with CUDA grads: + "Expected all tensors to be on the same device, but found cuda:0 and cpu". + + THE SHARD-LOCAL NORM DEFECT (align port review, 2026-10-12). Under FSDP2 + each rank holds a DISJOINT 1/world slice of every gradient, so the sum of + squares over the local slice is a norm of a quarter of the gradient -- + and a different number on every rank. `GradNormTripwire` is a HALT wire + reading this value: a rank-local norm lets ONE rank cross the ceiling and + raise while its peers continue into the next collective (a hang until the + NCCL watchdog), and it under-reads a true explosion by ~sqrt(world). The + sum of squares is therefore all-reduced (SUM) before the root. Every + rank reaches this call together or not at all, because the finiteness + gate that precedes it is itself a collective. + """ + import torch.distributed as dist + + present = [g for g in grads if g is not None] + distributed = dist.is_available() and dist.is_initialized() + if not present and not distributed: + return float("nan") + device = present[0].device if present else torch.device("cpu") + total = torch.zeros((), dtype=torch.float64, device=device) + for g in present: + total += g.detach().to(torch.float64).pow(2).sum() + if distributed: + total = total.to(OffloadAdamW._collective_device()) + dist.all_reduce(total, op=dist.ReduceOp.SUM) + return float(total.sqrt()) + + # -- introspection ------------------------------------------------------ + + def describe_placement(self) -> dict: + """Where every tensor actually lives. Consumed by the launch banner and + by the device-partition test; a placement claim nobody checks is how + 'the state is offloaded' becomes untrue after a refactor.""" + + def entry(t: torch.Tensor) -> dict: + return { + "device": t.device.type, + "dtype": str(t.dtype), + "pinned": bool(t.is_pinned()) if t.device.type == "cpu" else False, + "bytes": t.numel() * t.element_size(), + } + + state = [] + for group in self._inner.state.values(): + for key, v in group.items(): + if isinstance(v, torch.Tensor): + state.append({"key": key, **entry(v)}) + return { + "state": state, + "master": [entry(m) for m in self._master], + "params": [entry(self._localize(p)) for p in self.params], + "staging_bytes_required": self.staging_bytes_required, + "pinned_staging_cap_bytes": self.pinned_staging_cap_bytes, + } + + def state_snapshot_for_tests(self) -> dict: + """Flat clone of every optimizer-state tensor, including the step + counts. Tests assert these are byte-identical across a skipped step.""" + out = {} + for i, p in enumerate(self._master): + for key, v in self._inner.state.get(p, {}).items(): + out[f"{i}.{key}"] = ( + v.detach().clone() if isinstance(v, torch.Tensor) else torch.tensor(float(v)) + ) + return out + + # -- resume ------------------------------------------------------------- + + def state_dict(self) -> dict: + """A DETACHED CLONE of every state tensor, on CPU. + + THE SHARED-STATE ALIASING INCIDENT. Two traps stack here, and both are + silent: + + 1. `torch.optim.Optimizer.state_dict()` returns per-param dicts that + SHARE the live state tensors, and `.to("cpu")` on a tensor already + on CPU returns the same object -- so a state dict built without + clones is a live view of the optimizer, not a snapshot of it. + 2. Mutating that returned dict in place (to clone the values) rebinds + the optimizer's OWN state entries, so the "snapshot" aliases the + live state no matter which order you do it in. + + The result of getting this wrong is not a crash: `load_state_dict` + hands the loaded optimizer the same `step`/`exp_avg`/`exp_avg_sq` + objects the source still holds, both mutate them every step, Adam's + step counter advances twice per step, and the two runs diverge while + every state comparison between them says they are identical. + + So this builds a NEW nested structure and never touches what the inner + optimizer returned. + """ + inner = self._inner.state_dict() + return { + "param_groups": inner["param_groups"], + "state": { + idx: { + k: (v.detach().to("cpu").clone() if isinstance(v, torch.Tensor) else v) + for k, v in group.items() + } + for idx, group in inner["state"].items() + }, + "master": [m.detach().to("cpu").clone() for m in self._master], + "skipped_steps": self.skipped_steps, + } + + def load_state_dict(self, sd: dict) -> None: + """Restore moments AND master weights, then refresh the device params. + + The master is the authoritative weight copy, so a resume that restored + only the moments would carry the pre-checkpoint parameters forward -- + a run that looks like it resumed and is training a different model. + """ + masters = sd.get("master") + if masters is None: + raise KeyError( + "optimizer state_dict has no 'master' entry; refusing to " + "resume from a checkpoint that carries moments but not the " + "fp32 master weights." + ) + if len(masters) != len(self._master): + raise ValueError( + f"checkpoint has {len(masters)} master tensors but this " + f"optimizer holds {len(self._master)}" + ) + with torch.no_grad(): + for dst, src in zip(self._master, masters): + dst.copy_(src.to(dst.dtype)) + for p, master in zip(self.params, self._master): + local = self._localize(p).detach() + local.copy_(master.to(local.dtype)) + # Clone on the way IN as well: torch stores these objects directly when + # no dtype/device cast is needed, so loading one checkpoint dict into + # two optimizers would otherwise make them share moments. Symmetric + # with the cloning in state_dict(), and for the same reason. + inner_sd = { + "param_groups": sd["param_groups"], + "state": { + idx: { + k: (v.detach().clone() if isinstance(v, torch.Tensor) else v) + for k, v in group.items() + } + for idx, group in sd["state"].items() + }, + } + self._inner.load_state_dict(inner_sd) + self.skipped_steps = int(sd.get("skipped_steps", 0)) + + def reseed_masters_from_params(self) -> None: + """Overwrite the fp32 masters with the CURRENT device params (audit U01-2). + + The master is authoritative: every step rewrites the params from it. A resume that loads + weights but no optimizer state (a legacy checkpoint, `reshard(drop_optimizer=True)`) would + otherwise leave the masters at the LAUNCH weights and the first step would silently revert + the restored model. Moments stay fresh; only the master copy is re-seeded. + """ + with torch.no_grad(): + for p, master in zip(self.params, self._master): + master.copy_(self._localize(p).detach().to(torch.float32)) + + @property + def param_groups(self): + """Exposed so a torch LR scheduler can drive this optimizer directly.""" + return self._inner.param_groups + + +class ShardLocalAdamW8bit: + """Compatibility shim: the legacy name for the shard-local 8-bit AdamW. + + The optimizer itself is `align.train.adamw8bit.BlockwiseAdamW8bit` (pure + torch; `make_optimizer` returns THAT directly). This class keeps the + legacy wrapper shape -- `_inner`, `_pairs`, and a `state_dict` that wraps + the inner state with `world_size`/`n_shards` -- because two invariants are + regression-tested against that shape WITHOUT constructing the class + (tests build a stub via `__new__` and hand it a fake `_inner`): + + * the recursive CPU clone: a one-level clone once passed ~3.2GB of live + CUDA moments straight into the checkpoint pickle, and `gather_object` + restored them onto the SENDER'S device on rank 0 and OOM'd the DPO + run at its first checkpoint; + * the world-size refusal: the saved state is SHARD-shaped, and reloading + it under a different world size would silently align rank r's moments + to a different slice of the parameter. + + WHY SHARD-LOCAL STEPPING IS EXACT, not an approximation: AdamW is + ELEMENTWISE. Every update depends only on that element's own gradient and + its own two moment scalars, so there is nothing for a shard boundary to + cut. (This is exactly what Adafactor cannot claim, and why Adafactor is + banned here: its factored second moment is a row/column statistic that + DOES cross shard boundaries.) `to_local()` is a VIEW sharing storage with + the DTensor, so stepping it updates the parameter -- measured on 4 real + ranks: storage pointers stable across calls and steps, and the DTensor + observes the update. + + HISTORY: the first version wrapped bitsandbytes, whose fused kernel + cannot consume DTensors ("optimizer_update_8bit_blockwise got mixed + torch.Tensor and DTensor"), and was then retired with the dependency. It + is now a thin delegate to the in-repo implementation, which does the + gating, the GLOBAL grad norm and the state handling itself; the shim only + mirrors `skipped_steps` / `last_grad_norm` so legacy readers keep working. + """ + + def __init__( + self, + params: Iterable[torch.Tensor], + lr: float, + betas: tuple[float, float] = (0.9, 0.95), + eps: float = 1e-8, + weight_decay: float = 0.0, + ): + # Consume the parameter iterable first so a generator-backed caller + # (`model.parameters()`) behaves the same however it is used, and + # validate the empty case before anything is built. + params = list(params) + if not params: + raise ValueError("ShardLocalAdamW8bit got an empty parameter list") + # Lazy: adamw8bit imports this module at top level (it reuses the + # collective helpers), so the reverse import cannot be top-level. + from .adamw8bit import BlockwiseAdamW8bit + + self._inner = BlockwiseAdamW8bit( + params, lr=lr, betas=betas, eps=eps, weight_decay=weight_decay + ) + self._pairs = [(p, self._localize(p).detach()) for p in params] + self.skipped_steps = 0 + self.last_grad_norm = float("nan") + self.banner_tag = self._inner.banner_tag + + @staticmethod + def _localize(t): + return t.to_local() if hasattr(t, "to_local") else t + + def step(self) -> bool: + """One optimizer step, or a refusal. Same contract as OffloadAdamW. + + Gating, the global grad norm and the update all live in the inner + optimizer; doing them here too would pay the collectives twice.""" + stepped = self._inner.step() + self.skipped_steps = self._inner.skipped_steps + self.last_grad_norm = self._inner.last_grad_norm + return stepped + + def zero_grad(self, set_to_none: bool = True) -> None: + for p, local in self._pairs: + p.grad = None if set_to_none else p.grad + local.grad = None + + def state_dict(self) -> dict: + from ..utils.dist import world_size + + inner = self._inner.state_dict() + + # DETACHED CPU CLONES, RECURSIVELY -- same two aliasing traps + # OffloadAdamW.state_dict documents, plus the one that survived the + # first fix: bnb nests its real tensors under + # state[idx]["__bnb_optimizer_quant_state__"], a dict, so a one-level + # clone passed ~3.2GB of live CUDA moments straight into the pickle. + # gather_object then restored them onto the SENDER'S device on rank 0 + # and OOM'd the DPO run at its first checkpoint (SFT's end-save + # survived the same bug on VRAM headroom alone). + def _to_cpu(o): + if isinstance(o, torch.Tensor): + return o.detach().to("cpu").clone() + if isinstance(o, dict): + return {k: _to_cpu(v) for k, v in o.items()} + if isinstance(o, (list, tuple)): + return type(o)(_to_cpu(v) for v in o) + return o + + return { + "inner": _to_cpu(inner), + "world_size": world_size(), + "n_shards": len(self._pairs), + "skipped_steps": self.skipped_steps, + } + + def load_state_dict(self, sd: dict) -> None: + from ..utils.dist import world_size + + saved_ws, now_ws = sd.get("world_size"), world_size() + if saved_ws is not None and saved_ws != now_ws: + raise ValueError( + f"this optimizer state was saved at world_size={saved_ws} but " + f"the current run has world_size={now_ws}. The 8-bit moments " + "are SHARD-shaped: loading them under a different world size " + "would align each rank's state to a different slice of the " + "parameter, and training would continue plausibly on " + "corrupted state. Resume at the original world size, or start " + "fresh." + ) + saved_n = sd.get("n_shards") + if saved_n is not None and saved_n != len(self._pairs): + raise ValueError( + f"checkpoint holds {saved_n} shards, this optimizer has {len(self._pairs)}" + ) + self._inner.load_state_dict(sd["inner"]) + self.skipped_steps = int(sd.get("skipped_steps", 0)) + + @property + def param_groups(self): + return self._inner.param_groups + + +def make_optimizer(cfg, params: Iterable[torch.Tensor]): + """Build the optimizer named by the config, and tag it for the banner. + + Which optimizer actually ran is recorded in the banner: a run that used a + different optimizer than its config names is not reproducible from that + config. + + `adamw8bit` is the pre-registered on-device fallback for the case where + host RAM cannot hold the offloaded state (every shipped full-FT config + names it). It is the in-repo torch-only `BlockwiseAdamW8bit`; the banner + states its state size from the RANK-LOCAL element count + (`2*n + 8*n/block` bytes), so the launch log cannot claim a footprint the + optimizer does not have. It is never silently swapped for `offload_adamw`: + a run whose banner says one optimizer while the config names another is + exactly the irreproducibility this function exists to prevent. + """ + name = cfg.optimizer.name + lowered = str(name).lower() + + if lowered == "adafactor": + raise ValueError( + "Adafactor is BANNED in this repo. Its factored second moment " + "crosses DTensor shard boundaries: under ZeRO-3 on this box it " + "produced a perfect-looking loss curve while moving ~1% of " + "tensors -- a run that trained nothing and reported success for " + "hours. AdamW only (offload_adamw is the optimizer of record)." + ) + if lowered not in KNOWN_OPTIMIZERS: + raise ValueError( + f"unknown optimizer {name!r}; known: {list(KNOWN_OPTIMIZERS)}. " + "A typo must not fall through to a default -- the whole point of " + "naming the optimizer in the config is that the banner can state " + "which one ran." + ) + + o = cfg.optimizer + if lowered == "offload_adamw": + # The staging cap is a full-FT host-RAM budget. The tiny CPU harness + # has no layer shards to size it from (n_params = -1), so it runs + # uncapped rather than against a fabricated number. + cap = pinned_staging_bytes(cfg) if cfg.train.full_ft else None + opt = OffloadAdamW( + params, + lr=o.lr, + betas=tuple(o.betas), + eps=o.eps, + weight_decay=o.weight_decay, + pinned_staging_cap_bytes=cap, + max_grad_norm=getattr(o, "max_grad_norm", None), + ) + opt.banner_tag = ( + f"offload_adamw (fp32 master + moments on host, " + f"{opt.staging_bytes_required / 2**30:.2f}GiB staging)" + ) + return opt + + # Only 'adamw8bit' can reach here (unknown names raised above). + # Lazy import: adamw8bit imports this module for the collective helpers. + from .adamw8bit import BlockwiseAdamW8bit + + opt = BlockwiseAdamW8bit( + params, + lr=o.lr, + betas=tuple(o.betas), + eps=o.eps, + weight_decay=o.weight_decay, + # OptimizerConfig.max_grad_norm (default 1.0), same rule and same pre-clip + # `last_grad_norm` record as the offload_adamw branch above. + max_grad_norm=getattr(o, "max_grad_norm", None), + ) + n_local = sum(s["numel"] for s in opt._state) + state_bytes = BlockwiseAdamW8bit.projected_state_bytes( + [s["numel"] for s in opt._state], opt.block_size, opt.min_8bit_size + ) + opt.banner_tag = ( + f"adamw8bit (block-wise 8-bit moments ON DEVICE, block {opt.block_size}, " + f"{state_bytes / 2**30:.2f}GiB state for {n_local / 1e6:.1f}M local params " + f"= 2B + 8B/block per param; no master copy; zero host RSS)" + ) + return opt diff --git a/code/align/train/probes.py b/code/align/train/probes.py new file mode 100644 index 0000000000000000000000000000000000000000..c80512613400437011ba4864572d0025acdec83a --- /dev/null +++ b/code/align/train/probes.py @@ -0,0 +1,627 @@ +"""Probes and tripwires: the checks a loss curve cannot make. + +Every mechanism here exists because the predecessor shipped through the +failure it detects, with healthy-looking metrics the whole way: + + * TRUNK MOVEMENT. Reentrant gradient checkpointing silently zeroes trunk + gradients under sharding. The run trains -- loss falls, throughput is + normal -- while only the embeddings and the LM head move. Nothing in the + loss, the grad norm, or the throughput distinguishes it from a healthy + run, so the probe compares actual parameter values and RAISES at the first + log step rather than warning at the hundredth. + * logps/chosen DECLINE. DPO's objective only asks for a MARGIN, which is + equally well served by pushing the rejected logprob down as by pulling the + chosen one up. When it takes the second route the model gets better at the + loss and worse at the task. Maximal for Arm B by design, since pi_SFT + already assigns the chosen sequence high likelihood. + * LENGTH DRIFT. Preference optimization has a documented length bias. The + alarm is baseline-RELATIVE (Arm A measured 54.9% chosen-longer), because + an absolute threshold says nothing about a dataset whose baseline is not + 50%. + +Tripwires are pure functions over metric windows, so they are tested without a +model. NaN in means NaN out and never a trip: a NaN coerced to 0.0 reads as +'flat', and flat-chosen-with-rising-margin is itself the alarm condition. +""" + +from __future__ import annotations + +import logging +import math +from dataclasses import dataclass, field +from typing import Any, Optional, Sequence + +import torch + +logger = logging.getLogger(__name__) + +NAN = float("nan") + +#: Parameter-name fragments that are NOT trunk. The probe must exclude them: +#: the incident's signature is "head and embeddings moved, trunk did not", so +#: a probe that tracked them would call that run healthy. +NON_TRUNK_FRAGMENTS = ("embed_tokens", "lm_head", "embed_out", "wte", "wpe") + + +class TrunkMovementProbe: + """Snapshot trunk parameters, then assert they actually moved.""" + + def __init__(self, model, max_tracked: int = 16, seed: int = 0): + self._model = model + self.tracked_names: list[str] = [] + self._snapshots: list[torch.Tensor] = [] + + # Only TRAINABLE parameters can move. On a LoRA/partially-frozen model a + # stride that landed on frozen base weights would report "trunk frozen" + # on a perfectly healthy run (found in the PPO port: the probe was + # rebuilt on the real model at resume and tracked frozen tensors). + candidates = [ + (n, p) + for n, p in model.named_parameters() + if p.requires_grad and not any(f in n for f in NON_TRUNK_FRAGMENTS) + ] + if not candidates: + raise ValueError( + "TrunkMovementProbe found no trunk parameters to track " + f"(every TRAINABLE parameter was absent or matched {NON_TRUNK_FRAGMENTS}). It cannot report " + "'no movement' on an empty set -- that is the alarm condition, " + "and reporting it from nothing would be a false alarm forever." + ) + # Deterministic even sample across depth, so a probe on a 32-layer + # model does not track 16 tensors from layer 0. + stride = max(1, len(candidates) // max_tracked) + for name, p in candidates[::stride][:max_tracked]: + self.tracked_names.append(name) + self._snapshots.append(self.snapshot_tensor(p)) + self.n_tracked = len(self._snapshots) + + def release(self) -> None: + """Drop the model reference and the snapshots (U01-11): the probe is dead after the + post-train handoff and must not keep the training replica alive.""" + self._model = None + self._snapshots = [] + + @staticmethod + def snapshot_tensor(t: Any) -> torch.Tensor: + """Detached CPU copy of a parameter, reaching through DTensor. + + Under FSDP2 every sharded parameter is a DTensor whose global view is + an unmaterialised placeholder; `.to_local()` is the rank's actual + shard. Comparing global views would compare something that never + changes on this rank. + """ + if hasattr(t, "to_local"): + t = t.to_local() + if hasattr(t, "detach"): + t = t.detach() + return t.to("cpu", copy=True).to(torch.float32) + + def check(self, step: int, model=None, raise_on_frozen: bool = True) -> dict: + """Compare against the snapshot. Zero movement RAISES.""" + target = model or self._model + if target is None: + raise RuntimeError("TrunkMovementProbe.check after release(): the model reference was dropped") + current = dict(target.named_parameters()) + tensors = [current[n] for n in self.tracked_names] + deltas = [] + for snap, t in zip(self._snapshots, tensors): + now = self.snapshot_tensor(t) + deltas.append((now - snap).abs().max().item()) + + moved = sum(1 for d in deltas if d > 0.0) + report = { + "step": step, + "n_tracked": self.n_tracked, + "moved_fraction": moved / self.n_tracked if self.n_tracked else NAN, + "max_abs_delta": max(deltas) if deltas else NAN, + "tracked_names": list(self.tracked_names), + } + if moved == 0 and raise_on_frozen: + raise RuntimeError( + f"TRUNK MOVEMENT PROBE FAILED at step {step}: not one of " + f"{self.n_tracked} tracked trunk parameters changed by any " + "amount since step 0.\n\nThis is the reentrant-checkpointing " + "incident: `torch.utils.checkpoint` with use_reentrant=True " + "silently zeroes trunk gradients under sharding, and the run " + "keeps training the embeddings and the LM head while the body " + "stays frozen. Loss still falls. Throughput is normal. Nothing " + "else detects it.\n\nCheck that activation checkpointing was " + "wrapped with use_reentrant=False, that the trunk parameters " + "are in the optimizer's param groups, and that requires_grad " + f"is set on them. Tracked: {self.tracked_names[:4]}..." + ) + logger.info( + "trunk probe ok at step %d: %d/%d moved, max|d|=%.3e", + step, + moved, + self.n_tracked, + report["max_abs_delta"], + ) + return report + + +# --------------------------------------------------------------------------- +# tripwires +# --------------------------------------------------------------------------- + + +@dataclass +class TripwireResult: + tripped: bool + response: str + value: float = NAN + logps_slope: float = NAN + margin_slope: float = NAN + detail: str = "" + + +def _slope(values: Sequence[float]) -> float: + """Least-squares slope over an evenly spaced window. NaN anywhere in the + window makes the slope NaN -- a window with missing data has no trend, and + pretending otherwise is how a tripwire fires on absent measurements.""" + n = len(values) + if n < 2 or any(math.isnan(v) for v in values): + return NAN + xs = list(range(n)) + mx = sum(xs) / n + my = sum(values) / n + denom = sum((x - mx) ** 2 for x in xs) + if denom == 0: + return NAN + return sum((x - mx) * (y - my) for x, y in zip(xs, values)) / denom + + +class LogpsChosenTripwire: + """Fires when PER-TOKEN chosen NLL rises materially while the margin improves. + + R2 RECALIBRATION (2026-08-23 audit; docs/audits/phase1_postmortem.md). + The v1 instrument read raw SUMMED logps/chosen -- corr -0.89 with batch + completion length -- and applied a zero-threshold slope test over a + 20-raw-row window (~1.25 optimizer steps). On the primary Arm B run it + fired 3,049 times; on a SHUFFLED copy of the same series, 2,987 times: + zero discriminating power. Its false alarm at micro-step 43 selected the + objective of the recorded (destroyed) rerun. By the correct metric -- + per-token NLL, DPOP's own published diagnostic -- that primary run showed + no collapse at all (0.487 -> 0.548 nats/token across 727 steps). + + v2 semantics: per-token chosen NLL (= -logps/chosen / lengths/chosen), + baseline median over the first `window` rows vs trailing median over the + last `window` rows; fires only when the trailing median exceeds baseline + by `nll_rise_nats` (default 0.15 -- healthy phase-1 drift measured 0.06, + Smaug's documented collapse is +1.45) AND the margin median has risen. + LATCHED: once fired it stays fired and stops logging. The calibration + contract is pinned by tests: it must NOT fire on a shuffled copy of a + healthy series, and MUST fire on an injected +0.3 nats/token shift. + """ + + #: The metric keys this tripwire READS, declared so the wiring can be + #: checked instead of assumed (THE DISARMED-TRIPWIRE INCIDENT, below). + INPUT_KEYS: tuple[str, ...] = ("logps/chosen", "lengths/chosen", "rewards/margins") + + #: The response is PRE-REGISTERED: decided before the run, so a tripped + #: alarm produces a recorded configuration change rather than a debate + #: about whether the number is real. Recorded as the arm's configuration. + PRE_REGISTERED_RESPONSE = ( + "rerun this arm with DPOP (chosen-logprob floor) or an NLL auxiliary " + "term, and record the switch as the arm's configuration" + ) + + def __init__(self, window: int = 400, nll_rise_nats: float = 0.15): + self.window = int(window) + self.nll_rise_nats = float(nll_rise_nats) + self._baseline_nll: list[float] = [] + self._baseline_margin: list[float] = [] + self._nll: list[float] = [] + self._margin: list[float] = [] + self.fired = False + self._fired_at_row: Optional[int] = None + self._rows = 0 + + def state_dict(self) -> dict: + """Baselines, window and latch (U01-6): primitives only, so resume.pt stays + `weights_only`-loadable. Without it every supervised relaunch re-baselined.""" + return { + "baseline_nll": [float(v) for v in self._baseline_nll], + "baseline_margin": [float(v) for v in self._baseline_margin], + "nll": [float(v) for v in self._nll], + "margin": [float(v) for v in self._margin], + "fired": bool(self.fired), + "fired_at_row": self._fired_at_row, + "rows": int(self._rows), + } + + def load_state_dict(self, sd: dict) -> None: + self._baseline_nll = [float(v) for v in sd["baseline_nll"]] + self._baseline_margin = [float(v) for v in sd["baseline_margin"]] + self._nll = [float(v) for v in sd["nll"]] + self._margin = [float(v) for v in sd["margin"]] + self.fired = bool(sd["fired"]) + fr = sd.get("fired_at_row") + self._fired_at_row = None if fr is None else int(fr) + self._rows = int(sd["rows"]) + + @staticmethod + def _median(values: Sequence[float]) -> float: + # NaN-poisoning median: any NaN in the window makes the statistic NaN, + # so missing data can never fire (blind != healthy != alarm). + if any(math.isnan(v) for v in values): + return NAN + s = sorted(values) + n = len(s) + return s[n // 2] if n % 2 else 0.5 * (s[n // 2 - 1] + s[n // 2]) + + def update(self, logps_chosen: float, lengths_chosen: float, margin: float) -> TripwireResult: + self._rows += 1 + lp, ln = float(logps_chosen), float(lengths_chosen) + nll = -lp / ln if (not math.isnan(lp) and not math.isnan(ln) and ln > 0) else NAN + m = float(margin) + + if self.fired: + return TripwireResult( + True, + self.PRE_REGISTERED_RESPONSE, + detail=f"latched since row {self._fired_at_row}", + ) + if len(self._baseline_nll) < self.window: + self._baseline_nll.append(nll) + self._baseline_margin.append(m) + return TripwireResult( + False, "", detail=f"baselining {len(self._baseline_nll)}/{self.window}" + ) + self._nll.append(nll) + self._margin.append(m) + self._nll = self._nll[-self.window :] + self._margin = self._margin[-self.window :] + if len(self._nll) < self.window: + return TripwireResult(False, "", detail=f"windowing {len(self._nll)}/{self.window}") + + base_nll = self._median(self._baseline_nll) + cur_nll = self._median(self._nll) + base_m = self._median(self._baseline_margin) + cur_m = self._median(self._margin) + rise = cur_nll - base_nll + tripped = ( + not math.isnan(rise) + and not math.isnan(cur_m) + and not math.isnan(base_m) + and rise > self.nll_rise_nats + and cur_m > base_m + ) + if tripped: + self.fired = True + self._fired_at_row = self._rows + logger.error( + "TRIPWIRE: per-token chosen NLL rose %.3f nats/token over baseline " + "(%.3f -> %.3f) while the DPO margin rises (%.4f -> %.4f). The " + "objective is degrading chosen likelihood in real terms. " + "Pre-registered response: %s", + rise, + base_nll, + cur_nll, + base_m, + cur_m, + self.PRE_REGISTERED_RESPONSE, + ) + return TripwireResult( + tripped, + self.PRE_REGISTERED_RESPONSE if tripped else "", + value=rise, + logps_slope=rise, # field kept for record-schema compat: nll shift + margin_slope=(cur_m - base_m) if not math.isnan(cur_m) else NAN, + ) + + +class GradNormTripwire: + """HALTS the run on a gradient-norm explosion. R3 (2026-08-23 audit). + + grad_norm was logged every optimizer step of both destroyed-run attempts + and read by NOTHING: the recorded rerun's first step showed 2,851 vs the + primary's 22 (~130x), and the terminal blow-up reached 355,830 with the + run continuing 221 steps past the break. A ceiling here would have fired + at step 1. Unlike the diagnostic tripwires this one HALTS (HALT=True): + training past a gradient explosion spends GPU-hours destroying weights. + """ + + INPUT_KEYS: tuple[str, ...] = ("grad_norm",) + PRE_REGISTERED_RESPONSE = ( + "halt the run; a gradient explosion is a launch/config defect, not a " + "tunable -- diagnose before any rerun" + ) + HALT = True + #: `grad_norm` is a TRAINER-produced metric that is legitimately NaN on + #: every micro-step without an applied optimizer step (the NaN-reporting + #: contract). That is a periodic honest state, not a disarmed feed -- + #: this wire handles NaN as "blind, cannot fire" itself. The arm-time + #: self-test therefore still requires the KEY (name drift stays a launch + #: failure) but tolerates NaN for wires that declare this. + TOLERATES_NAN_INPUT = True + + def __init__( + self, + absolute_ceiling: float = 500.0, + relative_factor: float = 10.0, + window: int = 50, + warmup: int = 10, + ): + self.absolute_ceiling = float(absolute_ceiling) + self.relative_factor = float(relative_factor) + self.window = int(window) + self.warmup = int(warmup) + self._history: list[float] = [] + self.fired = False + + def state_dict(self) -> dict: + """Trailing history and latch (U01-6); primitives only.""" + return {"history": [float(v) for v in self._history], "fired": bool(self.fired)} + + def load_state_dict(self, sd: dict) -> None: + self._history = [float(v) for v in sd["history"]] + self.fired = bool(sd["fired"]) + + def update(self, grad_norm: float) -> TripwireResult: + g = float(grad_norm) + if self.fired: + return TripwireResult(True, self.PRE_REGISTERED_RESPONSE, value=g, detail="latched") + if math.isnan(g): + return TripwireResult(False, "", value=NAN, detail="NaN grad_norm: blind, cannot fire") + history = self._history + trailing = sorted(history[-self.window :]) + med = trailing[len(trailing) // 2] if trailing else NAN + over_abs = g > self.absolute_ceiling + over_rel = ( + len(history) >= self.warmup + and not math.isnan(med) + and med > 0 + and g > self.relative_factor * med + ) + history.append(g) + if over_abs or over_rel: + self.fired = True + logger.error( + "TRIPWIRE (HALT): grad_norm %.1f exceeds %s (trailing median %.2f). %s", + g, + f"absolute ceiling {self.absolute_ceiling}" + if over_abs + else f"{self.relative_factor}x trailing median", + med, + self.PRE_REGISTERED_RESPONSE, + ) + return TripwireResult(True, self.PRE_REGISTERED_RESPONSE, value=g) + return TripwireResult(False, "", value=g) + + +class LengthDriftTripwire: + """Fires when the chosen-longer fraction leaves a band around the measured + baseline for the arm -- but only once it has seen enough pairs to mean it. + + THREE DECLARED STATES, and keeping them distinct is the whole design: + + * BLIND -- input absent or NaN. The guard cannot see AND cannot say + so. Forbidden; `assert_tripwires_armed` halts the run. + * WARMING UP -- inputs present and finite, cumulative pairs below + `min_pairs`. The guard is watching and honestly reports + insufficient sample. Valid; the self-test accepts it. + * WATCHING -- armed and evaluating. + + Why `min_pairs` exists (sec09's measurement): at micro_batch 2 the + per-batch chosen-longer fraction can only take the values {0, 0.5, 1}, two + of which sit outside a +-0.10 band around 0.549 -- so the alarm fired on + 78% of batches while measuring nothing but the batch size. Their rolling + window fixes the estimator; this threshold fixes when it may speak. From + their standard-error table: 512 pairs gives 5.4e-06 false-fire per check, + 256 gives roughly 4 spurious alarms per Arm-B run. An alarm that fires + four times a run is an alarm nobody reads the fifth time. + + The baseline is a config field, never a constant here: Arm A measured + 0.549 and Arm B's is different, so a hardcoded threshold would mis-fire on + one of them permanently. + """ + + INPUT_KEYS: tuple[str, ...] = ("chosen_longer_fraction", "pairs") + + RESPONSE = ( + "length bias suspected: report length-controlled win-rate " + "alongside the raw metric and record the drift band that fired" + ) + + def __init__(self, baseline: float, band: float = 0.10, min_pairs: int = 512): + if math.isnan(baseline): + raise ValueError( + "LengthDriftTripwire needs a measured baseline; NaN means " + "nobody measured the arm and the check would be meaningless" + ) + self.baseline = float(baseline) + self.band = float(band) + self.min_pairs = int(min_pairs) + self._pairs_seen = 0 + + def state_dict(self) -> dict: + return {"pairs_seen": int(self._pairs_seen)} + + def load_state_dict(self, sd: dict) -> None: + self._pairs_seen = int(sd["pairs_seen"]) + + def state(self) -> str: + """`warming_up` until the cumulative sample reaches min_pairs, then + `watching`. Reported in the manifest so 'armed' is never ambiguous.""" + return "watching" if self._pairs_seen >= self.min_pairs else "warming_up" + + def update(self, chosen_longer_fraction: float, n_pairs: int = 1) -> TripwireResult: + self._pairs_seen += int(n_pairs) + v = float(chosen_longer_fraction) + if math.isnan(v): + # No measurement is not a drift and not an all-clear. + return TripwireResult(False, "", value=NAN, detail="chosen_longer_fraction undefined") + if self._pairs_seen < self.min_pairs: + return TripwireResult( + False, "", value=v, detail=f"warming up: {self._pairs_seen}/{self.min_pairs} pairs" + ) + + tripped = abs(v - self.baseline) > self.band + if tripped: + logger.error( + "TRIPWIRE: chosen-longer fraction %.3f is outside %.3f +- %.3f over %d pairs", + v, + self.baseline, + self.band, + self._pairs_seen, + ) + return TripwireResult( + tripped, + self.RESPONSE if tripped else "", + value=v, + detail=f"watching ({self._pairs_seen} pairs)", + ) + + +def assert_tripwires_armed(metrics: dict, tripwires: dict) -> None: + """Every ARMED tripwire's inputs must be present and finite, or halt. + + THE DISARMED-TRIPWIRE INCIDENT. section-05's kernel emits the implicit + margin as `rewards/margins`; section-07's Trainer seeded `margin` with NaN + and the tripwire read that. Nothing produced the key, `_slope` returns NaN + for any window containing one, and the trip condition requires a non-NaN + slope -- so the chosen-likelihood-collapse tripwire could never fire while + appearing fully wired: constructed, updated every log step, and listed as + armed in every manifest. A guard that cannot fire is worse than no guard, + because it is also a claim that the failure mode is being watched. + + TWO DIFFERENT CONTRACTS, and conflating them is what caused this: + + * A REPORTED statistic that is undefined must be NaN. `0.0` would read + as a real measurement ("no preference learned"), which is a finding + rather than a missing number. + * A tripwire INPUT must never be NaN-seeded. An armed guard reading NaN + is running blind, and blind is indistinguishable from healthy in every + log it writes. + + Run at the first log step of any stage with armed tripwires, so metric-name + drift becomes a launch failure instead of a silent disarming. + + A tripwire reporting `warming_up` PASSES this check. Its inputs are + present and finite; it simply has not accumulated enough sample to speak + yet, and it says so. Treating that as a failure would halt every DPO run + on its first batch, and the fix for THAT would be to delete the self-test + -- which is exactly how the original disarmed tripwire came about. + """ + problems = [] + for name, wire in tripwires.items(): + for key in getattr(wire, "INPUT_KEYS", ()): + if key not in metrics: + problems.append( + f"{name}: input {key!r} is ABSENT from the logged metrics " + f"(present: {sorted(metrics)[:8]})" + ) + elif ( + isinstance(metrics[key], float) + and math.isnan(metrics[key]) + and not getattr(wire, "TOLERATES_NAN_INPUT", False) + ): + problems.append(f"{name}: input {key!r} is NaN -- the guard would run blind") + if problems: + raise RuntimeError( + "ARMED TRIPWIRE SELF-TEST FAILED -- halting before training " + "proceeds:\n - " + + "\n - ".join(problems) + + "\n\nAn armed tripwire whose input is missing or NaN cannot " + "fire, and will report itself armed in every manifest anyway. " + "Either supply the metric (the loss adapter owns this) or do not " + "arm the tripwire for this stage. Canonical margin key: " + "'rewards/margins' -- the name section-05's kernel emits." + ) + + +# --------------------------------------------------------------------------- +# throughput probe + RSS projection +# --------------------------------------------------------------------------- + + +def _percentile(sorted_vals: Sequence[float], q: float) -> float: + if not sorted_vals: + return NAN + idx = min(len(sorted_vals) - 1, max(0, int(round(q * (len(sorted_vals) - 1))))) + return sorted_vals[idx] + + +def aggregate_micro_step_times(micro_times_s: Sequence[float], grad_accum: int) -> list[float]: + """Sum consecutive micro-step durations into OPTIMIZER-step durations. + + The unit bug this exists to kill (task #25): both probes measure + per-MICRO durations, while `throughput_report` takes per-OPTIMIZER token + counts and horizon. Feeding micro times straight in under-projects + wall-clock and over-reports tokens/s by ~grad_accum x (8x on the DPO + config) -- a banner that costs GPU-hours wrong by an order of magnitude. + + Only COMPLETE groups are kept: a trailing partial group would read as one + impossibly fast optimizer step. Raises when no complete group exists -- + same contract as throughput_report itself (resolved or refused, never + quietly wrong); size probe_steps >= grad_accum at the config level. + """ + if grad_accum <= 0: + raise ValueError(f"grad_accum={grad_accum} is not a schedule") + times = [float(t) for t in micro_times_s] + groups = [ + sum(times[i : i + grad_accum]) for i in range(0, len(times) - grad_accum + 1, grad_accum) + ] + if not groups: + raise ValueError( + f"{len(times)} micro-step times cannot fill one optimizer step at " + f"grad_accum={grad_accum}; raise probe_steps to at least grad_accum" + ) + return groups + + +def throughput_report( + step_times_s: Sequence[float], + tokens_per_step: int, + optimizer_steps_planned: int, + offload_transfer_s: Optional[float] = None, + offload_cpu_step_s: Optional[float] = None, +) -> dict: + """Turn measured step times into the banner's throughput entry. + + Refuses to produce a partial entry: a stage that starts without knowing its + step time is a stage committing GPU-hours to a schedule nobody costed. When + offload is inactive the offload timings are NaN -- explicitly, because a + 0.0 there would read as 'offload is free'. + """ + times = [float(t) for t in step_times_s] + if not times: + raise ValueError( + "throughput_report got no step times. A probe that cannot fill " + "its banner keys must raise: the banner's contract is that every " + "value is resolved or explicitly NaN, never quietly absent." + ) + if optimizer_steps_planned <= 0: + raise ValueError( + f"optimizer_steps_planned={optimizer_steps_planned} is not a " + "schedule; the projected wall-clock would be meaningless" + ) + + mean = sum(times) / len(times) + ordered = sorted(times) + return { + "n_steps": len(times), + "mean_step_time_s": mean, + "p50_step_time_s": _percentile(ordered, 0.50), + "p90_step_time_s": _percentile(ordered, 0.90), + "tokens_per_s": tokens_per_step / mean if mean > 0 else NAN, + "projected_epoch_s": optimizer_steps_planned * mean, + "offload_transfer_s": (NAN if offload_transfer_s is None else float(offload_transfer_s)), + "offload_cpu_step_s": (NAN if offload_cpu_step_s is None else float(offload_cpu_step_s)), + } + + +def projected_job_rss(cfg) -> dict: + """Projected host RSS for this job, for the guard and the launch banner. + + Delegates to `guard.projected_full_ft_rss_gb` rather than restating the + arithmetic. Two formulas for the same budget WILL drift, and then the + banner advertises a number the preflight is not enforcing -- while the + preflight is the only thing standing between this job and the 2026-08-12 + host crash (2GB free, load 619, no swap, a healthy run killed by an NCCL + timeout five hours into a stalled checkpoint). + """ + from ..utils.guard import projected_full_ft_rss_gb + + return projected_full_ft_rss_gb(cfg) diff --git a/code/align/train/quant8.py b/code/align/train/quant8.py new file mode 100644 index 0000000000000000000000000000000000000000..7282de99450421800c57842e1c8e5b7cb7d7deea --- /dev/null +++ b/code/align/train/quant8.py @@ -0,0 +1,193 @@ +"""Block-wise 8-bit dynamic quantization, in plain torch. + +This is the numeric core of `adamw8bit.py` and carries NO optimizer logic, so +the codebook and the quantize/dequantize round trip can be tested (and +mis-implemented) on their own. The scheme is Dettmers et al. 2022, "8-bit +Optimizers via Block-wise Quantization" (arXiv:2110.02861), rebuilt from the +paper's description with torch only (docs/DEPENDENCY_POLICY.md: bitsandbytes +is not on the allowed list). + +WHY BLOCK-WISE: one absmax for a whole 134M-element embedding shard lets a +single outlier set the scale for every element, and the other 134M-1 values +land in the bottom few codes. Normalising each block of `block_size` (default +2048) elements by its OWN absmax confines an outlier's damage to its block and +makes the quantization independent of how the tensor happens to be sharded +across ranks -- which matters, because under FSDP2 the blocks are cut from the +rank-LOCAL shard. + +WHY A DYNAMIC (NON-LINEAR) CODEBOOK: Adam's moments span many decades inside +one block (the second moment is a square of a heavy-tailed gradient). A +linear 8-bit grid has uniform ABSOLUTE resolution, so everything below +~absmax/256 collapses to zero -- and a zero second moment makes the update +`m / (sqrt(0) + eps)`, i.e. m / 1e-8. The dynamic map spends its 256 codes as +an exponent (a power of ten, 7 of them) plus a linear fraction inside each +decade: relative resolution of a few percent from absmax down to ~1e-6*absmax. + +THE ONE THING THIS MODULE DOES NOT DO is decide when quantization is safe: +the caller keeps tensors below `min_8bit_size` in fp32 (small tensors such as +norm scales are both cheap to keep and the most sensitive to rounding). +""" + +from __future__ import annotations + +import functools + +import torch + +#: 8-bit codes. Not configurable: the code type is `uint8` and the lookup +#: arithmetic assumes exactly 256 entries. +N_CODES = 256 + + +def create_dynamic_map(signed: bool = True, max_exponent_bits: int = 7, total_bits: int = 8): + """The sorted 256-entry dynamic codebook, float32, built like bnb's + `create_dynamic_map` (the construction the paper describes). + + Layout: for each exponent `i` in `0..max_exponent_bits-1` the decade + `10**(i - (max_exponent_bits-1)) * [0.1, 1]` is cut into linear fraction + bins and each bin contributes its MIDPOINT (so no code sits on a decade + edge and codes are strictly increasing). Decade `i` gets `2**i` fraction + values when signed and `2**(i+1)` when unsigned -- the unsigned map spends + the sign bit on one more bit of fraction. Exact `0.0` and `1.0` are then + appended. Counting, signed: 2 * (1+2+...+64) + 2 = 256; unsigned: + (2+4+...+128) + 2 = 256. Both assertions below fire if someone changes a + parameter without redoing the arithmetic. + + Signed map range: [-0.99297, 1.0] (there is no exact -1.0; the most + negative code is the midpoint of the top bin, 0.7% from -1). That is the + same asymmetry bnb has, and it is bounded: the block's largest-magnitude + element, if negative, is stored within 0.7%. + Unsigned map range: [0.0, 1.0]. + + Built in float64 and cast once, so the table is bit-identical across + machines and torch versions (linspace/mean in fp32 is not guaranteed to be). + """ + if total_bits != 8: + raise ValueError("create_dynamic_map builds 256-entry (8-bit) maps only") + non_sign_bits = total_bits - 1 + if not 1 <= max_exponent_bits <= non_sign_bits: + raise ValueError(f"max_exponent_bits must be in [1, {non_sign_bits}]") + additional_items = 2 ** (non_sign_bits - max_exponent_bits) - 1 + + data: list[float] = [] + for i in range(max_exponent_bits): + if signed: + fraction_items = 2 ** (i + non_sign_bits - max_exponent_bits) + 1 + else: + fraction_items = 2 ** (i + non_sign_bits - max_exponent_bits + 1) + 1 + boundaries = torch.linspace(0.1, 1.0, fraction_items, dtype=torch.float64) + means = (boundaries[:-1] + boundaries[1:]) / 2.0 + scale = 10.0 ** (-(max_exponent_bits - 1) + i) + data += (scale * means).tolist() + if signed: + data += (-scale * means).tolist() + if additional_items > 0: + boundaries = torch.linspace(0.1, 1.0, additional_items + 1, dtype=torch.float64) + means = (boundaries[:-1] + boundaries[1:]) / 2.0 + data += means.tolist() + if signed: + data += (-means).tolist() + data.append(0.0) + data.append(1.0) + data.sort() + if len(data) != N_CODES: + raise AssertionError(f"dynamic map has {len(data)} entries, expected {N_CODES}") + out = torch.tensor(data, dtype=torch.float64).to(torch.float32) + if not bool((out[1:] > out[:-1]).all()): + raise AssertionError("dynamic map is not strictly increasing in float32") + return out + + +@functools.lru_cache(maxsize=None) +def _cached_map(signed: bool) -> torch.Tensor: + return create_dynamic_map(signed=signed) + + +_DEVICE_CACHE: dict = {} + + +def codebook(signed: bool, device) -> torch.Tensor: + """The shared codebook on `device` (cached; never mutate the result).""" + device = torch.device(device) + key = (bool(signed), device.type, device.index) + cb = _DEVICE_CACHE.get(key) + if cb is None: + cb = _cached_map(bool(signed)).to(device) + _DEVICE_CACHE[key] = cb + return cb + + +def zero_code(signed: bool) -> int: + """Index of the exact-0.0 code (the all-zero state initialises to it).""" + return int((_cached_map(bool(signed)) == 0.0).nonzero()[0]) + + +def nearest_code(x: torch.Tensor, cb: torch.Tensor) -> torch.Tensor: + """Nearest-code index of every element of `x` (any shape), as uint8. + + `searchsorted` gives, for each x, the first index `hi` with cb[hi] >= x; the + nearest code is then either `hi` or `hi-1`, decided by comparing x against + their MIDPOINT (ties go to the lower code). Clamping `hi` to [1, 255] + first makes both candidates always exist, and values outside the table + (x <= cb[0] or x >= cb[-1]) resolve to the end codes by the same + comparison -- no special-casing, so no off-by-one at the edges. + + `out_int32=True`: the index tensor is the largest transient in a chunked + step, and int32 halves it. (The final uint8 cast is what is stored.) + """ + flat = x.reshape(-1).contiguous() + hi = torch.searchsorted(cb, flat, out_int32=True).clamp_(1, N_CODES - 1) + lo = hi - 1 + mid = (cb[lo] + cb[hi]) * 0.5 + pick_hi = flat > mid + return torch.where(pick_hi, hi, lo).to(torch.uint8).reshape(x.shape) + + +def quantize_rows(x: torch.Tensor, cb: torch.Tensor): + """Quantize a `[n_blocks, block_size]` fp32 matrix, one block per row. + + Returns `(codes uint8 [n_blocks, block_size], absmax fp32 [n_blocks])`. + An all-zero block has absmax 0; dividing by it would put NaN through the + lookup, so the divisor is replaced by 1 there (the block's values are all + 0, which then quantize to the zero code and dequantize to 0 * absmax = 0). + """ + absmax = x.abs().amax(dim=1) + safe = torch.where(absmax > 0, absmax, torch.ones_like(absmax)) + normalized = x / safe.unsqueeze(1) + return nearest_code(normalized, cb), absmax + + +def dequantize_rows(codes: torch.Tensor, absmax: torch.Tensor, cb: torch.Tensor) -> torch.Tensor: + """Inverse of `quantize_rows`: fp32 `[n_blocks, block_size]`. + + The index MUST be a signed integer tensor: `cb[codes]` with a uint8 `codes` + is interpreted by torch as a (deprecated) boolean-mask index, not a gather. + `index_select` with an int32 index has no such reading. + """ + n_blocks, block_size = codes.shape + values = cb.index_select(0, codes.reshape(-1).to(torch.int32)).reshape(n_blocks, block_size) + return values * absmax.unsqueeze(1) + + +def quantize_blockwise(x: torch.Tensor, block_size: int = 2048, signed: bool = True): + """Quantize any tensor (flattened) -> `(codes uint8 [n_blocks*block_size], absmax)`. + + The final partial block is zero-padded; the pad quantizes to the zero code + and is dropped by `dequantize_blockwise(..., numel=)`. + """ + flat = x.detach().reshape(-1).to(torch.float32) + n = flat.numel() + n_blocks = max(1, -(-n // block_size)) + padded = torch.zeros(n_blocks * block_size, dtype=torch.float32, device=flat.device) + padded[:n] = flat + codes, absmax = quantize_rows(padded.view(n_blocks, block_size), codebook(signed, flat.device)) + return codes.reshape(-1), absmax + + +def dequantize_blockwise( + codes: torch.Tensor, absmax: torch.Tensor, numel: int, block_size: int = 2048, signed: bool = True +) -> torch.Tensor: + """Inverse of `quantize_blockwise`, trimmed to `numel` elements (fp32, flat).""" + rows = codes.reshape(-1, block_size) + out = dequantize_rows(rows, absmax, codebook(signed, codes.device)) + return out.reshape(-1)[:numel] diff --git a/code/align/train/qwen3_stage.py b/code/align/train/qwen3_stage.py new file mode 100644 index 0000000000000000000000000000000000000000..4eaabc3409bcc30d44567c8e71d66b876fadd906 --- /dev/null +++ b/code/align/train/qwen3_stage.py @@ -0,0 +1,466 @@ +"""Qwen3 (Goedel-Prover-V2-8B) SFT stage pieces: model build, LoRA train module, weight format. + +`scripts/sft.py` dispatches here when `model.arch == "qwen3"`; the dense-Mistral path never +imports this module. Everything the Trainer needs that is family-specific lives behind the +two seams the Trainer already has: `weight_format` (what a checkpoint's weight file is) and +`train_module` (what touches the model). + +THE LoRA CHECKPOINT CONTRACT (same as `PPOTrainModule`, for the same reasons): + + * The weight file of every checkpoint is the MERGED bf16 model (base + scaling * B @ A, + accumulated in fp32, cast once). Checkpoint saves are how vLLM / transformers / the + rollout engine receive the policy, and they load HF base weights, not adapters. + * The adapter itself (fp32, exact) rides in the optimizer payload, so a resume is lossless: + base is reloaded from the pinned snapshot at launch, the adapter and the 8-bit moments + come back from `optimizer_rank{r}.pt`. + * `load_weights` on a LoRA resume reads only the safetensors HEADERS (key set + shapes, on + the meta device). Materialising the merged 16 GB on each of four ranks would cost 64 GB of + host RAM to verify a key set and then be thrown away -- the 2026-08-12 shape. + +FSDP2 + frozen base. Per-block `fully_shard` shards the frozen bf16 base (16.4 GB / world) and +the fp32 adapters together; only adapter gradients are reduce-scattered. Activation +checkpointing wraps each block. The root unit also owns embed_tokens / lm_head / final norm. +""" + +from __future__ import annotations + +import gc +import logging +import os +from typing import Any, Optional + +import torch + +from .ckpt_format import WeightFormat # noqa: F401 (the Protocol this implements) +from .train_module import TrainModule + +logger = logging.getLogger(__name__) + +SUPPORTED_ARCHS = ("mistral", "qwen3") + + +class Qwen3StageError(RuntimeError): + """A qwen3 stage config that cannot be launched as written.""" + + +# --------------------------------------------------------------------------- +# Config validation +# --------------------------------------------------------------------------- + + +def validate_qwen3_cfg(cfg, qcfg) -> None: + """Refuse launches whose declared numbers disagree with the snapshot they will load. + + Derived-vs-hardcoded: `model.n_params` feeds the RSS projection and the banner; the + architecture truth is the snapshot's config.json. A TOML that still carries the Mistral + defaults (7.25B / 32 layers) would project the wrong host footprint and print a banner + describing a different model. + """ + from ..model.qwen3 import count_params + + n = count_params(qcfg) + problems = [] + if cfg.model.n_params != n: + problems.append(f"model.n_params={cfg.model.n_params} but the snapshot implies {n}") + if cfg.model.n_layers != qcfg.n_layers: + problems.append(f"model.n_layers={cfg.model.n_layers} but the snapshot has {qcfg.n_layers}") + if cfg.model.vocab_size != qcfg.vocab_size: + problems.append(f"model.vocab_size={cfg.model.vocab_size} but the snapshot has {qcfg.vocab_size}") + if cfg.model.hidden_size != qcfg.hidden_size: + problems.append(f"model.hidden_size={cfg.model.hidden_size} but the snapshot has {qcfg.hidden_size}") + if cfg.model.precision != "bf16": + problems.append(f"model.precision={cfg.model.precision!r}: bf16 only") + if problems: + raise Qwen3StageError("qwen3 stage config disagrees with its snapshot: " + "; ".join(problems)) + lo = cfg.lora + if lo.enabled: + if lo.dropout != 0.0: + raise Qwen3StageError( + f"lora.dropout={lo.dropout}: align.ppo.lora has no dropout path (train-time and " + "score-time logprobs would differ); set 0.0" + ) + if cfg.train.full_ft: + raise Qwen3StageError("lora.enabled with train.full_ft=true: LoRA freezes the base; set train.full_ft=false") + elif not cfg.train.full_ft: + raise Qwen3StageError("train.full_ft=false requires lora.enabled=true (otherwise nothing trains)") + + +def resolve_qwen3(cfg): + """(snapshot_dir, Qwen3Config) from `paths.model_snapshot`, with the attention request applied.""" + from ..model import checkpoint as ckpt + from ..model.qwen3_checkpoint import read_qwen3_config + + snapshot = ckpt.resolve_snapshot_dir(cfg.paths.model_snapshot) + qcfg = read_qwen3_config(snapshot).replace(attn_implementation=cfg.model.attn_implementation) + validate_qwen3_cfg(cfg, qcfg) + return snapshot, qcfg + + +# --------------------------------------------------------------------------- +# Weight format +# --------------------------------------------------------------------------- + + +class Qwen3Format: + """`WeightFormat` for Qwen3: sharded HF safetensors + config.json + tokenizer files.""" + + def __init__(self, qcfg, tokenizer_dir: str, lora: bool): + self.qcfg = qcfg + self.tokenizer_dir = tokenizer_dir + self.lora = bool(lora) + + def save_weights(self, state, out_dir, dtype): + from ..model.qwen3_checkpoint import save_hf_qwen3 + + save_hf_qwen3(dict(state), out_dir, cfg=self.qcfg, dtype=dtype) + + def load_weights(self, path): + from ..model.checkpoint import load_hf_safetensors + from ..model.qwen3_checkpoint import hf_to_align + + if self.lora: + return hf_to_align(_hf_headers_on_meta(path), self.qcfg) + return hf_to_align(load_hf_safetensors(path), self.qcfg) + + def copy_tokenizer(self, snapshot, dst_dir): # noqa: ARG002 -- the configured dir is authoritative + from ..model.qwen3_checkpoint import copy_tokenizer_files + + return copy_tokenizer_files(self.tokenizer_dir, dst_dir) + + +def _hf_headers_on_meta(path: str) -> dict: + """{hf key: empty meta tensor of the stored shape/dtype} for a checkpoint dir. Reads the + safetensors headers only -- no tensor data is touched.""" + import json + + from safetensors import safe_open + + from ..model.checkpoint import INDEX_NAME, WEIGHTS_NAME + + idx = os.path.join(path, INDEX_NAME) + if os.path.isfile(idx): + with open(idx) as f: + files = sorted(set(json.load(f)["weight_map"].values())) + elif os.path.isfile(os.path.join(path, WEIGHTS_NAME)): + files = [WEIGHTS_NAME] + else: + raise FileNotFoundError(f"no {WEIGHTS_NAME} or {INDEX_NAME} at {path!r}") + out: dict[str, torch.Tensor] = {} + for fname in files: + with safe_open(os.path.join(path, fname), framework="pt") as f: + for k in f.keys(): + sl = f.get_slice(k) + dt = _ST_DTYPES[sl.get_dtype()] + out[k] = torch.empty(sl.get_shape(), dtype=dt, device="meta") + return out + + +_ST_DTYPES = {"BF16": torch.bfloat16, "F32": torch.float32, "F16": torch.float16} + + +# --------------------------------------------------------------------------- +# Base identity (a LoRA resume must reattach the adapter to the base it was trained on) +# --------------------------------------------------------------------------- + + +def base_fingerprint(state) -> str: + """sha256 over the frozen base's identity: every non-adapter tensor's name/shape/dtype, every + 1-D tensor in full (norm weights differ between fine-tunes of one architecture), and the first + and last 8 rows of every matrix (embeddings, lm_head and each projection). Cheap (~tens of MB + hashed for 8B) yet distinguishes two bases with the SAME key set and shapes -- the only + difference a LoRA resume, which never loads the checkpoint's weights, could otherwise miss. + Needs plain (unsharded, non-meta) tensors: a shard-local hash would differ per rank.""" + import hashlib + + h = hashlib.sha256() + for k in sorted(k for k in state if ".adapters." not in k): + t = state[k] + if hasattr(t, "to_local") or t.device.type == "meta": + raise ValueError(f"cannot fingerprint {k!r}: sharded or meta tensor") + t = t.detach() + h.update(f"{k}|{tuple(t.shape)}|{t.dtype}".encode()) + parts = [t] if t.dim() <= 1 else [t[:8], t[-8:]] + for part in parts: + h.update(part.to("cpu").contiguous().reshape(-1).view(torch.uint8).numpy().tobytes()) + return h.hexdigest() + + +# --------------------------------------------------------------------------- +# LoRA train module +# --------------------------------------------------------------------------- + + +class LoRASFTModule(TrainModule): + """`TrainModule` whose checkpoints publish merged weights and persist the adapter.""" + + def __init__(self, model, loss_adapter, optimizer, grad_accum: int, adapter: str, weight_format=None): + super().__init__(model, loss_adapter, optimizer, grad_accum) + from ..ppo.lora import has_lora + + if not has_lora(model): + raise Qwen3StageError("LoRASFTModule needs a model with injected LoRA layers") + self.adapter = adapter + if weight_format is not None: + self.weight_format = weight_format + # Identity of the frozen base this adapter trains on (recorded in the optimizer payload, + # checked on resume). `build_qwen3_stage_model` stamps it BEFORE the FSDP wrap, when the + # tensors are still whole; a directly built model is fingerprinted here if it can be. + fp = getattr(model, "_base_fingerprint", None) + if fp is None: + try: + fp = base_fingerprint(model.state_dict()) + except ValueError as e: + logger.warning("LoRA base fingerprint unavailable (%s); a resume cannot verify its base", e) + self.base_fingerprint: Optional[str] = fp + + def full_model_state_dict(self): + """BASE-keyed weights with the adapter FOLDED IN (see the module docstring). + + `get_model_state_dict(full_state_dict=True, cpu_offload=True)` returns the full dict on + RANK 0 ONLY; every other rank gets `{}`. The gather is the collective every rank + joins; merging an empty dict is a KeyError on ranks 1..N-1 at the FIRST save, which + strands rank 0 in the next collective until the watchdog kills the run. + """ + import torch.distributed as dist + + from ..ppo.lora import export_merged_state_dict + + sd = super().full_model_state_dict() + if not sd and dist.is_available() and dist.is_initialized() and dist.get_rank() != 0: + return sd + self.last_export_report: dict = {} # retained-delta fidelity of the bf16 cast (warned on when poor) + return export_merged_state_dict(self.model, sd, self.adapter, report=self.last_export_report) + + def load_model_state_dict(self, nmo_state: dict) -> None: + """LoRA resume: the checkpoint's weights are MERGED and are deliberately NOT loaded -- + the frozen base was reloaded from the snapshot at launch, and loading merged weights + into it would double-count the delta once the adapter is restored from the optimizer + payload. The key set is still verified so a checkpoint of another architecture cannot + resume silently.""" + base_keys = {k for k in self.model.state_dict() if ".adapters." not in k} + missing, unexpected = sorted(base_keys - set(nmo_state)), sorted(set(nmo_state) - base_keys) + if missing or unexpected: + raise KeyError(f"resume state mismatch: missing={missing[:5]} unexpected={unexpected[:5]}") + logger.info("LoRA resume: merged weights verified (%d tensors) and NOT loaded; adapter comes from the optimizer payload", len(base_keys)) + + def optim_state_dict(self) -> dict: + from ..ppo.lora import lora_state_dict + + lora = lora_state_dict(self.model, self.adapter) + # The ZeRO-3 save defect, structurally: a sharded placeholder serialises as an EMPTY + # tensor and the file loads without error while being untrained. + empty = [k for k, v in lora.items() if v.numel() == 0] + if empty: + raise RuntimeError( + f"{len(empty)} adapter tensors are empty (e.g. {empty[:2]}): a sharded placeholder was " + "serialised instead of the gathered parameter. Refusing to write a checkpoint that " + "loads without error and is untrained." + ) + return {"optimizer": self.optimizer.state_dict(), "lora": lora, "base_fingerprint": self.base_fingerprint} + + def load_optim_state_dict(self, sd: dict) -> None: + from ..ppo.lora import load_lora_state_dict + + if "lora" not in sd or "optimizer" not in sd: + raise KeyError( + "checkpoint optimizer payload lacks 'lora'/'optimizer'; resuming would restart the " + "policy from the bare base while claiming a resume" + ) + # THE UNBOUND-ADAPTER DEFECT. The checkpoint's merged weights are not loaded, so nothing + # else ties this adapter to the base reloaded at launch: a repointed model_snapshot or a + # second HF-cache snapshot (same keys, same shapes) would resume "fine" on the wrong base. + saved = sd.get("base_fingerprint") + if saved is None or self.base_fingerprint is None: + logger.warning( + "LoRA resume cannot verify the base: base fingerprint missing (checkpoint=%s, this launch=%s)", + saved is not None, self.base_fingerprint is not None, + ) + elif saved != self.base_fingerprint: + raise RuntimeError( + "LoRA resume: the base model loaded at launch is not the base this adapter was trained on " + f"(fingerprint {self.base_fingerprint[:12]} != checkpoint {saved[:12]}). Check " + "paths.model_snapshot and the HF cache for a second snapshot." + ) + self.optimizer.load_state_dict(sd["optimizer"]) + load_lora_state_dict(self.model, self.adapter, sd["lora"], strict=True) + + +# --------------------------------------------------------------------------- +# Model build +# --------------------------------------------------------------------------- + + +def _vm_rss_gb(field: str = "VmRSS") -> float: + with open("/proc/self/status") as f: + for line in f: + if line.startswith(field + ":"): + return float(line.split()[1]) / 1024**2 + return float("nan") + + +def build_qwen3_stage_model(cfg, attn_implementation: Optional[str] = None): + """Rank-serial load -> GPU -> (LoRA inject, freeze base) -> activation checkpointing -> FSDP2. + + RANK-SERIAL because each rank materialises the 16.4 GB bf16 state dict on the host before + moving it to its card; four at once is 66 GB on a no-swap box. Ranks load one at a time + (barrier-ordered) and return freed heap to the OS (`malloc_trim`) before the next starts. + """ + from ..model import qwen3 as q3 + from ..model.qwen3_checkpoint import hf_to_align + from ..model.checkpoint import load_hf_safetensors + from ..ppo.lora import LoRAConfig, inject_lora, mark_only_adapter_trainable + from ..utils.dist import barrier, local_rank, rank, world_size + from . import fsdp + + snapshot, qcfg = resolve_qwen3(cfg) + if attn_implementation: + qcfg = qcfg.replace(attn_implementation=attn_implementation) + device = torch.device("cuda", local_rank()) + torch.cuda.set_device(device) + + model = None + peaks: dict[str, Any] = {} + for r in range(world_size()): + if rank() == r: + sd = hf_to_align(load_hf_safetensors(snapshot, dtype=torch.bfloat16), qcfg) + model = q3.Qwen3ForCausalLM.from_state_dict(qcfg, sd, device="cuda") + del sd + model = model.to(device) + peaks["rss_hwm_gb"] = round(_vm_rss_gb("VmHWM"), 2) # high-water mark of the load, not the residual + gc.collect() + try: + import ctypes + + ctypes.CDLL("libc.so.6").malloc_trim(0) + except (OSError, AttributeError): + pass + peaks["rss_after_trim_gb"] = round(_vm_rss_gb(), 2) + barrier() + + if cfg.lora.enabled: + model._base_fingerprint = base_fingerprint(model.state_dict()) # whole tensors, before inject/FSDP + lc = LoRAConfig(r=cfg.lora.r, alpha=cfg.lora.alpha, target_modules=tuple(cfg.lora.target_modules), rslora=cfg.lora.rslora) + # Identical adapter init on every rank: FSDP2 shards what each rank already holds and + # does NOT broadcast, so a per-rank random A would be a different adapter per shard. + gen = torch.Generator().manual_seed(cfg.train.seed) + hit = inject_lora(model, lc, adapter=cfg.lora.adapter, generator=gen) + n_trainable = mark_only_adapter_trainable(model, cfg.lora.adapter) + expected = len(cfg.lora.target_modules) * qcfg.n_layers + if len(hit) != expected: + raise Qwen3StageError(f"LoRA hit {len(hit)} layers, expected {expected} ({len(cfg.lora.target_modules)} targets x {qcfg.n_layers} layers)") + peaks["lora_trainable_params"] = n_trainable + fsdp.apply_activation_checkpointing(model) + if world_size() > 1: + fsdp.apply_fsdp(model) + model._stage_load_stats = peaks # for the banner / probe records + return model + + +def qwen3_trainer_extras(cfg, model, loss_adapter, run_dir: str) -> dict: + """The Trainer kwargs a qwen3 stage adds: weight_format, per-rank tracker, and for LoRA the + train_module and the probe view. + + PER-RANK TRACKER. The Trainer's default constructs a `Tracker` on EVERY rank, all appending + to the same `/history.jsonl`: four interleaved streams with no rank field, so + "did each rank see different rows?" cannot be answered from the record (and torn + interleaving is one fsync away). Rank 0 keeps ``; rank r writes `/rank{r}`. + """ + from ..utils.dist import rank as _rank + from ..utils.tracking import Tracker + from .offload_adamw import make_optimizer + from .trainer import MANDATORY_METRICS + + snapshot, qcfg = resolve_qwen3(cfg) + r = _rank() + extras: dict = { + "weight_format": Qwen3Format(qcfg, tokenizer_dir=snapshot, lora=cfg.lora.enabled), + "tracker": Tracker(run_dir if r == 0 else os.path.join(run_dir, f"rank{r}"), "sft", + mandatory_keys=MANDATORY_METRICS, run_name=cfg.run_name), + } + if not cfg.lora.enabled: + return extras + optimizer = make_optimizer(cfg, [p for p in model.parameters() if p.requires_grad]) + extras["train_module"] = LoRASFTModule( + model, loss_adapter, optimizer, cfg.optimizer.grad_accum, cfg.lora.adapter, + weight_format=extras["weight_format"], + ) + from ..ppo.trainer import AdapterProbeView + + extras["probe_model"] = AdapterProbeView(model, cfg.lora.adapter) + return extras + + +def qwen3_entry_banner(cfg, ledger) -> dict: + """The qwen3 counterpart of `stage_gates.run_entry_gates`: what can be verified WITHOUT the + Mistral-specific machinery, and an explicit PENDING for what cannot. + + NOT APPLICABLE here, and why (each is a Mistral/PRM800K artifact, not a skipped check): + * golden regression + MATH-500/GSM8K quality gate: they certify the Mistral eval stack + against a Mistral checkpoint's recorded score. The qwen3 experiment's evaluation is the + Lean verifier loop (P2-B/C). + * the 10-step 7B smoke / 20-step probe: `build_stage_model` is Mistral-only. The qwen3 + memory and throughput are measured by scripts/qwen3_sft_probe.py and recorded in + docs; the banner says PENDING rather than quoting a number this launch did not measure. + KEPT: batch arithmetic, shard receipts (hashes into the banner), the RSS projection, the + sampler-derived scheduler horizon, the snapshot-vs-config agreement. + """ + from ..utils.guard import projected_full_ft_rss_gb + from .stage_gates import PENDING, assemble_sft_banner, assert_batch_arithmetic_consistent + from .stage_smoke import build_training_sampler, resolve_split_dir, sampler_derived_horizon + + snapshot, qcfg = resolve_qwen3(cfg) + assert_batch_arithmetic_consistent(cfg) + sampler, dataset = build_training_sampler(cfg) + horizon = sampler_derived_horizon(cfg, sampler) + # THE OVERLONG-ROW DEFECT. The length-grouped sampler budgets tokens, but a row longer than the + # budget is not rejected: it becomes a batch of one and trains. seq_len is the length the + # memory envelope was MEASURED at (scripts/qwen3_sft_probe.py); a longer row would be the + # first thing to run at an untested length, on the last GPU-hour of an epoch. + lengths = dataset.lengths() + over = int((lengths > cfg.train.seq_len).sum()) + if over: + raise Qwen3StageError( + f"{over} of {len(lengths)} rows are longer than train.seq_len={cfg.train.seq_len} " + f"(longest {int(lengths.max())}). Filter them at data-build time or raise seq_len to a " + "length that has been measured; the sampler would otherwise train each as a lone batch." + ) + split_dir = resolve_split_dir(cfg.data.shard_dir, cfg.data.sft_split) + import json + + hashes = {} + for rp in sorted(split_dir.glob("*.receipt.json")): + with open(rp) as f: + r = json.load(f) + hashes[r["name"]] = r["content_hash"] + if not hashes: + raise Qwen3StageError(f"no shard receipts under {split_dir}") + banner = assemble_sft_banner( + cfg, + attention_backend=qcfg.attn_implementation or "auto(sdpa)", + optimizer_impl=f"{cfg.optimizer.name} lora={'on r=%d alpha=%g' % (cfg.lora.r, cfg.lora.alpha) if cfg.lora.enabled else 'off'}", + dataset_hashes=hashes, + ceiling_results={"lean_verifier": PENDING, "note": "qwen3 stage: evaluated by the Lean loop (P2), not MATH/GSM8K"}, + probe_report=None, + rss_projection=projected_full_ft_rss_gb(cfg), + mde={"note": PENDING}, + scheduler_horizon_optimizer_steps=horizon, + scheduler_horizon_rows_derived=None, + ) + banner.update({"arch": cfg.model.arch, "snapshot": snapshot, "n_rows": len(dataset), "seq_len": cfg.train.seq_len}) + # The Mistral gate ledger enforces the golden->smoke->probe order, which does not apply here + # (recording a pass for a gate that did not run would be a lie), so the entry is persisted as + # its own receipt next to the ledger instead. + from ..utils.dist import is_rank0 + + if is_rank0(): + tmp = os.path.join(ledger.run_dir, "qwen3_entry.json.partial") + with open(tmp, "w") as f: + json.dump(banner, f, indent=1, sort_keys=True, default=str) + os.replace(tmp, os.path.join(ledger.run_dir, "qwen3_entry.json")) + return banner + + +__all__ = [ + "SUPPORTED_ARCHS", "Qwen3StageError", "base_fingerprint", "Qwen3Format", "LoRASFTModule", "validate_qwen3_cfg", + "resolve_qwen3", "build_qwen3_stage_model", "qwen3_trainer_extras", "qwen3_entry_banner", +] diff --git a/code/align/train/ref_cache.py b/code/align/train/ref_cache.py new file mode 100644 index 0000000000000000000000000000000000000000..5e534c4cfe7742f5aad476bbd10d3fc84222ee52 --- /dev/null +++ b/code/align/train/ref_cache.py @@ -0,0 +1,834 @@ +"""Reference log-probabilities: precompute, cache, join, and the path-bias rule. + +DPO needs, for every pair, what the FROZEN reference policy thought of the +chosen and rejected completions. The textbook implementation keeps a second +7B model resident and forwards it alongside the policy. That does not fit: +14.5 GB of policy weights plus optimizer shards plus activations already fills +a 23 GB A10G, and a second copy fills a second one for no gradient. + +So the reference is computed once, offline, and consumed as constants. The +whole arrangement rests on one property -- with dropout disabled, a no-grad +pass over a fixed dataset yields the same numbers every time -- and on one +discipline: the cache must be keyed on EVERYTHING that could change those +numbers, because every failure mode of a stale cache is silent. A cache from +the wrong checkpoint, the wrong tokenizer, or the pre-rebuild shards still +produces a finite log-sigmoid of a difference of plausible numbers. The loss +decreases. The margin it reports is a margin against something that does not +exist. + +The key therefore carries six components, and each one is a way somebody has +or could break this: + + * `checkpoint_hash` -- the obvious one; a cache from the previous SFT run. + Must be a CONTENT hash (`checkpoint_content_hash`): the tensor-inventory + hash cannot tell two SFT checkpoints of one architecture apart. + (A seventh, DIAGNOSTIC field, `checkpoint_inventory_hash`, carries the + inventory hash beside it: it is compared like the rest, but its only job + is to make a `checkpoint_hash` mismatch legible -- inventory equal means + "same architecture, different weights", the stale-SFT-attempt case.) + * `tokenizer_hash` -- retokenized pairs are different pairs. + * `manifest_hash` -- the one the plan did not list and this project needs + most: section-03's shards are being REBUILT (the duplicated `# Answer` + marker fix). A rebuild changes every pair's tokens while leaving the + checkpoint, the tokenizer and max_length identical, so nothing else in the + key moves. + * `max_length` and `truncation_mode` -- a completion truncated differently + has a different summed logprob, and summed logprobs are what DPO compares. + * `forward_impl` -- a single-GPU forward and an FSDP2-sharded forward are + not bitwise identical. That is the PATH-BIAS risk, and it is measured + (`path_bias_decision`) rather than assumed away, because early in DPO the + policy IS the reference and the loss argument sits at zero, which is + exactly where a systematic reference bias does the most damage. + +EXISTING CACHES MUST BE RE-PRECOMPUTED (2026-10-12). Before this date the +launchers filled `checkpoint_hash` from the tensor-inventory hash +(`checkpoint_fingerprint()["manifest_sha256"]`). Every cache written that way +carries a key that can no longer be reproduced from a checkpoint's weights, so +it is refused by `load_ref_cache(expect=...)` -- correctly, because it could not +have told its own checkpoint from any sibling's. The refusal names +`checkpoint_hash`; the fix is to re-run scripts/precompute_ref_logprobs.py, not +to loosen the comparison. Both launchers now build the key through +`build_ref_cache_key`, the single place the six facts are assembled. +""" + +from __future__ import annotations + +import hashlib +import json +import logging +import math +import os +from dataclasses import asdict, dataclass, field, fields +from typing import Any, Iterable, Optional, Sequence + +import torch + +logger = logging.getLogger(__name__) + +NAN = float("nan") + +#: One entry per pair. Lengths are carried because `sigmoid_norm` divides by +#: them; a length of 0 (a prompt-only row) must make the normalised quantity +#: NaN rather than raise a ZeroDivisionError three weeks later. +ENTRY_FIELDS = ("ref_logp_chosen", "ref_logp_rejected", "len_chosen", "len_rejected") + +#: How the pass actually ran. Not a preference -- a record. +FORWARD_IMPLS = ("single_gpu", "fsdp2_sharded") + + +@dataclass(frozen=True) +class RefCacheKey: + """Everything that could silently change a cached reference logprob. + + Frozen and compared component-by-component so a mismatch names the guilty + field. `RuntimeError: ref cache mismatch` with no further detail sends + somebody hunting through three sections; `mismatched: manifest_hash + (cache=man-abc, run=man-xyz)` sends them to the shard rebuild. + """ + + checkpoint_hash: str + tokenizer_hash: str + manifest_hash: str + max_length: int + truncation_mode: str + forward_impl: str + #: DIAGNOSTIC companion to `checkpoint_hash` (see the module docstring). + #: Empty only on caches written before 2026-10-12, which are refused on + #: `checkpoint_hash` anyway. + checkpoint_inventory_hash: str = "" + + def __post_init__(self) -> None: + if self.forward_impl not in FORWARD_IMPLS: + raise ValueError( + f"forward_impl={self.forward_impl!r} must be one of " + f"{FORWARD_IMPLS}: it records how the pass ACTUALLY ran, and " + "an unrecognised tag cannot be compared against the run's." + ) + + def to_json(self) -> str: + return json.dumps(asdict(self), sort_keys=True) + + @classmethod + def from_json(cls, blob: str) -> "RefCacheKey": + return cls(**json.loads(blob)) + + def mismatches(self, other: "RefCacheKey") -> list[str]: + return [f.name for f in fields(self) if getattr(self, f.name) != getattr(other, f.name)] + + +@dataclass +class RefCache: + key: RefCacheKey + #: pair_id -> (ref_logp_chosen, ref_logp_rejected, len_chosen, len_rejected) + entries: dict[str, tuple[float, float, float, float]] = field(default_factory=dict) + + def __len__(self) -> int: + return len(self.entries) + + def require(self, pair_id: str) -> tuple[float, float, float, float]: + """Look up a pair, or raise. There is no default: a zero reference + turns DPO into likelihood maximisation on the chosen side, which + trains and converges and is not DPO.""" + try: + return self.entries[pair_id] + except KeyError: + raise KeyError( + f"pair_id {pair_id!r} is not in the reference cache " + f"({len(self.entries)} entries, key {self.key.to_json()}). " + "Refusing to substitute a default reference logprob. Either " + "the precompute did not cover this split, or these shards are " + "not the ones it ran over." + ) from None + + +def build_ref_cache_key( + sft_checkpoint: str, manifest: dict, *, forward_impl: str +) -> RefCacheKey: + """The ONE place a launcher turns facts into a `RefCacheKey`. + + Both scripts/precompute_ref_logprobs.py (writer) and scripts/dpo.py + (reader) call this, so the key they compare cannot drift apart again. The + drift it replaces: each script assembled the key inline and BOTH filled + `checkpoint_hash` from the tensor-inventory hash (2026-10-12 review), so + two different-weight SFT checkpoints produced the same key. Here + `checkpoint_hash` is the WEIGHT-BYTES hash (`checkpoint_content_hash`; one + streamed read of the checkpoint, ~14.5GB at 7B) and the inventory hash + rides along as `checkpoint_inventory_hash`. + + `manifest_hash` covers the shard rebuild nothing else in the key notices; + `forward_impl` is a record of how the pass ran and is the caller's to state. + """ + from ..data.receipts import content_hash + + return RefCacheKey( + checkpoint_hash=checkpoint_content_hash(sft_checkpoint), + tokenizer_hash=manifest["tokenizer_hash"], + manifest_hash=content_hash( + [manifest["hashes"][k] for k in sorted(manifest.get("hashes", {}))] + ), + max_length=int(manifest.get("pinned", {}).get("max_len", 2048)), + truncation_mode="right", + forward_impl=forward_impl, + checkpoint_inventory_hash=checkpoint_inventory_hash(sft_checkpoint), + ) + + +def peek_ref_cache_key(path: str) -> Optional[RefCacheKey]: + """The key stored in a cache file's header, or None when there is no file. + + INSPECTION ONLY -- it validates nothing about the cache. It exists so a + launcher can read the one component that is a RECORD rather than an + expectation (`forward_impl`: how the cache's own pass ran) from the cache + itself, build the expected key around it, and then `load_ref_cache(path, + expect=...)`, which asserts the other components. Never a substitute for + that load. + """ + from safetensors import safe_open + + if not os.path.isfile(path): + return None + with safe_open(path, framework="pt") as f: + meta = f.metadata() or {} + if "key" not in meta: + return None + return RefCacheKey.from_json(meta["key"]) + + +#: What `cache_forward_impl` reads when the report is written before any cache +#: exists. Not a member of FORWARD_IMPLS on purpose: it can never equal a real +#: cache's tag, so nothing can mistake "no cache yet" for a measured pass. +NO_CACHE_YET = "no_cache_at_report_time" + + +def path_bias_report_cache_forward_impl(cache_path: str) -> str: + """The `forward_impl` a path-bias report should record as `cache_forward_impl`. + + The report's field is about the CACHE the training run will consume; the + `--path-bias` run measures it but does not recompute it. So the value is + the on-disk train cache's own tag, or `NO_CACHE_YET` when the measurement + was taken first. The launcher does not read this field back for its + expectation (it reads the cache), so this is a record, not a lever. + """ + key = peek_ref_cache_key(cache_path) + return key.forward_impl if key is not None else NO_CACHE_YET + + +def _checkpoint_files(path: str) -> list[str]: + """The weight files of a checkpoint, in the order they are hashed. + + A `.safetensors` file, a directory holding `model.safetensors`, or a + sharded directory (index + shards, sorted by name). + """ + from ..model.checkpoint import INDEX_NAME, WEIGHTS_NAME + + if os.path.isfile(path): + files = [path] + else: + single = os.path.join(path, WEIGHTS_NAME) + index = os.path.join(path, INDEX_NAME) + if os.path.isfile(single): + files = [single] + elif os.path.isfile(index): + with open(index) as f: + shards = sorted(set(json.load(f)["weight_map"].values())) + files = [os.path.join(path, s) for s in shards] + missing = [s for s in files if not os.path.isfile(s)] + if missing: + raise FileNotFoundError(f"{INDEX_NAME} names shard(s) absent from {path!r}: {missing}") + else: + raise FileNotFoundError(f"no {WEIGHTS_NAME} or {INDEX_NAME} at {path!r}") + return files + + +def checkpoint_inventory_hash(path: str) -> str: + """Hash of the tensor INVENTORY (name, shape, dtype) read from the safetensors + HEADERS only -- no tensor data is materialised. + + This is the DIAGNOSTIC companion to `checkpoint_content_hash`, not a + substitute: it is exactly the kind of hash that cannot distinguish two + checkpoints of one architecture, which is its use -- when `checkpoint_hash` + mismatches and this one does not, the cache is from the same architecture + with different weights (the stale-SFT-attempt case). Deliberately NOT + `checkpoint_fingerprint()["manifest_sha256"]`: that routes through + `load_hf_safetensors`, which reads the whole 14.5GB into RAM on every rank + just to print shapes -- four ranks of it at gate 3 on a no-swap box. + """ + from safetensors import safe_open + + inventory = {} + for fp in _checkpoint_files(path): + with safe_open(fp, framework="pt") as f: + for k in f.keys(): + sl = f.get_slice(k) + inventory[k] = [list(sl.get_shape()), str(sl.get_dtype())] + return hashlib.sha256(json.dumps(inventory, sort_keys=True).encode()).hexdigest()[:16] + + +def checkpoint_content_hash(path: str) -> str: + """Hash of the checkpoint's WEIGHT BYTES: the value `RefCacheKey.checkpoint_hash` must carry. + + WHY THIS EXISTS (review of 2026-10-12). The launchers used to fill + `checkpoint_hash` from `checkpoint_fingerprint(path)["manifest_sha256"]`, + which hashes only the tensor inventory (name, shape, dtype). Every full-FT + SFT checkpoint of one architecture has the SAME inventory, so a cache from + a previous SFT attempt, or from micro_00000100 when the gate passed + micro_00000200, produced an identical key and loaded without complaint -- + the exact stale-cache failure this key is documented to defend against + ("a cache from the previous SFT run"). The receipt module says so itself + (`weights_sha256` is the content hash; `manifest_sha256` is a structure + hash), and `test_fingerprint_does_not_call_a_structure_hash_a_content_hash` + pins it. Reading ~14.5GB once per launch is the price of the key meaning + what it says; it is streamed in 64MB blocks and never held in memory. + + Accepts a `.safetensors` file, a directory holding `model.safetensors`, or + a sharded directory (index + shards). Shard names are hashed together with + their bytes, in sorted order, so a renamed or reordered shard set changes + the hash too. + """ + files = _checkpoint_files(path) + h = hashlib.sha256() + for fp in files: + h.update(os.path.basename(fp).encode() + b"\0") + with open(fp, "rb") as fh: + for block in iter(lambda: fh.read(64 << 20), b""): + h.update(block) + return h.hexdigest()[:16] + + +def _atomic_write(path: str, write) -> None: + """Run `write(tmp_path)` then `os.replace` onto `path`. + + A cache or report written straight to its final name and killed mid-write + (the host has seized mid-checkpoint before) leaves a truncated file at the + name the next launch trusts, and REPLACES a previously good one. The temp + file sits beside the target (same filesystem, on /apps) so the rename is + atomic, and is removed if the write raises. + """ + tmp = f"{path}.tmp.{os.getpid()}" + try: + write(tmp) + os.replace(tmp, path) + except BaseException: + if os.path.exists(tmp): + os.remove(tmp) + raise + + +# --------------------------------------------------------------------------- +# I/O +# --------------------------------------------------------------------------- + + +def write_ref_cache(path: str, cache: RefCache) -> str: + """One safetensors file per (arm, split): tensors for the values, the key + and the pair-id order in the metadata. + + One file, not a tensor file plus a JSON sidecar, because a cache split + across two files can half-exist -- and a half-existing cache is the + resumable-looking partial checkpoint problem in another costume. + """ + from safetensors.torch import save_file + + from ..utils.guard import assert_paths_off_root + + assert_paths_off_root([os.path.dirname(os.path.abspath(path))]) + pair_ids = list(cache.entries) + cols = list(zip(*(cache.entries[p] for p in pair_ids))) if pair_ids else [(), (), (), ()] + # float64 throughout: the values arrive as fp32 (the log-softmax is upcast + # even in a bf16 forward) and float32 -> float64 is exact, so the stored + # number IS the computed number. Storing them as fp32 would be equally + # exact today and would silently truncate if the compute dtype ever rose. + tensors = { + name: torch.tensor(col, dtype=torch.float64) for name, col in zip(ENTRY_FIELDS, cols) + } + from ..data.loader import PREFERENCE_MASK_VERSION + + _atomic_write( + path, + lambda tmp: save_file( + tensors, + tmp, + metadata={ + "key": cache.key.to_json(), + "pair_ids": json.dumps(pair_ids), + "mask_version": PREFERENCE_MASK_VERSION, + }, + ), + ) + logger.info("ref cache written: %s (%d pairs)", path, len(pair_ids)) + return path + + +def load_ref_cache(path: str, expect: Optional[RefCacheKey] = None) -> RefCache: + """Load a cache and, when `expect` is given, ASSERT the key. + + Loading without `expect` is for inspection tools only. Every training path + passes it; that assertion is the entire defence against a stale cache. + """ + from safetensors import safe_open + + if not os.path.isfile(path): + raise FileNotFoundError( + f"reference cache {path!r} does not exist. Run " + "scripts/precompute_ref_logprobs.py for this arm first; DPO " + "cannot proceed without it and will not invent one." + ) + with safe_open(path, framework="pt") as f: + meta = f.metadata() or {} + cols = {name: f.get_tensor(name) for name in ENTRY_FIELDS} + if "key" not in meta or "pair_ids" not in meta: + raise RuntimeError( + f"{path!r} carries no cache key. An unkeyed cache cannot be shown " + "to belong to this checkpoint, tokenizer and shard build, so it is " + "refused rather than trusted." + ) + from ..data.loader import PREFERENCE_MASK_VERSION + + cache_mask = meta.get("mask_version", "prompt_len_v1") + if cache_mask != PREFERENCE_MASK_VERSION: + raise RuntimeError( + f"{path!r} was precomputed under completion-mask semantics " + f"{cache_mask!r} but this build uses {PREFERENCE_MASK_VERSION!r} " + "(audit R1, 2026-08-23: the boundary moved from prompt_len to " + "shared_prefix_len). Reference logprobs are mask-dependent; " + "recompute the cache rather than mixing semantics." + ) + key = RefCacheKey.from_json(meta["key"]) + if expect is not None: + bad = key.mismatches(expect) + if bad: + detail = "; ".join( + f"{n} (cache={getattr(key, n)!r}, run={getattr(expect, n)!r})" for n in bad + ) + legacy = "" + if "checkpoint_hash" in bad and not key.checkpoint_inventory_hash: + legacy = ( + " This cache carries no checkpoint_inventory_hash: it predates " + "the 2026-10-12 content-hash key, whose checkpoint_hash was a " + "tensor-inventory hash that cannot identify a checkpoint. It " + "must be re-precomputed." + ) + raise RuntimeError( + f"reference cache {path!r} does not match this run. " + f"Mismatched: {detail}.{legacy} A stale reference cache does not fail " + "loudly at train time -- the loss stays finite, the curve " + "stays healthy, and the margin is measured against a policy " + "that never existed. Re-run the precompute." + ) + pair_ids = json.loads(meta["pair_ids"]) + entries = {p: tuple(float(cols[n][i]) for n in ENTRY_FIELDS) for i, p in enumerate(pair_ids)} + return RefCache(key=key, entries=entries) + + +# --------------------------------------------------------------------------- +# Precompute +# --------------------------------------------------------------------------- + + +def _labels( + input_ids: torch.Tensor, completion_mask: torch.Tensor, ignore_index: int +) -> torch.Tensor: + """Completion-only labels: prompt AND pad positions ignored. + + Excluding the prompt is not cosmetic. For Arm B the entire shared prefix + is identical across the two sides, so including it adds the same term to + both logprobs: it cancels in the DPO difference while inflating both + magnitudes, and any length-normalised variant computed from it is wrong. + """ + return input_ids.masked_fill(completion_mask == 0, ignore_index) + + +@torch.no_grad() +def _side_logprobs( + model, input_ids: torch.Tensor, completion_mask: torch.Tensor, ignore_index: int +) -> tuple[torch.Tensor, torch.Tensor]: + """Summed completion logprobs via the SAME routine `fused_dpo` uses. + + Not a reimplementation: `completion_logprobs_eager` is imported from the + kernel module, and the caller-side shift here (`logits[:, :-1]` against + `labels[:, 1:]`) is the shift the DPO adapter applies at train time. If + precompute and consumption disagreed by one position, DPO would start from + a nonzero margin against itself and spend the run optimising a constant + offset it can never remove. + """ + from ..kernels.fused_dpo import completion_logprobs_eager + + labels = _labels(input_ids, completion_mask, ignore_index) + logits = model(input_ids=input_ids) + return completion_logprobs_eager(logits[:, :-1], labels[:, 1:], ignore_index) + + +def precompute_ref_logprobs( + model, + rows: Sequence[Any], + *, + key: RefCacheKey, + pad_token_id: int, + batch_size: int = 8, + device: Optional[torch.device] = None, +) -> RefCache: + """One no-grad pass over `rows`, returning a keyed cache. + + `rows` are in the shape `collate_preference` consumes (section-03's + `preference_row_from_store` produces them); every row must carry a + `pair_id`, because pair_id is how refs find their way back to the right + training example after any reshuffle. + + NOTE on batch size -- why it is NOT a key component, MEASURED not assumed. + Right-padding plus causal masking makes padded columns unreachable, so the + value is mathematically independent of how rows are grouped; the fp32 + reduction ORDER is not. Measured on the tiny CPU harness (40 pairs, batch + size 1 vs 2/4/8/20/40): max |delta logp| 3.8e-06 = 9.7e-08 relative, max + |delta reference MARGIN| 5.7e-06, mean delta ~1e-07. Symmetric rounding + noise, not a systematic offset -- which is the distinction that decides + it, since only a systematic offset biases the loss argument. Run through + this module's own `path_bias_decision` the ratio is ~1e-05 against a 0.05 + threshold, so the same rule that governs single-GPU-vs-sharded says + negligible here. Bitwise determinism holds at a FIXED batch size, which is + the property the caching design actually needs, and + `test_batch_size_variation_is_below_the_path_bias_threshold` keeps this + paragraph honest. + """ + from ..data.loader import collate_preference + from ..kernels.fused_dpo import IGNORE_INDEX + + if getattr(model, "training", False): + raise RuntimeError( + "the reference model is in train mode. Mistral-v0.3 sets " + "attention_dropout 0.0 so this is PROBABLY harmless -- which is " + "exactly why nobody would notice, and why 'probably' is not a " + "basis for numbers that get cached and consumed as constants for " + "the rest of the stage. Call model.eval()." + ) + if batch_size < 1: + raise ValueError(f"batch_size={batch_size} must be >= 1") + + rows = list(rows) + entries: dict[str, tuple[float, float, float, float]] = {} + for start in range(0, len(rows), batch_size): + chunk = rows[start : start + batch_size] + batch = collate_preference(chunk, pad_token_id=pad_token_id) + if device is not None: + batch = batch.to(device) + lp_c, len_c = _side_logprobs( + model, batch.chosen_input_ids, batch.chosen_completion_mask, IGNORE_INDEX + ) + lp_r, len_r = _side_logprobs( + model, batch.rejected_input_ids, batch.rejected_completion_mask, IGNORE_INDEX + ) + for i, meta in enumerate(batch.metadata): + pid = meta.get("pair_id") + if pid is None: + raise ValueError( + "a preference row carries no pair_id. Refs are joined to " + "training rows BY pair_id; a row without one could only be " + "joined by position, which mis-pairs under any reshuffle." + ) + if pid in entries: + raise ValueError( + f"duplicate pair_id {pid!r}: the cache is a mapping, so a " + "duplicate would silently overwrite one pair's reference " + "with another's." + ) + entries[pid] = (float(lp_c[i]), float(lp_r[i]), float(len_c[i]), float(len_r[i])) + logger.info("precomputed %d reference pairs (%s)", len(entries), key.forward_impl) + return RefCache(key=key, entries=entries) + + +# --------------------------------------------------------------------------- +# Joining refs to batches +# --------------------------------------------------------------------------- + + +def attach_refs(batch, cache: RefCache): + """Fill a `Preference` batch's ref tensors FROM THE CACHE, by pair_id. + + By pair_id and never by position. The section-03 loader is length-grouped + and shuffled per epoch, so batch order is not cache order and never will + be; a positional join would attach a perfectly plausible reference to the + wrong row, produce a finite loss, and point the gradient somewhere + arbitrary. Nothing downstream can see it. + """ + pair_ids = [] + for i, meta in enumerate(batch.metadata): + pid = (meta or {}).get("pair_id") + if pid is None: + raise ValueError( + f"row {i} of this batch carries no pair_id, so its reference " + "logprobs cannot be looked up. Falling back to batch order is " + "the silent-substitution incident this join exists to prevent." + ) + pair_ids.append(pid) + + vals = [cache.require(p) for p in pair_ids] + dtype = torch.float32 + batch.ref_chosen_logps = torch.tensor([v[0] for v in vals], dtype=dtype) + batch.ref_rejected_logps = torch.tensor([v[1] for v in vals], dtype=dtype) + return batch + + +# --------------------------------------------------------------------------- +# Held-out preference accuracy +# --------------------------------------------------------------------------- + + +@torch.no_grad() +def heldout_preference_accuracy( + model, batches: Iterable[Any], cache: RefCache, beta: float, z: float = 1.96 +) -> dict: + """Fraction of held-out pairs the policy's IMPLICIT reward prefers. + + The implicit reward difference is beta * [(logp_c - logp_r) - (ref_c - + ref_r)]; the pair counts as correct when it is strictly positive. This is + the stage's primary health metric together with the margin, and it is + deliberately NOT benchmark accuracy: the pre-registered expectations for + both arms are about preference fit, and section-13 owns the paired + benchmark evaluation. + + Empty or degenerate held-out sets report NaN, never 0. Note the + distinction the test pins: at initialisation the policy IS the reference, + every implicit margin is exactly 0.0, and nothing is STRICTLY preferred -- + accuracy 0.0 over a real denominator. That is an honest measurement, and + it is a different fact from NaN over a denominator of zero. + """ + from ..eval.metrics import wilson_interval + from ..kernels.fused_dpo import IGNORE_INDEX + + was_training = getattr(model, "training", False) + model.eval() + n = 0 + correct = 0 + margin_sum = 0.0 + try: + for batch in batches: + if int(batch.chosen_input_ids.shape[0]) == 0: + continue + lp_c, _ = _side_logprobs( + model, batch.chosen_input_ids, batch.chosen_completion_mask, IGNORE_INDEX + ) + lp_r, _ = _side_logprobs( + model, batch.rejected_input_ids, batch.rejected_completion_mask, IGNORE_INDEX + ) + for i, meta in enumerate(batch.metadata): + pid = (meta or {}).get("pair_id") + if pid is None: + raise ValueError("held-out row carries no pair_id") + ref_c, ref_r, _, _ = cache.require(pid) + m = beta * ((float(lp_c[i]) - float(lp_r[i])) - (ref_c - ref_r)) + margin_sum += m + correct += int(m > 0.0) + n += 1 + finally: + if was_training: + model.train() + + if n == 0: + return { + "accuracy": NAN, + "ci_low": NAN, + "ci_high": NAN, + "mean_margin": NAN, + "n": 0, + "correct": 0, + "beta": beta, + } + lo, hi = wilson_interval(correct, n, z) + return { + "accuracy": correct / n, + "ci_low": lo, + "ci_high": hi, + "mean_margin": margin_sum / n, + "n": n, + "correct": correct, + "beta": beta, + } + + +# --------------------------------------------------------------------------- +# Path bias +# --------------------------------------------------------------------------- + + +def path_bias_decision( + deltas: Sequence[float], *, beta: float, early_margin_scale: float, threshold: float +) -> dict: + """Decide whether a single-GPU reference cache is usable under FSDP2. + + `deltas` are per-pair differences of the REFERENCE MARGIN (ref_c - ref_r) + between the single-GPU forward and the sharded forward. The two are not + bitwise identical -- different reduction trees, different collective + orders -- and the question is whether the difference matters. + + It matters more here than anywhere else in the project. DPO's loss + argument is beta * (pi_margin - ref_margin). Early in the run the policy + IS the reference, so that argument sits at zero, which is where the + log-sigmoid's gradient is largest and where a systematic offset in + ref_margin is least attenuated. A bias that would be invisible against a + large margin is fully visible against a zero one. + + The rule compares max|delta| to the early-margin scale. Beta multiplies + the perturbation and the reference scale alike, so it CANCELS out of the + ratio; it stays in the signature because the receipt must record the beta + the decision was made under, and because a reader who does not see the + cancellation stated will assume it was forgotten. + + NaN is not small. A NaN delta means a pair could not be compared, and an + uncomparable pair forces the firing path rather than comparing False and + vanishing. So does an empty measurement: not measuring is not passing. + """ + if not (early_margin_scale > 0) or math.isnan(early_margin_scale): + raise ValueError( + f"early_margin_scale={early_margin_scale!r} must be a positive " + "measured scale; it is the denominator of the decision ratio and " + "a zero or NaN one makes the decision undefined rather than lenient" + ) + if not (threshold > 0): + raise ValueError(f"threshold={threshold!r} must be positive") + + vals = [float(d) for d in deltas] + n_nan = sum(1 for d in vals if math.isnan(d)) + if not vals or n_nan: + detail = ( + "no deltas were measured; not measuring is not passing" + if not vals + else f"{n_nan} of {len(vals)} deltas are NaN and a NaN delta is not a small delta" + ) + return { + "fired": True, + "action": "rerun_precompute_sharded", + "ratio": NAN, + "max_abs_delta": NAN, + "mean_delta": NAN, + "median_abs_delta": NAN, + "p95_abs_delta": NAN, + "n": len(vals), + "n_nan": n_nan, + "beta": beta, + "early_margin_scale": early_margin_scale, + "threshold": threshold, + "detail": detail, + } + + absd = sorted(abs(d) for d in vals) + max_abs = absd[-1] + ratio = max_abs / early_margin_scale + fired = ratio > threshold + return { + "fired": fired, + "action": ("rerun_precompute_sharded" if fired else "keep_single_gpu_cache"), + "ratio": ratio, + "max_abs_delta": max_abs, + "mean_delta": sum(vals) / len(vals), + "median_abs_delta": _quantile(absd, 0.5), + "p95_abs_delta": _quantile(absd, 0.95), + "n": len(vals), + "n_nan": 0, + "beta": beta, + "early_margin_scale": early_margin_scale, + "threshold": threshold, + "detail": ( + f"max|delta| {max_abs:.3e} is " + f"{'above' if fired else 'within'} {threshold:g} x the " + f"early-margin scale {early_margin_scale:g}" + ), + } + + +def _quantile(sorted_vals: Sequence[float], q: float) -> float: + if not sorted_vals: + return NAN + idx = min(len(sorted_vals) - 1, max(0, int(round(q * (len(sorted_vals) - 1))))) + return float(sorted_vals[idx]) + + +def batch_invariance_report( + model, + rows: Sequence[Any], + *, + key: RefCacheKey, + pad_token_id: int, + beta: float, + early_margin_scale: float, + threshold: float, + batch_sizes: Sequence[int] = (2, 4, 8, 16), +) -> dict: + """Batched-vs-single-row precompute deltas, as a receipt. + + A SECOND path-bias question, distinct from the single-GPU-vs-sharded one + and cheaper to answer: does it matter how many pairs share a forward? + Right-padding plus causal masking makes the value grouping-independent in + exact arithmetic; the fp32 reduction order is not, so the honest answer is + a measurement. + + It decides one thing: whether `batch_size` belongs in the cache key. It is + judged by the SAME rule as the sharded comparison (`path_bias_decision`), + because it is the same kind of error entering the same place -- a + perturbation of the reference margin, read at the point where the loss + argument sits near zero. + + Reported per batch size, plus the worst case across all of them. A + systematic MEAN delta matters more than a large max: symmetric rounding + averages out of the gradient, a consistent offset does not. + """ + single = precompute_ref_logprobs(model, rows, key=key, pad_token_id=pad_token_id, batch_size=1) + per_size = {} + worst = None + for bs in batch_sizes: + got = precompute_ref_logprobs( + model, rows, key=key, pad_token_id=pad_token_id, batch_size=bs + ) + deltas = [ + (got.entries[p][0] - got.entries[p][1]) - (single.entries[p][0] - single.entries[p][1]) + for p in single.entries + ] + d = path_bias_decision( + deltas, beta=beta, early_margin_scale=early_margin_scale, threshold=threshold + ) + per_size[str(bs)] = d + if worst is None or (not math.isnan(d["ratio"]) and d["ratio"] > worst["ratio"]): + worst = d + return { + "comparison": "batched_vs_single_row", + "n_examples": len(list(rows)), + "batch_sizes": list(batch_sizes), + "per_batch_size": per_size, + "worst": worst, + "belongs_in_cache_key": bool(worst and worst["fired"]), + "detail": ( + "if belongs_in_cache_key is true, batch_size must join the " + "six key components; measured false means regrouping is " + "below the threshold that governs the sharded comparison" + ), + } + + +def write_path_bias_report(path: str, decision: dict, *, n_examples: int, forward_impl: str) -> str: + """The decision is written, not remembered: precompute and training are + separate heavy jobs (serialized by the flock, never concurrent) in + different processes, and the banner reads this file.""" + from ..utils.guard import assert_paths_off_root + + assert_paths_off_root([os.path.dirname(os.path.abspath(path))]) + payload = dict(decision) + payload["n_examples"] = int(n_examples) + payload["cache_forward_impl"] = forward_impl + def _dump(tmp: str) -> None: + with open(tmp, "w") as f: + json.dump(payload, f, indent=2) + + _atomic_write(path, _dump) + logger.info("path-bias report -> %s (fired=%s)", path, decision["fired"]) + return path + + +def read_path_bias_report(path: str) -> dict: + if not os.path.isfile(path): + raise FileNotFoundError( + f"path-bias report {path!r} is missing. The measurement is " + "MANDATORY before a DPO launch: a sharded forward that disagrees " + "with the cached single-GPU reference biases the loss argument " + "exactly where it is most sensitive. Run " + "scripts/precompute_ref_logprobs.py --path-bias." + ) + with open(path) as f: + return json.load(f) diff --git a/code/align/train/sft_loss.py b/code/align/train/sft_loss.py new file mode 100644 index 0000000000000000000000000000000000000000..d9e27fcd132081a153ee25aa8b7081a4501b098b --- /dev/null +++ b/code/align/train/sft_loss.py @@ -0,0 +1,150 @@ +"""SFT loss adapter: collated batch -> section-05's chunked fused CE. + +LOSS NORMALISATION (G3 audit U03-2). DEFAULT UNCHANGED; the global token mean is OPT-IN via +`train.loss_normalization = "global_token_mean"` (Trainer window look-ahead + +`TrainModule.train_batch(window_tokens=...)`; this adapter supplies `count_tokens`). +The paragraph below describes the default, "micro_mean". +The returned loss is the TOKEN MEAN OF ONE MICRO-BATCH, and `n_tokens` is only +reported. Under grad-accum A and world W the window gradient is therefore the +mean of A*W micro-batch means -- not the gradient of the global per-token mean +(sum CE / sum n_tokens): a target token carries weight 1/(A*W*n_micro), so with +token-budget batches whose target counts differ (280 vs 6) the short batch's +tokens weigh ~47x more. The claim "matches one large batch" holds only for +equal-n micro-batches. Making it a global token mean needs the window's token +total (a look-ahead over the window's batches plus a cross-rank reduce) and the +adapter returning CE_sum; that changes the objective every recorded SFT run +was trained under, so it is a protocol decision, not a bug fix made here. + +The adapter owns plumbing only -- label shifting, masking, token accounting -- +and section-05 owns the kernel. Keeping the shift on THIS side (caller-shifted +views) is the arbitrated contract: `fused_linear_cross_entropy` takes hidden +states and labels that already line up, so there is exactly one place in the +repo that decides what predicts what. + +Why the fused path matters, so the reason survives the handoff: at seq 1024 and +micro-batch 8 the `[B*T, 32768]` logit tensor is 1.0GB in bf16 and its gradient +is another 1.0GB. Materialising both spends 2GB of a 23GB card on a tensor +nobody reads. The fused loss consumes HIDDEN STATES and applies the LM head per +chunk, which is why `NmoMistralForCausalLM.forward_hidden_states` exists as a +separate entry point. +""" + +from __future__ import annotations + +import logging +from typing import Any, Optional + +import torch +import torch.nn.functional as F + +from .trainer import LossOutput + +logger = logging.getLogger(__name__) + +#: Section-05's kernel module. Named here so the both-directions test can block +#: the import and exercise the refusal branch. +FUSED_CE_MODULE = "align.kernels.fused_ce" + +#: Fallback only. The authority is section-05's constant (imported below when +#: available) and section-03's collator, which both use -100; this literal +#: exists so the module still loads if the kernel is missing. +IGNORE_INDEX = -100 + + +def _load_fused(): + """Return (fused_fn, ignore_index) or (None, IGNORE_INDEX).""" + try: + import importlib + + mod = importlib.import_module(FUSED_CE_MODULE) + return mod.fused_linear_cross_entropy, mod.IGNORE_INDEX + except Exception: # noqa: BLE001 + return None, IGNORE_INDEX + + +def fused_ce_available() -> bool: + return _load_fused()[0] is not None + + +def make_sft_loss_adapter(chunk_size: Optional[int] = None, require_fused: bool = False): + """Build the SFT loss adapter the Trainer calls once per micro-step. + + `require_fused=True` refuses to run on the reference path -- which is what + the 7B stage scripts pass, so a GPU run cannot quietly spend 2GB of card on + a materialised logit tensor because section-05's import broke. + """ + fused_fn, ignore_index = _load_fused() + if require_fused and fused_fn is None: + raise RuntimeError( + f"the fused chunked cross-entropy ({FUSED_CE_MODULE}." + "fused_linear_cross_entropy) is not importable. Refusing to fall " + "back to the reference path for a full-scale run: it materialises " + "the [B*T, 32768] logit tensor AND its gradient, ~2GB of a 23GB " + "card at seq 1024." + ) + if fused_fn is None: + logger.warning( + "%s unavailable; using the reference path. Correct, and " + "memory-hungry -- small-model use only.", + FUSED_CE_MODULE, + ) + + kwargs = {} if chunk_size is None else {"chunk_size": chunk_size} + + def adapter(model, batch) -> LossOutput: + input_ids, labels = _unpack(batch) + # Caller-shifted: position t predicts token t+1. Done once, here. + target = labels[:, 1:] + n_tokens = int((target != ignore_index).sum()) + if n_tokens == 0: + raise ValueError( + "SFT batch has no unmasked target tokens: every position is " + f"ignore_index ({ignore_index}). The mean cross-entropy over " + "zero positions is undefined, and returning 0.0 would report a " + "perfectly fit batch. Check prompt_len against sequence length " + "in the collator." + ) + + if fused_fn is not None: + # The loss runs INSIDE the model's forward via `hidden_consumer`, + # so section-05 still owns the lm_head matmul while FSDP2 has both + # the hidden states and lm_head.weight gathered. Computing it + # after the forward returned would see `lm_head.weight` re-sharded + # -- the mixed-DTensor failure that killed the first 4-rank smoke. + def _consume(hidden, lm_head_weight): + return fused_fn( + hidden[:, :-1], lm_head_weight, target, ignore_index=ignore_index, **kwargs + ) + + loss = model(input_ids=input_ids, hidden_consumer=_consume) + else: + logits = model(input_ids=input_ids) + loss = F.cross_entropy( + logits[:, :-1].reshape(-1, logits.shape[-1]).float(), + target.reshape(-1), + ignore_index=ignore_index, + ) + + return LossOutput(loss=loss, n_tokens=n_tokens, metrics={"tokens_in_loss": float(n_tokens)}) + + def count_tokens(batch) -> int: + """Unmasked target tokens of `batch` (what `n_tokens` will be), without a forward pass. + The Trainer sums this over a look-ahead window for the global token mean.""" + _, labels = _unpack(batch) + return int((labels[:, 1:] != ignore_index).sum()) + + adapter.uses_fused = fused_fn is not None + adapter.count_tokens = count_tokens + return adapter + + +def _unpack(batch: Any) -> tuple[torch.Tensor, torch.Tensor]: + """Accept either a `Collated` from section-03 or a plain (ids, labels).""" + if hasattr(batch, "input_ids") and hasattr(batch, "labels"): + return batch.input_ids, batch.labels + if isinstance(batch, (tuple, list)) and len(batch) == 2: + return batch[0], batch[1] + raise TypeError( + f"SFT loss adapter got {type(batch).__name__}; expected a Collated " + "batch (input_ids, labels) from align.data.loader.collate_sft" + ) diff --git a/code/align/train/sharded_ckpt.py b/code/align/train/sharded_ckpt.py new file mode 100644 index 0000000000000000000000000000000000000000..e89b6640ed36a953cb67df7b7d5048bb4be68412 --- /dev/null +++ b/code/align/train/sharded_ckpt.py @@ -0,0 +1,1285 @@ +"""Sharded streaming checkpoints: every rank writes ONLY the weights it owns. + +OPT-IN (`train.checkpoint_format = "sharded"`; the default `"gathered"` is +untouched). Runtime deps: torch + stdlib. The converter half (`export_hf`, +`reshard`) never touches a GPU and never imports transformers/safetensors. + +THE PROBLEM, MEASURED (docs/MEASUREMENTS.md, Track M, OLMoE-1B-7B, 4 ranks) + * save 228-241 s, rank-0 RSS peak +28 GB. `get_model_state_dict( + full_state_dict=True, cpu_offload=True)` is a full all-gather into rank 0's + host RAM (1x weights), and the HF converter then builds a second dict of + cloned expert slices plus `.contiguous()` copies (the other 1x): 2x the + weights on ONE rank of a no-swap, shared box -- the 2026-08-12 OOM shape. + Ranks 1..N-1 sit in a barrier for the whole four minutes. + * resume peaks at 90 GiB SUMMED RSS across ranks: `resume_from` reads the + whole `model.safetensors` on EVERY rank and then slices out the 1/N it + owns. +OLMo-core avoids both with distributed checkpointing (per-rank files, no full +gather). This is the same idea at the size this repo needs. + +LAYOUT (a checkpoint directory in sharded mode) + model_rank00000.safetensors ... one per rank; that rank's LOCAL shards, + bf16, standard safetensors (any reader + opens them), written tensor by tensor + optimizer_rank{r}.pt unchanged: the existing per-rank optimizer + files (sharded mode implies them) + shard_manifest.json global shapes, placements, per-rank row + ranges, world size, per-file bytes and + sha256, the HF export recipe + resume.pt unchanged loop state (no weights) + tokenizer files as in the gathered layout +The manifest is written last, inside the `.partial` staging directory, and the +directory is published by the existing fsync-then-rename protocol. A directory +without a complete manifest and every rank file the manifest names is not a +checkpoint (`sharded_problem`, called from `trainer.checkpoint_problem`). + +WHAT EACH PIECE PREVENTS (incident-first, repo style) + +THE WRONG-SHARD DEFECT. A rank's file holds rows [off, off+n) of each tensor. +Loaded under a different world size, rank r would receive rows cut for another +partitioning and training would continue plausibly on scrambled weights -- +nothing crashes, the loss is merely worse. Resume therefore reads the manifest +FIRST and REFUSES a different world size with a message naming the offline +reshard (`scripts/ckpt_convert.py reshard`); it never "tries" a mismatch. The +per-row ranges recorded in the manifest are also compared against the LIVE +model's own sharding tensor by tensor, so a model rebuilt with a different mesh +or an uneven-sharding change is caught even at the same world size. + +THE SILENT-CORRUPTION DEFECT. Per-file sha256 is recorded at save and checked +by each rank, on its OWN file, before any weight is copied. The verdict is then +reduced across ranks (`any_rank`): a bit-rotted file on rank 2 alone would +otherwise make rank 2 raise while ranks 0/1/3 entered the next collective and +hung until the watchdog -- the lone-rank shape every other decision in the +trainer avoids. The save side uses the same reduction: a rank whose disk fills +mid-write must stop its peers at once, not leave them in a gather for the +watchdog's 30 minutes. + +THE TWO-COPIES-ON-RANK-0 DEFECT (the measured 28 GB). There is no gather. Each +rank's peak is ONE tensor (`emit` copies one local shard to host, writes it, +drops it). The export side is byte-copy `pread` -> `write` in 8 MiB pieces: for +1:1 families it never builds a tensor at all. + +THE PARTIAL-WRITE DEFECT (same as the gathered format). Rank files are written +to `*.tmp`, fsynced, renamed into the `.partial` staging dir; the staging dir +is fsync_tree'd and renamed to `micro_N` only after rank 0 has the manifest of +every rank. A kill anywhere leaves a `.partial` that `_discard_partials` +removes at the next start, never a `micro_N` that looks resumable. + +WHAT THIS DOES NOT DO (read before relying on it) + * It is not loadable by `eval_checkpoint.py` / the rollout weight sync / + `ref_cache` until exported: those read `model.safetensors`. Export is + `ckpt_convert.py export` (streaming, bounded memory). + * Placements: `Shard(0)` and `Replicate()` on a 1-D mesh (what + `fully_shard` produces). Anything else (HSDP, TP, Shard(d>0)) is refused + at SAVE time, not discovered at resume. + * A train module that changes what "the weights" mean (LoRA folds an + adapter into merged weights; PPO has its own gather) must provide + `sharded_model_state()` / `load_sharded_model_state()` or the Trainer + refuses `"sharded"` at construction. Silent fallback to the base-class + behaviour would checkpoint the UNMERGED base under a merged name. +""" + +from __future__ import annotations + +import hashlib +import json +import logging +import os +import re +import shutil +import struct +from dataclasses import dataclass +from typing import Any, Callable, Iterable, Mapping, Optional + +import torch + +logger = logging.getLogger(__name__) + +SHARD_MANIFEST_NAME = "shard_manifest.json" +FORMAT_NAME = "align-sharded-ckpt" +FORMAT_VERSION = 1 +CHECKPOINT_FORMATS = ("gathered", "sharded") + +#: Bytes moved per pread/write while exporting or resharding. Peak RSS of the +#: converter is a small multiple of this plus one optimizer tensor, whatever the +#: model size. +COPY_CHUNK = 8 * 1024 * 1024 + +#: Files in a sharded checkpoint directory that are NOT tokenizer/config +#: payload (the exporter copies everything else next to the weights). +_OWN_FILE_RE = re.compile( + r"^(model_rank\d+\.safetensors(\.tmp)?|optimizer_rank\d+\.pt(\.tmp)?|resume\.pt|" + + r"integrity\.json|" + + re.escape(SHARD_MANIFEST_NAME) + + r")$" +) + + +class ShardedCheckpointError(RuntimeError): + """A sharded checkpoint that is malformed, mismatched, or corrupt.""" + + +class CheckpointIntegrityError(ShardedCheckpointError): + """A payload file's sha256 differs from the one recorded at save time.""" + + +class ShardedWorldSizeError(ShardedCheckpointError): + """Resume under a world size other than the one that saved the shards.""" + + +# --------------------------------------------------------------------------- +# dtypes +# --------------------------------------------------------------------------- + +_ST_TO_TORCH = { + "BOOL": torch.bool, + "U8": torch.uint8, + "I8": torch.int8, + "I16": torch.int16, + "F16": torch.float16, + "BF16": torch.bfloat16, + "I32": torch.int32, + "F32": torch.float32, + "F64": torch.float64, + "I64": torch.int64, +} +_TORCH_TO_ST = {v: k for k, v in _ST_TO_TORCH.items()} +#: safetensors serialises tensors sorted by (dtype DESC, name); this is the +#: dtype order of its enum. Byte-identical output to `save_file` is a tested +#: property (it is what lets "export equals gathered export" be a file hash). +_ST_ORDER = ["BOOL", "U8", "I8", "I16", "F16", "BF16", "I32", "F32", "F64", "I64"] +_ST_ITEMSIZE = {"BOOL": 1, "U8": 1, "I8": 1, "I16": 2, "F16": 2, "BF16": 2, "I32": 4, "F32": 4, "F64": 8, "I64": 8} + + +def _prod(shape: Iterable[int]) -> int: + n = 1 + for s in shape: + n *= int(s) + return n + + +def chunk_range(n: int, world_size: int, rank: int) -> tuple[int, int]: + """(row offset, row count) of `rank`'s `Shard(0)` slice of `n` rows. + + `torch.chunk` semantics, which is what `DTensor` `Shard(0)` uses: ceil(n/ws) + rows per rank, the tail ranks shorter or EMPTY (5 rows over 4 ranks is + 2,2,1,0). Evenly dividing would put row 4 nowhere. One function for save, + load, reshard and export so they cannot disagree about who owns a row. + """ + c = -(-int(n) // int(world_size)) + off = min(int(rank) * c, int(n)) + return off, min(c, int(n) - off) + + +# --------------------------------------------------------------------------- +# safetensors, streaming (writer) and random-access (reader) +# --------------------------------------------------------------------------- + + +@dataclass +class StEntry: + """One tensor to be written: `emit(f)` must write exactly `nbytes` bytes.""" + + name: str + st_dtype: str + shape: tuple + emit: Callable[[Any], None] + + @property + def nbytes(self) -> int: + return _prod(self.shape) * _ST_ITEMSIZE[self.st_dtype] + + +def _st_sort_key(e: StEntry): + return (-_ST_ORDER.index(e.st_dtype), e.name) + + +def safetensors_header(entries: list[StEntry], metadata: Optional[Mapping[str, str]] = None) -> tuple[bytes, list[StEntry]]: + """(8-byte length prefix + JSON header padded to 8 bytes, entries in file order).""" + ordered = sorted(entries, key=_st_sort_key) + header: dict[str, Any] = {} + if metadata: + header["__metadata__"] = dict(metadata) + off = 0 + for e in ordered: + header[e.name] = {"dtype": e.st_dtype, "shape": [int(s) for s in e.shape], "data_offsets": [off, off + e.nbytes]} + off += e.nbytes + raw = json.dumps(header, separators=(",", ":")).encode("utf-8") + raw += b" " * ((-len(raw)) % 8) + return struct.pack(" int: + self.sha.update(b) + self.n += len(b) + return self.f.write(b) + + +def write_safetensors_streaming( + path: str, entries: list[StEntry], metadata: Optional[Mapping[str, str]] = None +) -> dict: + """Write `path` tensor by tensor, fsync it, return {"bytes", "sha256"}. + + Peak memory is whatever ONE `emit` holds. `safetensors.save_file` needs the + whole dict resident, which is the 2x-weights transient this module exists + to remove. + """ + head, ordered = safetensors_header(entries, metadata) + with open(path, "wb") as raw: + w = _HashingWriter(raw) + w.write(head) + for e in ordered: + before = w.n + e.emit(w) + if w.n - before != e.nbytes: + raise ShardedCheckpointError( + f"{e.name}: emitted {w.n - before} bytes, header promised {e.nbytes}" + ) + raw.flush() + os.fsync(raw.fileno()) + return {"bytes": w.n, "sha256": w.sha.hexdigest()} + + +def tensor_bytes_emitter(t: torch.Tensor) -> Callable[[Any], None]: + def emit(f): + c = t.detach().contiguous().reshape(-1) + if c.numel(): + f.write(memoryview(c.view(torch.uint8).numpy())) + + return emit + + +class ShardFile: + """Random-access reader over one safetensors file (header parsed once).""" + + def __init__(self, path: str): + self.path = path + self.fd = os.open(path, os.O_RDONLY) + try: + size = os.fstat(self.fd).st_size + if size < 8: + raise ShardedCheckpointError(f"{os.path.basename(path)} is {size} bytes (no header)") + (n,) = struct.unpack(" size - 8 or n > 256 * 2**20: + raise ShardedCheckpointError(f"{os.path.basename(path)} header claims {n} bytes of {size}") + header = json.loads(os.pread(self.fd, n, 8)) + self.data_start = 8 + n + self.tensors: dict[str, tuple[str, tuple, int, int]] = {} + end = 0 + for k, v in header.items(): + if k == "__metadata__": + continue + a, b = v["data_offsets"] + self.tensors[k] = (v["dtype"], tuple(v["shape"]), int(a), int(b)) + end = max(end, int(b)) + if size < self.data_start + end: + raise ShardedCheckpointError( + f"{os.path.basename(path)} truncated: {size} bytes, header needs {self.data_start + end}" + ) + except BaseException: + os.close(self.fd) + raise + + def close(self) -> None: + if self.fd >= 0: + os.close(self.fd) + self.fd = -1 + + def __enter__(self): + return self + + def __exit__(self, *a): + self.close() + + def copy_range(self, name: str, lo: int, hi: int, sink) -> None: + """Stream bytes [lo, hi) of tensor `name` into `sink.write`.""" + _dt, _shape, a, b = self.tensors[name] + if not (0 <= lo <= hi <= b - a): + raise ShardedCheckpointError(f"{name}: byte range [{lo},{hi}) outside the {b - a}-byte tensor") + pos = self.data_start + a + lo + left = hi - lo + while left: + buf = os.pread(self.fd, min(COPY_CHUNK, left), pos) + if not buf: + raise ShardedCheckpointError(f"{self.path}: short read at {pos}") + sink.write(buf) + pos += len(buf) + left -= len(buf) + + def tensor(self, name: str) -> torch.Tensor: + dt, shape, a, b = self.tensors[name] + torch_dt = _ST_TO_TORCH[dt] + if b == a: + return torch.empty(shape, dtype=torch_dt) + buf = bytearray(b - a) + mv = memoryview(buf) + pos, got = self.data_start + a, 0 + while got < len(buf): + n = os.preadv(self.fd, [mv[got : got + COPY_CHUNK]], pos + got) + if n <= 0: + raise ShardedCheckpointError(f"{self.path}: short read of {name}") + got += n + return torch.frombuffer(buf, dtype=torch_dt).reshape(shape) + + +def file_sha256(path: str) -> str: + h = hashlib.sha256() + with open(path, "rb") as f: + while True: + b = f.read(COPY_CHUNK) + if not b: + break + h.update(b) + return h.hexdigest() + + +# --------------------------------------------------------------------------- +# payload integrity sidecar (audit U01-3) +# --------------------------------------------------------------------------- + +#: `/integrity.json`: {"version": 1, "sha256": {file name: hex}} for the payloads the +#: weights manifest does not already cover (resume.pt, optimizer_rank*.pt, and the gathered +#: layout's model.safetensors). A torch.save zip passes the structural check after a same-size +#: bit flip in a stored tensor, so structure alone cannot catch silent media corruption. +INTEGRITY_NAME = "integrity.json" + + +def write_integrity(out_dir: str, sha256: Mapping[str, str]) -> None: + path = os.path.join(out_dir, INTEGRITY_NAME) + with open(path, "w", encoding="utf-8") as f: + f.write(json.dumps({"version": 1, "sha256": dict(sha256)}, indent=1, sort_keys=True) + "\n") + f.flush() + os.fsync(f.fileno()) + + +def read_integrity(path: str) -> Optional[dict]: + """{file name: sha256} or None for a checkpoint that predates the sidecar. A sidecar that + exists but cannot be parsed is an error, never 'legacy' (fail closed).""" + fp = os.path.join(path, INTEGRITY_NAME) + if not os.path.isfile(fp): + return None + try: + with open(fp, encoding="utf-8") as f: + blob = json.load(f) + out = {str(k): str(v) for k, v in blob["sha256"].items()} + except (OSError, ValueError, KeyError, AttributeError, TypeError) as e: + raise CheckpointIntegrityError(f"{fp} is unreadable ({type(e).__name__}: {e})") from e + return out + + +def verify_integrity(path: str, names: Iterable[str], recorded: Optional[dict] = None) -> Optional[str]: + """None iff every name in `names` that the sidecar records matches its sha256. + + A name the sidecar does not list is skipped (a legacy or partial sidecar); a listed file that + is missing or differs is a problem. + """ + recorded = read_integrity(path) if recorded is None else recorded + if recorded is None: + return None + for n in names: + want = recorded.get(n) + if want is None: + continue + fp = os.path.join(path, n) + if not os.path.isfile(fp): + return f"{n} is missing (integrity.json records it)" + got = file_sha256(fp) + if got != want: + return f"{n} sha256 {got[:12]}.. != recorded {want[:12]}.. (bit rot or a partial copy)" + return None + + +# --------------------------------------------------------------------------- +# describing a live (possibly DTensor) tensor +# --------------------------------------------------------------------------- + + +def _local_and_desc(t: torch.Tensor, rank: int, world_size: int) -> tuple[torch.Tensor, dict]: + """(this rank's local tensor, descriptor) for a plain tensor or a DTensor. + + Descriptor: global `shape`, `placement` ("shard0" | "replicate"), and for + shard0 this rank's `row` = [offset, count]. Everything else is refused HERE + (save time): a layout the loader cannot place must not produce a file. + """ + if hasattr(t, "to_local") and hasattr(t, "placements"): + pl = tuple(t.placements) + mesh = t.device_mesh + if mesh.ndim != 1 or mesh.size() != world_size: + raise ShardedCheckpointError( + f"unsupported mesh {tuple(mesh.shape)} for world_size={world_size}: sharded checkpoints " + "support a 1-D mesh over all ranks (what fully_shard builds). HSDP/TP meshes are not " + "implemented; use checkpoint_format='gathered'." + ) + if mesh.get_local_rank() != rank: + raise ShardedCheckpointError(f"mesh local rank {mesh.get_local_rank()} != process rank {rank}") + local = t.to_local() + shape = tuple(int(s) for s in t.shape) + from torch.distributed.tensor import Replicate, Shard + + if len(pl) == 1 and isinstance(pl[0], Shard) and pl[0].dim == 0: + off, n = chunk_range(shape[0], world_size, rank) + if tuple(local.shape) != (n,) + shape[1:]: + raise ShardedCheckpointError( + f"local shard {tuple(local.shape)} != chunk_range-derived {(n,) + shape[1:]} " + f"(global {shape}, rank {rank}/{world_size}): uneven/padded layout not understood" + ) + return local, {"shape": list(shape), "placement": "shard0", "row": [off, n]} + if len(pl) == 1 and isinstance(pl[0], Replicate): + return local, {"shape": list(shape), "placement": "replicate", "row": None} + raise ShardedCheckpointError(f"unsupported placements {pl}: only Shard(0) and Replicate() are implemented") + return t, {"shape": [int(s) for s in t.shape], "placement": "replicate", "row": None} + + +def _store_dtype(t: torch.Tensor, store_dtype: torch.dtype) -> str: + dt = store_dtype if t.is_floating_point() else t.dtype + try: + return _TORCH_TO_ST[dt] + except KeyError as e: + raise ShardedCheckpointError(f"unsupported tensor dtype {dt}") from e + + +def rank_file_name(rank: int) -> str: + return f"model_rank{rank:05d}.safetensors" + + +# --------------------------------------------------------------------------- +# save (one rank) +# --------------------------------------------------------------------------- + + +def save_rank_shard( + state: Mapping[str, torch.Tensor], + out_dir: str, + *, + rank: int, + world_size: int, + store_dtype: torch.dtype = torch.bfloat16, +) -> dict: + """Write THIS rank's local shards to `out_dir/model_rank{r}.safetensors`. + + Atomic per file (tmp + fsync + rename). Returns this rank's info for the + manifest: {"file": {name, bytes, sha256}, "tensors": {name: descriptor}}. + Peak host memory is one tensor. + """ + entries: list[StEntry] = [] + tensors: dict[str, dict] = {} + for name in sorted(state): + local, desc = _local_and_desc(state[name], rank, world_size) + st_dt = _store_dtype(local, store_dtype) + desc["dtype"] = st_dt + tensors[name] = desc + + def emit(f, local=local, st_dt=st_dt): + host = local.detach().to(device="cpu", dtype=_ST_TO_TORCH[st_dt]) + tensor_bytes_emitter(host)(f) + + entries.append(StEntry(name, st_dt, tuple(local.shape), emit)) + fname = rank_file_name(rank) + final = os.path.join(out_dir, fname) + tmp = final + ".tmp" + try: + meta = write_safetensors_streaming(tmp, entries, {"format": "pt"}) + os.replace(tmp, final) + except BaseException: + for p in (tmp, final): + try: + os.remove(p) + except OSError: + pass + raise + return {"file": {"name": fname, **meta}, "tensors": tensors, "order": list(state)} + + +def build_manifest( + infos: list[dict], + *, + param_order: Optional[list[str]] = None, + export: Optional[dict] = None, + extra: Optional[dict] = None, +) -> dict: + """Merge every rank's info (rank-ordered) into the manifest. Cross-checks + that all ranks saw the same tensors and that shard0 rows tile [0, n).""" + ws = len(infos) + names = sorted(infos[0]["tensors"]) + tensors: dict[str, dict] = {} + for n in names: + d0 = infos[0]["tensors"][n] + rows = [] + for r, info in enumerate(infos): + if sorted(info["tensors"]) != names: + raise ShardedCheckpointError(f"rank {r} wrote a different tensor set than rank 0") + d = info["tensors"][n] + for k in ("shape", "placement", "dtype"): + if d[k] != d0[k]: + raise ShardedCheckpointError(f"{n}: rank {r} disagrees with rank 0 on {k}: {d[k]} vs {d0[k]}") + rows.append(d["row"]) + entry = {"shape": d0["shape"], "dtype": d0["dtype"], "placement": d0["placement"]} + if d0["placement"] == "shard0": + pos = 0 + for off, cnt in rows: + if off != min(pos, d0["shape"][0]) and cnt: + raise ShardedCheckpointError(f"{n}: shard rows do not tile ({rows})") + pos += cnt + if pos != d0["shape"][0]: + raise ShardedCheckpointError(f"{n}: shard rows sum to {pos}, global rows {d0['shape'][0]}") + entry["rows"] = rows + tensors[n] = entry + m: dict[str, Any] = { + "format": FORMAT_NAME, + "version": FORMAT_VERSION, + "world_size": ws, + "files": {str(r): infos[r]["file"] for r in range(ws)}, + "tensors": tensors, + } + if infos[0].get("order") is not None: + # The model's own state-dict order: shard planning (qwen3's 5 GB files) + # is greedy over insertion order, and the manifest JSON is key-sorted, + # so without this the exported file split would differ from the + # gathered writer's. + m["key_order"] = list(infos[0]["order"]) + if param_order is not None: + m["param_order"] = list(param_order) + if export is not None: + m["export"] = export + if extra: + m.update(extra) + return m + + +def write_manifest(out_dir: str, manifest: dict) -> None: + path = os.path.join(out_dir, SHARD_MANIFEST_NAME) + with open(path, "w", encoding="utf-8") as f: + f.write(json.dumps(manifest, indent=1, sort_keys=True) + "\n") + f.flush() + os.fsync(f.fileno()) + + +# --------------------------------------------------------------------------- +# read side: manifest, completeness, load +# --------------------------------------------------------------------------- + + +def is_sharded(path: str) -> bool: + return os.path.isfile(os.path.join(path, SHARD_MANIFEST_NAME)) + + +def read_manifest(path: str) -> dict: + """Parse + structurally validate; raises `ShardedCheckpointError`.""" + mp = os.path.join(path, SHARD_MANIFEST_NAME) + try: + with open(mp, encoding="utf-8") as f: + m = json.load(f) + except (OSError, ValueError) as e: + raise ShardedCheckpointError(f"unreadable {SHARD_MANIFEST_NAME} ({e})") from e + if not isinstance(m, dict) or m.get("format") != FORMAT_NAME: + raise ShardedCheckpointError(f"{SHARD_MANIFEST_NAME} is not an {FORMAT_NAME} manifest") + if m.get("version") != FORMAT_VERSION: + raise ShardedCheckpointError(f"manifest version {m.get('version')} != supported {FORMAT_VERSION}") + ws = m.get("world_size") + if not isinstance(ws, int) or ws < 1: + raise ShardedCheckpointError(f"manifest world_size {ws!r} is not a positive int") + files, tensors = m.get("files"), m.get("tensors") + if not isinstance(files, dict) or sorted(files, key=int) != [str(r) for r in range(ws)]: + raise ShardedCheckpointError("manifest does not name exactly one file per rank") + for r in range(ws): + fe = files[str(r)] + if not (isinstance(fe, dict) and {"name", "bytes", "sha256"} <= fe.keys()): + raise ShardedCheckpointError(f"manifest file entry for rank {r} is malformed") + # An EMPTY tensor set is legal: a module whose weights are reconstructible + # elsewhere (a frozen base + adapter) may declare `sharded_model_state() == {}` + # and checkpoint only its optimizer/adapter state. + if not isinstance(tensors, dict): + raise ShardedCheckpointError("manifest tensors entry is not an object") + for n, e in tensors.items(): + if e.get("placement") not in ("shard0", "replicate") or e.get("dtype") not in _ST_ITEMSIZE: + raise ShardedCheckpointError(f"{n}: malformed tensor entry") + if e["placement"] == "shard0" and len(e.get("rows", [])) != ws: + raise ShardedCheckpointError(f"{n}: shard0 entry has {len(e.get('rows', []))} row ranges, world {ws}") + return m + + +def sharded_problem(path: str, st_header_problem: Callable[[str], Optional[str]]) -> Optional[str]: + """None iff every rank file the manifest names is present, the size it + recorded, and a structurally complete safetensors file. CHEAP (no payload + reads): sha256 is verified on the rank that loads the file.""" + try: + m = read_manifest(path) + except ShardedCheckpointError as e: + return str(e) + for r in range(m["world_size"]): + fe = m["files"][str(r)] + fp = os.path.join(path, fe["name"]) + if not os.path.isfile(fp): + return f"missing shard file {fe['name']}" + if os.path.getsize(fp) != fe["bytes"]: + return f"{fe['name']} is {os.path.getsize(fp)} bytes, manifest recorded {fe['bytes']}" + problem = st_header_problem(fp) + if problem: + return problem + return None + + +def verify_rank_file(path: str, rank: int) -> Optional[str]: + """sha256 of THIS rank's file against the manifest; None if it matches.""" + m = read_manifest(path) + fe = m["files"][str(rank)] + got = file_sha256(os.path.join(path, fe["name"])) + if got != fe["sha256"]: + return f"{fe['name']} sha256 {got[:12]}.. != manifest {fe['sha256'][:12]}.. (bit rot or a partial copy)" + return None + + +def check_world_size(path: str, manifest: dict, world_size: int) -> None: + if manifest["world_size"] != world_size: + raise ShardedWorldSizeError( + f"checkpoint {path} was saved with world_size={manifest['world_size']} but this run has " + f"world_size={world_size}. Sharded weights are rank-local row slices and cannot be loaded " + "under another partitioning. Resume with the same number of ranks, or reshard offline: " + f"python scripts/ckpt_convert.py reshard {path} --world-size {world_size}" + ) + + +def load_rank_shard( + state: Mapping[str, torch.Tensor], path: str, *, rank: int, world_size: int, verify_hash: bool = False +) -> int: + """Copy this rank's file into the LIVE tensors of `state` (a model state + dict whose DTensors alias the parameters). Reads only this rank's file, one + tensor at a time. Returns the number of tensors loaded.""" + m = read_manifest(path) + check_world_size(path, m, world_size) + mt = m["tensors"] + missing, unexpected = sorted(set(mt) - set(state)), sorted(set(state) - set(mt)) + if missing or unexpected: + raise KeyError(f"resume state mismatch: missing={missing[:5]} unexpected={unexpected[:5]}") + if verify_hash: + bad = verify_rank_file(path, rank) + if bad: + raise ShardedCheckpointError(bad) + # validate EVERYTHING before the first copy_: a mismatch on tensor 300 must + # not leave a model half-overwritten. + plan = [] + for name in sorted(mt): + local, desc = _local_and_desc(state[name], rank, world_size) + e = mt[name] + if desc["shape"] != e["shape"] or desc["placement"] != e["placement"]: + raise ShardedCheckpointError( + f"{name}: live {desc['placement']} {desc['shape']} != checkpoint {e['placement']} {e['shape']}" + ) + if e["placement"] == "shard0" and list(e["rows"][rank]) != list(desc["row"]): + raise ShardedCheckpointError( + f"{name}: live rows {desc['row']} != checkpoint rows {e['rows'][rank]} for rank {rank}" + ) + if local.is_floating_point() != _ST_TO_TORCH[e["dtype"]].is_floating_point: + raise ShardedCheckpointError(f"{name}: dtype class differs (live {local.dtype}, ckpt {e['dtype']})") + plan.append((name, local)) + with ShardFile(os.path.join(path, m["files"][str(rank)]["name"])) as sf: + missing_in_file = [n for n, _ in plan if n not in sf.tensors] + if missing_in_file: + raise ShardedCheckpointError(f"{sf.path} lacks tensors {missing_in_file[:5]}") + with torch.no_grad(): + for name, local in plan: + t = sf.tensor(name) + if tuple(t.shape) != tuple(local.shape): + raise ShardedCheckpointError(f"{name}: file shape {tuple(t.shape)} != live {tuple(local.shape)}") + local.copy_(t.to(device=local.device)) + return len(plan) + + +class _ListSink: + def __init__(self): + self.parts: list[bytes] = [] + + def write(self, b): + self.parts.append(bytes(b)) + return len(b) + + +class GlobalReader: + """Byte-range reads over the GLOBAL (row-major) tensors of a sharded checkpoint.""" + + def __init__(self, path: str, manifest: Optional[dict] = None): + self.path = path + self.m = manifest or read_manifest(path) + self.files = { + r: ShardFile(os.path.join(path, self.m["files"][str(r)]["name"])) for r in range(self.m["world_size"]) + } + + def close(self): + for f in self.files.values(): + f.close() + + def __enter__(self): + return self + + def __exit__(self, *a): + self.close() + + def info(self, name: str) -> tuple[str, tuple]: + e = self.m["tensors"][name] + return e["dtype"], tuple(e["shape"]) + + def nbytes(self, name: str) -> int: + dt, shape = self.info(name) + return _prod(shape) * _ST_ITEMSIZE[dt] + + def copy_range(self, name: str, lo: int, hi: int, sink) -> None: + """Stream global bytes [lo, hi) of tensor `name` into `sink`.""" + e = self.m["tensors"][name] + if not (0 <= lo <= hi <= self.nbytes(name)): + raise ShardedCheckpointError(f"{name}: byte range [{lo},{hi}) outside tensor") + if e["placement"] == "replicate": + self.files[0].copy_range(name, lo, hi, sink) + return + dt, shape = self.info(name) + rb = _prod(shape[1:]) * _ST_ITEMSIZE[dt] + for r, (off, cnt) in enumerate(e["rows"]): + a, b = max(lo, off * rb), min(hi, (off + cnt) * rb) + if a < b: + self.files[r].copy_range(name, a - off * rb, b - off * rb, sink) + + def tensor(self, name: str) -> torch.Tensor: + dt, shape = self.info(name) + sink = _ListSink() + self.copy_range(name, 0, self.nbytes(name), sink) + buf = bytearray(b"".join(sink.parts)) + if not buf: + return torch.empty(shape, dtype=_ST_TO_TORCH[dt]) + return torch.frombuffer(buf, dtype=_ST_TO_TORCH[dt]).reshape(shape) + + +def load_full_state_dict(path: str) -> dict[str, torch.Tensor]: + """The WHOLE state dict, assembled in host memory. For tests and small + models only -- the production path is `export_hf`, which never does this.""" + with GlobalReader(path) as g: + return {n: g.tensor(n) for n in g.m["tensors"]} + + +# --------------------------------------------------------------------------- +# describing the weight format (so the checkpoint is self-exporting) +# --------------------------------------------------------------------------- + + +def describe_weight_format(weight_format: Any, dtype: torch.dtype = torch.bfloat16) -> Optional[dict]: + """{"family", "hf_config"} for the formats we can export; None otherwise + (the checkpoint still saves and resumes, `export` then refuses with a clear + message instead of guessing a config).""" + # Subclasses count: scripts wrap OlmoeFormat to serialise its loads + # (olmoe_sft_smoke.SerialWeightFormat) and must stay exportable. + names = {c.__name__ for c in type(weight_format).__mro__} + name = next((n for n in ("DenseFormat", "OlmoeFormat", "Qwen3Format") if n in names), type(weight_format).__name__) + try: + if name == "DenseFormat": + from ..model import hf_config as hfc + + return {"family": "dense", "hf_config": hfc.to_hf_config_dict(weight_format.model_cfg, dtype=dtype)} + if name == "OlmoeFormat": + from ..model.olmoe_checkpoint import config_to_hf_dict + + return {"family": "olmoe", "hf_config": config_to_hf_dict(weight_format.olmoe_cfg, dtype=dtype)} + if name == "Qwen3Format": + return {"family": "qwen3", "hf_config": weight_format.qcfg.to_hf_config(dtype=dtype)} + except Exception as e: # noqa: BLE001 -- a config we cannot describe must not block saving weights + logger.warning("cannot describe weight format %s for export (%s: %s)", name, type(e).__name__, e) + return None + + +# --------------------------------------------------------------------------- +# HF export plan + streaming export +# --------------------------------------------------------------------------- + + +@dataclass +class HFEntry: + hf_name: str + st_dtype: str + shape: tuple + src: str # align key + lo: int # global byte range in the source tensor + hi: int + + +def _meta(manifest: dict) -> dict[str, torch.Tensor]: + order = manifest.get("key_order") or list(manifest["tensors"]) + return { + n: torch.empty(tuple(manifest["tensors"][n]["shape"]), dtype=_ST_TO_TORCH[manifest["tensors"][n]["dtype"]], device="meta") + for n in order + } + + +def build_hf_plan(manifest: dict) -> list[HFEntry]: + """Plan the HF tensor list from the manifest ALONE (no data). 1:1 families + run the family's own converter on META tensors and map outputs back by + object identity, so the name table is the converter's, not a copy of it. + OLMoE's stacked experts become per-expert byte ranges of the fused tensor.""" + if not manifest["tensors"]: + raise ShardedCheckpointError("this checkpoint holds no weight tensors (adapter/optimizer-only); nothing to export") + ex = manifest.get("export") + if not ex: + raise ShardedCheckpointError( + "this checkpoint carries no export recipe (its weight format is not Dense/Olmoe/Qwen3); " + "export cannot guess a config" + ) + fam, hfc_d = ex["family"], ex["hf_config"] + meta = _meta(manifest) + ident = {id(v): k for k, v in meta.items()} + entries: list[HFEntry] = [] + + def one_to_one(out: Mapping[str, torch.Tensor]) -> None: + for hf_name, v in out.items(): + src = ident.get(id(v)) + if src is None: + raise ShardedCheckpointError(f"{hf_name}: not a 1:1 image of an align tensor") + e = manifest["tensors"][src] + entries.append(HFEntry(hf_name, e["dtype"], tuple(e["shape"]), src, 0, _prod(e["shape"]) * _ST_ITEMSIZE[e["dtype"]])) + + if fam == "dense": + from ..model import checkpoint as ckpt + from ..model import hf_config as hfc + + cfg = hfc.from_hf_config_dict(hfc_d) + one_to_one(ckpt.nmo_to_hf(meta, expected_n_layers=cfg.n_layers)) + elif fam == "qwen3": + from ..model.qwen3 import Qwen3Config + from ..model.qwen3_checkpoint import align_to_hf + + one_to_one(align_to_hf(meta, Qwen3Config.from_hf_config(hfc_d))) + elif fam == "olmoe": + from ..model import olmoe_checkpoint as oc + + cfg = oc.config_from_hf_dict(hfc_d) + real = oc.align_to_hf(meta, cfg) # the converter's own key set and shapes: the oracle + inter = cfg.intermediate_size + fused = set() + for i in range(cfg.n_layers): + gu_k, dn_k = (k.format(i=i) for k in oc._AL_FUSED) + fused.update((gu_k, dn_k)) + gu, dn = manifest["tensors"][gu_k], manifest["tensors"][dn_k] + es = _ST_ITEMSIZE[gu["dtype"]] + e_n, two_i, d = gu["shape"] + for e in range(e_n): + base = e * two_i * d * es + half = inter * d * es + entries.append(HFEntry(oc._HF_EXPERT.format(i=i, e=e, p="gate"), gu["dtype"], (inter, d), gu_k, base, base + half)) + entries.append(HFEntry(oc._HF_EXPERT.format(i=i, e=e, p="up"), gu["dtype"], (inter, d), gu_k, base + half, base + 2 * half)) + dbase = e * dn["shape"][1] * dn["shape"][2] * es + entries.append(HFEntry(oc._HF_EXPERT.format(i=i, e=e, p="down"), dn["dtype"], tuple(dn["shape"][1:]), dn_k, dbase, dbase + _prod(dn["shape"][1:]) * es)) + rest = {k: v for k, v in real.items() if id(v) in ident and ident[id(v)] not in fused} + one_to_one(rest) + got = {e.hf_name: e.shape for e in entries} + want = {k: tuple(v.shape) for k, v in real.items()} + if got != want: + raise ShardedCheckpointError( + f"olmoe export plan disagrees with align_to_hf: only-plan={sorted(set(got) - set(want))[:3]} " + f"only-converter={sorted(set(want) - set(got))[:3]} " + f"shape-diff={[k for k in got if k in want and got[k] != want[k]][:3]}" + ) + else: + raise ShardedCheckpointError(f"unknown export family {fam!r}") + return entries + + +def export_hf(src: str, dst: str, *, verify: bool = True) -> dict: + """Sharded checkpoint -> HF-layout directory, tensor by tensor. + + Byte-identical to what the gathered path writes (`save_nmo_as_hf` / + `save_olmoe_as_hf` / `save_hf_qwen3`) -- tested by file hash -- with peak RSS + of one `COPY_CHUNK` instead of 2x the weights. `dst` is staged as + `dst.partial`, fsynced and renamed: an interrupted export leaves nothing at + `dst`. + """ + if os.path.exists(dst): + raise FileExistsError(f"{dst} exists; export never overwrites") + m = read_manifest(src) + if verify: + for r in range(m["world_size"]): + bad = verify_rank_file(src, r) + if bad: + raise ShardedCheckpointError(bad) + plan = build_hf_plan(m) + fam = m["export"]["family"] + staging = dst.rstrip("/") + ".partial" + if os.path.isdir(staging): + shutil.rmtree(staging) + os.makedirs(staging) + try: + with GlobalReader(src, m) as g: + def make_entry(h: HFEntry) -> StEntry: + def emit(f, h=h): + g.copy_range(h.src, h.lo, h.hi, f) + + return StEntry(h.hf_name, h.st_dtype, h.shape, emit) + + by_name = {h.hf_name: h for h in plan} + if fam == "qwen3": + from ..model.qwen3_checkpoint import MAX_SHARD_BYTES, _plan_shards + + sizes = {h.hf_name: _prod(h.shape) * _ST_ITEMSIZE[h.st_dtype] for h in plan} + groups = _plan_shards(sizes, MAX_SHARD_BYTES) + weight_map: dict[str, str] = {} + for n, keys in enumerate(groups, start=1): + fname = f"model-{n:05d}-of-{len(groups):05d}.safetensors" + write_safetensors_streaming( + os.path.join(staging, fname), [make_entry(by_name[k]) for k in keys], {"format": "pt"} + ) + weight_map.update({k: fname for k in keys}) + with open(os.path.join(staging, "model.safetensors.index.json"), "w") as fh: + json.dump({"metadata": {"total_size": sum(sizes.values())}, "weight_map": weight_map}, fh, indent=2, sort_keys=True) + fh.flush() + os.fsync(fh.fileno()) + else: + write_safetensors_streaming( + os.path.join(staging, "model.safetensors"), [make_entry(h) for h in plan], {"format": "pt"} + ) + with open(os.path.join(staging, "config.json"), "w", encoding="utf-8") as fh: + fh.write(json.dumps(m["export"]["hf_config"], indent=2, sort_keys=True) + "\n") + fh.flush() + os.fsync(fh.fileno()) + for fn in sorted(os.listdir(src)): + if not _OWN_FILE_RE.match(fn) and os.path.isfile(os.path.join(src, fn)) and fn != "config.json": + shutil.copyfile(os.path.join(src, fn), os.path.join(staging, fn)) + _fsync_tree(staging) + os.rename(staging, dst) + _fsync_dir(os.path.dirname(os.path.abspath(dst))) + except BaseException: + shutil.rmtree(staging, ignore_errors=True) + raise + return {"tensors": len(plan), "family": fam, "dst": dst} + + +def _fsync_dir(p: str) -> None: + fd = os.open(p, os.O_RDONLY) + try: + os.fsync(fd) + finally: + os.close(fd) + + +def _fsync_tree(root: str) -> None: + dirs = [] + for dp, _dn, fns in os.walk(root): + dirs.append(dp) + for fn in fns: + fd = os.open(os.path.join(dp, fn), os.O_RDONLY) + try: + os.fsync(fd) + finally: + os.close(fd) + for d in reversed(dirs): + _fsync_dir(d) + + +# --------------------------------------------------------------------------- +# offline reshard +# --------------------------------------------------------------------------- + + +class ReshardUnsupported(ShardedCheckpointError): + """Optimizer state whose layout cannot be re-cut without knowing the optimizer.""" + + +def _check_opt_leaf(vals: list, shapes_old: list[tuple], name: str, where: str) -> None: + """Every old rank's piece must have exactly the LOCAL shard shape of the parameter it is + filed under (shape metadata only: reads nothing from an mmap'd file).""" + for r, (v, want) in enumerate(zip(vals, shapes_old)): + if tuple(v.shape) != tuple(want): + raise ReshardUnsupported( + f"{where}: tensor shape {tuple(v.shape)} on old rank {r} != the local shard {tuple(want)} of " + f"parameter {name!r}. This optimizer state is not elementwise-per-shard (quantised/blocked " + "moments?) or its parameter order differs from the model's; it cannot be re-cut safely." + ) + + +def _cut_opt_leaf(vals: list, old_rows: Optional[list], new_ws: int, new_rank: int) -> torch.Tensor: + """NEW rank `new_rank`'s piece of one per-param optimizer tensor, built from only the + old pieces that overlap its rows (no whole-tensor concatenation, no other new rank).""" + if old_rows is None: # replicated parameter + return vals[0].clone() + total = sum(c for _o, c in old_rows) + off, n = chunk_range(total, new_ws, new_rank) + parts = [] + for v, (qo, qc) in zip(vals, old_rows): + a, b = max(off, qo), min(off + n, qo + qc) + if a < b: + parts.append(v[a - qo : b - qo]) + if not parts: + return torch.empty((0,) + tuple(vals[0].shape[1:]), dtype=vals[0].dtype) + return torch.cat(parts, dim=0) if len(parts) > 1 else parts[0].clone() + + +def iter_reshard_optimizer(old: list[dict], manifest: dict, new_ws: int): + """Yield the re-cut optimizer state dict of NEW rank 0, 1, ... one at a time. + + THE ALL-RANKS-AT-ONCE DEFECT this shape prevents. The first version returned a + list holding every new rank's state, so its peak was the WHOLE optimizer + (12 B/param for fp32-master AdamW: 83 GB for a 7B model) while the CLI + estimated `optimizer_bytes / new_ws` and the 45 GB floor check was sized on + that. Measured on 4 old -> 4 new ranks, 50 M params: anonymous-RSS growth 576 + MiB against an estimate of 144 MiB, i.e. `new_ws` times the estimate. On this + no-swap shared box a reshard that passes the preflight at 21 GB and takes 83 + GB is the 2026-08-12 OOM. Here only the old pieces that overlap the rank being + built are read (mmap'd), and the caller writes and drops each yielded dict + before asking for the next, so the peak is one new rank's state. + + Every shape/consistency refusal is raised BEFORE the first yield, so a + resharder that cannot prove it understands the state writes no file at all. + """ + order = manifest.get("param_order") + if not order: + raise ReshardUnsupported("manifest has no param_order: cannot map optimizer slots to parameters") + ws = manifest["world_size"] + if len(old) != ws: + raise ReshardUnsupported(f"{len(old)} optimizer file(s) for a {ws}-rank checkpoint") + if "world_size" in old[0]: + raise ReshardUnsupported("optimizer state is stamped with its world_size (quantised shard-local state)") + + def entry(pname: str) -> dict: + e = manifest["tensors"].get(pname) + if e is None: + raise ReshardUnsupported(f"param_order names {pname!r}, which is not a tensor of this checkpoint") + return e + + def local_shape(pname: str, r: int) -> tuple: + e = entry(pname) + if e["placement"] == "replicate": + return tuple(e["shape"]) + return (e["rows"][r][1],) + tuple(e["shape"][1:]) + + def rows_of(pname: str) -> Optional[list]: + e = entry(pname) + return None if e["placement"] == "replicate" else [tuple(x) for x in e["rows"]] + + def agree(vals: list, where: str): + v0 = vals[0] + for v in vals[1:]: + same = torch.equal(v, v0) if isinstance(v0, torch.Tensor) else v == v0 + if not same: + raise ReshardUnsupported(f"{where}: differs across old ranks ({v0!r} vs {v!r})") + return v0 + + # -- pass 1: validate everything, build a per-key plan (no tensor payload read) ----------- + plan: list[tuple] = [] + for key in old[0]: + vals = [o[key] for o in old] + if key == "state": + leaves = [] # (idx, k, kind, payload) + for idx in vals[0]: + if not 0 <= int(idx) < len(order): + raise ReshardUnsupported(f"state slot {idx} is outside param_order ({len(order)} entries)") + pname = order[int(idx)] + for k in vals[0][idx]: + leaf = [v[idx][k] for v in vals] + where = f"state[{idx}][{k}]" + if isinstance(leaf[0], torch.Tensor) and leaf[0].ndim >= 1: + _check_opt_leaf(leaf, [local_shape(pname, r) for r in range(ws)], pname, where) + leaves.append((idx, k, "cut", (leaf, rows_of(pname)))) + else: + leaves.append((idx, k, "same", agree(leaf, where))) + plan.append((key, "state", leaves)) + elif key == "master": + if len(vals[0]) != len(order) or any(len(v) != len(order) for v in vals): + raise ReshardUnsupported( + f"master has {[len(v) for v in vals]} entries per old rank, param_order {len(order)}: the " + "optimizer was not built over the model's trainable parameters in order" + ) + masters = [] + for i, pname in enumerate(order): + leaf = [v[i] for v in vals] + _check_opt_leaf(leaf, [local_shape(pname, r) for r in range(ws)], pname, f"master[{i}]") + masters.append((leaf, rows_of(pname))) + plan.append((key, "master", masters)) + else: + if _has_tensor(vals[0], min_ndim=1): + raise ReshardUnsupported(f"optimizer key {key!r} holds sharded tensors this resharder does not understand") + plan.append((key, "plain", _agree_tree(vals, key))) + + # -- pass 2: build ONE new rank at a time --------------------------------------------------- + for r in range(new_ws): + out: dict = {} + for key, kind, payload in plan: + if kind == "state": + st: dict = {} + for idx, k, how, p in payload: + st.setdefault(idx, {})[k] = _cut_opt_leaf(p[0], p[1], new_ws, r) if how == "cut" else p + out[key] = st + elif kind == "master": + out[key] = [_cut_opt_leaf(leaf, rows, new_ws, r) for leaf, rows in payload] + else: + out[key] = payload + yield out + + +def reshard_optimizer(old: list[dict], manifest: dict, new_ws: int) -> list[dict]: + """Re-cut per-rank optimizer state dicts for `new_ws`, all at once (tests, small models). + + Production resharding uses `iter_reshard_optimizer` and writes each rank + before building the next; this wrapper holds every new rank in memory. + + Handles the layout `torch.optim.AdamW` / `OffloadAdamW` produce: + `state[idx][k]` tensors and a `master` list, each shaped like the LOCAL + shard of parameter `param_order[idx]`. Scalars (`step`) and non-tensor + leaves must agree across old ranks. ANYTHING else that holds a tensor with + ndim >= 1 (adamw8bit's quantised blocks, a `world_size`-stamped state) + raises `ReshardUnsupported`: re-cutting what we do not understand is how a + resume loads plausible, wrong moments. + """ + return list(iter_reshard_optimizer(old, manifest, new_ws)) + + +def _has_tensor(o: Any, min_ndim: int) -> bool: + if isinstance(o, torch.Tensor): + return o.ndim >= min_ndim + if isinstance(o, dict): + return any(_has_tensor(v, min_ndim) for v in o.values()) + if isinstance(o, (list, tuple)): + return any(_has_tensor(v, min_ndim) for v in o) + return False + + +def _agree_tree(vals: list, where: str): + v0 = vals[0] + for v in vals[1:]: + if repr(v) != repr(v0): + raise ReshardUnsupported(f"{where}: differs across old ranks") + return v0 + + +def reshard(src: str, dst: str, new_ws: int, *, drop_optimizer: bool = False) -> dict: + """Offline reshard of a sharded checkpoint to `new_ws` ranks. + + Model shards are re-cut by byte range (bounded memory). Optimizer files are + re-cut by `reshard_optimizer` (peak RSS = one NEW rank's optimizer state -- + at 7B fp32-master AdamW that is 12 B/param/new_ws; run it on an idle box). + With `drop_optimizer=True` the optimizer files are omitted and the loop + state is marked, so resume starts FRESH moments: a recorded deviation, and + NOT lossless when the optimizer holds the fp32 master. + `resume.pt` is carried over with its world-size stamp rewritten and the + per-rank RNG list dropped (the trainer restarts RNG from the seed with a + warning; carrying N_old streams into N_new ranks would be wrong). + """ + if new_ws < 1: + raise ValueError("new_ws must be >= 1") + m = read_manifest(src) + for r in range(m["world_size"]): + bad = verify_rank_file(src, r) + if bad: + raise ShardedCheckpointError(bad) + if os.path.exists(dst): + raise FileExistsError(f"{dst} exists; reshard never overwrites") + staging = dst.rstrip("/") + ".partial" + if os.path.isdir(staging): + shutil.rmtree(staging) + os.makedirs(staging) + try: + infos = [] + with GlobalReader(src, m) as g: + for r in range(new_ws): + entries, tdesc = [], {} + for name in sorted(m["tensors"]): + e = m["tensors"][name] + dt, shape = e["dtype"], tuple(e["shape"]) + if e["placement"] == "shard0": + off, cnt = chunk_range(shape[0], new_ws, r) + lshape = (cnt,) + shape[1:] + rb = _prod(shape[1:]) * _ST_ITEMSIZE[dt] + lo, hi = off * rb, (off + cnt) * rb + tdesc[name] = {"shape": list(shape), "placement": "shard0", "row": [off, cnt], "dtype": dt} + else: + lshape, lo, hi = shape, 0, g.nbytes(name) + tdesc[name] = {"shape": list(shape), "placement": "replicate", "row": None, "dtype": dt} + + def emit(f, name=name, lo=lo, hi=hi): + g.copy_range(name, lo, hi, f) + + entries.append(StEntry(name, dt, lshape, emit)) + fname = rank_file_name(r) + meta = write_safetensors_streaming(os.path.join(staging, fname), entries, {"format": "pt"}) + infos.append({"file": {"name": fname, **meta}, "tensors": tdesc, "order": m.get("key_order")}) + new_manifest = build_manifest( + infos, + param_order=m.get("param_order"), + export=m.get("export"), + extra={"resharded_from": {"world_size": m["world_size"], "source": os.path.basename(src.rstrip("/"))}}, + ) + write_manifest(staging, new_manifest) + + state = torch.load(os.path.join(src, "resume.pt"), weights_only=True, map_location="cpu") + state.pop("rng_per_rank", None) + if drop_optimizer: + state["optimizer_state"] = {"layout": "none", "world_size": new_ws} + else: + state["optimizer_state"] = {"layout": "per_rank_files", "world_size": new_ws} + olds = [ + torch.load(os.path.join(src, f"optimizer_rank{r}.pt"), weights_only=True, map_location="cpu", mmap=True) + for r in range(m["world_size"]) + ] + for r, sd in enumerate(iter_reshard_optimizer(olds, m, new_ws)): + p = os.path.join(staging, f"optimizer_rank{r}.pt") + with open(p, "wb") as f: + torch.save(sd, f) + f.flush() + os.fsync(f.fileno()) + del sd # one new rank's state alive at a time + del olds + with open(os.path.join(staging, "resume.pt"), "wb") as f: + torch.save(state, f) + f.flush() + os.fsync(f.fileno()) + write_integrity( + staging, + { + fn: file_sha256(os.path.join(staging, fn)) + for fn in sorted(os.listdir(staging)) + if fn == "resume.pt" or re.fullmatch(r"optimizer_rank\d+\.pt", fn) + }, + ) + for fn in sorted(os.listdir(src)): + if not _OWN_FILE_RE.match(fn) and os.path.isfile(os.path.join(src, fn)): + shutil.copyfile(os.path.join(src, fn), os.path.join(staging, fn)) + _fsync_tree(staging) + os.rename(staging, dst) + _fsync_dir(os.path.dirname(os.path.abspath(dst))) + except BaseException: + shutil.rmtree(staging, ignore_errors=True) + raise + return {"dst": dst, "world_size": new_ws, "from": m["world_size"], "optimizer": "dropped" if drop_optimizer else "resharded"} + + +def peak_rss_kb() -> int: + """VmHWM of this process in kB (psutil is not a dependency).""" + with open("/proc/self/status") as f: + for line in f: + if line.startswith("VmHWM:"): + return int(line.split()[1]) + return -1 + + +__all__ = [ + "CHECKPOINT_FORMATS", + "SHARD_MANIFEST_NAME", + "ShardedCheckpointError", + "ShardedWorldSizeError", + "ReshardUnsupported", + "chunk_range", + "save_rank_shard", + "build_manifest", + "write_manifest", + "read_manifest", + "is_sharded", + "sharded_problem", + "verify_rank_file", + "load_rank_shard", + "load_full_state_dict", + "describe_weight_format", + "build_hf_plan", + "export_hf", + "reshard", + "reshard_optimizer", + "iter_reshard_optimizer", + "peak_rss_kb", +] diff --git a/code/align/train/stage_gates.py b/code/align/train/stage_gates.py new file mode 100644 index 0000000000000000000000000000000000000000..ea10246115985b0e503234867134ddccc62e9d75 --- /dev/null +++ b/code/align/train/stage_gates.py @@ -0,0 +1,1002 @@ +"""Stage gate sequencing and decisions (section-11). + +This is the first stage that spends real GPU-hours, so the job of this module +is to make wasting them structurally impossible rather than merely unlikely. +Everything here is a pure decision over recorded facts; the stage script drives +it and owns the side effects. + +WHY THE ORDER IS FIXED, and why it is enforced instead of documented: + + golden_regression -> smoke_7b -> probe_20step -> rss_preflight + -> train -> eval -> quality_gate + + * The golden regression runs before ANY new training because it validates + the eval stack itself against numbers that are already known. A defective + harness silently corrupts every downstream measurement, and a full-epoch + run that under-performs a 0.35-epoch run then looks like a modeling + result instead of the stack bug it is. + * The 7B smoke runs before the probe because the chunked-loss peak-memory + assertion is only meaningful at 7B on the real 4-GPU topology. A + unit-scale memory check cannot catch what a 32768-vocab logit tensor does + to a 23GB card. + * The probe runs before the preflight and the launch because a measured step + time that invalidates the schedule must stop the run BEFORE it starts, not + three hours in. + +MODULE-LEVEL IMPORTS ARE DELIBERATELY TORCH-FREE. `scripts/sft.py` imports this +module above `apply_resource_guards()`, and torch reads +PYTORCH_CUDA_ALLOC_CONF, the cache paths and the thread caps AT IMPORT -- so +anything that pulls torch in transitively (probes, trainer, model) is imported +lazily inside the function that needs it. A test asserts this. +""" + +from __future__ import annotations + +import hashlib +import json +import logging +import math +import os +from dataclasses import dataclass +from datetime import datetime, timezone +from typing import Any, Optional + +from ..registry import MANDATORY_BANNER_KEYS, assert_banner_complete + +logger = logging.getLogger(__name__) + +NAN = float("nan") + +#: Explicit "not measured". Never absent, never a plausible substitute. +PENDING = "PENDING" + +#: The fixed stage sequence. Data, not prose: the ledger iterates it. +GATE_ORDER: tuple[str, ...] = ( + "golden_regression", + "smoke_7b", + "probe_20step", + "rss_preflight", + "train", + "eval", + "quality_gate", +) + +#: Gates whose result depends on the eval stack. A change under `align/eval/` +#: invalidates exactly these -- re-running the 7B smoke or the probe because +#: someone edited a verifier would burn GPU-hours for nothing. +EVAL_DEPENDENT_GATES: frozenset[str] = frozenset({"golden_regression", "eval", "quality_gate"}) + +LEDGER_FILENAME = "stage_gates.json" + + +def _is_rank0() -> bool: + """Rank from the environment, so this works before (and without) any + process group -- same convention as the heavy-job flock.""" + return int(os.environ.get("RANK", "0")) == 0 + + +class GateOrderError(RuntimeError): + """Raised when a gate runs before its predecessors have passed.""" + + +@dataclass +class GateDecision: + passed: bool + halt_message: str = "" + detail: dict = None # type: ignore[assignment] + + +# --------------------------------------------------------------------------- +# ledger +# --------------------------------------------------------------------------- + + +def eval_source_hash(repo_root: Optional[str] = None) -> str: + """Hash the `align/eval/` source tree. + + The golden regression certifies the harness, so its pass is only valid for + the harness that produced it. Keying the ledger entry on this hash is what + turns "we ran the golden regression once" into "we ran it against THIS + code". + """ + root = repo_root or os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + eval_dir = os.path.join(root, "align", "eval") + h = hashlib.sha256() + for dirpath, _dirs, files in sorted(os.walk(eval_dir)): + for fn in sorted(files): + if not fn.endswith(".py"): + continue + path = os.path.join(dirpath, fn) + h.update(os.path.relpath(path, eval_dir).encode()) + with open(path, "rb") as f: + h.update(f.read()) + return h.hexdigest()[:16] + + +class GateLedger: + """Records gate results, enforces the order, survives a restart.""" + + def __init__(self, run_dir: str, eval_source_hash: Optional[str] = None): + self.run_dir = run_dir + os.makedirs(run_dir, exist_ok=True) + self.path = os.path.join(run_dir, LEDGER_FILENAME) + self.eval_source_hash = eval_source_hash + self._entries: dict[str, dict] = {} + self._load() + + # -- persistence -------------------------------------------------------- + + def _load(self) -> None: + if not os.path.isfile(self.path): + return + try: + with open(self.path) as f: + blob = json.load(f) + except (OSError, json.JSONDecodeError): + logger.warning("unreadable gate ledger at %s; starting fresh", self.path) + return + + recorded_hash = blob.get("eval_source_hash") + self._entries = dict(blob.get("gates", {})) + if ( + self.eval_source_hash is not None + and recorded_hash is not None + and recorded_hash != self.eval_source_hash + ): + dropped = [g for g in EVAL_DEPENDENT_GATES if g in self._entries] + for g in dropped: + del self._entries[g] + if dropped: + logger.warning( + "align/eval/ changed since this ledger was written (%s -> %s); " + "invalidated %s. The golden regression certifies the eval " + "stack, so its pass does not carry across a change to it.", + recorded_hash, + self.eval_source_hash, + sorted(dropped), + ) + + def _save(self) -> None: + """Persist. RANK 0 ONLY -- see `record`.""" + if not _is_rank0(): + return + tmp = self.path + ".partial" + with open(tmp, "w") as f: + json.dump( + {"eval_source_hash": self.eval_source_hash, "gates": self._entries}, + f, + indent=1, + sort_keys=True, + # Runs on EVERY record: the site with the most chances to meet + # a non-serializable detail (attempt-6 class). + default=str, + ) + os.replace(tmp, self.path) + + # -- recording ---------------------------------------------------------- + + def record(self, gate: str, passed: bool, detail: str = "") -> dict: + if gate not in GATE_ORDER: + raise GateOrderError(f"unknown gate {gate!r}; the sequence is {list(GATE_ORDER)}") + idx = GATE_ORDER.index(gate) + for earlier in GATE_ORDER[:idx]: + if not self.is_passed(earlier): + raise GateOrderError( + f"refusing to record {gate!r}: {earlier!r} has not passed " + f"(it reads {self.status()[earlier]!r}). The stage sequence " + f"is fixed at {list(GATE_ORDER)} and each gate exists to " + "stop the next one from wasting GPU-hours. Run the earlier " + "gate, or fix why it failed." + ) + entry = { + "passed": bool(passed), + "detail": detail, + "recorded_at": datetime.now(timezone.utc).isoformat(timespec="seconds"), + } + # EVERY rank updates its own in-memory view; only RANK 0 persists. + # + # THE LEDGER RENAME RACE (killed attempt 3, past the smoke): all four + # ranks must run the gates -- the 7B smoke needs the full FSDP + # topology -- so all four called this, all four wrote the SAME + # `.partial`, the first rename consumed it and the other three died on + # FileNotFoundError. A gate is a property of the JOB, not of a rank. + # + # NO BARRIER, deliberately, and this is the safer half of the choice. + # Every rank keeps an identical in-memory ledger (the order checks and + # the passed flag are deterministic from local state), so no rank ever + # needs to READ the file mid-run -- which means no collective here, + # which means no way for a rank-0 raise to strand its peers waiting on + # one. A barrier would have re-introduced the NCCL-timeout shape to + # fix a filesystem race. Gate failures are themselves deterministic + # across ranks (same config, same files, host-wide MemAvailable), so + # all ranks raise together and torchrun propagates it. + self._entries[gate] = entry + self._save() + logger.info("gate %s: %s (%s)", gate, "PASS" if passed else "FAIL", detail or "-") + return entry + + # -- reading ------------------------------------------------------------ + + def is_passed(self, gate: str) -> bool: + return self._entries.get(gate, {}).get("passed") is True + + def status(self) -> dict: + """Every gate present; unrun gates read PENDING, never absent.""" + return {g: (self._entries[g] if g in self._entries else PENDING) for g in GATE_ORDER} + + def next_gate(self) -> Optional[str]: + for gate in GATE_ORDER: + if not self.is_passed(gate): + return gate + return None + + def require(self, gate: str) -> None: + if not self.is_passed(gate): + raise GateOrderError( + f"gate {gate!r} has not passed (reads {self.status()[gate]!r}); " + "refusing to continue" + ) + + +# --------------------------------------------------------------------------- +# individual gates +# --------------------------------------------------------------------------- + + +def _mem_available_gb() -> float: + with open("/proc/meminfo") as f: + for line in f: + if line.startswith("MemAvailable:"): + return float(line.split()[1]) / 1024**2 + raise RuntimeError("/proc/meminfo has no MemAvailable line") + + +def rss_preflight(cfg, mem_available_gb: Optional[float] = None) -> dict: + """`MemAvailable >= projected_job_RSS + headroom`, or refuse to start. + + The generic 45GB launch floor is insufficient for this job class and that + insufficiency IS the 2026-08-12 incident: the offloaded optimizer state + (~87GB) arrives over the first optimizer steps, AFTER any launch-time free + check has passed. On a box with no swap there is no overflow -- exhausting + RAM wedges the host in D-state and takes unrelated runs down with it. + """ + from .probes import projected_job_rss # imports torch; kept lazy + + projection = projected_job_rss(cfg) + projected = projection["total_gb"] + headroom = cfg.gates.rss_headroom_gb + required = projected + headroom + available = _mem_available_gb() if mem_available_gb is None else float(mem_available_gb) + + result = { + "passed": available >= required, + "mem_available_gb": available, + "projected_job_rss_gb": projected, + "headroom_gb": headroom, + "required_gb": required, + "breakdown": projection, + } + if not result["passed"]: + raise RuntimeError( + f"RSS PREFLIGHT FAILED: MemAvailable {available:.1f}GB < projected " + f"job RSS {projected:.1f}GB + {headroom:.0f}GB headroom = " + f"{required:.1f}GB.\nBreakdown: {projection}\nThis box has NO SWAP, " + "so there is no overflow: the offloaded optimizer state lands after " + "launch and would wedge the host mid-run (2026-08-12: 2GB free, " + "load 619, a healthy run killed by a 5-hour NCCL stall). Wait for " + "the host to quiesce, or switch optimizer.name to adamw8bit, which " + "drops the host-state term entirely." + ) + logger.info("RSS preflight ok: %.1fGB available >= %.1fGB required", available, required) + return result + + +def schedule_check(probe_report: dict, cfg, optimizer_steps_planned: int) -> dict: + """Project epoch wall-clock from the measured step time, or refuse. + + A measured step time that invalidates the schedule must stop the run before + it starts. Three hours into an epoch is too late to discover that the + epoch was never going to fit the window. + """ + step_time = float(probe_report.get("mean_step_time_s", NAN)) + if math.isnan(step_time): + raise RuntimeError( + "schedule check refused: the probe did not measure a step time " + "(mean_step_time_s is NaN). Every comparison against NaN is False, " + "so a naive budget check would read 'within budget' and launch. " + "Re-run the 20-step probe." + ) + if optimizer_steps_planned <= 0: + raise ValueError(f"optimizer_steps_planned={optimizer_steps_planned} is not a schedule") + + projected = step_time * optimizer_steps_planned + allowed = cfg.gates.epoch_budget_s * cfg.gates.schedule_budget_factor + result = { + "passed": projected <= allowed, + "mean_step_time_s": step_time, + "optimizer_steps_planned": optimizer_steps_planned, + "projected_epoch_s": projected, + "budget_s": cfg.gates.epoch_budget_s, + "allowed_s": allowed, + } + if not result["passed"]: + raise RuntimeError( + f"SCHEDULE CHECK FAILED: measured step time {step_time:.2f}s x " + f"{optimizer_steps_planned} optimizer steps projects an epoch " + f"wall-clock of {projected:.0f}s, beyond the allowed " + f"{allowed:.0f}s (budget {cfg.gates.epoch_budget_s:.0f}s x factor " + f"{cfg.gates.schedule_budget_factor}). Refusing to launch: the " + "GPU-hours are spent whether or not the epoch finishes. Either " + "raise gates.epoch_budget_s deliberately, or find the step-time " + "regression first." + ) + logger.info("schedule ok: %.0fs projected <= %.0fs allowed", projected, allowed) + return result + + +def quality_gate(report: dict, cfg) -> GateDecision: + """Does the new SFT checkpoint reach the golden anchors? + + Delegates the accuracy-vs-CI comparison to section-10's + `assert_meets_golden` rather than restating it: that function compares + against the WILSON LOWER BOUND (the golden numbers are themselves + measurements with sampling noise, so demanding the point estimate meet + them would fail correct runs about half the time), and two copies of that + reasoning would drift. + + NaN halts. That is the extraction-ceiling incident in gate form: a PERFECT + policy scored 0/100 for two full PPO runs because extraction was broken, + and an undefined accuracy that compared False would read as 'above golden'. + """ + from ..eval.harness import assert_meets_golden + + golden = {"math500": cfg.gates.golden_math500, "gsm8k": cfg.gates.golden_gsm8k} + try: + assert_meets_golden(report, golden) + except RuntimeError as exc: + return GateDecision( + passed=False, + halt_message=( + f"{exc}\n\nSTAGE HALTED. Section-12 (DPO) must not start on a " + "failed SFT gate. Bisect in this order before touching any " + "hyperparameter -- DATA (is the corpus the rebuilt one, and " + "does a decoded sample match the training format?), then LOSS " + "(does fused_ce still match the eager reference?), then " + "TRAINER (did the trunk-movement probe pass, and did the " + "schedule run in optimizer steps?), then EVAL (does the golden " + "regression still reproduce 0.09/0.258?). A full-epoch run " + "below a 0.35-epoch anchor is near-certain evidence of a " + "new-stack defect, not a modeling result." + ), + detail={"golden": golden, "report": report.get("per_set", {})}, + ) + return GateDecision(passed=True, detail={"golden": golden}) + + +def write_quality_gate_receipt(cfg, decision: "GateDecision", checkpoint: str = "") -> str: + """Write the receipt section-12 reads before it will start. + + The contract is narrow on purpose: a JSON object with a BOOLEAN `passed`. + Section-12's `read_sft_quality_gate` refuses anything else -- absent, + PENDING, or a truthy string all read as "not passed", because the whole + point is that a DPO run cannot begin on an SFT stage that did not clear + its own gate. + """ + path = cfg.paths.sft_quality_gate_path + if not _is_rank0(): + # Same rename race as the ledger: one receipt, written by the job. + return path + os.makedirs(os.path.dirname(path), exist_ok=True) + payload = { + "passed": bool(decision.passed), + # `detail` is the key SECTION-12's reader quotes in its refusal + # message. Emitting only `halt_message` would leave their error + # reading "(no detail recorded)" -- technically a correct refusal, + # and useless to whoever has to act on it. + "detail": ( + decision.halt_message.splitlines()[0] + if decision.halt_message + else "quality gate passed" + ), + "halt_message": decision.halt_message, + "checkpoint": checkpoint, + "golden": (decision.detail or {}).get("golden", {}), + "recorded_at": datetime.now(timezone.utc).isoformat(timespec="seconds"), + } + tmp = path + ".partial" + with open(tmp, "w") as f: + # default=str: this receipt is written AFTER the full epoch and both + # evals -- a non-serializable value here would discard the run's + # verdict at maximum cost (the smoke-receipt Tensor crash, attempt 6). + json.dump(payload, f, indent=1, sort_keys=True, default=str) + os.replace(tmp, path) + logger.info("SFT quality-gate receipt written: %s (passed=%s)", path, payload["passed"]) + return path + + +def assert_build_is_current(manifest_path: str, cfg) -> dict: + """Refuse to train on a data build that predates the last semantic fix. + + SECTION-03 REOPENED: every SFT target rendered `# Answer` TWICE -- the raw + PRM800K final step carries the marker inline and the renderer prepended it + again. Extraction survived by taking the last match, so nothing failed + loudly; the cost is training on a format the extraction ceiling never + exercised. + + Read honestly from the manifest, with no hardcoded dates: `pins_verified` + must be True, `pin_violations` must be empty, and `build_version` must + reach the configured minimum. A MISSING `build_version` raises -- an + unstamped build is not evidence of a current one. + """ + if not os.path.isfile(manifest_path): + raise RuntimeError( + f"no data build manifest at {manifest_path}. The stage consumes " + "shard hashes from the build artifact and never rebuilds data; " + "run scripts/build_data.py first." + ) + + # Section-03 drops a DEFECTIVE marker beside a build it has condemned. + # Checked FIRST and independently of build_version: a human-written "do + # not train on this" is the most direct signal there is, and honouring it + # costs one stat() while ignoring it costs a 4-hour epoch. + defective = os.path.join(os.path.dirname(os.path.abspath(manifest_path)), "DEFECTIVE") + if os.path.isfile(defective): + with open(defective) as f: + reason = f.read().strip() + raise RuntimeError( + f"the data build at {os.path.dirname(defective)} is marked " + f"DEFECTIVE by section-03:\n\n{reason}\n\nRefusing to train on " + "condemned shards." + ) + + with open(manifest_path) as f: + manifest = json.load(f) + + if manifest.get("pins_verified") is not True: + raise RuntimeError( + f"{manifest_path}: pins_verified is " + f"{manifest.get('pins_verified')!r}, not True. The corpus counts " + "were not corroborated against their pinned values, so the stage " + "cannot say what it would be training on." + ) + violations = manifest.get("pin_violations") or [] + if violations: + raise RuntimeError( + f"{manifest_path}: pins_verified is True but pin_violations is " + f"non-empty: {violations}. Trust the violations, not the flag." + ) + + version = manifest.get("build_version") + minimum = cfg.gates.min_build_version + if version is None: + raise RuntimeError( + f"{manifest_path} has no `build_version` field, so the stage " + "cannot tell whether this corpus predates the doubled-`# Answer`-" + "marker fix. An unstamped build is NOT assumed current: section-03 " + "stamps build_version (>= 2 after the fix; 1 is everything before " + "it) and this stage requires at least " + f"{minimum}. Rebuild the corpus, or add the field if the rebuild " + "already happened." + ) + if int(version) < minimum: + raise RuntimeError( + f"{manifest_path}: build_version {version} < required {minimum}. " + "This corpus predates the doubled-`# Answer`-marker fix -- every " + "SFT target renders the marker twice, which trains a format the " + "extraction ceiling never exercised. Rebuild before spending " + "GPU-hours on it." + ) + logger.info("data build ok: build_version=%s, pins verified", version) + return manifest + + +def assert_distinct_devices() -> dict: + """Every rank must own a DIFFERENT physical GPU. Microseconds, at startup. + + THE DUPLICATE-GPU DEFECT. torchrun starts four processes and assigns no + devices; nothing bound a rank to its LOCAL_RANK, so every `.cuda()` landed + on device 0 and NCCL died with "Duplicate GPU detected : rank 2 and rank 0 + both on CUDA device 1b0" -> ncclInvalidUsage. The symptom appeared deep in + a 7B forward+backward and read like a sharding or dtype problem; the cause + was four processes sharing one card. + + Two checks, and the second is the one that matters. `current_device() == + local_rank()` catches the missing bind. But the REAL invariant is that the + four devices are physically distinct -- a correct-looking local index can + still collide under an unexpected CUDA_VISIBLE_DEVICES -- so the ranks + all-gather their device UUIDs and assert uniqueness. UUID rather than + pci_bus_id: `get_device_properties(i).pci_bus_id` returns the local index + (0 here), which is exactly the number that would agree while the hardware + collides. + + Raises with the full rank -> device map, so the failure names itself + instead of surfacing 400 lines later as an NCCL error code. + """ + import torch + + from ..utils.dist import local_rank, world_size + + if not torch.cuda.is_available(): + return {"checked": False, "reason": "no CUDA device visible"} + + current, lr = torch.cuda.current_device(), local_rank() + uuid = str(getattr(torch.cuda.get_device_properties(current), "uuid", current)) + ws = world_size() + + import torch.distributed as dist + + distributed = ws > 1 and dist.is_available() and dist.is_initialized() + + # THE COLLECTIVE COMES FIRST, and my own both-directions test is why. My + # first version raised the local mismatch BEFORE gathering: under a real + # collision ranks 1-3 raised immediately while rank 0 (whose + # current_device DID equal its local_rank) entered the all-gather alone + # and waited forever for peers that had already died. A guard against a + # hang must not be able to hang. So every rank enters the collective + # unconditionally, then all of them evaluate the SAME gathered map and + # raise identically. + gathered: list = [(0, lr, current, uuid)] + if distributed: + # GLOO, not the default NCCL group. NCCL cannot complete a collective + # on ranks that share a device -- it raises ncclInvalidUsage -- so a + # guard that gathers over NCCL reports the very failure it exists to + # name, in NCCL's words instead of ours. gloo is CPU-side and does not + # care about GPU binding, so the duplicate map survives to the error + # message. Verified: with all four ranks forced onto device 0 this + # prints the rank->device map; over NCCL it printed "invalid usage". + group = getattr(assert_distinct_devices, "_guard_group", None) + if group is None: + group = dist.new_group(backend="gloo") + assert_distinct_devices._guard_group = group + gathered = [None] * ws + dist.all_gather_object(gathered, (dist.get_rank(), lr, current, uuid), group=group) + + device_map = {r: {"local_rank": l, "current_device": c, "uuid": u} for r, l, c, u in gathered} + + mismatched = {r: v for r, v in device_map.items() if v["current_device"] != v["local_rank"]} + if mismatched: + raise RuntimeError( + f"rank binding is wrong on {sorted(mismatched)}: " + f"{mismatched}. Call align.utils.dist.init_distributed() BEFORE any " + "CUDA op -- it does init_process_group + set_device(local_rank) -- " + "and place tensors with torch.device('cuda', local_rank()), never " + "a bare .cuda()." + ) + + uuids = [v["uuid"] for v in device_map.values()] + if len(set(uuids)) != len(uuids): + collisions: dict = {} + for r, v in device_map.items(): + collisions.setdefault(v["uuid"], []).append(r) + dupes = {u: rs for u, rs in collisions.items() if len(rs) > 1} + raise RuntimeError( + f"DUPLICATE GPU: {len(uuids)} ranks are sharing " + f"{len(set(uuids))} physical device(s). Ranks per device: {dupes}. " + f"Full map: {device_map}. Every rank must bind its own card before " + "any CUDA allocation; this is the ncclInvalidUsage that surfaces " + "later as a mysterious failure inside the model's forward." + ) + logger.info("device binding ok: %d rank(s) on %d distinct GPU(s)", len(uuids), len(set(uuids))) + return {"checked": True, "world_size": len(uuids), "device_map": device_map} + + +def derived_global_batch_rows(cfg) -> int: + """Rows per OPTIMIZER step, derived from the numbers that actually + produce them: grad_accum x micro_batch_size x world_size.""" + return cfg.optimizer.grad_accum * cfg.train.micro_batch_size * cfg.train.world_size + + +def assert_batch_arithmetic_consistent(cfg) -> dict: + """`global_batch_rows` must equal accum x micro x world, or refuse. + + THE TWO-HORIZONS DEFECT (found pre-launch). configs/sft.toml carried + grad_accum 4 x micro_batch 3 x world 4 = 48 rows per optimizer step while + declaring global_batch_rows = 24. Nothing reconciled them, and the two + numbers feed DIFFERENT consumers: the banner's reported horizon is + ceil(rows / global_batch_rows), while the Trainer's LR schedule is + ceil(len(sampler) x epochs / accum) and never reads global_batch_rows at + all. An LR schedule that ends at half or a third of its reported horizon + is the iterations-vs-steps incident wearing a new coat -- the run finishes + at a learning rate nobody chose, and the banner records the intended one. + + This makes the config internally consistent. It does NOT by itself make + the banner agree with the Trainer -- see `assert_horizon_agrees`, because + the length-grouped sampler batches by TOKEN budget, so its batch count is + not rows/global_batch under any value. + """ + derived = derived_global_batch_rows(cfg) + declared = cfg.train.global_batch_rows + if declared != derived: + raise RuntimeError( + f"batch arithmetic is inconsistent: train.global_batch_rows=" + f"{declared} but grad_accum({cfg.optimizer.grad_accum}) x " + f"micro_batch_size({cfg.train.micro_batch_size}) x world_size(" + f"{cfg.train.world_size}) = {derived}. One of these is wrong and " + "the stage cannot tell which: they drive DIFFERENT consumers " + "(the banner's reported horizon vs the optimizer step the trainer " + "actually takes), so a mismatch means the LR schedule ends " + f"{max(declared, derived) / min(declared, derived):.1f}x away from " + "the horizon the banner reports. Set global_batch_rows to " + f"{derived}, or change accum/micro/world so the product is " + f"{declared}." + ) + return {"global_batch_rows": declared, "derived": derived} + + +def assert_horizon_agrees(sampler_horizon: int, cfg, tolerance: float = 0.0) -> dict: + """The banner's horizon and the Trainer's must be the SAME number. + + The Trainer schedules on `ceil(len(sampler) x epochs / accum)`; the banner + reports `ceil(rows / global_batch_rows) x epochs`. Because the sampler + batches by token budget rather than row count, these agree only by + coincidence. Rather than pick one silently, this refuses on disagreement + and prints both -- an LR horizon is a pre-registered quantity and choosing + it is a human decision, not a rounding convention. + """ + from .stage_smoke import _sft_rows + + config_horizon = scheduler_horizon_optimizer_steps( + rows=_sft_rows(cfg), global_batch=cfg.train.global_batch_rows, epochs=cfg.train.epochs + ) + if sampler_horizon != config_horizon: + spread = max(sampler_horizon, config_horizon) / max(1, min(sampler_horizon, config_horizon)) + raise RuntimeError( + f"HORIZON MISMATCH: the trainer will schedule over " + f"{sampler_horizon} optimizer steps (len(sampler) x epochs / " + f"accum) but the config projects {config_horizon} " + f"(rows / global_batch_rows x epochs) -- {spread:.2f}x apart. The " + "LR schedule is a pre-registered quantity; the stage refuses to " + "guess which horizon was intended. Reconcile global_batch_rows " + "with the sampler's token budget, or set the horizon explicitly." + ) + return {"horizon_optimizer_steps": sampler_horizon} + + +def stamp_golden_report(path: str, repo_root: Optional[str] = None) -> str: + """Stamp the golden report with the hash of the eval source that PRODUCED it (audit U01-9). + + Called by `scripts/eval.py --mode=golden` right after the run (also when the gate raised: the + failing report is evidence too). `record_golden_from_report` refuses a report whose stamp is + not the current eval source, so editing align/eval/ and re-recording from the old report + cannot re-certify the new code. Atomic rewrite; returns the stamped hash. + """ + h = eval_source_hash(repo_root) + with open(path, "rb") as f: + report = json.loads(f.read()) + report["eval_source_hash"] = h + tmp = path + ".partial" + with open(tmp, "w") as f: + json.dump(report, f, indent=1, default=str) + f.flush() + os.fsync(f.fileno()) + os.replace(tmp, path) + return h + + +def record_golden_from_report( + ledger: GateLedger, report_path: Optional[str] = None, cfg=None +) -> dict: + """Bridge the golden-regression RUN to the gate LEDGER, by re-deciding. + + THE MISSING-BRIDGE DEFECT (pre-launch): `scripts/eval.py --mode=golden` + writes its report and passes or raises IN PROCESS; nothing ever wrote the + verdict into the ledger. `require_golden_receipt` reads + `ledger.is_passed("golden_regression")`, so after a PASSING golden run the + SFT stage would still have refused on PENDING. + + VERIFY FROM EVIDENCE, NOT FROM A FLAG. This does not take "the run + exited 0" as the receipt -- it loads the persisted report and re-runs the + verdict through section-10's own `assert_meets_golden`, so there is ONE + authority for what meeting the golden numbers means. A report that no + longer passes cannot leave a stale PASS in the ledger. + + Three outcomes, and the middle one is the one that gets skipped: + * report passes -> record PASSED, with the path and sha256 in the + detail so the receipt names the exact bytes it certified; + * report FAILS -> record FAILED with the failure text. Failing is not + not-yet-run: a recorded failure BLOCKS every later gate, whereas + leaving it unrecorded would let a rerun quietly try again; + * report absent -> record NOTHING, leaving the gate PENDING. The run + has not happened; inventing a verdict from a missing file is the + failure this whole gate exists to prevent. + + sha256 is computed inline rather than via `receipts.sha256_file` to keep + this module importable above the resource guards -- see the module header. + """ + from ..eval.golden import GOLDEN, GOLDEN_N, assert_meets_golden + + path = report_path or (cfg.paths.golden_report_path if cfg is not None else None) + if not path: + raise ValueError("record_golden_from_report needs a report path or a cfg") + + if not os.path.isfile(path): + logger.warning( + "golden report %s is absent; leaving golden_regression PENDING. " + "Run `scripts/eval.py --mode=golden` before the stage.", + path, + ) + return {"recorded": False, "passed": None, "path": path, "reason": "report absent"} + + with open(path, "rb") as f: + raw = f.read() + digest = hashlib.sha256(raw).hexdigest() + report = json.loads(raw) + + # U01-9: the ledger drops the golden pass when align/eval/ changes (`GateLedger._load`), but a + # report produced by the OLD source would otherwise be re-recorded as a fresh PASS here. The + # report must name the source that produced it, and it must be the source we are running. + stamped = report.get("eval_source_hash") if isinstance(report, dict) else None + current = ledger.eval_source_hash or eval_source_hash() + if stamped is None: + logger.warning( + "golden report %s carries no eval_source_hash (it predates producer stamping): " + "cannot verify it was produced by the current align/eval/ source", + path, + ) + elif stamped != current: + logger.error( + "golden report %s was produced by eval source %s but align/eval/ is now %s; refusing to " + "re-certify it. Re-run `scripts/eval.py --mode=golden`.", + path, + stamped, + current, + ) + return { + "recorded": False, + "passed": None, + "path": path, + "reason": f"golden report produced by a different eval source ({stamped} != {current})", + } + + try: + assert_meets_golden(report, GOLDEN, expected_n=GOLDEN_N) + except (RuntimeError, AssertionError) as exc: + detail = json.dumps({"report": path, "sha256": digest, "failure": str(exc)[:600]}) + ledger.record("golden_regression", passed=False, detail=detail) + logger.error("golden regression FAILED per %s: %s", path, exc) + return { + "recorded": True, + "passed": False, + "path": path, + "sha256": digest, + "failure": str(exc), + } + + detail = json.dumps( + { + "report": path, + "sha256": digest, + "golden": GOLDEN, + "expected_n": GOLDEN_N, + "per_set": report.get("per_set", {}), + }, + default=str, + ) + ledger.record("golden_regression", passed=True, detail=detail) + logger.info("golden regression PASSED per %s (sha256 %s)", path, digest[:12]) + return {"recorded": True, "passed": True, "path": path, "sha256": digest} + + +def require_golden_receipt(ledger: GateLedger, cfg) -> None: + """The golden regression must have PASSED, not merely been attempted. + + PENDING is never passed. This is the precondition that keeps a defective + eval stack from certifying everything downstream of it. + """ + if not cfg.gates.require_golden_receipt: + logger.warning( + "gates.require_golden_receipt is False -- training will " + "start without a validated eval stack" + ) + return + if not ledger.is_passed("golden_regression"): + raise GateOrderError( + "the golden-regression gate has not passed (it reads " + f"{ledger.status()['golden_regression']!r}). Refusing to train: " + "that run is what validates the eval stack -- verifier, prompt " + "template, extraction, inference path -- against numbers that are " + "already known. Without it, every accuracy this stage produces is " + "unfalsifiable. Run `scripts/eval.py --mode=golden` first." + ) + + +# --------------------------------------------------------------------------- +# banner +# --------------------------------------------------------------------------- + + +def assemble_sft_banner( + cfg, + attention_backend: str, + optimizer_impl: str, + dataset_hashes: Optional[dict], + ceiling_results: Optional[dict], + probe_report: Optional[dict], + rss_projection: Optional[dict], + mde: Optional[dict], + scheduler_horizon_optimizer_steps: Optional[int], + scheduler_horizon_rows_derived: Optional[int] = None, +) -> dict: + """Every mandatory banner value, resolved or explicitly PENDING/NaN. + + `beta` is NaN for SFT rather than 0.0: 0.0 is a legitimate DPO beta, so a + zero here would be indistinguishable from a real setting. + + THE HORIZON IS THE TRAINER'S, NOT THE CONFIG'S. `scheduler_horizon_ + optimizer_steps` must be the sampler-derived number the scheduler will + actually run; the rows/global_batch projection rides beside it under a + LABELED secondary key. A banner that records a horizon the scheduler does + not run is the config-translation value-drift class in its purest form -- + the record looks right and the run is something else. A mismatch is LOGGED + loudly here rather than raised; the hard refusal + (`assert_horizon_agrees`) is wired after the first SFT run so it cannot + become a fresh launch blocker. + """ + banner = { + "attention_backend": attention_backend, + "loss_type": "sft_ce", + "beta": NAN, + "lr": cfg.optimizer.lr, + "scheduler_horizon_optimizer_steps": ( + scheduler_horizon_optimizer_steps + if scheduler_horizon_optimizer_steps is not None + else PENDING + ), + "dataset_hashes": dataset_hashes, + "ceiling_results": ceiling_results, + "rss_budget": rss_projection, + "pinned_staging_gb": (rss_projection or {}).get("pinned_staging_gb", PENDING), + "probe_step_time_s": (probe_report or {}).get("mean_step_time_s", PENDING), + "mde": mde, + "optimizer_impl": optimizer_impl, + "grad_accum": cfg.optimizer.grad_accum, + "probe_p90_step_time_s": (probe_report or {}).get("p90_step_time_s", PENDING), + "scheduler_horizon_rows_derived": ( + scheduler_horizon_rows_derived + if scheduler_horizon_rows_derived is not None + else PENDING + ), + } + if ( + scheduler_horizon_rows_derived is not None + and scheduler_horizon_optimizer_steps is not None + and scheduler_horizon_rows_derived != scheduler_horizon_optimizer_steps + ): + logger.warning( + "HORIZON DIVERGENCE: the scheduler will run %s optimizer steps " + "(sampler-derived, AUTHORITATIVE) but rows/global_batch_rows " + "projects %s -- %.2fx apart. The banner records the former " + "because that is what runs. Reconcile global_batch_rows with the " + "sampler's token budget; the hard refusal lands after this run.", + scheduler_horizon_optimizer_steps, + scheduler_horizon_rows_derived, + max(scheduler_horizon_optimizer_steps, scheduler_horizon_rows_derived) + / max(1, min(scheduler_horizon_optimizer_steps, scheduler_horizon_rows_derived)), + ) + # Raises rather than printing a partial banner: a run that cannot answer + # its own question does not begin. + assert_banner_complete(banner) + return banner + + +def assert_probe_resolved(banner: dict) -> None: + """A stage that REQUIRES the probe refuses to launch on PENDING. + + Banner completeness and banner resolution are different properties: every + key being present is not the same as every value having been measured. + """ + pending = [ + k + for k in ("probe_step_time_s", "rss_budget", "scheduler_horizon_optimizer_steps") + if banner.get(k) == PENDING or banner.get(k) is None + ] + if pending: + raise RuntimeError( + f"refusing to launch: {pending} still read PENDING. The 20-step " + "probe and the RSS projection must be MEASURED before the epoch " + "starts -- their whole purpose is to stop a run that cannot fit " + "its schedule or its host RAM." + ) + step_time = banner["probe_step_time_s"] + if isinstance(step_time, float) and math.isnan(step_time): + raise RuntimeError( + "probe_step_time_s is NaN: the probe ran but measured nothing. " + "Refusing to launch on an unmeasured schedule." + ) + + +# --------------------------------------------------------------------------- +# CLI contract + stage drivers (thin; scripts/sft.py owns the side effects) +# --------------------------------------------------------------------------- + + +def parse_args(argv: Optional[list[str]] = None): + """`torchrun --nproc_per_node=4 scripts/sft.py configs/sft.toml + --optimizer.lr=1e-5` -- first positional is the TOML, the rest are dotted + overrides handed to section-01's loader (struct mode on, so a typo'd key + raises at launch instead of training with the default it failed to + override). + + Parsed by hand rather than with argparse: `--optimizer.lr=1e-5` is not an + argparse option, it is a dotted-override entry (`section.field=value`), and argparse rejects + every one of them as unrecognized. + """ + import sys as _sys + + argv = list(_sys.argv[1:] if argv is None else argv) + if "-h" in argv or "--help" in argv: + print(__doc__) + raise SystemExit(0) + + positional = [a for a in argv if not a.startswith("-")] + overrides = [a.lstrip("-") for a in argv if a.startswith("-")] + if not positional: + raise SystemExit( + "usage: sft.py [--section.field=value ...]\n" + "The stage TOML is required: a stage that picks its own defaults " + "is a stage nobody can reproduce." + ) + if len(positional) > 1: + raise SystemExit( + f"expected exactly one config TOML, got {positional}. Extra " + "positional arguments are silently ignored by most launchers, " + "which is how a run ends up using the wrong config." + ) + bad = [o for o in overrides if "=" not in o] + if bad: + raise SystemExit(f"overrides must be dotted key=value pairs; got {bad}") + return type("Args", (), {"config": positional[0], "overrides": overrides})() + + +def run_entry_gates( + cfg, + ledger: GateLedger, + smoke_steps: int = 10, + probe_steps: int = 20, + mem_available_gb: Optional[float] = None, + optimizer_steps_planned: Optional[int] = None, +) -> dict: + """The M5 entry sequence, in order: 7B smoke -> 20-step probe -> RSS + preflight. GPU-only; imported lazily so this module stays torch-free.""" + from .stage_smoke import run_smoke_and_probe # GPU-only helpers + + require_golden_receipt(ledger, cfg) + assert_batch_arithmetic_consistent(cfg) + + smoke = run_smoke_and_probe(cfg, smoke_steps=smoke_steps, probe_steps=probe_steps) + ledger.record("smoke_7b", passed=True, detail=json.dumps(smoke["smoke"], default=str)) + ledger.record("probe_20step", passed=True, detail=json.dumps(smoke["probe"], default=str)) + + steps = optimizer_steps_planned or smoke["optimizer_steps_planned"] + schedule_check(smoke["probe"], cfg, optimizer_steps_planned=steps) + rss = rss_preflight(cfg, mem_available_gb=mem_available_gb) + ledger.record( + "rss_preflight", + passed=True, + detail=json.dumps({k: v for k, v in rss.items() if k != "breakdown"}), + ) + + return assemble_sft_banner( + cfg, + attention_backend=smoke["attention_backend"], + optimizer_impl=smoke["optimizer_impl"], + dataset_hashes=smoke["dataset_hashes"], + ceiling_results=smoke["ceiling_results"], + probe_report=smoke["probe"], + rss_projection=rss["breakdown"], + mde=smoke["mde"], + scheduler_horizon_optimizer_steps=steps, + scheduler_horizon_rows_derived=smoke.get("optimizer_steps_rows_derived"), + ) + + +def evaluate_and_gate(cfg, ledger: GateLedger, checkpoint: str) -> GateDecision: + """Run the post-training eval and apply the quality gate, recording both.""" + from .stage_smoke import run_stage_eval # GPU-only helper + + report = run_stage_eval(cfg, checkpoint) + ledger.record("eval", passed=True, detail=json.dumps(report.get("per_set", {}), default=str)) + decision = quality_gate(report, cfg) + ledger.record("quality_gate", passed=decision.passed, detail=decision.halt_message[:400]) + write_quality_gate_receipt(cfg, decision, checkpoint=checkpoint) + return decision diff --git a/code/align/train/stage_smoke.py b/code/align/train/stage_smoke.py new file mode 100644 index 0000000000000000000000000000000000000000..1392c7bceee886967c548b3b880b2435dd5afbe6 --- /dev/null +++ b/code/align/train/stage_smoke.py @@ -0,0 +1,530 @@ +"""GPU-only stage helpers: the 7B smoke, the throughput probe, the stage eval. + +Separated from `stage_gates.py` so that module stays importable above the +resource guards. Everything here touches torch, the 7B weights, or the eval +harness, so nothing here runs in the CPU suite -- the gate DECISIONS these +feed are what the CPU tests cover. + +The peak-memory assertion lives here rather than in the unit tests because it +is only meaningful at 7B on the real topology: the tensor it proves we avoid +is `[B*T, 32768]`, which at seq 1024 x micro-batch 8 is 1.0GB in bf16 plus +another 1.0GB of gradient. A unit-scale check cannot see that. +""" + +from __future__ import annotations + +import logging +import time +from typing import Optional + +import torch + +logger = logging.getLogger(__name__) + + +def _load_snapshot_state(snapshot: str) -> dict: + """HF-layout state dict from a snapshot dir, single-file OR sharded, cast + to bf16 shard-by-shard. + + The pinned Mistral-7B-v0.3 snapshot is THREE shards plus + `model.safetensors.index.json`; `transformers.from_pretrained` used to + resolve that. The layout logic (and the index-vs-shards completeness + check) now lives in `ckpt.load_hf_safetensors`, so every caller pointed at + a base snapshot gets the same behaviour; this wrapper only pins the dtype. + """ + from ..model import checkpoint as ckpt + + return ckpt.load_hf_safetensors(snapshot, dtype=torch.bfloat16) + + +def build_stage_model( + cfg, attn_implementation: Optional[str] = None, weights_dir: Optional[str] = None +): + """The real 7B model, FSDP2-sharded per block with activation + checkpointing. Wrapping happens HERE (the stage), never inside the + Trainer -- the Trainer receives an already-wrapped model, which is what + keeps it identical between the SFT and DPO stages. + + `weights_dir` names an HF-layout checkpoint whose weights replace the + pinned snapshot's (the architecture still comes from the snapshot's + config.json, which a full-FT checkpoint shares). Without it the model is + the PRETRAINED BASE -- right for training, wrong for evaluating a trained + checkpoint (G3 audit U01-4: the stage-11 gate scored the base).""" + from ..model import checkpoint as ckpt + from ..model.hf_config import read_config + from ..model.mistral import NmoMistralForCausalLM + from . import fsdp + + # Local only -- never let a stage reach the hub and start a 15GB download + # onto a shared box mid-launch. `resolve_snapshot_dir` accepts the + # configured `snapshots/` parent and resolves the one hash dir under it. + snapshot = ckpt.resolve_snapshot_dir(cfg.paths.model_snapshot) + # The pre-port path went through transformers' `from_pretrained` (and its + # MistralConfig defaults); `read_config` states every architecture field + # explicitly and refuses a config.json that omits one. + model_cfg = read_config(snapshot) + model_cfg.attn_implementation = attn_implementation or cfg.model.attn_implementation + # Shards are read straight from safetensors (the snapshot is bf16 on disk; + # the cast is a no-op there and a safety net for an fp32 checkpoint). + hf_state = _load_snapshot_state(weights_dir if weights_dir is not None else snapshot) + model = NmoMistralForCausalLM.from_state_dict( + model_cfg, + ckpt.hf_to_nmo(hf_state), + attn_implementation=model_cfg.attn_implementation, + ) + del hf_state + + # Onto THIS rank's device before sharding. The weights arrive on CPU from + # safetensors, and `fully_shard` on CPU parameters shards the wrong + # thing; the batches are already `.cuda()`. Uses the local rank explicitly + # rather than a bare `.cuda()`, which is device 0 for every rank. + from ..utils.dist import local_rank + + device = torch.device("cuda", local_rank()) if torch.cuda.is_available() else None + if device is not None: + torch.cuda.set_device(device) + model = model.to(device) + + fsdp.apply_activation_checkpointing(model) + fsdp.apply_fsdp(model) + return model + + +def assert_chunked_loss_memory(cfg, model, batch) -> dict: + """The chunked-loss peak-memory assertion, at 7B scale. + + MEASURES THE LOSS, NOT THE STEP -- and the first 7B run is why. I had + wrapped the whole adapter forward+backward, so the measured peak was + 6103 MiB against a [1002, 32768] logit tensor of 125 MiB: a 40x "failure" + that was really the 7B model's own activations and FSDP all-gathers being + attributed to the loss. The gate asserts that CHUNKING controls the loss's + memory; feeding it the model's memory makes it unsatisfiable by any + implementation, which is the same unsatisfiable-gate trap section-05 + already hit once with the lm_head gradient. + + So the hidden states are produced OUTSIDE the measured region and + detached, and the lm_head weight is materialised once via `full_tensor()` + (it is a DTensor under FSDP2 and the fused loss needs the whole thing). + What remains inside the measurement is exactly the chunked loss and its + backward. + + The full step's peak is still REPORTED, as `full_step_peak_bytes` -- it is + the number that tells us what a rank actually costs -- it just is not what + this gate asserts on. + """ + from ..kernels.fused_ce import ( + IGNORE_INDEX, + assert_chunking_saves, + assert_peak_memory_below_full_logits, + fused_linear_cross_entropy, + lm_head_grad_allowance, + ) + from .sft_loss import make_sft_loss_adapter + + input_ids, labels = batch + target = labels[:, 1:] + + # 1. The real step, executed and measured for the record (this is also the + # end-to-end wiring check: FSDP2 hooks, checkpointing, fused path). + torch.cuda.reset_peak_memory_stats() + out = make_sft_loss_adapter(require_fused=True)(model, (input_ids, labels)) + out.loss.backward() + torch.cuda.synchronize() + full_step_peak = int(torch.cuda.max_memory_allocated()) + model.zero_grad(set_to_none=True) + loss_value = float(out.loss.detach()) + del out + + # 2. The gate: the chunked loss in isolation, over detached hidden states. + with torch.no_grad(): + hidden = model(input_ids=input_ids, return_hidden_states=True) + h = hidden[:, :-1].detach().clone().requires_grad_(True) + del hidden + # n_rows DERIVED FROM THE TENSOR, never from the config. The measured + # batch is 1002 rows where seq_len x micro_batch would predict 3072 -- + # the sampler is token-budgeted -- and a budget computed from the config + # would silently be 3x the shape actually being measured. + n_rows = int(h.reshape(-1, h.shape[-1]).shape[0]) + w = model.lm_head.weight + w_full = w.full_tensor() if hasattr(w, "full_tensor") else w + w_full = w_full.detach().clone().requires_grad_(True) + + def _loss_only(): + loss = fused_linear_cross_entropy(h, w_full, target, ignore_index=IGNORE_INDEX) + loss.backward() + return loss + + report = assert_peak_memory_below_full_logits( + _loss_only, + n_rows, + cfg.model.vocab_size, + device=h.device, + # DTYPE-AWARE, and section-05's gate now refuses the alternative. The + # fp32 default (8 bytes/element) came to 1024 MiB, which EXCEEDED the + # entire 775.8 MiB measured peak -- so `attributable` clamped to zero + # and the gate passed no matter what the loss did. Under FSDP2 + # mixed-precision the lm_head is bf16 with fp32 gradient accumulation: + # 6 bytes/element, 768 MiB. That leaves a real 7.8 MiB attributable + # against a 125.2 MiB budget -- a measurement instead of a rubber stamp. + # `param_dtype` is the lm_head's own dtype under FSDP2 + # mixed-precision (bf16); `accum_dtype` is the fp32 the fused kernel + # accumulates d_weight in. Their sum -- 6 bytes/element, 768 MiB -- is + # what the module provably holds at the instant d_weight is cast to + # the parameter dtype, which is the peak. + unavoidable_bytes=lm_head_grad_allowance( + cfg.model.vocab_size, + cfg.model.hidden_size, + param_dtype=torch.bfloat16, + accum_dtype=torch.float32, + ), + label="section-11 M5 7B smoke", + ) + + # DIFFERENTIAL gate: chunked vs unchunked at the SAME shape, so every + # confounder cancels and no allowance is needed. An implementation that + # materialised the full logit tensor would show ~0 saving. This is the + # check that cannot be made vacuous by a mis-specified allowance, which is + # the failure the previous version of this gate actually had. + def _make_fn(chunk_size: int): + def _run(): + h.grad = None + w_full.grad = None + fused_linear_cross_entropy( + h, w_full, target, chunk_size=chunk_size, ignore_index=IGNORE_INDEX + ).backward() + + return _run + + report["chunking_saves"] = assert_chunking_saves( + _make_fn, + n_rows=n_rows, + vocab=cfg.model.vocab_size, + chunk_rows=128, + device=h.device, + label="section-11 M5 7B smoke (differential)", + ) + + report["full_step_peak_bytes"] = full_step_peak + report["step_loss"] = loss_value + logger.info( + "7B smoke: loss=%.4f full-step peak=%.0fMiB loss-only peak=%.0fMiB", + loss_value, + full_step_peak / 2**20, + report.get("peak_bytes", 0) / 2**20, + ) + return report + + +def resolve_split_dir(shard_dir, split: str): + """Find the directory holding `-NNNN.receipt.json`, by DISCOVERY. + + THE HAND-COMPOSED-PATH DEFECT (caught at launch). I wrote + `ShardDataset(cfg.data.shard_dir, names=[cfg.data.sft_split])`, expecting a + flat `data/shards/sft-train.receipt.json`. Section-03's real layout is + `data/shards/sft/train/sft-train-0000.receipt.json`. Resolved by searching + for the receipts the store itself wrote rather than rebuilding + `//` from a naming convention, so a layout change moves + this by itself and a missing split reports the splits that ARE present. + """ + from pathlib import Path + + root = Path(shard_dir) + if not root.is_dir(): + raise FileNotFoundError( + f"shard root {root} does not exist; the stage consumes shards " + "built by scripts/build_data.py and never builds them itself" + ) + + found: dict[str, "Path"] = {} + for receipt in root.rglob("*.receipt.json"): + prefix = receipt.name.split(".receipt.json")[0].rsplit("-", 1)[0] + found.setdefault(prefix, receipt.parent) + if split not in found: + raise FileNotFoundError( + f"no shards for split {split!r} under {root}. Splits present: " + f"{sorted(found)}. (The stage never composes this path from a " + "naming convention -- it looks for the receipts the store wrote.)" + ) + return found[split] + + +def open_split(cfg, split: Optional[str] = None): + """The ONE way this stage opens shards. Both the smoke batches and the + training sampler go through here, so they cannot disagree about layout.""" + from ..data.store import ShardDataset + + name = split or cfg.data.sft_split + return ShardDataset(resolve_split_dir(cfg.data.shard_dir, name)) + + +def build_training_sampler(cfg, rank: int | None = None, world_size: int | None = None): + """The sampler the Trainer will actually iterate -- THIS RANK's share. + + Built HERE and reused by scripts/sft.py and scripts/pretrain.py so the + stage cannot time, project, and then train on three different batch + streams. The LR horizon is derived from THIS object's length, which is + therefore the per-rank micro-step count the Trainer really runs. + + Under world_size > 1 the token-budgeted batch list is sharded by + `DistributedBatchSampler` (the same seam dpo_stage uses). Before this, + every rank iterated the full unsharded list: a 4-rank run averaged four + IDENTICAL gradients -- the throughput of one GPU at the cost of four -- + and scheduled on a horizon 4x the per-rank work. Nothing failed; the loss + curve was that of a smaller-batch run. + + `rank`/`world_size` default to the live environment and are explicit so + the inter-rank contract can be tested in one CPU process. + """ + from ..data.loader import DistributedBatchSampler, LengthGroupedSampler + from ..utils.dist import rank as env_rank + from ..utils.dist import world_size as env_world_size + + dataset = open_split(cfg) + lengths = [len(dataset[i].input_ids) for i in range(len(dataset))] + base = LengthGroupedSampler( + lengths, max_tokens=cfg.train.seq_len * cfg.train.micro_batch_size, seed=cfg.train.seed + ) + r = env_rank() if rank is None else int(rank) + ws = env_world_size() if world_size is None else int(world_size) + if ws <= 1: + return base, dataset + if not 0 <= r < ws: + raise ValueError(f"rank {r} is outside world_size {ws}") + return DistributedBatchSampler(base, rank=r, world_size=ws), dataset + + +def sampler_derived_horizon(cfg, sampler) -> int: + """The horizon the TRAINER will schedule on: the same arithmetic + `Trainer.__init__` uses, `ceil(len(sampler) x epochs / accum)`. + + This is the authoritative number. The rows/global_batch figure is a + projection over a ROW count, but the sampler batches by TOKEN budget, so + the two agree only by coincidence -- and the banner must record the + schedule that runs, not the one that was estimated. + """ + import math as _math + + total_micro = len(sampler) * cfg.train.epochs + return max(1, _math.ceil(total_micro / cfg.optimizer.grad_accum)) + + +def run_smoke_and_probe(cfg, smoke_steps: int = 10, probe_steps: int = 20) -> dict: + """10-step 7B smoke (with the peak-memory assertion) then the 20-step + throughput probe. Returns everything the launch banner needs.""" + from ..data.loader import assert_worker_count + from .offload_adamw import make_optimizer + from .probes import aggregate_micro_step_times, throughput_report + from .sft_loss import make_sft_loss_adapter + from .trainer import scheduler_horizon_optimizer_steps + + assert_worker_count(cfg.data.num_workers) + model = build_stage_model(cfg) + optimizer = make_optimizer(cfg, [p for p in model.parameters() if p.requires_grad]) + adapter = make_sft_loss_adapter(require_fused=True) + + batches = _stage_batches(cfg, n=smoke_steps + probe_steps) + memory_report = assert_chunked_loss_memory(cfg, model, batches[0]) + + step_times: list[float] = [] + for i, batch in enumerate(batches): + t0 = time.perf_counter() + out = adapter(model, batch) + (out.loss / cfg.optimizer.grad_accum).backward() + if (i + 1) % cfg.optimizer.grad_accum == 0: + optimizer.step() + optimizer.zero_grad() + torch.cuda.synchronize() + elapsed = time.perf_counter() - t0 + if i >= smoke_steps: # the smoke steps are warmup + step_times.append(elapsed) + + # AUTHORITATIVE: what the Trainer will actually schedule on. + sampler, _dataset = build_training_sampler(cfg) + planned = sampler_derived_horizon(cfg, sampler) + # SECONDARY, labeled: the rows/global_batch projection, kept beside it so + # a divergence is visible in the record rather than silently resolved. + rows_derived = scheduler_horizon_optimizer_steps( + rows=_sft_rows(cfg), global_batch=cfg.train.global_batch_rows, epochs=cfg.train.epochs + ) + probe = throughput_report( + # micro -> optimizer-step durations (task #25): tokens_per_step and + # `planned` below are per-optimizer-step units. + step_times_s=aggregate_micro_step_times(step_times, cfg.optimizer.grad_accum), + tokens_per_step=cfg.train.seq_len + * cfg.train.micro_batch_size + * cfg.optimizer.grad_accum + * cfg.train.world_size, + optimizer_steps_planned=planned, + offload_transfer_s=None, + offload_cpu_step_s=None, + ) + + return { + "smoke": {"steps": smoke_steps, **memory_report}, + "probe": probe, + "optimizer_steps_planned": planned, + "optimizer_steps_rows_derived": rows_derived, + "attention_backend": model.attn_implementation, + "optimizer_impl": getattr(optimizer, "banner_tag", cfg.optimizer.name), + "dataset_hashes": _manifest_hashes(cfg), + "ceiling_results": _ceiling_results(cfg), + "mde": _mde(cfg), + } + + +def run_stage_eval(cfg, checkpoint: str) -> dict: + """Evaluate a checkpoint on MATH-500 + GSM8K under section-10's harness.""" + from ..eval.harness import EvalConfig, load_eval_set, run_eval + from ..eval.verifier import OutcomeVerifier + + verifier = OutcomeVerifier() + reports = {} + for name, path, limit in ( + ("math500", cfg.paths.math500_path, cfg.eval.math500_n), + ("gsm8k", cfg.paths.gsm8k_path, cfg.eval.gsm8k_n), + ): + problems = load_eval_set(path, limit=limit) + report = run_eval( + problems, _stage_generate_fn(cfg, checkpoint), verifier, EvalConfig(), model_name=name + ) + # EvalReport has no `.results`; per-set scores live in `per_set`, + # keyed by each problem's source (one key for a single-set call). + # The old attribute error was latent -- this path never ran to + # completion before 2026-08-18. + reports[name] = report.per_set[name] + return { + "per_set": reports, + "config": { + "mde": _mde(cfg), + "n_problems": sum(r.get("n", 0) for r in reports.values()), + "eval_set_hash": _manifest_hashes(cfg), + }, + } + + +# -- small helpers the stage script fills in from the build artifact --------- + + +def _stage_batches(cfg, n: int): + from ..data.loader import collate_sft + from ..utils.dist import local_rank + + dataset = open_split(cfg) + mb = cfg.train.micro_batch_size + out = [] + for i in range(n): + rows = [dataset[(i * mb + j) % len(dataset)] for j in range(mb)] + batch = collate_sft(rows, pad_token_id=cfg.data.pad_token_id) + # Explicit device: a bare .cuda() is device 0 for every rank unless + # set_device already ran, and relying on that ordering is what the + # duplicate-GPU guard exists to stop us doing. + dev = torch.device("cuda", local_rank()) + out.append((batch.input_ids.to(dev), batch.labels.to(dev))) + return out + + +def _sft_rows(cfg) -> int: + """Corpus size from the BUILD ARTIFACT, never a literal. + + The plan says "~11.8K"; the build measured 12,410 (walk- and max_len- + dependent). The schedule horizon must follow the corpus that actually + exists, or the LR decays against a row count nobody trained on. + """ + import json + + with open(cfg.data.manifest_path) as f: + counts = json.load(f).get("counts", {}) + rows = counts.get("sft_rows") + if not rows: + raise RuntimeError( + f"{cfg.data.manifest_path} has no counts.sft_rows; the scheduler " + "horizon cannot be derived and must not be guessed." + ) + return int(rows) + + +def _manifest_hashes(cfg) -> dict: + import json + + with open(cfg.data.manifest_path) as f: + return json.load(f).get("hashes", {}) + + +def _ceiling_results(cfg) -> dict: + """The extraction ceiling, re-run against THIS stage's eval sets. + + `preflight_extraction` returns NaN with a loud warning when no source + exists, and a NaN here is what the banner shows and the gate refuses -- + which is the point: an outcome signal nobody ceiling-tested is how a + PERFECT policy scored 0/100 for two full PPO runs. + """ + from ..eval.roundtrip import preflight_extraction + + return { + "extraction_roundtrip": preflight_extraction( + [cfg.paths.math500_path, cfg.paths.gsm8k_path], eos="", label="section-11 SFT stage" + ) + } + + +def _mde(cfg) -> dict: + from ..eval.metrics import min_detectable_effect + + return { + "math500": min_detectable_effect(cfg.eval.math500_n), + "gsm8k": min_detectable_effect(cfg.eval.gsm8k_n), + } + + +def _stage_generate_fn(cfg, checkpoint: str): + """Bind section-09's Engine to the harness's `generate_fn(prompts, cfg, + seeds)` contract, over the weights IN `checkpoint`. + + THE BASE-MODEL-GATE DEFECT (G3 audit U01-4). This used to build the model + from `cfg.paths.model_snapshot` and use `checkpoint` only to find + tokenizer.json, so the post-epoch quality gate (and the receipt section-12 + reads) scored the untouched base model; and its signature + `(prompts, seeds=None, **kw)` could not even accept the harness's three + positional arguments. Generation is the golden gate's greedy path + (`golden_generate_fn`), so the numbers are comparable to the anchors the + gate compares against. + + PAIRED SEEDS. The Engine owns ONE sampling generator per instance, so + per-problem seeds cannot be threaded through it. Under greedy decoding + (the eval default) the seeds are irrelevant and dropping them is exact; a + SAMPLED eval would silently decorrelate the arms and invalidate every + McNemar comparison, so it is refused instead. + """ + import os + + from ..eval.golden import golden_generate_fn + from ..model.checkpoint import resolve_snapshot_dir + from ..tokenizer import load_tokenizer + + # Weights-only checkpoints (pre tokenizer-copy fix) have no tokenizer.json + # -- that crash cost stage-11's first post-epoch eval. Vocab never changes + # during full-FT, so the pinned snapshot's tokenizer IS the checkpoint's. + # (`load_tokenizer` reads tokenizer.json directly; there is no slow + # sentencepiece-conversion path left to fall into.) + tok_src = checkpoint + if not os.path.isfile(os.path.join(checkpoint, "tokenizer.json")): + tok_src = resolve_snapshot_dir(cfg.paths.model_snapshot) + logger.warning( + "checkpoint %s has no tokenizer.json; loading tokenizer from the pinned snapshot %s", + checkpoint, + tok_src, + ) + tokenizer = load_tokenizer(tok_src) + model = build_stage_model(cfg, weights_dir=checkpoint) + greedy_fn = golden_generate_fn(model, tokenizer) + + def generate_fn(prompts, eval_cfg, seeds): + if eval_cfg.temperature != 0.0: + raise ValueError( + f"stage eval is greedy-only: temperature={eval_cfg.temperature} needs the " + "paired per-problem seeds, which the Engine cannot thread (one generator " + "per engine); dropping them would invalidate every paired comparison" + ) + return greedy_fn(prompts, eval_cfg, seeds) + + return generate_fn diff --git a/code/align/train/train_module.py b/code/align/train/train_module.py new file mode 100644 index 0000000000000000000000000000000000000000..92a1bded452a1822f169cc4c52f4f37387a88395 --- /dev/null +++ b/code/align/train/train_module.py @@ -0,0 +1,283 @@ +"""The TrainModule: model + loss adapter + optimizer behind one seam. + +This is the OLMo-core separation (olmo_core/train/train_module/train_module.py) +ported as a PATTERN, not as code: the Trainer owns the loop, the schedule, the +checkpoint orchestration, the instruments and history.jsonl; the TrainModule +owns everything that touches the model -- forward, backward, the gated +optimizer step, and the model/optimizer state movement that FSDP2 makes +non-trivial. The Trainer never calls `.backward()` or `.step()` itself and +never inspects a DTensor; the TrainModule never opens a file, never logs a +metric, and never decides WHEN anything happens. + +Why the seam matters here and not just aesthetically: stage-b GRPO (M-C/M-D) +needs a second module -- same Trainer loop, same checkpoint orchestration, +same tripwires-and-history machinery, different train_batch (rollout batch, +vendored GRPO loss, rho weights). Under the old single-class Trainer that +would have meant a second trainer or a stage flag forest; under this seam it +is one new TrainModule subclass. + +Two contracts are load-bearing and inherited verbatim from the old Trainer: + + * `train_batch` performs EXACTLY `(out.loss / grad_accum).backward()`. The + DPO decoupled-backward adapter returns a detached leaf proxy sized so + that this call applies the trainer's accumulation contract to gradients + the adapter already planted -- any cleverness here (scaling elsewhere, + calling backward twice, retaining graphs) silently double-scales DPO + gradients. + * The FSDP2 state movement (full gather on save, CPU-slice per-tensor load + on resume) keeps its exact production-proven form; both carry incident + history in their docstrings. +""" + +from __future__ import annotations + +import logging +from dataclasses import dataclass, field +from typing import Any, Optional, Protocol + +import torch + +logger = logging.getLogger(__name__) + + +@dataclass +class LossOutput: + """What every loss adapter returns. + + `metrics` carries stage-specific values for the log (DPO's margin, + logps/chosen, logps/rejected). Undefined entries must be NaN, never 0.0 -- + a 0.0 margin reads as 'no preference learned', which is a finding, not a + missing measurement. + """ + + loss: torch.Tensor + n_tokens: int + metrics: dict[str, float] = field(default_factory=dict) + + +class LossAdapter(Protocol): + """The interface the TrainModule consumes. Section-05 owns the two real + implementations; neither the Trainer nor the TrainModule imports either. + + SFT: batch -> chunked fused CE over hidden states, so the + [B*T, 32768] logit tensor never materialises. + DPO: batch (with precomputed reference logprobs as constants) -> + fused DPO loss, reporting margin and both logps in `metrics`. + """ + + def __call__(self, model: Any, batch: Any) -> LossOutput: ... + + +LOSS_NORMALIZATIONS = ("micro_mean", "global_token_mean") + + +def reduce_window_tokens(local_tokens: int) -> int: + """SUM of `local_tokens` over every rank (gloo group; identity on one process). + + The denominator of the global token mean: the number of target tokens in the whole accumulation + window of the WHOLE world. A collective -- every rank must call it at the same program point. + """ + import torch.distributed as dist + + if not (dist.is_available() and dist.is_initialized()): + return int(local_tokens) + from ..utils.dist import gloo_group + + g = gloo_group() + if g is None: + return int(local_tokens) + t = torch.tensor([int(local_tokens)], dtype=torch.int64) + dist.all_reduce(t, op=dist.ReduceOp.SUM, group=g) + return int(t.item()) + + +def _dp_world_size() -> int: + import torch.distributed as dist + + return dist.get_world_size() if (dist.is_available() and dist.is_initialized()) else 1 + + +class TrainModule: + """Owns the model, the loss adapter, and the optimizer. + + The default module wraps the existing SFT/DPO path unchanged; stage-b + GRPO subclasses `train_batch`. + """ + + def __init__(self, model, loss_adapter: LossAdapter, optimizer, grad_accum: int): + if grad_accum < 1: + raise ValueError(f"grad_accum must be >= 1, got {grad_accum}") + self.model = model + self.loss_adapter = loss_adapter + self.optimizer = optimizer + self.grad_accum = int(grad_accum) + + # -- the two loop-facing calls ------------------------------------------- + + def train_batch(self, batch, window_tokens: Optional[int] = None) -> LossOutput: + """Forward + backward for one micro-batch. + + Scales by accumulation so the gradient matches one large batch rather + than the sum of `grad_accum` batches. This exact call is the contract + the DPO decoupled-backward proxy honors -- see the module docstring. + + `window_tokens` (None = `loss_normalization="micro_mean"`, the original + behaviour, byte-for-byte the line above) switches to the GLOBAL TOKEN + MEAN (audit U03-2): the adapter's micro-batch mean is turned back into + the micro-batch's summed CE (`loss * n_tokens`) and divided by the + target-token count of the whole window across all ranks. FSDP2/DDP then + AVERAGE the per-rank gradients over the world, so the local term is + multiplied by the world size to make that average a SUM: + grad = (1/N) * sum over every rank and micro-batch of grad(sum CE). + """ + out = self.loss_adapter(self.model, batch) + if window_tokens is None: + (out.loss / self.grad_accum).backward() + else: + if window_tokens < 1: + raise ValueError(f"window_tokens must be >= 1, got {window_tokens}") + scale = _dp_world_size() * float(out.n_tokens) / float(window_tokens) + (out.loss * scale).backward() + return out + + def optim_step(self) -> bool: + """Gated optimizer step + zero_grad; True iff the step was applied. + + The gate (non-finite grads skip the step) lives in the optimizer + wrapper; this module only reports what happened so the Trainer can + keep its rule that the schedule counts steps that ACTUALLY happened. + """ + stepped = self.optimizer.step() + self.optimizer.zero_grad() + return stepped + + def zero_grads(self) -> None: + self.optimizer.zero_grad() + + def set_train(self) -> None: + self.model.train() + + # -- optimizer telemetry the Trainer logs -------------------------------- + + @property + def last_grad_norm(self) -> float: + return self.optimizer.last_grad_norm + + @property + def skipped_steps(self) -> int: + return getattr(self.optimizer, "skipped_steps", 0) + + # -- state movement ------------------------------------------------------- + + def full_model_state_dict(self): + """An UNSHARDED, CPU state dict that safetensors can actually write. + + THE DTENSOR CHECKPOINT DEFECT (found before it could fire, one gate + after the ledger race). Under FSDP2 `model.state_dict()` returns + DTensors -- global shape, local shard -- and safetensors dies on them + with "Attempted to access the data pointer on an invalid python + storage". Measured on the tiny model at 4 ranks: a [64,64] weight + comes back as a DTensor holding a [16,64] shard. Nothing in the CPU + suite can see this; a single process has no sharding. + + `get_model_state_dict(full_state_dict=True, cpu_offload=True)` is the + canonical gather. It costs a transient full copy in host RAM per rank, + which is why the write is rank-0-only rather than the gather being + skipped. + """ + import torch.distributed as dist + + if not (dist.is_available() and dist.is_initialized()): + return self.model.state_dict() + from torch.distributed.checkpoint.state_dict import StateDictOptions, get_model_state_dict + + return get_model_state_dict( + self.model, options=StateDictOptions(full_state_dict=True, cpu_offload=True) + ) + + def load_model_state_dict(self, nmo_state: dict) -> None: + """Load full CPU tensors into a possibly-FSDP2-sharded model. + + FSDP2 params are DTensors: a plain load_state_dict copies full + tensors into shards and throws "mixed torch.Tensor and DTensor" + -- first exercised IN PRODUCTION at the stage-11 tail resume, + since every earlier launch resumed from nothing. And + set_model_state_dict(full_state_dict=True) is the wrong mirror + here, and so is per-tensor distribute_tensor over full tensors: + both put each WHOLE tensor on GPU before sharding, and the + varying-shape transients churn reserved memory toward + full-model size per rank (measured: rank 0 at 14GB against a + 3.4GB shard; the 4-rank resume OOM'd on a card also carrying + peers' NCCL IPC mappings). Every rank already read the FULL + state from disk, so: slice on CPU, ship ONLY the local shard. + """ + if any(hasattr(p, "to_local") for p in self.model.parameters()): + from torch.distributed.tensor import Shard, distribute_tensor + + params = dict(self.model.named_parameters()) + missing = sorted(set(params) - set(nmo_state)) + unexpected = sorted(set(nmo_state) - set(params)) + if missing or unexpected: + raise KeyError( + f"resume state mismatch: missing={missing[:5]} unexpected={unexpected[:5]}" + ) + with torch.no_grad(): + for pname, p in params.items(): + full = nmo_state[pname].to(p.dtype) + local = p.to_local() + if tuple(p.placements) == (Shard(0),): + ws = p.device_mesh.size() + rk = p.device_mesh.get_local_rank() + chunk = full.chunk(ws, dim=0)[rk] + if chunk.shape != local.shape: + raise RuntimeError( + f"{pname}: local shard {tuple(local.shape)} != " + f"chunk {tuple(chunk.shape)} (uneven sharding?)" + ) + local.copy_(chunk.to(local.device)) + else: + p.copy_( + distribute_tensor(full, p.device_mesh, p.placements, src_data_rank=None) + ) + else: + self.model.load_state_dict(nmo_state, strict=True) + + def optim_state_dict(self) -> dict: + return self.optimizer.state_dict() + + def load_optim_state_dict(self, sd: dict) -> None: + self.optimizer.load_state_dict(sd) + + def reseed_optimizer_from_params(self) -> bool: + """After a resume that restored weights but NO optimizer state: let an optimizer that owns an + fp32 master copy (OffloadAdamW) re-seed it from the restored params. True iff it did.""" + fn = getattr(self.optimizer, "reseed_masters_from_params", None) + if fn is None: + return False + fn() + return True + + # -- module-owned state that must survive a kill -------------------------- + + def extra_state(self) -> dict: + """Module-private resume state, saved under `resume.pt["extra_state"]`. + + The Trainer owns weights, optimizer, schedule and stream position; it + cannot know about state a SUBCLASS accumulates across steps (the GRPO + collapse tripwire's baseline window and latch). That state used to die + with the process: a resume re-measured the baseline on the post-resume + policy, so a collapse that began before the kill was invisible for + ~min_steps_before_fire steps. Subclasses override this pair; the default + is an empty dict so the key always exists and `load_extra_state({})` + is a no-op, never a KeyError on an older checkpoint's neighbour. + + Contract: only tensors, dicts, lists and primitives. `resume.pt` is + read back with `weights_only=True`, so anything else would make the + checkpoint unloadable -- fail at SAVE time, not at the resume you + needed it for. + """ + return {} + + def load_extra_state(self, sd: dict) -> None: + """Inverse of `extra_state`. Called BEFORE the scheduler/stream restore.""" + return None diff --git a/code/align/train/trainer.py b/code/align/train/trainer.py new file mode 100644 index 0000000000000000000000000000000000000000..5da8a80ecba15d9ceb50656ace8ac6c7637f5b82 --- /dev/null +++ b/code/align/train/trainer.py @@ -0,0 +1,2405 @@ +"""The one Trainer for SFT and DPO, plus the resume machinery it depends on. + +The stage scripts (sections 11/12) differ only in loss adapter, dataset, and +config; the loop, the checkpoint cadence, the schedule, the probes, and the +tripwires are shared so a fix to any of them cannot land in one stage and miss +the other. + +M-A (course-correction, 2026-08-22): the OLMo-core Trainer/TrainModule split. +Everything that touches the model -- forward, backward, the gated optimizer +step, FSDP2 state movement -- now lives in `align.train.train_module.TrainModule`; +this class owns the loop, the schedule, the checkpoint ORCHESTRATION (cadence, +idempotence, barriers, prune), the instruments and history.jsonl. `model`, +`optimizer` and `loss_adapter` remain readable and assignable on the Trainer +(scripts and tests use both), delegating to the module. + +Three properties here are load-bearing, and each of them is a documented +predecessor failure rather than a design preference: + + * THE SCHEDULE IS COUNTED IN OPTIMIZER STEPS. Under grad-accum 4, a horizon + counted in dataloader iterations decays the learning rate four times too + fast, and the run ends at a learning rate its config never asked for. + * THE CHECKPOINT CADENCE IS COUNTED IN MICRO-STEPS. That keeps "a kill loses + at most N micro-steps of work" true when someone changes accumulation. The + host on this box seizes without warning; a 3-hour run that checkpoints on + an accumulation-dependent cadence loses an unpredictable amount. + * RESUME IS LOSSLESS AND SEEDED. The batch stream's offset is the number of + batches CONSUMED, advanced before the yield -- see ResumableBatchStream. + +Checkpoints are bf16-weights-only, which is safe precisely because the fp32 +optimizer master is restored alongside them and is the authoritative copy. + +G0 control plane (2026-10-12). Everything below is a DECISION that more than +one rank must take identically, and the failure it prevents is the same each +time: one rank acts alone while its peers sit in a collective, so the run does +not crash, it hangs until the NCCL watchdog fires (the 5-hour stall of +2026-08-12 had exactly this shape). Hence one rule: a rank-local fact (a +signal, a wall clock, a tripwire verdict, a non-finite loss) becomes an action +only after a MAX all-reduce on the gloo group, at a program point every rank +reaches. + + * stop (SIGTERM/SIGINT, a supervisor's STOP_REQUEST file, + `train.max_wall_seconds`) -- agreed at each OPTIMIZER-STEP boundary, saved + there, never mid-accumulation; + * HALT tripwires and the arm-time self-test -- rank-reduced before raising; + * the skip cap -- computed from reduced values, so every rank counts the same; + * checkpoint integrity -- fsync before the atomic rename, and a completeness + check so a truncated directory is skipped by `latest_checkpoint`. +""" + +from __future__ import annotations + +import json +import logging +import math +import os +import re +import shutil +import signal +import struct +import threading +import time +import zipfile +from typing import Optional + +import torch + +from ..exit_codes import ( + EXIT_NONFINITE_HALT, + EXIT_TRIPWIRE_HALT, + EXIT_WALL_BUDGET, + ExitCodeError, + write_halt_marker, +) +from ..utils.supervisor import ( + DRAIN_READY_NAME, + STOP_MARKER_NAME, + STOP_REQUEST_NAME, + clear_run_marker, + read_run_marker, + write_run_marker, +) +from ..utils.dist import ( + all_gather_objects, + all_reduce_max, + any_rank, + capture_rng_state, + restore_rng_state, + world_size as _dist_world_size, +) +from ..utils.guard import assert_paths_off_root +from ..utils.tracking import Tracker +from . import sharded_ckpt +from .ckpt_format import DenseFormat +from .offload_adamw import make_optimizer +from .probes import ( + GradNormTripwire, + LengthDriftTripwire, + LogpsChosenTripwire, + TrunkMovementProbe, + aggregate_micro_step_times, + assert_tripwires_armed, + throughput_report, +) + +# Loss surface lives with the TrainModule now; re-exported here because the +# loss adapters and tests import them from this module. +from .train_module import ( # noqa: F401 + LOSS_NORMALIZATIONS, + LossAdapter, + LossOutput, + TrainModule, + reduce_window_tokens, +) + +logger = logging.getLogger(__name__) + +NAN = float("nan") + +#: Every log record must carry these. A missing key raises in the Tracker -- +#: undefined values are NaN, never absent and never 0. +MANDATORY_METRICS = ("loss", "lr", "micro_step", "optimizer_step", "grad_norm") + +#: THE CANONICAL MARGIN KEY, repo-wide. This is the name section-05's DPO +#: kernel emits, and the Trainer reads it DIRECTLY rather than through an +#: alias. One name, one authority: the previous arrangement had the kernel +#: emitting `rewards/margins` while the Trainer seeded and read `margin`, which +#: disarmed the chosen-likelihood-collapse tripwire completely. +MARGIN_KEY = "rewards/margins" +LOGPS_CHOSEN_KEY = "logps/chosen" +LENGTHS_CHOSEN_KEY = "lengths/chosen" +GRAD_NORM_KEY = "grad_norm" + +#: Tripwire names the Trainer knows how to arm. +TRIPWIRE_BUILDERS = ("logps_chosen", "length_drift", "grad_norm") + +#: Measured on this box (tmp/offload_bench.json): 2.56s CPU AdamW per 1.81B +#: rank shard + ~0.82s PCIe transfer per rank per optimizer step. At accum 4 +#: that is 20-30% step-time overhead; at accum 1 it is 50-100%. +MIN_GRAD_ACCUM_FULL_FT = 4 + + +#: Skip-cap defaults (read with getattr off `cfg.train`, because config.py is +#: another lane's file; a config that carries the field overrides these, and +#: `None` disables that cap). +DEFAULT_MAX_CONSECUTIVE_SKIPPED_STEPS = 3 +DEFAULT_MAX_SKIPPED_FRACTION = 0.05 +#: The fraction cap is not evaluated before this many optimizer-step +#: boundaries: 1 skip in the first 5 steps is 20% and says nothing. +SKIP_FRACTION_MIN_STEPS = 100 + + +class HaltError(ExitCodeError): + """A run-ending decision that every rank raises together. + + Subclasses RuntimeError (via ExitCodeError) so every pre-existing + `pytest.raises(RuntimeError, match=...)` on a tripwire HALT keeps matching. + `exit_code` is the process exit status the stage scripts map it to + (`align.exit_codes.run_with_exit_codes`) and that the supervisor refuses to + retry; `Trainer.train` also writes it to `/HALT.json`, because + torchrun reports every worker failure as exit 1. + """ + + exit_code = EXIT_TRIPWIRE_HALT + + +class NonFiniteHaltError(HaltError): + """The skip cap (consecutive / fractional) fired: the run is not training.""" + + exit_code = EXIT_NONFINITE_HALT + + +class _StopSignals: + """SIGTERM/SIGINT -> a flag, for the duration of one `train()` call. + + THE SIGTERM-MID-SAVE DEFECT (REFERENCE_GAP_ANALYSIS gap 1; scripts/sft.py + documents a torchrun SIGTERM landing mid-save). Python's default SIGTERM + action kills the process wherever it is -- including inside a 13.5GB + checkpoint write or between a rank's gather and its peers'. The handler does + the only thing a handler may safely do (set a flag); the loop acts on it at + an optimizer-step boundary, after all ranks have agreed. + + A SECOND SIGINT raises KeyboardInterrupt: an operator whose first Ctrl-C is + being honoured slowly (a save in flight) still needs a way out, and the + save path already deletes its `.partial` on any BaseException. + Handlers can only be installed from the main thread; elsewhere (a test + harness thread) this degrades to "no handlers", loudly. + """ + + SIGNALS = (signal.SIGTERM, signal.SIGINT) + + def __init__(self) -> None: + self.signum: Optional[int] = None + self._previous: dict = {} + self.installed = False + + def _handle(self, signum, frame) -> None: # noqa: ARG002 + if self.signum is not None and signum == signal.SIGINT: + raise KeyboardInterrupt + if self.signum is None: + self.signum = int(signum) + + def __enter__(self) -> "_StopSignals": + if threading.current_thread() is not threading.main_thread(): + logger.warning( + "Trainer.train() is not on the main thread: SIGTERM/SIGINT handlers " + "cannot be installed, so no coordinated stop on signal" + ) + return self + for sig in self.SIGNALS: + self._previous[sig] = signal.signal(sig, self._handle) + self.installed = True + return self + + def __exit__(self, *exc) -> None: + for sig, prev in self._previous.items(): + signal.signal(sig, signal.SIG_DFL if prev is None else prev) + self._previous.clear() + self.installed = False + + +# --------------------------------------------------------------------------- +# checkpoint durability and completeness +# --------------------------------------------------------------------------- + + +def _fsync_path(path: str) -> None: + """fsync a file OR a directory by path (a directory fsync is what makes a + rename/create inside it durable).""" + fd = os.open(path, os.O_RDONLY) + try: + os.fsync(fd) + finally: + os.close(fd) + + +def fsync_tree(root: str) -> None: + """fsync every file under `root`, then every directory (leaves first). + + THE ATOMIC-RENAME-IS-NOT-DURABLE DEFECT. `os.rename(staging, final)` is + atomic against a process crash, not against a power loss or a host seizure + (the box has seized before): without an fsync the rename can reach the + journal before the file DATA reaches disk, leaving a `micro_N` directory of + zero-length files that passes every `os.path.isdir` check -- a half-written + checkpoint that looks complete. Data first, then the directory entries, then + (caller) the rename, then the parent directory. + """ + dirs = [] + for dirpath, _dirnames, filenames in os.walk(root): + dirs.append(dirpath) + for f in filenames: + _fsync_path(os.path.join(dirpath, f)) + for d in reversed(dirs): + _fsync_path(d) + + +def _torch_save_synced(obj, path: str) -> None: + """`torch.save` to `path` and fsync it before returning.""" + with open(path, "wb") as f: + torch.save(obj, f) + f.flush() + os.fsync(f.fileno()) + + +def _safetensors_problem(path: str) -> Optional[str]: + """None if `path` is a structurally complete safetensors file, else why not. + + Reads ONLY the header: 8-byte little-endian length, then that many bytes of + JSON whose `data_offsets` say how long the tensor buffer must be. A file cut + anywhere short of that fails the size check, so truncation is detected + without reading 13GB. + """ + if not os.path.isfile(path): + return f"missing weights file {os.path.basename(path)}" + size = os.path.getsize(path) + if size < 8: + return f"{os.path.basename(path)} is {size} bytes (no safetensors header)" + with open(path, "rb") as f: + (n,) = struct.unpack(" size - 8 or n > 100 * 2**20: + return f"{os.path.basename(path)} header claims {n} bytes of a {size}-byte file" + try: + header = json.loads(f.read(n)) + except ValueError: + return f"{os.path.basename(path)} header is not valid JSON (truncated?)" + end = 0 + for k, v in header.items(): + if k == "__metadata__": + continue + end = max(end, int(v["data_offsets"][1])) + if size < 8 + n + end: + return ( + f"{os.path.basename(path)} is truncated: {size} bytes on disk, header " + f"requires {8 + n + end}" + ) + return None + + +def _zip_problem(path: str) -> Optional[str]: + """None if `path` is a readable torch.save zip archive (central directory + intact -- it is written LAST, so any truncation destroys it).""" + if not os.path.isfile(path): + return f"missing {os.path.basename(path)}" + if os.path.getsize(path) == 0: + return f"{os.path.basename(path)} is empty" + try: + with zipfile.ZipFile(path) as z: + if not any(n.endswith("data.pkl") for n in z.namelist()): + return f"{os.path.basename(path)} has no data.pkl" + except (zipfile.BadZipFile, OSError) as e: + return f"{os.path.basename(path)} is not a readable torch archive ({e})" + return None + + +def checkpoint_problem(path: str) -> Optional[str]: + """`_checkpoint_problem` made TOTAL: it returns a reason, it never raises. + + THE VERDICT-THAT-CRASHES DEFECT. The completeness check parses files a dying + host may have cut anywhere, so a half-written manifest can be syntactically + valid but structurally wrong (a `per_rank_files` layout with no + `world_size`, a safetensors header that is JSON but not an object). Those + surfaced as a KeyError/AttributeError out of the check, and every caller + that asks "is this the newest GOOD checkpoint?" -- `latest_checkpoint` + (resume), the supervisor's progress rule -- died on the exact directory it + exists to step over, instead of skipping it and falling back. Unknown is + not complete: any exception is the finding. + """ + try: + return _checkpoint_problem(path) + except Exception as e: # noqa: BLE001 -- see docstring + return f"checkpoint metadata is malformed ({type(e).__name__}: {e})" + + +def _checkpoint_problem(path: str) -> Optional[str]: + """None iff the checkpoint directory is COMPLETE; otherwise the first reason. + + "Complete" is what resume will actually need, checked cheaply (headers and + file presence, no 13GB reads): + + * weights: `model.safetensors` -- or every shard named by + `model.safetensors.index.json` -- present with a header whose declared + tensor extent fits inside the file; + * `resume.pt`: a readable archive whose top-level object is a dict with + its loop state (`micro_step`, `stream`, `scheduler`); + * when its manifest says `per_rank_files`: one readable + `optimizer_rank{r}.pt` for EVERY rank the manifest names (the SAVED + world size, not the current one -- a rank-count mismatch is refused + later with its own message and must not be disguised as "incomplete"). + + The rename-after-fsync protocol means a complete directory is the norm; this + exists for the hosts that seize between the rename and the data reaching + disk, for a checkpoint copied by hand, and for a disk that filled mid-copy. + """ + if not os.path.isdir(path): + return "not a directory" + if sharded_ckpt.is_sharded(path): + # Sharded layout (train.checkpoint_format="sharded"): the manifest names + # one weights file per rank. The directory's own manifest decides, not + # the current config, exactly as for per_rank_files below. + problem = sharded_ckpt.sharded_problem(path, _safetensors_problem) + if problem: + return problem + shards = [] + else: + index = os.path.join(path, "model.safetensors.index.json") + if os.path.isfile(index): + try: + with open(index) as f: + shards = sorted(set(json.load(f)["weight_map"].values())) + except (ValueError, KeyError, OSError) as e: + return f"unreadable model.safetensors.index.json ({e})" + else: + shards = ["model.safetensors"] + for shard in shards: + problem = _safetensors_problem(os.path.join(path, shard)) + if problem: + return problem + + resume = os.path.join(path, "resume.pt") + problem = _zip_problem(resume) + if problem: + return problem + try: + # mmap: the gather-mode resume.pt carries every rank's optimizer state + # (tens of GB); we want the manifest, not the bytes. + try: + state = torch.load(resume, weights_only=True, map_location="cpu", mmap=True) + except RuntimeError: + state = torch.load(resume, weights_only=True, map_location="cpu") + except Exception as e: # noqa: BLE001 -- any failure to load IS the finding + return f"resume.pt does not load ({type(e).__name__}: {e})" + if not isinstance(state, dict) or not {"micro_step", "stream", "scheduler"} <= state.keys(): + return "resume.pt is missing its loop state (micro_step/stream/scheduler)" + layout = state.get("optimizer_state") + if isinstance(layout, dict) and layout.get("layout") == "per_rank_files": + for r in range(int(layout["world_size"])): + problem = _zip_problem(os.path.join(path, f"optimizer_rank{r}.pt")) + if problem: + return f"per-rank optimizer state incomplete: {problem}" + return None + + +# --------------------------------------------------------------------------- +# the batch stream +# --------------------------------------------------------------------------- + + +class ResumableBatchStream: + """A seeded, resumable iterator over (epoch, batch) with an exact offset. + + THE OFF-BY-ONE. `offset` is the number of batches CONSUMED, and it is + advanced BEFORE the yield. Advancing it after the yield looks equivalent + and is not: a generator does not execute past its yield until the consumer + asks for the next item, so a checkpoint taken while holding batch i would + record offset i and the resumed run would replay batch i. One duplicated + batch is one step of stale gradient -- nothing crashes, no metric moves, + and the run stops being the run its seed describes. + + A sibling lane shipped exactly this bug: their trainer-level resume test + passed while the stream offset was off by one, and only a dedicated + offset test found it. + """ + + def __init__(self, sampler, epochs: int = 1): + self.sampler = sampler + self.epochs = int(epochs) + self.epoch = 0 + self.offset = 0 + self.consumed_total = 0 + + def __iter__(self): + while self.epoch < self.epochs: + self.sampler.set_epoch(self.epoch) + batches = list(self.sampler) + for i in range(self.offset, len(batches)): + self.offset = i + 1 + self.consumed_total += 1 + yield batches[i] + self.epoch += 1 + self.offset = 0 + + def unconsume(self) -> None: + """Hand back the batch most recently yielded, because it was never trained. + + The loop must pull a batch before it can decide the run is over, so a + horizon stop leaves the stream one batch ahead of the work actually + done. Without this the end-of-training checkpoint records an offset + (and `consumed_total`) of micro_step + 1: the resumed stream would skip + a batch no step ever saw, which is the off-by-one the class docstring + describes, arriving from the other side. Exact because a generator is + suspended AT its yield: `offset == i + 1` and the epoch rollover has not + run yet. + """ + if self.offset < 1 or self.consumed_total < 1: + raise RuntimeError("unconsume() with nothing consumed") + self.offset -= 1 + self.consumed_total -= 1 + + def state_dict(self) -> dict: + return {"epoch": self.epoch, "offset": self.offset, "consumed_total": self.consumed_total} + + def load_state_dict(self, sd: dict) -> None: + self.epoch = int(sd["epoch"]) + self.offset = int(sd["offset"]) + self.consumed_total = int(sd["consumed_total"]) + + +# --------------------------------------------------------------------------- +# schedule +# --------------------------------------------------------------------------- + + +def scheduler_horizon_optimizer_steps(rows: int, global_batch: int, epochs: int) -> int: + """`epochs * ceil(rows / global_batch)`, in OPTIMIZER steps. + + The unit is the whole point. Counting this in dataloader iterations under + accum 4 decays the LR four times too fast, and the symptom -- a run that + plateaus early -- looks like a data or capacity problem, not a scheduler + bug. + """ + if rows <= 0 or global_batch <= 0 or epochs <= 0: + raise ValueError( + f"horizon needs positive rows/global_batch/epochs, got {rows}/{global_batch}/{epochs}" + ) + return epochs * math.ceil(rows / global_batch) + + +class WarmupCosineSchedule: + """Linear warmup then cosine decay, stepped once per OPTIMIZER step.""" + + def __init__( + self, base_lr: float, total_steps: int, warmup_frac: float = 0.03, min_lr_frac: float = 0.0 + ): + if total_steps <= 0: + raise ValueError("total_steps must be positive") + self.base_lr = float(base_lr) + self.total_steps = int(total_steps) + self.warmup_steps = max(1, int(round(warmup_frac * total_steps))) + self.min_lr_frac = float(min_lr_frac) + self.step_count = 0 + + def lr(self) -> float: + t = self.step_count + if t < self.warmup_steps: + return self.base_lr * (t + 1) / self.warmup_steps + # Clamped at the horizon: a scheduler stepped past its total must not + # produce a negative or oscillating LR. + progress = min(1.0, (t - self.warmup_steps) / max(1, self.total_steps - self.warmup_steps)) + cosine = 0.5 * (1.0 + math.cos(math.pi * progress)) + return self.base_lr * (self.min_lr_frac + (1.0 - self.min_lr_frac) * cosine) + + def step(self) -> None: + self.step_count += 1 + + def state_dict(self) -> dict: + return { + "step_count": self.step_count, + "total_steps": self.total_steps, + "warmup_steps": self.warmup_steps, + "base_lr": self.base_lr, + } + + def load_state_dict(self, sd: dict) -> None: + self.step_count = int(sd["step_count"]) + self.total_steps = int(sd["total_steps"]) + self.warmup_steps = int(sd["warmup_steps"]) + self.base_lr = float(sd["base_lr"]) + + +# --------------------------------------------------------------------------- +# the Trainer +# --------------------------------------------------------------------------- + + +class Trainer: + """Micro-step loop, accumulation, gated optimizer step, cadence, resume.""" + + def __init__( + self, + cfg, + model, + sampler, + loss_adapter: LossAdapter, + run_dir: str, + optimizer=None, + scheduler=None, + tracker=None, + stage: str = "sft", + train_module: Optional[TrainModule] = None, + weight_format=None, + allow_resume_mismatch: bool = False, + ): + self.cfg = cfg + self.sampler = sampler + self.stage = stage + + accum = cfg.optimizer.grad_accum + # RULED (team-lead, pre-launch): keyed to `offload_adamw`, because a + # guard must be keyed to the FAILURE IT PREVENTS, not to the + # circumstances that usually accompany it. This rule's failure mode is + # offload amortization -- the measured 2.56s CPU optimizer step and + # 0.82s PCIe transfer that only that optimizer pays. Under adamw8bit + # the state lives on-GPU and that failure mode is ABSENT, so the guard + # is inapplicable rather than weakened. Firing it there would have + # forced two pre-registration edits (global batch size and a halved + # horizon) to satisfy a constraint with nothing behind it. + if ( + cfg.train.full_ft + and cfg.optimizer.name == "offload_adamw" + and accum < MIN_GRAD_ACCUM_FULL_FT + ): + raise ValueError( + f"grad_accum={accum} is below {MIN_GRAD_ACCUM_FULL_FT}, which " + "full-FT with offloaded AdamW requires. Measured on this box: " + "the CPU optimizer step is 2.56s per 1.81B-param rank shard " + "and PCIe transfer is ~0.82s per rank per optimizer step. " + "Amortised over 4 accumulation micro-steps that is 20-30% " + "step-time overhead; at accum 1 it is 50-100% and the run " + "spends more wall-clock moving state than computing. Raise " + "grad_accum, or set train.full_ft=false for a small model. " + "If host RAM forced the adamw8bit fallback, set " + "optimizer.name=adamw8bit -- its state is on-GPU and this " + "rule does not apply to it." + ) + self.accum = accum + #: U01-5: resume refuses a checkpoint whose seed / grad_accum / data fingerprint differ + #: from this run's unless the operator says so (kwarg, or `train.allow_resume_mismatch`). + self.allow_resume_mismatch = bool( + allow_resume_mismatch or getattr(cfg.train, "allow_resume_mismatch", False) + ) + #: U01-1: micro-batches accumulated since the last optimizer boundary, and what became of + #: a partial tail window ({"micros", "action"}), None when the run ended on a boundary. + self._pending_micros = 0 + self.tail_window: Optional[dict] = None + + # THE MID-ACCUMULATION SAVE DEFECT (align port review, 2026-10-12). A + # checkpoint holds weights, optimizer state, schedule and stream offset -- + # NOT the gradients accumulated so far in the current window. A cadence + # that does not land on an optimizer-step boundary therefore saves a + # half-filled window: the resumed run restarts the counter at the saved + # micro_step, applies its first step after only (accum - k) micro-batches + # (each already scaled by 1/accum), and silently trains a different run. + # Measured on the tiny harness (accum 2, save_every 3): max weight + # divergence 3e-3 at lr 1e-3 against the uninterrupted run, no error, no + # metric out of line. The RL stage config already refuses this (its saves + # are weight syncs); the shared Trainer is where SFT/DPO/pretrain need it. + save_every = cfg.train.save_every_micro_steps + if save_every % accum != 0: + raise ValueError( + f"train.save_every_micro_steps={save_every} is not a multiple of " + f"optimizer.grad_accum={accum}: a checkpoint taken mid-accumulation " + "drops the window's accumulated gradients, so a resume from it is " + "NOT lossless. Pick a cadence that lands on an optimizer-step " + f"boundary (e.g. {max(1, save_every // accum) * accum})." + ) + + assert_paths_off_root([run_dir]) + self.run_dir = run_dir + self.ckpt_root = os.path.join(run_dir, "checkpoints") + os.makedirs(self.ckpt_root, exist_ok=True) + self._discard_partials() + + self.stream = ResumableBatchStream(sampler, epochs=cfg.train.epochs) + # The module is the ONLY holder of model/loss/optimizer; the Trainer's + # `model`/`optimizer`/`loss_adapter` attributes below are delegating + # properties, kept assignable because scripts free the optimizer + # before eval (`trainer.optimizer = None`) and tests swap adapters. + self.train_module = train_module or TrainModule( + model=model, + loss_adapter=loss_adapter, + optimizer=optimizer + or make_optimizer(cfg, [p for p in model.parameters() if p.requires_grad]), + grad_accum=accum, + ) + + # U03-2: "micro_mean" (default) is the original loop, untouched. "global_token_mean" buffers + # each accumulation window, all-reduces its target-token count and scales every micro-batch + # by n_micro / N_window. Refuse, at construction, every combination that cannot honour it. + self.loss_normalization = getattr(cfg.train, "loss_normalization", "micro_mean") + if self.loss_normalization not in LOSS_NORMALIZATIONS: + raise ValueError( + f"train.loss_normalization={self.loss_normalization!r}; expected one of {LOSS_NORMALIZATIONS}" + ) + if self.loss_normalization == "global_token_mean": + if type(self.train_module).train_batch is not TrainModule.train_batch: + raise ValueError( + f"train.loss_normalization='global_token_mean' needs the stock TrainModule.train_batch; " + f"{type(self.train_module).__name__} overrides it (RL/PPO/MoE modules own their loss scaling)" + ) + if not callable(getattr(self.train_module.loss_adapter, "count_tokens", None)): + raise ValueError( + "train.loss_normalization='global_token_mean' needs a loss adapter exposing " + "`count_tokens(batch)` (make_sft_loss_adapter provides it)" + ) + self._window_tokens: Optional[int] = None + + # Which converter writes/reads the weight file (align/train/ckpt_format.py). + # Explicit argument > the module's own (an MoE module knows its family) + # > dense from cfg.model, the behaviour every pre-MoE caller has. + self.weight_format = ( + weight_format + or getattr(self.train_module, "weight_format", None) + or DenseFormat(cfg.model) + ) + + self._validate_checkpoint_format() + + total_micro = len(sampler) * cfg.train.epochs + horizon = max(1, math.ceil(total_micro / self.accum)) + self.scheduler = scheduler or WarmupCosineSchedule( + base_lr=cfg.optimizer.lr, total_steps=horizon, warmup_frac=cfg.train.warmup_frac + ) + + self.tracker = tracker or Tracker( + run_dir, stage, mandatory_keys=MANDATORY_METRICS, run_name=cfg.run_name + ) + # Remember what the probe was built on: resume rebuilds it, and it must be + # rebuilt on the SAME view (a PPO run passes an adapter-only view because + # the frozen base can never move), not on the raw model. + self._probe_target = model + self.trunk_probe = TrunkMovementProbe(model) + self.trunk_report: dict = {} + tw = cfg.tripwires + # Only ARMED tripwires are constructed. An unarmed stage does not get + # a guard it cannot feed -- SFT has no preference margin, and arming + # the collapse tripwire there would either halt every run or (the old + # behaviour) quietly feed it NaN forever. + unknown = set(tw.armed) - set(TRIPWIRE_BUILDERS) + if unknown: + raise ValueError( + f"tripwires.armed names {sorted(unknown)}, which the Trainer " + f"cannot build; known: {list(TRIPWIRE_BUILDERS)}" + ) + self.tripwires: dict = {} + if "logps_chosen" in tw.armed: + self.tripwires["logps_chosen"] = LogpsChosenTripwire(window=tw.logps_window) + if "grad_norm" in tw.armed: + self.tripwires["grad_norm"] = GradNormTripwire() + if "length_drift" in tw.armed: + self.tripwires["length_drift"] = LengthDriftTripwire( + baseline=tw.chosen_longer_baseline, + band=tw.length_band, + min_pairs=tw.length_min_pairs, + ) + self.tripwire_alarms: list[dict] = [] + self._tripwire_self_test_done = False + + self.micro_step = 0 + self.optimizer_step = 0 + self._last_applied_lr: Optional[float] = None + #: Applied optimizer steps SINCE the trunk snapshot was taken. Not the + #: same as optimizer_step: after a resume the total is already nonzero + #: while the fresh snapshot has seen no movement yet, and probing on + #: the total would fire on every resumed run. + self._applied_since_snapshot = 0 + self.checkpoints_written: list[int] = [] + #: R5 (2026-08-23 audit): checkpoints pinned against pruning. Only the + #: final two checkpoints of each destroyed phase-1 run survived + #: (keep-2), so nothing from before the instability existed to rewind + #: to. The FIRST fire of any tripwire pins the NEXT save. + self.pinned_checkpoints: set[int] = set() + self._pin_next_save = False + self.step_times: list[float] = [] + self._probe_done = False + + # -- G0 control plane ------------------------------------------------ + tr = cfg.train + self.max_wall_seconds = getattr(tr, "max_wall_seconds", None) + if self.max_wall_seconds is not None and not float(self.max_wall_seconds) > 0: + raise ValueError( + f"train.max_wall_seconds={self.max_wall_seconds!r} must be > 0 (or None to disable)" + ) + self.max_consecutive_skipped = getattr( + tr, "max_consecutive_skipped_steps", DEFAULT_MAX_CONSECUTIVE_SKIPPED_STEPS + ) + self.max_skipped_fraction = getattr(tr, "max_skipped_fraction", DEFAULT_MAX_SKIPPED_FRACTION) + if self.max_consecutive_skipped is not None and int(self.max_consecutive_skipped) < 0: + raise ValueError( + f"train.max_consecutive_skipped_steps={self.max_consecutive_skipped!r} must be >= 0" + ) + if self.max_skipped_fraction is not None and not 0.0 <= float(self.max_skipped_fraction) <= 1.0: + raise ValueError( + f"train.max_skipped_fraction={self.max_skipped_fraction!r} must be in [0, 1]" + ) + self._stop_signals = _StopSignals() + self.stop_reason: Optional[str] = None + self._train_t0: Optional[float] = None + #: On-device OR of "this micro-batch's loss was non-finite" since the + #: last optimizer-step boundary; read once per boundary (one sync). + self._nonfinite_loss_acc: Optional[torch.Tensor] = None + #: Replicated on every rank (updated from reduced values only) and + #: persisted in resume.pt, so a resume does not forgive a bad run. + self.skip_stats = {"consecutive": 0, "bad_total": 0, "boundaries": 0} + + # -- delegation to the TrainModule --------------------------------------- + + @property + def model(self): + return self.train_module.model + + @model.setter + def model(self, value) -> None: + self.train_module.model = value + if value is None: + # U01-11: clearing the model is the post-train handoff; the probe's own references + # (`_probe_target`, `trunk_probe._model`) would otherwise keep the replica alive. + self._drop_probe_refs() + + def _drop_probe_refs(self) -> None: + self._probe_target = None + probe = getattr(self, "trunk_probe", None) + if probe is not None: + probe.release() + + def release(self) -> None: + """Free everything the Trainer holds on the training replica (model, optimizer, probe + snapshots). Call before building the post-train eval model; the Trainer cannot resume or + probe afterwards.""" + self.model = None + self.optimizer = None + self._drop_probe_refs() + + @property + def optimizer(self): + return self.train_module.optimizer + + @optimizer.setter + def optimizer(self, value) -> None: + self.train_module.optimizer = value + + @property + def loss_adapter(self) -> LossAdapter: + return self.train_module.loss_adapter + + @loss_adapter.setter + def loss_adapter(self, value: LossAdapter) -> None: + self.train_module.loss_adapter = value + + # -- the loop ----------------------------------------------------------- + + def train(self) -> dict: + self.stop_reason = None + with self._stop_signals: + self._train_t0 = time.monotonic() + self._train_wall_t0 = time.time() + self._announce_drain(True) + try: + return self._train_loop() + except HaltError as e: + # The verdict must survive the launcher: torchrun exits 1 for + # any worker failure, so the supervisor reads this file instead + # (align.exit_codes). Identical on every rank; rank 0 writes. + self._write_halt_marker(e.exit_code, str(e)) + raise + finally: + self._announce_drain(False) + + def _announce_drain(self, on: bool) -> None: + """Rank 0 tells a supervisor, through `DRAIN_READY.json`, that this + process polls `STOP_REQUEST` at every boundary -- so a stop should be + REQUESTED and waited for rather than signalled and killed (G3 audit + U01-1: a signal stop needs a boundary plus a save, longer than the + launcher's SIGTERM->SIGKILL window). Present only while `train()` runs: + before it there is no boundary to wait for, after it the post-train + eval is not interruptible this way.""" + from ..utils.dist import is_rank0 + + if not is_rank0(): + return + if on: + write_run_marker(self.run_dir, DRAIN_READY_NAME, pid=os.getpid()) + else: + clear_run_marker(self.run_dir, DRAIN_READY_NAME) + + def _stop_requested_by_file(self) -> bool: + """True iff a supervisor's `STOP_REQUEST` written during THIS train() + call exists. Read by rank 0 only (a shared run dir); the boundary + all-reduce spreads it, so a rank with a stale view cannot stop alone. + A request older than this call is a leftover and is ignored.""" + from ..utils.dist import is_rank0 + + if not is_rank0(): + return False + since = getattr(self, "_train_wall_t0", 0.0) + return read_run_marker(self.run_dir, STOP_REQUEST_NAME, since) is not None + + def _write_stop_marker(self) -> None: + """Leave `STOP.json` (code 128+signum) so the supervisor can tell an + operator's stop from a crash: torchrun reports both as exit 1 (G3 + audit U01-2). Written when the stop is AGREED, before the save, so a + launcher that SIGKILLs the save still leaves the verdict.""" + from ..utils.dist import is_rank0 + + if is_rank0(): + code = 128 + int(self._stop_signals.signum or signal.SIGTERM) + write_run_marker( + self.run_dir, STOP_MARKER_NAME, code=code, reason="coordinated stop (signal)" + ) + + def _write_halt_marker(self, code: int, reason: str) -> None: + from ..utils.dist import is_rank0 + + if is_rank0(): + write_halt_marker(self.run_dir, code, reason[:2000]) + + @property + def stop_exit_code(self) -> int: + """The process exit status the stage script should return after `train()`. + + 0 for a run that ended on its own terms (data exhausted, horizon, step + cap). A COORDINATED STOP is not a finished stage: continuing into the + post-train eval/gate of a half-trained model (what the scripts did) + would pass or fail it on weights nobody meant to evaluate. A wall-clock + stop is `EXIT_WALL_BUDGET` (the budget is spent; the supervisor must not + relaunch it); a signal stop is the shell convention 128+signum. + """ + if self.stop_reason == "wall_clock": + return EXIT_WALL_BUDGET + if self.stop_reason == "signal": + return 128 + int(self._stop_signals.signum or signal.SIGTERM) + return 0 + + def _train_loop(self) -> dict: + cfg = self.cfg + limit = cfg.train.max_micro_steps + self.train_module.set_train() + + stop_reason = "data_exhausted" + global_mean = self.loss_normalization == "global_token_mean" + it = iter(self.stream) + lookahead: list = [] # global_token_mean only: the rest of the current window, already pulled + while True: + if lookahead: + batch = lookahead.pop(0) + else: + try: + batch = next(it) + except StopIteration: + break + # THE ZOMBIE-RUN GUARD. Past the scheduler's horizon the cosine + # clamps, and with min_lr_frac=0 it clamps to EXACTLY 0 -- the + # loop then runs forward, backward, step, log and checkpoint on + # frozen weights, with every metric looking normal. DPO Arm A did + # that for 287 optimizer steps (~24 GPU-hours) because nothing + # stopped it. There is no learning left past the horizon by + # construction, so the run ends and says why. + if self.optimizer_step >= self.scheduler.total_steps: + stop_reason = "horizon" + logger.info( + "stopping at the scheduler horizon: %d optimizer steps " + "completed of %d planned. Past this point the cosine " + "schedule clamps the learning rate to %.3g and further " + "steps would not change the weights.", + self.optimizer_step, + self.scheduler.total_steps, + self.scheduler.lr(), + ) + # The batch just pulled is not going to be trained on: give it + # back so the end-of-training checkpoint's stream offset is the + # number of batches TRAINED, not trained + 1. + self.stream.unconsume() + break + + t0 = time.perf_counter() + if global_mean and self.micro_step % self.accum == 0: + # Window start: pull the rest of the window, count its target tokens, reduce over + # ranks. Saves/stops only happen on window boundaries, so the stream being up to + # accum-1 batches ahead mid-window is never observable in a checkpoint. + window = [batch] + while len(window) < self.accum: + try: + window.append(next(it)) + except StopIteration: + break + lookahead = window[1:] + count = self.train_module.loss_adapter.count_tokens + self._window_tokens = reduce_window_tokens(sum(int(count(b)) for b in window)) + self.micro_step += 1 + + if global_mean: + out = self.train_module.train_batch(batch, window_tokens=self._window_tokens) + else: + out = self.train_module.train_batch(batch) + self._note_loss(out.loss) + self._pending_micros += 1 + + stepped = False + stop: Optional[str] = None + if self.micro_step % self.accum == 0: + stepped, stop = self._optimizer_boundary() + # U01-8: the armed grad_norm HALT wire must inspect EVERY optimizer step. `_log` + # feeds it only on logged micros, so with log_every=10 / grad_accum=2 four steps in + # five were never seen. Feed the boundaries `_log` will not cover (a logged boundary + # is fed there, from the same value: one observation per step, never two). + if ( + stepped + and "grad_norm" in self.tripwires + and self.micro_step % cfg.train.log_every_micro_steps != 0 + ): + self._check_tripwires( + {GRAD_NORM_KEY: self.train_module.last_grad_norm}, names=("grad_norm",) + ) + self.step_times.append(time.perf_counter() - t0) + + if self.micro_step % cfg.train.log_every_micro_steps == 0: + self._log(batch, out, stepped) + if self.micro_step % cfg.train.save_every_micro_steps == 0: + self.save_checkpoint() + if stop is not None: + # Before the `limit` test: a stop request must win, because the + # capped-run branch below skips the final save and a SIGTERM + # that discarded the window's work is the failure this prevents. + stop_reason = stop + if stop == "signal": + self._write_stop_marker() + logger.warning( + "coordinated stop (%s) at optimizer step %d (micro %d)", + stop, + self.optimizer_step, + self.micro_step, + ) + break + if limit is not None and self.micro_step >= limit: + stop_reason = "max_micro_steps" + break + + stop_reason = self._finish_partial_window(stop_reason) + + # A COORDINATED STOP always saves: the boundary is the one point where + # the checkpoint is lossless (no half-filled accumulation window), and + # the cadence save may be up to save_every micro-steps away. + if stop_reason in ("signal", "wall_clock"): + self.save_checkpoint() + + # END-OF-TRAINING SAVE. The cadence saves at multiples of save_every; + # an epoch whose total is not divisible leaves the tail only in + # process memory. Stage-11's first full epoch ended at micro 2250 + # with the last save at 2000, then the post-epoch eval crashed -- the + # final 125 optimizer steps existed nowhere on disk. Only for + # uncapped runs: a capped probe must never spend minutes on a 14.5GB + # gather or leave a probe artifact that keep-N pruning could count + # against real checkpoints. + elif limit is None and self.micro_step % cfg.train.save_every_micro_steps != 0: + self.save_checkpoint() + + self.stop_reason = stop_reason + if stop_reason == "wall_clock": + self._write_halt_marker(EXIT_WALL_BUDGET, "train.max_wall_seconds reached; checkpointed") + summary = self.summary() + summary["stop_reason"] = stop_reason + logger.info( + "training finished (%s): %d micro-steps, %d optimizer steps", + stop_reason, + self.micro_step, + self.optimizer_step, + ) + return summary + + # -- G0 control plane ----------------------------------------------------- + + def _finish_partial_window(self, stop_reason: str) -> str: + """U01-1: decide what happens to a PARTIAL accumulation window when the loop ends. + + THE DROPPED-TAIL DEFECT (Codex audit U01-1). `train.epochs * len(sampler)` micro-batches + that are not a multiple of `grad_accum` left the last `< accum` micro-batches accumulated + but never stepped: their .grad stayed on the params (a later forward/eval, or an optimizer + reused after the run, would see it), the scheduler horizon (ceil) planned a step that was + never taken, and nothing recorded the loss. + + End of DATA (`data_exhausted`): the tail is a real, if short, window -- step it, with the + gradient rescaled to a mean over the `k` micro-batches it holds (each was scaled 1/accum), + so the horizon (ceil) is consistent with the steps taken. Under `global_token_mean` the + window is already normalised by its own token count (see `train_batch`), so no rescale. + A module that overrides `train_batch` owns its loss scaling, so the correct factor is + unknown: its tail is DROPPED, loudly, rather than stepped with a wrong scale. Any other + ending (`max_micro_steps` cap) drops the tail the same way. Dropping always zeroes the + grads and records `tail_window` in the summary. + """ + k = int(self._pending_micros) + if k == 0: + return stop_reason + tm = self.train_module + if stop_reason == "data_exhausted": + stock = type(tm).train_batch is TrainModule.train_batch + if stock: + if self.loss_normalization == "micro_mean" and k < self.accum: + factor = float(self.accum) / float(k) + with torch.no_grad(): + for prm in self.model.parameters(): + if prm.grad is not None: + prm.grad.mul_(factor) + logger.warning( + "data exhausted mid-window: stepping the %d-micro-batch tail (grad_accum=%d)", + k, + self.accum, + ) + _stepped, stop = self._optimizer_boundary() + self.tail_window = {"micros": k, "action": "stepped"} + if stop == "signal": + self._write_stop_marker() + if stop is not None: + return stop + return stop_reason + tm.zero_grads() + self._pending_micros = 0 + self._nonfinite_loss_acc = None + self.tail_window = {"micros": k, "action": "dropped"} + logger.warning( + "run ended (%s) with a partial accumulation window of %d micro-batch(es); its gradients " + "were DROPPED and zeroed (recorded in the summary as tail_window)", + stop_reason, + k, + ) + return stop_reason + + def _optimizer_boundary(self) -> tuple[bool, Optional[str]]: + """The optimizer-step boundary: apply the LR, step, advance the schedule, agree on stop/skip. + + Returns (stepped, stop_reason). Shared by the in-loop boundary and the end-of-data tail + window (U01-1) so both take exactly the same path. + """ + self._pending_micros = 0 + # THE UNAPPLIED-SCHEDULE DEFECT (found in the align port, present + # in the legacy trainer too). The scheduler was stepped and its LR + # was LOGGED, but nothing ever wrote it into the optimizer: the + # optimizer was built once with lr=cfg.optimizer.lr, so every + # SFT/DPO/GRPO run trained at a CONSTANT lr (no warmup, no decay) + # while history.jsonl reported a decaying one. Measured on the tiny + # harness: scheduler.lr() 1e-3 -> 7.5e-4 -> 2.5e-4 while + # optimizer.param_groups[0]["lr"] stayed 1e-3. The logged value and + # the applied value must be the same number, so apply it here, + # immediately before the step it governs. Idempotent with modules + # that set their own lr (PPO). + self._apply_scheduled_lr() + skipped_before = self.train_module.skipped_steps + stepped = self.train_module.optim_step() + # A step that was not applied is only a SKIP if the optimizer's + # grad gate said so (its `skipped_steps` counter moved). A + # module may decline to step by design -- PPO's critic-only + # warmup iterations return False every time -- and counting + # those would halt a healthy run on its fourth warmup window. + gate_skipped = self.train_module.skipped_steps > skipped_before + if stepped: + # The schedule counts steps that ACTUALLY happened: a run + # whose grads went non-finite for a stretch must not decay + # its LR on schedule while training nothing. + self.scheduler.step() + self.optimizer_step += 1 + self._applied_since_snapshot += 1 + # ONE reduced decision per optimizer step: stop request, skip + # health. Raises (identically on every rank) past the skip cap. + stop = self._boundary_control(gate_skipped) + return stepped, stop + + def _note_loss(self, loss) -> None: + """Remember, on-device, whether any micro-batch loss in this window was + non-finite. + + THE LOSS-ONLY-NAN BLIND SPOT. The skip gate looks at GRADIENTS. A + non-finite loss whose gradient is finite (a decoupled-backward proxy, a + NaN in a logged-only term) steps happily, and a loss that is NaN every + micro-step looks like a healthy run to the gate. The flag is OR-ed on + the loss's own device and read once per optimizer step, so it costs no + extra host sync per micro-step. + """ + bad = ~torch.isfinite(loss.detach()).all() + acc = self._nonfinite_loss_acc + self._nonfinite_loss_acc = bad if acc is None else (acc | bad) + + def _wall_limit_hit(self) -> bool: + if self.max_wall_seconds is None or self._train_t0 is None: + return False + return (time.monotonic() - self._train_t0) >= float(self.max_wall_seconds) + + def _boundary_control(self, gate_skipped: bool) -> Optional[str]: + """The optimizer-step-boundary agreement. Returns the stop reason or None. + + ONE MAX all-reduce carries four rank-local facts: [signalled, + wall-clock expired, a loss was non-finite, the grad gate skipped the step]. + Every rank therefore sees the same four numbers and takes the same + branch -- the only way "any rank signalled => all stop" can be true + without a rank stopping alone while a peer waits in the next + micro-step's FSDP all-gather. Wall clocks are per-rank, so they are + reduced too: ranks disagree about elapsed time by the skew of their + launch. + + Called only on a boundary, so a stop never lands mid-accumulation (a + checkpoint holds no half-filled gradient window; see __init__). + """ + nonfinite = False + if self._nonfinite_loss_acc is not None: + nonfinite = bool(self._nonfinite_loss_acc) + self._nonfinite_loss_acc = None + sig, wall, nf, gate_skipped = all_reduce_max( + [ + int(self._stop_signals.signum is not None or self._stop_requested_by_file()), + int(self._wall_limit_hit()), + int(nonfinite), + int(gate_skipped), + ] + ) + self._record_step_health(bool(nf), bool(gate_skipped)) + if sig: + return "signal" + if wall: + return "wall_clock" + return None + + def _record_step_health(self, nonfinite_loss: bool, gate_skipped: bool) -> None: + """Count bad optimizer steps; HALT past the consecutive or fractional cap. + + THE SILENT-SKIP RUN. The grad gate skips a non-finite step and trains + on; if the cause is persistent (an overflowing loss scale, a poisoned + shard, an LR that has already blown the weights) it skips FOREVER: + every step "succeeds", the schedule stalls (it counts applied steps), + and the run burns GPU-hours learning nothing. `skipped_steps` was + logged but nothing ever read it. A step is BAD if the grad gate skipped it OR + any of its micro-batch losses was non-finite. The inputs are the + already-reduced flags, so every rank holds identical counters and + raises the identical error with no further collective. + """ + st = self.skip_stats + st["boundaries"] += 1 + if nonfinite_loss or gate_skipped: + st["consecutive"] += 1 + st["bad_total"] += 1 + else: + st["consecutive"] = 0 + cause = ( + "non-finite loss" + (" and skipped step" if gate_skipped else "") + if nonfinite_loss + else "skipped step (non-finite gradient)" + ) + cap = self.max_consecutive_skipped + if cap is not None and st["consecutive"] > int(cap): + self._halt_skip_cap( + f"{st['consecutive']} consecutive bad optimizer steps exceed " + f"train.max_consecutive_skipped_steps={cap} (last cause: {cause})", + cause, + ) + frac = self.max_skipped_fraction + if frac is not None and st["boundaries"] >= SKIP_FRACTION_MIN_STEPS: + observed = st["bad_total"] / st["boundaries"] + if observed > float(frac): + self._halt_skip_cap( + f"{st['bad_total']} of {st['boundaries']} optimizer steps were bad " + f"({observed:.1%}), above train.max_skipped_fraction={frac} " + f"(last cause: {cause})", + cause, + ) + + def _halt_skip_cap(self, detail: str, cause: str) -> None: + self.tripwire_alarms.append( + {"step": self.micro_step, "alarm": "skip_cap", "response": f"HALT: {cause}"} + ) + raise NonFiniteHaltError( + f"HALT skip cap at micro_step {self.micro_step} (optimizer step " + f"{self.optimizer_step}): {detail}. The run is not training: fix the " + "cause (loss scale / LR / data) or raise the cap deliberately; the last " + "good checkpoint is on disk." + ) + + def _agree_or_raise( + self, local_exc: Optional[BaseException], what: str, halt_on_failure: bool = False + ) -> None: + """Make a rank-local failure a GLOBAL one before anyone raises. + + THE LONE-RAISER HANG. A tripwire verdict, the arm-time self-test and the + trunk probe all read rank-local numbers (this rank's data, this rank's + shard). A rank that raises alone unwinds out of the loop while its peers + enter the next micro-step's collective and wait for it -- the process + group does not fail, it blocks until the watchdog fires 30 minutes + later. So: reduce the verdict (MAX) first, every rank at the same + program point, then raise everywhere. + + A `HaltError` is raised IDENTICALLY on every rank, built from the + rank-ordered gather of every failing rank's message. Any other + exception (a KeyError from a missing metric) is re-raised as itself on + the rank that hit it, and peers get a `HaltError` naming it. + + `halt_on_failure=True` (the trunk probe and the arm-time self-test) converts ANY failure + into a `HaltError` on the originating rank too (U01-21): those checks are deterministic, + so a plain exception there was an ordinary crash with no HALT.json -- the supervisor + relaunched a run that would fail identically. + """ + if ( + halt_on_failure + and local_exc is not None + and not isinstance(local_exc, HaltError) + ): + converted = HaltError(f"{what} failed: {type(local_exc).__name__}: {local_exc}") + converted.__cause__ = local_exc + local_exc = converted + if _dist_world_size() == 1: + if local_exc is not None: + raise local_exc + return + from ..utils.dist import any_rank + + if not any_rank(local_exc is not None): + return + # (message, exit code) per rank, so the identical HaltError every rank + # raises carries the SAME exit status: a non-finite verdict on one rank + # must not be reported as a tripwire HALT by its peers. + msgs = all_gather_objects( + None + if local_exc is None + else ( + f"{type(local_exc).__name__}: {local_exc}", + int(getattr(local_exc, "exit_code", EXIT_TRIPWIRE_HALT)), + ) + ) + failed = [(r, m) for r, m in enumerate(msgs) if m is not None] + if local_exc is not None and not isinstance(local_exc, HaltError): + raise local_exc + cls = NonFiniteHaltError if any(c == EXIT_NONFINITE_HALT for _, (_, c) in failed) else HaltError + raise cls( + "; ".join(f"[rank {r}] {m}" for r, (m, _) in failed) + + f" (rank-reduced during {what}: all ranks stop together)" + ) + + def _apply_scheduled_lr(self) -> None: + """Write the scheduler's current LR into every optimizer param group. + + A no-op for an optimizer that exposes no `param_groups` (a test stub); + a real optimizer that does expose them gets the scheduled value. + """ + # Remember the value so the log reports what the step USED. The scheduler + # is stepped right after the optimizer step, so `scheduler.lr()` at log + # time is lr_{k+1} on the micro that applied step k: the log ran one + # schedule step ahead of the optimizer (review finding, low). + lr = self.scheduler.lr() + self._last_applied_lr = lr + opt = self.optimizer + groups = getattr(opt, "param_groups", None) + if not groups: + return + for g in groups: + g["lr"] = lr + + def _log(self, batch, out: LossOutput, stepped: bool) -> None: + metrics = { + "loss": float(out.loss.detach()), + # The lr the optimizer last APPLIED; before the first step (or just + # after a resume) the lr the next step will apply. + "lr": ( + self._last_applied_lr + if getattr(self, "_last_applied_lr", None) is not None + else self.scheduler.lr() + ), + "micro_step": self.micro_step, + "optimizer_step": self.optimizer_step, + # Undefined on a micro-step that did not step, and on a skipped + # step. NaN, never 0.0 -- a 0.0 grad norm reads as 'converged'. + "grad_norm": (self.train_module.last_grad_norm if stepped else NAN), + "batch": list(batch), + "n_tokens": out.n_tokens, + "skipped_steps": self.train_module.skipped_steps, + } + # NOTE: tripwire INPUTS are deliberately NOT seeded here. Seeding + # `margin`/`logps/chosen` with NaN is exactly what disarmed the + # collapse tripwire: it made the key always present and always + # unusable, so the guard ran blind and reported itself armed. The loss + # adapter supplies them when they exist; when it does not, the + # arm-time self-test below halts rather than pretending. + metrics.update(out.metrics) + self.tracker.log(self.micro_step, metrics) + + # Fail fast: the trunk probe runs at the first log step AFTER the + # first APPLIED optimizer step. Not earlier -- before any step lands, + # "the trunk has not moved" is trivially true and the probe would fire + # on every run. Not later: the whole point is to fail before + # GPU-hours accumulate behind a frozen trunk. + if not self._probe_done and self._applied_since_snapshot >= 1: + err = None + try: + self.trunk_report = self.trunk_probe.check(step=self.micro_step) + except Exception as e: # noqa: BLE001 -- re-raised by _agree_or_raise + err = e + self._agree_or_raise(err, "trunk-movement probe", halt_on_failure=True) + self._probe_done = True + + # Arm-time self-test, once, at the first log step: every armed + # tripwire's inputs present and finite, or halt before training + # proceeds. This turns metric-name drift into a launch failure. + if not self._tripwire_self_test_done: + err = None + try: + assert_tripwires_armed(metrics, self.tripwires) + except Exception as e: # noqa: BLE001 -- re-raised by _agree_or_raise + err = e + self._agree_or_raise(err, "tripwire arm-time self-test", halt_on_failure=True) + self._tripwire_self_test_done = True + + self._check_tripwires(metrics) + + def _check_tripwires(self, metrics: dict, names: Optional[tuple] = None) -> None: + """Feed each armed tripwire from the CANONICAL metric keys. + + Reads `metrics[...]` directly and lets a KeyError surface: an armed + tripwire whose input has gone missing mid-run must fail loudly, not + fall back to a default. The arm-time self-test catches this at step + one; this is the backstop if a later adapter stops emitting the key. + """ + halt: Optional[BaseException] = None + for name, wire in self.tripwires.items(): + if names is not None and name not in names: + continue + try: + if name == "logps_chosen": + r = wire.update( + metrics[LOGPS_CHOSEN_KEY], metrics[LENGTHS_CHOSEN_KEY], metrics[MARGIN_KEY] + ) + elif name == "grad_norm": + r = wire.update(metrics[GRAD_NORM_KEY]) + elif name == "length_drift": + # `pairs` is the sample the fraction was computed over: the + # tripwire needs it to know whether it has seen enough to + # speak, and it is a key the DPO adapter already emits. + r = wire.update(metrics["chosen_longer_fraction"], n_pairs=metrics["pairs"]) + else: # pragma: no cover + raise RuntimeError(f"no feed defined for tripwire {name!r}") + except Exception as e: # noqa: BLE001 -- a missing input is a rank-local failure + halt = e + break + if r.tripped: + if not any(a["alarm"] == name for a in self.tripwire_alarms): + # R5: first fire of this wire pins the next checkpoint, so + # an early-stop/rewind decision has somewhere to rewind TO. + self._pin_next_save = True + self.tripwire_alarms.append( + {"step": self.micro_step, "alarm": name, "response": r.response} + ) + if getattr(wire, "HALT", False): + # R3 (2026-08-23 audit): a HALT tripwire stops the run at + # the alarm. The recorded rerun trained 221 optimizer steps + # past a 355,830 grad-norm blow-up because every guard only + # logged; a gradient explosion is a defect, not a metric. + halt = HaltError( + f"HALT tripwire {name!r} fired at micro_step " + f"{self.micro_step}: {r.response} (value={r.value})" + ) + break + # The verdict is rank-local (this rank's data, this rank's shard); + # reducing it is what keeps a rank that raised from leaving its peers + # in the next micro-step's collective. Skipped only when NO tripwire is + # armed -- config-derived, hence the same on every rank. + if self.tripwires: + self._agree_or_raise(halt, "tripwire check") + elif halt is not None: # pragma: no cover -- nothing to feed + raise halt + + def summary(self) -> dict: + return { + "micro_step": self.micro_step, + "optimizer_step": self.optimizer_step, + "skipped_steps": self.train_module.skipped_steps, + "checkpoints_written": list(self.checkpoints_written), + "pinned_checkpoints": sorted(self.pinned_checkpoints), + "trunk_report": self.trunk_report, + "tripwire_alarms": list(self.tripwire_alarms), + "skip_stats": dict(self.skip_stats), + "tail_window": None if self.tail_window is None else dict(self.tail_window), + } + + def throughput_probe(self, tokens_per_step: int) -> dict: + """The probe's report, for the launch banner. + + `self.step_times` holds per-MICRO durations; `tokens_per_step` and + the scheduler horizon are per-OPTIMIZER-step. The aggregation is the + unit conversion (task #25) -- without it the banner over-reported + tokens/s and under-projected wall-clock by ~grad_accum x. + """ + return throughput_report( + step_times_s=aggregate_micro_step_times( + self.step_times[: self.cfg.train.probe_steps], self.accum + ), + tokens_per_step=tokens_per_step, + optimizer_steps_planned=self.scheduler.total_steps, + ) + + # -- checkpointing ------------------------------------------------------ + + def full_state_dict(self): + """The module's unsharded CPU gather; kept on the Trainer because + callers (eval handoff, tests) address the Trainer. Incident history + lives on `TrainModule.full_model_state_dict`.""" + return self.train_module.full_model_state_dict() + + def save_checkpoint(self) -> str: + """Write bf16 weights + resume state, atomically. + + Staged under `.partial` and renamed into place, so a host seizure + mid-write leaves nothing that looks resumable. A half-written + checkpoint is worse than none: it is found, loaded, and trusted. + """ + import torch.distributed as dist + + from ..utils.dist import is_rank0 + + # Idempotent BEFORE the collective: a re-save of an existing + # micro-step (resume that re-reaches an already-saved boundary) must + # neither crash on the rename nor delete a good checkpoint. Checked + # on every rank against the shared FS so all ranks skip together and + # nobody enters the state-gather collective alone. + name = f"micro_{self.micro_step:08d}" + # THE RANK-LOCAL PIN DEFECT (G3 audit U01-3). The flag is raised by a + # tripwire verdict, and logps_chosen / length_drift are fed from THIS + # rank's batch, so it can be set on rank 1 alone -- while pruning and + # resume.pt's pin list are rank 0's. Reduce it (MAX) so every rank pins + # or none does. save_checkpoint is entered by every rank at the same + # micro-step (cadence, coordinated stop, end-of-training), and the + # idempotence check just below is already a collective on this path. + if bool(all_reduce_max([int(self._pin_next_save)])[0]): + self._pin_next_save = True + if self._pin_next_save: + # R5: pinned on EVERY rank and on every save path (fresh, re-save, + # idempotent skip) -- prune consults this set on rank 0 only, but + # the flag must clear everywhere or a resume re-pins arbitrarily. + self.pinned_checkpoints.add(self.micro_step) + self._pin_next_save = False + logger.info("checkpoint %s PINNED (first tripwire fire precedes it)", name) + if self._resave_is_redundant(name): + logger.info("checkpoint %s already exists; skipping re-save", name) + if self.micro_step not in self.checkpoints_written: + self.checkpoints_written.append(self.micro_step) + return os.path.join(self.ckpt_root, name) if is_rank0() else "" + + if self._sharded_checkpoints(): + return self._save_checkpoint_sharded(name) + + # Gathered on EVERY rank (it is a collective); written by rank 0 only. + # The same rename race that killed the gate ledger lives here: four + # ranks renaming one `.partial` directory, first one wins, three die. + state = self.full_state_dict() + + # Optimizer state is SHARD-LOCAL per rank; a resume.pt holding only + # rank 0's moments hands ranks 1..N-1 the wrong slices on resume -- + # plausible training on corrupted state, the exact failure the + # world-size guard names, through a different door. Gather every + # rank's CPU-cloned state to rank 0 over gloo (control plane; NCCL + # would bind this to GPU state). + from ..utils.dist import gloo_group + + opt_sd = self.train_module.optim_state_dict() + from ..utils.dist import barrier + + # Every rank's RNG streams (collective, symmetric, a few KB each); only + # rank 0 writes them. Gathered BEFORE the layout dispatch so both layouts + # share one collective sequence on every rank. + rng_all = all_gather_objects(capture_rng_state()) + tw_all = all_gather_objects(self._tripwire_state()) + + if self._per_rank_optimizer_files(): + return self._save_checkpoint_per_rank(name, state, opt_sd, rng_all, tw_all) + + group = gloo_group() + if group is not None: + per_rank: list = [None] * dist.get_world_size() + dist.gather_object(opt_sd, per_rank if is_rank0() else None, dst=0, group=group) + else: + per_rank = [opt_sd] + + if not is_rank0(): + self.checkpoints_written.append(self.micro_step) + # WAIT for rank 0's write. Without this, peers ran ahead into the + # NEXT training step's FSDP all-gathers while rank 0 spent minutes + # writing 14.5GB; rank 0 could not join and the NCCL watchdog + # SIGABRT'd the run at the micro-300 save (Arm A rerun, + # 2026-08-20). The old no-barrier rationale (rank-0 crash mid-write + # strands peers) still ends the same way -- watchdog kills all -- + # so the barrier costs nothing on the failure path and fixes the + # healthy one. + barrier() + return "" + + final = os.path.join(self.ckpt_root, name) + staging = final + ".partial" + if os.path.isdir(staging): + shutil.rmtree(staging) + os.makedirs(staging, exist_ok=True) + + try: + self.weight_format.save_weights(state, staging, torch.bfloat16) + # HF-layout completeness: the eval stage loads AutoTokenizer from + # the checkpoint dir, and a weights-only dir sent it down the + # slow-tokenizer conversion path (no sentencepiece installed) at + # hour 9 of stage-11. Vocab never changes during full-FT, so the + # pinned snapshot's tokenizer files ARE this checkpoint's. + self._copy_tokenizer(staging, name) + payload = self._resume_payload(rng_all, tw_all) + payload["optimizer_per_rank"] = per_rank + _torch_save_synced(payload, os.path.join(staging, "resume.pt")) + self._write_integrity(staging) + self._publish(staging, final) + except BaseException: + shutil.rmtree(staging, ignore_errors=True) + raise + + # NO BARRIER AFTER THE WRITE, and my own 4-rank test is why. I had one + # here; a rank-0 failure during the write (in that run, a bad optimizer + # stub) meant rank 0 raised BEFORE reaching it while three peers sat in + # it -- a 400-second hang instead of a crash. That is the NCCL-timeout + # shape, produced by a barrier added for safety. + # + self.checkpoints_written.append(self.micro_step) + self._prune_checkpoints() + logger.info("checkpoint written: %s", final) + # Release the peers (see the barrier at the non-rank0 return above: + # both sides of the old barrier argument have now happened in + # production, and the watchdog makes the crash-path cost identical + # either way -- the barrier fixes the healthy path). + from ..utils.dist import barrier + + barrier() + return final + + def _resave_is_redundant(self, name: str) -> bool: + """COLLECTIVE. True iff a COMPLETE `name` is already on disk. + + THE TRUSTED-CORRUPTION DEFECT. "A directory called micro_N exists" was + taken as "micro_N is saved". But `latest_checkpoint` skips a micro_N + that fails `checkpoint_problem` (the host seized after the rename, the + disk filled mid-copy) and resumes from the previous good one -- and the + resumed run then walks back up to N, finds the directory, logs "already + exists" and WRITES NOTHING. The broken directory stays the newest + entry, the weights at N exist nowhere on disk, and (worse) it sits in + `checkpoints_written`, so keep-N pruning counts it as one of the two + kept and deletes the last good one when the next save lands. + + So: an existing directory is reused only if it is complete. A broken one + is moved aside (renamed, never deleted: an operator may want to look at + it; the name no longer matches `micro_*`, so neither resume nor the + supervisor sees it) and the save proceeds. + + The verdict is rank 0's alone, reduced (MAX) to every rank. Deciding + from each rank's own view of the filesystem means a rank that saw the + directory (cached attributes, a node-local disk) skips while a peer + enters the state-gather collective alone, which hangs until the + watchdog -- the lone-rank shape every other decision here avoids. + """ + from ..utils.dist import is_rank0 + + redundant = 0 + final = os.path.join(self.ckpt_root, name) + if is_rank0() and os.path.isdir(final): + problem = checkpoint_problem(final) + if problem is None: + redundant = 1 + else: + aside = os.path.join(self.ckpt_root, f"corrupt_{name}.{int(time.time())}") + logger.warning( + "checkpoint %s exists but is INCOMPLETE (%s): moved to %s and re-saving", + name, + problem, + os.path.basename(aside), + ) + os.rename(final, aside) + _fsync_path(self.ckpt_root) + return bool(all_reduce_max([redundant])[0]) + + def _copy_tokenizer(self, staging: str, name: str) -> None: + """Best-effort by design: weights are the irreplaceable part, and eval + has a snapshot fallback. Loud, never silent. WHICH tokenizer is the + weight format's decision (a dense checkpoint gets the pinned Mistral + files; an OLMoE one only an explicitly configured directory).""" + try: + copied = self.weight_format.copy_tokenizer(self.cfg.paths.model_snapshot, staging) + except (FileNotFoundError, OSError): + copied = [] + if not copied: + logger.warning( + "no tokenizer files copied for checkpoint %s (%s); it is weights-only " + "and eval must fall back to the snapshot", + name, + type(self.weight_format).__name__, + ) + + # -- per-rank optimizer-state files --------------------------------------- + + def _per_rank_optimizer_files(self) -> bool: + """Config flag `train.per_rank_optimizer_state` (default OFF). + + Default mode gathers every rank's optimizer state to rank 0 over gloo: + rank 0 holds the whole thing in host RAM at save time (12 B/param for + fp32 AdamW, 2 B/param under adamw8bit) on a shared box with no swap. + The per-rank mode has each rank write its OWN shard + (`optimizer_rank{r}.pt`) and gathers nothing. Read with getattr so a + config without the field (config.py is another lane's file) means OFF. + """ + return bool(getattr(self.cfg.train, "per_rank_optimizer_state", False)) + + @staticmethod + def _write_integrity(staging: str, opt_shas: Optional[dict] = None, include_weights: bool = True) -> None: + """Record sha256 of the payloads the weights manifest does not cover (U01-3): resume.pt, + the gathered layout's safetensors weights, and (per-rank / sharded layouts) every rank's + optimizer file, whose hashes the ranks gathered. Written LAST, before the publish.""" + sha = {} + for fn in sorted(os.listdir(staging)): + if fn == "resume.pt" or (include_weights and fn.endswith(".safetensors")): + sha[fn] = sharded_ckpt.file_sha256(os.path.join(staging, fn)) + sha.update(opt_shas or {}) + sharded_ckpt.write_integrity(staging, sha) + + def _publish(self, staging: str, final: str) -> None: + """Make `staging` durable, rename it into place, make the rename durable. + + fsync every file and directory under `staging` BEFORE the rename (see + `fsync_tree`), then fsync the checkpoint root so the new directory entry + itself survives a power loss. Order is the whole point. + """ + fsync_tree(staging) + os.rename(staging, final) + _fsync_path(os.path.dirname(final)) + + def _data_fingerprint(self) -> dict: + """What identifies the data this run trains on, as primitives (U01-5). `len(sampler)` and + `epochs` fix the horizon; a sampler may add its own `fingerprint()` (content/order hash).""" + fp: dict = {} + sampler = getattr(self, "sampler", None) + try: + fp["len"] = int(len(sampler)) + except (TypeError, AttributeError): + pass + epochs = getattr(getattr(getattr(self, "cfg", None), "train", None), "epochs", None) + if epochs is not None: + fp["epochs"] = int(epochs) + fn = getattr(sampler, "fingerprint", None) + if callable(fn): + fp["sampler"] = str(fn()) + return fp + + def _tripwire_state(self) -> dict: + """{wire name: its state_dict()} for every armed wire that can persist (U01-6).""" + out = {} + for name, wire in (getattr(self, "tripwires", None) or {}).items(): + fn = getattr(wire, "state_dict", None) + if callable(fn): + out[name] = fn() + return out + + def _resume_payload( + self, rng_per_rank: Optional[list] = None, tripwire_per_rank: Optional[list] = None + ) -> dict: + payload = { + "stream": self.stream.state_dict(), + "scheduler": self.scheduler.state_dict(), + "micro_step": self.micro_step, + "optimizer_step": self.optimizer_step, + "seed": self.cfg.train.seed, + # U01-5: what resume must still agree with. Recorded, never silently assumed. + "grad_accum": getattr(self, "accum", None), + "data_fingerprint": self._data_fingerprint(), + # U01-6: tripwire baselines / latches (rank-ordered, like the RNG streams: logps_chosen + # and length_drift are fed from each rank's own batch). + "tripwire_per_rank": ( + tripwire_per_rank if tripwire_per_rank is not None else [self._tripwire_state()] + ), + # So the logged lr is continuous across a resume (the lr the last + # step used, not the next one). + "last_applied_lr": self._last_applied_lr, + # R5 (the review that found this): the pin set lived only in process + # memory, so a resumed run forgot which checkpoints were pinned and + # the first prune after the resume deleted the one pinned + # checkpoint it had been told to keep. + # `or` tolerates the bare Trainer stubs other lanes' tests call + # `Trainer._resume_payload(stub)` with. + "pinned_checkpoints": sorted(getattr(self, "pinned_checkpoints", None) or ()), + "skip_stats": dict(getattr(self, "skip_stats", None) or {}), + # One entry per rank (rank-ordered): RNG streams are per-rank, and + # rank 0 is the only writer of resume.pt. + "rng_per_rank": ( + rng_per_rank if rng_per_rank is not None else [capture_rng_state()] + ), + } + # Generic extension slot: modules with loop-external resumable state + # (tripwire windows, a latest-weights pointer) expose extra_state(). + fn = getattr(self.train_module, "extra_state", None) + if fn is not None: + payload["extra_state"] = fn() + # Sampler-owned state. The stream's (epoch, offset) is enough for a + # sampler whose order is a pure function of (seed, epoch); a sampler + # whose position depends on what happened at run time (GRPO's prompt + # cursor advances on every dead-group retry) must carry its own. + sfn = getattr(self.sampler, "state_dict", None) + if callable(sfn): + payload["sampler_state"] = sfn() + return payload + + def _save_checkpoint_per_rank(self, name: str, state, opt_sd, rng_all=None, tw_all=None) -> str: + """Barriered, atomic per-rank save. Every rank runs this in lockstep. + + Protocol (barrier count identical on all ranks, so none can strand): + rank 0 makes a clean `.partial` dir -> B1 -> every rank writes its own + `optimizer_rank{r}.pt` via tmp + os.replace (a rank removes ONLY its + own tmp/final file on failure) -> B2 -> rank 0 writes weights and + resume.pt (which records the world size: the manifest), renames the + dir, prunes -> B3. A rank that dies before its write leaves B2 + unreached on its peers, and the rename never happens: the checkpoint + does not exist rather than existing incomplete. + """ + import torch.distributed as dist # noqa: F401 (symmetry with the default path) + + from ..utils.dist import barrier, is_rank0, rank as _rank, world_size as _world + + final = os.path.join(self.ckpt_root, name) + staging = final + ".partial" + if is_rank0(): + if os.path.isdir(staging): + shutil.rmtree(staging) + os.makedirs(staging, exist_ok=True) + barrier() + + mine = os.path.join(staging, f"optimizer_rank{_rank()}.pt") + tmp = mine + ".tmp" + try: + _torch_save_synced(opt_sd, tmp) + os.replace(tmp, mine) + my_sha = {os.path.basename(mine): sharded_ckpt.file_sha256(mine)} + except BaseException: + for f in (tmp, mine): + try: + os.remove(f) + except OSError: + pass + raise + barrier() + opt_shas: dict = {} + for d in all_gather_objects(my_sha): + opt_shas.update(d) + + if not is_rank0(): + self.checkpoints_written.append(self.micro_step) + barrier() + return "" + + try: + self.weight_format.save_weights(state, staging, torch.bfloat16) + self._copy_tokenizer(staging, name) + payload = self._resume_payload(rng_all, tw_all) + payload["optimizer_state"] = {"layout": "per_rank_files", "world_size": _world()} + _torch_save_synced(payload, os.path.join(staging, "resume.pt")) + self._write_integrity(staging, opt_shas) + self._publish(staging, final) + except BaseException: + shutil.rmtree(staging, ignore_errors=True) + raise + self.checkpoints_written.append(self.micro_step) + self._prune_checkpoints() + logger.info("checkpoint written (per-rank optimizer files): %s", final) + barrier() + return final + + # -- sharded checkpoints (train.checkpoint_format = "sharded") ------------- + + def _sharded_checkpoints(self) -> bool: + """Config flag `train.checkpoint_format == "sharded"` (default "gathered"). + Read with getattr so a config without the field means gathered.""" + return getattr(self.cfg.train, "checkpoint_format", "gathered") == "sharded" + + def _module_has_sharded_hooks(self) -> bool: + tm = self.train_module + return callable(getattr(tm, "sharded_model_state", None)) and callable( + getattr(tm, "load_sharded_model_state", None) + ) + + def _validate_checkpoint_format(self) -> None: + """Fail at CONSTRUCTION, not at the first save an hour in. + + THE MERGED-NAME DEFECT this prevents: a module that overrides + `full_model_state_dict` (LoRA folds the adapter into merged weights; PPO + has its own gather) defines what "the weights" mean. The base-class + sharded path reads `model.state_dict()` directly, so it would write the + UNMERGED base under the checkpoint's usual name and a resume/eval would + load a model without the adapter -- no error, a worse model. Such a + module must provide `sharded_model_state()` / `load_sharded_model_state()` + or it cannot use the sharded format. + """ + fmt = getattr(self.cfg.train, "checkpoint_format", "gathered") + if fmt not in sharded_ckpt.CHECKPOINT_FORMATS: + raise ValueError( + f"train.checkpoint_format={fmt!r}; expected one of {sharded_ckpt.CHECKPOINT_FORMATS}" + ) + if fmt != "sharded": + return + tm = self.train_module + plain = ( + type(tm).full_model_state_dict is TrainModule.full_model_state_dict + and type(tm).load_model_state_dict is TrainModule.load_model_state_dict + ) + if not plain: + # MoETrainModule overrides both methods, but without expert + # parallelism they are `super()` calls verbatim -- and that is the + # OLMoE case this format was built for (Track M). WITH ep_groups the + # experts live in EP groups, not in the FSDP shards, and the + # state-dict methods do real work: refused. + try: + from .moe_module import MoETrainModule + + plain = ( + isinstance(tm, MoETrainModule) + and getattr(tm, "ep_groups", None) is None + and type(tm).full_model_state_dict is MoETrainModule.full_model_state_dict + and type(tm).load_model_state_dict is MoETrainModule.load_model_state_dict + ) + except ImportError: + plain = False + if not (plain or self._module_has_sharded_hooks()): + raise ValueError( + f"train.checkpoint_format='sharded' with {type(tm).__name__}, which overrides the " + "weight state-dict methods (merged/adapter weights) and provides no " + "sharded_model_state()/load_sharded_model_state(): the sharded path would checkpoint " + "the unmerged base. Use checkpoint_format='gathered' or add the two hooks." + ) + + def _sharded_state(self): + fn = getattr(self.train_module, "sharded_model_state", None) + return fn() if callable(fn) and self._module_has_sharded_hooks() else self.train_module.model.state_dict() + + def _save_checkpoint_sharded(self, name: str) -> str: + """COLLECTIVE. Every rank writes its own shards; nothing is gathered. + + Protocol (every rank runs it; the collective sequence is identical): + rng all-gather -> rank 0 makes a clean `.partial` -> B1 -> each rank + writes `model_rank{r}.safetensors` + `optimizer_rank{r}.pt` (tmp + + fsync + rename) -> any-rank-failed reduction (a full disk on ONE rank + stops every rank now instead of stranding peers in the next gather) -> + all-gather of the per-rank infos -> rank 0 writes manifest, tokenizer, + resume.pt, fsync_tree + rename, prune -> any-rank-failed reduction + (doubles as the closing sync; rank-0 failure raises everywhere). + The peers' wait is the slowest rank's own 1/N write, not rank 0 writing + 14.5 GB while three ranks idle. + """ + from ..utils.dist import barrier, is_rank0, rank as _rank, world_size as _world + + final = os.path.join(self.ckpt_root, name) + staging = final + ".partial" + rng_all = all_gather_objects(capture_rng_state()) + tw_all = all_gather_objects(self._tripwire_state()) + opt_sd = self.train_module.optim_state_dict() + if is_rank0(): + if os.path.isdir(staging): + shutil.rmtree(staging) + os.makedirs(staging, exist_ok=True) + barrier() + + info, err, my_sha = None, None, {} + mine = os.path.join(staging, f"optimizer_rank{_rank()}.pt") + try: + info = sharded_ckpt.save_rank_shard( + self._sharded_state(), staging, rank=_rank(), world_size=_world() + ) + _torch_save_synced(opt_sd, mine + ".tmp") + os.replace(mine + ".tmp", mine) + my_sha = {os.path.basename(mine): sharded_ckpt.file_sha256(mine)} + except BaseException as e: # noqa: BLE001 -- stay in lockstep with the peers, then re-raise + err = e + for f in (mine + ".tmp", mine): + try: + os.remove(f) + except OSError: + pass + if any_rank(err is not None): + if is_rank0(): + shutil.rmtree(staging, ignore_errors=True) + if err is not None: + raise err + raise sharded_ckpt.ShardedCheckpointError( + f"a peer rank failed writing its shard of {name}; checkpoint abandoned" + ) + infos = all_gather_objects(info) + opt_shas: dict = {} + for d in all_gather_objects(my_sha): + opt_shas.update(d) + + err = None + if is_rank0(): + try: + fmt = sharded_ckpt.describe_weight_format(self.weight_format) + manifest = sharded_ckpt.build_manifest( + infos, + # The OPTIMIZER's slot order, not the model's: the optimizer is built over + # `p.requires_grad` params only (Trainer default, qwen3/olmoe/grpo launchers), + # so with a frozen parameter every slot index after it points one name + # earlier in the full list. `reshard` then refused (or, for same-shape + # neighbours, re-cut the wrong tensor's moments under the wrong name). + param_order=[ + n for n, p in self.train_module.model.named_parameters() if p.requires_grad + ], + export=fmt, + ) + sharded_ckpt.write_manifest(staging, manifest) + self._copy_tokenizer(staging, name) + payload = self._resume_payload(rng_all, tw_all) + payload["optimizer_state"] = {"layout": "per_rank_files", "world_size": _world()} + _torch_save_synced(payload, os.path.join(staging, "resume.pt")) + self._write_integrity(staging, opt_shas, include_weights=False) + self._publish(staging, final) + except BaseException as e: # noqa: BLE001 + err = e + shutil.rmtree(staging, ignore_errors=True) + if any_rank(err is not None): + if err is not None: + raise err + raise sharded_ckpt.ShardedCheckpointError(f"rank 0 failed publishing {name}; checkpoint abandoned") + self.checkpoints_written.append(self.micro_step) + if is_rank0(): + self._prune_checkpoints() + logger.info("checkpoint written (sharded, %d rank files): %s", _world(), final) + return final + return "" + + def _load_sharded_weights(self, path: str) -> None: + """COLLECTIVE. Each rank reads ONLY its own shard file. + + Rank-local verdicts (manifest/world size are identical everywhere, but a + sha256 mismatch or a truncated file is one rank's alone) are reduced + before any weight is copied, so a bad shard on rank 2 stops all four + ranks with the same error instead of leaving three of them in the next + collective. + """ + from ..utils.dist import rank as _rank, world_size as _world + + err = None + try: + m = sharded_ckpt.read_manifest(path) + sharded_ckpt.check_world_size(path, m, _world()) + bad = sharded_ckpt.verify_rank_file(path, _rank()) + if bad: + raise sharded_ckpt.ShardedCheckpointError(bad) + except BaseException as e: # noqa: BLE001 + err = e + if any_rank(err is not None): + if err is not None: + raise err + raise sharded_ckpt.ShardedCheckpointError( + f"a peer rank cannot load its shard of {path}; resume abandoned" + ) + if m.get("resharded_from"): + logger.warning( + "checkpoint %s was RESHARDED from world_size=%s: weights and optimizer are exact, but " + "data-order position and RNG streams follow the old partitioning", + path, + m["resharded_from"].get("world_size"), + ) + # THE LONE-READER DEFECT. The pre-checks above are deterministic across ranks; the reads + # below are not (EIO / a stale NFS handle on ONE rank's file, an OOM-killed page-in). That + # rank would raise while its peers moved on to the optimizer load and then into the first + # training collective, where they wait for the watchdog (30 minutes) instead of crashing + # with the cause. Same reduction as the save side: every rank stops together. + err = None + try: + loader = getattr(self.train_module, "load_sharded_model_state", None) + if callable(loader) and self._module_has_sharded_hooks(): + loader(path, rank=_rank(), world_size=_world()) + else: + n = sharded_ckpt.load_rank_shard( + self.train_module.model.state_dict(), path, rank=_rank(), world_size=_world() + ) + logger.info("loaded %d local shards from %s", n, m["files"][str(_rank())]["name"]) + except BaseException as e: # noqa: BLE001 -- stay in lockstep with the peers, then re-raise + err = e + if any_rank(err is not None): + if err is not None: + raise err + raise sharded_ckpt.ShardedCheckpointError( + f"a peer rank failed reading its shard of {path}; resume abandoned" + ) + + def _prune_checkpoints(self) -> None: + # Prune ONLY checkpoints THIS trainer wrote. Name-sorting the whole + # dir let a previous run's stale higher-numbered dirs shadow the live + # run's fresh saves: keep-2 kept the zombies and DELETED the new + # micro_00000100/200 (Arm A rerun, 2026-08-20). Stale dirs are a + # launch-hygiene problem, not this function's to silently absorb. + keep = self.cfg.train.keep_checkpoints + # R5: pinned checkpoints are outside the keep-N budget entirely. + prunable = set(self.checkpoints_written) - self.pinned_checkpoints + mine = sorted(f"micro_{m:08d}" for m in prunable) + for stale in mine[:-keep] if keep > 0 else mine: + shutil.rmtree(os.path.join(self.ckpt_root, stale), ignore_errors=True) + + def _older_checkpoint_steps(self, below: int) -> list[int]: + """Micro-steps of the `micro_NNNNNNNN` directories on disk strictly below `below` (no partials).""" + if not os.path.isdir(self.ckpt_root): + return [] + out = [] + for d in os.listdir(self.ckpt_root): + m = re.fullmatch(r"micro_(\d{8})", d) + if m and int(m.group(1)) < below: + out.append(int(m.group(1))) + return sorted(out) + + def _discard_partials(self) -> None: + """Delete leftover partials at startup. They masquerade as resumable.""" + if not os.path.isdir(self.ckpt_root): + return + for entry in os.listdir(self.ckpt_root): + if entry.endswith(".partial"): + shutil.rmtree(os.path.join(self.ckpt_root, entry), ignore_errors=True) + logger.warning("discarded partial checkpoint %s", entry) + + def latest_checkpoint(self) -> Optional[str]: + """The newest COMPLETE checkpoint directory, or None. + + THE FOUND-LOADED-AND-TRUSTED DEFECT. Name order alone picked the highest + `micro_N` -- including one whose rename survived a host seizure but + whose data did not (zero-length weights, a cut resume.pt, a missing + optimizer shard). Resume then died in the middle of a 13GB load, or + worse, resumed from a partial state. Each candidate passes + `checkpoint_problem` first; an incomplete one is SKIPPED WITH A WARNING + and left on disk (an operator may want to inspect or repair it; deleting + evidence is not this function's job) and the next-newest is tried. + """ + if not os.path.isdir(self.ckpt_root): + return None + dirs = sorted( + ( + d + for d in os.listdir(self.ckpt_root) + if d.startswith("micro_") and not d.endswith(".partial") + ), + reverse=True, + ) + for d in dirs: + path = os.path.join(self.ckpt_root, d) + problem = checkpoint_problem(path) + if problem is None: + return path + logger.warning( + "skipping INCOMPLETE checkpoint %s: %s (left on disk, not deleted)", d, problem + ) + return None + + def resume_from_latest(self) -> Optional[str]: + path = self.latest_checkpoint() + if path is None: + logger.info("no checkpoint to resume from; starting fresh") + return None + self.resume_from(path) + return path + + def _verify_payload_integrity(self, path: str) -> None: + """COLLECTIVE. sha256-verify the payloads this rank is about to read (U01-3). + + Rank 0 checks the shared files (resume.pt and, for the gathered layout, the weights); every + rank checks its own `optimizer_rank{r}.pt`. The verdicts are reduced before anyone raises, + so a bad file on one rank stops all ranks together instead of stranding the peers in the + next collective. A checkpoint with NO `integrity.json` predates the sidecar: it loads with + a warning. A sidecar that exists and disagrees never loads. + """ + from ..utils.dist import is_rank0, rank as _rank + + recorded = None + problem: Optional[str] = None + try: + recorded = sharded_ckpt.read_integrity(path) + if recorded is not None: + names = [f"optimizer_rank{_rank()}.pt"] + if is_rank0(): + names += [ + n + for n in recorded + if n == "resume.pt" or (n.endswith(".safetensors") and not n.startswith("model_rank")) + ] + problem = sharded_ckpt.verify_integrity(path, names, recorded) + except sharded_ckpt.CheckpointIntegrityError as e: + problem = str(e) + if recorded is None and problem is None: + logger.warning( + "checkpoint %s has no integrity.json (it predates payload hashing): resume.pt and " + "the optimizer files are NOT sha256-verified", + path, + ) + if any_rank(problem is not None): + if problem is not None: + raise sharded_ckpt.CheckpointIntegrityError( + f"checkpoint {path} failed its sha256 integrity check: {problem}" + ) + raise sharded_ckpt.CheckpointIntegrityError( + f"checkpoint {path}: a peer rank failed its sha256 integrity check" + ) + + def _check_resume_compat(self, state: dict, path: str) -> None: + """Refuse a resume whose seed / grad_accum / data fingerprint differ from the saved run (U01-5). + + A stateless sampler's order is a pure function of (seed, epoch, data), so changing any of + them resumes at a stream offset that now means a different batch: weights, optimizer and + schedule all load cleanly and nothing looks wrong. A field the checkpoint does not record + (it predates this check) is warned about, never refused. `allow_resume_mismatch` is the + explicit operator override; it logs what it overrode. + """ + diffs: list[str] = [] + missing: list[str] = [] + if "seed" in state: + if int(state["seed"]) != int(self.cfg.train.seed): + diffs.append(f"seed {state['seed']} -> {self.cfg.train.seed}") + else: + missing.append("seed") + if state.get("grad_accum") is not None: + if int(state["grad_accum"]) != int(self.accum): + diffs.append(f"grad_accum {state['grad_accum']} -> {self.accum}") + else: + missing.append("grad_accum") + saved_fp = state.get("data_fingerprint") + if isinstance(saved_fp, dict): + now_fp = self._data_fingerprint() + for k in sorted(set(saved_fp) & set(now_fp)): + if saved_fp[k] != now_fp[k]: + diffs.append(f"data fingerprint {k} {saved_fp[k]!r} -> {now_fp[k]!r}") + else: + missing.append("data fingerprint") + if missing: + logger.warning( + "checkpoint %s predates resume-compatibility recording (%s): cannot check them", + path, + ", ".join(missing), + ) + if not diffs: + return + msg = ( + f"checkpoint {path} was saved under a different configuration than this run: " + + "; ".join(diffs) + + ". The stream offset, schedule and optimizer state would be applied to a different " + "run with no error. Resume with the original seed / grad_accum / data, or pass " + "allow_resume_mismatch=True (train.allow_resume_mismatch) to override deliberately." + ) + if not self.allow_resume_mismatch: + raise RuntimeError(msg) + logger.warning("OVERRIDDEN (allow_resume_mismatch): %s", msg) + + def _restore_tripwire_state(self, state: dict, path: str) -> None: + """Restore tripwire baselines / latches (U01-6). Absent in older checkpoints: warn.""" + from ..utils.dist import rank as _rank + + if not self.tripwires: + return + per_rank = state.get("tripwire_per_rank") + if per_rank is None: + logger.warning( + "checkpoint %s predates tripwire-state persistence: tripwire baselines restart", path + ) + return + if len(per_rank) != _dist_world_size(): + logger.warning( + "checkpoint %s holds tripwire state for %d rank(s) but this run has %d: " + "tripwire baselines restart", + path, + len(per_rank), + _dist_world_size(), + ) + return + for name, sd in per_rank[_rank()].items(): + wire = self.tripwires.get(name) + loader = getattr(wire, "load_state_dict", None) + if not callable(loader): + continue + try: + loader(sd) + except Exception as e: # noqa: BLE001 -- a wire whose layout changed restarts, loudly + logger.warning("tripwire %r state in %s could not be restored (%s: %s)", name, path, type(e).__name__, e) + + def resume_from(self, path: str) -> None: + """Restore weights, then optimizer, then loop state. + + Order matters: the optimizer's fp32 master is the AUTHORITATIVE weight + copy, so it is loaded after the bf16 weights and overwrites them. That + is what makes a bf16-weights-only checkpoint a lossless resume. + """ + + self._verify_payload_integrity(path) + if sharded_ckpt.is_sharded(path): + # Self-describing, like per_rank_files: the directory's manifest, not + # the current flag, decides how weights are read. + self._load_sharded_weights(path) + else: + nmo_state = self.weight_format.load_weights(path) + # The CPU-slice per-tensor load (and its OOM incident history) lives + # on the module; the Trainer only sequences it against the rest of + # the resume payload below. + self.train_module.load_model_state_dict(nmo_state) + + # weights_only=True: a checkpoint is a file on disk, and the resume + # payload is only tensors, dicts, lists and primitives. Unpickling + # arbitrary objects to reload our own state would be a code-execution + # path we do not need. + # map_location="cpu": legacy resume.pt files carry cuda:0 tensors, + # and letting torch.load restore device puts every rank's copy on + # GPU 0 (the tail-resume OOM). Loading lands on CPU; the optimizer's + # own load_state_dict moves state to each param's device. + state = torch.load(os.path.join(path, "resume.pt"), weights_only=True, map_location="cpu") + from ..utils.dist import rank as _rank + + self._check_resume_compat(state, path) + per_rank = state.get("optimizer_per_rank") + layout = state.get("optimizer_state") + if layout is not None and layout.get("layout") == "per_rank_files": + # The checkpoint is self-describing: its manifest, not the current + # flag, decides how to read it. Shards are rank-local slices, so a + # different rank count would hand rank r a slice cut for another + # partitioning -- plausible training on wrong state. Refuse. + from ..utils.dist import world_size as _world + + saved_w = int(layout["world_size"]) + if saved_w != _world(): + raise RuntimeError( + f"checkpoint {path} holds per-rank optimizer state for " + f"world_size={saved_w}, but this run has world_size={_world()}. " + "Per-rank shards cannot be re-sharded; resume with the same " + "number of ranks." + ) + f = os.path.join(path, f"optimizer_rank{_rank()}.pt") + if not os.path.isfile(f): + raise FileNotFoundError(f"per-rank optimizer file missing: {f}") + self.train_module.load_optim_state_dict( + torch.load(f, weights_only=True, map_location="cpu") + ) + elif per_rank is not None: + # THE SILENT-SHARD DEFECT (gather layout). The per-rank-FILES + # layout records its world size and refuses a mismatch; this + # layout recorded nothing, so a 2-rank resume of a 4-rank save + # quietly handed ranks 0/1 the first two shards of a four-way + # partitioning (and a 4-rank resume of a 2-rank save died with an + # IndexError on ranks 2/3 only, leaving ranks 0/1 in the next + # collective). The list's length IS the saved world size. + if len(per_rank) != _dist_world_size(): + raise RuntimeError( + f"checkpoint {path} holds optimizer state for {len(per_rank)} rank(s), " + f"but this run has world_size={_dist_world_size()}. Per-rank optimizer " + "shards cannot be re-sharded; resume with the same number of ranks." + ) + self.train_module.load_optim_state_dict(per_rank[_rank()]) + else: + # Pre-fix checkpoint: only rank 0's shard-local moments were ever + # persisted; the other ranks' are gone. Loading rank 0's into + # every rank would be silently wrong state, so ALL ranks resume + # with FRESH moments -- consistent, honest, and recorded. Weights, + # schedule and stream position remain exact. + logger.warning( + "LEGACY resume.pt (%s) has no per-rank optimizer state; " + "resuming with FRESH optimizer moments on all ranks. This is " + "a recorded deviation, not a lossless resume.", + path, + ) + # U01-2: fresh MOMENTS are the recorded deviation; fresh MASTERS would be a silent weight + # revert (the optimizer's fp32 master is authoritative and is still the launch weights). + if self.train_module.reseed_optimizer_from_params(): + logger.warning( + "re-seeded the optimizer's fp32 master weights from the restored parameters" + ) + if "extra_state" in state: + loader = getattr(self.train_module, "load_extra_state", None) + if loader is None: + logger.warning("checkpoint carries extra_state but the module cannot load it") + else: + loader(state["extra_state"]) + self._restore_tripwire_state(state, path) + sampler_loader = getattr(self.sampler, "load_state_dict", None) + if callable(sampler_loader): + if "sampler_state" not in state: + # Strict on purpose: a stateful sampler resumed without its + # state restarts its data order from the beginning. Weights, + # optimizer and schedule would all be exact, so nothing would + # look wrong -- the run would just train on the wrong data. + raise RuntimeError( + f"checkpoint {path} carries no sampler state, but this run's " + f"sampler ({type(self.sampler).__name__}) keeps run-time " + "position. Resuming would replay its data from the start. " + "The checkpoint predates sampler-state persistence; start " + "the stage fresh or resume from a newer checkpoint." + ) + sampler_loader(state["sampler_state"]) + elif "sampler_state" in state: + raise RuntimeError( + f"checkpoint {path} carries sampler state but this run's sampler " + f"({type(self.sampler).__name__}) cannot load it: the data " + "source changed between save and resume." + ) + self._last_applied_lr = state.get("last_applied_lr") + # Absent in checkpoints that predate G0: leave the in-memory defaults. + if "pinned_checkpoints" in state: + self.pinned_checkpoints = {int(m) for m in state["pinned_checkpoints"]} + if "skip_stats" in state: + self.skip_stats = {k: int(v) for k, v in state["skip_stats"].items()} + self._nonfinite_loss_acc = None + self.scheduler.load_state_dict(state["scheduler"]) + self.stream.load_state_dict(state["stream"]) + self.micro_step = int(state["micro_step"]) + self.optimizer_step = int(state["optimizer_step"]) + # `checkpoints_written` is a PER-PROCESS list: a fresh process starts + # with it empty. Two consumers key off it, and both read an empty list + # as "nothing has ever been saved": + # * the launch scripts' `_latest_weights` (rollout engine weights): + # after a resume the first rollout was generated by the SFT + # SUBSTRATE -- the policy before every update -- while the trainer + # computed ratios against the resumed policy; + # * keep-N pruning: the resumed checkpoint was invisible to it, so it + # was never pruned and `keep_checkpoints` was exceeded by one for + # the rest of the run (13.5GB each). + # The checkpoint we just resumed from IS the newest one on disk by + # construction (resume_from_latest picks it; an explicit older path is + # the operator's call), so register it. Idempotent: a re-resume or an + # idempotent re-save must not list one micro-step twice. + if self.micro_step not in self.checkpoints_written: + self.checkpoints_written.append(self.micro_step) + # PREDECESSORS TOO (Track M, 2026-10-12: the SIGTERM-resumed OLMoE run left micro_40, _44 and _80 on + # disk = 83GB with keep_checkpoints=2, on a disk that is 95% full). The interrupted attempt wrote + # micro_40 and micro_44; the new process knew only 44, so after saving 80 the list was [44, 80] and 40 + # could never be pruned -- one leaked checkpoint per resume. Directories NUMBERED BELOW the one we + # resumed from are this lineage's older saves; adopting them is what keep-N means. Directories numbered + # ABOVE it are deliberately NOT adopted: those are the stale-run zombies `_prune_checkpoints` was + # written to ignore (a higher-numbered zombie shadowing a fresh save). + # OLDEST FIRST: consumers read `checkpoints_written[-1]` as "the newest save" (scripts/ppo.py + # `_latest_weights` hands it to the rollout engine), so the adopted predecessors go in FRONT of the + # resumed checkpoint, never after it. + adopted = [m for m in self._older_checkpoint_steps(self.micro_step) if m not in self.checkpoints_written] + self.checkpoints_written[:0] = adopted + # The trunk snapshot must be retaken: comparing post-resume parameters + # against a pre-resume snapshot would report movement that the resumed + # run did not produce. + self.trunk_probe = TrunkMovementProbe(self._probe_target if self._probe_target is not None else self.model) + self._probe_done = False + self._applied_since_snapshot = 0 + # Last: nothing above may draw from an RNG after this point, or the + # restored stream would already be advanced. + rng = state.get("rng_per_rank") + if rng is None: + logger.warning( + "checkpoint %s predates RNG persistence: RNG streams restart from the seed", path + ) + elif len(rng) != _dist_world_size(): + logger.warning( + "checkpoint %s holds RNG state for %d rank(s) but this run has %d: " + "RNG streams restart from the seed", + path, + len(rng), + _dist_world_size(), + ) + else: + restore_rng_state(rng[_rank()]) + logger.info( + "resumed from %s at micro_step %d (optimizer_step %d)", + path, + self.micro_step, + self.optimizer_step, + ) diff --git a/code/align/utils/__init__.py b/code/align/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/code/align/utils/dist.py b/code/align/utils/dist.py new file mode 100644 index 0000000000000000000000000000000000000000..82c3b0caa6196312e8aaae8bab0c6f5a93af4c42 --- /dev/null +++ b/code/align/utils/dist.py @@ -0,0 +1,391 @@ +"""Thin distributed helpers -- env-var based so they work before +init_process_group, plus the seeded-determinism policy and the +wait-condition helper. + +No framework: torchrun sets RANK/WORLD_SIZE/LOCAL_RANK; we read them. +""" + +from __future__ import annotations + +import os +import random + + +def rank() -> int: + return int(os.environ.get("RANK", "0")) + + +def local_rank() -> int: + return int(os.environ.get("LOCAL_RANK", "0")) + + +def world_size() -> int: + return int(os.environ.get("WORLD_SIZE", "1")) + + +def is_rank0() -> bool: + return rank() == 0 + + +#: Default collective timeout. torch's own default is 10 min for NCCL (30 min +#: for gloo), which is shorter than a 14.5GB checkpoint write on this box +#: while peers wait in the post-save barrier; 30 min is long enough for that +#: and short enough that a genuinely wedged rank is reported in the same +#: sitting rather than after the 5-hour stall of the 2026-08-12 incident. +DEFAULT_PG_TIMEOUT_S = 1800.0 + +PG_TIMEOUT_ENV = "ALIGN_PG_TIMEOUT_S" + + +def pg_timeout_s(environ=None) -> float: + """The process-group timeout in seconds: `ALIGN_PG_TIMEOUT_S` or 30 min. + + Parsed strictly. A typo ("30m") that silently fell back to the default + would leave an operator believing a 60-second watchdog was armed; a + non-positive value would make every collective time out instantly (or, + in torch, mean "no timeout"). Both raise instead. + """ + environ = os.environ if environ is None else environ + raw = environ.get(PG_TIMEOUT_ENV) + if raw is None or raw.strip() == "": + return DEFAULT_PG_TIMEOUT_S + try: + val = float(raw) + except ValueError: + raise ValueError(f"{PG_TIMEOUT_ENV}={raw!r} is not a number of seconds") from None + if not (val > 0.0) or val == float("inf"): + raise ValueError(f"{PG_TIMEOUT_ENV}={raw!r} must be a finite number of seconds > 0") + return val + + +#: The timeout `init_distributed` armed the default process group with. The +#: gloo CONTROL group (`gloo_group`) must use the same number -- see there. +_armed_timeout_s: float | None = None + + +#: The flight-recorder buffer-size variable was renamed TORCH_NCCL_TRACE_BUFFER_SIZE -> +#: TORCH_FR_BUFFER_SIZE when the recorder moved out of ProcessGroupNCCL (torch 2.11: +#: FlightRecorder.hpp:111 looks up {"TORCH_FR_BUFFER_SIZE", "TORCH_NCCL_TRACE_BUFFER_SIZE"} +#: in that order). Both are read by 2.11; only the new one is the supported name. +_FR_BUFFER_NEW = "TORCH_FR_BUFFER_SIZE" +_FR_BUFFER_LEGACY = "TORCH_NCCL_TRACE_BUFFER_SIZE" +_FR_RENAME_VERSION = (2, 11) + + +def _torch_version_tuple(version: str | None = None) -> tuple[int, int]: + """(major, minor) of the installed torch, or of an explicit version string.""" + import re + + if version is None: + import torch + + version = torch.__version__ + m = re.match(r"^(\d+)\.(\d+)", str(version)) + if not m: + raise ValueError(f"cannot parse a torch version from {version!r}") + return int(m.group(1)), int(m.group(2)) + + +def configure_nccl_diagnostics( + run_dir: str | None = None, environ=None, torch_version: str | None = None +) -> dict: + """Turn the PyTorch NCCL flight recorder on, with its dump under the run dir. + + Must run BEFORE `init_process_group`: the recorder and the watchdog read + these variables when the NCCL process group is constructed. Defaults only + (`setdefault`): an operator's explicit export always wins. Returns what it + set, for the launch banner. + + Variable names verified against the installed torch 2.11.0 (headers under + torch/include/torch/csrc/distributed/c10d/ and the strings in + libtorch_cpu.so / libtorch_cuda.so): + + * TORCH_FR_BUFFER_SIZE (torch >= 2.11, FlightRecorder.hpp:111) or, below 2.11, + TORCH_NCCL_TRACE_BUFFER_SIZE (ProcessGroupNCCL.hpp:114; still read as the + fallback alias on 2.11). Ring-buffer entries; + the 2.11 default is 2000, which one FSDP2 step with 32 layers can wrap, so we + ask for 20000. >0 enables the recorder. + * TORCH_NCCL_DUMP_ON_TIMEOUT (ProcessGroupNCCL.hpp:73). Dump the buffer when + the watchdog times out. Per the header it must be set together with + TORCH_NCCL_ENABLE_MONITORING=1 and a buffer size > 0; we do NOT set the + monitoring variable (its abort-on-stuck-heartbeat side effect is a separate + decision) and have not re-verified its 2.11 default, so on a build where it + is off the dump is simply not triggered. + * TORCH_FR_DUMP_TEMP_FILE (new name) / TORCH_NCCL_DEBUG_INFO_TEMP_FILE (legacy + name; both strings present in libtorch_cpu.so, neither in a header because the + dump writer is compiled). The value is a FILE PREFIX; torch appends the + global rank. Without it the dump goes to /tmp/nccl_trace_rank_, which this + box forbids (/tmp is noexec and not durable). We set both names so either + generation of the reader finds it. + + `run_dir=None` falls back to `/nccl_trace` rather than the /tmp default. + + THE DEPRECATED-NAME DEFECT (H2 review, 2026-10-13): on torch >= 2.11 the buffer + size is `TORCH_FR_BUFFER_SIZE`; the old `TORCH_NCCL_TRACE_BUFFER_SIZE` is only a + fallback alias, so exporting it alone arms the recorder through a name the + next release is free to drop -- and the recorder going dark is invisible until + the hang it was meant to explain. The legacy name is set ONLY below 2.11, where + it is the only one the build knows. An operator's explicit export of EITHER name + wins: the new name outranks the old in torch's lookup, so setting it over an + operator's legacy export would silently override their value. + """ + environ = os.environ if environ is None else environ + new_torch = _torch_version_tuple(torch_version) >= _FR_RENAME_VERSION + buffer_name = _FR_BUFFER_NEW if new_torch else _FR_BUFFER_LEGACY + operator_set_buffer = _FR_BUFFER_NEW in environ or _FR_BUFFER_LEGACY in environ + trace_dir = os.path.join(run_dir or os.getcwd(), "nccl_trace") + os.makedirs(trace_dir, exist_ok=True) + prefix = os.path.join(trace_dir, "rank_") + wanted = { + buffer_name: "20000", + "TORCH_NCCL_DUMP_ON_TIMEOUT": "1", + "TORCH_FR_DUMP_TEMP_FILE": prefix, + "TORCH_NCCL_DEBUG_INFO_TEMP_FILE": prefix, + } + applied = {} + for k, v in wanted.items(): + if k == buffer_name and operator_set_buffer: + continue + if k not in environ: + environ[k] = v + applied[k] = v + return applied + + +def init_distributed( + backend: str = "nccl", run_dir: str | None = None, timeout_s: float | None = None +) -> None: + """Idempotent process-group init for torchrun launches; no-op on a + single process. + + Always passes an EXPLICIT timeout (`ALIGN_PG_TIMEOUT_S`, default 30 min) + instead of inheriting torch's backend-dependent default, and, for NCCL, + arms the flight recorder first (see `configure_nccl_diagnostics`) so a hang + leaves a per-rank trace of the last collectives instead of only a + watchdog SIGABRT. + """ + if world_size() == 1: + return + import datetime + + import torch.distributed as dist + + if not dist.is_initialized(): + if backend == "nccl": + configure_nccl_diagnostics(run_dir) + global _armed_timeout_s + t = pg_timeout_s() if timeout_s is None else float(timeout_s) + _armed_timeout_s = t + dist.init_process_group(backend=backend, timeout=datetime.timedelta(seconds=t)) + import torch + + # Only NCCL needs a device bound per rank; a gloo group on a box whose + # GPUs are hidden (the CPU test children) must not touch CUDA. + if backend == "nccl" and torch.cuda.is_available(): + torch.cuda.set_device(local_rank()) + + +def barrier() -> None: + """No-op-safe barrier: single process or uninitialized group passes.""" + if world_size() == 1: + return + import torch.distributed as dist + + if dist.is_initialized(): + dist.barrier() + + +def seed_everything(seed: int, rank_offset: bool = True) -> int: + """The seeded-determinism policy. + + `rank_offset=True` gives each rank a distinct-but-derived stream + (seed + rank) -- required for dataloader shuffling; checkpoint-resume + tests (section-07) and crosscoder streaming (section-08) rely on this + exact derivation to reproduce batch order after a restart. + """ + s = seed + (rank() if rank_offset else 0) + random.seed(s) + try: + import numpy as np + + np.random.seed(s % 2**32) + except ImportError: + pass + import sys + + if "torch" in sys.modules: # never import torch just to seed it + import torch + + torch.manual_seed(s) + return s + + +def find_pids(interpreter_substr: str, script_path: str, exclude_self: bool = True) -> list[int]: + """Find processes by INTERPRETER + FULL SCRIPT PATH, never bare name. + + Incident: a stage-4 launcher waited on `pgrep -f `, matched + its own command line, and idled 4 GPUs for 3 hours. Matching both the + interpreter and the absolute script path (and excluding ourselves and + our parent shell) cannot self-match. + """ + me = os.getpid() + parent = os.getppid() + hits = [] + for pid_dir in os.listdir("/proc"): + if not pid_dir.isdigit(): + continue + pid = int(pid_dir) + if exclude_self and pid in (me, parent): + continue + try: + with open(f"/proc/{pid}/cmdline", "rb") as f: + argv = f.read().decode(errors="replace").split("\0") + except OSError: + continue + if len(argv) < 2: + continue + if interpreter_substr in os.path.basename(argv[0]) and any(a == script_path for a in argv): + hits.append(pid) + return hits + + +def gloo_group(): + """Cached CPU-side subgroup for object collectives and control-plane + gathers. None on a single process. gloo, never NCCL: object collectives + stage through pickled CPU tensors, and NCCL binds them to GPU state that + the control plane must not depend on. + + THE UNARMED-WATCHDOG DEFECT. `dist.new_group(backend="gloo")` with no + `timeout` does NOT inherit the default group's timeout: torch fills in its + own per-backend default (`_get_default_timeout`, 30 min for gloo) whatever + `init_process_group` was given. Every stop / HALT / skip-cap decision and + every checkpoint gather runs on THIS group, so an operator who exported + `ALIGN_PG_TIMEOUT_S=120` to be told about a wedged rank within two minutes + still waited 30 on the optimizer-step boundary all-reduce -- the exact + shape of the 2026-08-12 stall, behind a knob that read as armed. The group + is therefore built with the timeout `init_distributed` armed the default + group with (or, when a caller initialised the group itself, the env value). + """ + import datetime + + import torch.distributed as dist + + if world_size() == 1 or not dist.is_initialized(): + return None + g = getattr(gloo_group, "_group", None) + if g is None: + t = _armed_timeout_s if _armed_timeout_s is not None else pg_timeout_s() + g = dist.new_group(backend="gloo", timeout=datetime.timedelta(seconds=t)) + gloo_group._group = g + return g + + +def all_reduce_max(values: list[int]) -> list[int]: + """Element-wise MAX of a short int vector across ranks, on the gloo group. + + The control-plane primitive: "did ANY rank ...?" decisions (stop signal, + wall-clock, HALT, bad step) are made by reducing a 0/1 flag with MAX so that + every rank acts on the same answer at the same program point. gloo, not + NCCL, for the same reason as `gloo_group` -- and so a decision never + queues behind (or deadlocks with) in-flight CUDA collectives. A single + process returns the input unchanged. + """ + import torch + import torch.distributed as dist + + g = gloo_group() + if g is None: + return [int(v) for v in values] + t = torch.tensor([int(v) for v in values], dtype=torch.int64) + dist.all_reduce(t, op=dist.ReduceOp.MAX, group=g) + return [int(v) for v in t.tolist()] + + +def any_rank(flag: bool) -> bool: + """True iff `flag` is True on at least one rank (identical on all ranks).""" + return bool(all_reduce_max([1 if flag else 0])[0]) + + +def all_gather_objects(obj) -> list: + """`obj` from every rank, rank-ordered, on the gloo group ([obj] on one process).""" + import torch.distributed as dist + + g = gloo_group() + if g is None: + return [obj] + out: list = [None] * dist.get_world_size() + dist.all_gather_object(out, obj, group=g) + return out + + +def capture_rng_state() -> dict: + """This process's RNG state: torch CPU, torch CUDA (current device only), + python `random`, numpy. Every leaf is a tensor, list, int, float, str or + None, because `resume.pt` is read back with `weights_only=True`. + + WHY. `seed_everything` seeds the streams at launch, but a resumed process + re-seeds from scratch and so replays the first draws of the original run: + dropout masks, sampling noise and any shuffle that is not a pure function + of (seed, epoch) restart instead of continuing. The run is then not the run + its uninterrupted twin would have been. State is per rank (the streams are + seeded seed + rank). + + CUDA: only the CURRENT device, and only if CUDA is already initialised. + `torch.cuda.get_rng_state_all()` would create a context on every visible + GPU from every rank -- under torchrun that is world_size x n_gpus contexts + on a box with 23GB cards. + """ + import torch + + py = random.getstate() + out: dict = { + "torch": torch.get_rng_state(), + "python": [py[0], list(py[1]), py[2]], + } + try: + import numpy as np + + ns = np.random.get_state() + out["numpy"] = { + "name": str(ns[0]), + "keys": [int(k) for k in ns[1]], + "pos": int(ns[2]), + "has_gauss": int(ns[3]), + "cached_gaussian": float(ns[4]), + } + except ImportError: # pragma: no cover -- numpy is a hard dependency + pass + if torch.cuda.is_available() and torch.cuda.is_initialized(): + dev = torch.cuda.current_device() + out["cuda"] = {str(dev): torch.cuda.get_rng_state(dev)} + return out + + +def restore_rng_state(sd: dict) -> None: + """Inverse of `capture_rng_state`. Missing sections are skipped (an older + checkpoint or a CPU-only save resumed on GPU).""" + import torch + + if "python" in sd: + ver, keys, gauss = sd["python"] + random.setstate((int(ver), tuple(int(k) for k in keys), gauss)) + if "numpy" in sd: + import numpy as np + + n = sd["numpy"] + np.random.set_state( + ( + n["name"], + np.array(n["keys"], dtype=np.uint32), + int(n["pos"]), + int(n["has_gauss"]), + float(n["cached_gaussian"]), + ) + ) + if "torch" in sd: + torch.set_rng_state(sd["torch"].cpu()) + if "cuda" in sd and torch.cuda.is_available(): + for idx, state in sd["cuda"].items(): + if int(idx) < torch.cuda.device_count(): + # lazily applied if CUDA is not initialised yet + torch.cuda.set_rng_state(state.cpu(), device=int(idx)) diff --git a/code/align/utils/guard.py b/code/align/utils/guard.py new file mode 100644 index 0000000000000000000000000000000000000000..31aa13acafc607237542c44eabcac4c931b522a3 --- /dev/null +++ b/code/align/utils/guard.py @@ -0,0 +1,664 @@ +"""Resource guards. Import and call BEFORE torch, in every single script. + +Each rule corresponds to a way this specific box has already been made to +fall over: + + * / has ~13GB free (and /home lives on it). A default HF cache or TMPDIR + fills it and then EVERY process on the machine starts failing. /tmp is + additionally noexec here, and it is tmpfs -- a different device from '/', + which is why the path assertion requires the /apps device specifically + rather than merely "not the root device". + * 186GB RAM, NO SWAP. 2026-08-12: two external jobs grew to ~59GB RSS each, + free memory fell to 2GB, ~23 processes wedged in D-state, load hit 619, + a 13.5GB checkpoint stalled at 1.9GB, and NCCL timed out after 5 hours, + killing a healthy run. Same day, a 12-worker data build against a live + 4-rank run exhausted /dev/shm and killed it via SIGBUS. + * 4x A10G at 23GB. Two 7B models on one device is an OOM, not a tight fit. + * 48 shared cores; unbounded OMP threads starve the dataloaders. + +Lockfile-inode discipline: the heavy-job lockfile is NEVER deleted, by any +code path, ever. flock binds to the INODE -- deleting the file lets a second +job lock a fresh inode while the first still "holds" the old one, and both +run. Staleness is handled by flock's automatic release on process death. +A grep-level regression test enforces this. +""" + +from __future__ import annotations + +import logging +import os +import shutil +import subprocess +from dataclasses import dataclass +from typing import Iterable + +from ..exit_codes import PreflightRefused + +logger = logging.getLogger(__name__) + +# Absolute paths, verified on this box. Never relative, never $HOME, never /tmp. +APPS_ROOT = "/apps" +PROJECT_ROOT = "/apps/development/rlhf/align" +HF_HOME = "/apps/voxtral/.cache/huggingface" # already holds Mistral-7B-v0.3 +HF_HUB_CACHE = "/apps/voxtral/.cache/huggingface/hub" + +MIN_FREE_DISK_GB = 40.0 + +#: Launch-time host-pressure floor. NOTE: for full-FT stages this alone is +#: INSUFFICIENT -- offloaded optimizer state arrives over the first optimizer +#: steps, after launch checks pass. Those stages must also call +#: preflight_rss(cfg), which requires MemAvailable >= projected RSS + this. +MIN_AVAILABLE_RAM_GB = 45.0 +#: 2026-10-15 incident: the old 2.0 allowed load 96 on 48 cores (~200% oversubscribed); unbounded cargo/lake +#: builds then drove the host to 100% CPU and down. 0.75/core matches hostguard's 70% start line. +MAX_LOAD_PER_CORE = 0.75 +#: Host-wide busy CPU %% above which a heavy job refuses to start (align/utils/hostguard.py Policy.start_cpu_max). +MAX_START_CPU_PCT = 70.0 +MAX_DISK_IN_FLIGHT = 64 + +#: Only one heavy align job at a time. Held for the process lifetime; released +#: by the kernel on process death. See module docstring: never deleted. +LOCK_PATH = f"{PROJECT_ROOT}/.align_heavy_job.lock" +_lock_handle = None + +# RSS-projection constants with provenance. These are the ONLY hardcoded +# numbers in the projection; everything param-sized derives from the config. +#: Python + CUDA host-side allocations + NCCL buffers per rank process, +#: observed ~4GB/rank on the predecessor's 4-rank 7B FSDP runs. +PER_RANK_FIXED_OVERHEAD_GB = 4.0 +#: Dataloader allowance per rank at the mandated <=2 workers with +#: memory-mapped shards (workers touch pages, they do not copy shards). +DATALOADER_ALLOWANCE_GB_PER_RANK = 1.5 +#: adamw8bit state layout, restated (this module must import before torch, so +#: it cannot import `align.train.adamw8bit`): two uint8 code arrays (2 B/param) +#: plus two fp32 absmax arrays per block (8 B / block). tests/test_guards.py +#: pins these against `adamw8bit.DEFAULT_BLOCK_SIZE` so they cannot drift. +ADAMW8BIT_BLOCK_SIZE = 2048 +#: Host-RAM multiple of the TOTAL optimizer-state bytes that a checkpoint save +#: transiently holds. gather mode (default): every rank's CPU clone (1x summed +#: over ranks) + the pickle copy each rank makes for `gather_object` (1x) + the +#: unpickled copy on rank 0 (1x) = 3x. per-rank-file mode: the CPU clone only +#: (torch.save streams to the file) = 1x. An ESTIMATE from the code path, not a +#: measurement -- no 7B save has been run on this tree. +CKPT_GATHER_TRANSIENT_FACTOR = 3.0 +CKPT_PER_RANK_TRANSIENT_FACTOR = 1.0 + + +def apply_resource_guards( + cpu_threads: int = 8, + niceness: int = 5, + min_free_disk_gb: float = MIN_FREE_DISK_GB, + heavy: bool = False, + label: str = "job", + strict_host_check: bool = True, + rss_cfg=None, +) -> None: + """Set every environment variable that must be set before `import torch`, + then ASSERT the resolved paths landed on /apps. + + `expandable_segments` matters more than it looks: alternating generation + (many small KV allocations) and training (few huge activation blocks) + fragments the caching allocator badly enough to OOM with gigabytes + nominally free. + + Pass `rss_cfg` (a RunConfig) for full-FT stages to run the RSS-aware + preflight in addition to the generic host check. + """ + os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True") + + # Keep all caches on /apps. + os.environ.setdefault("HF_HOME", HF_HOME) + os.environ.setdefault("HF_HUB_CACHE", HF_HUB_CACHE) + os.environ.setdefault("HF_HUB_DISABLE_XET", "1") + os.environ.setdefault("TMPDIR", f"{PROJECT_ROOT}/.tmp") + os.environ.setdefault("TRITON_CACHE_DIR", f"{PROJECT_ROOT}/.cache/triton") + os.environ.setdefault("XDG_CACHE_HOME", f"{PROJECT_ROOT}/.cache") + + # Assert the RESOLVED values, not the intended defaults: setdefault keeps + # a pre-set TMPDIR=/tmp, and only this assertion catches it -- at launch, + # not mid-run when the root filesystem fills. + writable = [ + os.environ[k] + for k in ( + "TMPDIR", + "TRITON_CACHE_DIR", + "XDG_CACHE_HOME", + "HF_HOME", + "HF_HUB_CACHE", + ) + ] + assert_paths_off_root(writable) + + # Bound CPU parallelism: default OMP is one thread per core, and on 48 + # shared cores the main process fights its own dataloaders. + for var in ( + "OMP_NUM_THREADS", + "MKL_NUM_THREADS", + "OPENBLAS_NUM_THREADS", + "NUMEXPR_NUM_THREADS", + ): + os.environ.setdefault(var, str(cpu_threads)) + + # Tokenizers' Rust parallelism deadlocks after fork in dataloader workers. + os.environ.setdefault("TOKENIZERS_PARALLELISM", "false") + + try: + os.nice(niceness) + except OSError: + pass + + _check_disk(min_free_disk_gb) + + # `heavy=True` for anything that loads a 7B model, spawns workers, or + # writes multi-GB checkpoints -- but NEVER inside a multiprocessing + # child. `spawn` re-imports the entry script in every worker; a child + # that re-runs this call tries to take the EXCLUSIVE lock its parent + # holds, dies on BlockingIOError, and the pool silently breaks (the + # predecessor then trained for hours against a dead verifier). The lock + # and host checks are properties of the JOB; only the process that IS + # the job takes them. + if heavy and _in_multiprocessing_child(): + heavy = False + logger.debug("multiprocessing child: heavy-job guards not applicable") + if heavy: + preflight_host_check(strict=strict_host_check) + if rss_cfg is not None: + preflight_rss(rss_cfg) + acquire_heavy_job_lock(label) + + logger.info( + "resource guards applied (threads=%d nice=+%d heavy=%s alloc=%s)", + cpu_threads, + niceness, + heavy, + os.environ["PYTORCH_CUDA_ALLOC_CONF"], + ) + + +def assert_paths_off_root(paths: Iterable[str]) -> None: + """Assert every path stat-resolves onto the /apps device. + + Stronger than "not the root device": on this box /tmp is tmpfs and /home + sits on its own mapping, so a device-inequality check against '/' alone + would wrongly accept both. The only durable, large filesystem here is + /apps; everything writable must land on it. Fail at launch, not mid-run. + """ + apps_dev = os.stat(APPS_ROOT).st_dev + root_dev = os.stat("/").st_dev + for p in paths: + os.makedirs(p, exist_ok=True) + dev = os.stat(p).st_dev + if dev == root_dev or dev != apps_dev: + raise RuntimeError( + f"writable path {p!r} resolves to device {dev}, not the " + f"/apps device {apps_dev}. / has ~13GB free and /tmp is a " + "noexec tmpfs; a cache or TMPDIR off /apps takes down the " + "whole box. Fix the environment before launch." + ) + logger.info("path policy ok: %d writable paths on /apps", len(list(paths))) + + +# --------------------------------------------------------------------------- +# RSS-aware preflight (review C2) +# --------------------------------------------------------------------------- + + +def projected_full_ft_rss_gb(cfg) -> dict: + """Project host RSS for a full-FT job FROM THE CONFIG, never hardcoded. + + Components: + * offloaded optimizer state: 2 x fp32 moments = 8 bytes/param, only + when optimizer == offload_adamw (adamw8bit keeps state on GPU); + * fp32 master params: 4 bytes/param when offloading; + * pinned staging: <= cfg.train.pinned_staging_shards_per_rank + layer-shards per rank x world_size, at fp32 layer-shard size; + * fixed per-rank overhead + dataloader allowance (module constants, + provenance documented at their definition). + + For 7.25B offloaded this projects ~105GB -- which is why the generic + 45GB launch floor alone would re-create the 2026-08-12 crash shape. + + adamw8bit (the optimizer every shipped full-FT config names) keeps its + state ON the device: zero host optimizer RSS, so `total_gb` is just the + per-rank overhead. Two numbers the steady-state total cannot show are + reported separately: + * `device_optimizer_state_gb_per_rank`: the on-GPU budget + ((2 + 8/block) B/param over the rank's 1/world slice); + * `checkpoint_save_transient_gb`: the host RAM a SAVE transiently holds + (CKPT_*_FACTOR x total state; per-rank-file mode is 3x smaller than the + rank-0 gather). `peak_gb` = total + transient, and `preflight_rss` + gates on the PEAK -- a save is exactly when the box has been wedged. + For offload_adamw the transient is NOT modelled (it was not before this + change either; that config cannot launch 7.25B/4 ranks anyway), so there + peak == total. + """ + n = float(cfg.model.n_params) + gib = 2.0**30 + offloading = cfg.optimizer.name == "offload_adamw" + on_device_8bit = cfg.optimizer.name == "adamw8bit" + + optimizer_state_gb = (n * 8.0 / gib) if offloading else 0.0 + master_params_gb = (n * 4.0 / gib) if offloading else 0.0 + + world = cfg.train.world_size + layer_shard_gb = n / cfg.model.n_layers / world * 4.0 / gib + staging_cap = cfg.train.pinned_staging_shards_per_rank + pinned_staging_gb = (layer_shard_gb * staging_cap * world) if offloading else 0.0 + + per_rank_overhead_gb = (PER_RANK_FIXED_OVERHEAD_GB + DATALOADER_ALLOWANCE_GB_PER_RANK) * world + + total = optimizer_state_gb + master_params_gb + pinned_staging_gb + per_rank_overhead_gb + + state_8bit_gb = n * (2.0 + 8.0 / ADAMW8BIT_BLOCK_SIZE) / gib if on_device_8bit else 0.0 + device_state_per_rank_gb = state_8bit_gb / world + per_rank_files = bool(getattr(cfg.train, "per_rank_optimizer_state", False)) + factor = CKPT_PER_RANK_TRANSIENT_FACTOR if per_rank_files else CKPT_GATHER_TRANSIENT_FACTOR + ckpt_transient_gb = state_8bit_gb * factor + return { + "optimizer_state_gb": round(optimizer_state_gb, 2), + "master_params_gb": round(master_params_gb, 2), + "pinned_staging_gb": round(pinned_staging_gb, 2), + "per_rank_overhead_gb": round(per_rank_overhead_gb, 2), + "total_gb": round(total, 2), + "device_optimizer_state_gb_per_rank": round(device_state_per_rank_gb, 2), + "checkpoint_save_transient_gb": round(ckpt_transient_gb, 2), + "peak_gb": round(total + ckpt_transient_gb, 2), + } + + +def preflight_rss(cfg, headroom_gb: float = 45.0) -> dict: + """Refuse to start when MemAvailable < projected job RSS + headroom. + + The generic 45GB launch floor is INSUFFICIENT for this job class: the + offloaded optimizer state arrives over the first optimizer steps, AFTER + launch checks would have passed. This is the guard that closes that gap. + It gates on `peak_gb` (steady state + the checkpoint-save transient), not + `total_gb`: for adamw8bit the steady-state host footprint is just the + per-rank overhead and the save is the only thing that can push the box over. + Returns the projection breakdown for the launch banner. + """ + proj = projected_full_ft_rss_gb(cfg) + st = host_state() + required = proj["peak_gb"] + headroom_gb + if st["ram_available_gb"] < required: + raise PreflightRefused( + f"RSS preflight FAILED: MemAvailable {st['ram_available_gb']:.1f}GB " + f"< projected job peak RSS {proj['peak_gb']:.1f}GB + {headroom_gb:.0f}GB " + f"headroom = {required:.1f}GB. Breakdown: {proj}. This box has no " + "swap; the offloaded state lands after launch and would wedge the " + "host mid-run. Wait for the host to quiesce or use adamw8bit. Under " + "adamw8bit the PEAK is a checkpoint save: set " + "train.per_rank_optimizer_state = true to cut the save transient " + "3x (per-rank files instead of a rank-0 gather)." + ) + logger.info( + "RSS preflight ok: %.0fGB available >= %.0fGB required (%s)", + st["ram_available_gb"], + required, + proj, + ) + return proj + + +def _in_multiprocessing_child() -> bool: + """Are we executing inside a multiprocessing worker (or its import of us)? + + Three signals, because they become true at different moments and the one + that matters is the EARLIEST. During `spawn`, CPython's `spawn._main` -> + `prepare()` marks the current process `_inheriting` BEFORE re-importing + the parent's `__main__`; `parent_process()` only attaches later in + `_bootstrap`. Module-level code in the re-imported entry script therefore + runs while `parent_process()` is still None -- checking that alone misses + exactly the case this exists for. + """ + import multiprocessing as mp + + cur = mp.current_process() + if getattr(cur, "_inheriting", False): # mid-`spawn` re-import + return True + if cur.name != "MainProcess": # named worker + return True + return mp.parent_process() is not None # fully bootstrapped child + + +def _check_disk(min_free_gb: float) -> None: + free_gb = shutil.disk_usage(APPS_ROOT).free / 2**30 + if free_gb < min_free_gb: + raise PreflightRefused( + f"/apps has only {free_gb:.1f}GB free (need >= {min_free_gb}GB). " + "Refusing to start: a run that fills the disk corrupts its own " + "checkpoints. Free space or lower min_free_disk_gb deliberately." + ) + logger.info("disk ok: /apps has %.1fGB free", free_gb) + + +# --------------------------------------------------------------------------- +# Host-pressure preflight +# --------------------------------------------------------------------------- + + +def host_state() -> dict: + """Snapshot the shared-machine conditions that decide whether to start.""" + mem: dict[str, float] = {} + with open("/proc/meminfo") as f: + for line in f: + k, _, v = line.partition(":") + mem[k] = float(v.split()[0]) / 1024**2 # kB -> GiB + load1, load5, load15 = os.getloadavg() + n_cores = os.cpu_count() or 1 + + in_flight = 0 + try: + with open("/proc/diskstats") as f: + for line in f: + p = line.split() + if len(p) > 11 and p[2] == "nvme2n1": + in_flight = int(p[11]) + break + except OSError: + pass + + d_state = 0 + try: + out = subprocess.run( + ["ps", "-eo", "stat"], capture_output=True, text=True, timeout=15 + ).stdout + d_state = sum(1 for ln in out.splitlines() if ln.strip().startswith("D")) + except Exception: + pass + + return { + "ram_total_gb": mem.get("MemTotal", 0.0), + "ram_available_gb": mem.get("MemAvailable", 0.0), + "swap_total_gb": mem.get("SwapTotal", 0.0), + "load1": load1, + "load5": load5, + "n_cores": n_cores, + "load_per_core": load1 / n_cores, + "disk_in_flight": in_flight, + "d_state_procs": d_state, + } + + +def preflight_host_check( + min_available_ram_gb: float = MIN_AVAILABLE_RAM_GB, + max_load_per_core: float = MAX_LOAD_PER_CORE, + max_disk_in_flight: int = MAX_DISK_IN_FLIGHT, + strict: bool = True, +) -> dict: + """Refuse to start a heavy job on an already-stressed shared machine. + + This is the guard that did not exist on 2026-08-12. Each threshold maps + to one observed symptom of that incident. Failing loudly here costs + seconds; not failing cost a 5-hour stall, a corrupted checkpoint, and a + dead run. + """ + st = host_state() + problems = [] + + if st["ram_available_gb"] < min_available_ram_gb: + problems.append( + f"only {st['ram_available_gb']:.1f}GB RAM available " + f"(need >= {min_available_ram_gb:.0f}GB). This box has " + f"{st['swap_total_gb']:.0f}GB swap, so there is NO overflow: " + "exhausting RAM wedges the whole machine in D-state." + ) + if st["load_per_core"] > max_load_per_core: + problems.append( + f"load average {st['load1']:.1f} over {st['n_cores']} cores " + f"= {st['load_per_core']:.1f}x (max {max_load_per_core}). The host " + "is already oversubscribed; adding ranks makes it worse for " + "everyone and will not run faster." + ) + from align.utils import hostguard as _hg + cpu_pct = _hg.cpu_percent(1.0) + st["cpu_pct"] = cpu_pct + if cpu_pct > MAX_START_CPU_PCT: + problems.append(f"host CPU {cpu_pct:.0f}% busy (max {MAX_START_CPU_PCT:.0f}% at start; the watchdog freezes " + "our jobs at 92%).") + st["in_align_slice"] = _hg.in_slice() + if not st["in_align_slice"] and os.environ.get("ALIGN_ALLOW_UNSCOPED") != "1": + problems.append("not running inside align.slice: launch through `scripts/hostguard.py run -- ` so the " + "kernel caps CPU / memory for this job and every child (set ALIGN_ALLOW_UNSCOPED=1 only for tests).") + if st["disk_in_flight"] > max_disk_in_flight: + problems.append( + f"disk queue depth {st['disk_in_flight']} (max {max_disk_in_flight}). " + "Writeback is not keeping up; a multi-GB checkpoint write would " + "stall mid-file and can take the run down with an NCCL timeout." + ) + + if problems: + msg = ( + "host preflight FAILED -- refusing to start:\n - " + + "\n - ".join(problems) + + "\n\nWait for the host to quiesce, or pass strict=False " + "deliberately if you accept the risk." + ) + if strict: + raise PreflightRefused(msg) + logger.warning(msg) + else: + logger.info( + "host ok: %.0fGB RAM avail, load %.1f (%.2fx/core), disk q=%d", + st["ram_available_gb"], + st["load1"], + st["load_per_core"], + st["disk_in_flight"], + ) + return st + + +def acquire_heavy_job_lock( + label: str, blocking: bool = False, lock_path: str | None = None +) -> bool: + """Ensure only ONE heavy align job runs at a time. + + Uses flock, so the lock is released automatically by the kernel when the + process dies -- that is the ONLY staleness mechanism. The lockfile itself + is never deleted (see module docstring: flock binds to the inode). + Rank-aware: only rank 0 of a distributed job takes it. + """ + global _lock_handle + import fcntl + + if int(os.environ.get("RANK", "0")) != 0: + return True + + path = lock_path or LOCK_PATH + _lock_handle = open(path, "a+") + flags = fcntl.LOCK_EX if blocking else (fcntl.LOCK_EX | fcntl.LOCK_NB) + try: + fcntl.flock(_lock_handle.fileno(), flags) + except BlockingIOError: + try: + _lock_handle.seek(0) + holder = _lock_handle.read().strip() + except OSError: + holder = "unknown" + _lock_handle.close() + _lock_handle = None + raise PreflightRefused( + f"another heavy align job holds the lock ({holder}). Two heavy jobs " + "at once is what killed the predecessor's first SFT run. WAIT for " + "the holder to exit -- flock auto-releases on process death. Do " + "NOT delete the lockfile: flock binds to the inode, and deleting " + "it lets two jobs run at once." + ) + _lock_handle.seek(0) + _lock_handle.truncate() + _lock_handle.write(f"{label} pid={os.getpid()}\n") + _lock_handle.flush() + logger.info("acquired heavy-job lock for %r", label) + return True + + +def _die_with_parent(parent_pid: int) -> None: + """Make the kernel SIGTERM this process when the lock-holding parent dies (Linux PR_SET_PDEATHSIG). + + THE UNPROTECTED-ORPHAN DEFECT (R2 review). The lock lives and dies with the SUPERVISOR's file + description; a child that merely *borrowed* it keeps running after a SIGKILL / OOM-kill of the + supervisor, while the kernel has already released the flock. The next job then starts on a + host that still has an 8B generation or an 8-worker Lean pool running -- the "two heavy jobs at + once" the lock exists to prevent, reached through the very code written to keep it held. A + child that cannot be tied to its parent's lifetime must not borrow the lock, so a failure to + install the signal RAISES. The `getppid` re-check closes the window between the ownership check + and the prctl (a parent that died in it has already re-parented us to init). + """ + import ctypes + import signal + + try: + libc = ctypes.CDLL(None, use_errno=True) + rc = libc.prctl(1, int(signal.SIGTERM), 0, 0, 0) # PR_SET_PDEATHSIG = 1 + err = ctypes.get_errno() + except (OSError, AttributeError) as e: + raise PreflightRefused(f"inherit_heavy_job_lock: cannot call prctl(PR_SET_PDEATHSIG): {e}") from e + if rc != 0: + raise PreflightRefused( + f"inherit_heavy_job_lock: prctl(PR_SET_PDEATHSIG) failed (errno {err}); a child that outlives its " + "lock-holding parent would run unprotected, so it must not borrow the lock." + ) + if os.getppid() != parent_pid: + raise PreflightRefused(f"inherit_heavy_job_lock: parent {parent_pid} died while the lock was being inherited.") + + +def inherit_heavy_job_lock(parent_pid: int, lock_path: str | None = None) -> bool: + """Adopt the heavy-job flock that this process's PARENT holds, instead of taking it. + + A supervisor that must hold the lock across several consecutive heavy children (generation at + two caps, then Lean verification) cannot hand it down: the children's own + `acquire_heavy_job_lock` opens a new file description and blocks forever on the parent's. + Letting a child skip the lock on an unchecked flag would also let ANY process claim to hold it, + so the claim is verified three ways, and a failure raises instead of running unprotected: + + 1. we are a direct child of `parent_pid` (not an unrelated process that merely knows the pid); + 2. the lock file's recorded holder says that pid took it; + 3. the flock is genuinely held right now (a fresh non-blocking attempt must FAIL). + """ + import fcntl + + if os.getppid() != int(parent_pid): + raise PreflightRefused( + f"inherit_heavy_job_lock: parent pid is {os.getppid()}, not {parent_pid}; refusing to claim a lock " + "this process did not inherit." + ) + path = lock_path or LOCK_PATH + with open(path, "a+") as fh: + fh.seek(0) + holder = fh.read().strip() + if f"pid={int(parent_pid)}" not in holder.split(): + raise PreflightRefused(f"lock file names holder {holder!r}, not pid={parent_pid}; refusing to inherit.") + try: + fcntl.flock(fh.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB) + except BlockingIOError: + _die_with_parent(int(parent_pid)) + logger.info("inherited the heavy-job lock held by pid %s (%s)", parent_pid, holder) + return True + fcntl.flock(fh.fileno(), fcntl.LOCK_UN) + raise PreflightRefused( + f"lock file names pid={parent_pid} but nobody holds the flock (stale label): the parent did not take the " + "lock, so this child would run unprotected." + ) + + +def release_heavy_job_lock_for_tests() -> None: + """TESTS ONLY: drop the flock by closing the handle. Production code + never releases the lock explicitly -- it is held for process lifetime and + released by the kernel on exit.""" + global _lock_handle + if _lock_handle is not None: + _lock_handle.close() + _lock_handle = None + + +def pin_visible_devices(devices: str) -> None: + """Narrow CUDA_VISIBLE_DEVICES. MUST be called before `import torch`.""" + import sys + + if "torch" in sys.modules: + raise RuntimeError( + "pin_visible_devices() called after torch was imported; the device " + "list is read at torch's CUDA init and will be ignored. Move this " + "call to the top of the script." + ) + os.environ["CUDA_VISIBLE_DEVICES"] = devices + logger.info("CUDA_VISIBLE_DEVICES=%s", devices) + + +@dataclass(frozen=True) +class GpuState: + index: int + name: str + total_gb: float + free_gb: float + compute_capability: tuple[int, int] + + +def query_gpus() -> list[GpuState]: + """Query GPUs via nvidia-smi so this works before torch is imported.""" + out = subprocess.run( + [ + "nvidia-smi", + "--query-gpu=index,name,memory.total,memory.free,compute_cap", + "--format=csv,noheader,nounits", + ], + capture_output=True, + text=True, + check=True, + ).stdout.strip() + gpus = [] + for line in out.splitlines(): + idx, name, total, free, cap = [f.strip() for f in line.split(",")] + major, minor = cap.split(".") + gpus.append( + GpuState( + index=int(idx), + name=name, + total_gb=float(total) / 1024, + free_gb=float(free) / 1024, + compute_capability=(int(major), int(minor)), + ) + ) + return gpus + + +def preflight_vram_check( + required_gb: float, device_idx: int = 0, label: str = "allocation" +) -> None: + """Fail fast if `device_idx` cannot hold `required_gb`. The point is to + fail in 50ms with a clear message instead of 20 minutes into a run with + a CUDA OOM traceback that names no model.""" + gpus = {g.index: g for g in query_gpus()} + if device_idx not in gpus: + raise RuntimeError(f"cuda:{device_idx} does not exist; have {sorted(gpus)}") + g = gpus[device_idx] + if g.free_gb < required_gb: + raise RuntimeError( + f"preflight failed for '{label}': cuda:{device_idx} has " + f"{g.free_gb:.1f}GB free but {required_gb:.1f}GB is required. " + f"({g.name}, {g.total_gb:.1f}GB total). Either free the device or " + "shard this model across more GPUs." + ) + logger.info( + "preflight ok [%s]: cuda:%d %.1fGB free >= %.1fGB required", + label, + device_idx, + g.free_gb, + required_gb, + ) + + +def assert_ampere_or_newer() -> tuple[int, int]: + """bf16 needs SM80+. A10G is SM86, so this passes here -- but the check + exists so a future move to an older card fails loudly instead of silently + producing NaNs through an fp16 fallback.""" + gpus = query_gpus() + if not gpus: + raise RuntimeError("no GPUs visible") + cc = min(g.compute_capability for g in gpus) + if cc < (8, 0): + raise RuntimeError( + f"compute capability {cc} < (8,0): bf16 is unavailable and fp16 " + "training of this model is numerically unsafe." + ) + return cc diff --git a/code/align/utils/host_state_gate.py b/code/align/utils/host_state_gate.py new file mode 100644 index 0000000000000000000000000000000000000000..88f94c665ea58a1d354aaf3916c034e602053a24 --- /dev/null +++ b/code/align/utils/host_state_gate.py @@ -0,0 +1,159 @@ +"""Sustained D-state gate: /apps/CLAUDE.md hard rule 4. STDLIB ONLY. + +The rule: "`ps -eo stat | grep -c '^D'` above ~5 sustained means the host is +wedged on I/O; do not add load, and expect writes to stall mid-file." +`align.utils.guard.preflight_host_check` gates RAM, load and disk queue depth +but not this, and the 2026-08-12 incident is the case where it matters: ~23 +processes sat in uninterruptible sleep while each of the other three numbers +could be read as merely "busy". D-state processes cannot be killed, cannot be +timed out and do not show up as CPU load, so the symptom the operator is told +to watch for had no programmatic check at all. + +WHY "SUSTAINED". One `/proc` scan is a lottery ticket: a burst of reads on a +healthy box parks a dozen processes in D for a few milliseconds (an `ls` over +a cold NFS-ish directory, a writeback flush), and a gate that refuses on a +single sample would refuse on a healthy host and be switched off within a day. +A wedge is the opposite shape: the count STAYS high. So the gate samples +`samples` times, `interval_s` apart, and refuses only if EVERY sample exceeds +the threshold -- one clean reading is proof the host is draining. + +WHAT IT COUNTS. Processes (one per PID, the thread-group leader's state field +from `/proc//stat`), not threads: that is what `ps -eo stat` prints, and +therefore what the rule's "~5" was calibrated against. The state is parsed +from AFTER the last ')' because the command name (field 2) may itself contain +spaces and parentheses. + +This module is deliberately NOT wired into `guard.py` (a long run was live +when it was written and its `preflight_host_check` behaviour was frozen). The +recommended wiring is one line, below. It is opt-in until then: call +`preflight_dstate_check()` from a new entry point, or run + + python -m align.utils.host_state_gate [--max-d-state 5] [--samples 3] + +which exits 0 when the host is clear and `EXIT_PREFLIGHT_REFUSED` (83) when it +is wedged, so a shell wrapper or the supervisor's `preflight=` hook can use it. + +RECOMMENDED WIRING (one line, in `align/utils/guard.py::apply_resource_guards`, +directly after the existing `preflight_host_check()` call for `heavy=True`): + + from .host_state_gate import preflight_dstate_check; preflight_dstate_check() + +Caveat for that wiring: the job's own processes count. A relaunch while the +previous run's ranks are still unwinding in D-state is exactly what the gate +should refuse, but a launcher that has already forked >5 D-state workers +(heavy checkpoint load) must run it BEFORE spawning them -- which `heavy=True` +at script start does. +""" + +from __future__ import annotations + +import argparse +import logging +import os +import sys +import time +from typing import Callable, Optional + +from ..exit_codes import EXIT_PREFLIGHT_REFUSED, PreflightRefused + +logger = logging.getLogger(__name__) + +#: /apps/CLAUDE.md rule 4: "above ~5 sustained". +MAX_D_STATE_PROCESSES = 5 +#: Consecutive over-threshold readings required to call it sustained. +DEFAULT_SAMPLES = 3 +DEFAULT_INTERVAL_S = 1.0 + + +def _state_of(stat_line: str) -> Optional[str]: + """Process state letter from one `/proc//stat` line, or None if malformed. + + Parsed from after the LAST ')': field 2 is the command name in parentheses + and may contain ')' and spaces; the state is the first token after it.""" + close = stat_line.rfind(")") + if close < 0: + return None + rest = stat_line[close + 1 :].split() + return rest[0] if rest else None + + +def count_d_state_processes(proc_root: str = "/proc") -> int: + """Number of processes currently in uninterruptible sleep ('D'). + + A process that exits between `listdir` and `open` is simply not counted; + unreadable entries are skipped. An unreadable `/proc` raises (the gate must + not report "0 D-state" for a scan that did not happen).""" + n = 0 + for entry in os.listdir(proc_root): + if not entry.isdigit(): + continue + try: + with open(os.path.join(proc_root, entry, "stat")) as fh: + state = _state_of(fh.read()) + except OSError: + continue + if state == "D": + n += 1 + return n + + +def preflight_dstate_check( + max_d_state: int = MAX_D_STATE_PROCESSES, + samples: int = DEFAULT_SAMPLES, + interval_s: float = DEFAULT_INTERVAL_S, + strict: bool = True, + counter: Optional[Callable[[], int]] = None, + sleep: Callable[[float], None] = time.sleep, +) -> dict: + """Refuse (PreflightRefused, exit 83) iff the D-state count exceeds + `max_d_state` in EVERY one of `samples` readings taken `interval_s` apart. + + Returns `{"counts": [...], "max_d_state": n, "sustained": bool}`. With + `strict=False` a sustained wedge is logged, not raised. Stops sampling at + the first clean reading: a host that is draining is not wedged.""" + if samples < 1: + raise ValueError(f"samples must be >= 1, got {samples}") + if max_d_state < 0: + raise ValueError(f"max_d_state must be >= 0, got {max_d_state}") + read = counter or count_d_state_processes + counts: list[int] = [] + for i in range(samples): + if i: + sleep(interval_s) + counts.append(int(read())) + if counts[-1] <= max_d_state: + break + sustained = len(counts) == samples and all(c > max_d_state for c in counts) + result = {"counts": counts, "max_d_state": max_d_state, "sustained": sustained} + if sustained: + msg = ( + f"host D-state gate FAILED: {counts} processes in uninterruptible sleep over " + f"{samples} samples {interval_s:g}s apart (max {max_d_state}). The host is wedged " + "on I/O (the 2026-08-12 shape: ~23 D-state processes, load 619): do not add " + "load, and expect writes to stall mid-file. Wait for it to drain." + ) + if strict: + raise PreflightRefused(msg) + logger.warning(msg) + else: + logger.info("D-state ok: counts=%s (max %d)", counts, max_d_state) + return result + + +def main(argv=None) -> int: + ap = argparse.ArgumentParser(description="Refuse if the host has a sustained D-state pile-up.") + ap.add_argument("--max-d-state", type=int, default=MAX_D_STATE_PROCESSES) + ap.add_argument("--samples", type=int, default=DEFAULT_SAMPLES) + ap.add_argument("--interval", type=float, default=DEFAULT_INTERVAL_S) + a = ap.parse_args(argv) + try: + res = preflight_dstate_check(a.max_d_state, a.samples, a.interval) + except PreflightRefused as e: + print(str(e), file=sys.stderr) + return EXIT_PREFLIGHT_REFUSED + print(f"D-state ok: counts={res['counts']} (max {res['max_d_state']})") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/code/align/utils/hostguard.py b/code/align/utils/hostguard.py new file mode 100644 index 0000000000000000000000000000000000000000..333cc89edc5cc66356689bee41780e3a67baad72 --- /dev/null +++ b/code/align/utils/hostguard.py @@ -0,0 +1,447 @@ +"""Host guard: keep this shared box alive while our jobs run (stdlib only). + +Incident 2026-10-14/15: CPU-only build jobs (cargo / rustc / Lean `lake`) launched by an agent ignored the +Python-level thread caps, drove the 48-core host to 100% CPU, starved the vLLM workers (RPC timeout) and +finally took the machine down. The old guard (`align.utils.guard`) only checked the host at START and only +for jobs that opted into the heavy lock; nothing bounded a job after it started. + +Three layers, each independent of the code being run: + +1. **Kernel caps on our jobs** (`align.slice`, a systemd user slice; cgroup v2). Every job launched through + `scripts/hostguard.py run` gets its own transient scope inside the slice with CPUQuota / MemoryMax / + TasksMax. The kernel enforces them on the whole process tree (cargo, rustc, lake, Lean, vLLM workers), + so a job cannot exceed them no matter how many children it forks. +2. **Host watchdog** (`align-hostguard.service`). Samples host-wide CPU, MemAvailable, PSI, D-state count, + GPU temperature and disk headroom every few seconds, and acts on OUR processes only: + * host CPU >= `cpu_soft` -> lower the slice CPUQuota (throttle); + * host CPU >= `cpu_hard` (92%) -> freeze the slice (cgroup.freeze; state and memory kept) and SIGSTOP + heavy processes of ours that run outside the slice; thaw once CPU stays below `cpu_resume`; + * MemAvailable < `mem_warn_gb` -> SIGTERM the largest process of ours; < `mem_kill_gb` -> SIGKILL the slice; + * D-state, GPU temperature, disk headroom -> freeze. +3. **Preflight** (`preflight()` here, also called from `guard.preflight_host_check`): a job refuses to start + when the host is already busy. + +Everything here is a pure decision function over a `Sample` plus thin actuators, so the policy is unit-tested +without touching the host. +""" +from __future__ import annotations + +import dataclasses +import json +import os +import shutil +import signal +import subprocess +import time +from pathlib import Path +from typing import Iterable, Optional + +SLICE = "align.slice" +EVENT_LOG = Path(os.environ.get("ALIGN_HOSTGUARD_LOG", "/apps/development/rlhf/align/.tmp/hostguard/events.jsonl")) +STOP_FILE = Path(os.environ.get("ALIGN_HOSTGUARD_STOP", "/apps/development/rlhf/align/.tmp/hostguard/STOP")) + +#: process names of ours the watchdog never signals (the session, editors, the watchdog itself). +ALLOWLIST = frozenset({ + "claude", "node", "sshd", "bash", "sh", "systemd", "(sd-pam)", "dbus-broker", "dbus-broker-lau", + "sleep", "tmux", "screen", "ps", "python3-hostguard", +}) + + +@dataclasses.dataclass(frozen=True) +class Policy: + cpu_soft: float = 85.0 # % of all cores, host-wide + cpu_hard: float = 92.0 # the line the host must not cross + cpu_resume: float = 75.0 # thaw only below this ... + resume_after_s: float = 30.0 # ... for this long + hard_after_s: float = 6.0 # hard action once the hard line is held this long (two samples) + mem_warn_gb: float = 30.0 # MemAvailable: SIGTERM the largest of ours + mem_kill_gb: float = 15.0 # MemAvailable: SIGKILL every process in the slice + psi_mem_full: float = 20.0 # /proc/pressure/memory full avg10 (%) treated like mem_warn + dstate_max: int = 10 # D-state processes host-wide + gpu_temp_max: float = 85.0 # degC + home_min_gb: float = 1.0 # /home filled on 2026-10-14 and broke every tool call + apps_min_gb: float = 20.0 + root_min_gb: float = 3.0 # / is 30 GB and shared with the OS + tmp_min_gb: float = 1.0 + slice_cpu_cores: float = 40.0 # normal align.slice CPUQuota (cores); 40/48 = 83% + slice_cpu_floor: float = 8.0 # throttle never goes below this + slice_mem_gb: float = 130.0 # align.slice MemoryMax + # preflight (a job refuses to START above these) + start_cpu_max: float = 70.0 + start_mem_min_gb: float = 45.0 + + +@dataclasses.dataclass +class Sample: + t: float + cpu_pct: float # host-wide busy % over the last interval + mem_avail_gb: float + mem_total_gb: float + psi_mem_full: float + psi_cpu_some: float + dstate: int + gpu_temps: list + gpu_mem_used_frac: list + home_free_gb: float + apps_free_gb: float + root_free_gb: float = float("inf") + tmp_free_gb: float = float("inf") + + +#: environment variables that decide where downloads, caches and temp files land. All must be under /apps +#: (2026-10-19 rule: nothing is downloaded or written to /, /home or /tmp). +PATH_ENV = ("TMPDIR", "TMP", "TEMP", "XDG_CACHE_HOME", "HF_HOME", "PIP_CACHE_DIR", "UV_CACHE_DIR", "npm_config_cache", + "TORCH_HOME", "TRITON_CACHE_DIR", "TORCHINDUCTOR_CACHE_DIR", "CUDA_CACHE_PATH", "GOCACHE", "GOMODCACHE", + "CARGO_HOME", "RUSTUP_HOME", "OPAMROOT", "ELAN_HOME", "PLAYWRIGHT_BROWSERS_PATH", "PUPPETEER_CACHE_DIR") +APPS_ONLY_ENV = "/apps/development/rlhf/env/apps_only.sh" + + +def off_apps_paths(env: dict) -> list[str]: + """`VAR=path` entries that would send downloads/caches/temp outside /apps (unset vars are reported too + for the temp + XDG cache ones, since tools then fall back to /tmp or ~/.cache).""" + bad = [] + for k in PATH_ENV: + v = env.get(k) + if v is None: + if k in ("TMPDIR", "XDG_CACHE_HOME", "HF_HOME"): + bad.append(f"{k} unset") + continue + if not os.path.realpath(v).startswith("/apps/"): + bad.append(f"{k}={v}") + return bad + + +# --------------------------------------------------------------------------------------------- sampling + +def _read_cpu_times() -> tuple[int, int]: + with open("/proc/stat") as f: + parts = f.readline().split()[1:] + vals = [int(x) for x in parts] + idle = vals[3] + (vals[4] if len(vals) > 4 else 0) # idle + iowait + return sum(vals[:8]), idle + + +def cpu_percent(interval: float = 1.0) -> float: + t0, i0 = _read_cpu_times() + time.sleep(interval) + t1, i1 = _read_cpu_times() + dt = t1 - t0 + return 0.0 if dt <= 0 else 100.0 * (1.0 - (i1 - i0) / dt) + + +def _meminfo() -> dict: + out = {} + with open("/proc/meminfo") as f: + for line in f: + k, v = line.split(":", 1) + out[k] = int(v.split()[0]) / (1024 * 1024) # kB -> GiB + return out + + +def _psi(kind: str, line: str) -> float: + try: + with open(f"/proc/pressure/{kind}") as f: + for l in f: + if l.startswith(line): + return float(l.split("avg10=")[1].split()[0]) + except OSError: + pass + return 0.0 + + +def _dstate_count() -> int: + n = 0 + for pid in os.listdir("/proc"): + if pid.isdigit(): + try: + with open(f"/proc/{pid}/stat") as f: + if f.read().rsplit(")", 1)[1].split()[0] == "D": + n += 1 + except (OSError, IndexError): + pass + return n + + +def _gpus() -> tuple[list, list]: + if not shutil.which("nvidia-smi"): + return [], [] + try: + out = subprocess.run(["nvidia-smi", "--query-gpu=temperature.gpu,memory.used,memory.total", + "--format=csv,noheader,nounits"], capture_output=True, text=True, timeout=10).stdout + except (subprocess.TimeoutExpired, OSError): + return [], [] + temps, mem = [], [] + for row in out.strip().splitlines(): + try: + t, u, tot = (float(x) for x in row.split(",")) + temps.append(t); mem.append(u / tot if tot else 0.0) + except ValueError: + pass + return temps, mem + + +def _free_gb(path: str) -> float: + try: + return shutil.disk_usage(path).free / 2**30 + except OSError: + return float("inf") + + +def take_sample(interval: float = 2.0) -> Sample: + cpu = cpu_percent(interval) + m = _meminfo() + temps, gmem = _gpus() + return Sample(t=time.time(), cpu_pct=cpu, mem_avail_gb=m.get("MemAvailable", 0.0), mem_total_gb=m.get("MemTotal", 0.0), + psi_mem_full=_psi("memory", "full"), psi_cpu_some=_psi("cpu", "some"), dstate=_dstate_count(), + gpu_temps=temps, gpu_mem_used_frac=gmem, home_free_gb=_free_gb("/home"), apps_free_gb=_free_gb("/apps"), + root_free_gb=_free_gb("/"), tmp_free_gb=_free_gb("/tmp")) + + +# --------------------------------------------------------------------------------------------- policy + +@dataclasses.dataclass +class State: + frozen: bool = False + frozen_reason: str = "" + hard_since: Optional[float] = None + calm_since: Optional[float] = None + slice_cores: Optional[float] = None + + +def decide(s: Sample, st: State, p: Policy) -> list[tuple]: + """Pure policy: returns actions as tuples, updates `st` in place. + + Actions: ("kill_slice", reason) | ("term_largest", reason) | ("freeze", reason) | ("thaw", reason) + | ("set_cpu", cores, reason) | ("stop_outside", reason) | ("cont_outside", reason).""" + acts: list[tuple] = [] + # memory first: it is the failure mode with no recovery (no swap on this box) + if s.mem_avail_gb < p.mem_kill_gb: + acts.append(("kill_slice", f"MemAvailable {s.mem_avail_gb:.1f} GB < {p.mem_kill_gb}")) + elif s.mem_avail_gb < p.mem_warn_gb or s.psi_mem_full >= p.psi_mem_full: + acts.append(("term_largest", f"MemAvailable {s.mem_avail_gb:.1f} GB / PSI full {s.psi_mem_full:.1f}")) + + hard = [] + if s.cpu_pct >= p.cpu_hard: + hard.append(f"host CPU {s.cpu_pct:.1f}% >= {p.cpu_hard}") + if s.dstate > p.dstate_max: + hard.append(f"{s.dstate} D-state processes > {p.dstate_max}") + hot = [t for t in s.gpu_temps if t >= p.gpu_temp_max] + if hot: + hard.append(f"GPU temp {max(hot):.0f}C >= {p.gpu_temp_max}") + if s.home_free_gb < p.home_min_gb: + hard.append(f"/home free {s.home_free_gb:.2f} GB < {p.home_min_gb}") + if s.apps_free_gb < p.apps_min_gb: + hard.append(f"/apps free {s.apps_free_gb:.1f} GB < {p.apps_min_gb}") + if s.root_free_gb < p.root_min_gb: + hard.append(f"/ free {s.root_free_gb:.1f} GB < {p.root_min_gb}") + if s.tmp_free_gb < p.tmp_min_gb: + hard.append(f"/tmp free {s.tmp_free_gb:.1f} GB < {p.tmp_min_gb}") + + if hard: + st.calm_since = None + if st.hard_since is None: + st.hard_since = s.t + if not st.frozen and s.t - st.hard_since >= p.hard_after_s - 1e-9: + st.frozen, st.frozen_reason = True, "; ".join(hard) + acts += [("freeze", st.frozen_reason), ("stop_outside", st.frozen_reason)] + else: + st.hard_since = None + calm = s.cpu_pct < p.cpu_resume + if st.frozen: + if calm: + if st.calm_since is None: + st.calm_since = s.t + if s.t - st.calm_since >= p.resume_after_s - 1e-9: + st.frozen = False + acts += [("thaw", f"host CPU {s.cpu_pct:.1f}% < {p.cpu_resume} for {p.resume_after_s:.0f}s"), + ("cont_outside", "resume")] + st.calm_since = None + else: + st.calm_since = None + + # soft throttle of the slice quota (only while not frozen) + if not st.frozen: + cur = st.slice_cores if st.slice_cores is not None else p.slice_cpu_cores + if s.cpu_pct >= p.cpu_soft: + new = max(p.slice_cpu_floor, cur * 0.6) + if new < cur - 1e-9: + acts.append(("set_cpu", new, f"host CPU {s.cpu_pct:.1f}% >= soft {p.cpu_soft}")) + st.slice_cores = new + elif s.cpu_pct < p.cpu_resume and cur < p.slice_cpu_cores: + new = min(p.slice_cpu_cores, cur * 1.5) + acts.append(("set_cpu", new, f"host CPU {s.cpu_pct:.1f}% < {p.cpu_resume}: relax")) + st.slice_cores = new + return acts + + +def preflight(s: Sample, p: Policy) -> list[str]: + """Reasons a new job must not start now (empty = OK).""" + why = [] + if s.cpu_pct > p.start_cpu_max: + why.append(f"host CPU {s.cpu_pct:.1f}% > {p.start_cpu_max}") + if s.mem_avail_gb < p.start_mem_min_gb: + why.append(f"MemAvailable {s.mem_avail_gb:.1f} GB < {p.start_mem_min_gb}") + if s.dstate > p.dstate_max: + why.append(f"{s.dstate} D-state processes") + if s.home_free_gb < p.home_min_gb * 2: + why.append(f"/home free {s.home_free_gb:.2f} GB") + if s.apps_free_gb < p.apps_min_gb: + why.append(f"/apps free {s.apps_free_gb:.1f} GB") + if s.root_free_gb < p.root_min_gb * 2: + why.append(f"/ free {s.root_free_gb:.1f} GB") + if any(t >= p.gpu_temp_max - 5 for t in s.gpu_temps): + why.append(f"GPU temp {max(s.gpu_temps):.0f}C") + return why + + +# --------------------------------------------------------------------------------------------- actuators + +def _systemctl(*args: str) -> subprocess.CompletedProcess: + return subprocess.run(["systemctl", "--user", *args], capture_output=True, text=True, timeout=30) + + +def slice_cgroup() -> Optional[Path]: + uid = os.getuid() + p = Path(f"/sys/fs/cgroup/user.slice/user-{uid}.slice/user@{uid}.service/{SLICE}") + return p if p.exists() else None + + +def slice_pids() -> list[int]: + root = slice_cgroup() + if root is None: + return [] + pids = [] + for procs in root.rglob("cgroup.procs"): + try: + pids += [int(x) for x in procs.read_text().split()] + except OSError: + pass + return pids + + +def in_slice(pid: int = 0) -> bool: + try: + return f"/{SLICE}/" in Path(f"/proc/{pid or os.getpid()}/cgroup").read_text() + except OSError: + return False + + +def _rss_gb(pid: int) -> float: + try: + with open(f"/proc/{pid}/statm") as f: + return int(f.read().split()[1]) * os.sysconf("SC_PAGE_SIZE") / 2**30 + except (OSError, IndexError, ValueError): + return 0.0 + + +def _comm(pid: int) -> str: + try: + return Path(f"/proc/{pid}/comm").read_text().strip() + except OSError: + return "" + + +def own_heavy_outside(min_cpu_pct: float = 50.0, sample_s: float = 1.0, exclude: Iterable[int] = ()) -> list[int]: + """Our (same uid) processes OUTSIDE the slice using > min_cpu_pct of one core, excluding the allowlist, + the slice, our own ancestry and `exclude`. This is what catches ad-hoc commands launched without the + runner (the 2026-10-14 cargo builds).""" + uid, ex = os.getuid(), set(exclude) | {os.getpid(), os.getppid()} + sl = set(slice_pids()) + + def ticks(): + out = {} + for pid in os.listdir("/proc"): + if not pid.isdigit(): + continue + i = int(pid) + try: + if os.stat(f"/proc/{pid}").st_uid != uid: + continue + with open(f"/proc/{pid}/stat") as f: + rest = f.read().rsplit(")", 1)[1].split() + out[i] = int(rest[11]) + int(rest[12]) + except (OSError, IndexError, ValueError): + pass + return out + + a = ticks(); time.sleep(sample_s); b = ticks() + hz = os.sysconf("SC_CLK_TCK") + hits = [] + for pid, t in b.items(): + if pid in ex or pid in sl or _comm(pid) in ALLOWLIST: + continue + if 100.0 * (t - a.get(pid, t)) / (hz * sample_s) >= min_cpu_pct: + hits.append(pid) + return hits + + +def _signal(pids: Iterable[int], sig: int) -> list[int]: + done = [] + for pid in pids: + try: + os.kill(pid, sig); done.append(pid) + except OSError: + pass + return done + + +def log_event(kind: str, **kw) -> None: + EVENT_LOG.parent.mkdir(parents=True, exist_ok=True) + with open(EVENT_LOG, "a") as f: + f.write(json.dumps({"t": time.strftime("%Y-%m-%dT%H:%M:%S"), "event": kind, **kw}) + "\n") + + +class Actuator: + def __init__(self, policy: Policy, dry_run: bool = False): + self.p, self.dry = policy, dry_run + self.stopped_outside: set[int] = set() + + def apply(self, act: tuple, s: Sample) -> None: + kind = act[0] + log_event(kind, detail=act[1:], cpu=round(s.cpu_pct, 1), mem_avail_gb=round(s.mem_avail_gb, 1), + dstate=s.dstate, dry_run=self.dry) + if self.dry: + return + if kind == "freeze": + _systemctl("freeze", SLICE) + elif kind == "thaw": + _systemctl("thaw", SLICE) + elif kind == "set_cpu": + _systemctl("set-property", "--runtime", SLICE, f"CPUQuota={int(act[1] * 100)}%") + elif kind == "kill_slice": + _systemctl("kill", "--signal=SIGKILL", SLICE) + _signal(self.stopped_outside, signal.SIGKILL) + elif kind == "term_largest": + cands = [pid for pid in set(slice_pids()) | set(self.stopped_outside) if _comm(pid) not in ALLOWLIST] + if cands: + victim = max(cands, key=_rss_gb) + log_event("term_victim", pid=victim, comm=_comm(victim), rss_gb=round(_rss_gb(victim), 1)) + _signal([victim], signal.SIGCONT); _signal([victim], signal.SIGTERM) + elif kind == "stop_outside": + pids = own_heavy_outside() + if pids: + log_event("sigstop_outside", pids=pids, comms=[_comm(p) for p in pids]) + self.stopped_outside |= set(_signal(pids, signal.SIGSTOP)) + elif kind == "cont_outside": + _signal(self.stopped_outside, signal.SIGCONT) + self.stopped_outside.clear() + + +def watch(policy: Policy = Policy(), interval: float = 3.0, dry_run: bool = False, max_iters: Optional[int] = None) -> None: + st, act = State(), Actuator(policy, dry_run) + log_event("watchdog_start", policy=dataclasses.asdict(policy), dry_run=dry_run) + last_status = 0.0 + i = 0 + while max_iters is None or i < max_iters: + i += 1 + s = take_sample(interval) + if STOP_FILE.exists(): + act.apply(("kill_slice", f"kill switch {STOP_FILE}"), s) + STOP_FILE.unlink(missing_ok=True) + for a in decide(s, st, policy): + act.apply(a, s) + if s.t - last_status >= 60: + last_status = s.t + log_event("status", cpu=round(s.cpu_pct, 1), mem_avail_gb=round(s.mem_avail_gb, 1), psi_mem_full=s.psi_mem_full, + dstate=s.dstate, gpu_temps=s.gpu_temps, home_free_gb=round(s.home_free_gb, 2), + frozen=st.frozen, slice_cores=st.slice_cores, slice_pids=len(slice_pids())) diff --git a/code/align/utils/supervisor.py b/code/align/utils/supervisor.py new file mode 100644 index 0000000000000000000000000000000000000000..abc72b7f8e13e7eec74f0b7000527927e09e33d8 --- /dev/null +++ b/code/align/utils/supervisor.py @@ -0,0 +1,573 @@ +"""Bounded-retry launch supervisor (G0 / roadmap P0-11). STDLIB ONLY. + +Why this exists. A 4-rank job on this shared, swapless box dies for reasons +that are sometimes transient (an NCCL timeout behind someone else's I/O storm, +a host seizure) and sometimes terminal (a gradient explosion, a poisoned +checkpoint). A human re-typing `torchrun` after each is slow; a bash +`while true` loop is how a deterministic crash gets relaunched forever, burning +GPU-hours and, worse, re-launching onto a host that is still wedged -- the +2026-08-12 shape. This supervisor automates ONLY the safe relaunch: + + retry iff exit code != 0 + AND exit code is not a HALT/terminal code (see below) + AND the child was not signal-stopped (143/130/129, or killed by + SIGTERM/SIGINT/SIGHUP) unless --retry-on-stop: a stop somebody + ASKED FOR is a decision, not a fault + AND retries used < max_retries (default 2) + AND progress was made DURING the failed attempt + AND preflight_host_check() passes right now + +Every clause is a way a blind retry loop goes wrong: + + * HALT codes. A tripwire HALT (gradient explosion, non-finite streak) is a + verdict about the RUN, not about the host. Relaunching resumes from the + last checkpoint and walks straight back into the same blow-up. Never retry. + * Progress. "Progress" means BOTH `history.jsonl` mtime advanced (the trainer + fsyncs a record per log step, so it moved only if training logged) AND the + latest `checkpoints/micro_NNNNNNNN` number increased (so a resume would + start from further along than the attempt did). History alone can advance + on a run that crashes every 50 steps with no checkpoint in between -- each + retry would redo the same 50 steps forever. Checkpoint alone can be a stale + value from a previous run. Both together mean "a resume is strictly ahead". + This is deliberately conservative: a crash before the first checkpoint of + a fresh run stops the supervisor rather than looping on a config defect. + * Preflight. Relaunching onto a host that is still at 2GB free / load 619 is + the crash we are preventing; the check is the same one the job runs itself. + * No concurrency. The previous child's whole process group (torchrun + its + workers) is SIGKILLed and confirmed empty before the next launch, so a + straggler rank can never overlap a relaunch. The supervisor never holds + the heavy-job flock itself; the child takes it, and a leaked rank holding + it would make the relaunch fail loudly rather than run two jobs. + +The child runs in its OWN session/process group (start_new_session) so that +killing it cannot take the supervisor with it and so the supervisor can kill +the whole tree. On SIGTERM/SIGINT/SIGHUP to the supervisor the group is +SIGTERMed, given `grace_s`, then SIGKILLed: an orphaned torchrun that outlives +its supervisor keeps GPUs and /dev/shm pinned with nobody watching. + +Attempts are appended (fsynced) to `/supervisor.jsonl`. + +STOPS ARE DRAINED, NOT KILLED (G3 audit U01-1 / U01-2). A coordinated stop +needs up to one optimizer-step boundary (~68s at the P2 shape) plus a save +(~3.3 min); torchrun SIGKILLs its workers 30s after a SIGTERM and `grace_s` is +20s, so a SIGTERM-driven stop could never finish inside either. A trainer that +can drain says so (`DRAIN_READY.json`, written when `train()` starts); the +supervisor then asks it to stop through `STOP_REQUEST` -- a file polled at the +boundary, no signal -- and waits up to `drain_s` before the SIGTERM->SIGKILL +escalation. And because `torchrun` exits 1 whatever its worker did, a trainer +that stopped on an operator's signal also leaves `STOP.json` (code 128+signum) +so a `kill ` is read as the operator stop it is, not as a retryable +crash. All three files carry their own `written_at`, like HALT.json. + +The exit codes (`align.exit_codes`) are the CONTRACT with the trainer, carried +on TWO channels because `torchrun` collapses every worker's exit code to 1: the +child's exit code, and `/HALT.json`, which a halting rank writes before +it raises. A marker written after the attempt started is the verdict whatever +the launcher said (`halt_marker` in the log). The progress rule remains the +backstop for a halt that managed to write neither. +""" + +from __future__ import annotations + +import json +import os +import re +import signal +import subprocess +import threading +import time +from dataclasses import dataclass, field +from typing import Callable, Optional, Sequence + +# Exit-code contract: defined once in `align.exit_codes` (the trainer imports +# the same module, so neither side can drift) and re-exported here because the +# supervisor's tests and CLI have always imported them from this module. +from ..exit_codes import ( # noqa: E402 + EXIT_NONFINITE_HALT, + EXIT_PREFLIGHT_REFUSED, + EXIT_SUPERVISOR_GAVE_UP, + EXIT_TRIPWIRE_HALT, + EXIT_WALL_BUDGET, + NON_RETRYABLE_EXIT_CODES, + read_halt_marker, +) + +#: Supervisor -> trainer: "stop at the next optimizer-step boundary and save". +STOP_REQUEST_NAME = "STOP_REQUEST" +#: Trainer -> supervisor: "I stopped because I was told to" (code 128+signum). +STOP_MARKER_NAME = "STOP.json" +#: Trainer -> supervisor: "I poll STOP_REQUEST; wait for me instead of killing me". +DRAIN_READY_NAME = "DRAIN_READY.json" + + +def write_run_marker(run_dir: str, name: str, **fields) -> bool: + """Atomically (tmp + fsync + rename) write `/` as JSON with a + `written_at` stamp. Best-effort like `write_halt_marker`: False on OSError, + because a stop must proceed even if its marker cannot be written.""" + path = os.path.join(run_dir, name) + tmp = path + f".tmp{os.getpid()}" + try: + os.makedirs(run_dir, exist_ok=True) + with open(tmp, "w") as fh: + json.dump({**fields, "written_at": time.time()}, fh) + fh.flush() + os.fsync(fh.fileno()) + os.replace(tmp, path) + except OSError: + try: + os.unlink(tmp) + except OSError: + pass + return False + return True + + +def read_run_marker(run_dir: str, name: str, since: float = 0.0) -> Optional[dict]: + """The marker `name` if it exists AND its own `written_at` is >= `since` + (the file's contents, not its mtime, for the reason `read_halt_marker` + gives). Unreadable or malformed -> None.""" + try: + with open(os.path.join(run_dir, name)) as fh: + rec = json.load(fh) + if not isinstance(rec, dict) or float(rec["written_at"]) < since: + return None + return rec + except (OSError, ValueError, KeyError, TypeError): + return None + + +def clear_run_marker(run_dir: str, name: str) -> None: + try: + os.unlink(os.path.join(run_dir, name)) + except OSError: + pass + + +def read_stop_marker(run_dir: str, since: float = 0.0) -> Optional[dict]: + """STOP.json, only if its code is a stop-by-signal code (128+n).""" + rec = read_run_marker(run_dir, STOP_MARKER_NAME, since) + try: + if rec is not None and int(rec["code"]) in OPERATOR_STOP_CODES: + return rec + except (KeyError, TypeError, ValueError): + pass + return None + + +#: Child statuses that mean "something SIGNALLED this run to stop", in both +#: spellings: the shell convention 128+n (what the trainer returns after its +#: coordinated checkpoint-and-stop, `Trainer.stop_exit_code`) and Popen's +#: negative returncode (a launcher killed by the signal itself). Deliberately +#: only the three signals an operator or service manager sends to ask for a +#: stop: SIGKILL (137/-9, the OOM killer) and SIGSEGV/SIGABRT are CRASHES and +#: stay retryable under the normal progress+preflight rules. +OPERATOR_STOP_SIGNALS = (signal.SIGTERM, signal.SIGINT, signal.SIGHUP) +OPERATOR_STOP_CODES = frozenset( + [128 + int(s) for s in OPERATOR_STOP_SIGNALS] + [-int(s) for s in OPERATOR_STOP_SIGNALS] +) + +SUPERVISOR_LOG_NAME = "supervisor.jsonl" +HISTORY_NAME = "history.jsonl" # mirrors align.utils.tracking.HISTORY_NAME +_CKPT_RE = re.compile(r"^micro_(\d+)$") # `.partial` dirs never match + + +def latest_checkpoint_micro_step( + run_dir: str, validator: Optional[Callable[[str], Optional[str]]] = None +) -> int: + """Highest COMPLETE `checkpoints/micro_NNNNNNNN` number, or -1 if none. + + Parsed from directory names (the trainer's own naming) rather than by + importing the Trainer: this module must stay stdlib-only and importable + before torch. `.partial` staging dirs are excluded -- they masquerade as + resumable and must not count as progress. + + `validator(path) -> None | reason` is the completeness check. The CLI wires + `align.train.trainer.checkpoint_problem` into it (that function reads + headers and the resume manifest, hence needs torch, which this module may + not import). Without it a directory that exists but is truncated -- the + host seized between the publishing rename and the data reaching disk -- + would count as progress and the supervisor would relaunch onto a + checkpoint `latest_checkpoint` will refuse. A validator that RAISES is + treated as "invalid": unknown is not progress.""" + root = os.path.join(run_dir, "checkpoints") + best = -1 + try: + entries = os.listdir(root) + except OSError: + return -1 + for d in entries: + m = _CKPT_RE.match(d) + path = os.path.join(root, d) + if not (m and os.path.isdir(path)): + continue + n = int(m.group(1)) + if n <= best: + continue # cannot raise the max; skip the (expensive) validation + if validator is not None: + try: + if validator(path) is not None: + continue + except Exception: # noqa: BLE001 + continue + best = n + return best + + +def history_mtime_ns(run_dir: str) -> int: + """mtime of history.jsonl in ns, or -1 when absent.""" + try: + return os.stat(os.path.join(run_dir, HISTORY_NAME)).st_mtime_ns + except OSError: + return -1 + + +class _SignalFlag: + """A stop flag that is SAFE TO SET FROM A SIGNAL HANDLER. + + THE HANDLER-DEADLOCK DEFECT. `threading.Event.set()` acquires the event's + internal (non-reentrant) lock. CPython runs a Python signal handler on the + main thread between two bytecodes of whatever it was executing; if that was + `Event.wait()` -- the supervisor spends its entire backoff there -- holding + that very lock, the handler's `set()` blocks on a lock its own thread owns + and the supervisor hangs, ignoring SIGTERM, with the whole job pinned. + The window is a few bytecodes wide, which is why it would show up once in a + blue moon on a night nobody is watching. + + A plain attribute store takes no lock. `wait` therefore polls in short + slices instead of blocking on a condition variable; the slice bounds the + reaction time to a signal that lands mid-sleep. + """ + + _SLICE_S = 0.1 + + def __init__(self) -> None: + self._flag = False + + def set(self) -> None: + self._flag = True + + def is_set(self) -> bool: + return self._flag + + def wait(self, timeout: float) -> bool: + deadline = time.monotonic() + timeout + while not self._flag: + left = deadline - time.monotonic() + if left <= 0: + return False + time.sleep(min(self._SLICE_S, left)) + return True + + +@dataclass(frozen=True) +class Snapshot: + history_mtime_ns: int + ckpt_micro_step: int + + @classmethod + def take(cls, run_dir: str, validator=None) -> "Snapshot": + return cls(history_mtime_ns(run_dir), latest_checkpoint_micro_step(run_dir, validator)) + + +def made_progress(before: Snapshot, after: Snapshot) -> bool: + """BOTH signals must advance (see module docstring).""" + return ( + after.history_mtime_ns > before.history_mtime_ns + and after.ckpt_micro_step > before.ckpt_micro_step + ) + + +@dataclass +class SupervisorResult: + exit_code: int # what the supervisor process should exit with + reason: str # "success" | "retries_exhausted" | "halt_exit_code" | ... + attempts: int + child_codes: list[int] = field(default_factory=list) + + +class Supervisor: + """Run `cmd` as a child process group with bounded, gated retries.""" + + def __init__( + self, + cmd: Sequence[str], + run_dir: str, + *, + max_retries: int = 2, + backoff_s: float = 30.0, + grace_s: float = 20.0, + preflight: Optional[Callable[[], object]] = None, + sleep: Optional[Callable[[float], None]] = None, + cwd: Optional[str] = None, + env: Optional[dict] = None, + checkpoint_validator: Optional[Callable[[str], Optional[str]]] = None, + retry_on_stop: bool = False, + drain_s: float = 900.0, + ): + if max_retries < 0: + raise ValueError(f"max_retries must be >= 0, got {max_retries}") + if not cmd: + raise ValueError("empty command") + self.cmd = list(cmd) + self.run_dir = run_dir + self.max_retries = int(max_retries) + self.backoff_s = float(backoff_s) + self.grace_s = float(grace_s) + self._preflight = preflight + self._stop = _SignalFlag() + self._sleep = sleep or (lambda s: self._stop.wait(s)) + self.cwd = cwd + self.env = env + self._validator = checkpoint_validator + #: THE RELAUNCH-AFTER-OPERATOR-STOP DEFECT (H2 review, 2026-10-13). An + #: operator who `kill`s the trainer (or torchrun) to stop a run gets a + #: checkpointed 143 -- which is not a HALT code, left a checkpoint behind + #: (so "progress"), and therefore passed every retry clause: the + #: supervisor relaunched exactly what the human had just stopped. A stop + #: that was ASKED FOR is a decision, not a fault; it ends the supervisor + #: unless the caller opts in (`--retry-on-stop`, e.g. a service manager + #: that SIGTERMs for host maintenance and wants the job back afterwards). + self.retry_on_stop = bool(retry_on_stop) + #: How long a SIGNAL to the supervisor waits for a drain-capable trainer + #: to checkpoint and exit before SIGTERM/SIGKILL (see module docstring: + #: one boundary + one save, with margin). 0 disables the drain. + self.drain_s = float(drain_s) + self._drain_deadline: Optional[float] = None # monotonic; set while a drain is pending + self._drain_logged = False + self._t_launch = 0.0 + self._proc: Optional[subprocess.Popen] = None + self._term_signal: Optional[int] = None + os.makedirs(run_dir, exist_ok=True) + self.log_path = os.path.join(run_dir, SUPERVISOR_LOG_NAME) + + # -- logging ------------------------------------------------------------ + def _log(self, **rec) -> None: + rec["t"] = time.time() + line = json.dumps(rec, sort_keys=True) + "\n" + with open(self.log_path, "a") as fh: + fh.write(line) + fh.flush() + os.fsync(fh.fileno()) + + # -- preflight ---------------------------------------------------------- + def _preflight_ok(self) -> tuple[bool, str]: + fn = self._preflight + if fn is None: + from .guard import preflight_host_check # stdlib-only module + + fn = preflight_host_check + try: + fn() + except Exception as e: # preflight raises RuntimeError on refusal + return False, str(e) + return True, "" + + # -- process-group control --------------------------------------------- + def _kill_group(self, pgid: int, first: int = signal.SIGTERM) -> bool: + """SIGTERM -> grace -> SIGKILL the group; True once it is empty.""" + for sig, wait_s in ((first, self.grace_s), (signal.SIGKILL, 10.0)): + try: + os.killpg(pgid, sig) + except ProcessLookupError: + return True + deadline = time.monotonic() + wait_s + while time.monotonic() < deadline: + if self._proc is not None: + self._proc.poll() # reap the leader so killpg(0) sees truth + if not _group_alive(pgid): + return True + time.sleep(0.05) + return not _group_alive(pgid) + + def _try_drain(self) -> bool: + """Ask a drain-capable trainer to stop itself. Runs in the signal + handler: file I/O only, no locks.""" + if self.drain_s <= 0: + return False + if read_run_marker(self.run_dir, DRAIN_READY_NAME, self._t_launch) is None: + return False + if not write_run_marker(self.run_dir, STOP_REQUEST_NAME, by="supervisor"): + return False + self._drain_deadline = time.monotonic() + self.drain_s + return True + + def _on_signal(self, signum, _frame) -> None: + first = self._term_signal is None + self._term_signal = signum + self._stop.set() + p = self._proc + if p is None or p.poll() is not None: + return + if first and self._try_drain(): + return # the wait loop escalates after drain_s; a second signal does not wait + self._drain_deadline = None + try: + os.killpg(p.pid, signal.SIGTERM) # the wait loop escalates + except ProcessLookupError: + pass + + def _wait_child(self, p: subprocess.Popen) -> int: + """Wait for the leader; if we were told to terminate and it ignores + SIGTERM, escalate to SIGKILL after grace_s rather than hang forever. + A pending drain defers the SIGTERM until its deadline.""" + t_term: Optional[float] = None + while True: + try: + return p.wait(timeout=0.2) + except subprocess.TimeoutExpired: + if self._term_signal is not None: + dl = self._drain_deadline + if dl is not None: + if not self._drain_logged: + self._drain_logged = True + self._log(event="drain_requested", drain_s=self.drain_s) + if time.monotonic() < dl: + continue + self._drain_deadline = None + self._log(event="drain_timeout", drain_s=self.drain_s) + try: + os.killpg(p.pid, signal.SIGTERM) + except ProcessLookupError: + pass + t_term = t_term or time.monotonic() + if time.monotonic() - t_term > self.grace_s: + try: + os.killpg(p.pid, signal.SIGKILL) + except ProcessLookupError: + pass + + # -- main loop ---------------------------------------------------------- + def run(self, install_signal_handlers: bool = True) -> SupervisorResult: + old = {} + if install_signal_handlers and threading.current_thread() is threading.main_thread(): + for s in (signal.SIGTERM, signal.SIGINT, signal.SIGHUP): + old[s] = signal.signal(s, self._on_signal) + try: + return self._run() + finally: + p = self._proc + if p is not None: # never leave a group behind, whatever happened + self._kill_group(p.pid, signal.SIGKILL) + for s, h in old.items(): + signal.signal(s, h) + + def _result(self, code, reason, attempt, codes) -> SupervisorResult: + self._log(event="stop", reason=reason, exit_code=code, attempts=attempt) + return SupervisorResult(code, reason, attempt, codes) + + def _run(self) -> SupervisorResult: + codes: list[int] = [] + attempt = 0 + while True: + attempt += 1 + before = Snapshot.take(self.run_dir, self._validator) + t_launch = time.time() + self._log(event="launch", attempt=attempt, cmd=self.cmd, + history_mtime_ns=before.history_mtime_ns, + ckpt_micro_step=before.ckpt_micro_step) + if self._stop.is_set(): # signalled during backoff + return self._result(128 + (self._term_signal or signal.SIGTERM), + "supervisor_terminated", attempt - 1, codes) + # A RETRY is a resume by definition: the attempt being retried + # made progress (that is the retry precondition), so relaunching it + # fresh would discard that progress -- and stage scripts that rotate + # stale checkpoints on a fresh launch (scripts/dpo.py) would move it + # out of the way. The child reads ALIGN_RESUME=1 as "resume from the + # newest valid checkpoint instead of starting a fresh arm". + child_env = dict(os.environ if self.env is None else self.env) + if attempt > 1: + child_env["ALIGN_RESUME"] = "1" + # A request/ready file from an earlier attempt must not drain or + # condemn this one (the readers also compare written_at to launch). + clear_run_marker(self.run_dir, STOP_REQUEST_NAME) + clear_run_marker(self.run_dir, DRAIN_READY_NAME) + self._t_launch = t_launch + self._drain_deadline = None + self._drain_logged = False + self._proc = subprocess.Popen( + self.cmd, cwd=self.cwd, env=child_env, start_new_session=True + ) + pgid = self._proc.pid + if self._term_signal is not None: + # THE LOST-SIGNAL WINDOW. A signal that lands after the stop + # check above but before `self._proc` is assigned finds no + # child for `_on_signal` to forward to; the flag is set, the + # child is launched anyway, and `_wait_child` then only + # escalates to SIGKILL after grace_s -- the job never gets the + # SIGTERM that makes it checkpoint and stop. Forward it now. + try: + os.killpg(pgid, signal.SIGTERM) + except ProcessLookupError: + pass + rc = self._wait_child(self._proc) + # The leader exiting does not mean its workers did. Clear the + # whole group BEFORE deciding anything: a straggler rank must not + # overlap a relaunch (or keep GPUs pinned after we give up). + group_clear = self._kill_group( + pgid, signal.SIGTERM if self._term_signal is not None else signal.SIGKILL + ) + self._proc = None + clear_run_marker(self.run_dir, STOP_REQUEST_NAME) + codes.append(rc) + after = Snapshot.take(self.run_dir, self._validator) + progressed = made_progress(before, after) + self._log(event="exit", attempt=attempt, child_exit=rc, progressed=progressed, + group_clear=group_clear, + history_mtime_ns=after.history_mtime_ns, + ckpt_micro_step=after.ckpt_micro_step) + + if self._term_signal is not None: + return self._result(128 + self._term_signal, "supervisor_terminated", + attempt, codes) + if rc == 0: + return self._result(0, "success", attempt, codes) + if rc in NON_RETRYABLE_EXIT_CODES: + return self._result(rc, "halt_exit_code", attempt, codes) + # torchrun reports EVERY worker failure as exit 1, so the code + # above only fires for a launcher-less run. The marker is how a + # halting rank's verdict survives the launcher. + marker = read_halt_marker(self.run_dir, since=t_launch) + if marker is not None: + self._log(event="halt_marker", attempt=attempt, code=marker["code"], + reason=marker.get("reason")) + return self._result(int(marker["code"]), "halt_marker", attempt, codes) + # torchrun also collapses a worker's checkpointed 143 into exit 1; + # the trainer's STOP.json is how that stop survives the launcher. + stop_marker = read_stop_marker(self.run_dir, since=t_launch) + if (rc in OPERATOR_STOP_CODES or stop_marker is not None) and not self.retry_on_stop: + code = rc if rc in OPERATOR_STOP_CODES else int(stop_marker["code"]) + self._log(event="operator_stop", attempt=attempt, child_exit=rc, + marker=stop_marker is not None) + return self._result(code if code > 0 else 128 - code, "operator_stop", attempt, codes) + if not group_clear: + return self._result(EXIT_SUPERVISOR_GAVE_UP, "process_group_not_dead", + attempt, codes) + if attempt - 1 >= self.max_retries: + return self._result(rc if rc > 0 else EXIT_SUPERVISOR_GAVE_UP, + "retries_exhausted", attempt, codes) + if not progressed: + return self._result(rc if rc > 0 else EXIT_SUPERVISOR_GAVE_UP, + "no_progress", attempt, codes) + delay = self.backoff_s * (2 ** (attempt - 1)) + self._log(event="backoff", attempt=attempt, seconds=delay) + self._sleep(delay) + if self._stop.is_set(): + return self._result(128 + (self._term_signal or signal.SIGTERM), + "supervisor_terminated", attempt, codes) + # Preflight AFTER the backoff: the point of waiting is to let the + # host quiesce, and a pre-wait reading is stale by then. + ok, why = self._preflight_ok() + if not ok: + self._log(event="preflight_failed", attempt=attempt, detail=why) + return self._result(rc if rc > 0 else EXIT_SUPERVISOR_GAVE_UP, + "preflight_failed", attempt, codes) + + +def _group_alive(pgid: int) -> bool: + try: + os.killpg(pgid, 0) + except ProcessLookupError: + return False + except PermissionError: # exists, not ours: cannot be our child + return False + return True diff --git a/code/align/utils/tracking.py b/code/align/utils/tracking.py new file mode 100644 index 0000000000000000000000000000000000000000..58a0c9324081fedf3377562091ba63a59dd65ac0 --- /dev/null +++ b/code/align/utils/tracking.py @@ -0,0 +1,159 @@ +"""Experiment tracking: a dependency-free, kill-surviving run record. + +(wandb was removed under docs/DEPENDENCY_POLICY.md. Nothing replaces its UI; +the on-disk record below is the single source of truth.) + +Files under `/`: + * `history.jsonl` -- append-only, one JSON object per log step, flushed AND + fsync'd every write. The host can seize at any moment (it has); this file + loses at most the one line being written, and post-run analysis loads THIS + full history -- never the sampled monitor lines (three predecessor + analyses were retracted for interpreting every-5th-iteration monitor + samples as data). `read_history` tolerates a torn final line for that + reason. + * `config.json` -- written by `log_config` via write-to-`.partial` + + `os.replace`, so a reader never sees a half-written config. + +LIVENESS: house rules judge "is the run progressing" by the history file's +mtime (`stat -c %y`), NOT by PIDs -- a wedged NCCL job keeps its processes. So +every `log` must touch history.jsonl; the fsync after each append guarantees +the mtime reaches the disk. + +Contract, exercised for real by the Trainer: + * missing mandatory metric keys RAISE; + * None RAISES; + * undefined statistics are logged as NaN -- never 0, never omitted. +""" + +from __future__ import annotations + +import json +import math +import os +import sys +from typing import Iterable, Mapping + +HISTORY_NAME = "history.jsonl" +CONFIG_NAME = "config.json" + + +def read_history(run_dir: str) -> list[dict]: + """All records of `/history.jsonl`, in order. Missing file -> []. + + A kill mid-append can leave one truncated trailing line; that line (and + only a trailing one) is dropped. A corrupt line in the MIDDLE is real + damage and raises rather than being skipped. + """ + path = os.path.join(run_dir, HISTORY_NAME) + if not os.path.exists(path): + return [] + with open(path, "r") as fh: + lines = fh.read().split("\n") + out: list[dict] = [] + # split leaves a final "" when the file ends in a newline. + last = max((i for i, l in enumerate(lines) if l.strip()), default=-1) + for i, line in enumerate(lines): + if not line.strip(): + continue + try: + out.append(json.loads(line)) + except json.JSONDecodeError: + if i == last: + continue # torn tail from a kill mid-write + raise + return out + + +def _repair_torn_tail(path: str) -> None: + """Make an existing history file end on a record boundary before append. + + A kill mid-append leaves a final line with no newline. Appending to it + glues the next record onto the fragment and `read_history` then raises + (the glued line is no longer the last one). A tail that is a complete JSON + record only missing its newline is kept and terminated; an unparseable + fragment is truncated away (it was never a whole record). + """ + if not os.path.exists(path): + return + with open(path, "rb+") as fh: + data = fh.read() + if not data or data.endswith(b"\n"): + return + cut = data.rfind(b"\n") + 1 # 0 when the file is a single torn line + try: + json.loads(data[cut:].decode("utf-8")) + fh.seek(0, os.SEEK_END) + fh.write(b"\n") + except (json.JSONDecodeError, UnicodeDecodeError): + fh.truncate(cut) + fh.flush() + os.fsync(fh.fileno()) + + +class Tracker: + def __init__( + self, + run_dir: str, + stage: str, + mandatory_keys: Iterable[str] = (), + run_name: str = "dev", + stdout_every: int = 0, + ) -> None: + self.run_dir = run_dir + self.stage = stage + self.run_name = run_name + self.mandatory_keys = tuple(mandatory_keys) + self.stdout_every = int(stdout_every) + os.makedirs(run_dir, exist_ok=True) + self.history_path = os.path.join(run_dir, HISTORY_NAME) + self.config_path = os.path.join(run_dir, CONFIG_NAME) + _repair_torn_tail(self.history_path) + self._fh = open(self.history_path, "a") + self._n = 0 + + def log_config(self, config: Mapping) -> None: + """Write config.json atomically (.partial + os.replace).""" + tmp = self.config_path + ".partial" + with open(tmp, "w") as fh: + json.dump(dict(config), fh, indent=2, sort_keys=True, default=str) + fh.flush() + os.fsync(fh.fileno()) + os.replace(tmp, self.config_path) + + def log(self, step: int, metrics: Mapping | None = None, **kw) -> None: + """Append one record. Metrics come as a mapping, kwargs, or both.""" + metrics = {**(dict(metrics) if metrics else {}), **kw} + missing = [k for k in self.mandatory_keys if k not in metrics] + if missing: + raise RuntimeError( + f"stage {self.stage!r} step {step}: mandatory metrics missing " + f"{missing}. Undefined statistics must be logged as " + "float('nan') explicitly -- omission is how silent failures " + "start." + ) + nones = [k for k, v in metrics.items() if v is None] + if nones: + raise RuntimeError( + f"stage {self.stage!r} step {step}: metrics {nones} are None. " + "Use float('nan') for undefined values -- None serializes to " + "null and downstream tooling coerces it to 0." + ) + record = {"step": step, "stage": self.stage, **metrics} + self._fh.write(json.dumps(record) + "\n") + self._fh.flush() + os.fsync(self._fh.fileno()) + self._n += 1 + if self.stdout_every > 0 and (self._n % self.stdout_every == 0): + body = " ".join( + f"{k}={v:.4g}" if isinstance(v, float) and math.isfinite(v) else f"{k}={v}" + for k, v in metrics.items() + ) + print(f"[{self.stage}] step {step} {body}", file=sys.stdout, flush=True) + + def finish(self) -> None: + if not self._fh.closed: + self._fh.flush() + os.fsync(self._fh.fileno()) + self._fh.close() + + close = finish # legacy name used by callers diff --git a/code/align/verify/__init__.py b/code/align/verify/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..81f7ef556ed280b03be0c326b7ab4249728a11be --- /dev/null +++ b/code/align/verify/__init__.py @@ -0,0 +1,48 @@ +"""`align.verify`: answer extraction, normalisation and equivalence. + +The in-repo replacement for `math_verify` + `sympy` (see docs/DEPENDENCY_POLICY.md). +Pure stdlib. Ceiling-tested: `tests/test_verify_ceiling.py` scores a gold-vs-gold +set at 100/100 (the house rule: ceiling-test the grader before trusting any +accuracy -- a perfect policy once scored 0/100) and, under the oracle marker, +measures agreement with the legacy engine. +""" + +from __future__ import annotations + +from .equiv import is_equiv, is_readable +from .expr import VerifyError, VerifyTimeout, deadline +from .extract import extract_boxed, extract_final_answer, extract_gold_answer, last_number +from .normalize import normalize_answer + +__all__ = [ + "VerifyError", + "VerifyTimeout", + "deadline", + "extract_boxed", + "extract_final_answer", + "extract_gold_answer", + "is_equiv", + "is_readable", + "last_number", + "normalize_answer", + "verify_text", +] + + +def verify_text(gold_text: str | None, pred_text: str | None) -> bool: + """Extract a final answer from each side, then test equivalence. + + The gold goes through `extract_gold_answer`, NOT the prose extractor: a + bare `\\frac{1}{2}` is an answer, and the prose extractor's last-number + fallback would read it as "2". A prediction with no extractable answer + is False. + """ + if pred_text is None: + return False + pred = extract_final_answer(pred_text) + if pred is None: + return False + gold = extract_gold_answer(gold_text) + if gold is None: + return False + return is_equiv(gold, pred) diff --git a/code/align/verify/equiv.py b/code/align/verify/equiv.py new file mode 100644 index 0000000000000000000000000000000000000000..572a2c7b2f1586a1f7208d0e960bc9a11c96fe52 --- /dev/null +++ b/code/align/verify/equiv.py @@ -0,0 +1,616 @@ +"""Answer equivalence: is `pred` the same mathematical answer as `gold`? + +Replaces `math_verify.verify`. Pure stdlib (`fractions`, `decimal`). + +DECISION LADDER (first rung that can decide, decides): + + 1. identical after normalisation -> True + 2. TEXT answers (words, not math): casefolded alphanumeric key -> exact + 3. MATRICES (`\\begin{pmatrix}`): same shape, cell-wise equivalence + 4. UNIONS (`\\cup`) and BARE LISTS (`1,-2`, `A,B,E`, `x=1, x=2`): + ORDER-INSENSITIVE multiset match (a bare list is a solution set; + `\\pm` expands to two members) + 5. BRACKETED sequences: `(a,b)` `[a,b)` -- ORDER-SENSITIVE and + BRACKET-SENSITIVE (a tuple is not a set, `(1,2)` is not `[1,2]`); + `\\{a,b\\}` is a SET and is order-insensitive + 6. RELATIONS: equations compared as polynomials up to a nonzero scalar + (`y=2x+3` == `2x-y+3=0`, but `x+y-z+1=0` != `x+y-z-1=0`); inequalities + are put in `<`/`<=` orientation and compared sidewise + 7. SCALARS, in this order: + a. canonical polynomial equality (exact, symbolic) + b. numeric evaluation: Fractions compared EXACTLY; irrational values + compared at 60 digits with relative tolerance (see + `expr.values_close`); free variables are checked at several fixed + rational sample points and must agree at every valid one + c. canonical-string equality as the last resort for unparseable input + +PERCENT is a deliberate two-sided rule: `18\\%` may match `18` (a unit +suffix) or `0.18` (its value), but `18` does not match `0.18\\%`. The +predecessor pinned `18\\%` vs `18` as a known false negative; this engine +closes it, so the sentinel test was retired with a recorded improvement. + +EVERY FAILURE FOLDS TO False, NEVER TO AN EXCEPTION, with one exception that +is the point: `VerifyTimeout` (a BaseException) propagates so a deadline +cannot be swallowed. Unexpected programming errors (TypeError, KeyError, ...) +are also NOT swallowed here -- `_score_one` catches BaseException like the +predecessor's worker, but the ceiling tests run `is_equiv` directly, so a bug +fails a test instead of reading as a weak policy. +""" + +from __future__ import annotations + +import decimal +import hashlib +import random +import re +from fractions import Fraction + +from .expr import ( + Budget, + Parsed, + VerifyError, + evaluate, + free_vars, + is_bare_literal, + parse_expr, + poly_proportional, + to_poly, + values_close, +) +from .extract import match_brace +from .normalize import normalize_answer, normalize_labeled, split_var_prefix, strip_var_prefix + +__all__ = ["is_equiv", "is_readable"] + +_MAX_LEN = 2_000 +_MAX_DEPTH = 6 +_SOFT = (VerifyError, ArithmeticError, ValueError, RecursionError, MemoryError, decimal.DecimalException) + +# Free-variable checks use RANDOMISED rational sample points, seeded from the +# (sorted) expression pair so a verdict is deterministic and symmetric yet no +# fixed grid exists for an adversary (or an accident: `sin(prod/1e9)` vanishing +# at a fixed set, two variables 3 apart sharing a draw) to hit. EVERY variable +# gets its own independent draw at every point. Point 0 is the all-zero point +# and a share of draws are the special values {0, 1, -1}, so `x/x` vs `1` +# (undefined at 0) is caught: an expression undefined where the other is +# defined is NOT equivalent. +_N_POINTS = 24 +_MIN_VALID = 8 +_SPECIAL = (Fraction(0), Fraction(1), Fraction(-1)) + + +def _sample_envs(names: list[str], g: str, p: str) -> list[dict[str, Fraction]]: + a, b = sorted((g, p)) + seed = hashlib.sha256(f"{a}\x00{b}".encode()).digest() + rng = random.Random(seed) + envs: list[dict[str, Fraction]] = [{n: Fraction(0) for n in names}] + for _ in range(_N_POINTS - 1): + env = {} + for n in names: + if rng.random() < 0.12: + env[n] = rng.choice(_SPECIAL) + else: + env[n] = Fraction(rng.randint(-60, 60), rng.randint(1, 13)) + envs.append(env) + return envs + + +_KNOWN_WORDS = re.compile( + r"(?|=") + + +# --------------------------------------------------------------------------- +# String structure helpers +# --------------------------------------------------------------------------- + + +def _split_top(s: str, sep: str) -> list[str]: + """Split on `sep` at bracket depth 0. `sep` is "," or a macro like "\\cup".""" + parts: list[str] = [] + depth = 0 + last = 0 + i = 0 + n = len(s) + while i < n: + c = s[i] + if c == "\\": + if sep != "," and s.startswith(sep, i) and depth == 0: + end = i + len(sep) + if end >= n or not s[end].isalpha(): + parts.append(s[last:i]) + i = end + last = i + continue + nxt = s[i + 1 : i + 2] + if nxt in ("{", "}"): + depth += 1 if nxt == "{" else -1 + i += 2 + continue + if c in "([{": + depth += 1 + elif c in ")]}": + depth -= 1 + elif sep == "," and c == "," and depth == 0: + parts.append(s[last:i]) + last = i + 1 + i += 1 + parts.append(s[last:]) + return [p.strip() for p in parts] + + +def _is_texty(s: str) -> bool: + rest = re.sub(r"\\[A-Za-z]+", " ", s) + rest = _KNOWN_WORDS.sub(" ", rest) + return re.search(r"[A-Za-z]{3,}", rest) is not None + + +def _is_wordlike(s: str) -> bool: + """Letters and spaces only, at least two letters: `No`, `Monday`, `ab`.""" + return re.fullmatch(r"[A-Za-z][A-Za-z ]*", s) is not None and sum(c.isalpha() for c in s) >= 2 + + +def _text_key(s: str) -> str: + return re.sub(r"[^0-9a-z]", "", s.casefold()) + + +def _canon_str(s: str) -> str: + return re.sub(r"\s+|\\left|\\right", "", s) + + +def _expand_pm(elem: str) -> list[str]: + if "\\pm" not in elem and "\\mp" not in elem: + return [elem] + plus = elem.replace("\\pm", "+").replace("\\mp", "-") + minus = elem.replace("\\pm", "-").replace("\\mp", "+") + return [plus.lstrip("+").strip(), minus.strip()] + + +def _list_labeled(s: str) -> list[tuple[str | None, str]]: + """Members of a bare list as (label, value). `x=1, y=2` keeps its labels: + they are part of the answer (`x=1, y=2` is not `x=2, y=1`).""" + out: list[tuple[str | None, str]] = [] + for part in _split_top(s, ","): + if not part: + continue + label, rhs = split_var_prefix(part) + out.extend((label, e) for e in _expand_pm(rhs)) + return out + + +def _list_elems(s: str) -> list[str]: + return [e for _, e in _list_labeled(s)] + + +def _match_labeled(G: list[tuple[str | None, str]], P: list[tuple[str | None, str]], B: Budget, depth: int) -> bool: + """Order-insensitive list match that respects `var=` labels. + + * both sides labelled: a member matches only a member with the SAME label; + * one side labelled by a single variable (`x=1, x=2` vs `1, 2`): a solution + set of that variable, values compared as an unordered set; + * one side labelled by several variables vs a bare list: only the labelled + ORDER can be read as positional (`x=1, y=2` ~ `1, 2`, never `2, 1`); + * anything else partially labelled: not confirmable -> False. + """ + if len(G) != len(P): + return False + lg = {l for l, _ in G} + lp = {l for l, _ in P} + g_lab, p_lab = lg != {None}, lp != {None} + if g_lab and p_lab: + if None in lg or None in lp: + return False + used = [False] * len(P) + for la, a in G: + a_n = normalize_answer(a) + for j, (lb, b) in enumerate(P): + if not used[j] and lb == la and _eq(a_n, normalize_answer(b), B, depth + 1): + used[j] = True + break + else: + return False + return True + if g_lab or p_lab: + lab, bare = (G, P) if g_lab else (P, G) + labels = [l for l, _ in lab] + if None in labels: + return False + if len(set(labels)) == 1: + return _match_unordered([e for _, e in G], [e for _, e in P], B, depth) + if len(set(labels)) != len(labels): + return False + return all( + _eq(normalize_answer(a), normalize_answer(b), B, depth + 1) + for (_, a), (_, b) in zip(G, P) + ) + return _match_unordered([e for _, e in G], [e for _, e in P], B, depth) + + +def _bracketed(s: str) -> tuple[str, str, list[str]] | None: + """`(a,b)` / `[a,b)` -> (open, close, [a,b]) when it is ONE bracket group + with a top-level comma inside; else None.""" + if len(s) < 2 or s[0] not in "([" or s[-1] not in ")]": + return None + # the opener must close at the very end, not earlier: `(a)(b)` is not a tuple + depth = 0 + for i, c in enumerate(s): + if c == "\\": + continue + if c in "([{": + depth += 1 + elif c in ")]}": + depth -= 1 + if depth == 0 and i != len(s) - 1: + return None + inner = s[1:-1] + elems = _split_top(inner, ",") + if len(elems) < 2: + return None + return s[0], s[-1], elems + + +def _braced_set(s: str) -> list[str] | None: + if s.startswith("\\{") and s.endswith("\\}") and len(s) >= 4: + return [e for e in _split_top(s[2:-2], ",") if e != ""] + return None + + +_MATRIX = re.compile( + r"^\\begin\{(?P[pbBvV]?matrix|array)\}(?:\{[^{}]*\})?(?P.*)\\end\{(?P=env)\}$", + re.DOTALL, +) + + +def _matrix(s: str) -> list[list[str]] | None: + m = _MATRIX.match(s.strip()) + if not m: + return None + rows = [r for r in re.split(r"\\\\", m.group("body")) if r.strip()] + return [[c.strip() for c in r.split("&")] for r in rows] + + +# --------------------------------------------------------------------------- +# The ladder +# --------------------------------------------------------------------------- + + +def is_equiv(gold: str | None, pred: str | None) -> bool: + """True iff `pred` denotes the same answer as `gold` (module docstring).""" + if gold is None or pred is None: + return False + lg, g = normalize_labeled(gold) + lp, p = normalize_labeled(pred) + if not g or not p: + return False + if lg is not None and lp is not None and lg != lp: + return False # `x=1` is not `y=1` + if len(g) > _MAX_LEN or len(p) > _MAX_LEN: + return False + try: + return _eq(g, p, Budget(), 0) + except _SOFT: + return False + + +def _eq(g: str, p: str, B: Budget, depth: int) -> bool: + B.tick() + if depth > _MAX_DEPTH: + return False + if g == p: + return True + g, p = g.strip(), p.strip() + if not g or not p: + return False + if g == p: + return True + + # 3. matrices (before the text test: `pmatrix` is a macro, not a word) + mg, mp = _matrix(g), _matrix(p) + if mg is not None or mp is not None: + if mg is None or mp is None: + return False + if len(mg) != len(mp) or any(len(a) != len(b) for a, b in zip(mg, mp)): + return False + return all( + _eq(normalize_answer(x), normalize_answer(y), B, depth + 1) + for ra, rb in zip(mg, mp) + for x, y in zip(ra, rb) + ) + + # 2. text answers + if _is_wordlike(g) and _is_wordlike(p) and _text_key(g) == _text_key(p): + return True + tg, tp = _is_texty(g), _is_texty(p) + if tg or tp: + return tg and tp and _text_key(g) == _text_key(p) + + # 4a. unions + ug, up = _split_top(g, "\\cup"), _split_top(p, "\\cup") + if len(ug) > 1 or len(up) > 1: + return _match_unordered(ug, up, B, depth) + + # 4b. bare lists (order-insensitive); `\pm` expands + lg_, lp_ = _list_labeled(g), _list_labeled(p) + if len(lg_) > 1 or len(lp_) > 1: + return _match_labeled(lg_, lp_, B, depth) + if not lg_ or not lp_: + return False + g, p = lg_[0][1], lp_[0][1] + if g == p: + return True + + # 5. bracketed sequences / sets + bg, bp = _bracketed(g), _bracketed(p) + sg, sp = _braced_set(g), _braced_set(p) + if (bg is None) != (bp is None): + # `x > 3` against `(3, \infty)`: a single-variable inequality IS an interval. + text, seq = (g, p) if bg is None else (p, g) + rel = _split_relation(text, _REL.findall(text)) + interval = _inequality_as_interval(rel) if rel is not None else None + if interval is not None: + return _eq(normalize_answer(interval), normalize_answer(seq), B, depth + 1) + if bg or bp: + if not (bg and bp) or bg[0] != bp[0] or bg[1] != bp[1] or len(bg[2]) != len(bp[2]): + return False + return all( + _eq(normalize_answer(x), normalize_answer(y), B, depth + 1) + for x, y in zip(bg[2], bp[2]) + ) + if sg is not None or sp is not None: + if sg is None or sp is None: + # `\{1\}` against a bare `1`: a one-element set IS its element. + one, other = (sg, p) if sg is not None else (sp, g) + if len(one) == 1: + return _eq(normalize_answer(one[0]), normalize_answer(other), B, depth + 1) + return False + return _match_unordered(sg, sp, B, depth) + + # 6. relations + rg, rp = _REL.findall(g), _REL.findall(p) + if rg or rp: + return _eq_relation(g, p, rg, rp, B, depth) + + # 7. scalars + return _eq_scalar(g, p, B) + + +def _match_unordered(A: list[str], Bl: list[str], B: Budget, depth: int) -> bool: + if len(A) != len(Bl): + return False + used = [False] * len(Bl) + for a in A: + a_n = normalize_answer(a) + for j, b in enumerate(Bl): + if used[j]: + continue + if _eq(a_n, normalize_answer(b), B, depth + 1): + used[j] = True + break + else: + return False + return True + + +# -- relations --------------------------------------------------------------- + + +def _split_relation(s: str, rels: list[str]) -> tuple[str, str, str] | None: + if len(rels) != 1: + return None + m = re.search(re.escape(rels[0]), s) + if not m: + return None + return s[: m.start()].strip(), rels[0], s[m.end() :].strip() + + +def _orient(rel: tuple[str, str, str]) -> tuple[str, str, str]: + lhs, op, rhs = rel + if op == ">": + return rhs, "<", lhs + if op == "\\geq": + return rhs, "\\leq", lhs + return rel + + +def _eq_relation(g: str, p: str, rg: list[str], rp: list[str], B: Budget, depth: int) -> bool: + relg, relp = _split_relation(g, rg), _split_relation(p, rp) + if relg is None and relp is None: + return _canon_str(g) == _canon_str(p) + if relg is None or relp is None: + # `y=2x+3` against a bare `2x+3`: compare the right-hand side. + eq, other = (relg, p) if relg is not None else (relp, g) + assert eq is not None + lhs, op, rhs = eq + if op == "=" and re.fullmatch(r"[A-Za-z]|\\[A-Za-z]+", lhs): + return _eq(normalize_answer(rhs), normalize_answer(other), B, depth + 1) + return False + (lg, og, rg_), (lp, op_, rp_) = relg, relp + if og in ("=", "\\neq") and op_ == og: + # Symmetric relation: polynomial proportionality, else sidewise. + try: + pg = _poly_of_diff(lg, rg_, B) + pp = _poly_of_diff(lp, rp_, B) + except VerifyError: + pg = pp = None + if pg is not None and pp is not None: + if poly_proportional(pg, pp): + return True + return ( + _eq_scalar_safe(lg, lp, B) and _eq_scalar_safe(rg_, rp_, B) + ) or (_eq_scalar_safe(lg, rp_, B) and _eq_scalar_safe(rg_, lp, B)) + og2, op2 = _orient(relg), _orient(relp) + if og2[1] != op2[1]: + return False + return _eq_scalar_safe(og2[0], op2[0], B) and _eq_scalar_safe(og2[2], op2[2], B) + + +def _inequality_as_interval(rel: tuple[str, str, str]) -> str | None: + lhs, op, rhs = _orient_var_left(rel) + if op in ("=", "\\neq") or not re.fullmatch(r"[A-Za-z]", lhs) or re.search(r"[A-Za-z]", rhs.replace("pi", "").replace("\\infty", "")): + return None + return { + "<": f"(-\\infty, {rhs})", + "\\leq": f"(-\\infty, {rhs}]", + ">": f"({rhs}, \\infty)", + "\\geq": f"[{rhs}, \\infty)", + }.get(op) + + +def _orient_var_left(rel: tuple[str, str, str]) -> tuple[str, str, str]: + """Put the single variable on the left: `3 < x` -> `x > 3`.""" + lhs, op, rhs = rel + if re.fullmatch(r"[A-Za-z]", rhs) and not re.fullmatch(r"[A-Za-z]", lhs): + flip = {"<": ">", ">": "<", "\\leq": "\\geq", "\\geq": "\\leq"} + return rhs, flip.get(op, op), lhs + return rel + + +def _poly_of_diff(lhs: str, rhs: str, B: Budget): + from .expr import _padd # internal helper, same package + + a = _poly_or_none(lhs, B) + b = _poly_or_none(rhs, B) + if a is None or b is None: + return None + return _padd(a, b, -1) + + +def _poly_or_none(s: str, B: Budget): + q = to_poly(parse_expr(normalize_answer(s), B).ast, B) + return q + + +def _eq_scalar_safe(a: str, b: str, B: Budget) -> bool: + a_n, b_n = normalize_answer(a), normalize_answer(b) + if not a_n or not b_n: + return False + return _eq_scalar(a_n, b_n, B) + + +# -- scalars ----------------------------------------------------------------- + + +def _percent_variants(s: str) -> list[str]: + if "%" not in s: + return [s] + return [s, s.replace("%", "").strip()] + + +def _eq_scalar(g: str, p: str, B: Budget) -> bool: + for gv in _percent_variants(g): + for pv in _percent_variants(p): + if not gv or not pv: + continue + # `18%` -> `18` is allowed against a bare number, but if BOTH carry + # a percent sign the unstripped pair is the only honest reading. + if ("%" in g and "%" in p) and (gv != g or pv != p): + continue + if _eq_expr(gv, pv, B): + return True + return _canon_str(g) == _canon_str(p) + + +def _eq_expr(g: str, p: str, B: Budget) -> bool: + try: + pg: Parsed = parse_expr(g, B) + pp: Parsed = parse_expr(p, B) + except VerifyError: + return False + # (a) exact symbolic: canonical polynomials + qg, qp = to_poly(pg.ast, B), to_poly(pp.ast, B) + if qg is not None and qp is not None and qg == qp: + return True + # (b) numeric / sample-point evaluation. A decimal literal licenses the + # rounding tolerance only when it IS the whole side (`0.714286`); a decimal + # inside arithmetic (`10000000+0.1-0.1`) is exact arithmetic, not rounding. + names = sorted(free_vars(pg.ast) | free_vars(pp.ast)) + user_rounding = (pg.has_decimal and is_bare_literal(pg.ast)) or ( + pp.has_decimal and is_bare_literal(pp.ast) + ) + if not names: + try: + return values_close( + evaluate(pg.ast, {}, B), evaluate(pp.ast, {}, B), user_rounding=user_rounding + ) + except VerifyError: + return False + valid = 0 + for env in _sample_envs(names, g, p): + try: + vg = evaluate(pg.ast, env, B) + except VerifyError: + vg = None + try: + vp = evaluate(pp.ast, env, B) + except VerifyError: + vp = None + if vg is None and vp is None: + continue # both undefined here (domain): no information + if vg is None or vp is None: + return False # defined on one side only: NOT the same function + if not values_close(vg, vp, user_rounding=user_rounding): + return False + valid += 1 + return valid >= _MIN_VALID + + +# --------------------------------------------------------------------------- +# Readability: "could the engine read this at all?" +# --------------------------------------------------------------------------- + + +def is_readable(answer: str | None) -> bool: + """True iff `answer` parses into something the engine can reason about. + + This is NOT `is_equiv(a, a)`: identical normalised strings short-circuit + to True in `is_equiv` on purpose (a perfect policy that emits the gold + verbatim must score correct even when the notation is exotic -- the + gold-vs-gold ceiling). Readability is the separate question the corpus + instrumentation needs: "is a disagreement evidence about the answer, or + about the instrument's blind spot?" + """ + n = normalize_answer(answer) + if not n or len(n) > _MAX_LEN: + return False + try: + return _readable(n, Budget(), 0) + except _SOFT: + return False + + +def _readable(s: str, B: Budget, depth: int) -> bool: + B.tick() + if depth > _MAX_DEPTH or not s.strip(): + return False + if _is_wordlike(s) or _is_texty(s): + return True + m = _matrix(s) + if m is not None: + return all(_readable(normalize_answer(c), B, depth + 1) for row in m for c in row) + parts = _split_top(s, "\\cup") + if len(parts) > 1: + return all(_readable(normalize_answer(x), B, depth + 1) for x in parts) + elems = _list_elems(s) + if len(elems) > 1: + return all(_readable(normalize_answer(x), B, depth + 1) for x in elems) + if not elems: + return False + s = elems[0] + br = _bracketed(s) + if br is not None: + return all(_readable(normalize_answer(x), B, depth + 1) for x in br[2]) + st = _braced_set(s) + if st is not None: + return all(_readable(normalize_answer(x), B, depth + 1) for x in st) + rels = _REL.findall(s) + if rels: + rel = _split_relation(s, rels) + if rel is None: + return False + return all(_readable(normalize_answer(x), B, depth + 1) for x in (rel[0], rel[2])) + try: + parse_expr(s.replace("%", ""), B) + except VerifyError: + return False + return True diff --git a/code/align/verify/expr.py b/code/align/verify/expr.py new file mode 100644 index 0000000000000000000000000000000000000000..ab4bdc1c78e76d1103bd9204cc860914331e42d0 --- /dev/null +++ b/code/align/verify/expr.py @@ -0,0 +1,1046 @@ +"""A small expression engine: recursive-descent parser, exact/decimal +evaluator, and a tiny multivariate polynomial normaliser. Pure stdlib. + +Replaces the sympy half of the predecessor's verifier. Three jobs: + + parse LaTeX-ish / ASCII text -> AST (tuples). `+ - * / ^`, parentheses, + `\\frac`, `\\sqrt[n]{}`, `\\binom`, `!`, postfix `%`, pi, e, common + functions, IMPLICIT multiplication (`2\\sqrt{3}`, `3x`, `(a)(b)`), + and mixed numbers (`2\\frac{1}{3}` = 7/3, not 2/3). + evaluate AST -> `Fraction` (exact) or `Decimal` (60 digits). Rational + arithmetic stays exact; `sqrt` of a perfect-square rational stays + exact; everything else is high-precision decimal. + to_poly AST -> canonical polynomial dict, or None. Handles multivariate + polynomials with rational coefficients, `sqrt(k)` atoms reduced to + square-free form (`sqrt(12)` = `2*sqrt(3)`, `sqrt(3)^2` = 3), `pi`, + `e`, and `i` with i^2 = -1. + +HOSTILE-INPUT DISCIPLINE (the predecessor's hazards 1-5, re-derived for an +engine we now own). There is no sympy printer to hang in `str()`, but there are +still three ways to wedge a worker, each capped here: + + * unbounded POWER: `9...9 ^ 9...9`, `10**10**10`. Every integer power is + size-checked BEFORE it is computed (`_MAX_BITS`); decimal exponents are + capped; factorial / binomial arguments are capped. + * unbounded WORK: a global `Budget` ticks in the tokenizer, parser, evaluator + and polynomial multiplier; exhausting it raises `VerifyError`. + * unbounded DEPTH: nesting depth is capped (`_MAX_DEPTH`), so `\\sqrt{` x 10^5 + raises `VerifyError`, never `RecursionError`. + +`VerifyTimeout` subclasses BaseException ON PURPOSE, exactly like the exception +it replaces: an `except Exception` in some caller must not be able to swallow a +deadline. `deadline()` arms it via SIGALRM (main thread of the worker process, +which is what `ProcessPoolExecutor` workers are). +""" + +from __future__ import annotations + +import contextlib +import decimal +import math +import re +import signal +import threading +from dataclasses import dataclass +from decimal import Decimal +from fractions import Fraction +from typing import Iterator, Union + +__all__ = [ + "Budget", + "is_bare_literal", + "Parsed", + "VerifyError", + "VerifyTimeout", + "deadline", + "evaluate", + "free_vars", + "parse_expr", + "poly_proportional", + "to_poly", + "values_close", +] + +_PREC = 60 +_MAX_BITS = 60_000 # largest exact integer power we will materialise +_MAX_DEPTH = 60 +_MAX_TOKENS = 4_000 +_MAX_FACT = 3_000 +_MAX_POLY_TERMS = 3_000 +_MAX_POLY_EXP = 64 + +Num = Union[Fraction, Decimal] + +PI = Decimal( + "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899" +) +E = Decimal( + "2.71828182845904523536028747135266249775724709369995957496696762772407663035354759" +) + + +class VerifyError(Exception): + """Input could not be parsed/evaluated within the safety bounds. A SOFT + failure: the caller folds it to 'could not confirm equivalence'.""" + + +class VerifyTimeout(BaseException): + """Deadline expired. BaseException so `except Exception` cannot eat it.""" + + +@contextlib.contextmanager +def deadline(seconds: float) -> Iterator[None]: + """Arm a SIGALRM deadline iff we are the main thread on a platform with + SIGALRM; otherwise a no-op (the `Budget` still bounds the work).""" + if ( + seconds <= 0 + or not hasattr(signal, "setitimer") + or threading.current_thread() is not threading.main_thread() + ): + yield + return + + def _fire(signum, frame): # pragma: no cover - exercised via timing only + raise VerifyTimeout() + + old = signal.signal(signal.SIGALRM, _fire) + signal.setitimer(signal.ITIMER_REAL, float(seconds)) + try: + yield + finally: + signal.setitimer(signal.ITIMER_REAL, 0.0) + signal.signal(signal.SIGALRM, old) + + +class Budget: + """Global work counter for one comparison.""" + + __slots__ = ("left",) + + def __init__(self, n: int = 300_000): + self.left = n + + def tick(self, k: int = 1) -> None: + self.left -= k + if self.left < 0: + raise VerifyError("work budget exhausted") + + +# --------------------------------------------------------------------------- +# Tokenizer +# --------------------------------------------------------------------------- + +_TOK_RE = re.compile( + r""" + (?P\s+) + | (?P(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?) + | (?P\\[A-Za-z]+|\\.) + | (?P[A-Za-z]+) + | (?P\*\*|[-+*/^_!%(){}\[\]|,=<>]) + """, + re.VERBOSE, +) + +_FUNCS = { + "sin", "cos", "tan", "cot", "sec", "csc", "ln", "log", "exp", "lg", +} +_WORD_NAMES = sorted(_FUNCS | {"pi", "sqrt"}, key=len, reverse=True) +_GREEK = { + "theta", "alpha", "beta", "gamma", "delta", "phi", "lambda", "mu", "sigma", + "omega", "rho", "tau", "epsilon", "varphi", "vartheta", "psi", "eta", "kappa", + "nu", "xi", "zeta", "chi", +} +_STRUCT_CMDS = {"frac", "sqrt", "binom", "dbinom", "tbinom"} + + +@dataclass +class _Tok: + kind: str # num | var | const | fn | sqrt | frac | binom | op + text: str + sp: bool = False # whitespace precedes + + +def _tokenize(s: str, B: Budget) -> list[_Tok]: + if len(s) > 2_000: + raise VerifyError("expression too long") + toks: list[_Tok] = [] + i = 0 + sp = False + n = len(s) + while i < n: + B.tick() + m = _TOK_RE.match(s, i) + if not m: + raise VerifyError(f"bad character at {i}") + i = m.end() + kind = m.lastgroup + text = m.group() + if kind == "space": + sp = True + continue + if kind == "num": + toks.append(_Tok("num", text, sp)) + elif kind == "cmd": + name = text[1:] + if name in _STRUCT_CMDS: + toks.append(_Tok({"dbinom": "binom", "tbinom": "binom"}.get(name, name), text, sp)) + elif name == "pi": + toks.append(_Tok("const", "pi", sp)) + elif name in ("cdot", "times", "ast"): + toks.append(_Tok("op", "*", sp)) + elif name == "div": + toks.append(_Tok("op", "/", sp)) + elif name in _FUNCS or name in ("arcsin", "arccos", "arctan"): + toks.append(_Tok("fn", name, sp)) + elif name in _GREEK: + toks.append(_Tok("var", name, sp)) + elif name in ("{", "}"): + # literal braces never occur inside a scalar expression + raise VerifyError("literal brace in expression") + else: + raise VerifyError(f"unsupported macro {text}") + elif kind == "word": + w = text + first = True + while w: + for name in _WORD_NAMES: + if w.startswith(name): + if name == "pi": + toks.append(_Tok("const", "pi", sp and first)) + elif name == "sqrt": + toks.append(_Tok("sqrt", "sqrt", sp and first)) + else: + toks.append(_Tok("fn", name, sp and first)) + w = w[len(name) :] + break + else: + c = w[0] + toks.append(_Tok("const" if c == "e" else "var", c, sp and first)) + w = w[1:] + first = False + else: + op = "^" if text == "**" else text + toks.append(_Tok("op", op, sp)) + sp = False + if len(toks) > _MAX_TOKENS: + raise VerifyError("too many tokens") + return toks + + +# --------------------------------------------------------------------------- +# Parser +# --------------------------------------------------------------------------- + +Node = tuple + + +@dataclass +class Parsed: + ast: Node + has_decimal: bool # a decimal-point literal appeared (user may have rounded) + + +class _Parser: + def __init__(self, toks: list[_Tok], B: Budget): + self.t = toks + self.i = 0 + self.B = B + self.depth = 0 + self.has_decimal = False + + # -- plumbing --------------------------------------------------------- + def _peek(self) -> _Tok | None: + return self.t[self.i] if self.i < len(self.t) else None + + def _next(self) -> _Tok: + if self.i >= len(self.t): + raise VerifyError("unexpected end") + tok = self.t[self.i] + self.i += 1 + return tok + + def _is_op(self, tok: _Tok | None, *texts: str) -> bool: + return tok is not None and tok.kind == "op" and tok.text in texts + + def _expect(self, text: str) -> None: + tok = self._next() + if not (tok.kind == "op" and tok.text == text): + raise VerifyError(f"expected {text!r}") + + def _enter(self) -> None: + self.B.tick() + self.depth += 1 + if self.depth > _MAX_DEPTH: + raise VerifyError("nesting too deep") + + def _leave(self) -> None: + self.depth -= 1 + + # -- grammar ---------------------------------------------------------- + def parse(self) -> Node: + if not self.t: + raise VerifyError("empty") + node = self._expr() + if self.i != len(self.t): + raise VerifyError("trailing tokens") + return node + + def _expr(self) -> Node: + self._enter() + node = self._term() + while True: + tok = self._peek() + if self._is_op(tok, "+", "-"): + self.i += 1 + rhs = self._term() + node = ("add" if tok.text == "+" else "sub", node, rhs) + else: + break + self._leave() + return node + + def _starts_atom(self, tok: _Tok) -> bool: + if tok.kind in ("num", "var", "const", "fn", "sqrt", "frac", "binom"): + return True + return tok.kind == "op" and tok.text in ("(", "[", "{") + + def _term(self) -> Node: + node = self._unary() + while True: + tok = self._peek() + if tok is None: + break + if self._is_op(tok, "*", "/"): + self.i += 1 + rhs = self._unary() + node = ("mul" if tok.text == "*" else "div", node, rhs) + elif self._starts_atom(tok): + prev = self.t[self.i - 1] + if prev.kind == "num" and tok.kind == "num": + raise VerifyError("adjacent numbers") + rhs = self._power() + node = ("mul", node, rhs) + else: + break + return node + + def _unary(self) -> Node: + tok = self._peek() + if self._is_op(tok, "-"): + self.i += 1 + self._enter() + inner = self._unary() + self._leave() + return ("neg", inner) + if self._is_op(tok, "+"): + self.i += 1 + return self._unary() + return self._power() + + def _power(self) -> Node: + base = self._postfix() + tok = self._peek() + if self._is_op(tok, "^"): + self.i += 1 + self._enter() + exp = self._exp_operand() + self._leave() + return ("pow", base, exp) + return base + + def _exp_operand(self) -> Node: + tok = self._peek() + if tok is None: + raise VerifyError("dangling ^") + if self._is_op(tok, "{"): + self.i += 1 + node = self._expr() + self._expect("}") + return node + if self._is_op(tok, "-"): + self.i += 1 + return ("neg", self._exp_operand()) + if self._is_op(tok, "+"): + self.i += 1 + return self._exp_operand() + return self._power() + + def _postfix(self) -> Node: + node = self._primary() + while True: + tok = self._peek() + if self._is_op(tok, "!"): + self.i += 1 + node = ("fact", node) + elif self._is_op(tok, "%"): + self.i += 1 + node = ("div", node, ("num", Fraction(100))) + else: + break + return node + + def _group_arg(self) -> Node: + """A LaTeX macro argument: `{expr}` or ONE token (`\\frac12`, `\\sqrt2`).""" + tok = self._peek() + if tok is None: + raise VerifyError("missing argument") + if self._is_op(tok, "{"): + self.i += 1 + node = self._expr() + self._expect("}") + return node + if tok.kind == "num": + if "." not in tok.text and len(tok.text) > 1 and tok.text.isdigit(): + # `\frac12`: take ONE digit, leave the rest in the stream. + tok.text, head = tok.text[1:], tok.text[0] + return ("num", Fraction(int(head))) + self.i += 1 + return self._num_node(tok.text) + if tok.kind in ("var", "const"): + self.i += 1 + return ("const", tok.text) if tok.kind == "const" else ("var", tok.text) + if tok.kind in ("frac", "sqrt", "binom", "fn"): + return self._primary() + raise VerifyError("bad macro argument") + + def _num_node(self, text: str) -> Node: + if len(text) > 400: + raise VerifyError("numeral too long") + mant, exp = text, 0 + m = re.fullmatch(r"(.*?)[eE]([+-]?\d+)", text) + if m: + # Scientific literal `1e-3` = 0.001. It is NOT `1*e-3` (Euler's e): + # reading it that way made `e-3` and `1e-3` the same answer. + mant, exp = m.group(1), int(m.group(2)) + if abs(exp) > 300: + raise VerifyError("exponent too large") + if "." in mant and mant.split(".", 1)[1].strip("0"): + self.has_decimal = True + val = Fraction(mant if not mant.endswith(".") else mant[:-1]) + if exp: + val *= Fraction(10) ** exp + return ("num", val) + + def _primary(self) -> Node: + tok = self._next() + self.B.tick() + k = tok.kind + if k == "num": + node = self._num_node(tok.text) + nxt = self._peek() + # Mixed number: `2\frac{1}{3}` is 2 + 1/3 when the lead is an + # integer literal and the fraction is integer/integer. + if ( + nxt is not None + and nxt.kind == "frac" + and "." not in tok.text + and not self._is_op(self._prev_nonspace(), "^") + ): + frac = self._primary() + if frac[0] == "div" and frac[1][0] == "num" and frac[2][0] == "num": + return ("add", node, frac) + return ("mul", node, frac) + return node + if k == "op": + if tok.text in ("(", "["): + node = self._expr() + close = self._next() + want = ")" if tok.text == "(" else "]" + if not (close.kind == "op" and close.text == want): + raise VerifyError("unbalanced bracket") + return node + if tok.text == "{": + node = self._expr() + self._expect("}") + return node + if tok.text == "|": + node = self._expr() + self._expect("|") + return ("abs", node) + raise VerifyError(f"unexpected {tok.text!r}") + if k == "const": + return ("const", tok.text) + if k == "var": + name = tok.text + nxt = self._peek() + if self._is_op(nxt, "_"): + self.i += 1 + name += "_" + self._subscript() + return ("var", name) + if k == "frac": + a = self._group_arg() + b = self._group_arg() + return ("div", a, b) + if k == "binom": + a = self._group_arg() + b = self._group_arg() + return ("binom", a, b) + if k == "sqrt": + n_node = None + if self._is_op(self._peek(), "["): + self.i += 1 + n_node = self._expr() + self._expect("]") + tok2 = self._peek() + if self._is_op(tok2, "("): + self.i += 1 + arg = self._expr() + self._expect(")") + else: + arg = self._group_arg() + return ("sqrt", arg, n_node) + if k == "fn": + return self._function(tok.text) + raise VerifyError("bad token") + + def _prev_nonspace(self) -> _Tok | None: + return self.t[self.i - 2] if self.i >= 2 else None + + def _subscript(self) -> str: + tok = self._next() + if self._is_op(tok, "{"): + parts: list[str] = [] + while True: + t2 = self._next() + if self._is_op(t2, "}"): + break + parts.append(t2.text) + if len(parts) > 20: + raise VerifyError("subscript too long") + return "".join(parts) + return tok.text + + def _function(self, name: str) -> Node: + base: Node | None = None + if self._is_op(self._peek(), "_"): + self.i += 1 + base = self._group_arg() + exp: Node | None = None + if self._is_op(self._peek(), "^"): + self.i += 1 + exp = self._exp_operand() + if self._is_op(self._peek(), "("): + self.i += 1 + arg = self._expr() + self._expect(")") + else: + arg = self._power() + node: Node = ("fn", name, arg, base) + if exp is not None: + node = ("pow", node, exp) + return node + + +def parse_expr(s: str, B: Budget | None = None) -> Parsed: + B = B or Budget() + toks = _tokenize(s, B) + p = _Parser(toks, B) + ast = p.parse() + return Parsed(ast, p.has_decimal) + + +def is_bare_literal(node: Node) -> bool: + """True iff the whole expression is ONE numeric literal (optionally signed + or `%`): the only shape where a decimal can be a human ROUNDING of a value. + `10000000+0.1-0.1` is not a rounded number, it is arithmetic.""" + while True: + k = node[0] + if k == "num": + return True + if k == "neg": + node = node[1] + elif k == "div" and node[2] == ("num", Fraction(100)): + node = node[1] + else: + return False + + +def free_vars(node: Node, acc: set[str] | None = None) -> set[str]: + acc = set() if acc is None else acc + kind = node[0] + if kind == "var": + acc.add(node[1]) + elif kind in ("num", "const"): + pass + elif kind in ("neg", "fact", "abs"): + free_vars(node[1], acc) + elif kind == "sqrt": + free_vars(node[1], acc) + if node[2] is not None: + free_vars(node[2], acc) + elif kind == "fn": + free_vars(node[2], acc) + if node[3] is not None: + free_vars(node[3], acc) + else: + free_vars(node[1], acc) + free_vars(node[2], acc) + return acc + + +# --------------------------------------------------------------------------- +# Evaluation +# --------------------------------------------------------------------------- + + +def _ctx() -> decimal.Context: + return decimal.Context( + prec=_PREC, + rounding=decimal.ROUND_HALF_EVEN, + Emax=100_000, + Emin=-100_000, + traps=[decimal.InvalidOperation, decimal.DivisionByZero, decimal.Overflow], + ) + + +def _dec(x: Num) -> Decimal: + if isinstance(x, Decimal): + return x + return Decimal(x.numerator) / Decimal(x.denominator) + + +def _check(x: Num) -> Num: + if isinstance(x, Decimal): + if not x.is_finite(): + raise VerifyError("non-finite") + elif x.numerator.bit_length() > 4 * _MAX_BITS or x.denominator.bit_length() > 4 * _MAX_BITS: + raise VerifyError("number too large") + return x + + +def _iroot(n: int, k: int) -> int | None: + """Exact integer k-th root of n >= 0, or None.""" + if n < 0: + return None + if n < 2: + return n + if k == 2: + r = math.isqrt(n) + return r if r * r == n else None + lo, hi = 1, 1 << (n.bit_length() // k + 1) + while lo < hi: + mid = (lo + hi) // 2 + if mid**k < n: + lo = mid + 1 + else: + hi = mid + return lo if lo**k == n else None + + +def _frac_root(x: Fraction, k: int) -> Fraction | None: + if x < 0: + return None + a, b = _iroot(x.numerator, k), _iroot(x.denominator, k) + if a is None or b is None: + return None + return Fraction(a, b) + + +def _int_pow(x: Fraction, n: int) -> Fraction: + if n == 0: + return Fraction(1) + size = max(x.numerator.bit_length(), x.denominator.bit_length(), 1) + if size * abs(n) > _MAX_BITS: + raise VerifyError("power too large") + if n < 0: + if x == 0: + raise VerifyError("0 ** negative") + return Fraction(1) / (x**-n) + return x**n + + +def _pow(a: Num, b: Num) -> Num: + if isinstance(b, Fraction) and b.denominator == 1: + n = int(b) + if isinstance(a, Fraction): + return _int_pow(a, n) + if abs(n) > 10_000: + raise VerifyError("exponent too large") + if a == 0 and n < 0: + raise VerifyError("0 ** negative") + return a**n + if isinstance(a, Fraction) and isinstance(b, Fraction): + if a < 0: + raise VerifyError("negative base, fractional exponent") + if b.denominator <= 64 and abs(b.numerator) <= 10_000: + r = _frac_root(a, b.denominator) + if r is not None: + return _int_pow(r, b.numerator) + da, db = _dec(a), _dec(b) + if da < 0: + raise VerifyError("negative base, non-integer exponent") + if abs(db) > 10_000: + raise VerifyError("exponent too large") + if da == 0: + if db < 0: + raise VerifyError("0 ** negative") + return Fraction(0) + return da**db + + +def _sqrt(a: Num, n: int) -> Num: + if n < 2 or n > 64: + raise VerifyError("bad root index") + if isinstance(a, Fraction): + if a < 0: + if n % 2 == 1: + r = _sqrt(-a, n) + return -r if isinstance(r, Fraction) else -r + raise VerifyError("even root of negative") + r = _frac_root(a, n) + if r is not None: + return r + d = _dec(a) + else: + d = a + if d < 0: + if n % 2 == 1: + return -_sqrt(-d, n) + raise VerifyError("even root of negative") + if n == 2: + return d.sqrt() + return d ** (Decimal(1) / Decimal(n)) + + +def _reduce_angle(x: Decimal) -> Decimal: + if abs(x) > Decimal(10) ** 6: + raise VerifyError("angle too large") + two_pi = 2 * PI + x = x % two_pi + return x + + +def _sin(x: Decimal) -> Decimal: + x = _reduce_angle(x) + term, total, k = x, x, 1 + eps = Decimal(10) ** (-(_PREC + 5)) + while abs(term) > eps and k < 400: + term = -term * x * x / ((2 * k) * (2 * k + 1)) + total += term + k += 1 + return total + + +def _cos(x: Decimal) -> Decimal: + x = _reduce_angle(x) + term, total, k = Decimal(1), Decimal(1), 1 + eps = Decimal(10) ** (-(_PREC + 5)) + while abs(term) > eps and k < 400: + term = -term * x * x / ((2 * k - 1) * (2 * k)) + total += term + k += 1 + return total + + +def _fn(name: str, a: Num, base: Num | None) -> Num: + if base is not None: + # A base is meaningful (and validated) ONLY for log, and BEFORE any + # shortcut: `log_0(1)` and `log_{-2}(1)` are undefined, not 0. + if name != "log": + raise VerifyError("base on a non-log function") + db0 = _dec(base) + if db0 <= 0 or db0 == 1: + raise VerifyError("log base") + if name in ("log", "lg", "ln"): + if isinstance(a, Fraction): + if a <= 0: + raise VerifyError("log domain") + if a == 1: + return Fraction(0) + elif a <= 0: + raise VerifyError("log domain") + d = _dec(a) + if name == "ln": + return d.ln() + if base is None: + return d.log10() + db = _dec(base) + if db <= 0 or db == 1: + raise VerifyError("log base") + return d.ln() / db.ln() + if name == "exp": + if isinstance(a, Fraction) and a == 0: + return Fraction(1) + d = _dec(a) + if abs(d) > 1000: + raise VerifyError("exp too large") + return d.exp() + if isinstance(a, Fraction) and a == 0 and name in ("sin", "tan", "arcsin", "arctan"): + return Fraction(0) + if isinstance(a, Fraction) and a == 0 and name == "cos": + return Fraction(1) + d = _dec(a) + if name == "sin": + return _sin(d) + if name == "cos": + return _cos(d) + s, c = _sin(d), _cos(d) + if name == "tan": + if abs(c) < Decimal(10) ** -30: + raise VerifyError("tan pole") + return s / c + if name == "cot": + if abs(s) < Decimal(10) ** -30: + raise VerifyError("cot pole") + return c / s + if name == "sec": + if abs(c) < Decimal(10) ** -30: + raise VerifyError("sec pole") + return 1 / c + if name == "csc": + if abs(s) < Decimal(10) ** -30: + raise VerifyError("csc pole") + return 1 / s + raise VerifyError(f"unsupported function {name}") + + +def _ev(node: Node, env: dict[str, Num], B: Budget) -> Num: + B.tick() + k = node[0] + if k == "num": + return node[1] + if k == "const": + return PI if node[1] == "pi" else E + if k == "var": + if node[1] not in env: + raise VerifyError(f"free variable {node[1]}") + return env[node[1]] + if k == "neg": + return -_ev(node[1], env, B) + if k == "abs": + return abs(_ev(node[1], env, B)) + if k in ("add", "sub", "mul"): + a, b = _ev(node[1], env, B), _ev(node[2], env, B) + if isinstance(a, Fraction) and isinstance(b, Fraction): + r = a + b if k == "add" else a - b if k == "sub" else a * b + else: + da, db = _dec(a), _dec(b) + r = da + db if k == "add" else da - db if k == "sub" else da * db + return _check(r) + if k == "div": + a, b = _ev(node[1], env, B), _ev(node[2], env, B) + if b == 0: + raise VerifyError("division by zero") + if isinstance(a, Fraction) and isinstance(b, Fraction): + return _check(a / b) + return _check(_dec(a) / _dec(b)) + if k == "pow": + return _check(_pow(_ev(node[1], env, B), _ev(node[2], env, B))) + if k == "sqrt": + n = 2 + if node[2] is not None: + nv = _ev(node[2], env, B) + if not (isinstance(nv, Fraction) and nv.denominator == 1): + raise VerifyError("root index must be an integer") + n = int(nv) + return _check(_sqrt(_ev(node[1], env, B), n)) + if k == "fact": + a = _ev(node[1], env, B) + if not (isinstance(a, Fraction) and a.denominator == 1 and 0 <= a <= _MAX_FACT): + raise VerifyError("factorial domain") + return Fraction(math.factorial(int(a))) + if k == "binom": + a, b = _ev(node[1], env, B), _ev(node[2], env, B) + if not ( + isinstance(a, Fraction) + and isinstance(b, Fraction) + and a.denominator == 1 + and b.denominator == 1 + and 0 <= b <= a <= _MAX_FACT + ): + raise VerifyError("binom domain") + return Fraction(math.comb(int(a), int(b))) + if k == "fn": + a = _ev(node[2], env, B) + base = _ev(node[3], env, B) if node[3] is not None else None + return _check(_fn(node[1], a, base)) + raise VerifyError(f"unknown node {k}") + + +def evaluate(node: Node, env: dict[str, Num] | None = None, B: Budget | None = None) -> Num: + """Evaluate under a fixed 60-digit decimal context.""" + with decimal.localcontext(_ctx()): + return _ev(node, env or {}, B or Budget()) + + +def values_close(a: Num, b: Num, *, user_rounding: bool) -> bool: + """Equality of two evaluated numbers. + + Both exact and no rounded literal -> exact equality, period. Otherwise + RELATIVE closeness: 1e-6 when one side carried a decimal literal with a + nonzero fractional part (a human or model rounding, as in `0.714286` vs + `5/7`; `5.0` does not count), else 1e-12 (floating noise between + two exact irrational computations). Relative, never absolute: the + predecessor's `float_rounding=6` made every value below 1e-6 mutually + equivalent (hazard 7: 1/2004! "equals" 1/2006!). + """ + if isinstance(a, Fraction) and isinstance(b, Fraction) and not user_rounding: + return a == b + with decimal.localcontext(_ctx()): + da, db = _dec(a), _dec(b) + if da == db: + return True + denom = max(abs(da), abs(db)) + if denom == 0: + return True + tol = Decimal("1e-6") if user_rounding else Decimal("1e-12") + return abs(da - db) / denom < tol + + +# --------------------------------------------------------------------------- +# Polynomial normaliser +# --------------------------------------------------------------------------- + +Mono = tuple # sorted tuple of (symbol, exponent) +Poly = dict + + +def _sqfree(k: int, B: Budget) -> tuple[int, int]: + """k = out^2 * sf with sf square-free (trial division, bounded).""" + if k < 1: + raise VerifyError("sqfree domain") + out, sf, d = 1, k, 2 + while d * d <= sf and d <= 31_623: + B.tick() + dd = d * d + while sf % dd == 0: + sf //= dd + out *= d + d += 1 if d == 2 else 2 + return out, sf + + +def _norm_mono(mono: dict[str, int]) -> tuple[Fraction, Mono]: + """Apply sqrt(k)^2 = k and i^2 = -1; return (coefficient factor, monomial).""" + coef = Fraction(1) + out: list[tuple[str, int]] = [] + for sym, e in mono.items(): + if e == 0: + continue + if sym.startswith("sqrt:"): + k = int(sym[5:]) + q, r = divmod(e, 2) + coef *= Fraction(k) ** q + e = r + elif sym == "i": + # i^4 = 1, i^2 = -1, i^3 = -i. + r = e % 4 + if r in (2, 3): + coef = -coef + e = 1 if r in (1, 3) else 0 + if e: + out.append((sym, e)) + return coef, tuple(sorted(out)) + + +def _padd(p: Poly, q: Poly, sign: int = 1) -> Poly: + r = dict(p) + for m, c in q.items(): + v = r.get(m, 0) + sign * c + if v == 0: + r.pop(m, None) + else: + r[m] = v + return r + + +def _pmul(p: Poly, q: Poly, B: Budget) -> Poly: + if len(p) * len(q) > _MAX_POLY_TERMS * 4: + raise VerifyError("polynomial too large") + r: Poly = {} + for m1, c1 in p.items(): + for m2, c2 in q.items(): + B.tick() + acc: dict[str, int] = dict(m1) + for s, e in m2: + acc[s] = acc.get(s, 0) + e + f, m = _norm_mono(acc) + v = r.get(m, 0) + c1 * c2 * f + if v == 0: + r.pop(m, None) + else: + r[m] = v + if len(r) > _MAX_POLY_TERMS: + raise VerifyError("polynomial too large") + return r + + +def _pconst(p: Poly) -> Fraction | None: + if not p: + return Fraction(0) + if len(p) == 1 and () in p: + return p[()] + return None + + +def to_poly(node: Node, B: Budget | None = None) -> Poly | None: + """Canonical polynomial of `node`, or None if it is not one.""" + B = B or Budget() + try: + return _poly(node, B) + except _NotPoly: + return None + + +class _NotPoly(Exception): + pass + + +def _poly(node: Node, B: Budget) -> Poly: + B.tick() + k = node[0] + if k == "num": + return {(): node[1]} if node[1] != 0 else {} + if k == "const": + return {((node[1], 1),): Fraction(1)} + if k == "var": + return {((node[1], 1),): Fraction(1)} + if k == "neg": + return {m: -c for m, c in _poly(node[1], B).items()} + if k in ("add", "sub"): + return _padd(_poly(node[1], B), _poly(node[2], B), 1 if k == "add" else -1) + if k == "mul": + return _pmul(_poly(node[1], B), _poly(node[2], B), B) + if k == "div": + d = _pconst(_poly(node[2], B)) + if d is None or d == 0: + raise _NotPoly + return {m: c / d for m, c in _poly(node[1], B).items()} + if k == "pow": + e = _pconst(_poly(node[2], B)) + if e is None or e.denominator != 1 or not (0 <= e <= _MAX_POLY_EXP): + raise _NotPoly + base = _poly(node[1], B) + result: Poly = {(): Fraction(1)} + for _ in range(int(e)): + result = _pmul(result, base, B) + return result + if k == "sqrt": + n = 2 + if node[2] is not None: + nv = _pconst(_poly(node[2], B)) + if nv is None or nv != 2: + raise _NotPoly + c = _pconst(_poly(node[1], B)) + if c is None or c < 0: + raise _NotPoly + if c == 0: + return {} + p, q = c.numerator, c.denominator + out, sf = _sqfree(p * q, B) + coef = Fraction(out, q) + if sf == 1: + return {(): coef} + return {((f"sqrt:{sf}", 1),): coef} + if k in ("fact", "binom"): + raise _NotPoly # numeric path handles these exactly + raise _NotPoly + + +def poly_proportional(p: Poly, q: Poly) -> bool: + """p = c * q for a nonzero rational c (both nonzero).""" + if not p or not q or p.keys() != q.keys(): + return False + m0 = next(iter(p)) + ratio = p[m0] / q[m0] + return all(p[m] == ratio * q[m] for m in p) diff --git a/code/align/verify/extract.py b/code/align/verify/extract.py new file mode 100644 index 0000000000000000000000000000000000000000..11dcff756fc724c04c34cddd126b0a8f07dd8bb7 --- /dev/null +++ b/code/align/verify/extract.py @@ -0,0 +1,200 @@ +"""Final-answer extraction from model text and gold strings. + +Replaces the extraction half of `math_verify.parse`. Pure stdlib. + +Priority, highest first (the order is a contract, tested): + + 1. the LAST `\\boxed{...}` / `\\fbox{...}` with BRACE BALANCING. Balancing is + not optional: `\\boxed{\\frac{1}{2}}` and `\\boxed{\\{1,2\\}}` contain + braces, and a regex like `\\boxed\\{([^}]*)\\}` truncates both at the first + `}` -- a silent false negative on exactly the LaTeX-heavy answers a + stronger policy emits more often. Escaped braces (`\\{`, `\\}`) are + LaTeX literals and do not open or close a group. + 2. GSM8K's `#### 42` terminator (last occurrence). + 3. "final answer is ...", "the answer is ...", "Final Answer: ..." (last). + 4. FALLBACK: the last number in the text. + +The fallback is deliberately last and deliberately weak: a model that never +states an answer but happens to end on a number is being read charitably, not +verified. `extract_final_answer` returns None only when no number exists at +all, which is the NO_ANSWER signal upstream (a different fact from a wrong +answer). +""" + +from __future__ import annotations + +import re + +__all__ = [ + "extract_boxed", + "extract_gold_answer", + "extract_final_answer", + "last_number", + "match_brace", +] + +_BOXED_OPEN = re.compile(r"\\(?:boxed|fbox)\s*\{") +_BOXED_BARE = re.compile(r"\\boxed\s+([^\s${}]+)") + + +def match_brace(s: str, open_idx: int) -> int: + """Index of the `}` closing the `{` at `open_idx`, or -1 if unbalanced. + + Skips backslash-escaped characters so `\\{` / `\\}` / `\\\\` never change + depth. O(n); no recursion, so a hostile 10^5-deep brace string cannot + blow the stack. + """ + if open_idx >= len(s) or s[open_idx] != "{": + return -1 + depth = 0 + j = open_idx + n = len(s) + while j < n: + c = s[j] + if c == "\\": + j += 2 + continue + if c == "{": + depth += 1 + elif c == "}": + depth -= 1 + if depth == 0: + return j + j += 1 + return -1 + + +def extract_boxed(text: str | None) -> str | None: + """Contents of the LAST balanced `\\boxed{...}` / `\\fbox{...}`, else None. + + "Last" because chain-of-thought often boxes an intermediate value; the + committed answer is the final one. An unbalanced trailing box (a truncated + generation) is skipped in favour of the previous balanced one. + """ + if not text: + return None + opens = list(_BOXED_OPEN.finditer(text)) + for m in reversed(opens): + close = match_brace(text, m.end() - 1) + if close != -1: + return text[m.end() : close] + # `\boxed 5` (no braces) is legal LaTeX and appears in a few corpora. + bare = list(_BOXED_BARE.finditer(text)) + if bare: + return bare[-1].group(1) + return None + + +_HASHES = re.compile(r"####\s*([^\n]+)") +# "final answer is", "the answer is", "Final Answer:", "answer = ". Last wins. +_ANSWER_IS = re.compile( + r"(?:final\s+answer|answer)\s*(?:is|:|=)\s*", + re.IGNORECASE, +) +_NUMBER = re.compile(r"-?\d[\d,]*(?:\.\d+)?(?:\s*/\s*\d+)?|-?\.\d+") +_INLINE_MATH = re.compile(r"\$\$?(.+?)\$\$?|\\\((.+?)\\\)|\\\[(.+?)\\\]", re.DOTALL) + + +def _clean_tail(s: str) -> str: + """Trim presentation noise from a free-text answer span.""" + s = s.strip() + # Markdown emphasis around the answer. + s = s.strip("*_` ") + s = s.lstrip(":").strip() + # A leading inline-math span wins over the prose that follows it. + m = _INLINE_MATH.match(s) + if m: + s = next(g for g in m.groups() if g is not None) + s = s.strip().strip("$").strip() + # Cut at a sentence terminator that is NOT a decimal point: a period + # followed by whitespace+uppercase or end of string. + cut = re.search(r"\.(?=\s+[A-Z]|\s*$)", s) + if cut: + s = s[: cut.start()] + return s.strip().rstrip(".").strip() + + +def last_number(text: str | None) -> str | None: + """The last number-looking token, thousands separators removed.""" + if not text: + return None + hits = _NUMBER.findall(text) + if not hits: + return None + tok = hits[-1].replace(" ", "") + if re.fullmatch(r"-?\d{1,3}(?:,\d{3})+(?:\.\d+)?", tok): + tok = tok.replace(",", "") + return tok.rstrip(",") + + +def extract_final_answer(text: str | None) -> str | None: + """Best single answer string from free model text (see module docstring).""" + if text is None: + return None + text = str(text) + if not text.strip(): + return None + + boxed = extract_boxed(text) + if boxed is not None and boxed.strip(): + return boxed.strip() + + hashes = _HASHES.findall(text) + if hashes: + tail = _clean_tail(hashes[-1]) + if tail: + return tail + + last = None + for last in _ANSWER_IS.finditer(text): + pass + if last is not None: + rest = text[last.end() :].split("\n", 1)[0] + tail = _clean_tail(rest) + if tail: + return tail + + # A text that is ALREADY just math (`\\frac{3}{4}`, `(1, 2)`, `x=5`) is an + # answer, not prose. Without this the last-number fallback reads a bare + # `\\frac{3}{4}` as "4" -- the gold-vs-gold ceiling caught exactly that. + if _looks_like_bare_answer(text): + return _clean_tail(text.strip().strip("$")) or last_number(text) + + return last_number(text) + + +def _looks_like_bare_answer(text: str) -> bool: + t = text.strip() + if not t or "\n" in t or len(t) > 200: + return False + t = re.sub(r"\\(?:begin|end)\{[^{}]*\}", " ", t) # matrix environments + t = re.sub(r"\\[A-Za-z]+", " ", t) # LaTeX macros are not words + t = re.sub(r"\b(?:pi|sin|cos|tan|cot|sec|csc|ln|log|exp|sqrt)\b", " ", t) + return re.search(r"[A-Za-z]{3,}", t) is None and re.search(r"\d", t) is not None + + +def extract_gold_answer(gold: str | None) -> str | None: + """The answer inside a GOLD string. + + A gold is already an answer, not prose, so the prose heuristics must NOT + run on it. This is the exact bug the gold-vs-gold ceiling caught on the + first run: `extract_final_answer("\\frac{3}{4}")` falls through to the + last-number fallback and returns "4", so every unboxed fractional gold + "failed to verify against itself" -- the 0/100 incident in miniature. + Order: a `\\boxed{}` wins (golds are sometimes stored boxed), then a + GSM8K `#### n` terminator, else the whole string, verbatim. + """ + if gold is None: + return None + g = str(gold) + if not g.strip(): + return None + boxed = extract_boxed(g) + if boxed is not None and boxed.strip(): + return boxed.strip() + hashes = _HASHES.findall(g) + if hashes: + tail = _clean_tail(hashes[-1]) + if tail: + return tail + return g.strip() diff --git a/code/align/verify/lean/__init__.py b/code/align/verify/lean/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..ccb3046145b3ec908fb61378bda1fe7f86c0dab0 --- /dev/null +++ b/code/align/verify/lean/__init__.py @@ -0,0 +1,73 @@ +"""`align.verify.lean`: a strict Lean 4 verifier (reward + evaluator), stdlib only. + +The Lean toolchain itself is an external binary installed by `scripts/lean_setup.sh` +(docs/DEPENDENCY_POLICY.md, "Lean toolchain"); nothing here imports anything outside the +standard library. See docs/LEAN_VERIFIER.md for the pin, the measurements and the +pre-registered ceiling test. + + toolchain.py locate the install, build the sanitized child environment + repl_pool.py persistent REPL workers, hard memory/time/output limits, watchdog + strict.py lexical gate + compile + Lean-side audit (axioms, statement bridge, ...) + recheck.py opt-in independent second check in a fresh REPL (docs/LEAN_RECHECK.md) + reward.py {0,1} accuracy producer for `align.rl.rewards.CompositeReward` +""" + +from .repl_pool import ( + HostBusy, + ReplCrash, + ReplError, + ReplLimits, + ReplMemoryExceeded, + ReplOutputTooLarge, + ReplPool, + ReplProcess, + ReplProtocolError, + ReplTimeout, + Worker, + default_workers, + plan_workers, + process_memory, +) +from .recheck import IndependentRechecker, RecheckVerdict +from .reward import LeanAccuracy, LeanScore, extract_lean_code +from .strict import ( + AXIOM_WHITELIST, + LeanInfraError, + StrictConfig, + StrictResult, + StrictVerifier, + static_check, +) +from .toolchain import LeanToolchain, ToolchainNotFound, find_toolchain, toolchain_available + +__all__ = [ + "AXIOM_WHITELIST", + "HostBusy", + "IndependentRechecker", + "LeanAccuracy", + "LeanInfraError", + "LeanScore", + "LeanToolchain", + "ReplCrash", + "ReplError", + "ReplLimits", + "ReplMemoryExceeded", + "ReplOutputTooLarge", + "ReplPool", + "ReplProcess", + "ReplProtocolError", + "RecheckVerdict", + "ReplTimeout", + "StrictConfig", + "StrictResult", + "StrictVerifier", + "ToolchainNotFound", + "Worker", + "default_workers", + "extract_lean_code", + "find_toolchain", + "plan_workers", + "process_memory", + "static_check", + "toolchain_available", +] diff --git a/code/align/verify/lean/recheck.py b/code/align/verify/lean/recheck.py new file mode 100644 index 0000000000000000000000000000000000000000..a724507b16536421537c668e420104e6c61b0c68 --- /dev/null +++ b/code/align/verify/lean/recheck.py @@ -0,0 +1,310 @@ +"""An opt-in, INDEPENDENT second check for proofs the strict verifier accepted. + +The "comparator" pattern of the Lean community (Lean FRO's `comparator`, the Kimina/AXLE +audits): never let the thing that judged the proof also be the only thing that judges the +verdict. `StrictVerifier` already audits a candidate inside the same REPL worker that +compiled it, with a Lean metaprogram (`AUDIT_PRELUDE`) we wrote. If that worker's state, or +that audit, were wrong, the policy under RL would find the hole. This module re-derives the +two facts that matter in a different process with different code: + + (a) elaborate the ORIGINAL problem statement (the problem record's `statement`, never + anything the model wrote) as a reference `_cmp_ref ... := by sorry`; + (b) elaborate the accepted candidate on top of it, and confirm that the candidate + theorem's TYPE is definitionally equal to the reference type (the elaborator's + `isDefEq` AND the kernel's `Kernel.isDefEq`; both must say yes); + (c) `#print axioms `: Lean's own command, not `alignCollectAxioms`; the axiom set + must be a subset of {propext, Classical.choice, Quot.sound}. + +What is shared and what is not +------------------------------ +Independent: the OS process (a new REPL is spawned for every check and killed after it, so +no worker state, no environment ids, no cached reference env, no audit prelude survives +from the first pass), the prelude (`CMP_PRELUDE`, a different metaprogram that never calls +`alignCollectAxioms` or `addDecl`), the axiom walker (`#print axioms` instead of our own +traversal), the defeq judge (`Meta.isDefEq` + `Kernel.isDefEq` instead of a kernel +`addDecl` of a bridge theorem) and the reference text (rebuilt from the statement here). + +Shared, on purpose: the Lean toolchain, the tokenizer (`lex`) and `parse_statement`, which +split the TRUSTED reference. This module does not re-implement the lexical gate; it is a +second semantic check, not a second policy check. A policy-only reject in `strict` +(`banned:*`, `target_modifier`, ...) is not re-judged here, so this module run alone on a +policy violation may agree with a proof that strict rejects; with the flag on, strict runs +first and the re-check only ever sees what strict accepted. + +Verdict. Both checks must agree. The re-check can only turn an accept into a reject: + + strict reject -> reject (re-check never runs) + strict accept, re-check agrees -> accept + strict accept, re-check disagrees -> REJECT, reasons `recheck_disagree:` + +Failure policy: the candidate failing to elaborate, using `sorry`, or timing out in the +fresh process is a disagreement (reject with a reason). A fresh process that cannot even +build the trusted base environment (imports, prelude, reference header) is an +infrastructure fault and raises `LeanInfraError`, exactly like strict: a dead toolchain +must not read as "every proof was disagreed with". + +Stdlib only. +""" + +from __future__ import annotations + +import json +import re +import secrets +import time +from dataclasses import dataclass, field +from typing import Callable, Optional + +from .repl_pool import ReplError, ReplProcess, Worker +from .strict import AXIOM_WHITELIST, LeanInfraError, lex, parse_statement + +CMP_REF = "_cmp_ref" + +# ============================================================================ Lean prelude +#: Trusted comparison code, compiled into the FRESH process before any candidate text exists. +#: Deliberately does not reuse anything from `strict.AUDIT_PRELUDE`. +CMP_PRELUDE = r''' +open Lean Elab Command Meta in +elab "#align_cmp " nonce:str refId:ident candId:ident : command => do + let env ← getEnv + let tag := "ALIGN_CMP " ++ nonce.getString ++ " " + let some r := env.find? refId.getId + | logInfo m!"{tag}{(Json.mkObj [("ref_found", Json.bool false)]).compress}"; return + let some c := env.find? candId.getId + | logInfo m!"{tag}{(Json.mkObj [("ref_found", Json.bool true), ("cand_found", Json.bool false)]).compress}"; return + let kind := match c with + | .thmInfo _ => "theorem" | .defnInfo _ => "def" | .axiomInfo _ => "axiom" + | .opaqueInfo _ => "opaque" | .inductInfo _ => "inductive" | .ctorInfo _ => "ctor" + | .recInfo _ => "rec" | .quotInfo _ => "quot" + let n := r.levelParams.length + let lpOk := n == c.levelParams.length + let mut metaEq := false + let mut kernelEq := false + let mut err := "" + if lpOk then + let ps : List Level := (List.range n).map fun i => mkLevelParam (Name.mkSimple s!"cmpU{i}") + let tr := r.type.instantiateLevelParams r.levelParams ps + let tc := c.type.instantiateLevelParams c.levelParams ps + try + metaEq ← liftTermElabM (isDefEq tr tc) + catch e => + err := ← e.toMessageData.toString + match Lean.Kernel.isDefEq env {} tr tc with + | .ok b => kernelEq := b + | .error _ => kernelEq := false + let j := Json.mkObj [("ref_found", Json.bool true), ("cand_found", Json.bool true), ("kind", kind), + ("level_params_match", Json.bool lpOk), ("meta_defeq", Json.bool metaEq), + ("kernel_defeq", Json.bool kernelEq), ("err", err)] + logInfo m!"{tag}{j.compress}" +''' + +# ============================================================================ result types + + +@dataclass +class RecheckVerdict: + #: True only when every independent check passed. + agree: bool + #: Reasons for a disagreement (stable codes, no `recheck_disagree:` prefix). + reasons: tuple = () + diagnostics: dict = field(default_factory=dict) + elapsed_s: float = 0.0 + + def summary(self) -> dict: + d = {"agree": self.agree, "reasons": list(self.reasons), "elapsed_s": round(self.elapsed_s, 3)} + d.update(self.diagnostics) + return d + + +# ============================================================================ pure helpers +# Each of these is a seam the unit tests mutate (see tests/test_lean_recheck.py): the logic +# that matters lives in small named functions so that "mutant X survives" is a testable claim. + +_AX_DEPENDS = re.compile(r"^'(?P[^']+)' depends on axioms: \[(?P.*)\]\s*$", re.S) +_AX_NONE = re.compile(r"^'(?P[^']+)' does not depend on any axioms\s*$") + + +def parse_print_axioms(resp: dict, target: str) -> Optional[list[str]]: + """The axiom list from a `#print axioms` response, or None if it is absent/unparseable. + + Only an info message whose quoted name is exactly `target` counts. More than one such + message, or a differently-named one, is ambiguity and parses to None: the caller treats + None as a REJECT (fail closed).""" + found: list[list[str]] = [] + for m in resp.get("messages", []): + if not isinstance(m, dict) or m.get("severity") != "info": + continue + d = m.get("data") + if not isinstance(d, str): + continue + mn = _AX_NONE.match(d.strip()) + if mn: + if mn.group("name") != target: + continue + found.append([]) + continue + md = _AX_DEPENDS.match(d.strip()) + if md and md.group("name") == target: + found.append([a.strip() for a in re.split(r",\s*", md.group("list").replace("\n", " ")) if a.strip()]) + return found[0] if len(found) == 1 else None + + +def parse_cmp(resp: dict, nonce: str) -> Optional[dict]: + """The nonce-tagged comparison message. Messages without OUR nonce are ignored, so a + candidate that prints a forged verdict (`logInfo` in a macro) cannot supply one.""" + tag = f"ALIGN_CMP {nonce} " + for m in resp.get("messages", []): + d = m.get("data", "") if isinstance(m, dict) else "" + if isinstance(m, dict) and m.get("severity") == "info" and isinstance(d, str) and d.startswith(tag): + try: + return json.loads(d[len(tag) :]) + except ValueError: + return None + return None + + +def reference_signature(statement_sig_text: str, candidate_body: str) -> str: + """The signature the reference is elaborated from. ALWAYS the original problem + statement's: the model's own displayed statement is exactly what must not be trusted.""" + return statement_sig_text + + +def check_axioms(axioms: Optional[list[str]], whitelist=AXIOM_WHITELIST) -> list[str]: + """Reasons from the `#print axioms` result. None (unparseable) fails closed.""" + if axioms is None: + return ["axioms_unparsed"] + return [("sorry" if a == "sorryAx" else f"axiom:{a}") for a in axioms if a not in whitelist] + + +def check_types(cmp: Optional[dict]) -> list[str]: + """Reasons from the comparison message: the candidate's type must be defeq to the + reference's under BOTH the elaborator and the kernel.""" + if cmp is None: + return ["cmp_missing"] + if not cmp.get("ref_found"): + return ["reference_missing"] + if not cmp.get("cand_found"): + return ["target_missing"] + out: list[str] = [] + if cmp.get("kind") != "theorem": + out.append("not_theorem") + if not cmp.get("level_params_match"): + out.append("level_params_mismatch") + elif not (cmp.get("meta_defeq") and cmp.get("kernel_defeq")): + out.append("type_mismatch") + return out + + +# ============================================================================ the re-checker + + +def _msgs(resp: dict) -> list[dict]: + return [m for m in resp.get("messages", []) if isinstance(m, dict)] + + +def _short(s: str, n: int = 300) -> str: + return s if len(s) <= n else s[: n - 3] + "..." + + +class IndependentRechecker: + """Re-check one accepted (statement, code) pair in a FRESH REPL process. + + `launcher(idx) -> ReplProcess` is the same factory the pool uses (so the re-check child + gets the same sanitized environment and resource limits), but every call to `check` + makes its own `Worker`, i.e. its own OS process, and kills it afterwards. + """ + + def __init__( + self, + launcher: Callable[[int], ReplProcess], + axiom_whitelist=AXIOM_WHITELIST, + timeout_s: float = 180.0, + prepend_missing_header: bool = False, + ) -> None: + self.launcher = launcher + self.axiom_whitelist = frozenset(axiom_whitelist) + self.timeout_s = timeout_s + self.prepend_missing_header = prepend_missing_header + self._n = 0 + + # -- the process this check runs in; a test seam (the "reuse a worker" mutant swaps it) + def _fresh_worker(self) -> Worker: + self._n += 1 + return Worker(10_000 + self._n, self.launcher, max_requests=10**9) + + def check(self, statement: str, code: Optional[str]) -> RecheckVerdict: + t0 = time.monotonic() + v = self._check(statement, code, t0 + self.timeout_s) + v.elapsed_s = time.monotonic() - t0 + return v + + def _split(self, statement: str, code: Optional[str]): + """(ref, body) or a RecheckVerdict that already disagrees.""" + ref = parse_statement(statement) + if not ref.ok: + return RecheckVerdict(False, ("reference_unparseable",), {"detail": _short(ref.problem)}) + if code is None or not code.strip(): + return RecheckVerdict(False, ("no_code",)) + lx = lex(code) + if lx.broken: + return RecheckVerdict(False, ("parse_error",), {"detail": lx.broken}) + if self.prepend_missing_header and not any(t.text == "import" for t in lx.toks): + code = ref.header_text + "\n" + code + lx = lex(code) + nh = len(ref.header_toks) + if tuple(t.text for t in lx.toks[:nh]) != ref.header_toks: + return RecheckVerdict(False, ("header_mismatch",)) + body = code[lx.toks[nh - 1].end :] if nh else code + return ref, body + + def _check(self, statement: str, code: Optional[str], deadline: float) -> RecheckVerdict: + split = self._split(statement, code) + if isinstance(split, RecheckVerdict): + return split + ref, body = split + name = ref.name + w = self._fresh_worker() + diag: dict = {"pid": None} + try: + try: + hdr_env = w.header_env(ref.header_text, CMP_PRELUDE) + except ReplError as e: + raise LeanInfraError(f"re-check cannot build its base environment: {e}") from e + diag["pid"] = w.proc.pid if w.proc is not None else None + + # (a) the reference, from the ORIGINAL statement, before any candidate text exists + sig = reference_signature(ref.sig_text, body) + r = w.command(f"theorem {CMP_REF} {sig} := by\n sorry", hdr_env, max(5.0, deadline - time.monotonic())) + errs = [m for m in _msgs(r) if m.get("severity") == "error"] + if errs or "env" not in r: + return RecheckVerdict(False, ("reference_invalid",), {**diag, "detail": _short(json.dumps(errs[:2] or r), 300)}) + ref_env = r["env"] + + # the candidate, in the environment that already holds the reference + resp = w.command(body, ref_env, max(1.0, deadline - time.monotonic())) + msgs = _msgs(resp) + errors = [m for m in msgs if m.get("severity") == "error"] + if errors or "env" not in resp: + diag["errors"] = [_short(m.get("data", ""), 240) for m in errors[:3]] + return RecheckVerdict(False, ("compile_error",), diag) + if resp.get("sorries") or any("sorry" in str(m.get("data", "")) for m in msgs if m.get("severity") == "warning"): + return RecheckVerdict(False, ("sorry",), diag) + cand_env = resp["env"] + + # (c) Lean's own axiom report for the target + ax_resp = w.command(f"#print axioms _root_.{name}", cand_env, max(1.0, deadline - time.monotonic())) + axioms = parse_print_axioms(ax_resp, name) + diag["axioms"] = axioms + reasons = list(check_axioms(axioms, self.axiom_whitelist)) + + # (b) type of the target vs the type of the reference + nonce = secrets.token_hex(8) + cmp_resp = w.command(f'#align_cmp "{nonce}" {CMP_REF} {name}', cand_env, max(1.0, deadline - time.monotonic())) + cmp = parse_cmp(cmp_resp, nonce) + diag["cmp"] = cmp + reasons += check_types(cmp) + return RecheckVerdict(not reasons, tuple(dict.fromkeys(reasons)), diag) + except ReplError as e: + return RecheckVerdict(False, (f"repl_{e.code}",), {**diag, "detail": _short(str(e))}) + finally: + w.discard() diff --git a/code/align/verify/lean/repl_pool.py b/code/align/verify/lean/repl_pool.py new file mode 100644 index 0000000000000000000000000000000000000000..3b68600dfe162a25f1e7d0852362a4c69dd3419a --- /dev/null +++ b/code/align/verify/lean/repl_pool.py @@ -0,0 +1,946 @@ +"""A pool of persistent Lean REPL processes with hard resource limits. + +Why a pool of PERSISTENT processes +---------------------------------- +`import Mathlib` costs ~3.2s warm (measured, docs/LEAN_VERIFIER.md) and maps ~3.4GB of +.olean files. A verifier that spawns one `lean` per proof pays that on every proof; +a REPL keeps the imported environment alive and elaborates the next proof on top of +it in ~15ms. The imported-header environment is cached per worker (`Worker.header_env`), +which is the import-keyed cache that gives Kimina's server its 1.94x. + +What the pool must survive (each guard below maps to a way this goes wrong) +---------------------------------------------------------------------------- +* A proof that never terminates (`decide` on a huge term, `simp` loop with + `maxHeartbeats 0`): a per-request WALL-CLOCK deadline, enforced by SIGKILL of the whole + process group (the REPL never reaches a cooperative check). The worker is then + re-spawned lazily; the caller sees `ReplTimeout`, never a hang. +* A proof that eats RAM: this box has NO SWAP and one OOM already wedged it + (/apps/CLAUDE.md). Two layers: (1) a watchdog that polls `/proc//smaps_rollup` + and kills on `Pss_Anon` over the cap. We cap ANONYMOUS memory, not RSS: RSS of a + Mathlib REPL is ~3.65GB of which 3.40GB is the file-backed, shared, read-only .olean + mapping (Pss_Anon is ~0.25GB) -- an RSS cap would either be uselessly high or kill every + healthy worker. (2) `prlimit --as` as a backstop for the allocation burst that fits + between two watchdog ticks. +* A proof that prints without bound (`set_option trace...`): output is capped, the + worker is killed on overflow. +* A REPL that dies (OOM-killer, stack overflow, SIGXFSZ): EOF on stdout -> `ReplCrash` + with the stderr tail; the next acquire re-spawns. +* REPL environment growth: every command stores a new environment snapshot. Workers are + recycled after `max_requests` commands. +* Zombies / orphans: children are session leaders (`start_new_session`), killed with + `killpg` and always `wait()`ed; `close()` and an `atexit` hook reap every live child. + Those hooks do not run when THIS process is SIGKILLed or OOM-killed, and a REPL that is busy + elaborating never reads the EOF on its stdin: it would run on, unwatched, holding GBs. So every + real child runs under the launcher of `sandbox.py` (`ReplProcess.supervise`, on by default), + a tiny single-threaded python that polls its parent PROCESS and SIGKILLs the REPL the moment the + parent is gone. (`PR_SET_PDEATHSIG` alone is not enough: it fires on death of the spawning + THREAD, and the pool spawns from short-lived executor threads.) `ReplPool.from_toolchain` + additionally puts the REPL in the namespace sandbox by default (`sandbox=True`). +* Stale environment ids: a worker that dies between requests is re-spawned with an EMPTY + environment table; replaying an id from the dead process would make the real REPL answer + `Unknown environment.`, which the verifier would score as a compile error. `Worker.command` + raises `ReplCrash` instead (infra failure, not a verdict). + +The REPL does not flush stdout when it is a pipe (only a pty line-buffers it), so the +binary is wrapped in `stdbuf -o0 -e0`; see toolchain.py. + +Stdlib only. Everything that talks to a real Lean binary goes through `ReplProcess`'s +`argv`, so the unit tests drive the identical code with a fake REPL script. +""" + +from __future__ import annotations + +import atexit +import json +import os +import re +import select +import shutil +import signal +import subprocess +import threading +import time +import weakref +from collections import OrderedDict +from concurrent.futures import ThreadPoolExecutor +from contextlib import contextmanager +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, Any, Callable, Iterator, Optional, Sequence + +if TYPE_CHECKING: # the sandbox module is imported lazily + from align.verify.lean.sandbox import SandboxSpec + +# --------------------------------------------------------------------------- errors + + +class ReplError(Exception): + """Base class. `.code` is the failure-taxonomy token (ROADMAP P4-1).""" + + code = "repl_error" + + +class ReplTimeout(ReplError): + code = "timeout" + + +class ReplCrash(ReplError): + code = "crash" + + +class ReplMemoryExceeded(ReplError): + code = "memory" + + +class ReplOutputTooLarge(ReplError): + code = "output_too_large" + + +class ReplProtocolError(ReplError): + code = "protocol" + + +class HeaderError(ReplProtocolError): + """A header-building command failed to elaborate. `stage` is `imports` / `prelude` (the verifier's own + infrastructure is broken) or `header` (one reference's `open`/`set_option` lines do not elaborate: a bad + item, not a dead verifier).""" + + def __init__(self, stage: str, msg: str) -> None: + super().__init__(msg) + self.stage = stage + + +class HostBusy(RuntimeError): + """The host cannot take a Lean pool right now (the /apps/CLAUDE.md preflight).""" + + +# --------------------------------------------------------------------------- memory + + +def read_smaps_rollup(pid: int) -> Optional[dict[str, int]]: + """Parse `/proc//smaps_rollup` into {field: kB}. None if the pid is gone. + + This (not `VmRSS`) is the source of every memory number in this package: RSS + double-counts shared .olean pages across workers, PSS divides them by the number of + sharers, and `Pss_Anon` is the private heap that actually scales with the proof. + """ + try: + with open(f"/proc/{pid}/smaps_rollup") as f: + text = f.read() + except OSError: + return None + out: dict[str, int] = {} + for line in text.splitlines(): + key, sep, rest = line.partition(":") + if not sep: + continue + parts = rest.split() + if parts and parts[0].isdigit(): + out[key.strip()] = int(parts[0]) + return out or None + + +def process_memory(pid: int) -> Optional[dict[str, float]]: + """Memory report for one process, in MiB. Keys: rss, pss, pss_anon, pss_file, + anon, private_dirty, vm_size, threads.""" + sm = read_smaps_rollup(pid) + if sm is None: + return None + rep = { + "rss": sm.get("Rss", 0) / 1024.0, + "pss": sm.get("Pss", 0) / 1024.0, + "pss_anon": sm.get("Pss_Anon", sm.get("Anonymous", 0)) / 1024.0, + "pss_file": sm.get("Pss_File", 0) / 1024.0, + "anon": sm.get("Anonymous", 0) / 1024.0, + "private_dirty": sm.get("Private_Dirty", 0) / 1024.0, + "vm_size": 0.0, + "threads": 0.0, + } + try: + with open(f"/proc/{pid}/status") as f: + for line in f: + if line.startswith("VmSize:"): + rep["vm_size"] = int(line.split()[1]) / 1024.0 + elif line.startswith("Threads:"): + rep["threads"] = float(line.split()[1]) + except (OSError, ValueError, IndexError): + pass + return rep + + +# --------------------------------------------------------------------------- limits + + +@dataclass(frozen=True) +class ReplLimits: + #: Kill the worker when its private (anonymous) memory exceeds this. See module doc + #: for why anonymous and not RSS. Measured healthy worker: ~0.25 GiB. + anon_cap_gb: float = 4.0 + #: `prlimit --as` backstop. Virtual size of a healthy worker is ~4.2GiB (the .olean + #: mappings), so this is "cap + mappings + slack", not a working-set limit. + as_limit_gb: float = 16.0 + #: Largest file the child may write (stderr spool, any file a proof creates). + fsize_mb: int = 256 + nice: int = 5 + max_output_bytes: int = 16 << 20 + #: Wait granularity of the read loop (also the deadline resolution). + poll_s: float = 0.1 + #: How often the watchdog samples smaps_rollup while a request is in flight. + mem_poll_s: float = 0.5 + #: Consecutive unreadable memory samples (while the child is alive) after which the request is + #: killed as `memory`: an unmeasurable process must not run uncapped on a no-swap box. + mem_miss_limit: int = 3 + #: Deadline for the cold `import Mathlib` header command. + header_timeout_s: float = 600.0 + + +# --------------------------------------------------------------------------- process + +_LIVE: "weakref.WeakSet[ReplProcess]" = weakref.WeakSet() + + +def _reap_all() -> None: # pragma: no cover - interpreter shutdown path + for p in list(_LIVE): + try: + p.kill() + except Exception: + pass + + +atexit.register(_reap_all) + + +class ReplProcess: + """One persistent REPL child speaking blank-line-delimited JSON on stdin/stdout. + + `argv` is the bare command. With `wrap=True` it is prefixed by + `nice -n N prlimit --as=.. --core=0 --fsize=.. -- stdbuf -o0 -e0`; each of those + `exec`s the next program, so `self.pid` is the REPL's own pid and the memory + watchdog reads the right /proc entry. `wrap=False` is for fake REPLs in tests. + """ + + def __init__( + self, + argv: Sequence[str], + env: dict[str, str], + cwd: Optional[str] = None, + limits: ReplLimits = ReplLimits(), + stderr_path: Optional[str] = None, + wrap: bool = True, + sandbox: Optional["SandboxSpec"] = None, + supervise: Optional[bool] = None, + ) -> None: + #: OS sandbox (align/verify/lean/sandbox.py: namespaces, allow-list root, no network). None = no isolation. + self.sandbox = sandbox + #: Run the child under the launcher/supervisor, which SIGKILLs the REPL when this PROCESS (not just the + #: spawning thread) disappears: SIGKILL/OOM of the trainer must not orphan a live Lean elaboration. On by + #: default for real (wrapped) children; implied by `sandbox`. + self.supervise = bool(sandbox is not None or (wrap if supervise is None else supervise)) + self.argv = list(argv) + self.env = dict(env) + self.cwd = cwd + self.limits = limits + self.stderr_path = stderr_path + self.wrap = wrap + self.proc: Optional[subprocess.Popen] = None + self._stderr_f = None + self._poller: Optional[select.poll] = None + self.n_requests = 0 + self.started_at = 0.0 + self.peak_anon_mb = 0.0 + + # -- lifecycle + + def _wrapped_argv(self) -> list[str]: + if not self.wrap: + return list(self.argv) + lim = self.limits + pre: list[str] = [] + nice = shutil.which("nice") + if nice and lim.nice: + pre += [nice, "-n", str(int(lim.nice))] + prlimit = shutil.which("prlimit") + if prlimit: + pre += [ + prlimit, + f"--as={int(lim.as_limit_gb * (1 << 30))}", + "--core=0", + f"--fsize={int(lim.fsize_mb) << 20}", + "--", + ] + stdbuf = shutil.which("stdbuf") + if stdbuf: + pre += [stdbuf, "-o0", "-e0"] + return pre + self.argv + + def _spec(self) -> "SandboxSpec": + """The launcher spec: the caller's sandbox, or a lifetime-only one (no namespaces).""" + if self.sandbox is not None: + return self.sandbox + from align.verify.lean.sandbox import SandboxSpec + + return SandboxSpec(scratch_dir=self.cwd or os.getcwd(), cwd=self.cwd, env=dict(self.env), isolate=False) + + def _spawn_argv(self) -> list[str]: + """What `Popen` runs: `[launcher --] nice prlimit stdbuf repl`. The launcher is OUTSIDE the resource + limits, which run inside it.""" + argv = self._wrapped_argv() + if not self.supervise: + return argv + from align.verify.lean.sandbox import sandbox_argv + + return sandbox_argv(self._spec(), argv) + + def _spawn_env(self) -> dict[str, str]: + if not self.supervise: + return self.env + from align.verify.lean.sandbox import helper_env + + return helper_env() # the launcher gets nothing; the REPL's env travels in the spec + + def memory_pid(self) -> Optional[int]: + """Host pid of the REPL itself. Under the supervisor `Popen.pid` is the launcher, whose + private memory is ~10 MB: the memory watchdog must read the REPL (its only child).""" + pid = self.pid + if pid is None or not self.supervise: + return pid + try: + with open(f"/proc/{pid}/task/{pid}/children") as f: + kids = [int(x) for x in f.read().split()] + if kids: + return kids[0] + except (OSError, ValueError): + pass + spec = self._spec() + if spec.pidfile: + from align.verify.lean.sandbox import inner_pid + + return inner_pid(spec, pid) + return None + + def start(self) -> None: + if self.alive: + return + self.kill() + if self.stderr_path: + os.makedirs(os.path.dirname(self.stderr_path), exist_ok=True) + self._stderr_f = open(self.stderr_path, "wb") # truncated per spawn + err = self._stderr_f + else: + err = subprocess.DEVNULL + self.proc = subprocess.Popen( + self._spawn_argv(), + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=err, + env=self._spawn_env(), + cwd=self.cwd, + start_new_session=True, # own process group => killpg reaps every descendant + close_fds=True, + ) + assert self.proc.stdin is not None and self.proc.stdout is not None + os.set_blocking(self.proc.stdin.fileno(), False) + os.set_blocking(self.proc.stdout.fileno(), False) + self._poller = select.poll() + self._poller.register(self.proc.stdout.fileno(), select.POLLIN | select.POLLHUP | select.POLLERR) + self.n_requests = 0 + self.started_at = time.monotonic() + self.peak_anon_mb = 0.0 + _LIVE.add(self) + + @property + def pid(self) -> Optional[int]: + return self.proc.pid if self.proc is not None else None + + @property + def alive(self) -> bool: + return self.proc is not None and self.proc.poll() is None + + def kill(self) -> None: + """SIGKILL the whole process group and reap. Idempotent.""" + p, self.proc = self.proc, None + if p is not None: + try: + os.killpg(p.pid, signal.SIGKILL) + except (ProcessLookupError, PermissionError): + try: + p.kill() + except Exception: + pass + try: + p.wait(timeout=15) + except Exception: + pass + for f in (p.stdin, p.stdout): + try: + if f is not None: + f.close() + except Exception: + pass + if self._stderr_f is not None: + try: + self._stderr_f.close() + except Exception: + pass + self._stderr_f = None + self._poller = None + + def stderr_tail(self, n: int = 2000) -> str: + if not self.stderr_path: + return "" + try: + with open(self.stderr_path, "rb") as f: + f.seek(0, os.SEEK_END) + f.seek(max(0, f.tell() - n)) + return f.read().decode("utf-8", "replace") + except OSError: + return "" + + def memory(self) -> Optional[dict[str, float]]: + pid = self.memory_pid() + return process_memory(pid) if pid else None + + # -- I/O + + def _write_all(self, data: bytes, deadline: float) -> None: + assert self.proc is not None and self.proc.stdin is not None + fd = self.proc.stdin.fileno() + view = memoryview(data) + w = select.poll() + w.register(fd, select.POLLOUT | select.POLLERR | select.POLLHUP) + while view: + left = deadline - time.monotonic() + if left <= 0: + self.kill() + raise ReplTimeout("timed out writing the request (child not reading)") + if not w.poll(min(left, self.limits.poll_s) * 1000): + continue + try: + n = os.write(fd, view) + except BlockingIOError: + continue + except (BrokenPipeError, OSError) as e: + rc = self.proc.poll() + tail = self.stderr_tail() + self.kill() + raise ReplCrash(f"REPL died before reading the request (rc={rc}): {e!r} {tail[-300:]}") + view = view[n:] + + def request(self, payload: dict, timeout: float) -> dict: + """Send one JSON command, return the parsed JSON response. + + Raises a `ReplError` subclass on timeout/crash/memory/oversize/garbage; in every + such case the child has ALREADY been killed (a REPL in an unknown state is never + reused: the next request would read the previous request's late answer). + """ + if not self.alive: + raise ReplCrash("REPL is not running") + assert self.proc is not None and self.proc.stdout is not None + lim = self.limits + t0 = time.monotonic() + deadline = t0 + timeout + fd = self.proc.stdout.fileno() + # Unsolicited output (a late second answer to the PREVIOUS request) would be read as + # THIS request's answer and attributed to the wrong proof. A REPL that does that is + # corrupt: kill it instead of trusting the stream. + try: + stray = os.read(fd, 1 << 16) + except BlockingIOError: + stray = b"" + if stray: + self.kill() + raise ReplProtocolError(f"unsolicited output before request: {stray[:80]!r}") + try: + data = (json.dumps(payload, ensure_ascii=False) + "\n\n").encode("utf-8") + except UnicodeEncodeError as e: # a lone surrogate: nothing was written, the child is untouched + raise ReplProtocolError(f"request is not encodable as UTF-8: {e}") from e + try: + return self._exchange(data, t0, deadline, fd, lim) + except BaseException: + # ANY exit that is not a returned answer (a ReplError, KeyboardInterrupt, MemoryError inside the + # watchdog...) leaves a pending answer on the pipe: a REPL in an unknown state is never reused. + self.kill() + raise + + def _exchange(self, data: bytes, t0: float, deadline: float, fd: int, lim: "ReplLimits") -> dict: + timeout = deadline - t0 + self._write_all(data, deadline) + buf = bytearray() + next_mem = t0 + lim.mem_poll_s + cap_mb = lim.anon_cap_gb * 1024.0 + misses = 0 + self.n_requests += 1 + while True: + now = time.monotonic() + if now >= deadline: + self.kill() + raise ReplTimeout(f"no response within {timeout:.1f}s") + assert self._poller is not None + events = self._poller.poll(min(deadline - now, lim.poll_s) * 1000) + if events: + try: + chunk = os.read(fd, 1 << 16) + except BlockingIOError: + chunk = None + if chunk == b"": + rc = self.proc.poll() + if rc is None: + try: + rc = self.proc.wait(timeout=2) + except Exception: + rc = None + tail = self.stderr_tail() + self.kill() + raise ReplCrash(f"REPL exited (rc={rc}) mid-request. stderr tail: {tail[-400:]!r}") + if chunk: + buf += chunk + if len(buf) > lim.max_output_bytes: + self.kill() + raise ReplOutputTooLarge(f"response over {lim.max_output_bytes} bytes") + idx = buf.find(b"\n\n") + if idx >= 0: + if idx + 2 != len(buf): + self.kill() + raise ReplProtocolError("extra bytes after the response terminator") + break + if time.monotonic() >= next_mem: + next_mem = time.monotonic() + lim.mem_poll_s + mem = self.memory() + if mem is None: + misses += 1 + if misses >= lim.mem_miss_limit: + self.kill() + raise ReplMemoryExceeded(f"memory unmeasurable for {misses} consecutive samples (fail closed)") + else: + misses = 0 + if mem is not None: + self.peak_anon_mb = max(self.peak_anon_mb, mem["pss_anon"]) + if mem["pss_anon"] > cap_mb: + self.kill() + raise ReplMemoryExceeded( + f"private memory {mem['pss_anon']:.0f}MiB over cap {cap_mb:.0f}MiB" + ) + try: + return json.loads(buf.decode("utf-8", "replace")) + except ValueError as e: + self.kill() + raise ReplProtocolError(f"unparsable REPL response: {e}; head={bytes(buf[:200])!r}") + + +# --------------------------------------------------------------------------- worker/pool + + +_IMPORT_LINE = re.compile(r"\s*(?:--[^\n]*\n\s*)*import[ \t]+([A-Za-z0-9_.\u00ab\u00bb']+)") + + +def split_imports(header: str) -> tuple[str, str]: + """Split a Lean header into (canonical `import` lines, everything after them). + + Why the split exists (MEASURED, not hypothetical): a SECOND fresh `import Mathlib` in a + live REPL process cannot re-mmap the .olean files at their fixed base addresses (they are + already mapped), so Lean falls back to reading them into malloc'd memory: Pss_Anon went + from 0.25GiB to 4.1GiB and tripped the 4GiB watchdog. The pool therefore imports ONCE per + process and layers every header variant (`open`, `set_option`, the audit prelude) on top + of that import environment as ordinary commands, which cost milliseconds and kilobytes. + """ + imports: list[str] = [] + pos = 0 + while True: + m = _IMPORT_LINE.match(header, pos) + if not m: + break + imports.append(f"import {m.group(1)}") + pos = m.end() + return "\n".join(imports), header[pos:] + + +class Worker: + """One pool slot: a lazily (re)started REPL plus its per-process caches. + + The caches (`header_envs`, `memo`) hold REPL environment ids, which are meaningless + in any other process; they are cleared whenever the process is killed or recycled. + """ + + MAX_HEADER_ENVS = 8 + MAX_MEMO = 256 + + def __init__( + self, + idx: int, + launcher: Callable[[int], ReplProcess], + max_requests: int, + on_error: Optional[Callable[["ReplError"], None]] = None, + ) -> None: + self.idx = idx + self._on_error = on_error + self._launcher = launcher + self.max_requests = max_requests + self.proc: Optional[ReplProcess] = None + self.header_envs: "OrderedDict[tuple, int]" = OrderedDict() + #: the one import set this process has loaded, and the env id right after it + self._imports: Optional[str] = None + self._import_env: Optional[int] = None + self._layers: dict[tuple, int] = {} + self.memo: "OrderedDict[Any, Any]" = OrderedDict() + self.total_requests = 0 + self.restarts = 0 + self._restarted = False + + def _drop_caches(self) -> None: + self.header_envs.clear() + self._layers.clear() + self._imports = None + self._import_env = None + self.memo.clear() + + def ensure(self) -> ReplProcess: + self._restarted = False + if self.proc is None: + self.proc = self._launcher(self.idx) + if not self.proc.alive: + self._drop_caches() + self.proc.start() + self.restarts += 1 + self._restarted = True + return self.proc + + def discard(self) -> None: + if self.proc is not None: + self.proc.kill() + self._drop_caches() + + def command(self, cmd: str, env: Optional[int] = None, timeout: float = 120.0) -> dict: + proc = self.ensure() + payload: dict[str, Any] = {"cmd": cmd} + if env is not None: + payload["env"] = env + self.total_requests += 1 + try: + if env is not None and self._restarted: + # The process this env id belonged to died between requests and ensure() just spawned a new one: + # the id names nothing here (the real REPL would answer "Unknown environment." and the verifier + # would score it as a compile error). Surface it as the crash it is. + raise ReplCrash("REPL died between requests; the environment id is stale (new process)") + resp = proc.request(payload, timeout) + if "env" not in resp and "Unknown environment" in str(resp.get("message", "")): + proc.kill() + raise ReplCrash(f"REPL reported a stale environment id: {resp.get('message')}") + return resp + except ReplError as e: + self.discard() # normally the child is already dead (its env ids died with it); never keep a live one + if self._on_error is not None: + self._on_error(e) + raise + + def _checked(self, resp: dict, what: str) -> int: + errs = [m for m in resp.get("messages", []) if isinstance(m, dict) and m.get("severity") == "error"] + if errs or "env" not in resp: + self.discard() + raise HeaderError(what, f"{what} failed to elaborate: {errs[:2] or resp}") + return resp["env"] + + def header_env(self, header: str, prelude: str = "", timeout: Optional[float] = None) -> int: + """Environment id for `header` (imports, opens, options) with `prelude` (trusted + commands) compiled BEFORE the header's opens, cached per worker. + + Layering: [imports, once per process] -> [prelude] -> [rest of header]. The prelude + goes before the header's `open ... Real Nat` so it elaborates in a pristine + namespace and cannot be affected by what the header opens. A header with a DIFFERENT + import set recycles the process (see `split_imports` for why a second import in the + same process is not an option). + """ + imports, rest = split_imports(header) + key = (imports, prelude, rest) + if key in self.header_envs and self.proc is not None and self.proc.alive: + self.header_envs.move_to_end(key) + return self.header_envs[key] + proc = self.ensure() + t = timeout if timeout is not None else proc.limits.header_timeout_s + if self._import_env is not None and imports != self._imports: + self.discard() + proc = self.ensure() + if self._import_env is None: + env = self._checked(self.command(imports if imports else "-- no imports", None, t), "imports") + self._imports, self._import_env = imports, env + env = self._import_env + if prelude.strip(): + lk = ("prelude", prelude) + if lk not in self._layers: + self._layers[lk] = self._checked(self.command(prelude, env, t), "prelude") + env = self._layers[lk] + if rest.strip(): + lk = ("rest", prelude, rest) + if lk not in self._layers: + self._layers[lk] = self._checked(self.command(rest, env, t), "header") + env = self._layers[lk] + self.header_envs[key] = env + while len(self.header_envs) > self.MAX_HEADER_ENVS: + self.header_envs.popitem(last=False) + return env + + def remember(self, key: Any, build: Callable[[], Any]) -> Any: + if key in self.memo: + self.memo.move_to_end(key) + return self.memo[key] + val = build() + self.memo[key] = val + while len(self.memo) > self.MAX_MEMO: + self.memo.popitem(last=False) + return val + + def should_retire(self) -> bool: + return self.proc is not None and self.proc.alive and self.proc.n_requests >= self.max_requests + + def memory(self) -> Optional[dict[str, float]]: + return self.proc.memory() if self.proc is not None and self.proc.alive else None + + +def default_workers(cores: Optional[int] = None) -> int: + """`min(8, cores // 4)`, at least 1. 8 is where Kimina's measured scaling is already + sublinear; cores//4 leaves the rest of the box to the trainer.""" + c = cores if cores is not None else (os.cpu_count() or 4) + return max(1, min(8, c // 4)) + + +def plan_workers( + requested: int, + per_worker_private_gb: float, + shared_gb: float, + mem_available_gb: float, + floor_gb: float = 45.0, +) -> int: + """Largest n <= requested with `shared + n * private <= available - floor`. + + The .olean mapping is shared across workers (counted once); each worker adds its + private heap, budgeted at the anon CAP (worst case), so the pool can never push + MemAvailable under the /apps/CLAUDE.md floor even if every worker hits its cap. + Raises `HostBusy` if not even one worker fits. + """ + budget = mem_available_gb - floor_gb - shared_gb + n = int(budget // per_worker_private_gb) if per_worker_private_gb > 0 else requested + n = min(requested, n) + if n < 1: + raise HostBusy( + f"cannot fit one Lean worker: available {mem_available_gb:.1f}GB - floor " + f"{floor_gb:.0f}GB - shared {shared_gb:.1f}GB leaves {budget:.1f}GB " + f"< {per_worker_private_gb:.1f}GB" + ) + return n + + +def meminfo_available_gb() -> float: + with open("/proc/meminfo") as f: + for line in f: + if line.startswith("MemAvailable:"): + return int(line.split()[1]) / 1024**2 + return 0.0 + + +@dataclass +class PoolStats: + spawned: int = 0 + timeouts: int = 0 + crashes: int = 0 + memory_kills: int = 0 + oversize: int = 0 + protocol: int = 0 + requests: int = 0 + recycled: int = 0 + per_code: dict = field(default_factory=dict) + + +class ReplPool: + """Bounded set of `Worker`s handed out one-at-a-time via `acquire()`. + + Thread-safe. Workers start lazily (the first `acquire` pays the import), so + constructing a pool is free and a pool of 8 never exists as 8 imports unless 8 + jobs run concurrently. `warm()` front-loads them. + """ + + def __init__( + self, + launcher: Callable[[int], ReplProcess], + n_workers: Optional[int] = None, + max_requests: int = 1000, + default_timeout_s: float = 120.0, + ) -> None: + self.n_workers = n_workers if n_workers is not None else default_workers() + if self.n_workers < 1: + raise ValueError("n_workers must be >= 1") + self.default_timeout_s = default_timeout_s + #: the process factory, kept so an independent re-check can spawn a FRESH process + self.launcher = launcher + self.stats = PoolStats() + self.workers = [Worker(i, launcher, max_requests, self._count) for i in range(self.n_workers)] + self._idle: list[Worker] = list(reversed(self.workers)) + self._cv = threading.Condition() + self._closed = False + + # -- construction from the real toolchain + + @classmethod + def from_toolchain( + cls, + toolchain, + n_workers: Optional[int] = None, + limits: ReplLimits = ReplLimits(), + scratch_dir: Optional[str] = None, + max_requests: int = 1000, + default_timeout_s: float = 120.0, + preflight: bool = False, + sandbox: bool = True, + ) -> "ReplPool": + """`sandbox=True` (the DEFAULT) runs every REPL inside the namespace sandbox of `sandbox.py` (no network, + allow-list filesystem, own pid namespace, no capabilities): the elaborator executes code a policy wrote. + It FAILS CLOSED: if the kernel refuses the namespaces this raises `SandboxUnavailable` instead of silently + running unisolated. `sandbox=False` is the explicit opt-out (a lifetime-only supervisor remains, so the REPL + still dies with this process). For the pre-/post-SFT comparability of a run, use the same value in both.""" + n = n_workers if n_workers is not None else default_workers() + if preflight: + n = preflight_pool(n, limits) + scratch = scratch_dir or os.path.join(str(toolchain.root), "tmp", "pool") + os.makedirs(scratch, exist_ok=True) + if sandbox: + from align.verify.lean.sandbox import SandboxUnavailable, sandbox_supported + + ok, why = sandbox_supported() + if not ok: + raise SandboxUnavailable( + f"sandbox=True but namespaces are unavailable ({why}); pass sandbox=False to opt out explicitly" + ) + + def launcher(idx: int) -> ReplProcess: + spec = None + if sandbox: + from align.verify.lean.sandbox import SandboxSpec, minimal_env + + wdir = os.path.join(scratch, f"sandbox{idx}") + os.makedirs(wdir, exist_ok=True) + spec = SandboxSpec( + scratch_dir=wdir, + ro_paths=tuple(str(toolchain.root / d) for d in ("elan", "repl", "workspace")), + cwd=toolchain.cwd, + pidfile=os.path.join(scratch, f"worker{idx}.pid"), + env=minimal_env(toolchain.child_env, wdir), + ) + return ReplProcess( + toolchain.argv(), + toolchain.child_env, + cwd=toolchain.cwd, + limits=limits, + stderr_path=os.path.join(scratch, f"worker{idx}.stderr"), + sandbox=spec, + ) + + return cls(launcher, n, max_requests, default_timeout_s) + + # -- scheduling + + @contextmanager + def acquire(self, timeout: Optional[float] = None) -> Iterator[Worker]: + deadline = None if timeout is None else time.monotonic() + timeout + with self._cv: + while True: + if self._closed: + raise RuntimeError("pool is closed") + if self._idle: + w = self._idle.pop() + break + left = None if deadline is None else deadline - time.monotonic() + if left is not None and left <= 0: + raise TimeoutError("no free Lean worker") + self._cv.wait(left) + try: + yield w + finally: + try: + if w.should_retire(): + w.discard() + self.stats.recycled += 1 + finally: + with self._cv: + self.stats.requests = sum(x.total_requests for x in self.workers) + self.stats.spawned = sum(x.restarts for x in self.workers) + self._idle.append(w) + self._cv.notify() + + def _count(self, e: ReplError) -> None: + s = self.stats + s.per_code[e.code] = s.per_code.get(e.code, 0) + 1 + if isinstance(e, ReplTimeout): + s.timeouts += 1 + elif isinstance(e, ReplCrash): + s.crashes += 1 + elif isinstance(e, ReplMemoryExceeded): + s.memory_kills += 1 + elif isinstance(e, ReplOutputTooLarge): + s.oversize += 1 + elif isinstance(e, ReplProtocolError): + s.protocol += 1 + + def map(self, fn: Callable[[Worker, Any], Any], items: Sequence[Any]) -> list[Any]: + """Run `fn(worker, item)` over items on up to `n_workers` threads. Exceptions are + RETURNED in place (a crashed item must not abort a batch of 10k proofs).""" + + def one(item: Any) -> Any: + try: + with self.acquire() as w: + return fn(w, item) + except BaseException as e: # noqa: BLE001 - returned, not swallowed + return e + + with ThreadPoolExecutor(max_workers=self.n_workers) as ex: + return list(ex.map(one, items)) + + def warm(self, header: str, prelude: str = "", timeout: Optional[float] = None) -> list[Optional[BaseException]]: + """Start every worker and cache `header` in each (parallel). Returns per-worker + exception-or-None.""" + + def one(_i: int) -> Optional[BaseException]: + try: + with self.acquire() as w: + w.header_env(header, prelude, timeout) + return None + except BaseException as e: # noqa: BLE001 + return e + + # n threads each take one worker; they overlap because acquire() hands out + # distinct idle workers while earlier ones are still importing. + with ThreadPoolExecutor(max_workers=self.n_workers) as ex: + return list(ex.map(one, range(self.n_workers))) + + def memory_report(self) -> list[Optional[dict[str, float]]]: + return [w.memory() for w in self.workers] + + def close(self) -> None: + with self._cv: + self._closed = True + self._cv.notify_all() + for w in self.workers: + w.discard() + + def __enter__(self) -> "ReplPool": + return self + + def __exit__(self, *exc) -> None: + self.close() + + +def preflight_pool(requested: int, limits: ReplLimits, shared_gb: float = 4.0) -> int: + """Apply the host rules and return the worker count that fits. + + Delegates the three host checks (MemAvailable >= 45GB, load < 2x cores, disk queue + < 64) to `align.utils.guard.preflight_host_check` -- the same function the training + scripts use -- then shrinks `n` so that even every worker at its anon cap leaves the + 45GB floor intact. + """ + try: + from align.utils.guard import preflight_host_check + from align.exit_codes import PreflightRefused + + try: + preflight_host_check(strict=True) + except PreflightRefused as e: + raise HostBusy(str(e)) from e + except ImportError: # pragma: no cover - guard is part of this repo + pass + return plan_workers(requested, limits.anon_cap_gb, shared_gb, meminfo_available_gb()) diff --git a/code/align/verify/lean/reward.py b/code/align/verify/lean/reward.py new file mode 100644 index 0000000000000000000000000000000000000000..730f8d798299323036cf303d8c751b4bcef50f03 --- /dev/null +++ b/code/align/verify/lean/reward.py @@ -0,0 +1,141 @@ +"""Lean accuracy as a reward term: {0, 1}, 1 only when the STRICT tier passes. + +The seam (read, not changed): `align.rl.rewards.CompositeReward.__call__(accuracy, +format_score, response_len)` takes an `accuracy` float produced by a verifier layer and +only composes/itemises it; `align.rl.assembly.assemble_rollout` consumes a +`verify_batch(golds, preds) -> outcomes` surface whose outcomes expose `.name == +"CORRECT"`. This module provides an accuracy producer for both entry points and leaves +the GRPO loss, `CompositeReward` and `assemble_rollout` untouched: + + acc = LeanAccuracy(StrictVerifier(pool)) + accuracy, result = acc.score(statement, completion) # float in {0,1}, diagnostics + terms = composite(accuracy=accuracy, format_score=f, response_len=n) # existing API + +Binary on purpose. Leanabell-V2 found shaped rewards did slightly WORSE than binary +success; and any partial credit ("compiles but has sorry") is exactly the gradient a +policy follows to the exploit. All the information that is NOT in the reward (why a proof +was rejected) goes in `StrictResult.reasons/diagnostics`, returned separately, so the +trainer can log exploit signatures (`axiom:*`, `statement_mismatch`, `banned:*`) without +paying for them in the reward. + +Failure semantics: a proof that times out, OOMs or kills its REPL scores 0 (that is a +property of the proof). A DEAD VERIFIER must not: `LeanInfraError` is raised when the base +environment cannot be built, or when more than `max_infra_fraction` of a batch (of at +least `min_batch`) died for infrastructure reasons -- otherwise a broken toolchain would +feed the policy an all-zero reward that reads as "the model got worse". +""" + +from __future__ import annotations + +import re +from dataclasses import dataclass +from typing import Optional, Sequence + +from .strict import LeanInfraError, StrictResult, StrictVerifier + +_FENCE = re.compile(r"```[ \t]*([A-Za-z0-9_+-]*)[^\n]*\n(.*?)```", re.S) +_THINK = re.compile(r".*?", re.S) +_LEAN_LANGS = {"lean", "lean4", "Lean", "Lean4", ""} +_CODE_START = re.compile(r"\s*(import|open|set_option|theorem|lemma)\b") + + +def extract_lean_code(completion: Optional[str]) -> Optional[str]: + """The model's final Lean code block, or None. + + Policy: the LAST closed ```lean4/```lean (or bare) fence outside `` wins -- the + convention of the Goedel/DeepSeek prompts, where the plan precedes the code. A fence + that never closes (generation cut off by the length limit) is NOT salvaged: a + truncated proof is not a proof. Unfenced text counts only if it already starts like a + Lean file. + """ + if not completion: + return None + text = _THINK.sub("", completion) + blocks = [m.group(2) for m in _FENCE.finditer(text) if m.group(1) in _LEAN_LANGS] + if blocks: + return blocks[-1] + if "```" not in text and _CODE_START.match(text): + return text + return None + + +@dataclass(frozen=True) +class LeanScore: + accuracy: float + result: StrictResult + + +class LeanAccuracy: + def __init__( + self, + verifier: StrictVerifier, + max_infra_fraction: float = 0.5, + min_batch: int = 8, + ) -> None: + if not verifier.cfg.lexical_gate: + raise ValueError("StrictConfig(lexical_gate=False) is an ablation switch; not a reward") + self.verifier = verifier + self.max_infra_fraction = max_infra_fraction + self.min_batch = min_batch + + # ---- single + def score(self, statement: str, completion: Optional[str]) -> LeanScore: + res = self.verifier.verify(statement, extract_lean_code(completion)) + return LeanScore(res.accuracy, res) + + def __call__(self, statement: str, completion: Optional[str]) -> float: + return self.score(statement, completion).accuracy + + # ---- batch + def accuracy_batch( + self, + statements: Sequence[str], + completions: Sequence[Optional[str]], + progress=None, + ) -> tuple[list[float], list[StrictResult]]: + if len(statements) != len(completions): + raise ValueError(f"{len(statements)} statements vs {len(completions)} completions") + items = [(s, extract_lean_code(c)) for s, c in zip(statements, completions)] + results = self.verifier.verify_batch(items, progress=progress) if progress else self.verifier.verify_batch(items) + n_infra = sum(1 for r in results if r.infra_failure) + if len(results) >= self.min_batch and n_infra / len(results) > self.max_infra_fraction: + from collections import Counter + + by = Counter(r.reasons[0] for r in results if r.infra_failure) + raise LeanInfraError( + f"{n_infra}/{len(results)} verifications died for infrastructure reasons " + f"{dict(by)}: either the pool is dead or the policy is emitting REPL-killing " + f"proofs; refusing to emit a batch of zeros that reads as 'model got worse'" + ) + return [r.accuracy for r in results], results + + # ---- seams + def verify_batch(self, golds: Sequence[str], preds: Sequence[Optional[str]]) -> list: + """`OutcomeVerifier.verify_batch` surface (golds = formal statements, preds = + completion text or already-extracted code) for `assemble_rollout`-style callers.""" + from align.eval.verifier import Outcome # lazy: keeps this package import-light + + _, results = self.accuracy_batch(golds, preds) + out = [] + for r in results: + if r.accepted: + out.append(Outcome.CORRECT) + elif r.reasons == ("no_code",): + out.append(Outcome.NO_ANSWER) + elif r.undecided: + out.append(Outcome.UNDECIDED) # timeout / crash / memory: not a negative label + else: + out.append(Outcome.INCORRECT) + return out + + def reward_terms( + self, + composite, + statement: str, + completion: Optional[str], + format_score: float, + response_len: int, + ) -> tuple[dict, StrictResult]: + """Itemised `CompositeReward` terms for one completion, plus the diagnostics.""" + sc = self.score(statement, completion) + return composite(accuracy=sc.accuracy, format_score=format_score, response_len=response_len), sc.result diff --git a/code/align/verify/lean/sandbox.py b/code/align/verify/lean/sandbox.py new file mode 100644 index 0000000000000000000000000000000000000000..d6f43f768655914704fe73f7c946c9cf4f292ca2 --- /dev/null +++ b/code/align/verify/lean/sandbox.py @@ -0,0 +1,503 @@ +"""OS-level sandbox for the Lean REPL child (opt-in; stdlib + ctypes only). + +Why this exists +--------------- +The static gate (`strict.py`) and the audit (`#print axioms`) decide whether a proof is +ACCEPTED. They do not constrain what the elaborator DOES while it checks one. Lean is a +programming language: `#eval`, `run_cmd`, `initialize`, a `macro`/`elab` that calls +`IO.Process.spawn`, `IO.FS.writeFile`, or `IO.getStdout` all execute arbitrary code, as the +user who runs the RL job, on a box that also holds the training checkpoints, `hf_cache/token` +and `~/.ssh`. A policy that is rewarded for compiling proofs is an optimiser pointed at +that surface: the cheapest "proof" that reads the reward cache, or kills the neighbouring +training run (same uid => `kill(2)` and `ptrace(2)` are allowed), is one gradient step +away. Until now the only containment was `prlimit` + a memory watchdog (resource +exhaustion, not capability). This module closes that gap with kernel namespaces, using +nothing that needs root (`unshare -Urn true` works here; there is no bwrap/firejail). + +What the child sees (each line is pinned by tests/test_lean_sandbox.py) +------------------------------------------------------------------------ +* NETWORK new net namespace: only a DOWN loopback. `connect()` to anything, including + 127.0.0.1, fails (ENETUNREACH). Abstract AF_UNIX sockets are per-netns too. +* FILESYSTEM an ALLOW-LIST root, not a read-only view of `/`. The child's `/` is a fresh + tmpfs (itself remounted read-only) containing only: the system dirs the + dynamic loader needs (`/usr`, plus the `/bin /lib /lib64 /sbin` symlinks), + a few `/etc` files, `/dev/{null,zero,full,random,urandom}`, a procfs of the + NEW pid namespace, the paths in `ro_paths` (the Lean install) bound READ-ONLY, + and ONE writable dir: `scratch_dir` (bound rw) plus a small noexec tmpfs on + `/tmp`. `/home`, `/root`, `/apps/*` other than the toolchain, checkpoints and + tokens simply do not exist. (A read-only view of `/` was the fallback plan; it + is unnecessary because unprivileged `pivot_root` into a tmpfs works here, and + it is strictly better: it also hides secrets rather than only protecting them + from writes.) +* PIDS new pid namespace + new procfs: the child cannot see, signal or ptrace any + other process of this uid (the neighbouring training job). Its pid 1 is the + REPL; when it dies the kernel SIGKILLs everything else in the namespace, so a + `setsid`+double-fork daemon from a proof cannot outlive the worker. +* PRIVILEGE `PR_SET_NO_NEW_PRIVS`; uid/gid mapped 1:1 to the caller (NOT fake root), so + the exec drops every capability: `CapEff=0` in the REPL. `setgroups` denied. +* IPC/UTS new ipc and uts namespaces (no SysV shm/sem/queues shared with the host). +* ENV only the variables the caller lists; `PATH` is pruned to entries that exist + in the new root; `HOME`/`TMPDIR` point at the private dirs. +* LIFETIME own session/process group, `RLIMIT_CORE=0`, a supervisor that SIGKILLs the + REPL when the parent process (not just the spawning thread) disappears. + +What is NOT claimed +------------------- +* No seccomp filter: the child can still make any syscall the kernel namespaces allow. + Kernel bugs in those paths are out of scope. Namespaces are a capability boundary, not a + proof of confinement. +* CPU/memory/file-size limits are still the pool's (`prlimit`, `smaps_rollup` watchdog). + The sandbox is composed OUTSIDE them: `sandbox -- nice prlimit stdbuf repl`. +* GPUs are not exposed (no `/dev/nvidia*`): the REPL never needs them. +* The toolchain is shared read-only between workers; scratch is per worker. + +Why a supervisor process instead of `preexec_fn` +------------------------------------------------- +`ReplPool` spawns from `ThreadPoolExecutor` threads: `preexec_fn` is unsafe in a threaded +parent and `unshare(CLONE_NEWUSER)` requires a single-threaded caller. `PR_SET_PDEATHSIG` +is documented (prctl(2)) to fire when the spawning THREAD exits, which for the pool is the +end of every `ReplPool.map`; on this host's kernel (6.1) it was measured NOT to fire for a +non-leader thread, but the guarantee differs across kernels, so nothing here depends on +it either way: the supervisor polls its parent PROCESS (`getppid()` changes when the +parent dies) and kills the REPL itself. So the launcher is a tiny single-threaded python +(`python -I -S sandbox.py ...`) that does the unshares, forks the REPL into the new pid +namespace, and stays outside as that supervisor. `Popen.pid` is therefore the supervisor, +not the REPL; `inner_pid()` returns the REPL's host pid (used by the memory watchdog) from a +pidfile that lives OUTSIDE the sandbox. +""" + +from __future__ import annotations + +import ctypes +import ctypes.util +import errno +import json +import os +import select +import signal +import stat +import subprocess +import sys +import time +from dataclasses import asdict, dataclass, field +from typing import Optional, Sequence + +# --------------------------------------------------------------------------- constants + +CLONE_NEWNS = 0x00020000 +CLONE_NEWUTS = 0x04000000 +CLONE_NEWIPC = 0x08000000 +CLONE_NEWUSER = 0x10000000 +CLONE_NEWPID = 0x20000000 +CLONE_NEWNET = 0x40000000 + +MS_RDONLY = 1 +MS_NOSUID = 2 +MS_NODEV = 4 +MS_NOEXEC = 8 +MS_REMOUNT = 32 +MS_NOATIME = 1024 +MS_NODIRATIME = 2048 +MS_BIND = 4096 +MS_REC = 16384 +MS_PRIVATE = 1 << 18 +MS_RELATIME = 1 << 21 +MNT_DETACH = 2 + +PR_SET_PDEATHSIG = 1 +PR_SET_NO_NEW_PRIVS = 38 + +#: statvfs.f_flag -> MS_* (the bits a bind-remount of a userns-locked mount must preserve) +_ST_TO_MS = ( + (getattr(os, "ST_NOSUID", 2), MS_NOSUID), + (getattr(os, "ST_NODEV", 4), MS_NODEV), + (getattr(os, "ST_NOEXEC", 8), MS_NOEXEC), + (getattr(os, "ST_NOATIME", 1024), MS_NOATIME), + (getattr(os, "ST_NODIRATIME", 2048), MS_NODIRATIME), + (getattr(os, "ST_RELATIME", 4096), MS_RELATIME), +) + +#: Directories the dynamic loader / coreutils wrappers (`nice`, `prlimit`, `stdbuf`) need. +DEFAULT_SYSTEM_DIRS = ("/usr",) +#: Individual files (never directories) bound read-only from /etc when they exist. +DEFAULT_ETC_FILES = ( + "/etc/ld.so.cache", + "/etc/ld.so.conf", + "/etc/nsswitch.conf", + "/etc/passwd", + "/etc/group", + "/etc/localtime", +) +DEFAULT_DEVICES = ("null", "zero", "full", "random", "urandom") +#: Environment variables that survive `minimal_env` (the REPL child's contract). +ENV_KEEP = ("LEAN_PATH", "LD_LIBRARY_PATH", "LEAN_SYSROOT", "MALLOC_ARENA_MAX", "LANG", "LC_ALL", "PATH") + + +class SandboxUnavailable(RuntimeError): + """The kernel refuses the namespaces we need (userns disabled, seccomp'd container...).""" + + +@dataclass(frozen=True) +class SandboxSpec: + """Everything the in-sandbox setup needs, JSON-serialisable (it travels in argv).""" + + #: The ONLY writable directory (bound rw at the same path inside). Must exist. + scratch_dir: str + #: Extra read-only paths (the Lean install root). Files and dirs both fine. + ro_paths: tuple = () + system_dirs: tuple = DEFAULT_SYSTEM_DIRS + etc_files: tuple = DEFAULT_ETC_FILES + devices: tuple = DEFAULT_DEVICES + #: chdir here after the pivot (must lie inside an allowed path). + cwd: Optional[str] = None + #: Where the supervisor writes the REPL's HOST pid. Keep it OUTSIDE scratch/ro_paths. + pidfile: Optional[str] = None + tmpfs_mb: int = 64 + #: Environment handed to the final exec (already minimal; see `minimal_env`). + env: dict = field(default_factory=dict) + #: Supervisor poll period for "did my parent die" (also bounds exit-propagation lag). + parent_poll_s: float = 0.25 + #: False = LIFETIME ONLY: no namespaces and no mounts (the explicit `sandbox=False` opt-out of the pool), but the + #: child is still forked under the supervisor, so it dies with the parent process. Never the default. + isolate: bool = True + + def to_json(self) -> str: + d = asdict(self) + return json.dumps(d, sort_keys=True) + + @staticmethod + def from_json(s: str) -> "SandboxSpec": + d = json.loads(s) + for k in ("ro_paths", "system_dirs", "etc_files", "devices"): + d[k] = tuple(d[k]) + return SandboxSpec(**d) + + +# --------------------------------------------------------------------------- parent side + +def minimal_env(env: dict, scratch_dir: str, keep: Sequence[str] = ENV_KEEP) -> dict: + """The environment the REPL gets inside the sandbox. + + `keep` allow-list only (inherited secrets such as `HF_TOKEN`, `WANDB_API_KEY`, + `SSH_AUTH_SOCK` must not reach code a policy wrote); `HOME` -> scratch, `TMPDIR` -> + the in-sandbox `/tmp`. `PATH` is pruned inside the sandbox (entries under /home etc. + do not exist there). + """ + out = {k: v for k, v in env.items() if k in keep} + out["HOME"] = scratch_dir + out["TMPDIR"] = "/tmp" + return out + + +def sandbox_argv(spec: SandboxSpec, cmd: Sequence[str]) -> list[str]: + """argv that runs `cmd` inside the sandbox. `cmd[0]` must be an absolute path. + + Intended use: `Popen(sandbox_argv(spec, pre + repl_argv), env=HELPER_ENV, cwd=...)` + where `HELPER_ENV` is `helper_env()` (NOT the lean env: LD_LIBRARY_PATH would then be + applied to the python helper too). The lean env travels in `spec.env`. + """ + if not cmd or not os.path.isabs(cmd[0]): + raise ValueError("sandboxed command must be an absolute path") + return [sys.executable, "-I", "-S", os.path.abspath(__file__), spec.to_json(), "--", *cmd] + + +def helper_env() -> dict: + """Environment for the launcher python itself: nothing the sandboxed code could use.""" + return {"LANG": "C.UTF-8", "LC_ALL": "C.UTF-8"} + + +def inner_pid(spec: SandboxSpec, supervisor_pid: Optional[int] = None) -> Optional[int]: + """Host pid of the REPL (pid 1 of the sandbox), or None before it has started. + + Pass the supervisor's pid (`Popen.pid`) whenever it is known. The pidfile outlives the + process it names: after a kill/respawn (or if the new launcher dies in setup before + rewriting it) it still holds the PREVIOUS REPL's pid, and on a box that has been up for + weeks that number can already belong to an unrelated process -- the memory watchdog would + then bill the neighbouring training job's RSS to a healthy proof worker and kill it. The + REPL is, by construction, a direct child of its supervisor, so a pid whose parent is not + `supervisor_pid` is stale and is reported as None.""" + if not spec.pidfile: + return None + try: + with open(spec.pidfile) as f: + pid = int(f.read().strip() or 0) or None + except (OSError, ValueError): + return None + if pid and supervisor_pid is not None: + try: + with open(f"/proc/{pid}/stat") as f: + ppid = int(f.read().rsplit(")", 1)[1].split()[1]) + except (OSError, ValueError, IndexError): + return None + if ppid != supervisor_pid: + return None + return pid + + +_SUPPORTED: Optional[tuple] = None + + +def sandbox_supported(refresh: bool = False) -> tuple: + """(ok, reason). Actually runs the launcher on `/usr/bin/true` -- a `/proc` flag is not + proof (containers and LSMs deny namespaces in ways no sysctl advertises).""" + global _SUPPORTED + if _SUPPORTED is not None and not refresh: + return _SUPPORTED + import tempfile + + base = os.environ.get("TMPDIR") or tempfile.gettempdir() + try: + with tempfile.TemporaryDirectory(dir=base) as d: + spec = SandboxSpec(scratch_dir=d, env=helper_env()) + r = subprocess.run( + sandbox_argv(spec, ["/usr/bin/true"]), + env=helper_env(), + capture_output=True, + timeout=30, + ) + ok = r.returncode == 0 + _SUPPORTED = (ok, "" if ok else r.stderr.decode("utf-8", "replace")[-400:]) + except Exception as e: # noqa: BLE001 + _SUPPORTED = (False, repr(e)) + return _SUPPORTED + + +# --------------------------------------------------------------------------- child side + +_libc = None + + +def _libc_(): + global _libc + if _libc is None: + _libc = ctypes.CDLL(ctypes.util.find_library("c") or "libc.so.6", use_errno=True) + return _libc + + +def _check(rc: int, what: str) -> None: + if rc != 0: + e = ctypes.get_errno() + raise OSError(e, f"{what}: {os.strerror(e)}") + + +def _mount(source, target, fstype, flags, data=None) -> None: + def b(x): + return None if x is None else os.fsencode(x) + + rc = _libc_().mount(b(source), b(target), b(fstype), ctypes.c_ulong(flags), b(data)) + _check(rc, f"mount({source!r} -> {target!r}, flags={flags:#x})") + + +def _preserved_flags(path: str) -> int: + f = os.statvfs(path).f_flag + out = 0 + for st, ms in _ST_TO_MS: + if f & st: + out |= ms + return out + + +def _bind(src: str, dst: str, rdonly: bool) -> None: + """Non-recursive bind (submounts of src are NOT carried: a nested rw mount would + punch a writable hole in a read-only tree) then remount with preserved flags.""" + keep = _preserved_flags(src) + _mount(src, dst, None, MS_BIND, None) + flags = MS_BIND | MS_REMOUNT | keep | (MS_RDONLY if rdonly else 0) + _mount(None, dst, None, flags, None) + + +def _ensure_target(newroot: str, path: str, is_dir: bool) -> str: + t = newroot + path + if is_dir: + os.makedirs(t, exist_ok=True) + else: + os.makedirs(os.path.dirname(t), exist_ok=True) + if not os.path.exists(t): + open(t, "wb").close() + return t + + +def _bind_ro_into(newroot: str, path: str, done: set, rdonly: bool = True, as_path: Optional[str] = None) -> None: + """Make `path` appear (read-only) at the same path under newroot. A symlink is + recreated as a symlink and its target is bound too, so `/bin -> usr/bin` keeps working. + + `as_path` binds the (already resolved) source at a DIFFERENT in-sandbox path: the spelling + the caller used for it (`LEAN_PATH`, `cwd`, `HOME` are all unresolved strings). Without + it a toolchain reached through a symlinked parent exists in the sandbox only under its + real name, and every later `chdir`/`open` of the configured spelling is ENOENT.""" + dst = as_path or path + if dst in done: + return + done.add(dst) + if os.path.islink(path): + tgt = os.readlink(path) + link = newroot + path + os.makedirs(os.path.dirname(link), exist_ok=True) + if not os.path.lexists(link): + os.symlink(tgt, link) + real = os.path.normpath(os.path.join(os.path.dirname(path), tgt)) + _bind_ro_into(newroot, real, done, rdonly) + return + if not os.path.exists(path): + return + is_dir = stat.S_ISDIR(os.stat(path).st_mode) + t = _ensure_target(newroot, dst, is_dir) + _bind(path, t, rdonly) + + +def _write(path: str, data: str) -> None: + with open(path, "w") as f: + f.write(data) + + +def _setup_mounts(spec: SandboxSpec) -> None: + """Runs in the pid-1 child. Builds the allow-list root and pivots into it.""" + _mount(None, "/", None, MS_REC | MS_PRIVATE) # nothing we do may propagate to the host + scratch = os.path.realpath(spec.scratch_dir) + if not os.path.isdir(scratch): + # makedirs below would otherwise CREATE the path on the host and run "sandboxed" + # with a scratch the caller never made (and a typo'd path would silently work). + raise FileNotFoundError(f"scratch_dir does not exist: {spec.scratch_dir!r}") + newroot = os.path.join(scratch, ".sandbox-root") + os.makedirs(newroot, exist_ok=True) + _mount("tmpfs", newroot, "tmpfs", MS_NOSUID | MS_NODEV, "size=1m,mode=755") + + done: set = set() + for d in spec.system_dirs: + _bind_ro_into(newroot, d, done) + for link in ("/bin", "/sbin", "/lib", "/lib64"): # usrmerge symlinks + if os.path.islink(link): + _bind_ro_into(newroot, link, done) + for p in spec.ro_paths: + real, spelled = os.path.realpath(p), os.path.abspath(p) + _bind_ro_into(newroot, real, done) + if spelled != real: # reached through a symlink: keep the caller's spelling valid too + _bind_ro_into(newroot, real, done, as_path=spelled) + for f in spec.etc_files: + _bind_ro_into(newroot, f, done) + + # devices: individual nodes only. (nodev is a property of the SOURCE mount; /dev is + # devtmpfs without it, and the tmpfs they land on has nodev cleared for the dev dir.) + devdir = newroot + "/dev" + os.makedirs(devdir, exist_ok=True) + _mount("tmpfs", devdir, "tmpfs", MS_NOSUID | MS_NOEXEC, "size=64k,mode=755") + for dname in spec.devices: + src = "/dev/" + dname + if os.path.exists(src): + tgt = devdir + "/" + dname + open(tgt, "wb").close() + _mount(src, tgt, None, MS_BIND, None) + _mount(None, devdir, None, MS_REMOUNT | MS_RDONLY | MS_NOSUID | MS_NOEXEC, "size=64k,mode=755") + + os.makedirs(newroot + "/proc", exist_ok=True) + _mount("proc", newroot + "/proc", "proc", MS_NOSUID | MS_NODEV | MS_NOEXEC) + + os.makedirs(newroot + "/tmp", exist_ok=True) + _mount("tmpfs", newroot + "/tmp", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC, + f"size={int(spec.tmpfs_mb)}m,mode=1777") + + # the ONE writable host directory (rw bind). Done last so nothing above can alias it. + for where in dict.fromkeys((scratch, os.path.abspath(spec.scratch_dir))): # real + spelled + _bind(scratch, _ensure_target(newroot, where, True), rdonly=False) + # scratch/.sandbox-root is a non-recursive bind artefact; hide it from the child. + # (Non-rec bind: the tmpfs mounted on it is not carried, so it is just an empty dir.) + + # make the new root itself read-only, then pivot. pivot_root(".", ".") stacks the old + # root over the new one; detaching it leaves no fd or path to the host filesystem. + _mount(None, newroot, None, MS_REMOUNT | MS_RDONLY | MS_NOSUID | MS_NODEV, "size=1m,mode=755") + os.chdir(newroot) + _check(_libc_().syscall(155 if os.uname().machine == "x86_64" else 41, b".", b"."), "pivot_root") + _check(_libc_().umount2(b".", MNT_DETACH), "umount old root") + os.chdir("/") + + +def _prctl(option: int, arg2: int = 0) -> None: + _check(_libc_().prctl(option, ctypes.c_ulong(arg2), 0, 0, 0), f"prctl({option})") + + +def _inner(spec: SandboxSpec, cmd: Sequence[str], supervisor_pid: int) -> None: + # (getppid() is 0 here -- the parent lives outside our pid namespace -- so the tiny + # fork->prctl race cannot be checked; PDEATHSIG covers every later supervisor death.) + _prctl(PR_SET_PDEATHSIG, signal.SIGKILL) + if spec.isolate: + _setup_mounts(spec) + env = dict(spec.env) + if "PATH" in env: + env["PATH"] = ":".join(p for p in env["PATH"].split(":") if p and os.path.isdir(p)) + if spec.cwd: + os.chdir(spec.cwd) + import resource + + resource.setrlimit(resource.RLIMIT_CORE, (0, 0)) + _prctl(PR_SET_NO_NEW_PRIVS, 1) + # nothing but stdio crosses the exec + os.closerange(3, 1 << 16) + os.execve(cmd[0], list(cmd), env) + + +def _supervise(inner: int, parent: int, spec: SandboxSpec) -> None: + """Outside the pid namespace. Never returns.""" + if spec.pidfile: + tmp = spec.pidfile + ".tmp" + _write(tmp, str(inner)) + os.replace(tmp, spec.pidfile) + + def die(signum, _frm): + try: + os.kill(inner, signal.SIGKILL) + finally: + os._exit(128 + signum) + + for s in (signal.SIGTERM, signal.SIGINT, signal.SIGHUP): + signal.signal(s, die) + pidfd = os.pidfd_open(inner) + while True: + r, _, _ = select.select([pidfd], [], [], spec.parent_poll_s) + if r: + _, status = os.waitpid(inner, 0) + os._exit(os.waitstatus_to_exitcode(status) % 256 if os.waitstatus_to_exitcode(status) >= 0 + else 128 - os.waitstatus_to_exitcode(status)) + if os.getppid() != parent: # reparented => the spawning PROCESS is gone + os.kill(inner, signal.SIGKILL) + os.waitpid(inner, 0) + os._exit(137) + + +def run(spec: SandboxSpec, cmd: Sequence[str]) -> None: + """Entry point of the launcher process. Does not return (execs or exits).""" + parent = os.getppid() + try: + os.setsid() + except OSError: + pass # already a session leader (Popen(start_new_session=True)) + uid, gid = os.getuid(), os.getgid() + flags = CLONE_NEWUSER | CLONE_NEWNET | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_NEWPID + if spec.isolate: + try: + _check(_libc_().unshare(flags), "unshare") + _write("/proc/self/setgroups", "deny") + _write("/proc/self/uid_map", f"{uid} {uid} 1\n") + _write("/proc/self/gid_map", f"{gid} {gid} 1\n") + except OSError as e: + sys.stderr.write(f"sandbox unavailable: {e}\n") + os._exit(125) + me = os.getpid() + pid = os.fork() # first child after CLONE_NEWPID is pid 1 of the new namespace + if pid: + _supervise(pid, parent, spec) + try: + _inner(spec, cmd, me) + except BaseException as e: # noqa: BLE001 - must not fall through into the caller + sys.stderr.write(f"sandbox setup failed: {e!r}\n") + os._exit(126) + + +def main(argv: Sequence[str]) -> None: + if len(argv) < 4 or argv[2] != "--": + sys.stderr.write("usage: sandbox.py SPEC_JSON -- CMD...\n") + os._exit(2) + run(SandboxSpec.from_json(argv[1]), argv[3:]) + + +if __name__ == "__main__": + main(sys.argv) diff --git a/code/align/verify/lean/strict.py b/code/align/verify/lean/strict.py new file mode 100644 index 0000000000000000000000000000000000000000..862665bc2cb185ae33fba12ece857c410703fcdb --- /dev/null +++ b/code/align/verify/lean/strict.py @@ -0,0 +1,980 @@ +"""The STRICT tier: "it compiles" is not "it proves the statement". + +A candidate proof is ACCEPTED only if ALL of the following hold. Each rule is a measured +or published way a policy under RL scores reward without proving anything (the audit +literature: AXLE, Lean FRO's comparator, miniF2F audits; Pythagoras saw models rewrite +statements to fit flawed proofs). This house has already scored a perfect policy 0/100 +because of a broken grader, and the mirror image -- a grader that accepts junk -- is +worse, because the policy finds it. + +1. **Lexical gate** (pure Python, no Lean; `static_check`). No `sorry`/`admit`, + `native_decide`, `unsafe`/`partial`, `implemented_by`/`extern`/`export`, `axiom`/`opaque`, + no meta-programming (`elab`/`macro`/`syntax`/`notation`/`run_cmd`/`initialize`/...), no + `#`-commands, no `namespace`/`section`/`variable`/`attribute`/`local`/`scoped`, a + WHITELIST of `set_option` names (`debug.skipKernelTC` would switch the kernel off), + and, unless `allow_helper_defs`, no `def`/`abbrev`/`instance`. The candidate must start + with the reference's header token-for-token and contain exactly one declaration of the + reference's name, with no `private`/`protected`/attributes on it. In `statement_mode = + "strict"` its signature must equal the reference's token-for-token (whitespace and + comments ignored). +2. **Compile** in a REPL environment that already contains the REFERENCE statement, + elaborated by us in a clean environment as `_align_ref`. No error, no `sorry` warning, + empty `sorries` list. +3. **Audit** (Lean metaprogram, `AUDIT_PRELUDE`, trusted: it is compiled into the base + environment BEFORE any candidate text exists, so a candidate can add constants but not + change what the audit does): + * the target is a `theorem`; + * its axioms (our own transitive walk, same algorithm as `#print axioms`; Lean 4.9 has + no public `collectAxioms`) are within {propext, Quot.sound, Classical.choice}. This is + what catches `native_decide` (Lean.ofReduceBool) and `sorry` (sorryAx) even if rule 1's + lexer were fooled; + * **statement bridge**: the kernel is asked to check `theorem _align_bridge : + := `. That is the definition of "proves the + given statement", stronger than comparing strings and stronger than `isDefEq` in the + elaborator: it defeats a definition-hole (candidate shadows `sqrt`, or adds a + coercion/instance, so the SAME text means something else) because the reference type + was elaborated before the candidate existed; + * `debug.skipKernelTC` is off, and (`kernel_recheck=True`, opt-in: 2-3x cost) every local + theorem is re-added with kernel checking forced ON, so even if checking had been disabled + while the candidate elaborated the kernel still sees every proof term; + * no NEW local constant mentions `Lean.Elab/Meta/Macro/Parser/...`, `IO`, `unsafeCast`: + the signature of an `elab`/`macro` that slipped past the lexer. The baseline (the + prelude's own meta constants) is measured on the reference environment and subtracted. + +Lean-lexer desync is the residual risk of rule 1 (a construct my tokenizer reads as a +comment/string but Lean reads as code). The tokenizer is Lean-faithful for nested block +comments, line comments, string escapes, raw strings, char literals, `«»`, numerals (a numeral +never swallows following letters: `1macro` is `1` + `macro`) and the longest-match symbols that +end in `/` (`\\/`, `//`: in `a \\/-1` the `-1` is code, not a comment). A comment opener glued to +any other symbol character is REFUSED as ambiguous (`parse_error`) instead of guessed; on ANY +unusual construct (`s!"..{..}"` interpolation, raw string, `«»`, `'"'`) it flags an +anomaly and the gate falls back to a RAW scan that rejects the banned words even inside +comments/strings. Rule 3 is independent of the lexer. + +Failure taxonomy (`StrictResult.reasons`): `no_code`, `parse_error`, `unsupported_statement`, +`header_mismatch`, `target_missing`, `target_modifier`, `statement_mismatch`, +`banned:`, `compile_error`, `sorry`, `not_theorem`, `axiom:`, `bridge_failed`, +`kernel_recheck_failed`, `meta_decl`, `skip_kernel_tc`, `timeout`, `crash`, `memory`, +`output_too_large`, `protocol`, `reference_invalid`. + +Stdlib only. +""" + +from __future__ import annotations + +import json +import re +import secrets +import time +from dataclasses import dataclass, field +from functools import lru_cache +from typing import Callable, Optional, Sequence + +from .repl_pool import HeaderError, ReplError, ReplPool, ReplProtocolError, Worker + +AXIOM_WHITELIST = frozenset({"propext", "Quot.sound", "Classical.choice"}) +REF_NAME = "_align_ref" +#: Reported as an axiom when the Lean-side axiom walk ran out of fuel (see AUDIT_PRELUDE): never whitelisted. +FUEL_SENTINEL = "_align_fuel_exhausted" +#: Identifiers a candidate may not spell: our reference alias and bridge (a sorry-backed theorem lives under the first). +INTERNAL_ID_PREFIXES = ("_align",) + +# ============================================================================ Lean prelude +#: Trusted audit code, compiled into each worker's base environment (after the header, before +#: any candidate). Verified against Lean 4.9.0-rc1 (the pinned toolchain); see tests. +AUDIT_PRELUDE = r''' +open Lean in +def alignCollectAxioms (env : Environment) (start : Name) : Array Name := Id.run do + let mut visited : NameSet := {} + let mut axs : Array Name := #[] + let mut stack : Array Name := #[start] + let mut fuel := 2000000 + while !stack.isEmpty && fuel > 0 do + fuel := fuel - 1 + let n := stack.back + stack := stack.pop + if visited.contains n then continue + visited := visited.insert n + match env.find? n with + | none => pure () + | some ci => + stack := ci.type.getUsedConstants.foldl (fun s c => s.push c) stack + match ci with + | .axiomInfo _ => axs := axs.push n + | .defnInfo v => stack := v.value.getUsedConstants.foldl (fun s c => s.push c) stack + | .thmInfo v => stack := v.value.getUsedConstants.foldl (fun s c => s.push c) stack + | .opaqueInfo v => stack := v.value.getUsedConstants.foldl (fun s c => s.push c) stack + | .quotInfo _ => pure () + | .ctorInfo v => stack := stack.push v.induct + | .recInfo v => stack := v.all.foldl (fun s c => s.push c) stack + | .inductInfo v => stack := v.ctors.foldl (fun s c => s.push c) stack + -- FAIL CLOSED: running out of fuel means the walk is INCOMPLETE; an incomplete axiom list must never + -- read as a clean one, so report a name that is not on any whitelist. + if !stack.isEmpty then + axs := axs.push `_align_fuel_exhausted + return axs + +open Lean in +def alignReDecl (i : Nat) (ci : ConstantInfo) : TheoremVal := + { name := Name.mkSimple ("_align_re" ++ toString i), levelParams := ci.levelParams, type := ci.type, value := ci.value! } + +open Lean Elab Command Meta in +elab "#align_audit " nonce:str flags:num cand:ident ref:ident : command => do + let env0 ← getEnv + let candName := cand.getId + let refName := ref.getId + let tag := "ALIGN_AUDIT " ++ nonce.getString ++ " " + let some candCi := env0.find? candName + | logInfo m!"{tag}{(Json.mkObj [("found", Json.bool false)]).compress}"; return + let some refCi := env0.find? refName + | logInfo m!"{tag}{(Json.mkObj [("found", Json.bool true), ("ref_found", Json.bool false)]).compress}"; return + let kind := match candCi with + | .thmInfo _ => "theorem" | .defnInfo _ => "def" | .axiomInfo _ => "axiom" + | .opaqueInfo _ => "opaque" | .inductInfo _ => "inductive" | .ctorInfo _ => "ctor" + | .recInfo _ => "rec" | .quotInfo _ => "quot" + let axioms := alignCollectAxioms env0 candName + -- statement bridge: the kernel checks that the candidate inhabits the REFERENCE type + let mut bridge := false + let mut bridgeErr := "" + if candCi.levelParams.length != refCi.levelParams.length then + bridgeErr := "level_params_mismatch" + else + let decl := Declaration.thmDecl { + name := `_align_bridge, levelParams := refCi.levelParams, type := refCi.type, + value := mkConst candName (refCi.levelParams.map mkLevelParam) } + try + withScope (fun s => { s with opts := s.opts.setBool `debug.skipKernelTC false }) do + liftCoreM (addDecl decl) + bridge := true + catch e => + bridgeErr := (← e.toMessageData.toString) + setEnv env0 + -- local declarations that reference meta-programming or IO (slipped-past elab/macro) + let metaPrefixes : List Name := [`Lean.Elab, `Lean.Meta, `Lean.Macro, `Lean.MacroM, `Lean.Parser, + `Lean.ParserDescr, `Lean.PrettyPrinter, `Lean.Syntax, `Lean.TSyntax, `Lean.Environment, + `Lean.Core, `Lean.CoreM, `IO, `EIO, `BaseIO, `unsafeCast, `Lean.Compiler] + let isMeta (n : Name) : Bool := metaPrefixes.any fun p => p.isPrefixOf n + let mut metaDecls : Array String := #[] + let mut nLocal := 0 + let mut localThms : Array (Name × ConstantInfo) := #[] + for (n, ci) in env0.constants.map₂.toList do + nLocal := nLocal + 1 + let used := ci.type.getUsedConstants ++ (match ci.value? with | some v => v.getUsedConstants | none => #[]) + if used.any isMeta then metaDecls := metaDecls.push n.toString + if let .thmInfo _ := ci then + if n != refName then localThms := localThms.push (n, ci) + -- kernel re-check of every local theorem with kernel checking forced ON + let mut recheckErr := "" + if flags.getNat &&& 1 == 1 then + let mut i := 0 + for (_, ci) in localThms do + i := i + 1 + try + withScope (fun s => { s with opts := s.opts.setBool `debug.skipKernelTC false }) do + liftCoreM (addDecl (Declaration.thmDecl (alignReDecl i ci))) + catch e => + recheckErr := (← e.toMessageData.toString) + break + setEnv env0 + let foreign := candCi.type.getUsedConstants.filter fun n => (env0.getModuleIdxFor? n).isNone + let skipTC := (← getOptions).getBool `debug.skipKernelTC false + let j := Json.mkObj [("found", Json.bool true), ("kind", kind), + ("axioms", toJson (axioms.map toString)), ("bridge", Json.bool bridge), + ("bridge_err", bridgeErr), ("foreign", toJson (foreign.map toString)), + ("skip_tc", Json.bool skipTC), ("meta_decls", toJson metaDecls), + ("n_local", toJson nLocal), ("recheck_err", recheckErr)] + logInfo m!"{tag}{j.compress}" +''' + +# ============================================================================ tokenizer + +_SUBSCRIPT = set(range(0x2080, 0x208A)) | set(range(0x2090, 0x209D)) | set(range(0x1D62, 0x1D6B)) +_NUM = re.compile( + r"0[xX][0-9a-fA-F]+|0[bB][01]+|0[oO][0-7]+|[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?" +) +_RAW_OPEN = re.compile(r'r(#*)"') +_NOT_LETTERLIKE = {"λ", "Π", "Σ"} # Lean keeps these as binders/keywords, not identifier chars + +_MULTI_SYMS = sorted( + [ + ":=", "=>", "->", "<-", "<=", ">=", "!=", "==", "&&", "||", "::", "++", "...", "..", + "<;>", "|>.", "|>", "<|", "\\/", "/\\", "//", "@[", "#[", "∘", "≠", "←", "↔", "→", "≤", "≥", "⟨", "⟩", + ], + key=len, + reverse=True, +) + + +#: characters after which `--`/`/-` is unambiguously a comment opener (whitespace, identifier/number characters +#: and closing brackets are never the tail of a longer Lean symbol token). +_SAFE_BEFORE_COMMENT = frozenset(" \t\r\n_'!?)]}⟩⦄\"»") + + +def _id_start(c: str) -> bool: + if c == "_": + return True + if c in _NOT_LETTERLIKE: + return False + return c.isalpha() + + +def _id_rest(c: str) -> bool: + return ( + _id_start(c) + or c.isdigit() + or c in ("'", "!", "?") + or ord(c) in _SUBSCRIPT + ) + + +@dataclass(frozen=True) +class Tok: + kind: str # id | hash | num | sym | str | char + text: str + start: int + end: int + + +@dataclass +class Lexed: + toks: list[Tok] + #: Unusual constructs the faithful-lexer assumption is weakest on; non-empty => the + #: banned-word gate also runs on the RAW text. + anomalies: set[str] = field(default_factory=set) + #: Lean would reject the file (parse error); no point sending it to the REPL. + broken: Optional[str] = None + + +def lex(src: str) -> Lexed: + """Tokenize Lean 4 source, dropping whitespace and comments, mirroring Lean's rules: + `--` line comments, NESTED `/- -/` block comments (incl. `/--` and `/-!`), string + literals with backslash escapes, raw strings `r#"..."#`, char literals, `«ident»`.""" + toks: list[Tok] = [] + an: set[str] = set() + broken: Optional[str] = None + glued = False + i, n = 0, len(src) + while i < n: + c = src[i] + if c.isspace(): + i += 1 + continue + if (c == "-" and src.startswith("--", i)) or (c == "/" and src.startswith("/-", i)): + if i > 0 and src[i - 1] not in _SAFE_BEFORE_COMMENT and not src[i - 1].isalnum(): + # a comment opener glued to a symbol character: whether it opens a comment depends on + # Lean's token table (`\/-1`, `//-1`, `|--` are NOT comments there). We do not guess. + an.add("glued_comment") + glued = True + if c == "-" and src.startswith("--", i): + j = src.find("\n", i) + i = n if j < 0 else j + 1 + continue + if c == "/" and src.startswith("/-", i): + depth, j = 1, i + 2 + while j < n and depth: + if src.startswith("/-", j): + depth += 1 + j += 2 + elif src.startswith("-/", j): + depth -= 1 + j += 2 + else: + j += 1 + if depth: + broken = "unterminated block comment" + i = j + continue + start = i + if c == "«": + j = src.find("»", i + 1) + if j < 0: + broken = "unterminated «" + j = n - 1 + an.add("guillemet") + toks.append(Tok("id", src[i : j + 1], i, j + 1)) + i = j + 1 + continue + if c == "r" and (m := _RAW_OPEN.match(src, i)): + hashes = m.group(1) + close = '"' + hashes + j = src.find(close, m.end()) + an.add("raw_string") + if j < 0: + broken = "unterminated raw string" + j = n - len(close) + toks.append(Tok("str", src[i : j + len(close)], i, j + len(close))) + i = j + len(close) + continue + if _id_start(c): + j = i + 1 + while j < n and _id_rest(src[j]): + j += 1 + # dotted continuation: a.b.c ; only when a letter (or «) follows the dot + while j + 1 < n and src[j] == "." and (_id_start(src[j + 1]) or src[j + 1] == "«"): + if src[j + 1] == "«": + k = src.find("»", j + 2) + an.add("guillemet") + j = n if k < 0 else k + 1 + else: + j += 2 + while j < n and _id_rest(src[j]): + j += 1 + text = src[i:j] + if text in ("s!", "f!", "m!"): + # interpolation: `s! "{term}"` runs a TERM inside the string, and Lean allows whitespace, newlines + # and comments between the `!` and the quote. Do not look at what follows: always flag it. + an.add("interp_string") + toks.append(Tok("id", text, i, j)) + i = j + continue + if c.isdigit(): + # Lean: a numeral is digits (or 0x/0b/0o + digits) with an optional fraction and exponent. It does NOT + # swallow following letters: `1macro` is the numeral `1` then the keyword `macro`. + m = _NUM.match(src, i) + j = m.end() if m else i + 1 # a non-ASCII digit (`²`, Arabic-Indic): one token, never glued + toks.append(Tok("num", src[i:j], i, j)) + i = j + continue + if c == '"': + j = i + 1 + while j < n and src[j] != '"': + j += 2 if src[j] == "\\" else 1 + if j >= n: + broken = "unterminated string" + j = n - 1 + toks.append(Tok("str", src[i : j + 1], i, j + 1)) + i = j + 1 + continue + if c == "'": + m = re.match(r"'(\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|.)|[^\\'])'", src[i : i + 12]) + if m: + if m.group(1) in ('"', "\\"): + an.add("char_quote") + toks.append(Tok("char", m.group(0), i, i + len(m.group(0)))) + i += len(m.group(0)) + continue + toks.append(Tok("sym", "'", i, i + 1)) + i += 1 + continue + if c == "#" and i + 1 < n and _id_start(src[i + 1]): + j = i + 1 + while j < n and _id_rest(src[j]): + j += 1 + toks.append(Tok("hash", src[i:j], i, j)) + i = j + continue + for s in _MULTI_SYMS: + if src.startswith(s, i): + toks.append(Tok("sym", s, i, i + len(s))) + i += len(s) + break + else: + toks.append(Tok("sym", c, i, i + 1)) + i += 1 + _ = start + if glued and broken is None: + broken = "comment opener glued to a symbol (ambiguous tokenisation)" + return Lexed(toks, an, broken) + + +# ============================================================================ banned constructs + +#: token -> reason label. Whole-token matches only (`sorry_lemma` is fine, `sorry` is not). +BANNED_IDS: dict[str, str] = { + "sorry": "sorry", "admit": "sorry", "sorryAx": "sorry", + "native_decide": "native_decide", + "unsafe": "unsafe", "partial": "partial", "unsafeCast": "unsafe", + "implemented_by": "implemented_by", "extern": "extern", "export": "extern", + "initialize": "initialize", "builtin_initialize": "initialize", + "axiom": "axiom", "opaque": "axiom", + "elab": "meta", "elab_rules": "meta", "macro": "meta", "macro_rules": "meta", + "syntax": "meta", "declare_syntax_cat": "meta", "notation": "meta", + "infix": "meta", "infixl": "meta", "infixr": "meta", "prefix": "meta", "postfix": "meta", + "run_cmd": "meta", "run_elab": "meta", "run_meta": "meta", "run_tac": "meta", + "unif_hint": "meta", "deriving": "meta", "mutual": "meta", "register_simp_attr": "meta", + "notation3": "meta", "binder_predicate": "meta", "declare_simp_like_tactic": "meta", + "register_option": "meta", "register_label_attr": "meta", "register_tactic_tag": "meta", + "namespace": "namespace", "section": "namespace", "end": "namespace", + "variable": "variable", "universe": "variable", "attribute": "attribute", + "local": "local", "scoped": "local", "import": "import", + "structure": "decl", "inductive": "decl", "class": "decl", + "instance": "instance", "irreducible_def": "decl", + "exact?": "search", "apply?": "search", "rw?": "search", "hint": "search", + "decide?": "search", "ofReduceBool": "native_decide", "reduceBool": "native_decide", + "reduceNat": "native_decide", "lcProof": "axiom", +} +#: banned only unless `allow_helper_defs`. +DEF_IDS = {"def": "def", "abbrev": "def"} +#: identifier PREFIXES that name meta-programming / IO APIs (a tactic proof never spells them). +BANNED_ID_PREFIXES = ("Lean.", "IO.", "System.", "Unsafe.", "EIO.", "BaseIO.") +#: First dotted component that marks meta-programming even after an `open Lean` +#: (`open Lean Elab Tactic` makes `Elab.Tactic.evalTactic` spellable without the `Lean.` prefix). +BANNED_ID_ROOTS = frozenset({"Lean", "Elab", "Meta", "CoreM", "MetaM", "TacticM", "TermElabM", + "CommandElabM", "MacroM", "IO", "EIO", "BaseIO"}) +#: attribute names (inside `@[...]`) that change compilation, elaboration or the parser. +BANNED_ATTRS = { + "implemented_by", "extern", "export", "csimp", "init", "builtin_init", "command_elab", + "term_elab", "tactic", "macro", "builtin_command_elab", "builtin_term_elab", + "builtin_tactic", "command_parser", "term_parser", "tactic_parser", "parser", "instance", + "default_instance", "unification_hint", "coe", "never_extract", "noinline", "inline", + "specialize", "simproc", "simprocs", "norm_num", "positivity", "gcongr", "mono", +} +#: Allowed `set_option` names (exact) and prefixes. Anything else is rejected: the dangerous +#: one is `debug.skipKernelTC`; `trace.*` floods the output; `compiler.*`/`interpreter.*` +#: change evaluation. maxRecDepth is bounded separately. +SET_OPTION_EXACT = { + "maxHeartbeats", "maxRecDepth", "synthInstance.maxHeartbeats", "synthInstance.maxSize", + "maxSynthPendingDepth", "autoImplicit", "relaxedAutoImplicit", "pp.proofs", + "pp.proofs.withType", "pp.unicode.fun", "tactic.hygienic", "linter.unusedVariables", + "exponentiation.threshold", "backward.synthInstance.canonInstances", + "genInjectivity", "structureDiamondWarning", "quotPrecheck", +} +SET_OPTION_PREFIX = ("linter.", "push_neg.", "pp.", "simprocs") +MAX_REC_DEPTH_LIMIT = 16384 + +_RAW_BAN_RE = re.compile( + r"(? list[str]: + bad: list[str] = [] + i = 0 + while i < len(toks): + if toks[i].text == "@[": + depth, j = 1, i + 1 + while j < len(toks) and depth: + t = toks[j].text + if t in ("[", "@["): + depth += 1 + elif t == "]": + depth -= 1 + elif toks[j].kind == "id" and (t in BANNED_ATTRS or t.rsplit(".", 1)[-1] in BANNED_ATTRS): + bad.append(f"banned:attr:{t}") + j += 1 + i = j + else: + i += 1 + return bad + + +def _scan_set_options(toks: Sequence[Tok]) -> list[str]: + bad: list[str] = [] + for i, t in enumerate(toks): + if t.kind == "id" and t.text == "set_option": + if i + 1 >= len(toks): + bad.append("banned:set_option:?") + continue + name = toks[i + 1].text + ok = name in SET_OPTION_EXACT or name.startswith(SET_OPTION_PREFIX) + if not ok: + bad.append(f"banned:set_option:{name}") + elif name == "maxRecDepth": + v = toks[i + 2].text if i + 2 < len(toks) else "" + if not v.isdigit() or int(v) > MAX_REC_DEPTH_LIMIT: + bad.append(f"banned:set_option:maxRecDepth>{MAX_REC_DEPTH_LIMIT}") + return bad + + +def _canonical_id(text: str) -> str: + """The name Lean resolves, for ban matching: `_root_.` prefixes (any number) and `«»` quoting removed.""" + text = text.replace("«", "").replace("»", "") + while text.startswith("_root_."): + text = text[len("_root_."):] + return text + + +def scan_banned(src: str, lx: Lexed, allow_helper_defs: bool = False) -> list[str]: + """Reasons (`banned:*`) for forbidden constructs in `src` (deduplicated, ordered).""" + out: list[str] = [] + + def add(r: str) -> None: + if r not in out: + out.append(r) + + for t in lx.toks: + if t.kind == "id": + text = _canonical_id(t.text) + lab = BANNED_IDS.get(text) + if lab is None and not allow_helper_defs: + lab = DEF_IDS.get(text) + if lab is None and (text.startswith(BANNED_ID_PREFIXES) or text.split(".", 1)[0] in BANNED_ID_ROOTS): + lab = "meta_api" + if lab is None and text.startswith(INTERNAL_ID_PREFIXES): + lab = "align_internal" + if lab is not None: + add(f"banned:{lab}" if lab != "meta_api" else f"banned:meta_api:{text.split('.')[0]}") + elif t.kind == "hash": + add(f"banned:#{t.text[1:]}") + for r in _scan_attributes(lx.toks) + _scan_set_options(lx.toks): + add(r) + if lx.anomalies: + # Weakest-assumption fallback: the faithful lexer could be out of sync with Lean's, + # so also reject banned words appearing ANYWHERE in the raw text (comments and + # strings included). Conservative on purpose; costs only exotic-but-legal inputs. + for m in _RAW_BAN_RE.finditer(src): + w = m.group(0) + lab = BANNED_IDS.get(w, w.lstrip("#")) + add(f"banned:{lab}") + return out + + +# ============================================================================ statement parsing + +_DECL_KW = {"theorem", "lemma"} +_OTHER_CMD_KW = { + "def", "abbrev", "instance", "example", "structure", "inductive", "class", "axiom", + "opaque", "namespace", "section", "variable", "universe", "mutual", "private", + "protected", "noncomputable", "nonrec", +} +_OPEN = {"(": ")", "[": "]", "{": "}", "⟨": "⟩", "⦃": "⦄", "@[": "]"} +_CLOSE = {")", "]", "}", "⟩", "⦄"} + + +def find_sig_end(toks: Sequence[Tok], start: int) -> Optional[int]: + """Index of the `:=` that ends a declaration signature, scanning from `start`. + + The naive "first `:=`" is wrong (roadmap P4-1 warns about it): `:=` also appears inside + binders `(x : Nat := 3)`, structure instances `{ x := 1 }`, and `let x := ..; body` in + the TYPE. We track bracket depth and skip one `:=` per pending `let`/`have`. + """ + depth = 0 + pending = 0 + for j in range(start, len(toks)): + t = toks[j] + if t.text in _OPEN: + depth += 1 + elif t.text in _CLOSE: + depth = max(0, depth - 1) + elif depth == 0 and t.kind == "id" and t.text in ("let", "have"): + pending += 1 + elif depth == 0 and t.text == ":=": + if pending: + pending -= 1 + else: + return j + elif t.kind == "id" and t.text in _DECL_KW and j > start: + return None + return None + + +@dataclass(frozen=True) +class StatementParse: + ok: bool + problem: str = "" + header_text: str = "" + header_toks: tuple = () + name: str = "" + sig_text: str = "" + sig_toks: tuple = () + + +@lru_cache(maxsize=4096) +def parse_statement(src: str) -> StatementParse: + """Split a reference formal statement into (header, name, signature). + + Supported shape (miniF2F / Goedel / DeepSeek / PutnamBench-style): header commands + (`import`, `set_option`, `open`) then ONE `theorem`/`lemma` ending `:= by sorry`. + Anything else -> `ok=False` with a reason; the verifier then scores 0 and says why, + instead of guessing.""" + lx = lex(src) + if lx.broken: + return StatementParse(False, f"reference does not lex: {lx.broken}") + toks = lx.toks + k = next( + ( + i + for i, t in enumerate(toks) + if t.text == "@[" or (t.kind == "id" and (t.text in _DECL_KW or t.text in _OTHER_CMD_KW)) + ), + None, + ) + if k is None or toks[k].text not in _DECL_KW: + return StatementParse(False, "reference has no plain `theorem`/`lemma` after its header") + for t in toks[:k]: + if t.kind == "id" and t.text in ("def", "abbrev", "instance", "variable", "namespace", "section", "universe"): + return StatementParse(False, f"reference header contains `{t.text}`") + if k + 1 >= len(toks) or toks[k + 1].kind != "id": + return StatementParse(False, "reference theorem has no name") + j = find_sig_end(toks, k + 2) + if j is None: + return StatementParse(False, "reference theorem has no `:=`") + if any(t.kind == "id" and t.text in _DECL_KW for t in toks[j:]): + return StatementParse(False, "reference contains more than one theorem") + hdr_end = toks[k - 1].end if k > 0 else 0 + sig_toks = tuple(t.text for t in toks[k + 2 : j]) + sig_text = src[toks[k + 2].start : toks[j].start] if j > k + 2 else "" + return StatementParse( + True, + header_text=src[:hdr_end], + header_toks=tuple(t.text for t in toks[:k]), + name=toks[k + 1].text, + sig_text=sig_text, + sig_toks=sig_toks, + ) + + +# ============================================================================ static check + + +@dataclass(frozen=True) +class StrictConfig: + axiom_whitelist: frozenset = AXIOM_WHITELIST + #: "strict": signature token-equal to the reference AND kernel bridge. + #: "defeq": kernel bridge only (allows a restated-but-defeq signature). + statement_mode: str = "strict" + allow_helper_defs: bool = False + #: Wall-clock budget for compile + audit of ONE candidate (seconds). + proof_timeout_s: float = 180.0 + max_code_chars: int = 200_000 + #: Re-add every local theorem with kernel checking forced on (see module docstring). + #: Measured cost in isolation: +0.04-0.12 s per proof on `nlinarith`-heavy proofs whose + #: elaboration takes 20-43 s (lean_workbook_10009/10013), i.e. negligible; on the pinned + #: Lean there is no way to switch kernel checking off short of meta-programming + #: (`debug.skipKernelTC` does not exist in 4.9.0-rc1), so this is defence in depth that + #: guards a pin upgrade. (An earlier "2-3x" reading was a contended-host artefact and was + #: retracted: see docs/LEAN_VERIFIER.md section 7.) + kernel_recheck: bool = True + #: Prepend the reference header when the candidate has none at all. Off by default: + #: "the completion must be a complete file" is the unambiguous contract. + prepend_missing_header: bool = False + #: ABLATION ONLY. False skips the banned-construct scan, the target-modifier rule and the + #: signature-token rule, leaving header split + target lookup + the Lean-side audit. The + #: ceiling test uses it to measure how much the semantic layer catches by itself; + #: `LeanAccuracy` refuses a verifier built with it off. + lexical_gate: bool = True + #: OPT-IN second opinion (align/verify/lean/recheck.py, docs/LEAN_RECHECK.md). After the + #: strict tier accepts, re-elaborate the ORIGINAL statement and the candidate in a FRESH + #: REPL process and require (type defeq) AND (`#print axioms` within the whitelist). + #: Costs one `import Mathlib` + a second elaboration of the proof per accepted proof. + #: Default off: with it off nothing below changes by a byte. + independent_recheck: bool = False + #: Wall-clock budget of the re-check alone (seconds); `None` = `proof_timeout_s`. + recheck_timeout_s: Optional[float] = None + + def __post_init__(self) -> None: + if self.statement_mode not in ("strict", "defeq"): + raise ValueError(f"statement_mode must be 'strict' or 'defeq', got {self.statement_mode!r}") + + +@dataclass(frozen=True) +class Plan: + name: str + header: str # the reference header (imports + opens + options), compared token-for-token + ref_cmd: str + body: str # candidate text after the header + reasons: tuple = () + + +@dataclass +class StrictResult: + accepted: bool + reasons: tuple[str, ...] + stage: str + diagnostics: dict = field(default_factory=dict) + elapsed_s: float = 0.0 + + @property + def accuracy(self) -> float: + return 1.0 if self.accepted else 0.0 + + @property + def undecided(self) -> bool: + """No verdict about the PROOF: it timed out, or the verifier/host failed. Scores 0 as a reward (never an + accept) but must never be counted as a negative label (docs/SOTA_PLAN.md: timeouts are undecided).""" + return any(r in ("timeout", "crash", "protocol", "memory", "output_too_large") for r in self.reasons) + + @property + def infra_failure(self) -> bool: + return any(r in ("crash", "protocol", "memory", "output_too_large") for r in self.reasons) + + +def static_check(statement: str, code: Optional[str], cfg: StrictConfig = StrictConfig()) -> tuple[Optional[Plan], list[str], dict]: + """The pure-Python half. Returns (plan or None, reasons, diagnostics). `plan` is + non-None only when every lexical rule passed and Lean should now be consulted.""" + diag: dict = {} + if code is None or not code.strip(): + return None, ["no_code"], diag + if len(code) > cfg.max_code_chars: + return None, ["parse_error"], {"detail": f"code over {cfg.max_code_chars} chars"} + try: + code.encode("utf-8") + except UnicodeEncodeError: + # a lone surrogate (broken detokenisation) is not Lean source and cannot be sent to the REPL as UTF-8: this + # item scores 0; it must not abort the whole batch. + return None, ["parse_error"], {"detail": "code is not valid unicode text (lone surrogate)"} + try: + statement.encode("utf-8") + except UnicodeEncodeError: + return None, ["unsupported_statement"], {"detail": "statement is not valid unicode text"} + ref = parse_statement(statement) + if not ref.ok: + return None, ["unsupported_statement"], {"detail": ref.problem} + lx = lex(code) + if lx.broken: + return None, ["parse_error"], {"detail": lx.broken} + toks = lx.toks + nh = len(ref.header_toks) + if cfg.prepend_missing_header and not any(t.text == "import" for t in toks): + code = ref.header_text + "\n" + code + lx = lex(code) + toks = lx.toks + if tuple(t.text for t in toks[:nh]) != ref.header_toks: + return None, ["header_mismatch"], diag + body_toks = toks[nh:] + body_start = toks[nh - 1].end if nh else 0 + body = code[body_start:] + + reasons: list[str] = [] + # banned constructs are scanned over the BODY only (the header was just proven equal to + # the trusted reference header, which legitimately contains `import` and `set_option`). + body_lx = Lexed(list(body_toks), lx.anomalies, None) + if cfg.lexical_gate: + reasons += scan_banned(code[body_start:], body_lx, cfg.allow_helper_defs) + + targets = [ + i + for i, t in enumerate(body_toks) + if t.kind == "id" and t.text in _DECL_KW and i + 1 < len(body_toks) and body_toks[i + 1].text == ref.name + ] + if not targets: + reasons.append("target_missing") + elif len(targets) > 1: + reasons.append("target_missing") + diag["detail"] = "target declared more than once" + else: + i = targets[0] + j = i - 1 + # modifiers / attributes attached to the target + mods: list[str] = [] + while j >= 0 and body_toks[j].text in ("private", "protected", "noncomputable", "nonrec"): + mods.append(body_toks[j].text) + j -= 1 + if j >= 0 and body_toks[j].text == "]": + mods.append("@[...]") + if mods and cfg.lexical_gate: + reasons.append("target_modifier") + if cfg.statement_mode == "strict" and cfg.lexical_gate: + e = find_sig_end(body_toks, i + 2) + if e is None: + reasons.append("statement_mismatch") + diag["detail"] = "target has no `:=`" + elif tuple(t.text for t in body_toks[i + 2 : e]) != ref.sig_toks: + reasons.append("statement_mismatch") + if reasons: + return None, reasons, diag + ref_cmd = f"theorem {REF_NAME} {ref.sig_text} := by\n sorry" + plan = Plan( + name=ref.name, + header=ref.header_text, + ref_cmd=ref_cmd, + body=body, + ) + return plan, [], diag + + +# ============================================================================ execution + + +class LeanInfraError(RuntimeError): + """The verifier infrastructure is broken (header will not elaborate, toolchain gone). + Raised, never converted to a 0: a dead verifier scoring every proof 0 is the same + constant-reward masquerade as the 0/100 perfect-policy incident.""" + + +def _msgs(resp: dict) -> list[dict]: + return [m for m in resp.get("messages", []) if isinstance(m, dict)] + + +def _short(s: str, n: int = 300) -> str: + return s if len(s) <= n else s[: n - 3] + "..." + + +def _parse_audit(resp: dict, nonce: str) -> Optional[dict]: + tag = f"ALIGN_AUDIT {nonce} " + for m in _msgs(resp): + d = m.get("data", "") + if m.get("severity") == "info" and isinstance(d, str) and d.startswith(tag): + try: + return json.loads(d[len(tag) :]) + except ValueError: + return None + return None + + +class StrictVerifier: + """Strict verification of (statement, candidate code) pairs on a `ReplPool`.""" + + def __init__(self, pool: ReplPool, cfg: StrictConfig = StrictConfig(), rechecker=None) -> None: + self.pool = pool + self.cfg = cfg + self.rechecker = rechecker + if cfg.independent_recheck and rechecker is None: + from .recheck import IndependentRechecker # lazy: unused (and unimported) when off + + self.rechecker = IndependentRechecker( + pool.launcher, + axiom_whitelist=cfg.axiom_whitelist, + timeout_s=cfg.recheck_timeout_s if cfg.recheck_timeout_s is not None else cfg.proof_timeout_s, + prepend_missing_header=cfg.prepend_missing_header, + ) + + def _second_opinion(self, res: StrictResult, statement: str, code: Optional[str]) -> StrictResult: + """The opt-in independent re-check. A no-op unless `cfg.independent_recheck` and the + strict tier accepted; it can only turn an accept into a reject.""" + if not self.cfg.independent_recheck or not res.accepted: + return res + v = self.rechecker.check(statement, code) + diag = dict(res.diagnostics) + diag["recheck"] = v.summary() + if v.agree: + res.diagnostics = diag + return res + reasons = tuple(f"recheck_disagree:{r}" for r in v.reasons) or ("recheck_disagree:unknown",) + return StrictResult(False, reasons, "recheck", diag, res.elapsed_s) + + # ---- public + def verify(self, statement: str, code: Optional[str]) -> StrictResult: + t0 = time.monotonic() + plan, reasons, diag = static_check(statement, code, self.cfg) + if plan is None: + return StrictResult(False, tuple(reasons), "static", diag, time.monotonic() - t0) + try: + with self.pool.acquire() as w: + # the proof's budget starts when it GETS a worker, not while it queues behind other proofs + res = self._run(w, plan, time.monotonic() + self.cfg.proof_timeout_s) + res = self._second_opinion(res, statement, code) + except LeanInfraError: + raise + except ReplError as e: + res = StrictResult(False, (e.code,), "repl", {"detail": _short(str(e))}) + res.elapsed_s = time.monotonic() - t0 + return res + + def verify_batch( + self, + items: Sequence[tuple[str, Optional[str]]], + progress: Optional[Callable[[int, StrictResult], None]] = None, + ) -> list[StrictResult]: + """Verify many (statement, code) pairs on the pool's workers; results keep input order. + + `progress(index, result)` (optional) is called from a worker thread as each item + completes, so a long batch is observable.""" + indexed = list(enumerate(items)) + + def one(w, ix_it): + ix, it = ix_it + r = self._verify_on(w, it) + if progress is not None: + progress(ix, r) + return r + + out = self.pool.map(one, indexed) + for o in out: + if not isinstance(o, StrictResult): + # LeanInfraError, or a programming error: either way a loud failure, never a 0. + raise o + return out # type: ignore[return-value] + + # ---- internals + def _verify_on(self, w: Worker, item: tuple[str, Optional[str]]) -> StrictResult: + t0 = time.monotonic() + plan, reasons, diag = static_check(item[0], item[1], self.cfg) + if plan is None: + return StrictResult(False, tuple(reasons), "static", diag, time.monotonic() - t0) + try: + res = self._run(w, plan, t0 + self.cfg.proof_timeout_s) + res = self._second_opinion(res, item[0], item[1]) + except LeanInfraError: + raise + except ReplError as e: + res = StrictResult(False, (e.code,), "repl", {"detail": _short(str(e))}) + res.elapsed_s = time.monotonic() - t0 + return res + + def _audit(self, w: Worker, env: int, cand: str, deadline: float, recheck: bool) -> dict: + nonce = secrets.token_hex(8) + flags = 1 if recheck else 0 + resp = w.command(f'#align_audit "{nonce}" {flags} {cand} {REF_NAME}', env, max(1.0, deadline - time.monotonic())) + a = _parse_audit(resp, nonce) + if a is None: + raise ReplProtocolError(f"audit produced no result: {_short(json.dumps(resp), 400)}") + return a + + def _run(self, w: Worker, plan: Plan, deadline: float) -> StrictResult: + diag: dict = {"worker": w.idx} + try: + hdr_env = w.header_env(plan.header, AUDIT_PRELUDE) + except HeaderError as e: + if e.stage == "header": + # THIS reference's own header does not elaborate (a bad dataset row), while the imports and our + # prelude did: a fact about this item, not a dead verifier. Score it 0 with a reason. + return StrictResult(False, ("reference_invalid",), "reference", {"detail": _short(str(e), 400)}) + raise LeanInfraError(f"cannot build the base environment: {e}") from e + except ReplError as e: + raise LeanInfraError(f"cannot build the base environment: {e}") from e + + def build_ref() -> int: + r = w.command(plan.ref_cmd, hdr_env, max(5.0, deadline - time.monotonic())) + errs = [m for m in _msgs(r) if m.get("severity") == "error"] + if errs or "env" not in r: + raise _RefInvalid(_short(json.dumps(errs[:2] or r), 400)) + return r["env"] + + try: + ref_env = w.remember(("ref", hdr_env, plan.ref_cmd), build_ref) + except _RefInvalid as e: + return StrictResult(False, ("reference_invalid",), "reference", {"detail": str(e)}) + + def build_base() -> list: + a = self._audit(w, ref_env, REF_NAME, deadline, recheck=False) + return list(a.get("meta_decls", [])) + + base_meta = set(w.remember(("meta_base", ref_env), build_base)) + + resp = w.command(plan.body, ref_env, max(1.0, deadline - time.monotonic())) + msgs = _msgs(resp) + errors = [m for m in msgs if m.get("severity") == "error"] + diag["n_messages"] = len(msgs) + if errors: + diag["errors"] = [_short(m.get("data", ""), 240) for m in errors[:3]] + return StrictResult(False, ("compile_error",), "compile", diag) + if "env" not in resp: + diag["detail"] = _short(json.dumps(resp), 300) + return StrictResult(False, ("compile_error",), "compile", diag) + if resp.get("sorries") or any("sorry" in str(m.get("data", "")) for m in msgs if m.get("severity") == "warning"): + return StrictResult(False, ("sorry",), "compile", diag) + + a = self._audit(w, resp["env"], plan.name, deadline, recheck=self.cfg.kernel_recheck) + diag["axioms"] = a.get("axioms") + reasons: list[str] = [] + if not a.get("found"): + reasons.append("target_missing") + else: + if a.get("kind") != "theorem": + reasons.append("not_theorem") + if not isinstance(a.get("axioms"), list): + reasons.append("audit_incomplete") # fail closed: no axiom list is not an empty axiom list + for ax in a.get("axioms") or []: + if ax not in self.cfg.axiom_whitelist: + reasons.append("sorry" if ax == "sorryAx" else f"axiom:{ax}") + if not a.get("bridge"): + reasons.append("statement_mismatch" if self.cfg.statement_mode == "strict" else "bridge_failed") + diag["bridge_err"] = _short(str(a.get("bridge_err", "")), 300) + if a.get("skip_tc"): + reasons.append("skip_kernel_tc") + if a.get("recheck_err"): + reasons.append("kernel_recheck_failed") + diag["recheck_err"] = _short(str(a["recheck_err"]), 300) + new_meta = sorted(set(a.get("meta_decls", [])) - base_meta) + if new_meta: + reasons.append("meta_decl") + diag["meta_decls"] = new_meta[:5] + diag["foreign"] = a.get("foreign", []) + return StrictResult(not reasons, tuple(dict.fromkeys(reasons)), "audit", diag) + + +class _RefInvalid(Exception): + pass diff --git a/code/align/verify/lean/toolchain.py b/code/align/verify/lean/toolchain.py new file mode 100644 index 0000000000000000000000000000000000000000..9edbe783026f57c03858bf655aa63897a7055fd7 --- /dev/null +++ b/code/align/verify/lean/toolchain.py @@ -0,0 +1,181 @@ +"""Locate the pinned Lean 4 toolchain and build the sanitized child environment. + +Why this module exists +---------------------- +The Lean toolchain is an EXTERNAL BINARY (docs/DEPENDENCY_POLICY.md, "Lean +toolchain"); the Python side only ever reaches it through `subprocess`. Three +facts learned from the install on this box shape the code below, and each one +is a failure that is silent if you do not know it: + +1. `lake env` prints RELATIVE paths (`././.lake/packages/mathlib/.lake/build/lib`) + resolved against the CURRENT DIRECTORY. A REPL spawned from any other cwd + fails at `import Mathlib` ("unknown package"). We therefore absolutise every + path-list variable once, at discovery time, and still set `cwd` to the + workspace. +2. The REPL does not flush stdout after a response when stdout is a PIPE + (only a pty, which is what Goedel-Prover-V2's pexpect scheduler gives it, + line-buffers). Over a pipe the client blocks forever on a response that the + REPL "sent" into a userspace buffer: the pool wraps the binary in + `stdbuf -o0 -e0`. A pty would also work but needs `stty -icanon` or any input + line over 4096 bytes is truncated. +3. The child gets a MINIMAL environment, not ours. A proof is attacker-shaped text + executed by a Lean elaborator; whatever environment the child has, a + meta-programming escape could read (API keys, HF tokens in the parent + environment). PATH/LEAN_PATH/LD_LIBRARY_PATH/LEAN_SYSROOT and nothing else. + +Stdlib only. +""" + +from __future__ import annotations + +import json +import os +import shutil +import subprocess +from dataclasses import dataclass, field +from pathlib import Path + +#: Where `scripts/lean_setup.sh` installs. Overridable for tests and other boxes. +DEFAULT_LEAN_ROOT = "/apps/development/rlhf/lean" +ENV_ROOT = "ALIGN_LEAN_ROOT" + +#: Variables that hold `:`-separated path lists and must be absolute. +_PATH_LIST_VARS = ("LEAN_PATH", "LD_LIBRARY_PATH", "PATH", "LEAN_SRC_PATH") +#: The only variables the REPL child receives (plus the fixed ones added below). +_CHILD_VARS = ("LEAN_PATH", "LD_LIBRARY_PATH", "PATH", "LEAN_SYSROOT") + + +class ToolchainNotFound(RuntimeError): + """The Lean install is absent or incomplete. Carries the setup command.""" + + +@dataclass(frozen=True) +class LeanToolchain: + root: Path + workspace: Path + repl_bin: Path + lake: Path + pins: dict = field(default_factory=dict) + #: The child environment (already minimal and absolute). + child_env: dict = field(default_factory=dict) + + def argv(self) -> list[str]: + """The bare REPL command (the pool adds nice/prlimit/stdbuf around it).""" + return [str(self.repl_bin)] + + @property + def cwd(self) -> str: + return str(self.workspace) + + def describe(self) -> str: + p = self.pins + return ( + f"{p.get('lean_toolchain', '?')} mathlib={str(p.get('mathlib_rev', '?'))[:10]} " + f"repl={p.get('repl_tag', '?')}" + ) + + +def lean_root(root: str | os.PathLike | None = None) -> Path: + return Path(root or os.environ.get(ENV_ROOT) or DEFAULT_LEAN_ROOT) + + +def _absolutise(value: str, base: Path) -> str: + parts = [] + for p in value.split(":"): + if not p: + continue + parts.append(p if os.path.isabs(p) else os.path.normpath(os.path.join(base, p))) + return ":".join(parts) + + +def parse_env0(blob: bytes) -> dict[str, str]: + """Parse `env -0` output (NUL-separated KEY=VALUE). Values may hold newlines.""" + out: dict[str, str] = {} + for item in blob.decode("utf-8", "replace").split("\0"): + if "=" in item: + k, v = item.split("=", 1) + out[k] = v + return out + + +def build_child_env(lake_env: dict[str, str], workspace: Path) -> dict[str, str]: + """Reduce `lake env`'s environment to what the REPL child may see. + + Pure function (unit-tested without Lean): relative path lists become absolute + against `workspace`, everything not in `_CHILD_VARS` is dropped, and glibc's + arena count is pinned to 2. The last matters: without it each of the 48 cores + can get a 64MB arena reservation, which makes RLIMIT_AS (the pool's backstop) + useless because the virtual size is dominated by reservations, not use. + """ + env: dict[str, str] = {} + for k in _CHILD_VARS: + if k in lake_env: + env[k] = _absolutise(lake_env[k], workspace) if k in _PATH_LIST_VARS else lake_env[k] + env["MALLOC_ARENA_MAX"] = "2" + env["LANG"] = "C.UTF-8" + env["LC_ALL"] = "C.UTF-8" + return env + + +def find_toolchain(root: str | os.PathLike | None = None) -> LeanToolchain: + """Resolve the install, or raise `ToolchainNotFound` with the fix.""" + r = lean_root(root) + ws = r / "workspace" + repl_bin = r / "repl" / ".lake" / "build" / "bin" / "repl" + lake = r / "elan" / "bin" / "lake" + missing = [ + str(p) + for p in (lake, repl_bin, ws / "lakefile.lean", ws / "lake-manifest.json") + if not p.exists() + ] + if missing: + raise ToolchainNotFound( + f"Lean toolchain incomplete under {r} (missing: {', '.join(missing)}). " + "Run: bash scripts/lean_setup.sh" + ) + pins: dict = {} + pins_path = r / "PINS.json" + if pins_path.exists(): + try: + pins = json.loads(pins_path.read_text()) + except (OSError, ValueError): + pins = {} + base = {"ELAN_HOME": str(r / "elan"), "PATH": os.environ.get("PATH", "/usr/bin:/bin")} + try: + proc = subprocess.run( + [str(lake), "env", "env", "-0"], + cwd=ws, + capture_output=True, + env=base, + timeout=60, + ) + except (OSError, subprocess.TimeoutExpired) as e: + raise ToolchainNotFound(f"`lake env` failed under {ws}: {e!r}") from e + if proc.returncode != 0: + raise ToolchainNotFound( + f"`lake env` exited {proc.returncode}: {proc.stderr.decode('utf-8', 'replace')[:300]}" + ) + lake_env = parse_env0(proc.stdout) + if "LEAN_PATH" not in lake_env: + raise ToolchainNotFound("`lake env` did not set LEAN_PATH") + return LeanToolchain( + root=r, + workspace=ws, + repl_bin=repl_bin, + lake=lake, + pins=pins, + child_env=build_child_env(lake_env, ws), + ) + + +def toolchain_available(root: str | os.PathLike | None = None) -> bool: + """Cheap existence probe for `pytest.mark.skipif` (no subprocess).""" + r = lean_root(root) + return (r / "repl" / ".lake" / "build" / "bin" / "repl").exists() and ( + r / "workspace" / ".lake" / "packages" / "mathlib" / ".lake" / "build" / "lib" / "Mathlib.olean" + ).exists() + + +def which_wrapper(name: str) -> str | None: + """Absolute path of a coreutils/util-linux wrapper (`nice`, `prlimit`, `stdbuf`).""" + return shutil.which(name) diff --git a/code/align/verify/normalize.py b/code/align/verify/normalize.py new file mode 100644 index 0000000000000000000000000000000000000000..d9e595054ecbf7595d0e2ffae27a011b9ab27559 --- /dev/null +++ b/code/align/verify/normalize.py @@ -0,0 +1,291 @@ +"""Answer-string normalisation: presentation noise OUT, mathematical content IN. + +Replaces the normalisation half of `math_verify.parse`. Pure stdlib. + +THE ASYMMETRY THAT GOVERNS EVERY RULE HERE +------------------------------------------ +A normalisation that is too weak costs a FALSE NEGATIVE (a correct answer +scored wrong -- measured 5-12% on the predecessor's engine, and concentrated +on unusual-but-correct formats a stronger policy emits more often). One that +is too strong costs a FALSE POSITIVE (a wrong answer scored right), which +silently inflates every reported accuracy. So each rule below strips only +things that are presentation by construction: + + * whole-string / trailing `\\text{...}` words and unit words, but only after a + number-ish prefix (`5 \\text{ cm}` -> `5`; `x \\text{ and } y` is untouched); + * degree marks, `$`, thousands separators, `\\left`/`\\right`, size macros, + `\\dfrac`->`\\frac`, trailing periods; + * a leading `x=` ONLY when the right-hand side is a constant expression + (`x=5` -> `5`, but `y=2x+3` stays an equation). + +Percent is NOT stripped here: `18\\%` and `18` are equal only as a deliberate, +two-sided decision made in `equiv.py` (so `0.18` still matches `18\\%` and `18` +still does not match `0.18\\%`). +""" + +from __future__ import annotations + +import re + +from .extract import match_brace + +__all__ = ["normalize_answer", "normalize_labeled", "strip_var_prefix", "split_var_prefix", "is_const_expr"] + +_TEXT_NAMES = ( + "text|textbf|textit|textrm|textsf|mbox|mathrm|mathbf|mathit|mathsf|operatorname|rm|hbox" +) +#: Macros whose body is PROSE. The others (`\\mathrm`, `\\mathbf`, `\\operatorname`, +#: ...) typeset MATH: `2\\mathrm{pi}` is 2*pi, never "2 plus a unit". +_PROSE_MACROS = frozenset({"text", "textbf", "textit", "textrm", "textsf", "mbox", "hbox"}) +_MATH_WORDS = frozenset( + "pi e i sin cos tan cot sec csc ln log lg exp sqrt arcsin arccos arctan infty infinity inf".split() +) +_TEXT_MACRO = re.compile(r"\\(?:" + _TEXT_NAMES + r")\s*\{([^{}]*)\}") +_WHOLE_TEXT = re.compile(r"^\\(?:" + _TEXT_NAMES + r")\s*\{([^{}]*)\}$") +# A text macro (plus an optional ^2 / ^3) hanging off the END of a number-ish +# head: the MATH-style `5\text{ cm}^2`, `10\mbox{ degrees}`. +_TRAIL_TEXT = re.compile( + r"^(?P.*[0-9\}\)])\s*\\(?P" + _TEXT_NAMES + r")\s*\{(?P[^{}]*)\}" + r"(?:\s*\^\s*\{?\s*[23]\s*\}?)?\s*$", + re.DOTALL, +) + +#: Unit / counting words stripped after a number. Single letters (m, h, s, g, +#: l) are deliberately absent: `3m` is far more likely `3*m` than metres. +_UNIT_WORDS = frozenset( + """ + unit units square sq cubic cm cms mm km kms meter meters metre metres + inch inches foot feet ft yard yards yd yds mile miles mi mph kph + hour hours hr hrs minute minutes min mins second seconds sec secs + day days week weeks month months year years + degree degrees deg radian radians rad + dollar dollars cent cents percent + kg kgs gram grams lb lbs pound pounds ounce ounces oz + liter liters litre litres ml gallon gallons + people person students student ways pieces points times + """.split() +) +_GLUED_UNITS = frozenset(w for w in _UNIT_WORDS if len(w) >= 2) + +_TRAIL_UNIT = re.compile( + r"^(?P.*[0-9\}\)])(?P\s*)(?P[A-Za-z][A-Za-z\s\.]*?)" + r"(?:\s*\^\s*\{?\s*[23]\s*\}?)?\s*$", + re.DOTALL, +) + +_UNICODE = { + "\u2212": "-", # minus sign + "\u2013": "-", + "\u2014": "-", + "\u00d7": r"\times ", + "\u00f7": r"\div ", + "\u00b7": r"\cdot ", + "\u03c0": "pi", + "\u221e": r"\infty ", + "\u2264": r"\leq ", + "\u2265": r"\geq ", + "\u2260": r"\neq ", + "\u222a": r"\cup ", + "\u00b1": r"\pm ", + "\u221a": r"\sqrt", + "\u00a0": " ", +} + +_GREEK_VAR = ( + "theta|alpha|beta|gamma|delta|phi|lambda|mu|sigma|omega|rho|tau|epsilon|varphi|vartheta" +) +_CONST_WORDS = re.compile( + r"(? str | None: + m = re.match(r"^\\(?:boxed|fbox)\s*\{", t) + if not m: + return None + close = match_brace(t, m.end() - 1) + if close == len(t) - 1: + return t[m.end() : close] + return None + + +def _strip_wrappers(t: str) -> str: + changed = True + while changed: + changed = False + t = t.strip() + inner = _unwrap_whole_boxed(t) + if inner is not None: + t, changed = inner, True + elif len(t) >= 4 and t.startswith("$$") and t.endswith("$$"): + t, changed = t[2:-2], True + elif len(t) >= 2 and t.startswith("$") and t.endswith("$") and t.count("$") == 2: + t, changed = t[1:-1], True + elif t.startswith("\\(") and t.endswith("\\)"): + t, changed = t[2:-2], True + elif t.startswith("\\[") and t.endswith("\\]"): + t, changed = t[2:-2], True + return t + + +def is_const_expr(rhs: str) -> bool: + """True if `rhs` has no free variable: only numbers, pi, e, functions.""" + if re.search(r"\\(?:" + _GREEK_VAR + r")(?![A-Za-z])", rhs): + return False + rest = re.sub(r"\\[A-Za-z]+", " ", rhs) + rest = _CONST_WORDS.sub(" ", rest) + return re.search(r"[A-Za-z]", rest) is None + + +def split_var_prefix(t: str, *, require_const: bool = True) -> tuple[str | None, str]: + """`x=5` -> (`x`, `5`); anything else -> (None, t). The label is returned + canonicalised (no spaces / braces) so callers can compare it.""" + m = _VAR_PREFIX.match(t) + if not m: + return None, t + rhs = t[m.end() :] + if "=" in rhs or not rhs.strip(): + return None, t + if require_const and not is_const_expr(rhs): + return None, t + label = re.sub(r"[\s{}]", "", t[: m.end()].rsplit("=", 1)[0]) + return label, rhs.strip() + + +def strip_var_prefix(t: str, *, require_const: bool = True) -> str: + """`x=5` -> `5`; leaves `y=2x+3` (non-constant RHS) and chained `a=b=c`.""" + return split_var_prefix(t, require_const=require_const)[1] + + +def _strip_trailing_text_units(t: str) -> str: + for _ in range(4): + m = _TRAIL_TEXT.match(t) + if not m: + break + body = m.group("body").strip() + # Multi-letter words only: `2\mathrm{e}` is a variable/constant, not a unit. + if len(body) >= 2 and re.fullmatch(r"[A-Za-z][A-Za-z .]*", body): + words = [w.lower() for w in body.split()] + if any(w in _MATH_WORDS for w in words): + break # `2\text{pi}` is 2*pi, not a number with a unit + # Math-font macros (`\mathrm{cm}`) are units only when they ARE units. + if m.group("macro") not in _PROSE_MACROS and not all(w in _UNIT_WORDS for w in words): + break + t = m.group("head").rstrip() + else: + break + return t + + +def _strip_trailing_unit_words(t: str) -> str: + for _ in range(3): + m = _TRAIL_UNIT.match(t) + if not m: + break + words = re.findall(r"[A-Za-z]+", m.group("words")) + if not words: + break + low = [w.lower() for w in words] + if not all(w in _UNIT_WORDS for w in low): + break + # Glued ("5cm") only for multi-letter units; spaced ("5 cm") for any. + if not m.group("gap") and not all(w in _GLUED_UNITS for w in low): + break + t = m.group("head").rstrip() + return t + + +def normalize_answer(s: str | None) -> str: + """Canonical comparison form of one answer string (see module docstring).""" + return strip_var_prefix(_normalize_core(s)) + + +def normalize_labeled(s: str | None) -> tuple[str | None, str]: + """Like `normalize_answer`, but also returns the stripped `x=` label (or + None). `x=1` vs `y=1` must not be equal: the label is part of the answer + whenever BOTH sides state one.""" + return split_var_prefix(_normalize_core(s)) + + +def _normalize_core(s: str | None) -> str: + if s is None: + return "" + t = _strip_wrappers(str(s)) + if not t: + return "" + + for k, v in _UNICODE.items(): + t = t.replace(k, v) + + # --- LaTeX presentation macros --------------------------------------- + t = re.sub(r"\\[dtc]frac(?![A-Za-z])", r"\\frac", t) + t = t.replace("\\displaystyle", "").replace("\\textstyle", "") + t = re.sub(r"\\(?:left|right)\s*\.", "", t) + t = re.sub(r"\\(?:left|right|bigl|bigr|Bigl|Bigr|biggl|biggr|bigg|Bigg|big|Big)(?![A-Za-z])", "", t) + t = re.sub(r"\\lbrace(?![A-Za-z])", r"\\{", t) + t = re.sub(r"\\rbrace(?![A-Za-z])", r"\\}", t) + t = re.sub(r"\\[lr]vert(?![A-Za-z])", "|", t) + t = re.sub(r"\\(?:le|leqslant)(?![A-Za-z])", r"\\leq", t) + t = re.sub(r"\\(?:ge|geqslant)(?![A-Za-z])", r"\\geq", t) + t = re.sub(r"\\ne(?![A-Za-z])", r"\\neq", t) + + # --- spacing ----------------------------------------------------------- + # Thousands written with a LaTeX space (`12\,345`) close up; every other + # spacing macro becomes a plain space. The `(? "x=1, x=2" --------------------------------------- + if re.search(r"[0-9=]", t): + t = re.sub(r"\s+(?:or|and)\s+", ", ", t) + + # --- tail hygiene ----------------------------------------------------- + t = re.sub(r"\\\.\s*$", "", t) + t = re.sub(r"[\s.;,]+$", "", t) + t = re.sub(r"\s+", " ", t).strip() + if t.startswith("+"): + t = t[1:].lstrip() + + # `x \in [2,5)` -> `[2,5)`: membership prefix on an interval/set answer. + t = re.sub(r"^[A-Za-z](?:_\{?[A-Za-z0-9]+\}?)?\s*\\in\s*(?=[\[\(\\{])", "", t) + + # Thousands separators: whole-string only. `(1,000)` stays a tuple. + if re.fullmatch(r"-?\d{1,3}(?:,\d{3})+(?:\.\d+)?", t): + t = t.replace(",", "") + # `(C)` -> `C` for multiple-choice letters. + t = re.sub(r"^\(\s*([A-Za-z])\s*\)$", r"\1", t) + + return t diff --git a/code/align/verify_backends/__init__.py b/code/align/verify_backends/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..6174c7cfddcd5d7592590d7fc929780602a3c809 --- /dev/null +++ b/code/align/verify_backends/__init__.py @@ -0,0 +1,5 @@ +"""Optional verification backends that sit BESIDE (never inside) `align.verify.lean`. + +Nothing here may produce an accept on its own: a backend is a pre-filter / throughput layer, +and every accept still comes from `align.verify.lean.StrictVerifier`. See `kimina_server.py`. +""" diff --git a/code/align/verify_backends/kimina_server.py b/code/align/verify_backends/kimina_server.py new file mode 100644 index 0000000000000000000000000000000000000000..e0508e4a177e94021b169bd1fc54f1e5ab8869da --- /dev/null +++ b/code/align/verify_backends/kimina_server.py @@ -0,0 +1,186 @@ +"""Optional PRE-FILTER backed by a Kimina Lean server (project-numina/kimina-lean-server, Apache-2.0). + +Safety contract (the reason this module is shaped the way it is) +---------------------------------------------------------------- +The strict verifier (`align.verify.lean`, docs/LEAN_VERIFIER.md) is the ONLY authority that can +accept a proof: lexical gate, statement bridge, axiom audit, kernel recheck, sandboxed REPL. +Kimina's `/api/check` is a compile-only REPL front end: it has no axiom audit, no statement +bridge, no lexical gate and no sandbox. Therefore: + + * `PrefilterVerdict` has NO `accepted` field and no truthiness; its verdicts are + `reject` (the code certainly fails: a Lean error or a `sorry`), `maybe` (nothing found; this + is NOT an accept) and `error` (the server could not decide: timeout, dead server, bad reply). + * `GatedVerifier.verify` reports an accept only when the wrapped strict verifier + returned an accept for the SAME code. `maybe` and `error` always go to the strict verifier; + only `reject` short-circuits, and a short-circuit can only turn a would-be-accept into a + reject (lost recall, never lost soundness). If the server is down, behaviour degrades to + "strict verifier only". + * Code never reaches the (unsandboxed) server unless it first passes the strict verifier's lexical + ban scan (`strict.scan_banned`: `#eval`, `run_cmd`, `IO.*`, `Lean.*`, `initialize`, `extern`, ...). + Banned code is a certain strict reject, so this is free. Residual risk: an execution path the + scan misses would run unsandboxed here but sandboxed in the strict tier; keep the server loopback- + only, inside a hostguard scope, and do not run it on untrusted input at scale. + * Nothing in this file touches `align/verify/lean/`; it only imports `extract_lean_code`, + `lex`/`scan_banned` and the strict verifier's public surface. + +Stdlib only (dependency policy): HTTP through `urllib`. Start the server with +`toolchains/work/kimina-run/start.sh` (see docs/KIMINA_BACKEND.md). +""" + +from __future__ import annotations + +import json +import time +import urllib.error +import urllib.request +import uuid +from dataclasses import dataclass, field +from typing import Any, Optional + +REJECT = "reject" +MAYBE = "maybe" +ERROR = "error" + + +@dataclass(frozen=True) +class PrefilterVerdict: + """Outcome of the compile-only pre-filter. Deliberately NOT an accept/reject boolean.""" + + verdict: str # REJECT | MAYBE | ERROR + reasons: tuple[str, ...] = () + elapsed_s: float = 0.0 + detail: dict = field(default_factory=dict) + + @property + def is_reject(self) -> bool: + return self.verdict == REJECT + + def __bool__(self) -> bool: # `if verdict:` would silently read MAYBE as an accept + raise TypeError("PrefilterVerdict has no truth value: compare .verdict explicitly (MAYBE is not an accept)") + + +def classify_response(resp: dict) -> PrefilterVerdict: + """Map one Kimina `ReplResponse` dict ({id, response|error, time}) to a verdict. + + reject : a Lean message of severity `error`, a `sorry` warning, or a non-empty `sorries`. + error : the server reported an error (`error` field: timeout / REPL died), a reply with no + `response`, or a Lean-level `message` the REPL itself returned instead of a result. + maybe : anything else. NEVER an accept.""" + t = float(resp.get("time") or 0.0) + if resp.get("error"): + err = str(resp["error"]) + why = "timeout" if "timed out" in err else "server_error" + return PrefilterVerdict(ERROR, (why,), t, {"error": err[:300]}) + body = resp.get("response") + if not isinstance(body, dict): + return PrefilterVerdict(ERROR, ("protocol",), t, {"raw": str(resp)[:300]}) + if "message" in body and "env" not in body and "messages" not in body: # REPL-level {"message": "..."} + return PrefilterVerdict(ERROR, ("repl_message",), t, {"message": str(body["message"])[:300]}) + msgs = [m for m in body.get("messages", []) if isinstance(m, dict)] + errors = [m for m in msgs if m.get("severity") == "error"] + if errors: + return PrefilterVerdict(REJECT, ("compile_error",), t, {"first_error": str(errors[0].get("data", ""))[:240], "n_errors": len(errors)}) + if body.get("sorries") or any("sorry" in str(m.get("data", "")) for m in msgs): + return PrefilterVerdict(REJECT, ("sorry",), t) + return PrefilterVerdict(MAYBE, (), t) + + +class KiminaClient: + """Minimal stdlib client for `POST /api/check`.""" + + def __init__(self, url: str = "http://127.0.0.1:18000", api_key: Optional[str] = None) -> None: + if not url.startswith(("http://127.0.0.1", "http://localhost", "http://[::1]")): + # Proof text is attacker-shaped; the server has no sandbox. Loopback only, unless the caller + # deliberately builds their own client. + raise ValueError(f"refusing non-loopback Kimina URL {url!r}") + self.url = url.rstrip("/") + self.api_key = api_key + + def check(self, code: str, timeout_s: float = 180.0, snippet_id: Optional[str] = None) -> dict: + sid = snippet_id or uuid.uuid4().hex + payload = json.dumps({"snippets": [{"id": sid, "code": code}], "timeout": timeout_s, "reuse": True}).encode() + headers = {"Content-Type": "application/json"} + if self.api_key: + headers["Authorization"] = f"Bearer {self.api_key}" + req = urllib.request.Request(self.url + "/api/check", data=payload, headers=headers, method="POST") + with urllib.request.urlopen(req, timeout=timeout_s + 90.0) as r: + data = json.loads(r.read().decode("utf-8")) + results = data.get("results") + if not isinstance(results, list) or len(results) != 1: + raise ValueError(f"unexpected Kimina reply: {str(data)[:200]}") + return results[0] + + def healthy(self) -> bool: + try: + with urllib.request.urlopen(self.url + "/health", timeout=5) as r: + return r.status == 200 + except Exception: # noqa: BLE001 + return False + + +class KiminaPrefilter: + def __init__(self, client: Optional[KiminaClient] = None, timeout_s: float = 180.0) -> None: + self.client = client or KiminaClient() + self.timeout_s = timeout_s + + def check_code(self, code: Optional[str]) -> PrefilterVerdict: + if code is None or not code.strip(): + return PrefilterVerdict(REJECT, ("no_code",)) + # Code-execution gate BEFORE anything leaves this process: the Kimina REPL is not namespace- + # sandboxed, and Lean code can execute (`#eval`, `run_cmd`, `IO.*`, `initialize`, ...). Run the strict + # verifier's own lexical ban scan first; a banned construct is a certain strict reject anyway, so + # rejecting here costs nothing in soundness or recall. If the scan itself fails, send nothing. + try: + from align.verify.lean.strict import lex, scan_banned + + banned = scan_banned(code, lex(code)) + except Exception as e: # noqa: BLE001 + return PrefilterVerdict(ERROR, ("lexical_gate_failed",), 0.0, {"exc": repr(e)[:200]}) + if banned: + return PrefilterVerdict(REJECT, tuple(banned), 0.0, {"gate": "strict.scan_banned"}) + t0 = time.monotonic() + try: + resp = self.client.check(code, self.timeout_s) + except urllib.error.HTTPError as e: + return PrefilterVerdict(ERROR, (f"http_{e.code}",), time.monotonic() - t0) + except Exception as e: # noqa: BLE001 (URLError, timeouts, JSON: all mean "no opinion") + return PrefilterVerdict(ERROR, ("unreachable",), time.monotonic() - t0, {"exc": repr(e)[:200]}) + v = classify_response(resp) + return PrefilterVerdict(v.verdict, v.reasons, v.elapsed_s or (time.monotonic() - t0), v.detail) + + def check_completion(self, completion: Optional[str]) -> PrefilterVerdict: + from align.verify.lean.reward import extract_lean_code + + return self.check_code(extract_lean_code(completion)) + + +@dataclass(frozen=True) +class GatedResult: + prefilter: Optional[PrefilterVerdict] + strict: Any # StrictResult, or None when the pre-filter short-circuited with a reject + skipped_strict: bool + + @property + def accepted(self) -> bool: + # The ONLY path to True. Derived from the strict verifier's own verdict; never from the pre-filter. + return bool(self.strict is not None and getattr(self.strict, "accepted", False) is True) + + @property + def reasons(self) -> tuple[str, ...]: + if self.strict is not None: + return tuple(self.strict.reasons) + return tuple(f"prefilter:{r}" for r in (self.prefilter.reasons if self.prefilter else ())) + + +class GatedVerifier: + """Pre-filter, then the strict verifier on everything the pre-filter did not reject.""" + + def __init__(self, strict_verifier, prefilter: KiminaPrefilter) -> None: + self.strict = strict_verifier + self.prefilter = prefilter + + def verify(self, statement: str, code: Optional[str]) -> GatedResult: + pf = self.prefilter.check_code(code) + if pf.verdict == REJECT: + return GatedResult(pf, None, True) + return GatedResult(pf, self.strict.verify(statement, code), False) diff --git a/code/assets/tokenizer/mistral-7b-v0.3/PROVENANCE.md b/code/assets/tokenizer/mistral-7b-v0.3/PROVENANCE.md new file mode 100644 index 0000000000000000000000000000000000000000..2ce3acb242e8317bb72c64b911da393d7a87b964 --- /dev/null +++ b/code/assets/tokenizer/mistral-7b-v0.3/PROVENANCE.md @@ -0,0 +1,9 @@ +Mistral-7B-v0.3 tokenizer files (Apache-2.0, mistralai/Mistral-7B-v0.3), vendored so the +test-suite and data pipeline do not depend on a rotating checkpoint dir or a missing HF +cache snapshot. Byte-identical copies were found in the legacy nano-mistral-o1 SFT +checkpoints (micro_00002000 and micro_00002250). md5: + tokenizer.json 32d192f59838957494261e9ae868506b + tokenizer.model 2bbc01eba250283314fdbd53d05de94b + tokenizer_config.json c4103b11a988818d399e4082a1bd7d5c + special_tokens_map.json e60ae4706e691cf378545ad0bd042f6f +Tokenizer only: no config.json, no weights. diff --git a/code/assets/tokenizer/mistral-7b-v0.3/special_tokens_map.json b/code/assets/tokenizer/mistral-7b-v0.3/special_tokens_map.json new file mode 100644 index 0000000000000000000000000000000000000000..451134b2ddc2e78555d1e857518c54b4bdc2e87d --- /dev/null +++ b/code/assets/tokenizer/mistral-7b-v0.3/special_tokens_map.json @@ -0,0 +1,23 @@ +{ + "bos_token": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false + }, + "eos_token": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false + }, + "unk_token": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false + } +} diff --git a/code/assets/tokenizer/mistral-7b-v0.3/tokenizer.json b/code/assets/tokenizer/mistral-7b-v0.3/tokenizer.json new file mode 100644 index 0000000000000000000000000000000000000000..8d7d23136b474a3df1182ed829db19984e295ee7 --- /dev/null +++ b/code/assets/tokenizer/mistral-7b-v0.3/tokenizer.json @@ -0,0 +1,98793 @@ +{ + "version": "1.0", + "truncation": null, + "padding": null, + "added_tokens": [ + { + "id": 0, + "content": "", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 1, + "content": "", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 2, + "content": "", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 3, + "content": "[INST]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 4, + "content": "[/INST]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 5, + "content": "[TOOL_CALLS]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 6, + "content": "[AVAILABLE_TOOLS]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 7, + "content": "[/AVAILABLE_TOOLS]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 8, + "content": "[TOOL_RESULTS]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 9, + "content": "[/TOOL_RESULTS]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 10, + "content": "[control_8]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 11, + "content": "[control_9]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 12, + "content": "[control_10]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 13, + "content": "[control_11]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 14, + "content": "[control_12]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 15, + "content": "[control_13]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 16, + "content": "[control_14]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 17, + "content": "[control_15]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 18, + "content": "[control_16]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 19, + "content": "[control_17]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 20, + "content": "[control_18]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 21, + "content": "[control_19]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 22, + "content": "[control_20]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 23, + "content": "[control_21]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 24, + "content": "[control_22]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 25, + "content": "[control_23]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 26, + "content": "[control_24]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 27, + "content": "[control_25]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 28, + "content": "[control_26]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 29, + "content": "[control_27]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 30, + "content": "[control_28]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 31, + "content": "[control_29]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 32, + "content": "[control_30]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 33, + "content": "[control_31]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 34, + "content": "[control_32]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 35, + "content": "[control_33]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 36, + "content": "[control_34]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 37, + "content": "[control_35]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 38, + "content": "[control_36]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 39, + "content": "[control_37]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 40, + "content": "[control_38]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 41, + "content": "[control_39]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 42, + "content": "[control_40]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 43, + "content": "[control_41]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 44, + "content": "[control_42]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 45, + "content": "[control_43]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 46, + "content": "[control_44]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 47, + "content": "[control_45]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 48, + "content": "[control_46]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 49, + "content": "[control_47]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 50, + "content": "[control_48]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 51, + "content": "[control_49]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 52, + "content": "[control_50]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 53, + "content": "[control_51]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 54, + "content": "[control_52]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 55, + "content": "[control_53]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 56, + "content": "[control_54]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 57, + "content": "[control_55]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 58, + "content": "[control_56]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 59, + "content": "[control_57]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 60, + "content": "[control_58]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 61, + "content": "[control_59]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 62, + "content": "[control_60]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 63, + "content": "[control_61]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 64, + "content": "[control_62]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 65, + "content": "[control_63]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 66, + "content": "[control_64]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 67, + "content": "[control_65]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 68, + "content": "[control_66]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 69, + "content": "[control_67]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 70, + "content": "[control_68]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 71, + "content": "[control_69]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 72, + "content": "[control_70]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 73, + "content": "[control_71]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 74, + "content": "[control_72]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 75, + "content": "[control_73]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 76, + "content": "[control_74]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 77, + "content": "[control_75]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 78, + "content": "[control_76]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 79, + "content": "[control_77]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 80, + "content": "[control_78]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 81, + "content": "[control_79]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 82, + "content": "[control_80]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 83, + "content": "[control_81]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 84, + "content": "[control_82]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 85, + "content": "[control_83]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 86, + "content": "[control_84]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 87, + "content": "[control_85]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 88, + "content": "[control_86]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 89, + "content": "[control_87]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 90, + "content": "[control_88]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 91, + "content": "[control_89]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 92, + "content": "[control_90]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 93, + "content": "[control_91]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 94, + "content": "[control_92]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 95, + "content": "[control_93]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 96, + "content": "[control_94]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 97, + "content": "[control_95]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 98, + "content": "[control_96]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 99, + "content": "[control_97]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 100, + "content": "[control_98]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 101, + "content": "[control_99]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 102, + "content": "[control_100]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 103, + "content": "[control_101]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 104, + "content": "[control_102]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 105, + "content": "[control_103]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 106, + "content": "[control_104]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 107, + "content": "[control_105]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 108, + "content": "[control_106]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 109, + "content": "[control_107]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 110, + "content": "[control_108]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 111, + "content": "[control_109]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 112, + "content": "[control_110]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 113, + "content": "[control_111]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 114, + "content": "[control_112]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 115, + "content": "[control_113]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 116, + "content": "[control_114]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 117, + "content": "[control_115]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 118, + "content": "[control_116]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 119, + "content": "[control_117]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 120, + "content": "[control_118]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 121, + "content": "[control_119]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 122, + "content": "[control_120]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 123, + "content": "[control_121]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 124, + "content": "[control_122]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 125, + "content": "[control_123]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 126, + "content": "[control_124]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 127, + "content": "[control_125]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 128, + "content": "[control_126]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 129, + "content": "[control_127]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 130, + "content": "[control_128]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 131, + "content": "[control_129]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 132, + "content": "[control_130]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 133, + "content": "[control_131]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 134, + "content": "[control_132]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 135, + "content": "[control_133]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 136, + "content": "[control_134]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 137, + "content": "[control_135]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 138, + "content": "[control_136]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 139, + "content": "[control_137]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 140, + "content": "[control_138]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 141, + "content": "[control_139]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 142, + "content": "[control_140]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 143, + "content": "[control_141]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 144, + "content": "[control_142]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 145, + "content": "[control_143]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 146, + "content": "[control_144]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 147, + "content": "[control_145]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 148, + "content": "[control_146]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 149, + "content": "[control_147]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 150, + "content": "[control_148]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 151, + "content": "[control_149]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 152, + "content": "[control_150]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 153, + "content": "[control_151]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 154, + "content": "[control_152]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 155, + "content": "[control_153]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 156, + "content": "[control_154]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 157, + "content": "[control_155]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 158, + "content": "[control_156]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 159, + "content": "[control_157]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 160, + "content": "[control_158]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 161, + "content": "[control_159]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 162, + "content": "[control_160]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 163, + "content": "[control_161]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 164, + "content": "[control_162]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 165, + "content": "[control_163]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 166, + "content": "[control_164]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 167, + "content": "[control_165]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 168, + "content": "[control_166]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 169, + "content": "[control_167]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 170, + "content": "[control_168]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 171, + "content": "[control_169]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 172, + "content": "[control_170]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 173, + "content": "[control_171]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 174, + "content": "[control_172]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 175, + "content": "[control_173]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 176, + "content": "[control_174]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 177, + "content": "[control_175]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 178, + "content": "[control_176]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 179, + "content": "[control_177]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 180, + "content": "[control_178]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 181, + "content": "[control_179]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 182, + "content": "[control_180]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 183, + "content": "[control_181]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 184, + "content": "[control_182]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 185, + "content": "[control_183]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 186, + "content": "[control_184]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 187, + "content": "[control_185]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 188, + "content": "[control_186]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 189, + "content": "[control_187]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 190, + "content": "[control_188]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 191, + "content": "[control_189]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 192, + "content": "[control_190]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 193, + "content": "[control_191]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 194, + "content": "[control_192]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 195, + "content": "[control_193]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 196, + "content": "[control_194]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 197, + "content": "[control_195]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 198, + "content": "[control_196]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 199, + "content": "[control_197]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 200, + "content": "[control_198]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 201, + "content": "[control_199]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 202, + "content": "[control_200]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 203, + "content": "[control_201]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 204, + "content": "[control_202]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 205, + "content": "[control_203]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 206, + "content": "[control_204]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 207, + "content": "[control_205]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 208, + "content": "[control_206]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 209, + "content": "[control_207]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 210, + "content": "[control_208]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 211, + "content": "[control_209]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 212, + "content": "[control_210]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 213, + "content": "[control_211]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 214, + "content": "[control_212]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 215, + "content": "[control_213]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 216, + "content": "[control_214]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 217, + "content": "[control_215]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 218, + "content": "[control_216]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 219, + "content": "[control_217]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 220, + "content": "[control_218]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 221, + "content": "[control_219]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 222, + "content": "[control_220]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 223, + "content": "[control_221]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 224, + "content": "[control_222]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 225, + "content": "[control_223]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 226, + "content": "[control_224]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 227, + "content": "[control_225]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 228, + "content": "[control_226]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 229, + "content": "[control_227]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 230, + "content": "[control_228]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 231, + "content": "[control_229]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 232, + "content": "[control_230]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 233, + "content": "[control_231]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 234, + "content": "[control_232]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 235, + "content": "[control_233]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 236, + "content": "[control_234]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 237, + "content": "[control_235]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 238, + "content": "[control_236]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 239, + "content": "[control_237]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 240, + "content": "[control_238]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 241, + "content": "[control_239]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 242, + "content": "[control_240]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 243, + "content": "[control_241]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 244, + "content": "[control_242]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 245, + "content": "[control_243]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 246, + "content": "[control_244]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 247, + "content": "[control_245]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 248, + "content": "[control_246]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 249, + "content": "[control_247]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 250, + "content": "[control_248]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 251, + "content": "[control_249]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 252, + "content": "[control_250]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 253, + "content": "[control_251]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 254, + "content": "[control_252]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 255, + "content": "[control_253]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 256, + "content": "[control_254]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 257, + "content": "[control_255]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 258, + "content": "[control_256]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 259, + "content": "[control_257]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 260, + "content": "[control_258]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 261, + "content": "[control_259]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 262, + "content": "[control_260]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 263, + "content": "[control_261]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 264, + "content": "[control_262]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 265, + "content": "[control_263]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 266, + "content": "[control_264]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 267, + "content": "[control_265]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 268, + "content": "[control_266]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 269, + "content": "[control_267]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 270, + "content": "[control_268]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 271, + "content": "[control_269]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 272, + "content": "[control_270]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 273, + "content": "[control_271]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 274, + "content": "[control_272]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 275, + "content": "[control_273]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 276, + "content": "[control_274]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 277, + "content": "[control_275]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 278, + "content": "[control_276]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 279, + "content": "[control_277]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 280, + "content": "[control_278]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 281, + "content": "[control_279]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 282, + "content": "[control_280]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 283, + "content": "[control_281]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 284, + "content": "[control_282]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 285, + "content": "[control_283]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 286, + "content": "[control_284]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 287, + "content": "[control_285]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 288, + "content": "[control_286]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 289, + "content": "[control_287]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 290, + "content": "[control_288]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 291, + "content": "[control_289]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 292, + "content": "[control_290]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 293, + "content": "[control_291]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 294, + "content": "[control_292]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 295, + "content": "[control_293]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 296, + "content": "[control_294]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 297, + "content": "[control_295]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 298, + "content": "[control_296]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 299, + "content": "[control_297]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 300, + "content": "[control_298]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 301, + "content": "[control_299]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 302, + "content": "[control_300]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 303, + "content": "[control_301]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 304, + "content": "[control_302]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 305, + "content": "[control_303]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 306, + "content": "[control_304]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 307, + "content": "[control_305]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 308, + "content": "[control_306]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 309, + "content": "[control_307]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 310, + "content": "[control_308]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 311, + "content": "[control_309]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 312, + "content": "[control_310]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 313, + "content": "[control_311]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 314, + "content": "[control_312]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 315, + "content": "[control_313]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 316, + "content": "[control_314]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 317, + "content": "[control_315]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 318, + "content": "[control_316]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 319, + "content": "[control_317]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 320, + "content": "[control_318]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 321, + "content": "[control_319]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 322, + "content": "[control_320]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 323, + "content": "[control_321]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 324, + "content": "[control_322]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 325, + "content": "[control_323]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 326, + "content": "[control_324]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 327, + "content": "[control_325]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 328, + "content": "[control_326]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 329, + "content": "[control_327]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 330, + "content": "[control_328]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 331, + "content": "[control_329]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 332, + "content": "[control_330]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 333, + "content": "[control_331]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 334, + "content": "[control_332]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 335, + "content": "[control_333]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 336, + "content": "[control_334]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 337, + "content": "[control_335]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 338, + "content": "[control_336]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 339, + "content": "[control_337]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 340, + "content": "[control_338]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 341, + "content": "[control_339]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 342, + "content": "[control_340]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 343, + "content": "[control_341]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 344, + "content": "[control_342]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 345, + "content": "[control_343]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 346, + "content": "[control_344]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 347, + "content": "[control_345]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 348, + "content": "[control_346]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 349, + "content": "[control_347]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 350, + "content": "[control_348]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 351, + "content": "[control_349]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 352, + "content": "[control_350]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 353, + "content": "[control_351]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 354, + "content": "[control_352]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 355, + "content": "[control_353]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 356, + "content": "[control_354]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 357, + "content": "[control_355]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 358, + "content": "[control_356]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 359, + "content": "[control_357]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 360, + "content": "[control_358]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 361, + "content": "[control_359]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 362, + "content": "[control_360]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 363, + "content": "[control_361]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 364, + "content": "[control_362]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 365, + "content": "[control_363]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 366, + "content": "[control_364]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 367, + "content": "[control_365]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 368, + "content": "[control_366]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 369, + "content": "[control_367]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 370, + "content": "[control_368]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 371, + "content": "[control_369]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 372, + "content": "[control_370]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 373, + "content": "[control_371]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 374, + "content": "[control_372]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 375, + "content": "[control_373]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 376, + "content": "[control_374]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 377, + "content": "[control_375]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 378, + "content": "[control_376]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 379, + "content": "[control_377]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 380, + "content": "[control_378]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 381, + "content": "[control_379]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 382, + "content": "[control_380]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 383, + "content": "[control_381]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 384, + "content": "[control_382]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 385, + "content": "[control_383]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 386, + "content": "[control_384]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 387, + "content": "[control_385]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 388, + "content": "[control_386]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 389, + "content": "[control_387]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 390, + "content": "[control_388]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 391, + "content": "[control_389]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 392, + "content": "[control_390]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 393, + "content": "[control_391]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 394, + "content": "[control_392]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 395, + "content": "[control_393]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 396, + "content": "[control_394]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 397, + "content": "[control_395]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 398, + "content": "[control_396]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 399, + "content": "[control_397]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 400, + "content": "[control_398]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 401, + "content": "[control_399]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 402, + "content": "[control_400]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 403, + "content": "[control_401]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 404, + "content": "[control_402]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 405, + "content": "[control_403]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 406, + "content": "[control_404]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 407, + "content": "[control_405]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 408, + "content": "[control_406]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 409, + "content": "[control_407]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 410, + "content": "[control_408]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 411, + "content": "[control_409]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 412, + "content": "[control_410]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 413, + "content": "[control_411]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 414, + "content": "[control_412]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 415, + "content": "[control_413]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 416, + "content": "[control_414]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 417, + "content": "[control_415]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 418, + "content": "[control_416]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 419, + "content": "[control_417]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 420, + "content": "[control_418]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 421, + "content": "[control_419]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 422, + "content": "[control_420]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 423, + "content": "[control_421]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 424, + "content": "[control_422]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 425, + "content": "[control_423]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 426, + "content": "[control_424]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 427, + "content": "[control_425]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 428, + "content": "[control_426]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 429, + "content": "[control_427]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 430, + "content": "[control_428]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 431, + "content": "[control_429]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 432, + "content": "[control_430]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 433, + "content": "[control_431]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 434, + "content": "[control_432]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 435, + "content": "[control_433]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 436, + "content": "[control_434]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 437, + "content": "[control_435]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 438, + "content": "[control_436]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 439, + "content": "[control_437]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 440, + "content": "[control_438]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 441, + "content": "[control_439]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 442, + "content": "[control_440]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 443, + "content": "[control_441]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 444, + "content": "[control_442]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 445, + "content": "[control_443]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 446, + "content": "[control_444]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 447, + "content": "[control_445]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 448, + "content": "[control_446]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 449, + "content": "[control_447]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 450, + "content": "[control_448]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 451, + "content": "[control_449]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 452, + "content": "[control_450]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 453, + "content": "[control_451]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 454, + "content": "[control_452]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 455, + "content": "[control_453]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 456, + "content": "[control_454]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 457, + "content": "[control_455]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 458, + "content": "[control_456]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 459, + "content": "[control_457]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 460, + "content": "[control_458]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 461, + "content": "[control_459]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 462, + "content": "[control_460]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 463, + "content": "[control_461]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 464, + "content": "[control_462]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 465, + "content": "[control_463]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 466, + "content": "[control_464]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 467, + "content": "[control_465]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 468, + "content": "[control_466]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 469, + "content": "[control_467]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 470, + "content": "[control_468]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 471, + "content": "[control_469]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 472, + "content": "[control_470]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 473, + "content": "[control_471]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 474, + "content": "[control_472]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 475, + "content": "[control_473]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 476, + "content": "[control_474]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 477, + "content": "[control_475]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 478, + "content": "[control_476]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 479, + "content": "[control_477]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 480, + "content": "[control_478]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 481, + "content": "[control_479]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 482, + "content": "[control_480]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 483, + "content": "[control_481]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 484, + "content": "[control_482]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 485, + "content": "[control_483]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 486, + "content": "[control_484]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 487, + "content": "[control_485]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 488, + "content": "[control_486]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 489, + "content": "[control_487]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 490, + "content": "[control_488]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 491, + "content": "[control_489]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 492, + "content": "[control_490]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 493, + "content": "[control_491]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 494, + "content": "[control_492]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 495, + "content": "[control_493]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 496, + "content": "[control_494]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 497, + "content": "[control_495]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 498, + "content": "[control_496]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 499, + "content": "[control_497]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 500, + "content": "[control_498]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 501, + "content": "[control_499]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 502, + "content": "[control_500]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 503, + "content": "[control_501]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 504, + "content": "[control_502]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 505, + "content": "[control_503]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 506, + "content": "[control_504]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 507, + "content": "[control_505]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 508, + "content": "[control_506]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 509, + "content": "[control_507]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 510, + "content": "[control_508]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 511, + "content": "[control_509]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 512, + "content": "[control_510]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 513, + "content": "[control_511]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 514, + "content": "[control_512]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 515, + "content": "[control_513]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 516, + "content": "[control_514]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 517, + "content": "[control_515]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 518, + "content": "[control_516]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 519, + "content": "[control_517]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 520, + "content": "[control_518]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 521, + "content": "[control_519]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 522, + "content": "[control_520]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 523, + "content": "[control_521]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 524, + "content": "[control_522]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 525, + "content": "[control_523]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 526, + "content": "[control_524]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 527, + "content": "[control_525]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 528, + "content": "[control_526]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 529, + "content": "[control_527]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 530, + "content": "[control_528]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 531, + "content": "[control_529]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 532, + "content": "[control_530]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 533, + "content": "[control_531]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 534, + "content": "[control_532]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 535, + "content": "[control_533]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 536, + "content": "[control_534]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 537, + "content": "[control_535]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 538, + "content": "[control_536]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 539, + "content": "[control_537]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 540, + "content": "[control_538]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 541, + "content": "[control_539]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 542, + "content": "[control_540]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 543, + "content": "[control_541]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 544, + "content": "[control_542]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 545, + "content": "[control_543]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 546, + "content": "[control_544]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 547, + "content": "[control_545]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 548, + "content": "[control_546]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 549, + "content": "[control_547]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 550, + "content": "[control_548]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 551, + "content": "[control_549]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 552, + "content": "[control_550]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 553, + "content": "[control_551]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 554, + "content": "[control_552]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 555, + "content": "[control_553]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 556, + "content": "[control_554]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 557, + "content": "[control_555]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 558, + "content": "[control_556]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 559, + "content": "[control_557]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 560, + "content": "[control_558]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 561, + "content": "[control_559]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 562, + "content": "[control_560]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 563, + "content": "[control_561]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 564, + "content": "[control_562]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 565, + "content": "[control_563]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 566, + "content": "[control_564]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 567, + "content": "[control_565]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 568, + "content": "[control_566]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 569, + "content": "[control_567]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 570, + "content": "[control_568]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 571, + "content": "[control_569]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 572, + "content": "[control_570]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 573, + "content": "[control_571]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 574, + "content": "[control_572]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 575, + "content": "[control_573]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 576, + "content": "[control_574]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 577, + "content": "[control_575]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 578, + "content": "[control_576]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 579, + "content": "[control_577]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 580, + "content": "[control_578]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 581, + "content": "[control_579]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 582, + "content": "[control_580]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 583, + "content": "[control_581]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 584, + "content": "[control_582]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 585, + "content": "[control_583]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 586, + "content": "[control_584]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 587, + "content": "[control_585]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 588, + "content": "[control_586]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 589, + "content": "[control_587]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 590, + "content": "[control_588]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 591, + "content": "[control_589]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 592, + "content": "[control_590]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 593, + "content": "[control_591]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 594, + "content": "[control_592]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 595, + "content": "[control_593]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 596, + "content": "[control_594]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 597, + "content": "[control_595]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 598, + "content": "[control_596]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 599, + "content": "[control_597]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 600, + "content": "[control_598]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 601, + "content": "[control_599]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 602, + "content": "[control_600]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 603, + "content": "[control_601]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 604, + "content": "[control_602]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 605, + "content": "[control_603]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 606, + "content": "[control_604]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 607, + "content": "[control_605]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 608, + "content": "[control_606]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 609, + "content": "[control_607]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 610, + "content": "[control_608]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 611, + "content": "[control_609]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 612, + "content": "[control_610]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 613, + "content": "[control_611]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 614, + "content": "[control_612]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 615, + "content": "[control_613]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 616, + "content": "[control_614]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 617, + "content": "[control_615]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 618, + "content": "[control_616]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 619, + "content": "[control_617]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 620, + "content": "[control_618]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 621, + "content": "[control_619]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 622, + "content": "[control_620]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 623, + "content": "[control_621]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 624, + "content": "[control_622]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 625, + "content": "[control_623]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 626, + "content": "[control_624]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 627, + "content": "[control_625]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 628, + "content": "[control_626]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 629, + "content": "[control_627]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 630, + "content": "[control_628]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 631, + "content": "[control_629]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 632, + "content": "[control_630]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 633, + "content": "[control_631]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 634, + "content": "[control_632]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 635, + "content": "[control_633]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 636, + "content": "[control_634]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 637, + "content": "[control_635]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 638, + "content": "[control_636]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 639, + "content": "[control_637]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 640, + "content": "[control_638]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 641, + "content": "[control_639]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 642, + "content": "[control_640]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 643, + "content": "[control_641]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 644, + "content": "[control_642]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 645, + "content": "[control_643]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 646, + "content": "[control_644]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 647, + "content": "[control_645]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 648, + "content": "[control_646]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 649, + "content": "[control_647]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 650, + "content": "[control_648]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 651, + "content": "[control_649]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 652, + "content": "[control_650]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 653, + "content": "[control_651]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 654, + "content": "[control_652]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 655, + "content": "[control_653]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 656, + "content": "[control_654]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 657, + "content": "[control_655]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 658, + "content": "[control_656]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 659, + "content": "[control_657]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 660, + "content": "[control_658]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 661, + "content": "[control_659]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 662, + "content": "[control_660]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 663, + "content": "[control_661]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 664, + "content": "[control_662]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 665, + "content": "[control_663]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 666, + "content": "[control_664]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 667, + "content": "[control_665]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 668, + "content": "[control_666]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 669, + "content": "[control_667]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 670, + "content": "[control_668]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 671, + "content": "[control_669]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 672, + "content": "[control_670]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 673, + "content": "[control_671]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 674, + "content": "[control_672]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 675, + "content": "[control_673]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 676, + "content": "[control_674]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 677, + "content": "[control_675]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 678, + "content": "[control_676]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 679, + "content": "[control_677]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 680, + "content": "[control_678]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 681, + "content": "[control_679]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 682, + "content": "[control_680]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 683, + "content": "[control_681]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 684, + "content": "[control_682]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 685, + "content": "[control_683]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 686, + "content": "[control_684]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 687, + "content": "[control_685]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 688, + "content": "[control_686]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 689, + "content": "[control_687]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 690, + "content": "[control_688]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 691, + "content": "[control_689]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 692, + "content": "[control_690]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 693, + "content": "[control_691]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 694, + "content": "[control_692]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 695, + "content": "[control_693]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 696, + "content": "[control_694]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 697, + "content": "[control_695]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 698, + "content": "[control_696]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 699, + "content": "[control_697]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 700, + "content": "[control_698]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 701, + "content": "[control_699]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 702, + "content": "[control_700]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 703, + "content": "[control_701]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 704, + "content": "[control_702]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 705, + "content": "[control_703]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 706, + "content": "[control_704]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 707, + "content": "[control_705]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 708, + "content": "[control_706]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 709, + "content": "[control_707]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 710, + "content": "[control_708]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 711, + "content": "[control_709]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 712, + "content": "[control_710]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 713, + "content": "[control_711]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 714, + "content": "[control_712]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 715, + "content": "[control_713]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 716, + "content": "[control_714]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 717, + "content": "[control_715]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 718, + "content": "[control_716]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 719, + "content": "[control_717]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 720, + "content": "[control_718]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 721, + "content": "[control_719]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 722, + "content": "[control_720]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 723, + "content": "[control_721]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 724, + "content": "[control_722]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 725, + "content": "[control_723]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 726, + "content": "[control_724]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 727, + "content": "[control_725]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 728, + "content": "[control_726]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 729, + "content": "[control_727]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 730, + "content": "[control_728]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 731, + "content": "[control_729]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 732, + "content": "[control_730]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 733, + "content": "[control_731]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 734, + "content": "[control_732]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 735, + "content": "[control_733]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 736, + "content": "[control_734]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 737, + "content": "[control_735]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 738, + "content": "[control_736]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 739, + "content": "[control_737]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 740, + "content": "[control_738]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 741, + "content": "[control_739]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 742, + "content": "[control_740]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 743, + "content": "[control_741]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 744, + "content": "[control_742]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 745, + "content": "[control_743]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 746, + "content": "[control_744]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 747, + "content": "[control_745]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 748, + "content": "[control_746]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 749, + "content": "[control_747]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 750, + "content": "[control_748]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 751, + "content": "[control_749]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 752, + "content": "[control_750]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 753, + "content": "[control_751]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 754, + "content": "[control_752]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 755, + "content": "[control_753]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 756, + "content": "[control_754]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 757, + "content": "[control_755]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 758, + "content": "[control_756]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 759, + "content": "[control_757]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 760, + "content": "[control_758]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 761, + "content": "[control_759]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 762, + "content": "[control_760]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 763, + "content": "[control_761]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 764, + "content": "[control_762]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 765, + "content": "[control_763]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 766, + "content": "[control_764]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 767, + "content": "[control_765]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 768, + "content": "[control_766]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 769, + "content": "[control_767]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + }, + { + "id": 770, + "content": "[control_768]", + "single_word": false, + "lstrip": false, + "rstrip": false, + "normalized": false, + "special": true + } + ], + "normalizer": null, + "pre_tokenizer": { + "type": "Metaspace", + "replacement": "▁", + "prepend_scheme": "first", + "split": false + }, + "post_processor": { + "type": "TemplateProcessing", + "single": [ + { + "SpecialToken": { + "id": "", + "type_id": 0 + } + }, + { + "Sequence": { + "id": "A", + "type_id": 0 + } + } + ], + "pair": [ + { + "SpecialToken": { + "id": "", + "type_id": 0 + } + }, + { + "Sequence": { + "id": "A", + "type_id": 0 + } + }, + { + "SpecialToken": { + "id": "", + "type_id": 1 + } + }, + { + "Sequence": { + "id": "B", + "type_id": 1 + } + } + ], + "special_tokens": { + "": { + "id": "", + "ids": [ + 1 + ], + "tokens": [ + "" + ] + } + } + }, + "decoder": { + "type": "Sequence", + "decoders": [ + { + "type": "Replace", + "pattern": { + "String": "▁" + }, + "content": " " + }, + { + "type": "ByteFallback" + }, + { + "type": "Fuse" + }, + { + "type": "Strip", + "content": " ", + "start": 1, + "stop": 0 + } + ] + }, + "model": { + "type": "BPE", + "dropout": null, + "unk_token": "", + "continuing_subword_prefix": null, + "end_of_word_suffix": null, + "fuse_unk": true, + "byte_fallback": true, + "ignore_merges": false, + "vocab": { + "": 0, + "": 1, + "": 2, + "[INST]": 3, + "[/INST]": 4, + "[TOOL_CALLS]": 5, + "[AVAILABLE_TOOLS]": 6, + "[/AVAILABLE_TOOLS]": 7, + "[TOOL_RESULTS]": 8, + "[/TOOL_RESULTS]": 9, + "[control_8]": 10, + "[control_9]": 11, + "[control_10]": 12, + "[control_11]": 13, + "[control_12]": 14, + "[control_13]": 15, + "[control_14]": 16, + "[control_15]": 17, + "[control_16]": 18, + "[control_17]": 19, + "[control_18]": 20, + "[control_19]": 21, + "[control_20]": 22, + "[control_21]": 23, + "[control_22]": 24, + "[control_23]": 25, + "[control_24]": 26, + "[control_25]": 27, + "[control_26]": 28, + "[control_27]": 29, + "[control_28]": 30, + "[control_29]": 31, + "[control_30]": 32, + "[control_31]": 33, + "[control_32]": 34, + "[control_33]": 35, + "[control_34]": 36, + "[control_35]": 37, + "[control_36]": 38, + "[control_37]": 39, + "[control_38]": 40, + "[control_39]": 41, + "[control_40]": 42, + "[control_41]": 43, + "[control_42]": 44, + "[control_43]": 45, + "[control_44]": 46, + "[control_45]": 47, + "[control_46]": 48, + "[control_47]": 49, + "[control_48]": 50, + "[control_49]": 51, + "[control_50]": 52, + "[control_51]": 53, + "[control_52]": 54, + "[control_53]": 55, + "[control_54]": 56, + "[control_55]": 57, + "[control_56]": 58, + "[control_57]": 59, + "[control_58]": 60, + "[control_59]": 61, + "[control_60]": 62, + "[control_61]": 63, + "[control_62]": 64, + "[control_63]": 65, + "[control_64]": 66, + "[control_65]": 67, + "[control_66]": 68, + "[control_67]": 69, + "[control_68]": 70, + "[control_69]": 71, + "[control_70]": 72, + "[control_71]": 73, + "[control_72]": 74, + "[control_73]": 75, + "[control_74]": 76, + "[control_75]": 77, + "[control_76]": 78, + "[control_77]": 79, + "[control_78]": 80, + "[control_79]": 81, + "[control_80]": 82, + "[control_81]": 83, + "[control_82]": 84, + "[control_83]": 85, + "[control_84]": 86, + "[control_85]": 87, + "[control_86]": 88, + "[control_87]": 89, + "[control_88]": 90, + "[control_89]": 91, + "[control_90]": 92, + "[control_91]": 93, + "[control_92]": 94, + "[control_93]": 95, + "[control_94]": 96, + "[control_95]": 97, + "[control_96]": 98, + "[control_97]": 99, + "[control_98]": 100, + "[control_99]": 101, + "[control_100]": 102, + "[control_101]": 103, + "[control_102]": 104, + "[control_103]": 105, + "[control_104]": 106, + "[control_105]": 107, + "[control_106]": 108, + "[control_107]": 109, + "[control_108]": 110, + "[control_109]": 111, + "[control_110]": 112, + "[control_111]": 113, + "[control_112]": 114, + "[control_113]": 115, + "[control_114]": 116, + "[control_115]": 117, + "[control_116]": 118, + "[control_117]": 119, + "[control_118]": 120, + "[control_119]": 121, + "[control_120]": 122, + "[control_121]": 123, + "[control_122]": 124, + "[control_123]": 125, + "[control_124]": 126, + "[control_125]": 127, + "[control_126]": 128, + "[control_127]": 129, + "[control_128]": 130, + "[control_129]": 131, + "[control_130]": 132, + "[control_131]": 133, + "[control_132]": 134, + "[control_133]": 135, + "[control_134]": 136, + "[control_135]": 137, + "[control_136]": 138, + "[control_137]": 139, + "[control_138]": 140, + "[control_139]": 141, + "[control_140]": 142, + "[control_141]": 143, + "[control_142]": 144, + "[control_143]": 145, + "[control_144]": 146, + "[control_145]": 147, + "[control_146]": 148, + "[control_147]": 149, + "[control_148]": 150, + "[control_149]": 151, + "[control_150]": 152, + "[control_151]": 153, + "[control_152]": 154, + "[control_153]": 155, + "[control_154]": 156, + "[control_155]": 157, + "[control_156]": 158, + "[control_157]": 159, + "[control_158]": 160, + "[control_159]": 161, + "[control_160]": 162, + "[control_161]": 163, + "[control_162]": 164, + "[control_163]": 165, + "[control_164]": 166, + "[control_165]": 167, + "[control_166]": 168, + "[control_167]": 169, + "[control_168]": 170, + "[control_169]": 171, + "[control_170]": 172, + "[control_171]": 173, + "[control_172]": 174, + "[control_173]": 175, + "[control_174]": 176, + "[control_175]": 177, + "[control_176]": 178, + "[control_177]": 179, + "[control_178]": 180, + "[control_179]": 181, + "[control_180]": 182, + "[control_181]": 183, + "[control_182]": 184, + "[control_183]": 185, + "[control_184]": 186, + "[control_185]": 187, + "[control_186]": 188, + "[control_187]": 189, + "[control_188]": 190, + "[control_189]": 191, + "[control_190]": 192, + "[control_191]": 193, + "[control_192]": 194, + "[control_193]": 195, + "[control_194]": 196, + "[control_195]": 197, + "[control_196]": 198, + "[control_197]": 199, + "[control_198]": 200, + "[control_199]": 201, + "[control_200]": 202, + "[control_201]": 203, + "[control_202]": 204, + "[control_203]": 205, + "[control_204]": 206, + "[control_205]": 207, + "[control_206]": 208, + "[control_207]": 209, + "[control_208]": 210, + "[control_209]": 211, + "[control_210]": 212, + "[control_211]": 213, + "[control_212]": 214, + "[control_213]": 215, + "[control_214]": 216, + "[control_215]": 217, + "[control_216]": 218, + "[control_217]": 219, + "[control_218]": 220, + "[control_219]": 221, + "[control_220]": 222, + "[control_221]": 223, + "[control_222]": 224, + "[control_223]": 225, + "[control_224]": 226, + "[control_225]": 227, + "[control_226]": 228, + "[control_227]": 229, + "[control_228]": 230, + "[control_229]": 231, + "[control_230]": 232, + "[control_231]": 233, + "[control_232]": 234, + "[control_233]": 235, + "[control_234]": 236, + "[control_235]": 237, + "[control_236]": 238, + "[control_237]": 239, + "[control_238]": 240, + "[control_239]": 241, + "[control_240]": 242, + "[control_241]": 243, + "[control_242]": 244, + "[control_243]": 245, + "[control_244]": 246, + "[control_245]": 247, + "[control_246]": 248, + "[control_247]": 249, + "[control_248]": 250, + "[control_249]": 251, + "[control_250]": 252, + "[control_251]": 253, + "[control_252]": 254, + "[control_253]": 255, + "[control_254]": 256, + "[control_255]": 257, + "[control_256]": 258, + "[control_257]": 259, + "[control_258]": 260, + "[control_259]": 261, + "[control_260]": 262, + "[control_261]": 263, + "[control_262]": 264, + "[control_263]": 265, + "[control_264]": 266, + "[control_265]": 267, + "[control_266]": 268, + "[control_267]": 269, + "[control_268]": 270, + "[control_269]": 271, + "[control_270]": 272, + "[control_271]": 273, + "[control_272]": 274, + "[control_273]": 275, + "[control_274]": 276, + "[control_275]": 277, + "[control_276]": 278, + "[control_277]": 279, + "[control_278]": 280, + "[control_279]": 281, + "[control_280]": 282, + "[control_281]": 283, + "[control_282]": 284, + "[control_283]": 285, + "[control_284]": 286, + "[control_285]": 287, + "[control_286]": 288, + "[control_287]": 289, + "[control_288]": 290, + "[control_289]": 291, + "[control_290]": 292, + "[control_291]": 293, + "[control_292]": 294, + "[control_293]": 295, + "[control_294]": 296, + "[control_295]": 297, + "[control_296]": 298, + "[control_297]": 299, + "[control_298]": 300, + "[control_299]": 301, + "[control_300]": 302, + "[control_301]": 303, + "[control_302]": 304, + "[control_303]": 305, + "[control_304]": 306, + "[control_305]": 307, + "[control_306]": 308, + "[control_307]": 309, + "[control_308]": 310, + "[control_309]": 311, + "[control_310]": 312, + "[control_311]": 313, + "[control_312]": 314, + "[control_313]": 315, + "[control_314]": 316, + "[control_315]": 317, + "[control_316]": 318, + "[control_317]": 319, + "[control_318]": 320, + "[control_319]": 321, + "[control_320]": 322, + "[control_321]": 323, + "[control_322]": 324, + "[control_323]": 325, + "[control_324]": 326, + "[control_325]": 327, + "[control_326]": 328, + "[control_327]": 329, + "[control_328]": 330, + "[control_329]": 331, + "[control_330]": 332, + "[control_331]": 333, + "[control_332]": 334, + "[control_333]": 335, + "[control_334]": 336, + "[control_335]": 337, + "[control_336]": 338, + "[control_337]": 339, + "[control_338]": 340, + "[control_339]": 341, + "[control_340]": 342, + "[control_341]": 343, + "[control_342]": 344, + "[control_343]": 345, + "[control_344]": 346, + "[control_345]": 347, + "[control_346]": 348, + "[control_347]": 349, + "[control_348]": 350, + "[control_349]": 351, + "[control_350]": 352, + "[control_351]": 353, + "[control_352]": 354, + "[control_353]": 355, + "[control_354]": 356, + "[control_355]": 357, + "[control_356]": 358, + "[control_357]": 359, + "[control_358]": 360, + "[control_359]": 361, + "[control_360]": 362, + "[control_361]": 363, + "[control_362]": 364, + "[control_363]": 365, + "[control_364]": 366, + "[control_365]": 367, + "[control_366]": 368, + "[control_367]": 369, + "[control_368]": 370, + "[control_369]": 371, + "[control_370]": 372, + "[control_371]": 373, + "[control_372]": 374, + "[control_373]": 375, + "[control_374]": 376, + "[control_375]": 377, + "[control_376]": 378, + "[control_377]": 379, + "[control_378]": 380, + "[control_379]": 381, + "[control_380]": 382, + "[control_381]": 383, + "[control_382]": 384, + "[control_383]": 385, + "[control_384]": 386, + "[control_385]": 387, + "[control_386]": 388, + "[control_387]": 389, + "[control_388]": 390, + "[control_389]": 391, + "[control_390]": 392, + "[control_391]": 393, + "[control_392]": 394, + "[control_393]": 395, + "[control_394]": 396, + "[control_395]": 397, + "[control_396]": 398, + "[control_397]": 399, + "[control_398]": 400, + "[control_399]": 401, + "[control_400]": 402, + "[control_401]": 403, + "[control_402]": 404, + "[control_403]": 405, + "[control_404]": 406, + "[control_405]": 407, + "[control_406]": 408, + "[control_407]": 409, + "[control_408]": 410, + "[control_409]": 411, + "[control_410]": 412, + "[control_411]": 413, + "[control_412]": 414, + "[control_413]": 415, + "[control_414]": 416, + "[control_415]": 417, + "[control_416]": 418, + "[control_417]": 419, + "[control_418]": 420, + "[control_419]": 421, + "[control_420]": 422, + "[control_421]": 423, + "[control_422]": 424, + "[control_423]": 425, + "[control_424]": 426, + "[control_425]": 427, + "[control_426]": 428, + "[control_427]": 429, + "[control_428]": 430, + "[control_429]": 431, + "[control_430]": 432, + "[control_431]": 433, + "[control_432]": 434, + "[control_433]": 435, + "[control_434]": 436, + "[control_435]": 437, + "[control_436]": 438, + "[control_437]": 439, + "[control_438]": 440, + "[control_439]": 441, + "[control_440]": 442, + "[control_441]": 443, + "[control_442]": 444, + "[control_443]": 445, + "[control_444]": 446, + "[control_445]": 447, + "[control_446]": 448, + "[control_447]": 449, + "[control_448]": 450, + "[control_449]": 451, + "[control_450]": 452, + "[control_451]": 453, + "[control_452]": 454, + "[control_453]": 455, + "[control_454]": 456, + "[control_455]": 457, + "[control_456]": 458, + "[control_457]": 459, + "[control_458]": 460, + "[control_459]": 461, + "[control_460]": 462, + "[control_461]": 463, + "[control_462]": 464, + "[control_463]": 465, + "[control_464]": 466, + "[control_465]": 467, + "[control_466]": 468, + "[control_467]": 469, + "[control_468]": 470, + "[control_469]": 471, + "[control_470]": 472, + "[control_471]": 473, + "[control_472]": 474, + "[control_473]": 475, + "[control_474]": 476, + "[control_475]": 477, + "[control_476]": 478, + "[control_477]": 479, + "[control_478]": 480, + "[control_479]": 481, + "[control_480]": 482, + "[control_481]": 483, + "[control_482]": 484, + "[control_483]": 485, + "[control_484]": 486, + "[control_485]": 487, + "[control_486]": 488, + "[control_487]": 489, + "[control_488]": 490, + "[control_489]": 491, + "[control_490]": 492, + "[control_491]": 493, + "[control_492]": 494, + "[control_493]": 495, + "[control_494]": 496, + "[control_495]": 497, + "[control_496]": 498, + "[control_497]": 499, + "[control_498]": 500, + "[control_499]": 501, + "[control_500]": 502, + "[control_501]": 503, + "[control_502]": 504, + "[control_503]": 505, + "[control_504]": 506, + "[control_505]": 507, + "[control_506]": 508, + "[control_507]": 509, + "[control_508]": 510, + "[control_509]": 511, + "[control_510]": 512, + "[control_511]": 513, + "[control_512]": 514, + "[control_513]": 515, + "[control_514]": 516, + "[control_515]": 517, + "[control_516]": 518, + "[control_517]": 519, + "[control_518]": 520, + "[control_519]": 521, + "[control_520]": 522, + "[control_521]": 523, + "[control_522]": 524, + "[control_523]": 525, + "[control_524]": 526, + "[control_525]": 527, + "[control_526]": 528, + "[control_527]": 529, + "[control_528]": 530, + "[control_529]": 531, + "[control_530]": 532, + "[control_531]": 533, + "[control_532]": 534, + "[control_533]": 535, + "[control_534]": 536, + "[control_535]": 537, + "[control_536]": 538, + "[control_537]": 539, + "[control_538]": 540, + "[control_539]": 541, + "[control_540]": 542, + "[control_541]": 543, + "[control_542]": 544, + "[control_543]": 545, + "[control_544]": 546, + "[control_545]": 547, + "[control_546]": 548, + "[control_547]": 549, + "[control_548]": 550, + "[control_549]": 551, + "[control_550]": 552, + "[control_551]": 553, + "[control_552]": 554, + "[control_553]": 555, + "[control_554]": 556, + "[control_555]": 557, + "[control_556]": 558, + "[control_557]": 559, + "[control_558]": 560, + "[control_559]": 561, + "[control_560]": 562, + "[control_561]": 563, + "[control_562]": 564, + "[control_563]": 565, + "[control_564]": 566, + "[control_565]": 567, + "[control_566]": 568, + "[control_567]": 569, + "[control_568]": 570, + "[control_569]": 571, + "[control_570]": 572, + "[control_571]": 573, + "[control_572]": 574, + "[control_573]": 575, + "[control_574]": 576, + "[control_575]": 577, + "[control_576]": 578, + "[control_577]": 579, + "[control_578]": 580, + "[control_579]": 581, + "[control_580]": 582, + "[control_581]": 583, + "[control_582]": 584, + "[control_583]": 585, + "[control_584]": 586, + "[control_585]": 587, + "[control_586]": 588, + "[control_587]": 589, + "[control_588]": 590, + "[control_589]": 591, + "[control_590]": 592, + "[control_591]": 593, + "[control_592]": 594, + "[control_593]": 595, + "[control_594]": 596, + "[control_595]": 597, + "[control_596]": 598, + "[control_597]": 599, + "[control_598]": 600, + "[control_599]": 601, + "[control_600]": 602, + "[control_601]": 603, + "[control_602]": 604, + "[control_603]": 605, + "[control_604]": 606, + "[control_605]": 607, + "[control_606]": 608, + "[control_607]": 609, + "[control_608]": 610, + "[control_609]": 611, + "[control_610]": 612, + "[control_611]": 613, + "[control_612]": 614, + "[control_613]": 615, + "[control_614]": 616, + "[control_615]": 617, + "[control_616]": 618, + "[control_617]": 619, + "[control_618]": 620, + "[control_619]": 621, + "[control_620]": 622, + "[control_621]": 623, + "[control_622]": 624, + "[control_623]": 625, + "[control_624]": 626, + "[control_625]": 627, + "[control_626]": 628, + "[control_627]": 629, + "[control_628]": 630, + "[control_629]": 631, + "[control_630]": 632, + "[control_631]": 633, + "[control_632]": 634, + "[control_633]": 635, + "[control_634]": 636, + "[control_635]": 637, + "[control_636]": 638, + "[control_637]": 639, + "[control_638]": 640, + "[control_639]": 641, + "[control_640]": 642, + "[control_641]": 643, + "[control_642]": 644, + "[control_643]": 645, + "[control_644]": 646, + "[control_645]": 647, + "[control_646]": 648, + "[control_647]": 649, + "[control_648]": 650, + "[control_649]": 651, + "[control_650]": 652, + "[control_651]": 653, + "[control_652]": 654, + "[control_653]": 655, + "[control_654]": 656, + "[control_655]": 657, + "[control_656]": 658, + "[control_657]": 659, + "[control_658]": 660, + "[control_659]": 661, + "[control_660]": 662, + "[control_661]": 663, + "[control_662]": 664, + "[control_663]": 665, + "[control_664]": 666, + "[control_665]": 667, + "[control_666]": 668, + "[control_667]": 669, + "[control_668]": 670, + "[control_669]": 671, + "[control_670]": 672, + "[control_671]": 673, + "[control_672]": 674, + "[control_673]": 675, + "[control_674]": 676, + "[control_675]": 677, + "[control_676]": 678, + "[control_677]": 679, + "[control_678]": 680, + "[control_679]": 681, + "[control_680]": 682, + "[control_681]": 683, + "[control_682]": 684, + "[control_683]": 685, + "[control_684]": 686, + "[control_685]": 687, + "[control_686]": 688, + "[control_687]": 689, + "[control_688]": 690, + "[control_689]": 691, + "[control_690]": 692, + "[control_691]": 693, + "[control_692]": 694, + "[control_693]": 695, + "[control_694]": 696, + "[control_695]": 697, + "[control_696]": 698, + "[control_697]": 699, + "[control_698]": 700, + "[control_699]": 701, + "[control_700]": 702, + "[control_701]": 703, + "[control_702]": 704, + "[control_703]": 705, + "[control_704]": 706, + "[control_705]": 707, + "[control_706]": 708, + "[control_707]": 709, + "[control_708]": 710, + "[control_709]": 711, + "[control_710]": 712, + "[control_711]": 713, + "[control_712]": 714, + "[control_713]": 715, + "[control_714]": 716, + "[control_715]": 717, + "[control_716]": 718, + "[control_717]": 719, + "[control_718]": 720, + "[control_719]": 721, + "[control_720]": 722, + "[control_721]": 723, + "[control_722]": 724, + "[control_723]": 725, + "[control_724]": 726, + "[control_725]": 727, + "[control_726]": 728, + "[control_727]": 729, + "[control_728]": 730, + "[control_729]": 731, + "[control_730]": 732, + "[control_731]": 733, + "[control_732]": 734, + "[control_733]": 735, + "[control_734]": 736, + "[control_735]": 737, + "[control_736]": 738, + "[control_737]": 739, + "[control_738]": 740, + "[control_739]": 741, + "[control_740]": 742, + "[control_741]": 743, + "[control_742]": 744, + "[control_743]": 745, + "[control_744]": 746, + "[control_745]": 747, + "[control_746]": 748, + "[control_747]": 749, + "[control_748]": 750, + "[control_749]": 751, + "[control_750]": 752, + "[control_751]": 753, + "[control_752]": 754, + "[control_753]": 755, + "[control_754]": 756, + "[control_755]": 757, + "[control_756]": 758, + "[control_757]": 759, + "[control_758]": 760, + "[control_759]": 761, + "[control_760]": 762, + "[control_761]": 763, + "[control_762]": 764, + "[control_763]": 765, + "[control_764]": 766, + "[control_765]": 767, + "[control_766]": 768, + "[control_767]": 769, + "[control_768]": 770, + "<0x00>": 771, + "<0x01>": 772, + "<0x02>": 773, + "<0x03>": 774, + "<0x04>": 775, + "<0x05>": 776, + "<0x06>": 777, + "<0x07>": 778, + "<0x08>": 779, + "<0x09>": 780, + "<0x0A>": 781, + "<0x0B>": 782, + "<0x0C>": 783, + "<0x0D>": 784, + "<0x0E>": 785, + "<0x0F>": 786, + "<0x10>": 787, + "<0x11>": 788, + "<0x12>": 789, + "<0x13>": 790, + "<0x14>": 791, + "<0x15>": 792, + "<0x16>": 793, + "<0x17>": 794, + "<0x18>": 795, + "<0x19>": 796, + "<0x1A>": 797, + "<0x1B>": 798, + "<0x1C>": 799, + "<0x1D>": 800, + "<0x1E>": 801, + "<0x1F>": 802, + "<0x20>": 803, + "<0x21>": 804, + "<0x22>": 805, + "<0x23>": 806, + "<0x24>": 807, + "<0x25>": 808, + "<0x26>": 809, + "<0x27>": 810, + "<0x28>": 811, + "<0x29>": 812, + "<0x2A>": 813, + "<0x2B>": 814, + "<0x2C>": 815, + "<0x2D>": 816, + "<0x2E>": 817, + "<0x2F>": 818, + "<0x30>": 819, + "<0x31>": 820, + "<0x32>": 821, + "<0x33>": 822, + "<0x34>": 823, + "<0x35>": 824, + "<0x36>": 825, + "<0x37>": 826, + "<0x38>": 827, + "<0x39>": 828, + "<0x3A>": 829, + "<0x3B>": 830, + "<0x3C>": 831, + "<0x3D>": 832, + "<0x3E>": 833, + "<0x3F>": 834, + "<0x40>": 835, + "<0x41>": 836, + "<0x42>": 837, + "<0x43>": 838, + "<0x44>": 839, + "<0x45>": 840, + "<0x46>": 841, + "<0x47>": 842, + "<0x48>": 843, + "<0x49>": 844, + "<0x4A>": 845, + "<0x4B>": 846, + "<0x4C>": 847, + "<0x4D>": 848, + "<0x4E>": 849, + "<0x4F>": 850, + "<0x50>": 851, + "<0x51>": 852, + "<0x52>": 853, + "<0x53>": 854, + "<0x54>": 855, + "<0x55>": 856, + "<0x56>": 857, + "<0x57>": 858, + "<0x58>": 859, + "<0x59>": 860, + "<0x5A>": 861, + "<0x5B>": 862, + "<0x5C>": 863, + "<0x5D>": 864, + "<0x5E>": 865, + "<0x5F>": 866, + "<0x60>": 867, + "<0x61>": 868, + "<0x62>": 869, + "<0x63>": 870, + "<0x64>": 871, + "<0x65>": 872, + "<0x66>": 873, + "<0x67>": 874, + "<0x68>": 875, + "<0x69>": 876, + "<0x6A>": 877, + "<0x6B>": 878, + "<0x6C>": 879, + "<0x6D>": 880, + "<0x6E>": 881, + "<0x6F>": 882, + "<0x70>": 883, + "<0x71>": 884, + "<0x72>": 885, + "<0x73>": 886, + "<0x74>": 887, + "<0x75>": 888, + "<0x76>": 889, + "<0x77>": 890, + "<0x78>": 891, + "<0x79>": 892, + "<0x7A>": 893, + "<0x7B>": 894, + "<0x7C>": 895, + "<0x7D>": 896, + "<0x7E>": 897, + "<0x7F>": 898, + "<0x80>": 899, + "<0x81>": 900, + "<0x82>": 901, + "<0x83>": 902, + "<0x84>": 903, + "<0x85>": 904, + "<0x86>": 905, + "<0x87>": 906, + "<0x88>": 907, + "<0x89>": 908, + "<0x8A>": 909, + "<0x8B>": 910, + "<0x8C>": 911, + "<0x8D>": 912, + "<0x8E>": 913, + "<0x8F>": 914, + "<0x90>": 915, + "<0x91>": 916, + "<0x92>": 917, + "<0x93>": 918, + "<0x94>": 919, + "<0x95>": 920, + "<0x96>": 921, + "<0x97>": 922, + "<0x98>": 923, + "<0x99>": 924, + "<0x9A>": 925, + "<0x9B>": 926, + "<0x9C>": 927, + "<0x9D>": 928, + "<0x9E>": 929, + "<0x9F>": 930, + "<0xA0>": 931, + "<0xA1>": 932, + "<0xA2>": 933, + "<0xA3>": 934, + "<0xA4>": 935, + "<0xA5>": 936, + "<0xA6>": 937, + "<0xA7>": 938, + "<0xA8>": 939, + "<0xA9>": 940, + "<0xAA>": 941, + "<0xAB>": 942, + "<0xAC>": 943, + "<0xAD>": 944, + "<0xAE>": 945, + "<0xAF>": 946, + "<0xB0>": 947, + "<0xB1>": 948, + "<0xB2>": 949, + "<0xB3>": 950, + "<0xB4>": 951, + "<0xB5>": 952, + "<0xB6>": 953, + "<0xB7>": 954, + "<0xB8>": 955, + "<0xB9>": 956, + "<0xBA>": 957, + "<0xBB>": 958, + "<0xBC>": 959, + "<0xBD>": 960, + "<0xBE>": 961, + "<0xBF>": 962, + "<0xC0>": 963, + "<0xC1>": 964, + "<0xC2>": 965, + "<0xC3>": 966, + "<0xC4>": 967, + "<0xC5>": 968, + "<0xC6>": 969, + "<0xC7>": 970, + "<0xC8>": 971, + "<0xC9>": 972, + "<0xCA>": 973, + "<0xCB>": 974, + "<0xCC>": 975, + "<0xCD>": 976, + "<0xCE>": 977, + "<0xCF>": 978, + "<0xD0>": 979, + "<0xD1>": 980, + "<0xD2>": 981, + "<0xD3>": 982, + "<0xD4>": 983, + "<0xD5>": 984, + "<0xD6>": 985, + "<0xD7>": 986, + "<0xD8>": 987, + "<0xD9>": 988, + "<0xDA>": 989, + "<0xDB>": 990, + "<0xDC>": 991, + "<0xDD>": 992, + "<0xDE>": 993, + "<0xDF>": 994, + "<0xE0>": 995, + "<0xE1>": 996, + "<0xE2>": 997, + "<0xE3>": 998, + "<0xE4>": 999, + "<0xE5>": 1000, + "<0xE6>": 1001, + "<0xE7>": 1002, + "<0xE8>": 1003, + "<0xE9>": 1004, + "<0xEA>": 1005, + "<0xEB>": 1006, + "<0xEC>": 1007, + "<0xED>": 1008, + "<0xEE>": 1009, + "<0xEF>": 1010, + "<0xF0>": 1011, + "<0xF1>": 1012, + "<0xF2>": 1013, + "<0xF3>": 1014, + "<0xF4>": 1015, + "<0xF5>": 1016, + "<0xF6>": 1017, + "<0xF7>": 1018, + "<0xF8>": 1019, + "<0xF9>": 1020, + "<0xFA>": 1021, + "<0xFB>": 1022, + "<0xFC>": 1023, + "<0xFD>": 1024, + "<0xFE>": 1025, + "<0xFF>": 1026, + "▁▁": 1027, + "▁▁▁▁": 1028, + "▁t": 1029, + "in": 1030, + "er": 1031, + "▁a": 1032, + "he": 1033, + "on": 1034, + "re": 1035, + "▁s": 1036, + "en": 1037, + "at": 1038, + "or": 1039, + "▁the": 1040, + "▁▁▁▁▁▁▁▁": 1041, + "es": 1042, + "▁w": 1043, + "an": 1044, + "▁c": 1045, + "is": 1046, + "it": 1047, + "ou": 1048, + "▁d": 1049, + "al": 1050, + "ar": 1051, + "▁p": 1052, + "▁f": 1053, + "ed": 1054, + "▁b": 1055, + "ing": 1056, + "▁o": 1057, + "▁m": 1058, + "le": 1059, + "nd": 1060, + "as": 1061, + "ic": 1062, + "▁h": 1063, + "ion": 1064, + "▁in": 1065, + "▁to": 1066, + "et": 1067, + "om": 1068, + "el": 1069, + "▁of": 1070, + "st": 1071, + "▁and": 1072, + "▁l": 1073, + "▁th": 1074, + "▁n": 1075, + "ent": 1076, + "il": 1077, + "ct": 1078, + "ro": 1079, + "▁re": 1080, + "id": 1081, + "am": 1082, + "▁I": 1083, + "ad": 1084, + "▁e": 1085, + "▁S": 1086, + "▁g": 1087, + "▁T": 1088, + "im": 1089, + "ot": 1090, + "ac": 1091, + "ur": 1092, + "▁(": 1093, + "ig": 1094, + "▁=": 1095, + "ol": 1096, + "ut": 1097, + "▁A": 1098, + "se": 1099, + "▁u": 1100, + "ve": 1101, + "▁C": 1102, + "if": 1103, + "ow": 1104, + "▁y": 1105, + "ch": 1106, + "ay": 1107, + "▁de": 1108, + "▁st": 1109, + "▁|": 1110, + "ver": 1111, + ");": 1112, + "▁\"": 1113, + "ly": 1114, + "▁be": 1115, + "**": 1116, + "▁is": 1117, + "od": 1118, + "▁M": 1119, + "ation": 1120, + "ul": 1121, + "▁for": 1122, + "▁▁▁▁▁": 1123, + "▁on": 1124, + "ag": 1125, + "ce": 1126, + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁": 1127, + "ter": 1128, + "ir": 1129, + "th": 1130, + "▁v": 1131, + "qu": 1132, + "▁B": 1133, + "em": 1134, + "▁P": 1135, + "▁you": 1136, + "▁that": 1137, + "un": 1138, + "▁{": 1139, + "ith": 1140, + "ri": 1141, + "est": 1142, + "ab": 1143, + "--": 1144, + "ap": 1145, + "▁it": 1146, + "▁con": 1147, + "ate": 1148, + "us": 1149, + "▁H": 1150, + "um": 1151, + "▁D": 1152, + "os": 1153, + "pe": 1154, + "▁-": 1155, + "▁wh": 1156, + "▁al": 1157, + "▁as": 1158, + "and": 1159, + "ist": 1160, + "▁L": 1161, + "▁W": 1162, + "▁with": 1163, + "▁an": 1164, + "ere": 1165, + "▁*": 1166, + "▁R": 1167, + "▁he": 1168, + "▁F": 1169, + "oc": 1170, + "▁was": 1171, + "ers": 1172, + "ke": 1173, + "out": 1174, + "ht": 1175, + "▁r": 1176, + "ess": 1177, + "op": 1178, + "res": 1179, + "ie": 1180, + "▁E": 1181, + "▁\\": 1182, + "▁The": 1183, + "end": 1184, + "ld": 1185, + "▁N": 1186, + "ort": 1187, + "▁G": 1188, + "//": 1189, + "▁#": 1190, + "our": 1191, + "te": 1192, + "ill": 1193, + "ain": 1194, + "▁se": 1195, + "▁▁▁▁▁▁": 1196, + "▁$": 1197, + "▁pro": 1198, + "ore": 1199, + "▁com": 1200, + "ame": 1201, + "tr": 1202, + "▁ne": 1203, + "rom": 1204, + "ub": 1205, + "▁at": 1206, + "▁ex": 1207, + "ant": 1208, + "ue": 1209, + "▁or": 1210, + "▁}": 1211, + "art": 1212, + "ction": 1213, + "▁k": 1214, + "pt": 1215, + "nt": 1216, + "iv": 1217, + "de": 1218, + "▁O": 1219, + "pl": 1220, + "urn": 1221, + "ight": 1222, + "all": 1223, + "▁this": 1224, + "ser": 1225, + "ave": 1226, + "▁not": 1227, + "▁are": 1228, + "▁j": 1229, + "▁le": 1230, + "iz": 1231, + "▁'": 1232, + "age": 1233, + "ment": 1234, + "▁tr": 1235, + "ack": 1236, + "ust": 1237, + "()": 1238, + "->": 1239, + "ity": 1240, + "ine": 1241, + "ould": 1242, + "▁J": 1243, + "og": 1244, + "▁from": 1245, + "▁we": 1246, + "ell": 1247, + "▁sh": 1248, + "▁en": 1249, + "ure": 1250, + "port": 1251, + "▁ch": 1252, + "ne": 1253, + "▁by": 1254, + "per": 1255, + "ard": 1256, + "ass": 1257, + "ge": 1258, + "ak": 1259, + "are": 1260, + "ok": 1261, + "av": 1262, + "ive": 1263, + "ff": 1264, + "ies": 1265, + "ath": 1266, + "turn": 1267, + "▁U": 1268, + "int": 1269, + "----": 1270, + "▁im": 1271, + "ost": 1272, + "ial": 1273, + "▁have": 1274, + "ind": 1275, + "ip": 1276, + "ans": 1277, + "xt": 1278, + "▁do": 1279, + "cl": 1280, + "▁if": 1281, + "con": 1282, + "ia": 1283, + "▁his": 1284, + "ult": 1285, + "rou": 1286, + "▁su": 1287, + "ra": 1288, + "▁un": 1289, + "able": 1290, + "▁<": 1291, + "▁K": 1292, + "ome": 1293, + "▁qu": 1294, + "get": 1295, + "▁me": 1296, + "ast": 1297, + "ect": 1298, + "▁##": 1299, + "to": 1300, + "▁cl": 1301, + "▁ab": 1302, + "ice": 1303, + "ire": 1304, + "ber": 1305, + "one": 1306, + "ich": 1307, + "hen": 1308, + "▁can": 1309, + "▁Th": 1310, + "▁la": 1311, + "▁all": 1312, + "ime": 1313, + "ile": 1314, + "ide": 1315, + "\",": 1316, + "▁pl": 1317, + "▁V": 1318, + "ru": 1319, + "orm": 1320, + "▁had": 1321, + "ud": 1322, + "ase": 1323, + "ord": 1324, + "),": 1325, + "▁▁▁▁▁▁▁▁▁▁▁▁": 1326, + "▁her": 1327, + "▁In": 1328, + "ace": 1329, + "▁but": 1330, + "ata": 1331, + "::": 1332, + "****": 1333, + "ong": 1334, + "▁&": 1335, + "..": 1336, + "▁▁▁▁▁▁▁▁▁▁▁▁▁": 1337, + "ite": 1338, + "ype": 1339, + "act": 1340, + "ode": 1341, + "▁your": 1342, + "▁out": 1343, + "▁go": 1344, + "lic": 1345, + "ally": 1346, + "▁so": 1347, + "ork": 1348, + "au": 1349, + "▁up": 1350, + "▁_": 1351, + "ll": 1352, + "==": 1353, + "▁my": 1354, + "pp": 1355, + "cc": 1356, + "▁//": 1357, + "▁they": 1358, + "gh": 1359, + "▁us": 1360, + "ib": 1361, + "ions": 1362, + "ach": 1363, + "ens": 1364, + "▁ar": 1365, + "ob": 1366, + "elf": 1367, + "ook": 1368, + "ated": 1369, + "ang": 1370, + "ign": 1371, + "▁return": 1372, + "▁res": 1373, + "ck": 1374, + "ous": 1375, + "ст": 1376, + ").": 1377, + "▁п": 1378, + ".\"": 1379, + "на": 1380, + "▁i": 1381, + "ail": 1382, + "ep": 1383, + "▁ad": 1384, + "ance": 1385, + "(\"": 1386, + "▁**": 1387, + "ther": 1388, + "ake": 1389, + "▁will": 1390, + "▁comp": 1391, + "▁one": 1392, + "▁get": 1393, + "ov": 1394, + "▁Y": 1395, + "ary": 1396, + "ock": 1397, + "▁she": 1398, + "che": 1399, + "ft": 1400, + "▁new": 1401, + "▁des": 1402, + "▁li": 1403, + "ence": 1404, + "▁sa": 1405, + "ress": 1406, + "▁el": 1407, + "▁und": 1408, + "eg": 1409, + "fer": 1410, + "ry": 1411, + "ear": 1412, + "ose": 1413, + "very": 1414, + "',": 1415, + "▁+": 1416, + "▁в": 1417, + "▁He": 1418, + "ublic": 1419, + "▁their": 1420, + "ize": 1421, + "▁were": 1422, + "ink": 1423, + "own": 1424, + "In": 1425, + "{\\": 1426, + "▁has": 1427, + "▁per": 1428, + "▁It": 1429, + "▁St": 1430, + "her": 1431, + "ject": 1432, + "ра": 1433, + "ild": 1434, + "so": 1435, + "▁sp": 1436, + "ни": 1437, + "du": 1438, + "row": 1439, + "alue": 1440, + "set": 1441, + "form": 1442, + "com": 1443, + "▁man": 1444, + "ont": 1445, + "ull": 1446, + "▁cont": 1447, + "▁more": 1448, + "ick": 1449, + "▁would": 1450, + "▁ev": 1451, + "▁about": 1452, + "ition": 1453, + "▁z": 1454, + "ound": 1455, + "ree": 1456, + "▁Ch": 1457, + "▁which": 1458, + "io": 1459, + "();": 1460, + "▁who": 1461, + "err": 1462, + "ory": 1463, + "ount": 1464, + "ations": 1465, + "▁с": 1466, + "ring": 1467, + "": 1644, + "▁em": 1645, + "▁$\\": 1646, + "▁year": 1647, + "wn": 1648, + "},": 1649, + "▁del": 1650, + "ale": 1651, + "ty": 1652, + "fig": 1653, + "sp": 1654, + "hed": 1655, + "round": 1656, + "ew": 1657, + "▁di": 1658, + "▁der": 1659, + "ри": 1660, + "red": 1661, + "this": 1662, + "let": 1663, + "RE": 1664, + "ax": 1665, + "fr": 1666, + "essage": 1667, + "ough": 1668, + "▁comm": 1669, + "fo": 1670, + "uch": 1671, + "oy": 1672, + "▁people": 1673, + "ystem": 1674, + "▁first": 1675, + "▁function": 1676, + "ange": 1677, + "▁how": 1678, + "▁et": 1679, + "ah": 1680, + "▁look": 1681, + "то": 1682, + "und": 1683, + "▁under": 1684, + "ка": 1685, + "▁!": 1686, + "ray": 1687, + "ST": 1688, + "ific": 1689, + "ли": 1690, + "read": 1691, + "▁bet": 1692, + "ious": 1693, + "arg": 1694, + "▁need": 1695, + "math": 1696, + "▁на": 1697, + "ert": 1698, + "▁op": 1699, + "▁acc": 1700, + "Pro": 1701, + "▁est": 1702, + "▁Un": 1703, + "▁ent": 1704, + "▁rec": 1705, + "▁use": 1706, + "ен": 1707, + "▁par": 1708, + "az": 1709, + "▁д": 1710, + "▁Wh": 1711, + "self": 1712, + "▁ke": 1713, + "та": 1714, + "▁want": 1715, + "▁end": 1716, + "▁don": 1717, + "ek": 1718, + "ren": 1719, + "Name": 1720, + "▁=>": 1721, + "▁app": 1722, + "▁que": 1723, + "igh": 1724, + "▁bu": 1725, + "equ": 1726, + "vel": 1727, + "▁act": 1728, + "cre": 1729, + "AT": 1730, + "▁var": 1731, + "cess": 1732, + "====": 1733, + "Ex": 1734, + "▁add": 1735, + "▁mod": 1736, + "ung": 1737, + "▁where": 1738, + "ning": 1739, + "▁fl": 1740, + "als": 1741, + "tern": 1742, + "}}": 1743, + "▁Al": 1744, + "▁pos": 1745, + "ank": 1746, + "▁ap": 1747, + "eng": 1748, + "▁“": 1749, + "ble": 1750, + "▁reg": 1751, + "^{": 1752, + "▁She": 1753, + "▁*/": 1754, + "ude": 1755, + "add": 1756, + "▁two": 1757, + "▁col": 1758, + "▁sm": 1759, + "air": 1760, + "▁may": 1761, + "fore": 1762, + "▁You": 1763, + "rough": 1764, + "▁che": 1765, + "▁att": 1766, + "oth": 1767, + "ла": 1768, + "▁co": 1769, + "ates": 1770, + "▁rem": 1771, + "ood": 1772, + "Type": 1773, + "led": 1774, + "ful": 1775, + "▁self": 1776, + "of": 1777, + "▁Ar": 1778, + "que": 1779, + "▁every": 1780, + "ref": 1781, + "The": 1782, + "▁And": 1783, + "▁rel": 1784, + "OR": 1785, + "Id": 1786, + "▁even": 1787, + "EN": 1788, + "▁hand": 1789, + "ait": 1790, + "▁should": 1791, + "▁after": 1792, + "▁dif": 1793, + "ght": 1794, + "ife": 1795, + "ator": 1796, + "ash": 1797, + "ribut": 1798, + "umber": 1799, + "▁see": 1800, + "ms": 1801, + "▁call": 1802, + "yn": 1803, + "dd": 1804, + "▁es": 1805, + "▁make": 1806, + "other": 1807, + "▁—": 1808, + "\");": 1809, + "str": 1810, + "▁long": 1811, + "lement": 1812, + "▁wor": 1813, + "its": 1814, + "▁If": 1815, + "alse": 1816, + "ль": 1817, + "ward": 1818, + "▁по": 1819, + "val": 1820, + "ons": 1821, + "▁Z": 1822, + "▁now": 1823, + "data": 1824, + "amp": 1825, + "ense": 1826, + "▁through": 1827, + "▁down": 1828, + "att": 1829, + "▁static": 1830, + "ics": 1831, + "##": 1832, + "pos": 1833, + "▁void": 1834, + "aw": 1835, + "oun": 1836, + "▁way": 1837, + "ible": 1838, + "vent": 1839, + "ower": 1840, + "▁think": 1841, + "ts": 1842, + "*/": 1843, + "▁again": 1844, + "ating": 1845, + "те": 1846, + "ner": 1847, + "▁most": 1848, + "line": 1849, + "ym": 1850, + "▁sub": 1851, + "erson": 1852, + "▁requ": 1853, + "AL": 1854, + "AR": 1855, + "abel": 1856, + "ond": 1857, + "));": 1858, + "▁Se": 1859, + "▁But": 1860, + "alk": 1861, + "▁An": 1862, + "new": 1863, + "▁because": 1864, + "ger": 1865, + "ular": 1866, + "roup": 1867, + "ta": 1868, + "...": 1869, + "▁cons": 1870, + "▁right": 1871, + "▁fr": 1872, + "be": 1873, + "ily": 1874, + "ки": 1875, + "▁ph": 1876, + "ead": 1877, + "?\"": 1878, + "▁gu": 1879, + "▁else": 1880, + "▁som": 1881, + "rent": 1882, + "co": 1883, + "ement": 1884, + "▁str": 1885, + "ault": 1886, + "▁з": 1887, + "ло": 1888, + "sert": 1889, + "var": 1890, + "type": 1891, + "▁Com": 1892, + "ле": 1893, + "ins": 1894, + "me": 1895, + "way": 1896, + "ident": 1897, + "▁prov": 1898, + "▁м": 1899, + "▁true": 1900, + "▁Pro": 1901, + "fl": 1902, + "▁sl": 1903, + "▁As": 1904, + "}\\": 1905, + "ID": 1906, + "ues": 1907, + "▁inst": 1908, + "▁name": 1909, + "ox": 1910, + "▁)": 1911, + "li": 1912, + "ames": 1913, + "Res": 1914, + "▁sur": 1915, + "param": 1916, + "▁start": 1917, + "aj": 1918, + "SE": 1919, + "ask": 1920, + "IT": 1921, + "String": 1922, + "▁ass": 1923, + "▁play": 1924, + "ting": 1925, + "ton": 1926, + "▁before": 1927, + "▁pol": 1928, + "arch": 1929, + "▁well": 1930, + "Com": 1931, + "any": 1932, + "olog": 1933, + "▁err": 1934, + "▁these": 1935, + "ars": 1936, + "eb": 1937, + "▁br": 1938, + "▁incl": 1939, + "▁hel": 1940, + "ern": 1941, + "ody": 1942, + "во": 1943, + "▁ind": 1944, + "----------------": 1945, + "▁data": 1946, + "▁good": 1947, + "LE": 1948, + "],": 1949, + "▁av": 1950, + "▁ac": 1951, + "ider": 1952, + "не": 1953, + "▁Q": 1954, + "▁min": 1955, + "▁much": 1956, + "ci": 1957, + "els": 1958, + "▁cur": 1959, + "▁value": 1960, + "ery": 1961, + "uf": 1962, + "▁loc": 1963, + "reak": 1964, + "ative": 1965, + "imes": 1966, + "Cl": 1967, + "▁,": 1968, + "▁ser": 1969, + "▁die": 1970, + "▁trans": 1971, + "▁result": 1972, + "ext": 1973, + "▁aut": 1974, + "land": 1975, + "▁&&": 1976, + "Ch": 1977, + "ten": 1978, + "}$": 1979, + "▁type": 1980, + "cond": 1981, + "ices": 1982, + "▁very": 1983, + "▁own": 1984, + "▁fil": 1985, + "ities": 1986, + "▁produ": 1987, + "▁read": 1988, + "▁form": 1989, + "▁case": 1990, + "ather": 1991, + "ти": 1992, + "да": 1993, + "ер": 1994, + "Th": 1995, + "aut": 1996, + "▁spec": 1997, + "ij": 1998, + "bl": 1999, + "ility": 2000, + "▁é": 2001, + "▁er": 2002, + "▁does": 2003, + "▁here": 2004, + "the": 2005, + "ures": 2006, + "▁%": 2007, + "min": 2008, + "▁null": 2009, + "rap": 2010, + "\")": 2011, + "rr": 2012, + "List": 2013, + "right": 2014, + "▁User": 2015, + "UL": 2016, + "ational": 2017, + "▁being": 2018, + "AN": 2019, + "sk": 2020, + "▁car": 2021, + "ole": 2022, + "▁dist": 2023, + "plic": 2024, + "ollow": 2025, + "▁pres": 2026, + "▁such": 2027, + "ream": 2028, + "ince": 2029, + "gan": 2030, + "▁For": 2031, + "\":": 2032, + "son": 2033, + "rivate": 2034, + "▁years": 2035, + "▁serv": 2036, + "▁made": 2037, + "def": 2038, + ";\r": 2039, + "▁gl": 2040, + "▁bel": 2041, + "▁list": 2042, + "▁cor": 2043, + "▁det": 2044, + "ception": 2045, + "egin": 2046, + "▁б": 2047, + "▁char": 2048, + "trans": 2049, + "▁fam": 2050, + "▁!=": 2051, + "ouse": 2052, + "▁dec": 2053, + "ica": 2054, + "▁many": 2055, + "aking": 2056, + "▁à": 2057, + "▁sim": 2058, + "ages": 2059, + "uff": 2060, + "ased": 2061, + "man": 2062, + "▁Sh": 2063, + "iet": 2064, + "irect": 2065, + "▁Re": 2066, + "▁differ": 2067, + "▁find": 2068, + "ethod": 2069, + "▁\r": 2070, + "ines": 2071, + "▁inv": 2072, + "▁point": 2073, + "▁They": 2074, + "▁used": 2075, + "ctions": 2076, + "▁still": 2077, + "ió": 2078, + "ined": 2079, + "▁while": 2080, + "It": 2081, + "ember": 2082, + "▁say": 2083, + "▁help": 2084, + "▁cre": 2085, + "▁x": 2086, + "▁Tr": 2087, + "ument": 2088, + "▁sk": 2089, + "ought": 2090, + "ually": 2091, + "message": 2092, + "▁Con": 2093, + "▁mon": 2094, + "ared": 2095, + "work": 2096, + "):": 2097, + "ister": 2098, + "arn": 2099, + "ized": 2100, + "Data": 2101, + "orn": 2102, + "▁head": 2103, + "DE": 2104, + "▁Le": 2105, + "▁person": 2106, + "ments": 2107, + "ength": 2108, + "▁false": 2109, + "▁med": 2110, + "▁De": 2111, + "ache": 2112, + "ited": 2113, + "▁let": 2114, + "▁show": 2115, + "▁same": 2116, + "uss": 2117, + "▁gener": 2118, + "▁у": 2119, + "cur": 2120, + "▁real": 2121, + "ced": 2122, + "\">": 2123, + "struct": 2124, + "begin": 2125, + "cept": 2126, + "▁bo": 2127, + "ired": 2128, + "▁Fr": 2129, + "▁stud": 2130, + "dev": 2131, + "Ar": 2132, + "(\\": 2133, + "▁Cl": 2134, + "ween": 2135, + "▁too": 2136, + "▁test": 2137, + "▁day": 2138, + "oh": 2139, + "▁follow": 2140, + "ature": 2141, + "ze": 2142, + "ien": 2143, + "reg": 2144, + "ces": 2145, + "uring": 2146, + "amb": 2147, + "ina": 2148, + "cri": 2149, + "▁ed": 2150, + "SS": 2151, + "uck": 2152, + "▁/*": 2153, + "CT": 2154, + "▁There": 2155, + "▁take": 2156, + "par": 2157, + "ule": 2158, + "cal": 2159, + "for": 2160, + "****************": 2161, + "source": 2162, + "▁those": 2163, + "col": 2164, + "▁eff": 2165, + "mod": 2166, + "cont": 2167, + "}{": 2168, + "▁around": 2169, + "press": 2170, + "by": 2171, + "▁going": 2172, + "ponse": 2173, + "▁С": 2174, + "▁line": 2175, + "date": 2176, + "code": 2177, + "['": 2178, + "▁life": 2179, + "ason": 2180, + "▁using": 2181, + "▁val": 2182, + "▁du": 2183, + "yp": 2184, + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁": 2185, + "▁On": 2186, + "▁found": 2187, + "olut": 2188, + "']": 2189, + "arent": 2190, + "▁string": 2191, + "▁met": 2192, + "▁wr": 2193, + "ush": 2194, + "string": 2195, + "size": 2196, + "▁ver": 2197, + "▁each": 2198, + "value": 2199, + "▁last": 2200, + "▁got": 2201, + "ven": 2202, + "back": 2203, + "Set": 2204, + "ey": 2205, + "rol": 2206, + "▁cr": 2207, + "thing": 2208, + "ret": 2209, + "és": 2210, + "ism": 2211, + "▁between": 2212, + "Ob": 2213, + "ething": 2214, + "mp": 2215, + "▁lo": 2216, + "ats": 2217, + "▁New": 2218, + "ви": 2219, + "ado": 2220, + "dex": 2221, + "ди": 2222, + "▁pass": 2223, + "wh": 2224, + "▁den": 2225, + "Get": 2226, + "apt": 2227, + "▁ask": 2228, + "▁sup": 2229, + "Value": 2230, + "ны": 2231, + "▁try": 2232, + "lation": 2233, + "day": 2234, + "ness": 2235, + "ets": 2236, + "▁exper": 2237, + "Tr": 2238, + "▁Mar": 2239, + "serv": 2240, + "br": 2241, + "▁number": 2242, + "inal": 2243, + "cent": 2244, + "/*": 2245, + "not": 2246, + "ional": 2247, + "▁final": 2248, + "')": 2249, + "▁run": 2250, + "over": 2251, + "▁never": 2252, + "uc": 2253, + "▁high": 2254, + "yle": 2255, + "▁ins": 2256, + "▁best": 2257, + "ittle": 2258, + "ric": 2259, + "▁sign": 2260, + "▁dem": 2261, + "iness": 2262, + "gy": 2263, + "▁war": 2264, + "ished": 2265, + "▁giv": 2266, + "key": 2267, + "▁X": 2268, + "($": 2269, + "▁child": 2270, + "less": 2271, + "ways": 2272, + "incl": 2273, + "rop": 2274, + "raw": 2275, + "://": 2276, + "▁«": 2277, + "no": 2278, + "indow": 2279, + "fe": 2280, + "riend": 2281, + "▁les": 2282, + "▁los": 2283, + "file": 2284, + "formation": 2285, + "ccess": 2286, + "▁В": 2287, + "na": 2288, + "▁il": 2289, + "ision": 2290, + "ler": 2291, + "▁art": 2292, + "Cont": 2293, + "▁world": 2294, + "▁turn": 2295, + "▁really": 2296, + "▁Ex": 2297, + "ма": 2298, + "▁П": 2299, + "ters": 2300, + "arget": 2301, + "Err": 2302, + "▁happ": 2303, + "time": 2304, + "▁So": 2305, + "div": 2306, + "▁didn": 2307, + "ada": 2308, + "oot": 2309, + "})": 2310, + "▁sch": 2311, + "▁cle": 2312, + "▁something": 2313, + "().": 2314, + "▁cour": 2315, + "ever": 2316, + "ants": 2317, + "▁?": 2318, + "To": 2319, + "▁`": 2320, + "try": 2321, + "ux": 2322, + "ais": 2323, + "ross": 2324, + "hip": 2325, + "▁rep": 2326, + "label": 2327, + "▁both": 2328, + "*,": 2329, + "ott": 2330, + "ми": 2331, + "ane": 2332, + "▁open": 2333, + "ww": 2334, + "▁come": 2335, + "▁ext": 2336, + "rem": 2337, + "_{\\": 2338, + "▁old": 2339, + "ched": 2340, + "._": 2341, + "ME": 2342, + "ify": 2343, + "gg": 2344, + "Col": 2345, + "view": 2346, + "▁bus": 2347, + "▁must": 2348, + "▁different": 2349, + "log": 2350, + "ists": 2351, + "roll": 2352, + "ai": 2353, + "▁за": 2354, + "▁system": 2355, + "ivers": 2356, + "atus": 2357, + "ote": 2358, + "med": 2359, + "].": 2360, + "akes": 2361, + "RO": 2362, + "▁cent": 2363, + "gram": 2364, + "▁private": 2365, + "▁great": 2366, + "\";": 2367, + "opy": 2368, + "▁feel": 2369, + "▁How": 2370, + "////": 2371, + "IC": 2372, + "▁dr": 2373, + "ains": 2374, + "lock": 2375, + "En": 2376, + "▁Sch": 2377, + "▁mat": 2378, + "▁home": 2379, + "perty": 2380, + "test": 2381, + "loc": 2382, + "▁wom": 2383, + "sw": 2384, + "arly": 2385, + "▁En": 2386, + "▁ко": 2387, + "den": 2388, + "ста": 2389, + "▁а": 2390, + "eter": 2391, + "▁includ": 2392, + "ULL": 2393, + "▁mem": 2394, + "▁po": 2395, + "▁little": 2396, + "▁arg": 2397, + "▁},": 2398, + "include": 2399, + "eta": 2400, + "▁place": 2401, + "idth": 2402, + "ustom": 2403, + "▁||": 2404, + "▁tem": 2405, + "ried": 2406, + "▁fact": 2407, + "ience": 2408, + "▁Pl": 2409, + "opt": 2410, + "ele": 2411, + "go": 2412, + "AC": 2413, + "inter": 2414, + "========": 2415, + "(),": 2416, + "ots": 2417, + "ral": 2418, + "ique": 2419, + "aving": 2420, + "ml": 2421, + "▁thought": 2422, + "frac": 2423, + "▁care": 2424, + "());": 2425, + "▁put": 2426, + "▁might": 2427, + "▁Amer": 2428, + "▁(!": 2429, + "ample": 2430, + "alth": 2431, + "▁few": 2432, + "▁state": 2433, + "sub": 2434, + "▁Or": 2435, + "];": 2436, + "▁size": 2437, + "▁Sp": 2438, + "▁without": 2439, + "▁poss": 2440, + "eq": 2441, + "play": 2442, + "▁expect": 2443, + "▁second": 2444, + "▁String": 2445, + "uild": 2446, + "▁next": 2447, + "++": 2448, + "requ": 2449, + "▁All": 2450, + "▁men": 2451, + "▁When": 2452, + "iter": 2453, + "ament": 2454, + "net": 2455, + "▁К": 2456, + "ron": 2457, + "aint": 2458, + "▁Is": 2459, + "ве": 2460, + "pend": 2461, + "translation": 2462, + "▁го": 2463, + "че": 2464, + "▁van": 2465, + "▁another": 2466, + "▁ret": 2467, + "▁La": 2468, + "Mod": 2469, + "ION": 2470, + "list": 2471, + "▁post": 2472, + "da": 2473, + "ware": 2474, + "▁word": 2475, + "Error": 2476, + "▁seem": 2477, + "▁contin": 2478, + "atic": 2479, + "▁three": 2480, + "Object": 2481, + "▁partic": 2482, + "$.": 2483, + "▁mark": 2484, + "▁vis": 2485, + "rc": 2486, + "▁sw": 2487, + "ptions": 2488, + "▁break": 2489, + "▁things": 2490, + "ute": 2491, + "ui": 2492, + "▁That": 2493, + "urs": 2494, + "gl": 2495, + "ру": 2496, + "▁file": 2497, + "use": 2498, + "igned": 2499, + "part": 2500, + "Un": 2501, + "▁equ": 2502, + "(&": 2503, + "▁lead": 2504, + "rm": 2505, + "ained": 2506, + "▁Be": 2507, + "path": 2508, + "▁small": 2509, + "ager": 2510, + "▁always": 2511, + "▁El": 2512, + "▁order": 2513, + "▁ey": 2514, + "▁won": 2515, + "ape": 2516, + "▁left": 2517, + "ava": 2518, + "item": 2519, + "hor": 2520, + "▁away": 2521, + "bb": 2522, + "fun": 2523, + "▁Ind": 2524, + "mb": 2525, + "▁struct": 2526, + "▁process": 2527, + "▁support": 2528, + ");\r": 2529, + "ión": 2530, + "LO": 2531, + "▁oper": 2532, + "UT": 2533, + "▁·": 2534, + "PE": 2535, + "load": 2536, + "off": 2537, + "▁No": 2538, + "ives": 2539, + "ican": 2540, + "▁ve": 2541, + "action": 2542, + "';": 2543, + "▁vo": 2544, + "$,": 2545, + "▁Gr": 2546, + "pre": 2547, + "ny": 2548, + "aining": 2549, + "ior": 2550, + "init": 2551, + "lection": 2552, + "arm": 2553, + "umn": 2554, + "ags": 2555, + "ци": 2556, + "ско": 2557, + "version": 2558, + "▁To": 2559, + "▁ref": 2560, + "stand": 2561, + "▁At": 2562, + "ift": 2563, + "▁ein": 2564, + "face": 2565, + "bo": 2566, + "ified": 2567, + "ved": 2568, + "sum": 2569, + "une": 2570, + "ital": 2571, + "ump": 2572, + "comm": 2573, + "▁mov": 2574, + "elt": 2575, + "▁von": 2576, + "velop": 2577, + "ctor": 2578, + "head": 2579, + "cle": 2580, + "▁build": 2581, + "inc": 2582, + ".'": 2583, + "bs": 2584, + "info": 2585, + "chn": 2586, + "▁week": 2587, + "▁book": 2588, + "HE": 2589, + "bar": 2590, + "icense": 2591, + "▁What": 2592, + "▁quest": 2593, + "urch": 2594, + "ato": 2595, + "left": 2596, + "▁mar": 2597, + "▁top": 2598, + "FF": 2599, + "▁friend": 2600, + "▁beh": 2601, + "▁field": 2602, + "▁against": 2603, + "ract": 2604, + "ization": 2605, + "user": 2606, + "chen": 2607, + "▁keep": 2608, + "AD": 2609, + "itor": 2610, + "▁non": 2611, + "ird": 2612, + "ope": 2613, + "▁rest": 2614, + "▁dev": 2615, + "▁__": 2616, + "▁una": 2617, + "▁term": 2618, + "IS": 2619, + "▁pop": 2620, + "rist": 2621, + "▁since": 2622, + "ves": 2623, + "▁hard": 2624, + "pi": 2625, + "util": 2626, + "▁soc": 2627, + "ene": 2628, + "Exception": 2629, + "▁local": 2630, + "▁direct": 2631, + "▁sure": 2632, + "▁bro": 2633, + "▁da": 2634, + "▁": 3138, + "aim": 3139, + "▁service": 3140, + "▁within": 3141, + "angu": 3142, + "▁Д": 3143, + "uffer": 3144, + "AG": 3145, + "▁Do": 3146, + "▁incre": 3147, + "▁understand": 3148, + "}^": 3149, + "▁looked": 3150, + "gen": 3151, + "ailed": 3152, + "▁е": 3153, + "ayer": 3154, + "▁One": 3155, + "▁bas": 3156, + "▁job": 3157, + "mu": 3158, + "but": 3159, + "elta": 3160, + "▁Christ": 3161, + "uration": 3162, + "▁record": 3163, + "▁Univers": 3164, + "ivid": 3165, + "valid": 3166, + "▁Р": 3167, + "▁hold": 3168, + "▁table": 3169, + "ones": 3170, + "link": 3171, + "▁Ge": 3172, + "▁offer": 3173, + "ster": 3174, + "Form": 3175, + "={": 3176, + "▁не": 3177, + "stance": 3178, + "▁govern": 3179, + "▁techn": 3180, + "▁prim": 3181, + "*.": 3182, + "cho": 3183, + "max": 3184, + "▁fore": 3185, + "▁Can": 3186, + "▁polit": 3187, + "ories": 3188, + "▁times": 3189, + "▁dans": 3190, + "▁air": 3191, + "▁anything": 3192, + "▁sever": 3193, + "acy": 3194, + "}_": 3195, + "He": 3196, + "▁least": 3197, + "ips": 3198, + "ENT": 3199, + "do": 3200, + "▁от": 3201, + "▁cost": 3202, + ".”": 3203, + "▁children": 3204, + "ability": 3205, + "But": 3206, + "▁path": 3207, + "result": 3208, + "acter": 3209, + "▁element": 3210, + "ee": 3211, + "▁wait": 3212, + "▁money": 3213, + "Map": 3214, + "td": 3215, + "oin": 3216, + "iving": 3217, + "icht": 3218, + "icy": 3219, + "sch": 3220, + "ste": 3221, + "ду": 3222, + "ored": 3223, + "oud": 3224, + "ille": 3225, + "ised": 3226, + "plication": 3227, + "▁custom": 3228, + "▁having": 3229, + "ponent": 3230, + "▁By": 3231, + "ules": 3232, + "ued": 3233, + "atter": 3234, + "And": 3235, + "itive": 3236, + "Def": 3237, + "▁moment": 3238, + "aterial": 3239, + "Class": 3240, + "ograph": 3241, + "ike": 3242, + "▁large": 3243, + "▁####": 3244, + "▁either": 3245, + "duct": 3246, + "▁Then": 3247, + "▁Gu": 3248, + "olean": 3249, + "pert": 3250, + "▁Get": 3251, + "▁Ab": 3252, + "▁short": 3253, + "On": 3254, + "iment": 3255, + "▁project": 3256, + "cript": 3257, + "▁including": 3258, + "ния": 3259, + "▁making": 3260, + "▁someone": 3261, + "▁Fl": 3262, + "▁sat": 3263, + "▁company": 3264, + "ocus": 3265, + "pu": 3266, + "▁God": 3267, + "ification": 3268, + "No": 3269, + "▁sn": 3270, + "ano": 3271, + "ga": 3272, + "▁au": 3273, + "▁cou": 3274, + "ás": 3275, + "ended": 3276, + "ту": 3277, + "ober": 3278, + "▁nothing": 3279, + "▁net": 3280, + "▁pot": 3281, + "▁typ": 3282, + "▁item": 3283, + "rew": 3284, + "Att": 3285, + "▁young": 3286, + "}\r": 3287, + "nder": 3288, + "start": 3289, + "▁Sc": 3290, + "*)": 3291, + "▁enc": 3292, + "▁women": 3293, + "▁looking": 3294, + "▁ро": 3295, + "▁health": 3296, + "Path": 3297, + "▁After": 3298, + "▁mult": 3299, + "▁{\\": 3300, + "▁land": 3301, + "orld": 3302, + "▁Des": 3303, + "▁eng": 3304, + "input": 3305, + "▁Pol": 3306, + "\"\"": 3307, + "Code": 3308, + "▁supp": 3309, + "ainer": 3310, + "heck": 3311, + "▁mor": 3312, + "▁mill": 3313, + "▁aw": 3314, + "fs": 3315, + "▁doing": 3316, + "tings": 3317, + "ades": 3318, + "▁toget": 3319, + "▁certain": 3320, + "▁together": 3321, + "CE": 3322, + "ideo": 3323, + "▁American": 3324, + "ony": 3325, + "idd": 3326, + "II": 3327, + "ged": 3328, + "ables": 3329, + "▁ident": 3330, + "iod": 3331, + "▁parent": 3332, + "For": 3333, + "ambda": 3334, + "ando": 3335, + "=\\": 3336, + "aged": 3337, + "ending": 3338, + "Int": 3339, + "▁possible": 3340, + "▁со": 3341, + "ivity": 3342, + "num": 3343, + "rt": 3344, + "ajor": 3345, + "create": 3346, + "ride": 3347, + "▁knew": 3348, + "bit": 3349, + "itional": 3350, + "▁lik": 3351, + "▁Her": 3352, + "ension": 3353, + "\".": 3354, + "oto": 3355, + "▁exist": 3356, + "aken": 3357, + "▁actually": 3358, + "ca": 3359, + "▁Г": 3360, + "хо": 3361, + "inn": 3362, + "All": 3363, + "buf": 3364, + "▁Me": 3365, + "▁seen": 3366, + "ops": 3367, + "▁▁▁▁▁▁▁▁▁": 3368, + "Not": 3369, + "▁control": 3370, + "▁respon": 3371, + "};": 3372, + "ilt": 3373, + "isk": 3374, + "▁bad": 3375, + "▁often": 3376, + "▁past": 3377, + "aper": 3378, + "▁reason": 3379, + "eters": 3380, + "▁wanted": 3381, + "ura": 3382, + "table": 3383, + "ormal": 3384, + "width": 3385, + "га": 3386, + "ptr": 3387, + "▁dest": 3388, + "▁design": 3389, + "▁sound": 3390, + "▁plan": 3391, + "▁base": 3392, + "hand": 3393, + "gs": 3394, + "▁says": 3395, + "function": 3396, + "▁tri": 3397, + "mt": 3398, + "▁invest": 3399, + "▁available": 3400, + "ayout": 3401, + "▁och": 3402, + "▁las": 3403, + "illed": 3404, + "Val": 3405, + "▁ф": 3406, + "iety": 3407, + "mon": 3408, + "Hand": 3409, + "Fr": 3410, + "iam": 3411, + "pace": 3412, + "▁Ob": 3413, + "▁para": 3414, + "▁meet": 3415, + "▁sum": 3416, + "Message": 3417, + "ici": 3418, + "▁known": 3419, + "▁gen": 3420, + "amma": 3421, + "arr": 3422, + "▁tre": 3423, + "oke": 3424, + "uth": 3425, + "~\\": 3426, + "▁experience": 3427, + "icle": 3428, + "▁Il": 3429, + "▁sent": 3430, + "▁others": 3431, + "▁soft": 3432, + "IP": 3433, + "▁max": 3434, + "ball": 3435, + "▁market": 3436, + "▁pour": 3437, + "pression": 3438, + "eps": 3439, + "▁saw": 3440, + "▁across": 3441, + "▁Su": 3442, + "Over": 3443, + "ние": 3444, + "ulation": 3445, + "▁Reg": 3446, + "▁+=": 3447, + "body": 3448, + ")\\": 3449, + "▁print": 3450, + "▁при": 3451, + "db": 3452, + "ources": 3453, + "wards": 3454, + "▁black": 3455, + "со": 3456, + "ili": 3457, + "▁Ed": 3458, + "▁complet": 3459, + "▁single": 3460, + "▁IN": 3461, + "ached": 3462, + "bt": 3463, + "▁code": 3464, + "▁bool": 3465, + "▁area": 3466, + "▁require": 3467, + "▁problem": 3468, + "aced": 3469, + "Equ": 3470, + "▁config": 3471, + "vec": 3472, + "ney": 3473, + "cy": 3474, + "Al": 3475, + "▁account": 3476, + "ymbol": 3477, + "▁ste": 3478, + "ges": 3479, + "Array": 3480, + "empl": 3481, + "context": 3482, + "Des": 3483, + "Result": 3484, + "ecut": 3485, + "▁target": 3486, + "▁getting": 3487, + "\"/>": 3488, + "ogle": 3489, + "▁himself": 3490, + "▁wasn": 3491, + "▁block": 3492, + "▁ant": 3493, + "▁York": 3494, + "▁become": 3495, + "iff": 3496, + "ports": 3497, + "reate": 3498, + "='": 3499, + "cd": 3500, + "location": 3501, + "ет": 3502, + "▁access": 3503, + "gress": 3504, + "ros": 3505, + "Up": 3506, + "▁working": 3507, + "▁Am": 3508, + "iqu": 3509, + "cer": 3510, + "▁((": 3511, + "▁Per": 3512, + "▁func": 3513, + "▁girl": 3514, + "▁above": 3515, + "pen": 3516, + "пи": 3517, + "ido": 3518, + "▁version": 3519, + "TY": 3520, + "▁;": 3521, + "mary": 3522, + "abled": 3523, + "annel": 3524, + "▁example": 3525, + "▁context": 3526, + "OP": 3527, + "▁red": 3528, + "▁cir": 3529, + "sm": 3530, + "Log": 3531, + "▁space": 3532, + "▁fut": 3533, + "▁Gener": 3534, + "ills": 3535, + "▁dri": 3536, + "_.": 3537, + "▁felt": 3538, + "▁offic": 3539, + "▁===": 3540, + "ii": 3541, + "▁started": 3542, + "▁Т": 3543, + "▁});": 3544, + "js": 3545, + "▁front": 3546, + "▁almost": 3547, + "irm": 3548, + "!\"": 3549, + "signed": 3550, + "▁yet": 3551, + "▁trad": 3552, + "ients": 3553, + "ama": 3554, + "▁input": 3555, + "lim": 3556, + "па": 3557, + "▁ка": 3558, + "▁camp": 3559, + "ibr": 3560, + "fect": 3561, + "unt": 3562, + "▁half": 3563, + "▁cover": 3564, + "anguage": 3565, + "▁ben": 3566, + "ha": 3567, + "▁diff": 3568, + "_\\": 3569, + "▁об": 3570, + "])": 3571, + "odes": 3572, + "hel": 3573, + "ios": 3574, + "▁О": 3575, + "▁mot": 3576, + "▁social": 3577, + "////////": 3578, + "▁stre": 3579, + "ground": 3580, + "ів": 3581, + "object": 3582, + "ples": 3583, + "reed": 3584, + "▁een": 3585, + "▁based": 3586, + "▁range": 3587, + "An": 3588, + "urg": 3589, + "▁learn": 3590, + "▁exc": 3591, + "▁imp": 3592, + "▁means": 3593, + "▁wur": 3594, + "ends": 3595, + "void": 3596, + "▁std": 3597, + "▁particular": 3598, + "ja": 3599, + "▁source": 3600, + "default": 3601, + "py": 3602, + "▁als": 3603, + "scri": 3604, + "status": 3605, + "▁story": 3606, + "▁begin": 3607, + "▁position": 3608, + "▁special": 3609, + "php": 3610, + "▁bar": 3611, + "▁pract": 3612, + "call": 3613, + "▁das": 3614, + "▁rad": 3615, + "▁close": 3616, + "www": 3617, + "ере": 3618, + "gu": 3619, + "▁Er": 3620, + "▁dom": 3621, + "AM": 3622, + "▁bed": 3623, + "▁several": 3624, + "aul": 3625, + "box": 3626, + "▁low": 3627, + "pack": 3628, + "Reg": 3629, + "Of": 3630, + "atures": 3631, + "én": 3632, + "eder": 3633, + "uilder": 3634, + "cast": 3635, + "conom": 3636, + "raft": 3637, + "▁makes": 3638, + "Loc": 3639, + "http": 3640, + "▁abs": 3641, + "resh": 3642, + "▁Will": 3643, + "break": 3644, + "▁options": 3645, + "fort": 3646, + "▁из": 3647, + "▁anal": 3648, + "▁env": 3649, + "({": 3650, + "event": 3651, + "▁page": 3652, + "ternal": 3653, + "▁distribut": 3654, + "▁food": 3655, + "check": 3656, + "CK": 3657, + "▁во": 3658, + "assert": 3659, + "án": 3660, + "base": 3661, + "▁whole": 3662, + "ación": 3663, + "OD": 3664, + "▁turned": 3665, + "igma": 3666, + "▁response": 3667, + "▁University": 3668, + "▁div": 3669, + "apter": 3670, + "▁results": 3671, + "▁represent": 3672, + "▁everything": 3673, + "▁Cent": 3674, + "utes": 3675, + "rix": 3676, + "▁Some": 3677, + "▁behind": 3678, + "▁creat": 3679, + "place": 3680, + "su": 3681, + "▁Part": 3682, + "umb": 3683, + "mathbb": 3684, + "ping": 3685, + "▁match": 3686, + "Out": 3687, + "dom": 3688, + "▁situ": 3689, + "dr": 3690, + "ara": 3691, + "▁window": 3692, + "ns": 3693, + "lished": 3694, + "▁Ver": 3695, + "▁message": 3696, + "▁Em": 3697, + "▁human": 3698, + "perties": 3699, + "лу": 3700, + "lem": 3701, + "ORT": 3702, + "▁early": 3703, + "▁quick": 3704, + "▁та": 3705, + "roid": 3706, + "▁country": 3707, + "▁due": 3708, + "▁Die": 3709, + "▁trying": 3710, + "▁live": 3711, + "▁press": 3712, + "INT": 3713, + "With": 3714, + "oved": 3715, + "▁specific": 3716, + "▁fall": 3717, + "uk": 3718, + "yl": 3719, + "▁general": 3720, + "му": 3721, + "ну": 3722, + "▁names": 3723, + "where": 3724, + "▁These": 3725, + "▁sil": 3726, + "ét": 3727, + "▁ener": 3728, + "▁Now": 3729, + "▁address": 3730, + "Response": 3731, + "▁Mr": 3732, + "▁answ": 3733, + "▁film": 3734, + "▁strong": 3735, + "▁bring": 3736, + "▁United": 3737, + "▁ge": 3738, + "▁woman": 3739, + "New": 3740, + "ett": 3741, + ".)": 3742, + "ename": 3743, + "▁AN": 3744, + "▁describ": 3745, + "за": 3746, + "ising": 3747, + "EL": 3748, + "ql": 3749, + "▁fur": 3750, + "ying": 3751, + "▁Cal": 3752, + "▁Dr": 3753, + "ERR": 3754, + "▁\\\\": 3755, + "angle": 3756, + "urope": 3757, + "▁city": 3758, + "▁index": 3759, + "▁action": 3760, + "▁However": 3761, + "▁fig": 3762, + "ias": 3763, + "▁question": 3764, + "▁Jan": 3765, + "▁Med": 3766, + "▁Cont": 3767, + "amed": 3768, + "Call": 3769, + "plied": 3770, + "tty": 3771, + "▁individ": 3772, + "page": 3773, + "▁comb": 3774, + "section": 3775, + "▁Comm": 3776, + "uel": 3777, + "▁het": 3778, + "▁Bar": 3779, + "agement": 3780, + "fin": 3781, + "▁major": 3782, + "oper": 3783, + "api": 3784, + "room": 3785, + "▁„": 3786, + "▁hab": 3787, + "зи": 3788, + "▁auf": 3789, + "current": 3790, + "ni": 3791, + "▁include": 3792, + "▁qui": 3793, + "va": 3794, + "UE": 3795, + "▁idea": 3796, + ",'": 3797, + "▁required": 3798, + "▁heart": 3799, + "ibility": 3800, + "iction": 3801, + "Model": 3802, + "write": 3803, + "▁content": 3804, + "▁wer": 3805, + "▁hands": 3806, + "zen": 3807, + "char": 3808, + "}^{": 3809, + "▁mass": 3810, + "ply": 3811, + "▁nat": 3812, + "rel": 3813, + "▁dat": 3814, + "================": 3815, + "imal": 3816, + "▁probably": 3817, + "unch": 3818, + "▁mer": 3819, + "ilar": 3820, + "ires": 3821, + "▁watch": 3822, + "SI": 3823, + "▁cult": 3824, + "▁mother": 3825, + "▁government": 3826, + "ording": 3827, + "▁()": 3828, + "▁pri": 3829, + "▁link": 3830, + "group": 3831, + "OL": 3832, + "▁near": 3833, + "▁Ser": 3834, + "Ser": 3835, + "ito": 3836, + "▁values": 3837, + "▁java": 3838, + "fully": 3839, + "Count": 3840, + "++)": 3841, + "▁vi": 3842, + "▁white": 3843, + "mat": 3844, + "ctx": 3845, + "▁conc": 3846, + "▁stay": 3847, + "ging": 3848, + "▁clear": 3849, + "▁copy": 3850, + "selves": 3851, + "▁provide": 3852, + "▁words": 3853, + "comp": 3854, + "args": 3855, + "▁pick": 3856, + "uly": 3857, + "▁vari": 3858, + "▁believe": 3859, + "▁Co": 3860, + "Property": 3861, + "Group": 3862, + "▁ten": 3863, + "ischen": 3864, + "eturn": 3865, + "ival": 3866, + "System": 3867, + "CL": 3868, + "bed": 3869, + "▁total": 3870, + "▁ist": 3871, + "Input": 3872, + "uments": 3873, + "Manager": 3874, + "ши": 3875, + "▁win": 3876, + "leep": 3877, + "PI": 3878, + "ного": 3879, + "ruction": 3880, + "▁inte": 3881, + "App": 3882, + "avor": 3883, + "▁respect": 3884, + "ators": 3885, + "▁como": 3886, + "▁cut": 3887, + "FA": 3888, + "▁sus": 3889, + "▁App": 3890, + "rect": 3891, + "FI": 3892, + "▁began": 3893, + "oph": 3894, + "▁sort": 3895, + "though": 3896, + "је": 3897, + "icro": 3898, + "Trans": 3899, + "лі": 3900, + "▁Inst": 3901, + "request": 3902, + "ор": 3903, + "▁relations": 3904, + "-\\": 3905, + "Status": 3906, + "жи": 3907, + "▁father": 3908, + "cs": 3909, + "▁sex": 3910, + "isch": 3911, + "vo": 3912, + "}_{": 3913, + "aven": 3914, + "▁Ne": 3915, + "ATE": 3916, + "itten": 3917, + "▁ess": 3918, + "TH": 3919, + "ights": 3920, + "▁hom": 3921, + "▁today": 3922, + "▁zu": 3923, + "ita": 3924, + "▁isn": 3925, + "▁opt": 3926, + "ogn": 3927, + "ér": 3928, + "▁whether": 3929, + "ixed": 3930, + "phi": 3931, + "idence": 3932, + "ald": 3933, + "Client": 3934, + "At": 3935, + "▁death": 3936, + "▁Let": 3937, + "ius": 3938, + "ги": 3939, + "▁ре": 3940, + "ben": 3941, + ")\r": 3942, + "ba": 3943, + ">": 3961, + "▁Just": 3962, + "What": 3963, + "atal": 3964, + "▁Min": 3965, + "▁Cor": 3966, + "▁dark": 3967, + "rl": 3968, + "▁larg": 3969, + "ding": 3970, + "ón": 3971, + "ouch": 3972, + "▁um": 3973, + "▁elect": 3974, + "▁dam": 3975, + "▁needs": 3976, + "▁matter": 3977, + "▁rather": 3978, + "from": 3979, + "ram": 3980, + "▁і": 3981, + "▁taken": 3982, + "▁deal": 3983, + "▁period": 3984, + "▁Mon": 3985, + "▁Л": 3986, + "▁Aug": 3987, + "run": 3988, + "mm": 3989, + "elle": 3990, + "▁export": 3991, + "Sc": 3992, + "vis": 3993, + "abor": 3994, + "▁author": 3995, + "ère": 3996, + "▁remember": 3997, + "▁redu": 3998, + "▁List": 3999, + "▁focus": 4000, + "▁character": 4001, + "Table": 4002, + "▁individual": 4003, + "▁needed": 4004, + "bum": 4005, + "▁style": 4006, + "inary": 4007, + "ersion": 4008, + "oute": 4009, + "▁Pe": 4010, + "▁hon": 4011, + "mut": 4012, + "see": 4013, + "▁became": 4014, + "▁dire": 4015, + "▁document": 4016, + "sec": 4017, + "ening": 4018, + "▁visit": 4019, + "▁fac": 4020, + "tx": 4021, + "down": 4022, + "plit": 4023, + "▁phys": 4024, + "itting": 4025, + "joy": 4026, + "▁hig": 4027, + "This": 4028, + "Ad": 4029, + "▁Brit": 4030, + "▁employ": 4031, + "▁ré": 4032, + "▁т": 4033, + "lambda": 4034, + "▁impro": 4035, + "▁Bo": 4036, + "iding": 4037, + "▁online": 4038, + "mem": 4039, + "atform": 4040, + "▁War": 4041, + "▁cas": 4042, + "asure": 4043, + "▁pur": 4044, + "medi": 4045, + "Dis": 4046, + "▁Germ": 4047, + "pc": 4048, + "са": 4049, + "▁friends": 4050, + "▁Mc": 4051, + "DI": 4052, + "▁plus": 4053, + "▁Set": 4054, + "iddle": 4055, + "itut": 4056, + "▁depend": 4057, + "rest": 4058, + "▁Je": 4059, + "▁hor": 4060, + "▁entire": 4061, + "Query": 4062, + "▁refer": 4063, + "▁hot": 4064, + "▁Aust": 4065, + "▁common": 4066, + "ці": 4067, + "▁pull": 4068, + "▁Add": 4069, + "▁season": 4070, + "▁invol": 4071, + "▁World": 4072, + "client": 4073, + "now": 4074, + "true": 4075, + "append": 4076, + "itted": 4077, + "empt": 4078, + "){": 4079, + "///": 4080, + "▁prop": 4081, + "imate": 4082, + "SC": 4083, + "▁hours": 4084, + "▁hope": 4085, + "andom": 4086, + "ід": 4087, + "istic": 4088, + "▁property": 4089, + "sg": 4090, + ">(": 4091, + "▁write": 4092, + "mark": 4093, + "find": 4094, + "▁personal": 4095, + "][": 4096, + "rown": 4097, + "Ph": 4098, + "▁foot": 4099, + "▁research": 4100, + "ironment": 4101, + "▁nom": 4102, + "▁instance": 4103, + "▁held": 4104, + "De": 4105, + "▁members": 4106, + "▁fire": 4107, + "▁history": 4108, + "▁map": 4109, + "▁discuss": 4110, + "▁espec": 4111, + "▁taking": 4112, + "▁services": 4113, + "▁indust": 4114, + "igen": 4115, + "▁Ass": 4116, + "▁expected": 4117, + "▁wurde": 4118, + "dir": 4119, + "▁among": 4120, + "▁sugg": 4121, + "rec": 4122, + "Inter": 4123, + "block": 4124, + "▁Rep": 4125, + "▁pain": 4126, + "▁five": 4127, + "▁fund": 4128, + "rid": 4129, + "arrow": 4130, + "▁treat": 4131, + "▁heard": 4132, + "▁determ": 4133, + "icult": 4134, + "▁sense": 4135, + "ese": 4136, + "Fun": 4137, + "▁months": 4138, + "json": 4139, + ",”": 4140, + "TI": 4141, + "orage": 4142, + "▁У": 4143, + "▁everyone": 4144, + "▁clos": 4145, + "iers": 4146, + "airs": 4147, + "define": 4148, + "If": 4149, + "osp": 4150, + "▁wonder": 4151, + "NA": 4152, + "query": 4153, + "pg": 4154, + "ites": 4155, + "▁material": 4156, + "yd": 4157, + "Read": 4158, + "html": 4159, + "TE": 4160, + "Pr": 4161, + "^{\\": 4162, + "▁gave": 4163, + "▁IS": 4164, + "▁suggest": 4165, + "Override": 4166, + "rodu": 4167, + "From": 4168, + "▁Europe": 4169, + "PO": 4170, + "▁soon": 4171, + "host": 4172, + "▁Ber": 4173, + "....": 4174, + "▁Har": 4175, + "▁energy": 4176, + "><": 4177, + "aves": 4178, + "▁easy": 4179, + "▁bre": 4180, + "frame": 4181, + "▁ground": 4182, + "with": 4183, + "▁inside": 4184, + "ief": 4185, + "▁mo": 4186, + "pm": 4187, + "pan": 4188, + "igr": 4189, + "▁om": 4190, + "next": 4191, + "omet": 4192, + "▁status": 4193, + "▁}\r": 4194, + "▁music": 4195, + "ora": 4196, + "iles": 4197, + "ki": 4198, + "▁esc": 4199, + "▁bes": 4200, + "▁Dis": 4201, + "▁host": 4202, + "▁comes": 4203, + "used": 4204, + "▁future": 4205, + "lick": 4206, + "aid": 4207, + "▁compet": 4208, + "▁voice": 4209, + "▁load": 4210, + "evel": 4211, + "▁neg": 4212, + "▁command": 4213, + "▁für": 4214, + "▁pie": 4215, + "▁quite": 4216, + "▁blo": 4217, + "agn": 4218, + "ilon": 4219, + "▁claim": 4220, + "▁teach": 4221, + "▁previous": 4222, + "▁site": 4223, + "color": 4224, + "attr": 4225, + "▁accept": 4226, + "▁exact": 4227, + ")}": 4228, + "aft": 4229, + "roller": 4230, + "он": 4231, + "oo": 4232, + "Date": 4233, + "▁ou": 4234, + "sy": 4235, + "▁pretty": 4236, + "▁image": 4237, + "BU": 4238, + "▁terms": 4239, + "▁search": 4240, + "▁è": 4241, + "▁Val": 4242, + "▁‘": 4243, + "▁Dav": 4244, + "MS": 4245, + "src": 4246, + "mar": 4247, + "incip": 4248, + "▁couldn": 4249, + "ados": 4250, + "▁dro": 4251, + "beta": 4252, + "imum": 4253, + "▁minutes": 4254, + "▁grand": 4255, + "▁»": 4256, + "▁Our": 4257, + "Str": 4258, + "VER": 4259, + "maz": 4260, + "▁original": 4261, + "ini": 4262, + "▁coll": 4263, + "loat": 4264, + "▁os": 4265, + "});": 4266, + "summary": 4267, + "▁wall": 4268, + "Color": 4269, + "▁vers": 4270, + "▁della": 4271, + "▁\"\"\"": 4272, + "mathbf": 4273, + "zer": 4274, + "aur": 4275, + "▁track": 4276, + "▁associ": 4277, + "▁suff": 4278, + "▁inde": 4279, + "ague": 4280, + "▁Apr": 4281, + "Le": 4282, + "roups": 4283, + "board": 4284, + "▁attack": 4285, + "▁series": 4286, + "▁instead": 4287, + "ham": 4288, + "book": 4289, + "▁six": 4290, + "▁Rec": 4291, + "▁coming": 4292, + "urt": 4293, + "▁global": 4294, + "▁necess": 4295, + "lege": 4296, + "Pos": 4297, + "▁leave": 4298, + "▁pod": 4299, + "ategory": 4300, + "uz": 4301, + "▁deep": 4302, + "▁km": 4303, + "▁outside": 4304, + "has": 4305, + "options": 4306, + "▁Sm": 4307, + "Sub": 4308, + "rows": 4309, + "▁ви": 4310, + "▁States": 4311, + "▁wrong": 4312, + "▁however": 4313, + "▁sem": 4314, + "▁catch": 4315, + "\"),": 4316, + "model": 4317, + "▁http": 4318, + "▁option": 4319, + "rie": 4320, + "▁ста": 4321, + "▁är": 4322, + "▁enjoy": 4323, + "nu": 4324, + "▁pas": 4325, + "▁amount": 4326, + "▁respons": 4327, + "▁Intern": 4328, + "▁myself": 4329, + "▁opp": 4330, + "▁Sim": 4331, + "▁sens": 4332, + "Ed": 4333, + "▁(\\": 4334, + "▁students": 4335, + "нов": 4336, + "▁points": 4337, + "arning": 4338, + "UP": 4339, + "elling": 4340, + "▁cannot": 4341, + "Be": 4342, + "▁length": 4343, + "null": 4344, + "uint": 4345, + "wise": 4346, + "▁double": 4347, + "ige": 4348, + "ista": 4349, + "▁estab": 4350, + "anch": 4351, + "▁ago": 4352, + "▁bound": 4353, + "▁fa": 4354, + "▁clean": 4355, + "▁simple": 4356, + "mi": 4357, + "########": 4358, + "ifier": 4359, + "▁General": 4360, + "▁seemed": 4361, + "ena": 4362, + "▁age": 4363, + "ной": 4364, + "endif": 4365, + "AA": 4366, + "▁caus": 4367, + "▁educ": 4368, + "▁cell": 4369, + "Gener": 4370, + "space": 4371, + "▁Your": 4372, + "▁beaut": 4373, + "gt": 4374, + "▁limit": 4375, + "▁date": 4376, + "Util": 4377, + "▁National": 4378, + "ows": 4379, + "pat": 4380, + "quad": 4381, + "▁ok": 4382, + "▁И": 4383, + "arth": 4384, + "hat": 4385, + "▁community": 4386, + "oul": 4387, + "▁econom": 4388, + "Component": 4389, + "bor": 4390, + "usion": 4391, + "▁below": 4392, + "earch": 4393, + "ores": 4394, + "ban": 4395, + "▁August": 4396, + "▁further": 4397, + "sigma": 4398, + "▁ha": 4399, + "ji": 4400, + "▁comput": 4401, + "гра": 4402, + "▁None": 4403, + "▁ter": 4404, + "▁anyone": 4405, + "▁task": 4406, + "ente": 4407, + "position": 4408, + "pped": 4409, + "▁aus": 4410, + "Attribute": 4411, + "req": 4412, + "addr": 4413, + "light": 4414, + "ше": 4415, + "▁arm": 4416, + "cover": 4417, + "upport": 4418, + "▁Gl": 4419, + "▁San": 4420, + "▁writing": 4421, + "▁lost": 4422, + "▁Mark": 4423, + "▁gre": 4424, + "TYPE": 4425, + "▁South": 4426, + "▁perfect": 4427, + "▁package": 4428, + "▁infl": 4429, + "haps": 4430, + "▁Ang": 4431, + "respon": 4432, + "ris": 4433, + "ptember": 4434, + "▁building": 4435, + "VAL": 4436, + "free": 4437, + "▁ce": 4438, + "HT": 4439, + "▁From": 4440, + "ds": 4441, + "roy": 4442, + "achine": 4443, + "nown": 4444, + "▁saying": 4445, + "▁бы": 4446, + "oe": 4447, + "Ref": 4448, + "▁network": 4449, + "parent": 4450, + "uge": 4451, + "▁similar": 4452, + ">\r": 4453, + "Builder": 4454, + "▁living": 4455, + "▁continue": 4456, + "anger": 4457, + "▁Red": 4458, + "▁hair": 4459, + "anced": 4460, + "ians": 4461, + "▁dead": 4462, + "▁boolean": 4463, + "ication": 4464, + "▁де": 4465, + "▁client": 4466, + "uct": 4467, + "▁•": 4468, + "SP": 4469, + "older": 4470, + "пе": 4471, + "udio": 4472, + "▁deg": 4473, + "asing": 4474, + "▁step": 4475, + "▁pers": 4476, + "ção": 4477, + "obj": 4478, + "oz": 4479, + "ula": 4480, + "▁round": 4481, + "▁upon": 4482, + "▁resource": 4483, + "▁valid": 4484, + "▁II": 4485, + "bug": 4486, + "std": 4487, + "▁ang": 4488, + "span": 4489, + "pol": 4490, + "ialog": 4491, + "▁phot": 4492, + "?'": 4493, + "DB": 4494, + "▁Fin": 4495, + "VE": 4496, + "Em": 4497, + "▁cam": 4498, + "target": 4499, + "pected": 4500, + "Hel": 4501, + "▁ut": 4502, + "▁Test": 4503, + "▁town": 4504, + "align": 4505, + "▁webs": 4506, + "inner": 4507, + "augh": 4508, + "▁except": 4509, + "▁initial": 4510, + "enty": 4511, + "lich": 4512, + "▁Aut": 4513, + "top": 4514, + "▁fail": 4515, + "ona": 4516, + "▁benef": 4517, + "anks": 4518, + "ische": 4519, + ".*": 4520, + "▁signific": 4521, + "▁contact": 4522, + "Rec": 4523, + "ario": 4524, + "ottom": 4525, + "▁relationship": 4526, + "]);": 4527, + "▁На": 4528, + "Head": 4529, + "format": 4530, + "▁ét": 4531, + "▁More": 4532, + "actory": 4533, + "portun": 4534, + "+\\": 4535, + "▁simply": 4536, + "▁ep": 4537, + "▁Russ": 4538, + "ní": 4539, + "ua": 4540, + "erc": 4541, + "▁longer": 4542, + "inition": 4543, + "ector": 4544, + "aption": 4545, + "▁profess": 4546, + "▁Mus": 4547, + "ilities": 4548, + "ès": 4549, + "▁Act": 4550, + "offset": 4551, + "▁ill": 4552, + "band": 4553, + "▁Ag": 4554, + "▁По": 4555, + "би": 4556, + "content": 4557, + "icon": 4558, + "▁works": 4559, + "ynam": 4560, + "plement": 4561, + "Resource": 4562, + "Action": 4563, + "▁difficult": 4564, + "▁West": 4565, + "▁video": 4566, + "▁THE": 4567, + "▁decl": 4568, + "ondon": 4569, + "ded": 4570, + "}{\\": 4571, + "ocr": 4572, + "▁City": 4573, + "▁я": 4574, + "uer": 4575, + "cz": 4576, + "▁imag": 4577, + "cr": 4578, + "ete": 4579, + "idget": 4580, + "▁Mod": 4581, + "▁forward": 4582, + "▁pict": 4583, + "orge": 4584, + "▁subject": 4585, + "update": 4586, + "attle": 4587, + "sa": 4588, + "▁Ant": 4589, + "▁running": 4590, + "▁sal": 4591, + "conne": 4592, + "▁output": 4593, + "adata": 4594, + "ML": 4595, + "Check": 4596, + "ledge": 4597, + "▁paper": 4598, + "params": 4599, + "avy": 4600, + "▁af": 4601, + "▁eine": 4602, + "▁jour": 4603, + "AY": 4604, + "▁itself": 4605, + "▁Str": 4606, + "style": 4607, + "That": 4608, + "▁million": 4609, + "▁language": 4610, + "OS": 4611, + "ving": 4612, + "▁ма": 4613, + "▁то": 4614, + ")(": 4615, + "▁buy": 4616, + "./": 4617, + "▁...": 4618, + "▁tried": 4619, + "▁compl": 4620, + "▁activ": 4621, + "apped": 4622, + "Button": 4623, + "Token": 4624, + "▁provided": 4625, + "iber": 4626, + "▁created": 4627, + "curity": 4628, + "End": 4629, + "ał": 4630, + "uster": 4631, + "izing": 4632, + "omb": 4633, + "▁sich": 4634, + "▁compon": 4635, + "▁See": 4636, + "▁uint": 4637, + "▁label": 4638, + "vol": 4639, + "ów": 4640, + "ocol": 4641, + "▁received": 4642, + "▁intern": 4643, + "це": 4644, + "Run": 4645, + "▁road": 4646, + "▁Oct": 4647, + "▁Comp": 4648, + "▁study": 4649, + "▁те": 4650, + "Act": 4651, + "▁tour": 4652, + "▁State": 4653, + "▁added": 4654, + "https": 4655, + "stream": 4656, + "▁lower": 4657, + "▁box": 4658, + "▁Sk": 4659, + "▁themselves": 4660, + "▁cross": 4661, + "▁echo": 4662, + "▁device": 4663, + "pose": 4664, + "▁games": 4665, + "PL": 4666, + "Window": 4667, + "ises": 4668, + "title": 4669, + "Stream": 4670, + "zt": 4671, + "▁Sw": 4672, + "▁role": 4673, + "iant": 4674, + "ku": 4675, + "sequ": 4676, + "▁late": 4677, + "▁sold": 4678, + "ря": 4679, + "Comm": 4680, + "▁entre": 4681, + "▁dog": 4682, + "device": 4683, + "Par": 4684, + "▁likely": 4685, + "^{-": 4686, + "▁len": 4687, + "▁Paul": 4688, + "▁tool": 4689, + "Off": 4690, + "▁famil": 4691, + "▁draw": 4692, + "apping": 4693, + "▁events": 4694, + "cret": 4695, + "rought": 4696, + "Content": 4697, + "▁software": 4698, + "ria": 4699, + "msg": 4700, + "gamma": 4701, + "▁hear": 4702, + "Oper": 4703, + "▁yourself": 4704, + "▁liter": 4705, + "emp": 4706, + "▁separ": 4707, + "▁З": 4708, + "▁title": 4709, + "Method": 4710, + "mathrm": 4711, + "▁slow": 4712, + "▁Rom": 4713, + "!!": 4714, + "▁tax": 4715, + "ска": 4716, + "emplate": 4717, + "oi": 4718, + "▁Art": 4719, + "false": 4720, + "astic": 4721, + "сть": 4722, + "ocket": 4723, + "▁ens": 4724, + "TO": 4725, + "amente": 4726, + "local": 4727, + "chie": 4728, + "▁pan": 4729, + "ний": 4730, + "chema": 4731, + "▁North": 4732, + "зо": 4733, + "▁>=": 4734, + "Aut": 4735, + "▁dig": 4736, + "▁seems": 4737, + "▁morning": 4738, + "sole": 4739, + "umer": 4740, + "delta": 4741, + "ité": 4742, + "abase": 4743, + "raf": 4744, + "▁observ": 4745, + "▁Est": 4746, + "▁seg": 4747, + "▁[]": 4748, + "▁Pres": 4749, + "iful": 4750, + "push": 4751, + "▁Off": 4752, + "ipe": 4753, + "ati": 4754, + "▁dim": 4755, + "ceed": 4756, + "Ent": 4757, + "____": 4758, + "entry": 4759, + "▁fight": 4760, + "▁cred": 4761, + "▁OR": 4762, + "▁Dep": 4763, + "${": 4764, + "лен": 4765, + "Create": 4766, + "▁April": 4767, + "ministr": 4768, + "FL": 4769, + "▁Ap": 4770, + "▁Here": 4771, + "private": 4772, + "Instance": 4773, + "iem": 4774, + "▁office": 4775, + "▁third": 4776, + "▁update": 4777, + "Line": 4778, + "tag": 4779, + "▁especially": 4780, + "▁года": 4781, + "▁cu": 4782, + "▁kill": 4783, + "aught": 4784, + "▁swe": 4785, + "Options": 4786, + "IM": 4787, + "CC": 4788, + "▁compan": 4789, + "just": 4790, + "▁While": 4791, + "izer": 4792, + "▁мо": 4793, + "ке": 4794, + "▁auto": 4795, + "▁band": 4796, + "мен": 4797, + "iques": 4798, + "▁ple": 4799, + "NO": 4800, + "▁OF": 4801, + "▁song": 4802, + "▁Acc": 4803, + "EXT": 4804, + "ensor": 4805, + "ining": 4806, + "▁lat": 4807, + "big": 4808, + "▁King": 4809, + "och": 4810, + "si": 4811, + "▁Hist": 4812, + "▁quality": 4813, + "mode": 4814, + "▁opportun": 4815, + "▁wouldn": 4816, + ":**": 4817, + "output": 4818, + "▁feet": 4819, + "▁mis": 4820, + "df": 4821, + "aging": 4822, + "▁ме": 4823, + "▁tro": 4824, + "▁defined": 4825, + "▁review": 4826, + "▁Fil": 4827, + ">>": 4828, + "▁princip": 4829, + "Base": 4830, + "dict": 4831, + "verage": 4832, + "icient": 4833, + "IF": 4834, + "▁hit": 4835, + "Page": 4836, + "▁perm": 4837, + "cel": 4838, + "ít": 4839, + "▁express": 4840, + "▁indic": 4841, + "▁September": 4842, + "image": 4843, + "▁products": 4844, + "▁media": 4845, + "change": 4846, + "igger": 4847, + "▁send": 4848, + "last": 4849, + "ming": 4850, + "pa": 4851, + "uary": 4852, + "▁speak": 4853, + "ный": 4854, + "ще": 4855, + "ysis": 4856, + "lying": 4857, + "▁ч": 4858, + "like": 4859, + "ры": 4860, + "ві": 4861, + "▁Mich": 4862, + "MO": 4863, + "▁Jah": 4864, + "ensive": 4865, + "▁share": 4866, + "▁development": 4867, + "CP": 4868, + "spec": 4869, + "▁fast": 4870, + "het": 4871, + "HO": 4872, + "▁particip": 4873, + "Block": 4874, + "▁viol": 4875, + "▁frame": 4876, + "▁qual": 4877, + "tre": 4878, + "▁Ф": 4879, + "▁toward": 4880, + "fg": 4881, + "Box": 4882, + "Column": 4883, + "▁milit": 4884, + "▁March": 4885, + "▁various": 4886, + "pass": 4887, + "▁Park": 4888, + "▁Ben": 4889, + "Frame": 4890, + "▁normal": 4891, + "open": 4892, + "px": 4893, + "▁phone": 4894, + "▁Even": 4895, + "▁ma": 4896, + "ibrary": 4897, + "Start": 4898, + "idden": 4899, + "rho": 4900, + "graph": 4901, + "acing": 4902, + "'.": 4903, + "arter": 4904, + "mes": 4905, + "inst": 4906, + "▁ir": 4907, + "active": 4908, + "▁fem": 4909, + "▁moved": 4910, + "▁store": 4911, + "▁price": 4912, + "\").": 4913, + "berg": 4914, + "▁nov": 4915, + "▁card": 4916, + "ellow": 4917, + "▁party": 4918, + "▁Mor": 4919, + "ael": 4920, + "▁percent": 4921, + "▁training": 4922, + "▁ing": 4923, + "imer": 4924, + "▁Sam": 4925, + "Default": 4926, + "▁fuck": 4927, + "▁complete": 4928, + "uid": 4929, + "▁details": 4930, + "▁led": 4931, + "Point": 4932, + "▁Count": 4933, + "▁regard": 4934, + "zo": 4935, + "▁Bro": 4936, + "▁recogn": 4937, + "▁Hol": 4938, + "UM": 4939, + "element": 4940, + "Mode": 4941, + "▁exam": 4942, + "▁EX": 4943, + "Image": 4944, + "verse": 4945, + "riter": 4946, + "soft": 4947, + "▁introdu": 4948, + "▁surpr": 4949, + "Buffer": 4950, + "lector": 4951, + "aren": 4952, + "anged": 4953, + "▁Pat": 4954, + "▁Pal": 4955, + "▁contr": 4956, + "Handler": 4957, + "▁features": 4958, + "iple": 4959, + "▁CON": 4960, + "Fil": 4961, + "▁Port": 4962, + "▁thinking": 4963, + "doc": 4964, + "wer": 4965, + "▁worked": 4966, + "PC": 4967, + "cm": 4968, + "dat": 4969, + "PRO": 4970, + "▁Every": 4971, + "▁era": 4972, + "▁First": 4973, + "gn": 4974, + "▁immedi": 4975, + "ovember": 4976, + "apan": 4977, + "▁extra": 4978, + "▁section": 4979, + "▁June": 4980, + "▁via": 4981, + "▁gone": 4982, + "come": 4983, + "▁stri": 4984, + "^\\": 4985, + "antly": 4986, + "▁arch": 4987, + "Source": 4988, + "▁conv": 4989, + "▁London": 4990, + "Number": 4991, + "▁questions": 4992, + "andid": 4993, + "▁played": 4994, + "env": 4995, + "▁School": 4996, + "▁natural": 4997, + "can": 4998, + "▁news": 4999, + "DR": 5000, + "▁chall": 5001, + "▁Soc": 5002, + "▁э": 5003, + "▁attempt": 5004, + "*}": 5005, + "Null": 5006, + "rote": 5007, + "▁bi": 5008, + "▁written": 5009, + "▁blood": 5010, + "▁happened": 5011, + "▁cause": 5012, + "ashing": 5013, + "▁William": 5014, + "adem": 5015, + "▁brought": 5016, + "▁display": 5017, + "ima": 5018, + "▁finally": 5019, + "tab": 5020, + "▁returned": 5021, + "ных": 5022, + "nie": 5023, + "▁q": 5024, + "▁hers": 5025, + "▁Pre": 5026, + "▁dou": 5027, + "buffer": 5028, + "▁effort": 5029, + "aine": 5030, + "xy": 5031, + "▁histor": 5032, + "enu": 5033, + "▁arriv": 5034, + "▁Dem": 5035, + "▁favor": 5036, + "▁handle": 5037, + "SET": 5038, + "▁Public": 5039, + "rupt": 5040, + "▁ur": 5041, + "▁force": 5042, + "▁és": 5043, + "ube": 5044, + "Pre": 5045, + "рі": 5046, + "iny": 5047, + "theta": 5048, + "isf": 5049, + "▁national": 5050, + "Equal": 5051, + "rench": 5052, + "▁wife": 5053, + "▁capt": 5054, + "▁Inter": 5055, + "tau": 5056, + "▁sleep": 5057, + "../../": 5058, + "▁issue": 5059, + "▁member": 5060, + "▁await": 5061, + "▁Dan": 5062, + "zi": 5063, + "inate": 5064, + "▁sym": 5065, + "chan": 5066, + "▁Jack": 5067, + "▁English": 5068, + "▁sz": 5069, + "ributes": 5070, + "▁ign": 5071, + "ál": 5072, + "▁appear": 5073, + "rad": 5074, + "idge": 5075, + "▁couple": 5076, + "▁ship": 5077, + "lig": 5078, + "web": 5079, + "▁usually": 5080, + "▁ready": 5081, + "▁vill": 5082, + "▁Why": 5083, + "ebru": 5084, + "▁grad": 5085, + "ords": 5086, + "▁inf": 5087, + "▁loss": 5088, + "▁od": 5089, + "▁Phil": 5090, + "server": 5091, + "▁Up": 5092, + "▁buff": 5093, + "▁filename": 5094, + "ABLE": 5095, + "iting": 5096, + "efore": 5097, + "()->": 5098, + "▁conditions": 5099, + "vm": 5100, + "eld": 5101, + "itz": 5102, + "▁Trans": 5103, + "▁weight": 5104, + "▁higher": 5105, + "▁rate": 5106, + "▁accom": 5107, + "vider": 5108, + "OM": 5109, + "▁ways": 5110, + "coming": 5111, + "▁lock": 5112, + "▁etc": 5113, + "▁avec": 5114, + "▁takes": 5115, + "▁Char": 5116, + "▁November": 5117, + "method": 5118, + "▁Austral": 5119, + "▁America": 5120, + "long": 5121, + "cember": 5122, + "▁political": 5123, + "flow": 5124, + "▁maybe": 5125, + "▁amb": 5126, + "Layout": 5127, + "iled": 5128, + "omen": 5129, + "ola": 5130, + "icip": 5131, + "partial": 5132, + "True": 5133, + "▁floor": 5134, + "▁Def": 5135, + "▁concern": 5136, + "yr": 5137, + "▁shows": 5138, + "ih": 5139, + "▁answer": 5140, + "acc": 5141, + "▁ball": 5142, + "▁Rev": 5143, + "▁sun": 5144, + "▁quickly": 5145, + "▁somet": 5146, + "mente": 5147, + "▁Mal": 5148, + "undred": 5149, + "▁issues": 5150, + "ecause": 5151, + "pes": 5152, + "▁player": 5153, + "▁parents": 5154, + "▁popular": 5155, + "▁mode": 5156, + "▁mention": 5157, + "NE": 5158, + "Load": 5159, + "▁regular": 5160, + "aved": 5161, + "?:": 5162, + "year": 5163, + "func": 5164, + "▁performance": 5165, + "▁July": 5166, + "thern": 5167, + "▁website": 5168, + "ford": 5169, + "PR": 5170, + "ela": 5171, + "level": 5172, + "uit": 5173, + "flags": 5174, + "▁worth": 5175, + "▁correspon": 5176, + "▁British": 5177, + "sim": 5178, + "▁alone": 5179, + "▁har": 5180, + "▁ones": 5181, + "obile": 5182, + "▁dru": 5183, + "chi": 5184, + "▁David": 5185, + "▁problems": 5186, + "▁column": 5187, + "();\r": 5188, + "ZE": 5189, + "▁relig": 5190, + "ological": 5191, + "▁region": 5192, + "ady": 5193, + "IO": 5194, + "ander": 5195, + "Net": 5196, + "▁built": 5197, + "▁install": 5198, + "▁approach": 5199, + "Cur": 5200, + "▁fine": 5201, + "▁talking": 5202, + "▁changes": 5203, + "Style": 5204, + "▁Mart": 5205, + "лю": 5206, + "response": 5207, + "teger": 5208, + "{\r": 5209, + "irit": 5210, + "▁protected": 5211, + "▁rele": 5212, + "ership": 5213, + "тель": 5214, + "unsigned": 5215, + "ialize": 5216, + "▁https": 5217, + "Tag": 5218, + "▁$(": 5219, + "more": 5220, + "ypes": 5221, + "▁stream": 5222, + "etch": 5223, + "▁engine": 5224, + "KE": 5225, + "cmd": 5226, + "script": 5227, + "ttp": 5228, + "▁avoid": 5229, + "▁terr": 5230, + "▁rock": 5231, + "▁ful": 5232, + "Update": 5233, + "▁environment": 5234, + "▁prec": 5235, + "▁са": 5236, + "▁cases": 5237, + "▁offset": 5238, + "▁rais": 5239, + "lib": 5240, + "ées": 5241, + "aa": 5242, + "yt": 5243, + "▁arr": 5244, + "opyright": 5245, + "first": 5246, + "▁util": 5247, + "▁feature": 5248, + "posed": 5249, + "ffect": 5250, + "жа": 5251, + "itude": 5252, + "ements": 5253, + "asc": 5254, + "ador": 5255, + "lections": 5256, + "▁club": 5257, + "]{": 5258, + "▁*)": 5259, + "ство": 5260, + "▁imm": 5261, + "▁former": 5262, + "▁rights": 5263, + "▁decided": 5264, + "▁rev": 5265, + "▁ment": 5266, + "ani": 5267, + "▁stru": 5268, + "▁attention": 5269, + "artment": 5270, + "▁Ital": 5271, + "alle": 5272, + "▁bis": 5273, + "gener": 5274, + "▁integr": 5275, + "ello": 5276, + "rypt": 5277, + "▁achie": 5278, + "nes": 5279, + "▁stra": 5280, + "sb": 5281, + "▁types": 5282, + "▁RE": 5283, + "Init": 5284, + "▁comment": 5285, + "▁addition": 5286, + "▁ID": 5287, + "ART": 5288, + "FO": 5289, + "щи": 5290, + "Conne": 5291, + "▁squ": 5292, + "▁considered": 5293, + "idad": 5294, + "▁October": 5295, + "cial": 5296, + "▁Of": 5297, + "▁travel": 5298, + "▁boy": 5299, + "').": 5300, + "uy": 5301, + "illa": 5302, + "istry": 5303, + "▁va": 5304, + "▁Che": 5305, + "ERT": 5306, + "ende": 5307, + "ungen": 5308, + "aby": 5309, + "▁Rober": 5310, + "▁playing": 5311, + "ils": 5312, + "▁sam": 5313, + "▁execut": 5314, + "▁Us": 5315, + "▁mut": 5316, + "▁bal": 5317, + "asse": 5318, + "▁kids": 5319, + "▁financ": 5320, + "gor": 5321, + "▁Sec": 5322, + "bert": 5323, + "▁High": 5324, + "▁је": 5325, + "▁kept": 5326, + "button": 5327, + "itory": 5328, + "▁Rem": 5329, + "▁DE": 5330, + "▁reach": 5331, + "▁bur": 5332, + "Label": 5333, + "át": 5334, + "ago": 5335, + "▁passed": 5336, + "▁behav": 5337, + "xFF": 5338, + "▁Return": 5339, + "STR": 5340, + "▁Les": 5341, + "▁ord": 5342, + "ala": 5343, + "inger": 5344, + "▁Since": 5345, + "▁experi": 5346, + "▁shall": 5347, + "▁star": 5348, + "non": 5349, + "▁gun": 5350, + "▁Bel": 5351, + "▁obj": 5352, + "ares": 5353, + "rs": 5354, + "▁weeks": 5355, + "nen": 5356, + "▁Stre": 5357, + "oring": 5358, + "▁î": 5359, + "▁serious": 5360, + "times": 5361, + "▁House": 5362, + "▁roll": 5363, + "▁register": 5364, + "▁module": 5365, + "▁applic": 5366, + "IR": 5367, + "▁cook": 5368, + "aux": 5369, + "▁save": 5370, + "▁Cr": 5371, + ",\r": 5372, + "▁states": 5373, + "▁empty": 5374, + "▁autom": 5375, + "figure": 5376, + "iance": 5377, + "▁happy": 5378, + "▁fn": 5379, + "▁jud": 5380, + "▁hat": 5381, + "ACK": 5382, + "▁Fe": 5383, + "$-": 5384, + "ivil": 5385, + "oted": 5386, + "▁sizeof": 5387, + "▁situation": 5388, + "▁lives": 5389, + "▁feeling": 5390, + "▁risk": 5391, + "▁January": 5392, + "▁Object": 5393, + "▁recomm": 5394, + "▁вы": 5395, + "▁potential": 5396, + "eah": 5397, + "▁complex": 5398, + "printf": 5399, + "istance": 5400, + "irth": 5401, + "lik": 5402, + "aste": 5403, + "▁whose": 5404, + "Arg": 5405, + "▁modern": 5406, + "iones": 5407, + "▁че": 5408, + "▁sett": 5409, + "▁Mag": 5410, + "ae": 5411, + "▁condition": 5412, + "Length": 5413, + "▁fit": 5414, + "ounds": 5415, + "▁changed": 5416, + "▁guy": 5417, + "filter": 5418, + "atever": 5419, + "éd": 5420, + "remove": 5421, + "▁hop": 5422, + "▁Out": 5423, + "▁Rich": 5424, + "child": 5425, + "▁included": 5426, + "$\\": 5427, + "▁Tom": 5428, + "eline": 5429, + "▁sometimes": 5430, + "▁drink": 5431, + "▁quant": 5432, + "▁please": 5433, + "▁Int": 5434, + "rief": 5435, + "▁exactly": 5436, + "cing": 5437, + "▁allowed": 5438, + "build": 5439, + "▁beautiful": 5440, + "▁Well": 5441, + "▁looks": 5442, + "▁ü": 5443, + "▁chance": 5444, + "▁wrote": 5445, + "▁nor": 5446, + "▁failed": 5447, + "Met": 5448, + "▁prior": 5449, + "▁hundred": 5450, + "ской": 5451, + "oria": 5452, + "▁cy": 5453, + "▁web": 5454, + "▁mess": 5455, + "leq": 5456, + "dy": 5457, + "tex": 5458, + "▁anim": 5459, + "atur": 5460, + "▁structure": 5461, + "option": 5462, + "▁actual": 5463, + "▁Franc": 5464, + "enced": 5465, + ".": 5652, + "▁production": 5653, + "iger": 5654, + "▁ст": 5655, + "show": 5656, + "▁population": 5657, + "▁park": 5658, + "▁Ze": 5659, + "▁necessary": 5660, + "▁trust": 5661, + "▁shown": 5662, + "module": 5663, + "GE": 5664, + "▁lay": 5665, + "▁announ": 5666, + "▁className": 5667, + "▁calcul": 5668, + "Function": 5669, + "▁Sal": 5670, + "OK": 5671, + "TP": 5672, + "▁entry": 5673, + "▁Stud": 5674, + "▁items": 5675, + "▁security": 5676, + "Entry": 5677, + "float": 5678, + "ls": 5679, + "ibly": 5680, + "▁contribut": 5681, + "▁Check": 5682, + "MD": 5683, + "▁improve": 5684, + "Part": 5685, + "▁systems": 5686, + "Bl": 5687, + "▁policy": 5688, + "▁screen": 5689, + "▁Any": 5690, + "▁opened": 5691, + "alloc": 5692, + "▁December": 5693, + "▁É": 5694, + "▁email": 5695, + "ader": 5696, + "=>": 5697, + "▁Hen": 5698, + "▁info": 5699, + "▁float": 5700, + "▁switch": 5701, + "ран": 5702, + "urance": 5703, + "▁assum": 5704, + "ustr": 5705, + "▁groups": 5706, + "▁Read": 5707, + "▁wat": 5708, + "Sp": 5709, + "вер": 5710, + "RAN": 5711, + "hib": 5712, + "ALL": 5713, + "▁hus": 5714, + "Spec": 5715, + "\"))": 5716, + "▁French": 5717, + "▁Class": 5718, + "▁president": 5719, + "▁definit": 5720, + "▁Nor": 5721, + "▁Thom": 5722, + "aign": 5723, + "Width": 5724, + "Do": 5725, + "▁{@": 5726, + "agon": 5727, + "▁Lu": 5728, + "▁followed": 5729, + "MM": 5730, + "asons": 5731, + "tmp": 5732, + "▁throws": 5733, + "ITY": 5734, + "ном": 5735, + "▁fair": 5736, + "▁pen": 5737, + "ég": 5738, + "▁interface": 5739, + "▁saf": 5740, + "oon": 5741, + "Back": 5742, + "▁speed": 5743, + "▁extends": 5744, + "empty": 5745, + "▁пере": 5746, + "▁proper": 5747, + "▁driv": 5748, + "фи": 5749, + "▁center": 5750, + "header": 5751, + "▁})": 5752, + "wa": 5753, + "▁middle": 5754, + "▁choose": 5755, + "▁Stad": 5756, + "SO": 5757, + "Factory": 5758, + "Dev": 5759, + "icles": 5760, + "▁application": 5761, + "▁models": 5762, + "pite": 5763, + "cap": 5764, + "xi": 5765, + "ospital": 5766, + "▁dream": 5767, + "END": 5768, + "▁contract": 5769, + "icrosoft": 5770, + "▁thous": 5771, + "izes": 5772, + "▁да": 5773, + "▁CO": 5774, + "▁direction": 5775, + "▁``": 5776, + "▁drive": 5777, + "Max": 5778, + "cia": 5779, + "▁continu": 5780, + "▁Alex": 5781, + "▁gold": 5782, + "▁prep": 5783, + "▁origin": 5784, + "▁rap": 5785, + "Op": 5786, + "ously": 5787, + "▁areas": 5788, + "PORT": 5789, + "она": 5790, + "▁safe": 5791, + "▁professional": 5792, + "apache": 5793, + "▁temper": 5794, + "sz": 5795, + "▁unit": 5796, + "▁cop": 5797, + "eqn": 5798, + "Listener": 5799, + "▁format": 5800, + "select": 5801, + "▁comfort": 5802, + "▁meant": 5803, + "iday": 5804, + "eme": 5805, + "▁active": 5806, + "▁note": 5807, + "▁Mil": 5808, + "only": 5809, + "▁<=": 5810, + "▁neigh": 5811, + "ao": 5812, + "▁blue": 5813, + "▁TV": 5814, + "Child": 5815, + "▁reached": 5816, + "Address": 5817, + "ств": 5818, + "▁closed": 5819, + "inder": 5820, + "olo": 5821, + "▁alt": 5822, + "▁adm": 5823, + "Format": 5824, + "UI": 5825, + "▁Ham": 5826, + "▁frequ": 5827, + "▁independ": 5828, + "▁easily": 5829, + "▁Land": 5830, + "▁tor": 5831, + "ography": 5832, + "infty": 5833, + "▁Work": 5834, + "iven": 5835, + "▁County": 5836, + "▁src": 5837, + "}$,": 5838, + "parse": 5839, + "CD": 5840, + "▁Cour": 5841, + "▁fol": 5842, + "Entity": 5843, + "pgf": 5844, + "▁China": 5845, + "▁Sub": 5846, + "hood": 5847, + "▁fields": 5848, + "▁yes": 5849, + "rend": 5850, + "▁towards": 5851, + "▁staff": 5852, + "▁Air": 5853, + "▁station": 5854, + "atives": 5855, + "▁impact": 5856, + "вы": 5857, + "▁directly": 5858, + "issions": 5859, + "iva": 5860, + "|\\": 5861, + "Ptr": 5862, + "▁Sant": 5863, + "Pol": 5864, + "▁progress": 5865, + "itar": 5866, + "▁parts": 5867, + "▁plant": 5868, + "▁absolut": 5869, + "▁guess": 5870, + "eqref": 5871, + "▁tim": 5872, + "▁Lou": 5873, + "▁cool": 5874, + "alu": 5875, + "▁mouth": 5876, + "них": 5877, + "▁height": 5878, + "gest": 5879, + "▁Post": 5880, + "▁board": 5881, + "▁tit": 5882, + "▁hour": 5883, + "▁server": 5884, + "▁players": 5885, + "rier": 5886, + "Link": 5887, + "▁President": 5888, + "](": 5889, + "▁construct": 5890, + "handle": 5891, + "}$.": 5892, + "rying": 5893, + "▁shop": 5894, + "iana": 5895, + "exp": 5896, + "Helper": 5897, + "Offset": 5898, + "aches": 5899, + "▁connection": 5900, + "▁difference": 5901, + "service": 5902, + "▁gas": 5903, + "▁priv": 5904, + "▁univers": 5905, + "▁wish": 5906, + "Rem": 5907, + "Url": 5908, + "geb": 5909, + "So": 5910, + "ensions": 5911, + "Module": 5912, + "SIZE": 5913, + "▁prem": 5914, + "window": 5915, + "▁dies": 5916, + "del": 5917, + "▁row": 5918, + "▁average": 5919, + "xim": 5920, + "▁pu": 5921, + "anç": 5922, + "Det": 5923, + "ker": 5924, + "ya": 5925, + "▁Det": 5926, + "▁på": 5927, + "▁named": 5928, + "▁decision": 5929, + "win": 5930, + "▁George": 5931, + "arily": 5932, + "▁solution": 5933, + "▁multiple": 5934, + "ategy": 5935, + "▁learning": 5936, + "▁secret": 5937, + "DO": 5938, + "▁nice": 5939, + "////////////////": 5940, + "Su": 5941, + "itation": 5942, + "▁join": 5943, + "▁elements": 5944, + "▁emer": 5945, + "tilde": 5946, + "▁dep": 5947, + "▁shot": 5948, + "▁platform": 5949, + "othing": 5950, + "My": 5951, + "edia": 5952, + "oms": 5953, + "aily": 5954, + "([": 5955, + "▁dress": 5956, + "▁official": 5957, + "estern": 5958, + "▁discover": 5959, + "▁mi": 5960, + "ные": 5961, + "CA": 5962, + "oding": 5963, + "▁Found": 5964, + "▁affect": 5965, + "Vis": 5966, + "stract": 5967, + "iced": 5968, + "debug": 5969, + "▁related": 5970, + "▁spect": 5971, + "ushed": 5972, + "сько": 5973, + "▁bank": 5974, + "▁cele": 5975, + "AND": 5976, + "olf": 5977, + "ем": 5978, + "▁fill": 5979, + "▁gives": 5980, + "▁бу": 5981, + "aron": 5982, + "▁Jes": 5983, + "REG": 5984, + "▁sudd": 5985, + "dated": 5986, + "vi": 5987, + "▁gi": 5988, + "send": 5989, + "cpp": 5990, + "▁spent": 5991, + "ande": 5992, + "▁operation": 5993, + "process": 5994, + "▁inform": 5995, + "▁Free": 5996, + "yond": 5997, + "▁perhaps": 5998, + "▁surv": 5999, + "▁Loc": 6000, + "▁concl": 6001, + "▁раз": 6002, + "▁Over": 6003, + "hol": 6004, + "raz": 6005, + "Write": 6006, + "▁giving": 6007, + "rd": 6008, + "instance": 6009, + "▁released": 6010, + "▁Ro": 6011, + "RA": 6012, + "▁practice": 6013, + "▁graph": 6014, + "▁increase": 6015, + "▁figure": 6016, + "Filter": 6017, + "HECK": 6018, + "idx": 6019, + "▁glass": 6020, + "ski": 6021, + "comes": 6022, + "▁cat": 6023, + "▁cold": 6024, + "goto": 6025, + "ufact": 6026, + "▁Copyright": 6027, + "}}\\": 6028, + "▁streng": 6029, + "▁dir": 6030, + "token": 6031, + "▁occur": 6032, + "arlier": 6033, + "▁measure": 6034, + "▁sec": 6035, + "▁más": 6036, + "▁Net": 6037, + "▁argument": 6038, + "▁sou": 6039, + "▁moving": 6040, + "▁prefer": 6041, + "mask": 6042, + "<<": 6043, + "▁breath": 6044, + "▁physical": 6045, + "▁positive": 6046, + "▁sor": 6047, + "▁depart": 6048, + "▁remove": 6049, + "▁kit": 6050, + "▁meeting": 6051, + "▁Data": 6052, + "ograf": 6053, + "actions": 6054, + "▁parameters": 6055, + "▁Att": 6056, + "esch": 6057, + "▁involved": 6058, + "ät": 6059, + "LL": 6060, + "Bar": 6061, + "▁си": 6062, + "ech": 6063, + "GET": 6064, + "▁prevent": 6065, + "▁beyond": 6066, + "▁Other": 6067, + "än": 6068, + "byte": 6069, + "▁sudden": 6070, + "olve": 6071, + "▁но": 6072, + "LOG": 6073, + "unit": 6074, + "▁truth": 6075, + "rat": 6076, + "SD": 6077, + "▁eat": 6078, + "▁Mad": 6079, + "▁provides": 6080, + "▁session": 6081, + "Dele": 6082, + "▁convers": 6083, + "center": 6084, + "▁continued": 6085, + "otion": 6086, + "cache": 6087, + "display": 6088, + "▁protect": 6089, + "ams": 6090, + "▁pow": 6091, + "CTION": 6092, + "▁Mac": 6093, + "mo": 6094, + "ха": 6095, + "▁distance": 6096, + "▁Time": 6097, + "gi": 6098, + "▁sequ": 6099, + "Target": 6100, + "сле": 6101, + "Server": 6102, + "▁wide": 6103, + "close": 6104, + "▁cru": 6105, + "Ext": 6106, + "▁select": 6107, + "▁pattern": 6108, + "\"));": 6109, + "Provider": 6110, + "URL": 6111, + "▁green": 6112, + "▁waiting": 6113, + "proto": 6114, + "▁immediately": 6115, + "common": 6116, + "azione": 6117, + "river": 6118, + "▁sen": 6119, + "▁!==": 6120, + "▁February": 6121, + "urb": 6122, + "▁Sen": 6123, + "dest": 6124, + ">": 6890, + "command": 6891, + "atz": 6892, + "▁mal": 6893, + "став": 6894, + "▁Press": 6895, + "▁characters": 6896, + "▁zero": 6897, + "AGE": 6898, + "rapper": 6899, + "▁kitchen": 6900, + "aming": 6901, + "▁restr": 6902, + "XX": 6903, + "▁College": 6904, + "▁Array": 6905, + "▁fresh": 6906, + "▁shift": 6907, + "▁specified": 6908, + "plete": 6909, + "ITE": 6910, + "▁Camp": 6911, + "rial": 6912, + "cb": 6913, + "▁TH": 6914, + "IB": 6915, + "osen": 6916, + "▁ú": 6917, + "▁params": 6918, + "ignment": 6919, + "adding": 6920, + "▁degree": 6921, + "Local": 6922, + "Oh": 6923, + "▁zur": 6924, + "▁levels": 6925, + "CS": 6926, + "finished": 6927, + "Case": 6928, + "riage": 6929, + "Vector": 6930, + "▁sea": 6931, + "antic": 6932, + "▁League": 6933, + "▁therefore": 6934, + "One": 6935, + "Return": 6936, + "Access": 6937, + "vas": 6938, + "▁ос": 6939, + "▁rat": 6940, + "Big": 6941, + "▁behavior": 6942, + "kr": 6943, + "▁undefined": 6944, + "▁Es": 6945, + "▁appeared": 6946, + "eles": 6947, + "▁WAR": 6948, + "Stat": 6949, + "▁Google": 6950, + "▁credit": 6951, + "▁File": 6952, + "anging": 6953, + "house": 6954, + "romise": 6955, + "gent": 6956, + "▁habit": 6957, + "▁society": 6958, + "▁encour": 6959, + "▁paint": 6960, + "pet": 6961, + "▁UK": 6962, + "aws": 6963, + "onom": 6964, + "Gl": 6965, + "}_{\\": 6966, + "eless": 6967, + "emy": 6968, + "▁Cong": 6969, + "▁developed": 6970, + "▁images": 6971, + "▁ö": 6972, + "▁font": 6973, + "clear": 6974, + "gin": 6975, + "▁Lord": 6976, + "▁transport": 6977, + "▁::": 6978, + "▁cup": 6979, + "ulate": 6980, + "▁During": 6981, + "priv": 6982, + "▁extrem": 6983, + "▁Di": 6984, + "▁doubt": 6985, + "Py": 6986, + "ifying": 6987, + "split": 6988, + "ego": 6989, + "github": 6990, + "▁),": 6991, + "ROM": 6992, + "▁chair": 6993, + "▁trade": 6994, + "▁nicht": 6995, + "Top": 6996, + "Store": 6997, + "▁parte": 6998, + "project": 6999, + "nia": 7000, + "▁від": 7001, + "war": 7002, + "▁Prof": 7003, + "▁caught": 7004, + "Thread": 7005, + "ства": 7006, + "author": 7007, + "▁doll": 7008, + "▁harm": 7009, + "▁Gen": 7010, + "tree": 7011, + "etime": 7012, + "cfg": 7013, + "▁guys": 7014, + "▁California": 7015, + "▁Green": 7016, + "▁movement": 7017, + "iej": 7018, + "▁statement": 7019, + "▁seeing": 7020, + "▁haven": 7021, + "vention": 7022, + "SL": 7023, + "chedul": 7024, + "iert": 7025, + "▁primary": 7026, + "▁civil": 7027, + "rian": 7028, + "▁button": 7029, + "▁lived": 7030, + "Pass": 7031, + "sor": 7032, + "▁watching": 7033, + "▁skills": 7034, + "tee": 7035, + "Level": 7036, + "▁scient": 7037, + "hs": 7038, + "▁agre": 7039, + "cat": 7040, + "▁tend": 7041, + "▁Mill": 7042, + "▁Cap": 7043, + "ORD": 7044, + "gle": 7045, + "▁сво": 7046, + "»,": 7047, + "▁ahead": 7048, + "vest": 7049, + "▁Jose": 7050, + "ischer": 7051, + "și": 7052, + "▁leaving": 7053, + "▁для": 7054, + "▁south": 7055, + "▁consum": 7056, + "Range": 7057, + "▁activities": 7058, + "Sec": 7059, + "▁sales": 7060, + "▁fix": 7061, + "▁jed": 7062, + "rum": 7063, + "vector": 7064, + "▁spot": 7065, + "▁manufact": 7066, + "кт": 7067, + "orrow": 7068, + "sign": 7069, + "▁college": 7070, + "▁driver": 7071, + "▁definitely": 7072, + "▁spend": 7073, + "mission": 7074, + "зу": 7075, + "atively": 7076, + "bi": 7077, + "Callback": 7078, + "▁particularly": 7079, + "▁hell": 7080, + "▁pool": 7081, + "PRE": 7082, + "▁clearly": 7083, + "PT": 7084, + "othes": 7085, + "▁Id": 7086, + "Location": 7087, + "▁Run": 7088, + "▁fixed": 7089, + "▁Hand": 7090, + "bal": 7091, + "double": 7092, + "Can": 7093, + "Omega": 7094, + "▁challeng": 7095, + "▁standing": 7096, + "iten": 7097, + "▁mechan": 7098, + "▁durch": 7099, + "▁dell": 7100, + "▁raised": 7101, + "▁weak": 7102, + "▁Du": 7103, + "grad": 7104, + "▁scene": 7105, + "poss": 7106, + "▁ton": 7107, + "▁earth": 7108, + "ulations": 7109, + "▁strength": 7110, + "aked": 7111, + "▁remain": 7112, + "▁Bi": 7113, + "▁customer": 7114, + "range": 7115, + "▁interested": 7116, + "ONE": 7117, + "▁coff": 7118, + "require": 7119, + "▁Only": 7120, + "▁Web": 7121, + "▁farm": 7122, + "▁activity": 7123, + "▁rout": 7124, + "bling": 7125, + "SY": 7126, + "▁Richard": 7127, + "▁Ref": 7128, + "▁кон": 7129, + "▁jun": 7130, + "born": 7131, + "ijn": 7132, + "Configuration": 7133, + "uman": 7134, + "EE": 7135, + "▁married": 7136, + "▁За": 7137, + "▁fat": 7138, + "▁kid": 7139, + "▁Tur": 7140, + "▁offered": 7141, + "nic": 7142, + "▁Big": 7143, + "Gamma": 7144, + "▁Health": 7145, + "▁TR": 7146, + "▁się": 7147, + "▁construction": 7148, + "▁Church": 7149, + "▁Bet": 7150, + "bus": 7151, + "▁earn": 7152, + "rict": 7153, + "▁пра": 7154, + "▁brain": 7155, + "▁fra": 7156, + "▁Op": 7157, + "FIG": 7158, + "ema": 7159, + "▁European": 7160, + "▁Saint": 7161, + "ARE": 7162, + "uri": 7163, + "▁River": 7164, + "{}": 7165, + "▁sitting": 7166, + "▁understanding": 7167, + "▁plans": 7168, + "ropri": 7169, + "▁older": 7170, + "▁pressure": 7171, + "Impl": 7172, + "▁peace": 7173, + "Connection": 7174, + "▁fi": 7175, + "rich": 7176, + "▁shut": 7177, + "apers": 7178, + "Port": 7179, + "▁Look": 7180, + "rim": 7181, + "auth": 7182, + "auto": 7183, + "▁highly": 7184, + "▁unless": 7185, + "▁Wal": 7186, + "▁ren": 7187, + "ws": 7188, + "▁core": 7189, + "(-": 7190, + "▁clim": 7191, + "ruit": 7192, + "▁callback": 7193, + "hest": 7194, + "▁Charles": 7195, + "▁Long": 7196, + "}=": 7197, + "ър": 7198, + "▁shared": 7199, + "ulated": 7200, + "gorithm": 7201, + "▁Home": 7202, + "▁village": 7203, + "ees": 7204, + "sv": 7205, + "▁restaur": 7206, + "rey": 7207, + "▁Cast": 7208, + "▁Person": 7209, + "кий": 7210, + "▁organiz": 7211, + "▁Rad": 7212, + "ponents": 7213, + "▁werden": 7214, + "▁bow": 7215, + "sen": 7216, + "ami": 7217, + "Interface": 7218, + "▁basis": 7219, + "▁Company": 7220, + "ernel": 7221, + "itu": 7222, + "Hash": 7223, + "▁aan": 7224, + "▁х": 7225, + "▁smile": 7226, + "xml": 7227, + "▁scen": 7228, + "amm": 7229, + "tool": 7230, + "aria": 7231, + "▁accur": 7232, + "settings": 7233, + "▁Jesus": 7234, + "acement": 7235, + "power": 7236, + "(!": 7237, + "▁calls": 7238, + "▁basic": 7239, + "▁settings": 7240, + "ript": 7241, + "pool": 7242, + "ctors": 7243, + "▁Foundation": 7244, + "▁weap": 7245, + "KEY": 7246, + "foot": 7247, + "▁radio": 7248, + "▁helped": 7249, + "mann": 7250, + "▁jump": 7251, + "▁tick": 7252, + "▁growing": 7253, + "aten": 7254, + "real": 7255, + "▁increasing": 7256, + "Device": 7257, + "varepsilon": 7258, + "▁sets": 7259, + "▁advant": 7260, + "Open": 7261, + "▁reasons": 7262, + "▁supposed": 7263, + "oes": 7264, + "ede": 7265, + "teen": 7266, + "ifdef": 7267, + "▁delete": 7268, + "▁&=": 7269, + "▁Bill": 7270, + "▁aim": 7271, + "▁Ok": 7272, + "▁Av": 7273, + "reci": 7274, + "acks": 7275, + "iste": 7276, + "Properties": 7277, + "▁tmp": 7278, + "▁dei": 7279, + "PER": 7280, + "DC": 7281, + "sta": 7282, + "нии": 7283, + "▁limited": 7284, + "▁greater": 7285, + "description": 7286, + "ori": 7287, + "aints": 7288, + "▁hy": 7289, + "▁Mel": 7290, + "▁CH": 7291, + "cons": 7292, + "▁surround": 7293, + "▁Who": 7294, + "arc": 7295, + "▁telev": 7296, + "itution": 7297, + "▁equal": 7298, + "кі": 7299, + "▁Israel": 7300, + "äh": 7301, + "▁Caption": 7302, + "▁exerc": 7303, + "empor": 7304, + "▁++": 7305, + "▁lib": 7306, + "make": 7307, + "▁MA": 7308, + "copy": 7309, + "friend": 7310, + "▁кото": 7311, + "▁damage": 7312, + "▁\\,": 7313, + "oded": 7314, + "▁none": 7315, + "▁evalu": 7316, + "ston": 7317, + ">,": 7318, + "FOR": 7319, + "▁norm": 7320, + "appe": 7321, + "Session": 7322, + "▁adult": 7323, + "▁hospital": 7324, + "▁recommend": 7325, + "property": 7326, + "stein": 7327, + "final": 7328, + "▁nu": 7329, + "second": 7330, + "▁aspect": 7331, + "\")]": 7332, + "жен": 7333, + "amento": 7334, + "▁rac": 7335, + "save": 7336, + "▁football": 7337, + "Ab": 7338, + "ungs": 7339, + "abil": 7340, + "▁Arch": 7341, + "system": 7342, + "hist": 7343, + "▁luck": 7344, + "render": 7345, + "▁sein": 7346, + "ioni": 7347, + "▁rot": 7348, + "▁corner": 7349, + "▁appropri": 7350, + "▁Software": 7351, + "▁tele": 7352, + "Delete": 7353, + "▁According": 7354, + "▁prison": 7355, + "▁lic": 7356, + "▁ми": 7357, + "term": 7358, + "sets": 7359, + "▁vel": 7360, + "▁rank": 7361, + "▁existing": 7362, + "▁Vir": 7363, + "▁trip": 7364, + "▁му": 7365, + "avax": 7366, + "▁ris": 7367, + "▁define": 7368, + "▁heat": 7369, + "car": 7370, + "▁convert": 7371, + "email": 7372, + "▁Under": 7373, + "▁Ш": 7374, + "▁Grand": 7375, + "▁exists": 7376, + "sys": 7377, + "eff": 7378, + "▁Top": 7379, + "▁č": 7380, + "▁tempor": 7381, + "▁arguments": 7382, + "▁supported": 7383, + "ensed": 7384, + "▁Francis": 7385, + "▁coord": 7386, + "▁achieve": 7387, + "▁Name": 7388, + "▁Jahr": 7389, + "▁Gi": 7390, + "she": 7391, + "▁Dev": 7392, + "▁alla": 7393, + "▁WIT": 7394, + "agment": 7395, + "custom": 7396, + "alls": 7397, + "&&": 7398, + "WE": 7399, + "▁holding": 7400, + "prototype": 7401, + "▁fing": 7402, + "▁bag": 7403, + "▁Party": 7404, + "stack": 7405, + "▁economic": 7406, + "▁Gal": 7407, + "idents": 7408, + "▁Jun": 7409, + "▁showed": 7410, + "osh": 7411, + "▁Bay": 7412, + "mail": 7413, + "▁SO": 7414, + "▁\"<": 7415, + "graphics": 7416, + "▁fu": 7417, + "click": 7418, + "▁battle": 7419, + "{{": 7420, + "▁Event": 7421, + "rior": 7422, + "chaft": 7423, + "▁favorite": 7424, + "usive": 7425, + "support": 7426, + "bm": 7427, + "Kind": 7428, + "▁safety": 7429, + "▁Ent": 7430, + "cup": 7431, + "▁Australia": 7432, + "▁destroy": 7433, + "▁organization": 7434, + "iden": 7435, + "################": 7436, + "dec": 7437, + "▁za": 7438, + "▁seven": 7439, + "arely": 7440, + "▁flag": 7441, + "Dir": 7442, + "▁Carl": 7443, + "▁doctor": 7444, + "▁variety": 7445, + "▁Lin": 7446, + "▁tom": 7447, + "^{(": 7448, + "Bo": 7449, + "antes": 7450, + "▁mine": 7451, + "▁Mit": 7452, + "▁describe": 7453, + "Args": 7454, + "LS": 7455, + "API": 7456, + "▁Luc": 7457, + "phone": 7458, + "▁science": 7459, + "▁Oper": 7460, + "Next": 7461, + "▁investig": 7462, + "▁demonstr": 7463, + "▁Govern": 7464, + "▁objects": 7465, + "▁Louis": 7466, + "▁Returns": 7467, + "▁han": 7468, + "nam": 7469, + "▁comme": 7470, + "▁presence": 7471, + "▁pel": 7472, + "▁detect": 7473, + ")=": 7474, + "▁Chinese": 7475, + "▁rich": 7476, + "▁classes": 7477, + "▁expand": 7478, + "▁Dom": 7479, + "▁Dec": 7480, + "sn": 7481, + "peed": 7482, + "▁Jim": 7483, + "should": 7484, + "▁Smith": 7485, + "▁pages": 7486, + "▁Jean": 7487, + "rics": 7488, + "▁Sund": 7489, + "ads": 7490, + "▁Their": 7491, + "unicip": 7492, + "ву": 7493, + "▁download": 7494, + "▁stress": 7495, + "▁Pet": 7496, + "menu": 7497, + "reme": 7498, + "▁compared": 7499, + "Ste": 7500, + "IND": 7501, + "container": 7502, + "▁Indian": 7503, + "oren": 7504, + "▁ses": 7505, + "▁Whe": 7506, + "▁roku": 7507, + "▁established": 7508, + "▁generally": 7509, + "▁fle": 7510, + "__(": 7511, + "=\"+": 7512, + "Var": 7513, + "▁Make": 7514, + "▁removed": 7515, + "zz": 7516, + "ün": 7517, + "▁mix": 7518, + "erk": 7519, + "iation": 7520, + "outer": 7521, + "SK": 7522, + "▁becomes": 7523, + "▁Hall": 7524, + "scious": 7525, + "▁watched": 7526, + "▁gather": 7527, + "▁Result": 7528, + "proof": 7529, + "pay": 7530, + "▁produced": 7531, + "▁|=": 7532, + "▁border": 7533, + "▁din": 7534, + "▁script": 7535, + "▁actions": 7536, + "▁mas": 7537, + "ща": 7538, + "ooth": 7539, + "▁Techn": 7540, + "Json": 7541, + "▁filled": 7542, + "ден": 7543, + "undle": 7544, + "сту": 7545, + "Tool": 7546, + "▁king": 7547, + "▁ven": 7548, + "stra": 7549, + "▁predict": 7550, + "▁lui": 7551, + "▁WARRAN": 7552, + "▁Fun": 7553, + "Script": 7554, + "▁powerful": 7555, + "▁lose": 7556, + "atically": 7557, + "▁daily": 7558, + "▁ring": 7559, + "▁arrived": 7560, + "Stack": 7561, + "scope": 7562, + "▁Back": 7563, + "elij": 7564, + "▁ze": 7565, + "keys": 7566, + "{\"": 7567, + "VID": 7568, + "▁license": 7569, + "what": 7570, + "▁proced": 7571, + "rant": 7572, + "estival": 7573, + "agram": 7574, + "▁LO": 7575, + "▁Henry": 7576, + "▁flags": 7577, + "Down": 7578, + "scription": 7579, + "▁families": 7580, + "isse": 7581, + "bour": 7582, + "▁Bur": 7583, + "—\"": 7584, + "▁brief": 7585, + "▁creating": 7586, + "▁clients": 7587, + "rangle": 7588, + "▁amazing": 7589, + "▁sind": 7590, + "▁covered": 7591, + "Well": 7592, + "сте": 7593, + "тор": 7594, + "▁Bas": 7595, + "total": 7596, + "▁Init": 7597, + "▁sand": 7598, + "Unit": 7599, + "▁murder": 7600, + "▁bright": 7601, + "▁trav": 7602, + "icans": 7603, + "▁attribute": 7604, + "fc": 7605, + "▁placed": 7606, + "EST": 7607, + "Vari": 7608, + "▁cos": 7609, + "▁attract": 7610, + "anel": 7611, + "}).": 7612, + "bytes": 7613, + "▁parse": 7614, + "▁belong": 7615, + "BN": 7616, + "▁Sol": 7617, + "Po": 7618, + "`,": 7619, + "▁calling": 7620, + "▁?>": 7621, + "▁iter": 7622, + "▁url": 7623, + "▁evening": 7624, + "reek": 7625, + "▁honest": 7626, + "▁director": 7627, + "RC": 7628, + "▁solid": 7629, + "▁phil": 7630, + "iene": 7631, + "FAULT": 7632, + "cope": 7633, + "▁History": 7634, + "▁Team": 7635, + "reedom": 7636, + "▁ru": 7637, + "UB": 7638, + "▁worse": 7639, + "imo": 7640, + "Mat": 7641, + "▁Mex": 7642, + "actor": 7643, + "▁vor": 7644, + "ться": 7645, + "▁experiment": 7646, + "▁Play": 7647, + "▁Another": 7648, + "▁happens": 7649, + "uan": 7650, + "▁patients": 7651, + "▁rend": 7652, + "▁Mo": 7653, + "▁Tex": 7654, + "▁wed": 7655, + "tn": 7656, + "insert": 7657, + "▁па": 7658, + "▁anti": 7659, + "Match": 7660, + "ampionship": 7661, + "▁forces": 7662, + "▁Hot": 7663, + "▁phase": 7664, + "▁template": 7665, + "stop": 7666, + "icated": 7667, + "▁managed": 7668, + "wait": 7669, + "▁*(": 7670, + "GB": 7671, + "▁appoint": 7672, + "ła": 7673, + "▁stick": 7674, + "▁FOR": 7675, + "▁Vis": 7676, + "tor": 7677, + "▁př": 7678, + "quest": 7679, + "uses": 7680, + "\");\r": 7681, + "▁suddenly": 7682, + "éc": 7683, + "ND": 7684, + "urop": 7685, + "ред": 7686, + "▁insurance": 7687, + "access": 7688, + "unfinished": 7689, + "▁tamb": 7690, + "▁sac": 7691, + "▁Court": 7692, + "▁missing": 7693, + "▁Where": 7694, + "▁Sum": 7695, + "}^{\\": 7696, + "▁sua": 7697, + "_,": 7698, + "▁thick": 7699, + "▁Trump": 7700, + "▁operations": 7701, + "FS": 7702, + "▁deux": 7703, + "dz": 7704, + "Template": 7705, + "▁\"/": 7706, + "▁odd": 7707, + "▁reality": 7708, + "▁teams": 7709, + "▁cer": 7710, + "oma": 7711, + "▁și": 7712, + "▁cloud": 7713, + "▁Department": 7714, + "Ne": 7715, + "▁requires": 7716, + "items": 7717, + "▁III": 7718, + "rightarrow": 7719, + ")->": 7720, + "▁writer": 7721, + "replace": 7722, + "▁thr": 7723, + "jen": 7724, + "▁ot": 7725, + "▁occup": 7726, + "▁eventually": 7727, + "▁Math": 7728, + "▁conserv": 7729, + "amer": 7730, + "▁Fort": 7731, + "▁dry": 7732, + "▁sexual": 7733, + "▁costs": 7734, + "▁forms": 7735, + "▁Vict": 7736, + "PAR": 7737, + "framework": 7738, + "▁ди": 7739, + "Operation": 7740, + "зна": 7741, + "which": 7742, + "▁tight": 7743, + "Invalid": 7744, + "▁partner": 7745, + "▁пред": 7746, + "▁thank": 7747, + "▁guard": 7748, + "hem": 7749, + "Body": 7750, + "▁emot": 7751, + "IX": 7752, + "fast": 7753, + "що": 7754, + "ño": 7755, + "night": 7756, + "▁Sci": 7757, + "ника": 7758, + "▁TO": 7759, + "▁individuals": 7760, + "сси": 7761, + "}),": 7762, + "False": 7763, + "(\"%": 7764, + "▁optim": 7765, + "▁-->": 7766, + "▁factor": 7767, + "▁smaller": 7768, + "▁contain": 7769, + "spect": 7770, + "Engine": 7771, + "▁announced": 7772, + "▁Democr": 7773, + "▁rob": 7774, + "▁flat": 7775, + "osoph": 7776, + "Search": 7777, + "ahl": 7778, + "▁Exception": 7779, + "▁Ol": 7780, + "equals": 7781, + "▁unter": 7782, + "shape": 7783, + "NS": 7784, + "Obj": 7785, + "▁species": 7786, + "weight": 7787, + "you": 7788, + "▁este": 7789, + "▁View": 7790, + "▁mission": 7791, + "▁journal": 7792, + "Values": 7793, + "▁einem": 7794, + "ismo": 7795, + "▁projects": 7796, + "▁Das": 7797, + "rible": 7798, + "▁serve": 7799, + "▁opening": 7800, + "▁hur": 7801, + "▁programs": 7802, + "▁USA": 7803, + "iliar": 7804, + "idos": 7805, + "Br": 7806, + "estamp": 7807, + "▁tools": 7808, + "anner": 7809, + "RT": 7810, + "▁Start": 7811, + "▁bath": 7812, + "▁coffee": 7813, + "orter": 7814, + "internal": 7815, + "files": 7816, + "INVAL": 7817, + "ako": 7818, + "dt": 7819, + "▁Second": 7820, + "▁alloc": 7821, + "▁ended": 7822, + "acional": 7823, + "▁manager": 7824, + "▁Sun": 7825, + "agg": 7826, + "▁leader": 7827, + "olved": 7828, + "▁что": 7829, + "▁traditional": 7830, + "shot": 7831, + "rup": 7832, + "CF": 7833, + "▁Each": 7834, + "wr": 7835, + "▁Som": 7836, + "▁materials": 7837, + "▁msg": 7838, + "▁syn": 7839, + "▁produce": 7840, + "▁storage": 7841, + "subsection": 7842, + "▁Sie": 7843, + "▁IP": 7844, + "CESS": 7845, + "▁wa": 7846, + "Record": 7847, + "▁marketing": 7848, + "plet": 7849, + "Dialog": 7850, + "▁mentioned": 7851, + "▁Na": 7852, + "▁Union": 7853, + "▁API": 7854, + "▁negative": 7855, + "txt": 7856, + "▁easier": 7857, + "legal": 7858, + "Dep": 7859, + "▁novel": 7860, + "eur": 7861, + "ació": 7862, + "▁Bud": 7863, + "▁carry": 7864, + "schaft": 7865, + "▁broken": 7866, + "▁trees": 7867, + ">();": 7868, + "▁emb": 7869, + "ieder": 7870, + "▁route": 7871, + "ikel": 7872, + "▁listen": 7873, + "ashion": 7874, + "▁Mrs": 7875, + "▁equipment": 7876, + "agger": 7877, + "▁Thus": 7878, + "▁matrix": 7879, + "alla": 7880, + "▁Tour": 7881, + "▁conversation": 7882, + "Mon": 7883, + "ournal": 7884, + "▁minute": 7885, + "Am": 7886, + "Api": 7887, + "▁forget": 7888, + "Me": 7889, + "levant": 7890, + "temp": 7891, + "▁telling": 7892, + "move": 7893, + "▁independent": 7894, + "toString": 7895, + "edit": 7896, + "▁Jac": 7897, + "azz": 7898, + "react": 7899, + "▁cin": 7900, + "▁Prov": 7901, + "isted": 7902, + "▁hash": 7903, + "onna": 7904, + "iki": 7905, + "▁generated": 7906, + "Render": 7907, + "▁psych": 7908, + "nav": 7909, + "▁entr": 7910, + "пра": 7911, + "rx": 7912, + "ATH": 7913, + "▁assume": 7914, + "Tree": 7915, + "sembly": 7916, + "▁Matt": 7917, + "caption": 7918, + "▁solutions": 7919, + "▁faith": 7920, + "▁digital": 7921, + "▁excell": 7922, + "▁Version": 7923, + "Debug": 7924, + "▁жи": 7925, + "▁carried": 7926, + "reset": 7927, + "▁slowly": 7928, + "ancing": 7929, + "▁owner": 7930, + "▁Ter": 7931, + "▁Did": 7932, + "▁gest": 7933, + "▁été": 7934, + "▁proof": 7935, + "Font": 7936, + "▁nob": 7937, + "Co": 7938, + "▁GNU": 7939, + "▁liber": 7940, + "itness": 7941, + "▁hij": 7942, + "▁vert": 7943, + "ша": 7944, + "FLAG": 7945, + "MENT": 7946, + "▁Son": 7947, + "Mult": 7948, + "▁district": 7949, + "connect": 7950, + "jection": 7951, + "lymp": 7952, + "▁realized": 7953, + "mos": 7954, + "ye": 7955, + "▁render": 7956, + "rio": 7957, + "▁interpret": 7958, + "▁slightly": 7959, + "fix": 7960, + "▁studies": 7961, + "▁rid": 7962, + "atre": 7963, + "▁benefits": 7964, + "▁Face": 7965, + "ivery": 7966, + "рия": 7967, + "document": 7968, + "▁asking": 7969, + "Last": 7970, + "arante": 7971, + "▁Martin": 7972, + "▁Ell": 7973, + "▁vector": 7974, + "▁forced": 7975, + "оло": 7976, + "PH": 7977, + "WR": 7978, + "▁Kl": 7979, + "▁sky": 7980, + "▁strategy": 7981, + "ocked": 7982, + "▁neck": 7983, + "ści": 7984, + "OUT": 7985, + ")),": 7986, + "Custom": 7987, + "▁wie": 7988, + "▁sweet": 7989, + "▁temp": 7990, + "▁foreign": 7991, + "▁hall": 7992, + "astr": 7993, + "Ass": 7994, + "MODE": 7995, + "▁maximum": 7996, + "annels": 7997, + "▁tip": 7998, + "▁seconds": 7999, + "▁stack": 8000, + "iga": 8001, + "▁raise": 8002, + "enable": 8003, + "oir": 8004, + "▁soul": 8005, + "Ke": 8006, + ")$.": 8007, + "▁Tim": 8008, + "ALSE": 8009, + "iser": 8010, + "contin": 8011, + "bel": 8012, + "▁mad": 8013, + "lichen": 8014, + "abe": 8015, + "safe": 8016, + "▁concent": 8017, + "bound": 8018, + "▁Requ": 8019, + "switch": 8020, + "▁stone": 8021, + "▁transl": 8022, + "▁vac": 8023, + "andon": 8024, + "▁Fore": 8025, + "▁sounds": 8026, + "▁Pop": 8027, + "▁HT": 8028, + "lia": 8029, + "enter": 8030, + "▁helps": 8031, + "edy": 8032, + "ствен": 8033, + "anted": 8034, + "▁Its": 8035, + "▁Step": 8036, + "Icon": 8037, + "▁EXPECT": 8038, + "ialized": 8039, + "Post": 8040, + "aze": 8041, + "▁Carol": 8042, + "▁req": 8043, + "▁critical": 8044, + "DS": 8045, + "▁seat": 8046, + "aped": 8047, + "▁upper": 8048, + "▁Sy": 8049, + "▁explain": 8050, + "▁'./": 8051, + "utils": 8052, + "possible": 8053, + "▁dont": 8054, + "Host": 8055, + "▁approxim": 8056, + "Async": 8057, + "▁grab": 8058, + "▁sources": 8059, + "▁Mos": 8060, + "▁Germany": 8061, + "▁rub": 8062, + "CHAN": 8063, + "▁rain": 8064, + "▁truly": 8065, + "▁joined": 8066, + "▁": 9044, + "agnost": 9045, + "▁proposed": 9046, + "▁Game": 9047, + "▁efforts": 9048, + "вя": 9049, + "tc": 9050, + "ск": 9051, + "▁intent": 9052, + "▁Bre": 9053, + "isc": 9054, + "▁protest": 9055, + "▁holds": 9056, + "ometry": 9057, + "▁Have": 9058, + "▁detail": 9059, + "▁WITHOUT": 9060, + "yer": 9061, + "▁Kon": 9062, + "▁noticed": 9063, + "▁requirements": 9064, + "DEBUG": 9065, + "kins": 9066, + "▁Span": 9067, + "▁cars": 9068, + "meta": 9069, + "▁kil": 9070, + "▁Bron": 9071, + "▁experienced": 9072, + "▁remind": 9073, + "ourse": 9074, + "▁Western": 9075, + "tered": 9076, + "▁devices": 9077, + "▁pictures": 9078, + "▁tut": 9079, + "\"`": 9080, + "▁impossible": 9081, + "▁rail": 9082, + "▁feels": 9083, + "icas": 9084, + "illing": 9085, + "▁accident": 9086, + "▁'@": 9087, + "________": 9088, + "▁notes": 9089, + "oman": 9090, + "Parser": 9091, + "▁discovered": 9092, + "▁Roman": 9093, + "▁budget": 9094, + "▁guide": 9095, + "king": 9096, + "▁incred": 9097, + "olar": 9098, + "enden": 9099, + "Desc": 9100, + "▁wave": 9101, + "бли": 9102, + "igt": 9103, + "▁restrict": 9104, + "▁Ret": 9105, + "▁mac": 9106, + "ур": 9107, + "BS": 9108, + "ís": 9109, + "▁generation": 9110, + "dem": 9111, + "alo": 9112, + "бра": 9113, + "▁ordered": 9114, + "drop": 9115, + "▁pp": 9116, + "▁Review": 9117, + "▁literally": 9118, + "▁Sir": 9119, + "▁Yeah": 9120, + "▁density": 9121, + "riz": 9122, + "inde": 9123, + "▁gain": 9124, + "▁panel": 9125, + "jet": 9126, + "▁Times": 9127, + "▁nella": 9128, + "▁previously": 9129, + "points": 9130, + "Send": 9131, + "▁Brown": 9132, + "each": 9133, + "▁trigger": 9134, + "ometimes": 9135, + "icos": 9136, + "GR": 9137, + "Panel": 9138, + "ogen": 9139, + "▁cm": 9140, + "ructions": 9141, + "▁kiss": 9142, + "▁solo": 9143, + "▁famous": 9144, + "ran": 9145, + "про": 9146, + "▁thro": 9147, + "Graph": 9148, + "imit": 9149, + "▁Value": 9150, + "▁starts": 9151, + "ipeline": 9152, + "hd": 9153, + "TC": 9154, + "▁discussion": 9155, + "▁truck": 9156, + "aka": 9157, + "Only": 9158, + "▁Equ": 9159, + "▁kö": 9160, + "▁Bes": 9161, + "▁critic": 9162, + "▁propos": 9163, + "▁batt": 9164, + "▁Section": 9165, + "Show": 9166, + "gp": 9167, + "STATE": 9168, + "POST": 9169, + "▁Nord": 9170, + "▁innov": 9171, + "▁crim": 9172, + "axis": 9173, + "▁Turn": 9174, + "conn": 9175, + "Runtime": 9176, + "▁remaining": 9177, + "oston": 9178, + "▁Э": 9179, + "▁windows": 9180, + "▁Royal": 9181, + "▁vide": 9182, + "PP": 9183, + "chron": 9184, + "▁san": 9185, + "▁rise": 9186, + "▁delle": 9187, + "▁Dur": 9188, + "▁rapid": 9189, + "cert": 9190, + "LA": 9191, + "edge": 9192, + "▁\\]": 9193, + "▁entered": 9194, + "▁laws": 9195, + "▁photo": 9196, + "▁applications": 9197, + "▁Berlin": 9198, + "▁arrest": 9199, + "▁federal": 9200, + "▁Russia": 9201, + "▁usual": 9202, + "▁raw": 9203, + "▁più": 9204, + "être": 9205, + "JSON": 9206, + "SION": 9207, + "xture": 9208, + "istent": 9209, + "▁Power": 9210, + "Bit": 9211, + "▁capacity": 9212, + "▁cards": 9213, + "UID": 9214, + "iments": 9215, + "▁dar": 9216, + "▁Chicago": 9217, + "▁comfortable": 9218, + "tip": 9219, + "bas": 9220, + "▁mu": 9221, + "▁enemy": 9222, + "yan": 9223, + "▁фи": 9224, + "▁updated": 9225, + "ango": 9226, + "Ev": 9227, + "Effect": 9228, + "osing": 9229, + "rence": 9230, + "▁Congress": 9231, + "▁defe": 9232, + "▁ip": 9233, + "▁tout": 9234, + "▁freedom": 9235, + "▁ao": 9236, + "▁Therefore": 9237, + "Edit": 9238, + "▁Virgin": 9239, + "REE": 9240, + "argo": 9241, + "▁Dam": 9242, + "▁traffic": 9243, + "ños": 9244, + "▁alle": 9245, + "▁depth": 9246, + "Now": 9247, + "▁sides": 9248, + "▁годи": 9249, + "Descriptor": 9250, + "▁artikel": 9251, + "▁narrow": 9252, + "___": 9253, + "kw": 9254, + "uto": 9255, + "▁Facebook": 9256, + "tegr": 9257, + "boolean": 9258, + "nik": 9259, + "bd": 9260, + "Track": 9261, + "▁gran": 9262, + "reshold": 9263, + "вет": 9264, + "wrap": 9265, + "▁noise": 9266, + "igu": 9267, + "▁Bon": 9268, + "▁wy": 9269, + "linux": 9270, + "cks": 9271, + "▁fans": 9272, + "▁mach": 9273, + "▁prices": 9274, + "év": 9275, + "outs": 9276, + "standing": 9277, + "▁categ": 9278, + ";\\": 9279, + "▁decre": 9280, + "▁Saturday": 9281, + "▁menu": 9282, + "▁Nov": 9283, + "▁Yet": 9284, + "▁так": 9285, + "liche": 9286, + "▁Academ": 9287, + "▁communication": 9288, + "using": 9289, + "▁Society": 9290, + "▁nuc": 9291, + "pective": 9292, + "orial": 9293, + "▁afraid": 9294, + "▁animal": 9295, + "▁turning": 9296, + "dst": 9297, + "mathfrak": 9298, + "lers": 9299, + "▁lots": 9300, + "▁á": 9301, + "▁Tra": 9302, + "np": 9303, + "▁rose": 9304, + "▁GL": 9305, + "▁helping": 9306, + "▁winter": 9307, + "▁ком": 9308, + "Mock": 9309, + "▁investment": 9310, + "Use": 9311, + "▁Canad": 9312, + "нд": 9313, + "Copy": 9314, + "▁fly": 9315, + "SER": 9316, + "▁Far": 9317, + "▁Ros": 9318, + "amil": 9319, + "▁fighting": 9320, + "▁religious": 9321, + "super": 9322, + "screen": 9323, + "▁furn": 9324, + "▁surprised": 9325, + "▁replied": 9326, + "Activity": 9327, + "▁Down": 9328, + "▁insert": 9329, + "▁Olymp": 9330, + "▁pointed": 9331, + "▁Card": 9332, + "driver": 9333, + "▁Da": 9334, + "!--": 9335, + "roud": 9336, + "undo": 9337, + "▁messages": 9338, + "▁Point": 9339, + "VM": 9340, + "▁plane": 9341, + "xc": 9342, + "▁television": 9343, + "ён": 9344, + "▁thousands": 9345, + "▁cris": 9346, + "▁delay": 9347, + "▁Next": 9348, + "▁nombre": 9349, + "▁tu": 9350, + "▁skip": 9351, + "road": 9352, + "istration": 9353, + "▁tur": 9354, + "▁Develop": 9355, + "▁Па": 9356, + "▁дру": 9357, + "▁wonderful": 9358, + ">&": 9359, + "▁Liber": 9360, + "▁scope": 9361, + "▁manage": 9362, + "▁dass": 9363, + "▁recall": 9364, + "PM": 9365, + "▁relevant": 9366, + "▁Earth": 9367, + "▁как": 9368, + "▁apr": 9369, + "▁ASS": 9370, + "ién": 9371, + "▁SH": 9372, + "oom": 9373, + "itet": 9374, + "none": 9375, + "asi": 9376, + "▁motor": 9377, + "▁Show": 9378, + "nb": 9379, + "▁factors": 9380, + "▁forest": 9381, + "▁вре": 9382, + "thm": 9383, + "▁municip": 9384, + "▁turns": 9385, + "▁Division": 9386, + "EC": 9387, + "▁disappe": 9388, + "structor": 9389, + "▁somewhere": 9390, + "▁African": 9391, + "▁Institute": 9392, + "Grid": 9393, + "▁teacher": 9394, + "uries": 9395, + "▁respectively": 9396, + "▁SD": 9397, + "▁alive": 9398, + "▁pou": 9399, + "▁Water": 9400, + "фе": 9401, + "▁changing": 9402, + "▁afternoon": 9403, + "▁orders": 9404, + "Ret": 9405, + "Pointer": 9406, + "▁sav": 9407, + "erg": 9408, + "oked": 9409, + "essions": 9410, + "▁Fire": 9411, + "aret": 9412, + "imm": 9413, + "▁desire": 9414, + "▁що": 9415, + "▁Design": 9416, + "uture": 9417, + "▁Office": 9418, + "▁cmd": 9419, + "▁eating": 9420, + "Network": 9421, + "▁rough": 9422, + "operator": 9423, + "IGN": 9424, + "▁sports": 9425, + "▁weren": 9426, + "▁noted": 9427, + "▁twice": 9428, + "III": 9429, + "▁anx": 9430, + "▁elim": 9431, + "▁ав": 9432, + "▁io": 9433, + "▁speech": 9434, + "▁condu": 9435, + "elles": 9436, + "idade": 9437, + "▁advance": 9438, + "RI": 9439, + "oca": 9440, + "/\\": 9441, + "apshot": 9442, + "▁tail": 9443, + "models": 9444, + "ogy": 9445, + "▁Jeff": 9446, + "iration": 9447, + "▁Kore": 9448, + "▁leads": 9449, + "bat": 9450, + "Adapter": 9451, + "category": 9452, + "angular": 9453, + "▁saved": 9454, + "▁uniform": 9455, + "▁né": 9456, + "▁businesses": 9457, + "Hist": 9458, + "▁ар": 9459, + "domain": 9460, + "▁Si": 9461, + "raise": 9462, + "▁warn": 9463, + "hetic": 9464, + "▁Gro": 9465, + ")).": 9466, + "}>": 9467, + "зе": 9468, + "▁Amazon": 9469, + "▁Organ": 9470, + "▁Lake": 9471, + "▁agreement": 9472, + "xa": 9473, + "▁perman": 9474, + "▁containing": 9475, + "▁strange": 9476, + "сті": 9477, + "▁stupid": 9478, + "▁speaking": 9479, + "▁Internet": 9480, + "prefix": 9481, + "esc": 9482, + "Assert": 9483, + "prote": 9484, + "▁manner": 9485, + "▁Sz": 9486, + "unte": 9487, + "iot": 9488, + "Profile": 9489, + "oven": 9490, + "▁formed": 9491, + "▁lit": 9492, + "▁economy": 9493, + "▁cz": 9494, + "wid": 9495, + "REQ": 9496, + "▁chosen": 9497, + "▁Produ": 9498, + "oster": 9499, + "stances": 9500, + "awa": 9501, + "▁Ren": 9502, + "▁confirm": 9503, + "▁Бо": 9504, + "▁billion": 9505, + "▁déc": 9506, + "ých": 9507, + "▁illustr": 9508, + "TIES": 9509, + "▁Pub": 9510, + "▁ban": 9511, + "aded": 9512, + "ahn": 9513, + "▁Cath": 9514, + "nonumber": 9515, + "▁worst": 9516, + "▁Ме": 9517, + "▁suggested": 9518, + "stats": 9519, + "▁cant": 9520, + "▁align": 9521, + "kappa": 9522, + "▁hen": 9523, + "▁initi": 9524, + "'])": 9525, + "BI": 9526, + "▁garden": 9527, + "▁secure": 9528, + "▁\\[": 9529, + "handler": 9530, + "elli": 9531, + "ldots": 9532, + "secut": 9533, + "▁extended": 9534, + "}-": 9535, + "anie": 9536, + "▁Find": 9537, + "▁Museum": 9538, + "▁Conne": 9539, + "yy": 9540, + "▁passion": 9541, + "akers": 9542, + "ahr": 9543, + "ologies": 9544, + "▁equation": 9545, + "▁occasion": 9546, + "Let": 9547, + "']['": 9548, + "Print": 9549, + "anes": 9550, + "iente": 9551, + "▁Today": 9552, + "LECT": 9553, + "▁Af": 9554, + ",,": 9555, + "▁Та": 9556, + "▁```": 9557, + "even": 9558, + "sin": 9559, + "urer": 9560, + "▁°": 9561, + "otimes": 9562, + "▁IO": 9563, + "▁poet": 9564, + "()));": 9565, + "▁−": 9566, + "▁adopt": 9567, + "phere": 9568, + "#[": 9569, + "▁centre": 9570, + "oves": 9571, + "▁ans": 9572, + "dp": 9573, + "▁Kir": 9574, + "▁applicable": 9575, + "fp": 9576, + "▁visual": 9577, + "▁okay": 9578, + "oro": 9579, + "▁opportunities": 9580, + "Repository": 9581, + "▁ll": 9582, + "▁Rod": 9583, + "▁shel": 9584, + "▁launch": 9585, + "▁conven": 9586, + "▁Spe": 9587, + "Amer": 9588, + "▁cette": 9589, + "Cond": 9590, + "dep": 9591, + "Own": 9592, + "▁hook": 9593, + "▁dict": 9594, + "▁Those": 9595, + "▁fellow": 9596, + "▁philosoph": 9597, + "vin": 9598, + "ferences": 9599, + "hav": 9600, + "▁adding": 9601, + "iverse": 9602, + "game": 9603, + "▁Blue": 9604, + "▁clin": 9605, + "note": 9606, + "▁Ram": 9607, + "мер": 9608, + "covery": 9609, + "ña": 9610, + "▁би": 9611, + "▁fashion": 9612, + "▁broke": 9613, + "▁'\\": 9614, + "▁reader": 9615, + "ное": 9616, + "ности": 9617, + "▁payment": 9618, + "▁Lic": 9619, + "▁lips": 9620, + "▁academ": 9621, + "▁Mot": 9622, + "ells": 9623, + "CHECK": 9624, + "▁ру": 9625, + "▁MS": 9626, + "Editor": 9627, + "▁zone": 9628, + "iture": 9629, + "▁IT": 9630, + "runtime": 9631, + "▁proceed": 9632, + "лов": 9633, + "▁Maria": 9634, + "olver": 9635, + "▁Thanks": 9636, + "▁shouldn": 9637, + "▁Joh": 9638, + "▁Model": 9639, + "▁Sov": 9640, + "!'": 9641, + "Di": 9642, + "▁cancer": 9643, + "Ident": 9644, + "▁exchange": 9645, + "iller": 9646, + "inf": 9647, + "LEN": 9648, + "(){": 9649, + "aga": 9650, + "\"],": 9651, + "uh": 9652, + "▁Ken": 9653, + "▁photos": 9654, + "▁tiny": 9655, + "▁gent": 9656, + "ül": 9657, + "▁Take": 9658, + "idel": 9659, + "outing": 9660, + "Internal": 9661, + "▁cells": 9662, + "ним": 9663, + "hard": 9664, + "▁Town": 9665, + "obe": 9666, + "plex": 9667, + "тер": 9668, + "tons": 9669, + "▁concentr": 9670, + "mock": 9671, + "vc": 9672, + "áz": 9673, + "▁Championship": 9674, + "▁бе": 9675, + "??": 9676, + "éri": 9677, + "aly": 9678, + "▁Ц": 9679, + "ierte": 9680, + "▁totally": 9681, + "▁Auf": 9682, + "▁ourselves": 9683, + "▁Self": 9684, + "Forms": 9685, + "ighter": 9686, + "▁island": 9687, + "fmt": 9688, + "▁rc": 9689, + "▁tells": 9690, + "BB": 9691, + "dit": 9692, + "▁variables": 9693, + "▁intended": 9694, + "izont": 9695, + "▁plays": 9696, + "dam": 9697, + "seq": 9698, + "▁Sup": 9699, + "▁cultural": 9700, + "▁scream": 9701, + "__,": 9702, + "cipl": 9703, + "Timeout": 9704, + "▁ж": 9705, + "orte": 9706, + "▁replaced": 9707, + "EM": 9708, + "▁abandon": 9709, + "▁Special": 9710, + "ellen": 9711, + "▁Bru": 9712, + "irmed": 9713, + "Te": 9714, + "olt": 9715, + "ju": 9716, + "Argument": 9717, + "▁neut": 9718, + "scape": 9719, + "▁Ray": 9720, + "▁Polit": 9721, + "▁crowd": 9722, + "▁Windows": 9723, + "iego": 9724, + "▁escape": 9725, + "▁Apache": 9726, + "sync": 9727, + "eben": 9728, + "ifies": 9729, + "ether": 9730, + "Meta": 9731, + "▁biggest": 9732, + "Game": 9733, + "▁transaction": 9734, + "Env": 9735, + "▁Мо": 9736, + "▁plenty": 9737, + "▁mel": 9738, + "пре": 9739, + "▁motiv": 9740, + "▁ор": 9741, + "organ": 9742, + "▁mock": 9743, + "▁$_": 9744, + "ене": 9745, + "▁Number": 9746, + "cknow": 9747, + "▁Update": 9748, + "zero": 9749, + "▁surprise": 9750, + "cean": 9751, + "pdf": 9752, + "Global": 9753, + "▁attend": 9754, + "▁fond": 9755, + "▁understood": 9756, + "Nav": 9757, + "▁Mic": 9758, + "=$": 9759, + "oking": 9760, + "▁Stadium": 9761, + "Close": 9762, + "▁competition": 9763, + "▁soldiers": 9764, + "▁OP": 9765, + "agne": 9766, + "▁Anton": 9767, + "Main": 9768, + "ák": 9769, + "▁#[": 9770, + "▁Commit": 9771, + "pyx": 9772, + "▁east": 9773, + "▁Order": 9774, + "Float": 9775, + "▁accepted": 9776, + "▁monitor": 9777, + "▁pad": 9778, + "onic": 9779, + "▁pushed": 9780, + "▁replace": 9781, + "CRE": 9782, + "▁ride": 9783, + "found": 9784, + "=%": 9785, + "вой": 9786, + "▁matches": 9787, + "▁Lie": 9788, + "▁experiences": 9789, + "Pool": 9790, + "ups": 9791, + "AV": 9792, + "▁existence": 9793, + "▁thin": 9794, + "▁magn": 9795, + "COMP": 9796, + "home": 9797, + "▁ni": 9798, + "▁wurden": 9799, + "лав": 9800, + "▁teeth": 9801, + "▁Stan": 9802, + "appro": 9803, + "anny": 9804, + "ifts": 9805, + "▁unknown": 9806, + "▁homes": 9807, + "▁entity": 9808, + "cie": 9809, + "ление": 9810, + "iar": 9811, + "▁compliance": 9812, + "▁focused": 9813, + "uzz": 9814, + "=\\\"": 9815, + "components": 9816, + "Attr": 9817, + "allery": 9818, + "▁identify": 9819, + "Ok": 9820, + "pie": 9821, + "▁Still": 9822, + "▁offering": 9823, + "▁busy": 9824, + "ctl": 9825, + "itors": 9826, + "▁concerned": 9827, + "▁brown": 9828, + "clk": 9829, + "Selected": 9830, + "▁Block": 9831, + "▁egy": 9832, + "icing": 9833, + "▁URL": 9834, + "▁topic": 9835, + "▁Product": 9836, + "▁чи": 9837, + "▁trial": 9838, + "▁weekend": 9839, + "lu": 9840, + "▁IV": 9841, + "▁Egy": 9842, + "xC": 9843, + "▁nove": 9844, + "▁lett": 9845, + "enne": 9846, + "()).": 9847, + ".**": 9848, + "▁promise": 9849, + "election": 9850, + "Auth": 9851, + "rv": 9852, + "ril": 9853, + "▁conduct": 9854, + "▁maintain": 9855, + "▁boat": 9856, + "▁opposite": 9857, + "spin": 9858, + "webpack": 9859, + "anta": 9860, + "▁orient": 9861, + "▁suc": 9862, + "▁exercise": 9863, + "▁efficient": 9864, + "▁tradition": 9865, + "▁zw": 9866, + "▁Sud": 9867, + "going": 9868, + "▁Pier": 9869, + "inv": 9870, + "ipes": 9871, + "ensuremath": 9872, + "▁conver": 9873, + "creen": 9874, + "▁terror": 9875, + "▁Dou": 9876, + "▁invalid": 9877, + "ceived": 9878, + "▁Arab": 9879, + "▁wire": 9880, + "application": 9881, + "shift": 9882, + "Generic": 9883, + "▁Plan": 9884, + "▁Wall": 9885, + "▁directory": 9886, + "▁egg": 9887, + "▁wealth": 9888, + "random": 9889, + "attribute": 9890, + "▁hide": 9891, + "Serial": 9892, + "cam": 9893, + "▁ital": 9894, + "▁Line": 9895, + "▁CHECK": 9896, + "ployment": 9897, + "▁massive": 9898, + "▁extract": 9899, + "chain": 9900, + "Rest": 9901, + "▁Las": 9902, + "▁bear": 9903, + "▁links": 9904, + "▁newsp": 9905, + "▁FC": 9906, + "Card": 9907, + "aks": 9908, + "▁visible": 9909, + "▁Marc": 9910, + "▁Boston": 9911, + "▁reserved": 9912, + "▁roof": 9913, + "licenses": 9914, + "dc": 9915, + "▁Information": 9916, + "▁witness": 9917, + "Sk": 9918, + "*),": 9919, + "Scope": 9920, + "'];": 9921, + "▁Mir": 9922, + "uding": 9923, + "▁trend": 9924, + "rep": 9925, + "▁musical": 9926, + "▁neither": 9927, + "▁Creat": 9928, + "▁positions": 9929, + "LC": 9930, + "ridge": 9931, + "▁officers": 9932, + "▁violence": 9933, + "▁Tem": 9934, + "▁Sus": 9935, + "▁Way": 9936, + "After": 9937, + "acket": 9938, + "▁Sou": 9939, + "acer": 9940, + "||": 9941, + "▁remark": 9942, + "water": 9943, + "ně": 9944, + "▁Са": 9945, + "▁sed": 9946, + "Each": 9947, + "▁photograph": 9948, + "▁letters": 9949, + "▁invent": 9950, + "▁Mas": 9951, + "▁songs": 9952, + "ól": 9953, + "kind": 9954, + "▁Non": 9955, + "▁dust": 9956, + "**:": 9957, + "nabla": 9958, + ".\",": 9959, + "Lock": 9960, + "▁До": 9961, + "▁cluster": 9962, + "loss": 9963, + "▁ASSERT": 9964, + "fall": 9965, + "▁reject": 9966, + "▁Spring": 9967, + "▁wedding": 9968, + "▁grav": 9969, + "ression": 9970, + "limit": 9971, + "RES": 9972, + "]}": 9973, + "▁listed": 9974, + "▁Tele": 9975, + "hline": 9976, + "▁chief": 9977, + "MEM": 9978, + "дар": 9979, + "▁expensive": 9980, + "trace": 9981, + "▁Rog": 9982, + "▁Coll": 9983, + "▁Author": 9984, + "▁Board": 9985, + "▁Capt": 9986, + "TEXT": 9987, + "▁recon": 9988, + "esta": 9989, + "▁properly": 9990, + "▁&\\": 9991, + "leton": 9992, + "iker": 9993, + "Gu": 9994, + "▁Kom": 9995, + "oco": 9996, + "▁anymore": 9997, + "▁taste": 9998, + "▁Santa": 9999, + "gex": 10000, + "▁Secret": 10001, + "▁talent": 10002, + "▁moments": 10003, + "▁Ba": 10004, + "▁extr": 10005, + "▁Commission": 10006, + "▁modify": 10007, + "▁Figure": 10008, + "▁domin": 10009, + "▁plot": 10010, + "enger": 10011, + "utch": 10012, + "▁cities": 10013, + "▁nut": 10014, + "profile": 10015, + "▁Stat": 10016, + "▁nodes": 10017, + "▁ns": 10018, + "essages": 10019, + "impl": 10020, + "icker": 10021, + "▁examples": 10022, + "abeth": 10023, + "▁stated": 10024, + "fire": 10025, + "bul": 10026, + "▁dangerous": 10027, + "▁Pay": 10028, + "▁Gre": 10029, + "▁Monday": 10030, + "esome": 10031, + "igan": 10032, + "rund": 10033, + "prise": 10034, + "fail": 10035, + "▁Never": 10036, + "Av": 10037, + "▁linear": 10038, + "▁ul": 10039, + "WAR": 10040, + "рен": 10041, + "▁AT": 10042, + "▁dop": 10043, + "▁nou": 10044, + "Dest": 10045, + "▁claims": 10046, + "enda": 10047, + "▁crazy": 10048, + "gel": 10049, + "oggle": 10050, + "▁representation": 10051, + "inen": 10052, + "▁alternative": 10053, + "DM": 10054, + "ABILITY": 10055, + "faces": 10056, + "▁doors": 10057, + "ativ": 10058, + "Look": 10059, + "▁JSON": 10060, + "▁appearance": 10061, + "бря": 10062, + "SQL": 10063, + "▁silence": 10064, + "udo": 10065, + "▁Director": 10066, + "Statement": 10067, + "selected": 10068, + "high": 10069, + "prime": 10070, + "▁ignore": 10071, + "▁colors": 10072, + "ushing": 10073, + "▁virt": 10074, + "manager": 10075, + "▁remote": 10076, + "ło": 10077, + "small": 10078, + "▁crime": 10079, + "rb": 10080, + "▁creation": 10081, + "▁flight": 10082, + "▁Sign": 10083, + "ILE": 10084, + "▁DO": 10085, + "comment": 10086, + "▁Cost": 10087, + ".__": 10088, + "▁Cop": 10089, + "▁vom": 10090, + "▁Science": 10091, + "ления": 10092, + "oop": 10093, + "interface": 10094, + "▁WARRANTIES": 10095, + "▁Page": 10096, + "******": 10097, + "ском": 10098, + "TRUE": 10099, + "▁repeated": 10100, + "▁его": 10101, + "шо": 10102, + "▁roz": 10103, + "Pe": 10104, + "▁ISBN": 10105, + "irts": 10106, + "poses": 10107, + "})$": 10108, + "▁І": 10109, + "children": 10110, + "bles": 10111, + "ECT": 10112, + "▁iz": 10113, + "▁builder": 10114, + "▁Media": 10115, + "iat": 10116, + "▁contrast": 10117, + "”,": 10118, + "▁Link": 10119, + "▁Education": 10120, + "▁joint": 10121, + "▁external": 10122, + "▁роз": 10123, + "▁bits": 10124, + "FORM": 10125, + "erman": 10126, + "wp": 10127, + "▁Mike": 10128, + "▁Master": 10129, + "▁senior": 10130, + "▁Nav": 10131, + "▁recorded": 10132, + "eling": 10133, + "esh": 10134, + "fx": 10135, + "кан": 10136, + "▁tall": 10137, + "▁Johnson": 10138, + "▁sono": 10139, + "▁anche": 10140, + "icken": 10141, + "loop": 10142, + "iciency": 10143, + "emporary": 10144, + "▁Does": 10145, + "▁relation": 10146, + "мы": 10147, + "was": 10148, + "low": 10149, + "ichte": 10150, + "▁Jones": 10151, + "▁bedroom": 10152, + "DIS": 10153, + "▁magnet": 10154, + "▁Engine": 10155, + "▁feelings": 10156, + "GC": 10157, + "▁torn": 10158, + "▁relationships": 10159, + "▁Ре": 10160, + "▁proud": 10161, + "▁twe": 10162, + "oval": 10163, + "▁waste": 10164, + "▁reduced": 10165, + "ilton": 10166, + "BP": 10167, + "▁forgot": 10168, + "▁bodies": 10169, + "▁Haw": 10170, + "lag": 10171, + "▁www": 10172, + "door": 10173, + "▁sufficient": 10174, + "▁dollars": 10175, + "Len": 10176, + "▁talked": 10177, + "▁bond": 10178, + "▁Bor": 10179, + "}}{": 10180, + "rod": 10181, + "Password": 10182, + "quare": 10183, + "▁lights": 10184, + "eren": 10185, + "▁thirty": 10186, + "NC": 10187, + "▁TODO": 10188, + "▁respond": 10189, + "ких": 10190, + "direct": 10191, + "ação": 10192, + "▁heav": 10193, + "Media": 10194, + "exit": 10195, + "License": 10196, + "`.": 10197, + "▁mixed": 10198, + "▁desk": 10199, + "▁teaching": 10200, + "▁maj": 10201, + "▁nerv": 10202, + "inations": 10203, + "typeof": 10204, + "▁coast": 10205, + "▁же": 10206, + "▁beside": 10207, + "ummy": 10208, + "Doc": 10209, + "▁schedule": 10210, + "▁recover": 10211, + "▁Further": 10212, + "▁steel": 10213, + "boot": 10214, + "▁Perhaps": 10215, + "▁съ": 10216, + "▁Os": 10217, + "rick": 10218, + "▁Ви": 10219, + "Support": 10220, + "▁(_": 10221, + "nil": 10222, + "pis": 10223, + "xpected": 10224, + "▁processing": 10225, + "Build": 10226, + "arian": 10227, + "▁icon": 10228, + "▁CA": 10229, + "wick": 10230, + "=(": 10231, + "▁algorithm": 10232, + "▁Young": 10233, + "▁Management": 10234, + "▁ancient": 10235, + "ность": 10236, + "oti": 10237, + "▁combination": 10238, + "world": 10239, + "nn": 10240, + "▁dram": 10241, + "enabled": 10242, + "Ac": 10243, + "CCESS": 10244, + "aration": 10245, + "▁blocks": 10246, + "▁Angeles": 10247, + "▁Qual": 10248, + "▁succeed": 10249, + "network": 10250, + "▁oblig": 10251, + "springframework": 10252, + "▁Tre": 10253, + "okes": 10254, + "mun": 10255, + "▁Network": 10256, + "Del": 10257, + "▁estate": 10258, + "▁liqu": 10259, + "▁pob": 10260, + "▁dad": 10261, + "▁distinct": 10262, + "▁Tit": 10263, + "▁Lear": 10264, + "ferred": 10265, + "android": 10266, + "▁subsequ": 10267, + "▁Florida": 10268, + "subset": 10269, + "▁whisper": 10270, + "Vol": 10271, + "ulous": 10272, + "▁crew": 10273, + "▁lug": 10274, + "pid": 10275, + "ocity": 10276, + "skb": 10277, + "▁tea": 10278, + "ун": 10279, + "▁honor": 10280, + "▁Ins": 10281, + "▁gew": 10282, + "Details": 10283, + "eneath": 10284, + "atar": 10285, + "▁_{": 10286, + "amen": 10287, + "▁setup": 10288, + "Transaction": 10289, + "▁blank": 10290, + "Failed": 10291, + "job": 10292, + "▁pret": 10293, + "ße": 10294, + "loor": 10295, + "ří": 10296, + "ncia": 10297, + "▁anywhere": 10298, + "▁Light": 10299, + "▁Ak": 10300, + "BD": 10301, + "▁excited": 10302, + "agers": 10303, + "▁warning": 10304, + "▁processes": 10305, + "hu": 10306, + "▁youth": 10307, + "▁dogs": 10308, + "▁oct": 10309, + "▁nine": 10310, + "Writer": 10311, + "grid": 10312, + "▁importance": 10313, + "estic": 10314, + "▁carefully": 10315, + "master": 10316, + "▁decisions": 10317, + "▁pin": 10318, + "▁crack": 10319, + "TEST": 10320, + "▁Local": 10321, + "▁Right": 10322, + "▁vast": 10323, + "▁faster": 10324, + "▁institut": 10325, + "▁annual": 10326, + "LAN": 10327, + "▁episode": 10328, + "▁XV": 10329, + "▁delivery": 10330, + "tl": 10331, + "FP": 10332, + "circ": 10333, + "▁typically": 10334, + "igo": 10335, + "▁intel": 10336, + "nat": 10337, + "xb": 10338, + "стро": 10339, + ")-": 10340, + "▁Bal": 10341, + "▁Jos": 10342, + "▁gonna": 10343, + "▁Rest": 10344, + "jor": 10345, + "onia": 10346, + "orship": 10347, + "overy": 10348, + "LINE": 10349, + "]:": 10350, + "Queue": 10351, + "▁compare": 10352, + "▁apartment": 10353, + "▁rul": 10354, + "Dr": 10355, + "gency": 10356, + "▁obviously": 10357, + "zie": 10358, + "ycl": 10359, + "fortunately": 10360, + "▁stepped": 10361, + "▁Seg": 10362, + "▁Which": 10363, + "▁PC": 10364, + "▁ast": 10365, + "endor": 10366, + "▁permission": 10367, + "COL": 10368, + "▁TEST": 10369, + "Pay": 10370, + "ères": 10371, + "▁studied": 10372, + "▁accompl": 10373, + "role": 10374, + "Where": 10375, + "protobuf": 10376, + "metadata": 10377, + "Job": 10378, + "▁Four": 10379, + "plements": 10380, + "disable": 10381, + "▁loud": 10382, + "▁happening": 10383, + "▁Using": 10384, + "rog": 10385, + "▁depends": 10386, + "ím": 10387, + "'\\": 10388, + "▁taught": 10389, + "shared": 10390, + "▁attributes": 10391, + "▁Action": 10392, + "▁dess": 10393, + "▁houses": 10394, + "▁reset": 10395, + "▁bien": 10396, + "▁explicit": 10397, + "LOW": 10398, + "->_": 10399, + "▁PM": 10400, + "Category": 10401, + "oice": 10402, + "into": 10403, + "▁mail": 10404, + "▁authority": 10405, + "▁unable": 10406, + "filename": 10407, + "ék": 10408, + "лей": 10409, + "▁sector": 10410, + "appoint": 10411, + "▁hang": 10412, + "▁cel": 10413, + "related": 10414, + "itate": 10415, + "▁'<": 10416, + "amber": 10417, + "▁cheap": 10418, + "▁enabled": 10419, + "▁division": 10420, + "Any": 10421, + "▁hier": 10422, + "▁Head": 10423, + "ntax": 10424, + "uda": 10425, + "▁limitations": 10426, + "▁studio": 10427, + "media": 10428, + "▁circle": 10429, + "нова": 10430, + "▁laug": 10431, + "acts": 10432, + "▁Во": 10433, + "ód": 10434, + "pled": 10435, + "LOC": 10436, + "Expr": 10437, + ">:": 10438, + "▁prés": 10439, + "▁laughed": 10440, + "▁Three": 10441, + "лы": 10442, + "▁ends": 10443, + "▁fundament": 10444, + "▁inher": 10445, + "▁liv": 10446, + "bid": 10447, + "▁responsibility": 10448, + "▁checked": 10449, + "▁Pac": 10450, + "▁fault": 10451, + "▁yellow": 10452, + "▁salt": 10453, + "▁Francisco": 10454, + "▁^": 10455, + "▁ON": 10456, + "▁beauty": 10457, + "yg": 10458, + "▁Aff": 10459, + "▁Eq": 10460, + "▁magic": 10461, + "▁handler": 10462, + "xE": 10463, + "▁numerous": 10464, + "▁hole": 10465, + "▁rooms": 10466, + "cción": 10467, + "▁Arm": 10468, + "person": 10469, + "▁buildings": 10470, + "▁plate": 10471, + "bled": 10472, + "errors": 10473, + "▁Again": 10474, + "▁Default": 10475, + "▁Hard": 10476, + "tó": 10477, + "hus": 10478, + "▁dimension": 10479, + "iale": 10480, + "▁Mult": 10481, + "▁Government": 10482, + "Func": 10483, + "▁blow": 10484, + "▁rect": 10485, + "erra": 10486, + "connection": 10487, + "▁passing": 10488, + "ßen": 10489, + "phas": 10490, + "ensional": 10491, + "record": 10492, + "cohol": 10493, + "▁Harry": 10494, + "izontal": 10495, + "▁finger": 10496, + "▁younger": 10497, + "▁SC": 10498, + "operation": 10499, + "BY": 10500, + "heim": 10501, + "▁Bad": 10502, + "▁storm": 10503, + "▁Nat": 10504, + "▁buying": 10505, + "▁Sometimes": 10506, + "▁Ста": 10507, + "essed": 10508, + "▁damn": 10509, + "▁meg": 10510, + "umes": 10511, + "ünd": 10512, + "тра": 10513, + "▁silver": 10514, + "wd": 10515, + "hidden": 10516, + "ardo": 10517, + "▁communities": 10518, + "▁diet": 10519, + "otted": 10520, + "▁bat": 10521, + "ancer": 10522, + "▁fmt": 10523, + "▁Pen": 10524, + "▁til": 10525, + "Enum": 10526, + "PATH": 10527, + "▁matters": 10528, + "timeout": 10529, + "------------": 10530, + "kan": 10531, + "▁Corpor": 10532, + "=\"../../": 10533, + "▁Ale": 10534, + "hentication": 10535, + "▁complic": 10536, + "▁Security": 10537, + "OFF": 10538, + "Rad": 10539, + "apse": 10540, + "▁dance": 10541, + "▁permissions": 10542, + "▁warrant": 10543, + "▁lad": 10544, + "▁isol": 10545, + "dl": 10546, + "▁Au": 10547, + "yes": 10548, + "▁tv": 10549, + "▁provider": 10550, + "▁terrible": 10551, + "▁department": 10552, + "eral": 10553, + "▁implementation": 10554, + "SR": 10555, + "▁hearing": 10556, + "▁Kn": 10557, + "FR": 10558, + "tv": 10559, + "▁diss": 10560, + "FUN": 10561, + "▁durante": 10562, + "osis": 10563, + "▁tasks": 10564, + "▁Blo": 10565, + "вод": 10566, + "▁branch": 10567, + "▁politics": 10568, + "▁Elle": 10569, + "▁leadership": 10570, + "expr": 10571, + "▁techniques": 10572, + "prec": 10573, + "Sigma": 10574, + "imately": 10575, + "tk": 10576, + "achment": 10577, + "▁Enter": 10578, + "▁creative": 10579, + "▁зна": 10580, + "appy": 10581, + "unched": 10582, + "▁'',": 10583, + "onder": 10584, + "{-": 10585, + "NUM": 10586, + "▁narr": 10587, + "Memory": 10588, + "▁winning": 10589, + "▁Follow": 10590, + "*/\r": 10591, + "vision": 10592, + "resents": 10593, + "zione": 10594, + "▁latter": 10595, + "▁requests": 10596, + "▁margin": 10597, + "▁{\"": 10598, + "video": 10599, + "cn": 10600, + "▁Image": 10601, + "Tim": 10602, + "CONFIG": 10603, + "▁allowing": 10604, + "▁combined": 10605, + "PUT": 10606, + "▁instanceof": 10607, + "igin": 10608, + "▁pero": 10609, + "▁''": 10610, + "▁confidence": 10611, + "▁equivalent": 10612, + "pad": 10613, + "effect": 10614, + "RX": 10615, + "▁lang": 10616, + "strong": 10617, + "▁bridge": 10618, + "aya": 10619, + "▁treated": 10620, + "▁forth": 10621, + "SW": 10622, + "▁accounts": 10623, + "▁PO": 10624, + "▁listening": 10625, + "Route": 10626, + "()))": 10627, + "cpy": 10628, + "▁reform": 10629, + "▁gate": 10630, + "▁Walk": 10631, + "▁somehow": 10632, + "tf": 10633, + "▁layout": 10634, + "umin": 10635, + "▁considering": 10636, + "▁premi": 10637, + "▁Mom": 10638, + "athan": 10639, + "Gen": 10640, + "▁planet": 10641, + "amples": 10642, + "▁MO": 10643, + "shop": 10644, + "▁premier": 10645, + "▁simpl": 10646, + "▁segu": 10647, + "LY": 10648, + "Sum": 10649, + "▁tables": 10650, + "ska": 10651, + "▁ž": 10652, + "pd": 10653, + "▁sous": 10654, + "▁conference": 10655, + "▁Dat": 10656, + "Scroll": 10657, + "▁standards": 10658, + "▁гру": 10659, + "esse": 10660, + "▁citizens": 10661, + "▁occurred": 10662, + "▁democr": 10663, + "▁elev": 10664, + "▁Sem": 10665, + "ensus": 10666, + "headers": 10667, + "▁Chris": 10668, + "imento": 10669, + "kom": 10670, + "Cor": 10671, + "MIN": 10672, + "usher": 10673, + "Database": 10674, + "▁formal": 10675, + "igne": 10676, + "▁organizations": 10677, + "▁Ire": 10678, + "Xml": 10679, + "из": 10680, + "▁pray": 10681, + "▁bomb": 10682, + "▁mand": 10683, + "erts": 10684, + "▁clock": 10685, + "▁buck": 10686, + "вали": 10687, + "ensch": 10688, + "▁volt": 10689, + "▁films": 10690, + "▁plants": 10691, + "inode": 10692, + "Boolean": 10693, + "▁restaurant": 10694, + "ían": 10695, + "▁debut": 10696, + "pages": 10697, + "▁wordt": 10698, + "▁Ба": 10699, + "▁greatest": 10700, + "(\"/": 10701, + "▁copyright": 10702, + "▁rit": 10703, + "sizeof": 10704, + "Trace": 10705, + "uent": 10706, + "тур": 10707, + "▁ko": 10708, + ":\\": 10709, + "▁bigger": 10710, + "▁perfectly": 10711, + "tenance": 10712, + "MASK": 10713, + "ré": 10714, + "▁ett": 10715, + "▁nose": 10716, + "▁craft": 10717, + "iteral": 10718, + "▁discussed": 10719, + "▁Jewish": 10720, + "Cap": 10721, + "▁Unless": 10722, + "▁Jackson": 10723, + "Attributes": 10724, + "▁lunch": 10725, + "öl": 10726, + "atr": 10727, + "▁paying": 10728, + "Parse": 10729, + "()\r": 10730, + "lad": 10731, + "▁rare": 10732, + "▁[];": 10733, + "stone": 10734, + "▁unc": 10735, + "▁defense": 10736, + "}+": 10737, + "▁Global": 10738, + "▁Soviet": 10739, + "▁Australian": 10740, + "▁gli": 10741, + "variant": 10742, + "▁Ron": 10743, + "▁loan": 10744, + "Step": 10745, + "member": 10746, + "Sch": 10747, + "▁Committee": 10748, + "▁spending": 10749, + "▁Tri": 10750, + "▁Journal": 10751, + "▁sugar": 10752, + "elly": 10753, + "HTML": 10754, + "▁advent": 10755, + "wing": 10756, + "▁Whether": 10757, + "oration": 10758, + "▁NE": 10759, + "iveness": 10760, + "▁hav": 10761, + "▁conscious": 10762, + "een": 10763, + "Symbol": 10764, + "▁ку": 10765, + "Logger": 10766, + "▁Little": 10767, + "widet": 10768, + "ocation": 10769, + "pin": 10770, + "▁symmet": 10771, + "▁AD": 10772, + "▁posts": 10773, + "shal": 10774, + "▁Conf": 10775, + "▁chose": 10776, + "mal": 10777, + "ulo": 10778, + "▁Method": 10779, + "▁missed": 10780, + "Remove": 10781, + "Auto": 10782, + "VALUE": 10783, + "thlet": 10784, + "▁Force": 10785, + "pf": 10786, + "▁Я": 10787, + "late": 10788, + "▁pul": 10789, + "Pop": 10790, + "▁advanced": 10791, + "aires": 10792, + "ressed": 10793, + "AME": 10794, + "bell": 10795, + "aching": 10796, + "ić": 10797, + "echo": 10798, + "HS": 10799, + "▁funny": 10800, + "рии": 10801, + "▁eer": 10802, + "▁veget": 10803, + "▁fourth": 10804, + "cf": 10805, + "transform": 10806, + "▁grown": 10807, + "▁McC": 10808, + "site": 10809, + "▁beneath": 10810, + "▁shell": 10811, + "xd": 10812, + "Play": 10813, + "short": 10814, + "Role": 10815, + "▁religion": 10816, + "inator": 10817, + "}<": 10891, + "asp": 10892, + "ajo": 10893, + "exports": 10894, + "▁Node": 10895, + "▁jako": 10896, + "▁ya": 10897, + "▁successfully": 10898, + "▁friendly": 10899, + "buff": 10900, + "DEFAULT": 10901, + "▁pregn": 10902, + "Required": 10903, + "▁binary": 10904, + "isting": 10905, + "▁stared": 10906, + "▁circumstances": 10907, + "▁хо": 10908, + "rei": 10909, + "▁Го": 10910, + "Transform": 10911, + "cnt": 10912, + "▁Ext": 10913, + "report": 10914, + "VERSION": 10915, + "▁analy": 10916, + "▁Marg": 10917, + "▁alleg": 10918, + "builder": 10919, + "ToString": 10920, + "Layer": 10921, + "íst": 10922, + "Prop": 10923, + "▁Emp": 10924, + "}]": 10925, + "▁selling": 10926, + "▁queue": 10927, + "▁seriously": 10928, + "▁Lead": 10929, + "textit": 10930, + "testing": 10931, + "▁Пре": 10932, + "security": 10933, + "iał": 10934, + "ún": 10935, + "chip": 10936, + "▁candidate": 10937, + "▁minister": 10938, + "eria": 10939, + "▁Het": 10940, + "дин": 10941, + "▁Britain": 10942, + "▁barely": 10943, + "▁sty": 10944, + "▁Spanish": 10945, + "▁Ven": 10946, + "timer": 10947, + "ків": 10948, + "▁documents": 10949, + "('.": 10950, + "▁debug": 10951, + "▁contro": 10952, + "стоя": 10953, + "▁joy": 10954, + "Sn": 10955, + "Inv": 10956, + "▁protocol": 10957, + "▁faces": 10958, + "▁Despite": 10959, + "sed": 10960, + "Conf": 10961, + "ARG": 10962, + "▁evolution": 10963, + "▁tod": 10964, + "▁Promise": 10965, + "▁posted": 10966, + "Perm": 10967, + "bet": 10968, + "Ang": 10969, + "Just": 10970, + "▁rum": 10971, + "layer": 10972, + "▁behavi": 10973, + "ipping": 10974, + "▁dynam": 10975, + "▁scheme": 10976, + "▁proto": 10977, + ")/": 10978, + "Collections": 10979, + "riev": 10980, + "▁Click": 10981, + "▁uns": 10982, + "widetilde": 10983, + "▁remembered": 10984, + "гі": 10985, + "inates": 10986, + "▁incorpor": 10987, + "▁Description": 10988, + "▁prepare": 10989, + "▁Final": 10990, + "uation": 10991, + "▁Queen": 10992, + ">;": 10993, + "▁automatically": 10994, + "▁sharp": 10995, + "▁meat": 10996, + "ateur": 10997, + "astern": 10998, + "▁stuck": 10999, + "ASSERT": 11000, + "▁planned": 11001, + "dots": 11002, + "ookie": 11003, + "▁Histor": 11004, + "▁reviews": 11005, + "IMP": 11006, + "▁answered": 11007, + "Total": 11008, + "▁sau": 11009, + "▁Mexico": 11010, + "continue": 11011, + "▁Apple": 11012, + "likely": 11013, + "зва": 11014, + "users": 11015, + "▁identified": 11016, + "▁Lev": 11017, + "▁mol": 11018, + "▁Islam": 11019, + "▁committed": 11020, + "writ": 11021, + "бер": 11022, + "rift": 11023, + "▁interrupt": 11024, + "▁readonly": 11025, + "schema": 11026, + "Sm": 11027, + "Double": 11028, + "aza": 11029, + "▁Hal": 11030, + "Move": 11031, + "▁Series": 11032, + "inline": 11033, + "▁которы": 11034, + "soc": 11035, + "▁tent": 11036, + "▁amer": 11037, + "aki": 11038, + "▁lady": 11039, + "▁tired": 11040, + "ifi": 11041, + "▁même": 11042, + "ouver": 11043, + "▁aside": 11044, + "Did": 11045, + "',\r": 11046, + "▁bringing": 11047, + "Drawing": 11048, + "aro": 11049, + "▁Rh": 11050, + "▁Naz": 11051, + "esso": 11052, + "▁reaction": 11053, + "mitted": 11054, + "▁absolute": 11055, + "haust": 11056, + "(()": 11057, + "▁Task": 11058, + "ERS": 11059, + "▁^{": 11060, + "VD": 11061, + "▁tone": 11062, + "dist": 11063, + "vs": 11064, + "▁wheel": 11065, + "▁administration": 11066, + "▁interests": 11067, + "▁pointer": 11068, + "▁encounter": 11069, + "aver": 11070, + "▁nord": 11071, + "ket": 11072, + "▁beach": 11073, + "▁enjoyed": 11074, + "contains": 11075, + "▁append": 11076, + "Wait": 11077, + "▁squad": 11078, + "zel": 11079, + "▁medium": 11080, + "▁sending": 11081, + "▁Lady": 11082, + "ções": 11083, + "▁destination": 11084, + "nych": 11085, + "▁conflict": 11086, + "▁Ly": 11087, + "▁vul": 11088, + "▁basically": 11089, + "reated": 11090, + "black": 11091, + "ugins": 11092, + "▁calm": 11093, + "érie": 11094, + "har": 11095, + "лан": 11096, + "▁Се": 11097, + "watch": 11098, + "▁Put": 11099, + "▁dump": 11100, + "acher": 11101, + "scroll": 11102, + "▁claimed": 11103, + "▁Control": 11104, + "▁blind": 11105, + "enti": 11106, + "▁Keep": 11107, + "▁Development": 11108, + "images": 11109, + "▁tough": 11110, + "gebra": 11111, + "▁sept": 11112, + "hew": 11113, + "▁skill": 11114, + "▁Tay": 11115, + "▁któ": 11116, + "owner": 11117, + "pare": 11118, + "▁fee": 11119, + "▁continues": 11120, + "▁kan": 11121, + "bes": 11122, + "▁cha": 11123, + "ovo": 11124, + "▁Night": 11125, + "icture": 11126, + "shire": 11127, + "▁essay": 11128, + "▁suppose": 11129, + "etic": 11130, + "Art": 11131, + "acon": 11132, + "lla": 11133, + "words": 11134, + "▁comparison": 11135, + "▁BE": 11136, + "▁challenges": 11137, + "▁ol": 11138, + "citep": 11139, + "▁Foot": 11140, + "▁Such": 11141, + "▁papers": 11142, + "activ": 11143, + "quer": 11144, + "тя": 11145, + "▁То": 11146, + "ський": 11147, + "thur": 11148, + "done": 11149, + "▁shock": 11150, + "▁dedicated": 11151, + "▁correspond": 11152, + "Second": 11153, + "▁bull": 11154, + "life": 11155, + "indent": 11156, + "▁figures": 11157, + "▁Andrew": 11158, + "isp": 11159, + "▁favour": 11160, + "зда": 11161, + "▁Elect": 11162, + "Full": 11163, + "▁nearby": 11164, + "▁Register": 11165, + "Scale": 11166, + "ications": 11167, + "ин": 11168, + "▁AM": 11169, + "pair": 11170, + "▁perspective": 11171, + "▁nos": 11172, + "apa": 11173, + "ostał": 11174, + "▁Pers": 11175, + "icer": 11176, + "▁plastic": 11177, + "дов": 11178, + "ciples": 11179, + "zą": 11180, + "clos": 11181, + "▁уча": 11182, + "▁Á": 11183, + "plugin": 11184, + "▁angle": 11185, + "▁commission": 11186, + "▁funds": 11187, + "▁indu": 11188, + "▁drawn": 11189, + "ám": 11190, + "▁developing": 11191, + "▁segment": 11192, + "isme": 11193, + "scr": 11194, + "▁lies": 11195, + "▁IL": 11196, + "▁api": 11197, + "Extension": 11198, + "▁scal": 11199, + "install": 11200, + "▁Week": 11201, + "▁gentle": 11202, + "▁Canadian": 11203, + "▁dialog": 11204, + "▁articles": 11205, + "Theme": 11206, + "SM": 11207, + "▁Bul": 11208, + "▁leur": 11209, + "▁stom": 11210, + "Plugin": 11211, + "▁после": 11212, + "▁stead": 11213, + "▁ś": 11214, + "ipher": 11215, + "▁prze": 11216, + "▁draft": 11217, + "bottom": 11218, + "▁{};": 11219, + "▁stayed": 11220, + "feature": 11221, + "▁vot": 11222, + "▁fabric": 11223, + "ça": 11224, + "('#": 11225, + "rea": 11226, + "▁reput": 11227, + "▁Cir": 11228, + "▁AL": 11229, + "▁assertEquals": 11230, + "results": 11231, + "▁Cross": 11232, + "ursday": 11233, + "▁audio": 11234, + "▁gap": 11235, + "▁streets": 11236, + "▁scientific": 11237, + "platform": 11238, + "▁auss": 11239, + "▁Cro": 11240, + "▁partial": 11241, + "unc": 11242, + "▁choices": 11243, + "▁или": 11244, + "pred": 11245, + "▁heads": 11246, + "terday": 11247, + "▁Nick": 11248, + "▁weird": 11249, + "asant": 11250, + "▁represented": 11251, + "▁пи": 11252, + "DP": 11253, + "orders": 11254, + "clock": 11255, + "▁Ho": 11256, + "arters": 11257, + "Cmd": 11258, + "oga": 11259, + "Keys": 11260, + "Report": 11261, + "▁Vill": 11262, + "▁Mu": 11263, + "▁owned": 11264, + "SUCCESS": 11265, + "▁typeof": 11266, + "hdr": 11267, + "uable": 11268, + "▁neighborhood": 11269, + "▁AP": 11270, + "▁resulting": 11271, + "▁shadow": 11272, + "STRING": 11273, + "▁videos": 11274, + "лення": 11275, + "expect": 11276, + "▁Valley": 11277, + "▁goto": 11278, + "▁Sher": 11279, + "frastr": 11280, + "▁operating": 11281, + "▁это": 11282, + "▁Licensed": 11283, + "Variable": 11284, + "▁PR": 11285, + "▁Hans": 11286, + "clone": 11287, + "▁Gesch": 11288, + "▁Band": 11289, + "........": 11290, + "uing": 11291, + "▁hundreds": 11292, + "▁ок": 11293, + "▁emotional": 11294, + "▁Indust": 11295, + ")+": 11296, + "▁Egypt": 11297, + "▁franç": 11298, + "▁š": 11299, + "▁fasc": 11300, + "onto": 11301, + "▁Adam": 11302, + "▁laid": 11303, + "▁rig": 11304, + "▁detailed": 11305, + "▁implements": 11306, + "▁university": 11307, + "▁Hy": 11308, + "▁grid": 11309, + "▁regions": 11310, + "Stop": 11311, + "▁slot": 11312, + "▁angry": 11313, + "▁-=": 11314, + "▁waited": 11315, + "Vert": 11316, + "\":\"": 11317, + "▁elem": 11318, + "▁rég": 11319, + "owed": 11320, + "Member": 11321, + "▁ratio": 11322, + "isen": 11323, + "▁Lem": 11324, + "gery": 11325, + "▁cream": 11326, + "▁était": 11327, + "▁geb": 11328, + "unique": 11329, + "▁Deb": 11330, + "▁factory": 11331, + "że": 11332, + "dialog": 11333, + "▁Config": 11334, + "Sync": 11335, + "angers": 11336, + "▁governing": 11337, + "▁Hun": 11338, + "Space": 11339, + "▁jest": 11340, + "icious": 11341, + "▁emphas": 11342, + "umps": 11343, + "▁Esp": 11344, + "▁sul": 11345, + "▁historical": 11346, + "ija": 11347, + "▁lying": 11348, + "▁Steve": 11349, + "▁measures": 11350, + "osto": 11351, + "?”": 11352, + "▁pocket": 11353, + "▁Sat": 11354, + "▁pitch": 11355, + "▁natur": 11356, + "▁humans": 11357, + "▁Simon": 11358, + "adores": 11359, + "(\"\\": 11360, + "inking": 11361, + "▁expos": 11362, + "material": 11363, + "▁apparently": 11364, + "▁Camb": 11365, + "▁Box": 11366, + "▁spaces": 11367, + "exists": 11368, + "▁acting": 11369, + "ORY": 11370, + "зова": 11371, + "Good": 11372, + "ienne": 11373, + "▁Williams": 11374, + "▁fruit": 11375, + "iera": 11376, + "▁Lim": 11377, + "▁trait": 11378, + "▁artists": 11379, + "▁absor": 11380, + "rait": 11381, + "LOAD": 11382, + "▁movies": 11383, + "▁dynamic": 11384, + "asts": 11385, + "▁Integer": 11386, + "▁smoke": 11387, + "пі": 11388, + "angel": 11389, + ">(\"": 11390, + "▁instrument": 11391, + "▁fuel": 11392, + "ної": 11393, + "atalogue": 11394, + "▁serial": 11395, + "Files": 11396, + "▁bathroom": 11397, + "ilo": 11398, + "esto": 11399, + "▁pm": 11400, + "entials": 11401, + "▁Online": 11402, + "white": 11403, + "▁tips": 11404, + "▁capable": 11405, + "Fig": 11406, + "TV": 11407, + "▁он": 11408, + "ké": 11409, + "bitr": 11410, + "Mapping": 11411, + "▁tak": 11412, + "ющи": 11413, + "вля": 11414, + ")\",": 11415, + "▁Karl": 11416, + "▁Human": 11417, + "▁Pot": 11418, + "▁represents": 11419, + "▁consistent": 11420, + "_(": 11421, + "wen": 11422, + "▁Rose": 11423, + "law": 11424, + "▁FROM": 11425, + "▁begins": 11426, + "▁edit": 11427, + "▁mountain": 11428, + "▁chapter": 11429, + "▁wondered": 11430, + "▁industrial": 11431, + "▁Major": 11432, + "▁ges": 11433, + "▁directed": 11434, + "eros": 11435, + "▁Wild": 11436, + "liament": 11437, + "Book": 11438, + "username": 11439, + "hot": 11440, + "▁nam": 11441, + "▁league": 11442, + "bra": 11443, + "кон": 11444, + "▁Tal": 11445, + "▁Ва": 11446, + "▁exports": 11447, + "(@": 11448, + "▁sharing": 11449, + "▁Tro": 11450, + "ść": 11451, + "uesday": 11452, + "ylv": 11453, + "▁guitar": 11454, + "elen": 11455, + "Selection": 11456, + "▁confident": 11457, + "rypto": 11458, + "▁hors": 11459, + "editor": 11460, + "▁shoulders": 11461, + "getName": 11462, + "encing": 11463, + "SELECT": 11464, + "вши": 11465, + "▁kinds": 11466, + "▁Wel": 11467, + "▁purposes": 11468, + "Matrix": 11469, + "invalid": 11470, + "▁owners": 11471, + "▁Records": 11472, + "▁Process": 11473, + "▁chat": 11474, + "▁Dor": 11475, + "▁bin": 11476, + "redit": 11477, + "oire": 11478, + "▁Total": 11479, + "▁Family": 11480, + "ARY": 11481, + "▁bread": 11482, + "▁compre": 11483, + "▁shoes": 11484, + "▁raz": 11485, + "▁trace": 11486, + "nej": 11487, + "orted": 11488, + "hn": 11489, + "▁procedure": 11490, + "properties": 11491, + "plier": 11492, + "▁hero": 11493, + "panel": 11494, + "▁marked": 11495, + "▁worried": 11496, + "\\|": 11497, + "pts": 11498, + "▁Support": 11499, + "▁serving": 11500, + "Fail": 11501, + "▁disappoint": 11502, + "▁Scot": 11503, + "▁pleasure": 11504, + "▁judge": 11505, + "zeich": 11506, + "▁forever": 11507, + "▁Zeit": 11508, + "uous": 11509, + "inent": 11510, + "▁dw": 11511, + "▁waren": 11512, + "▁flash": 11513, + "▁troops": 11514, + "▁drugs": 11515, + "▁diam": 11516, + ".~": 11517, + "imp": 11518, + "inned": 11519, + "▁EV": 11520, + "Struct": 11521, + "▁justice": 11522, + "▁officials": 11523, + "ffff": 11524, + "▁Common": 11525, + "▁Cat": 11526, + "▁tomorrow": 11527, + "▁él": 11528, + "Texture": 11529, + "qpoint": 11530, + "▁Fried": 11531, + "▁Term": 11532, + "pgfqpoint": 11533, + "▁nem": 11534, + "norm": 11535, + "▁hardly": 11536, + "oda": 11537, + "zeta": 11538, + "emic": 11539, + "▁полу": 11540, + "▁loaded": 11541, + "kes": 11542, + "ció": 11543, + "▁fool": 11544, + "▁trick": 11545, + "▁dst": 11546, + "Find": 11547, + "▁все": 11548, + "}},": 11549, + "▁framework": 11550, + "▁merely": 11551, + "▁union": 11552, + "▁Edward": 11553, + "rif": 11554, + "Flag": 11555, + "▁crisis": 11556, + "▁finite": 11557, + "▁lol": 11558, + "▁Kim": 11559, + "ната": 11560, + "since": 11561, + "▁compat": 11562, + "▁pert": 11563, + "ibilities": 11564, + "▁también": 11565, + "ibli": 11566, + "▁teen": 11567, + "▁sympt": 11568, + "oral": 11569, + "ders": 11570, + "otte": 11571, + "при": 11572, + "▁Jane": 11573, + "▁originally": 11574, + "▁throat": 11575, + "mag": 11576, + "sup": 11577, + "uni": 11578, + "$$": 11579, + "▁Library": 11580, + "▁attacks": 11581, + "ingen": 11582, + "('/": 11583, + "▁hes": 11584, + "coin": 11585, + "ounce": 11586, + "▁Academy": 11587, + "MODULE": 11588, + "isms": 11589, + "▁Adv": 11590, + "▁Bol": 11591, + "▁incident": 11592, + ")^{": 11593, + "▁bij": 11594, + "▁Rome": 11595, + "▁Italy": 11596, + "events": 11597, + "▁Fern": 11598, + "▁ber": 11599, + "▁silent": 11600, + "▁pier": 11601, + "▁YO": 11602, + "▁plain": 11603, + "Bas": 11604, + "▁pill": 11605, + "rase": 11606, + "▁carrying": 11607, + "▁resp": 11608, + "ную": 11609, + "▁typical": 11610, + "Wrapper": 11611, + "▁gau": 11612, + "▁chemical": 11613, + "▁hal": 11614, + "throw": 11615, + "Cluster": 11616, + "▁Gab": 11617, + "▁Girl": 11618, + "quir": 11619, + "▁Arg": 11620, + "▁relief": 11621, + "▁Ве": 11622, + "dm": 11623, + "▁frustr": 11624, + "\\%": 11625, + "▁stores": 11626, + "▁bottle": 11627, + "▁Lew": 11628, + "two": 11629, + "stad": 11630, + "▁cheek": 11631, + "▁concerns": 11632, + "▁helpful": 11633, + "▁coverage": 11634, + "isi": 11635, + "ADD": 11636, + "async": 11637, + "▁approximately": 11638, + "iffer": 11639, + "hook": 11640, + "▁enum": 11641, + "ová": 11642, + "▁evil": 11643, + "▁constantly": 11644, + "apply": 11645, + "▁siè": 11646, + "▁practices": 11647, + "▁teachers": 11648, + "▁Sn": 11649, + "▁Awards": 11650, + "▁substant": 11651, + "▁$.": 11652, + "dk": 11653, + "▁mob": 11654, + "▁ingred": 11655, + "vere": 11656, + "Multi": 11657, + "пер": 11658, + "stal": 11659, + "yard": 11660, + "required": 11661, + "vement": 11662, + "▁intelligence": 11663, + "▁thinks": 11664, + "▁personally": 11665, + "▁trained": 11666, + "orney": 11667, + ")\\": 12034, + "anal": 12035, + "Section": 12036, + "plus": 12037, + "üt": 12038, + "▁embed": 12039, + "▁strings": 12040, + "Before": 12041, + "proc": 12042, + "▁спо": 12043, + "trl": 12044, + "vr": 12045, + "Background": 12046, + "logger": 12047, + "agraph": 12048, + "iest": 12049, + "▁goods": 12050, + "batch": 12051, + "▁optional": 12052, + "▁Taylor": 12053, + "▁recognize": 12054, + "walk": 12055, + "▁Hit": 12056, + "▁Elizabeth": 12057, + "}:": 12058, + "▁careful": 12059, + "краї": 12060, + "▁locations": 12061, + "▁structures": 12062, + "▁disk": 12063, + "▁ships": 12064, + "▁suo": 12065, + "▁sowie": 12066, + "▁Ess": 12067, + "▁Hash": 12068, + "▁reasonable": 12069, + "▁Moreover": 12070, + "▁formula": 12071, + "▁Centre": 12072, + "▁residents": 12073, + "RS": 12074, + "Ids": 12075, + "▁Know": 12076, + "▁trib": 12077, + "▁rés": 12078, + "▁stable": 12079, + "▁Would": 12080, + "▁breaking": 12081, + "▁meal": 12082, + "▁phen": 12083, + "▁fel": 12084, + "▁Fred": 12085, + "Author": 12086, + "▁capture": 12087, + "opts": 12088, + "▁everywhere": 12089, + "▁sque": 12090, + "▁moder": 12091, + "setup": 12092, + "▁Supp": 12093, + "▁whenever": 12094, + "{(": 12095, + "wart": 12096, + "▁toe": 12097, + "Prefix": 12098, + "hou": 12099, + "gage": 12100, + ">\"": 12101, + "▁frag": 12102, + "▁Theorem": 12103, + "memory": 12104, + "▁contents": 12105, + "docs": 12106, + "}'": 12107, + "▁Irish": 12108, + "Then": 12109, + "aats": 12110, + "Save": 12111, + "▁agency": 12112, + "▁име": 12113, + "дова": 12114, + "▁Function": 12115, + "NN": 12116, + "destroy": 12117, + "▁Message": 12118, + "▁cancel": 12119, + "▁superior": 12120, + "▁ec": 12121, + "▁literature": 12122, + "▁PART": 12123, + "Il": 12124, + "▁Cab": 12125, + "engine": 12126, + "▁basket": 12127, + "worth": 12128, + "▁Sel": 12129, + "fetch": 12130, + "▁Stadt": 12131, + "▁Ки": 12132, + "▁conj": 12133, + "▁seiner": 12134, + "▁confirmed": 12135, + "▁Argent": 12136, + "amar": 12137, + "pgfpath": 12138, + "▁struggle": 12139, + "Pattern": 12140, + "▁Middle": 12141, + "itan": 12142, + "▁moon": 12143, + "orough": 12144, + "▁Catholic": 12145, + "▁struck": 12146, + "]->": 12147, + "▁weapon": 12148, + "▁subst": 12149, + "▁instructions": 12150, + "▁occas": 12151, + "protected": 12152, + "▁Less": 12153, + "▁batch": 12154, + "▁contra": 12155, + "▁deck": 12156, + "▁ignored": 12157, + "▁refused": 12158, + "trigger": 12159, + "▁criminal": 12160, + "GA": 12161, + "olly": 12162, + "▁Bell": 12163, + "▁Ю": 12164, + "forward": 12165, + "▁prefix": 12166, + "▁immediate": 12167, + "▁assigned": 12168, + "▁elected": 12169, + "▁tonight": 12170, + "▁Dies": 12171, + "▁Beach": 12172, + "▁preced": 12173, + "ował": 12174, + "▁galax": 12175, + "▁logic": 12176, + "enza": 12177, + "▁Captain": 12178, + "▁Hay": 12179, + "▁facts": 12180, + "▁ни": 12181, + "té": 12182, + "▁sb": 12183, + "oped": 12184, + "▁combat": 12185, + "▁explore": 12186, + "▁(-": 12187, + "Loader": 12188, + "▁Wilson": 12189, + "▁locked": 12190, + ":)": 13738, + "▁quel": 13739, + "▁Га": 13740, + "Ty": 13741, + "▁temps": 13742, + "▁ghost": 13743, + "Material": 13744, + "ERCHANT": 13745, + "pointer": 13746, + "жда": 13747, + "aha": 13748, + "ulf": 13749, + "▁supplement": 13750, + "▁dismiss": 13751, + "▁closing": 13752, + "▁vulner": 13753, + "▁après": 13754, + "▁overwhel": 13755, + "ское": 13756, + "▁disag": 13757, + "acia": 13758, + "oured": 13759, + "ruption": 13760, + "▁PS": 13761, + "Endpoint": 13762, + "Real": 13763, + "▁Tag": 13764, + "▁stairs": 13765, + "lyn": 13766, + "▁eleg": 13767, + "▁veter": 13768, + "factory": 13769, + "anne": 13770, + "▁Bat": 13771, + "▁franc": 13772, + "lung": 13773, + "▁\"'": 13774, + ".',": 13775, + "▁Country": 13776, + "^{[": 13777, + "▁yours": 13778, + "ailability": 13779, + "Clear": 13780, + "ätt": 13781, + "пис": 13782, + "▁joke": 13783, + "▁annoy": 13784, + "▁rag": 13785, + "vari": 13786, + "лекс": 13787, + "▁Psy": 13788, + "ilty": 13789, + "mount": 13790, + "▁cual": 13791, + "▁solar": 13792, + "}^{(": 13793, + "Short": 13794, + "▁taxes": 13795, + "Append": 13796, + "Win": 13797, + "estyle": 13798, + "▁facil": 13799, + "вро": 13800, + "▁sought": 13801, + "▁bare": 13802, + "▁react": 13803, + "jar": 13804, + "MAC": 13805, + "lov": 13806, + "warn": 13807, + "▁crucial": 13808, + "▁museum": 13809, + "ниц": 13810, + "▁Kent": 13811, + "Maybe": 13812, + "▁bike": 13813, + "▁Address": 13814, + "XML": 13815, + "▁admitted": 13816, + "▁$(\\": 13817, + "▁spell": 13818, + "▁vic": 13819, + "gre": 13820, + "▁proc": 13821, + "theless": 13822, + "▁Nom": 13823, + "▁Rail": 13824, + "▁acceler": 13825, + "▁convin": 13826, + "▁Property": 13827, + "▁DA": 13828, + "▁clip": 13829, + "▁plugin": 13830, + "Limit": 13831, + "views": 13832, + "bru": 13833, + "▁pra": 13834, + "▁ak": 13835, + "▁ej": 13836, + "▁opts": 13837, + "▁slip": 13838, + "▁gang": 13839, + "asted": 13840, + "uals": 13841, + "▁dying": 13842, + "Coll": 13843, + "ammen": 13844, + "▁Policy": 13845, + "ERCHANTABILITY": 13846, + "▁Collection": 13847, + "▁vec": 13848, + "▁Dick": 13849, + "stud": 13850, + "▁layers": 13851, + "▁tied": 13852, + "}\\\\": 13853, + "▁alors": 13854, + "▁jou": 13855, + "▁chicken": 13856, + "▁permanent": 13857, + "▁Everything": 13858, + "▁Low": 13859, + "▁Cook": 13860, + "▁peak": 13861, + "▁PARTICULAR": 13862, + "▁dear": 13863, + "ič": 13864, + "▁introduce": 13865, + "▁causing": 13866, + "писа": 13867, + "Bound": 13868, + "hund": 13869, + "multi": 13870, + "▁pare": 13871, + "annt": 13872, + "▁breat": 13873, + "▁commitment": 13874, + "▁increasingly": 13875, + "кой": 13876, + "▁Friend": 13877, + "▁statistics": 13878, + "▁Manager": 13879, + "plicate": 13880, + "Cloud": 13881, + "aci": 13882, + "▁Conference": 13883, + "Span": 13884, + "▁CEO": 13885, + "▁Wait": 13886, + "▁Ober": 13887, + "ifting": 13888, + "imiento": 13889, + "getElement": 13890, + "▁gle": 13891, + "лия": 13892, + "▁wieder": 13893, + "▁instruction": 13894, + "gly": 13895, + "▁blame": 13896, + "▁listade": 13897, + "▁aapt": 13898, + "▁Lewis": 13899, + "Fragment": 13900, + "▁gear": 13901, + "mill": 13902, + "prod": 13903, + "▁burning": 13904, + "ється": 13905, + "▁mé": 13906, + "ène": 13907, + "▁complicated": 13908, + "bh": 13909, + "▁Justice": 13910, + "▁tested": 13911, + "▁staring": 13912, + "▁survive": 13913, + "▁cous": 13914, + "▁rib": 13915, + "aml": 13916, + "▁Trust": 13917, + "▁cad": 13918, + "▁Terr": 13919, + "▁mapping": 13920, + "▁twelve": 13921, + "▁grant": 13922, + "▁thorough": 13923, + "▁Ü": 13924, + "▁folks": 13925, + "▁Content": 13926, + "▁childhood": 13927, + "cker": 13928, + "сно": 13929, + "RECT": 13930, + "▁finale": 13931, + "▁shower": 13932, + "éric": 13933, + "▁spat": 13934, + "odge": 13935, + "рь": 13936, + "▁pes": 13937, + "eda": 13938, + "Db": 13939, + "▁Antonio": 13940, + "▁engaged": 13941, + "▁vess": 13942, + "vals": 13943, + "▁electronic": 13944, + "lemma": 13945, + "▁Wy": 13946, + "mad": 13947, + "merge": 13948, + "apon": 13949, + "▁privile": 13950, + "▁novembre": 13951, + "▁Sports": 13952, + "will": 13953, + "▁controls": 13954, + "▁categories": 13955, + "▁Georgia": 13956, + "ipedia": 13957, + "▁AV": 13958, + "atori": 13959, + "▁___": 13960, + "▁À": 13961, + "▁Ryan": 13962, + "▁Charlie": 13963, + "▁исто": 13964, + "▁emotion": 13965, + "▁cooking": 13966, + "▁attempts": 13967, + "▁FITNESS": 13968, + "äter": 13969, + "Enable": 13970, + "DT": 13971, + "▁Change": 13972, + "AspNet": 13973, + "▁га": 13974, + "▁ordinary": 13975, + "▁SQL": 13976, + "plane": 13977, + "%.": 13978, + "▁Summer": 13979, + "▁avait": 13980, + "upp": 13981, + "▁illness": 13982, + "UINT": 13983, + ">{": 13984, + "▁zwischen": 13985, + "▁hardware": 13986, + "▁sounded": 13987, + "equiv": 13988, + "▁piano": 13989, + "uset": 13990, + "kn": 13991, + "TRY": 13992, + "▁bab": 13993, + "нен": 13994, + "▁reliable": 13995, + "▁Bronnen": 13996, + "▁Store": 13997, + "Az": 13998, + "▁»,": 13999, + "Static": 14000, + "dw": 14001, + "green": 14002, + "▁'';": 14003, + "lij": 14004, + "eva": 14005, + "ній": 14006, + "▁Syd": 14007, + "inois": 14008, + "convert": 14009, + "▁declare": 14010, + "bres": 14011, + "INK": 14012, + "itled": 14013, + "▁accord": 14014, + "▁mars": 14015, + "Sequence": 14016, + "zip": 14017, + "▁Brazil": 14018, + "▁meetings": 14019, + "▁accuracy": 14020, + "▁Machine": 14021, + "▁autor": 14022, + "▁ainsi": 14023, + "Simple": 14024, + "Resources": 14025, + "каза": 14026, + "▁MP": 14027, + "they": 14028, + "▁Bang": 14029, + "▁eing": 14030, + "ateful": 14031, + "▁Something": 14032, + "▁upset": 14033, + "History": 14034, + "dimensional": 14035, + "▁explanation": 14036, + "▁civ": 14037, + "▁conce": 14038, + "▁köz": 14039, + "▁promised": 14040, + "жду": 14041, + "wed": 14042, + "Fore": 14043, + "Amount": 14044, + "abb": 14045, + "▁clothing": 14046, + "лись": 14047, + "oen": 14048, + "▁Print": 14049, + "▁sizes": 14050, + "▁banks": 14051, + "ribed": 14052, + "▁'../": 14053, + "FIX": 14054, + "▁Hug": 14055, + "▁zn": 14056, + "▁INT": 14057, + "▁instances": 14058, + "▁alongside": 14059, + "Namespace": 14060, + "▁renew": 14061, + "▁asc": 14062, + "▁waves": 14063, + "▁pom": 14064, + "Duration": 14065, + "days": 14066, + "$(": 14067, + "▁grabbed": 14068, + "▁surgery": 14069, + "▁restore": 14070, + "Normal": 14071, + "▁Leb": 14072, + "▁analyt": 14073, + "Literal": 14074, + "HA": 14075, + "▁shares": 14076, + "illet": 14077, + "ols": 14078, + "▁Dog": 14079, + "orno": 14080, + "▁manip": 14081, + "jav": 14082, + "▁essentially": 14083, + "▁casual": 14084, + "opl": 14085, + "▁р": 14086, + "▁SU": 14087, + "▁engineering": 14088, + "▁Prime": 14089, + "▁SW": 14090, + "▁reaching": 14091, + "▁вла": 14092, + "▁Росси": 14093, + "▁Kre": 14094, + "erry": 14095, + "▁oppon": 14096, + "program": 14097, + "emper": 14098, + "isEmpty": 14099, + "▁Unit": 14100, + "INTER": 14101, + "ethe": 14102, + "zd": 14103, + "CUR": 14104, + "▁vm": 14105, + "conv": 14106, + "ropol": 14107, + "▁Coast": 14108, + "▁Select": 14109, + "▁была": 14110, + "▁Ve": 14111, + "owy": 14112, + "▁myth": 14113, + "ceptions": 14114, + "classes": 14115, + "▁worden": 14116, + "▁assault": 14117, + "▁dual": 14118, + "ORK": 14119, + "▁inches": 14120, + "▁FA": 14121, + "▁Station": 14122, + "▁personality": 14123, + "▁scar": 14124, + "▁regime": 14125, + "▁noten": 14126, + "▁rural": 14127, + "iza": 14128, + "Audio": 14129, + "▁disput": 14130, + "▁aver": 14131, + "▁obst": 14132, + "▁Region": 14133, + "utf": 14134, + "▁Cass": 14135, + "hspace": 14136, + "▁shipping": 14137, + "iko": 14138, + "icked": 14139, + "numer": 14140, + "дна": 14141, + "riel": 14142, + "disabled": 14143, + "opol": 14144, + "looking": 14145, + "▁classical": 14146, + "▁constructed": 14147, + "▁referenties": 14148, + "]+": 14149, + "▁captured": 14150, + "▁minimal": 14151, + "▁sock": 14152, + "father": 14153, + "isión": 14154, + "▁equally": 14155, + "▁reduction": 14156, + "Ant": 14157, + "aison": 14158, + "▁argue": 14159, + "circle": 14160, + "▁toler": 14161, + "}\",": 14162, + "▁primarily": 14163, + "usal": 14164, + "▁algebra": 14165, + "▁gathered": 14166, + "▁Remember": 14167, + "_);": 14168, + "UTE": 14169, + "▁Kit": 14170, + "Sy": 14171, + "HEAD": 14172, + "▁recipe": 14173, + "▁scenario": 14174, + "▁Following": 14175, + "VAR": 14176, + "▁yard": 14177, + "▁stad": 14178, + "*(": 14179, + "▁validate": 14180, + "DEX": 14181, + "▁committee": 14182, + "▁temporary": 14183, + "▁consequences": 14184, + "▁également": 14185, + "ктив": 14186, + "▁ra": 14187, + "▁displ": 14188, + "▁apps": 14189, + "▁Teil": 14190, + "▁».": 14191, + "▁adopted": 14192, + "tensor": 14193, + "▁femin": 14194, + "▁мар": 14195, + "логи": 14196, + "tech": 14197, + "▁Rot": 14198, + "▁knees": 14199, + "phys": 14200, + "owej": 14201, + "▁Oxford": 14202, + "анд": 14203, + "hell": 14204, + "ografia": 14205, + "▁exposed": 14206, + "ktop": 14207, + "oby": 14208, + "lower": 14209, + "▁Senate": 14210, + "▁sword": 14211, + "Flow": 14212, + "▁Unfortunately": 14213, + "▁boxes": 14214, + "▁cuando": 14215, + "▁pilot": 14216, + "▁Album": 14217, + "Bal": 14218, + "Sort": 14219, + "FIELD": 14220, + "▁desert": 14221, + "COMM": 14222, + "rons": 14223, + "adows": 14224, + "▁loyal": 14225, + "▁asset": 14226, + "▁mud": 14227, + "фа": 14228, + "▁secondary": 14229, + "▁Ар": 14230, + "▁cul": 14231, + "▁Asian": 14232, + "▁staying": 14233, + "▁dataset": 14234, + "▁USE": 14235, + "▁loves": 14236, + "▁velocity": 14237, + "áv": 14238, + "▁purchased": 14239, + "SOC": 14240, + "▁competitive": 14241, + "▁Football": 14242, + "iska": 14243, + "▁knock": 14244, + "stairs": 14245, + "azy": 14246, + "▁vend": 14247, + "▁arts": 14248, + "▁Bras": 14249, + "uela": 14250, + "кто": 14251, + "trim": 14252, + "▁dirty": 14253, + "▁websites": 14254, + "▁Indep": 14255, + "▁стра": 14256, + "sr": 14257, + "▁ticket": 14258, + "atile": 14259, + "▁implemented": 14260, + "▁время": 14261, + "▁bowl": 14262, + "DATE": 14263, + "▁alter": 14264, + "▁Space": 14265, + "▁accompan": 14266, + "ordon": 14267, + "▁doctors": 14268, + "istas": 14269, + "Cast": 14270, + "дом": 14271, + "CTL": 14272, + "urers": 14273, + "▁ingredients": 14274, + "▁calculated": 14275, + "▁leather": 14276, + "▁sensitive": 14277, + "▁suspic": 14278, + "stan": 14279, + "▁anni": 14280, + "await": 14281, + "▁Franç": 14282, + "▁abort": 14283, + "▁Spirit": 14284, + "▁Walter": 14285, + "unkt": 14286, + "▁vertical": 14287, + "ORS": 14288, + "best": 14289, + "▁Client": 14290, + "itated": 14291, + "▁ва": 14292, + "▁Č": 14293, + "▁ville": 14294, + "▁diplom": 14295, + "orne": 14296, + "▁bars": 14297, + "Uri": 14298, + "APTER": 14299, + "pons": 14300, + "utz": 14301, + "Proto": 14302, + "▁stir": 14303, + "▁це": 14304, + "▁primer": 14305, + "igible": 14306, + "extra": 14307, + "▁Books": 14308, + "▁Bos": 14309, + "▁Et": 14310, + "▁Welt": 14311, + "▁Korea": 14312, + "рито": 14313, + "▁vibr": 14314, + "Self": 14315, + "linear": 14316, + "об": 14317, + "▁Lang": 14318, + "▁deeper": 14319, + "▁termin": 14320, + "enschaft": 14321, + "▁році": 14322, + "ammed": 14323, + "visible": 14324, + "▁IOException": 14325, + "▁Wind": 14326, + "usqu": 14327, + "▁Stop": 14328, + "▁орга": 14329, + "INVALID": 14330, + "▁cub": 14331, + "▁jew": 14332, + "▁captain": 14333, + "зі": 14334, + "chunk": 14335, + "apture": 14336, + "ashboard": 14337, + "▁divided": 14338, + "▁extensive": 14339, + "▁suffer": 14340, + "▁heading": 14341, + "created": 14342, + "▁quietly": 14343, + "▁ny": 14344, + "▁пол": 14345, + "\"+": 14346, + "ikan": 14347, + "▁designs": 14348, + "zu": 14349, + "}+\\": 14350, + "Operator": 14351, + "▁Lemma": 14352, + "▁нау": 14353, + "acji": 14354, + "лове": 14355, + "Servlet": 14356, + "▁Kevin": 14357, + "stage": 14358, + "bn": 14359, + "textwidth": 14360, + "failed": 14361, + "▁Staff": 14362, + "▁enem": 14363, + "unde": 14364, + "ень": 14365, + "Packet": 14366, + "▁Als": 14367, + "kar": 14368, + "]['": 14369, + "ked": 14370, + "Pers": 14371, + ">::": 14372, + "▁arc": 14373, + "▁synt": 14374, + "SPE": 14375, + "▁Да": 14376, + "▁Mi": 14377, + "▁Moh": 14378, + "▁Death": 14379, + "browser": 14380, + "▁Dave": 14381, + "▁succ": 14382, + "toggle": 14383, + "▁tack": 14384, + "Comment": 14385, + "eron": 14386, + "▁awareness": 14387, + "▁hug": 14388, + "▁contemporary": 14389, + "ulating": 14390, + "▁Title": 14391, + "▁THIS": 14392, + "havior": 14393, + "rank": 14394, + "▁dozen": 14395, + "▁cheese": 14396, + "coln": 14397, + "▁radius": 14398, + "▁dimensions": 14399, + "roduction": 14400, + "▁adds": 14401, + "▁household": 14402, + "▁Davis": 14403, + "pkg": 14404, + "{$": 14405, + "▁casino": 14406, + "▁Pierre": 14407, + "▁objective": 14408, + "train": 14409, + "▁Michigan": 14410, + "payload": 14411, + "▁rug": 14412, + "▁severe": 14413, + "mean": 14414, + "▁toss": 14415, + "▁embarrass": 14416, + "▁Very": 14417, + "▁appeal": 14418, + "▁Comput": 14419, + "▁forgotten": 14420, + "▁kernel": 14421, + "▁carbon": 14422, + "fw": 14423, + "▁Су": 14424, + "▁Empire": 14425, + "▁quote": 14426, + "etz": 14427, + "▁mini": 14428, + "▁pipe": 14429, + "▁nous": 14430, + "▁Move": 14431, + "▁ду": 14432, + "▁nervous": 14433, + "▁Мар": 14434, + "*\r": 14435, + "▁Bush": 14436, + "▁peer": 14437, + "▁Writ": 14438, + "▁satisfied": 14439, + "▁pulling": 14440, + "▁Pur": 14441, + "▁Miller": 14442, + "▁FL": 14443, + "amaz": 14444, + "▁mile": 14445, + "▁Need": 14446, + "▁supplies": 14447, + "▁año": 14448, + "▁pace": 14449, + "▁Victoria": 14450, + "▁ought": 14451, + "▁Player": 14452, + "agnostic": 14453, + "▁viv": 14454, + "▁Patrick": 14455, + "▁Š": 14456, + "▁Story": 14457, + "aca": 14458, + "▁mountains": 14459, + "CLASS": 14460, + "▁fragment": 14461, + "▁settlement": 14462, + "▁Furthermore": 14463, + "▁drivers": 14464, + "▁Ju": 14465, + "▁были": 14466, + "Rows": 14467, + "▁impression": 14468, + "▁infer": 14469, + "▁Expl": 14470, + "olute": 14471, + "ovan": 14472, + "arance": 14473, + "CAP": 14474, + "▁enforce": 14475, + "▁Burn": 14476, + "Reset": 14477, + "mother": 14478, + "▁Battle": 14479, + "padding": 14480, + "iate": 14481, + "▁cried": 14482, + "AK": 14483, + "uns": 14484, + "▁siècle": 14485, + "▁Contin": 14486, + "bank": 14487, + "junit": 14488, + "objects": 14489, + "Rot": 14490, + "issa": 14491, + "▁begun": 14492, + "*-": 14493, + "▁visiting": 14494, + "жде": 14495, + "▁targets": 14496, + "▁Latin": 14497, + "ут": 14498, + "▁Esc": 14499, + "*;": 14500, + "ång": 14501, + "▁({": 14502, + "▁diagram": 14503, + "Models": 14504, + "▁partnership": 14505, + "▁från": 14506, + "ulty": 14507, + "Pod": 14508, + "CALL": 14509, + "modal": 14510, + "sig": 14511, + "itzer": 14512, + "itel": 14513, + "▁convinced": 14514, + "abl": 14515, + "стве": 14516, + "▁cot": 14517, + "▁repeat": 14518, + "▁lists": 14519, + "sound": 14520, + "▁royal": 14521, + "▁grace": 14522, + "▁oraz": 14523, + "Notification": 14524, + "prite": 14525, + "▁arrival": 14526, + "ancell": 14527, + "hentic": 14528, + "decode": 14529, + "▁fantastic": 14530, + "progress": 14531, + "proxy": 14532, + "ző": 14533, + "kel": 14534, + "▁convenient": 14535, + "aque": 14536, + "riet": 14537, + "▁Digital": 14538, + "iors": 14539, + "▁Budd": 14540, + "andra": 14541, + "addy": 14542, + "▁overs": 14543, + "▁consumers": 14544, + "pn": 14545, + "mouse": 14546, + "▁BC": 14547, + "deg": 14548, + "perm": 14549, + "ités": 14550, + "▁испо": 14551, + "heast": 14552, + "hour": 14553, + "PARAM": 14554, + "conscious": 14555, + "▁wing": 14556, + "▁atmosphere": 14557, + "▁gig": 14558, + "▁contre": 14559, + "▁drama": 14560, + "ят": 14561, + "▁Front": 14562, + "▁philosophy": 14563, + "▁Hart": 14564, + "▁nurs": 14565, + "uras": 14566, + "▁Tru": 14567, + "▁sud": 14568, + "▁performing": 14569, + "пы": 14570, + "▁confused": 14571, + "▁checks": 14572, + "amt": 14573, + "Make": 14574, + "▁RO": 14575, + "▁df": 14576, + "izations": 14577, + "▁degli": 14578, + "▁architecture": 14579, + "Renderer": 14580, + "▁Ла": 14581, + "▁ptr": 14582, + "▁dieser": 14583, + "submit": 14584, + "▁topics": 14585, + "▁principles": 14586, + "vars": 14587, + "sock": 14588, + "▁tongue": 14589, + "▁percentage": 14590, + "▁SS": 14591, + "▁dol": 14592, + "▁rice": 14593, + "ío": 14594, + "▁Eastern": 14595, + "▁recognition": 14596, + "▁Ern": 14597, + "▁Ut": 14598, + "▁caut": 14599, + "▁Cloud": 14600, + "▁conversion": 14601, + "▁Ohio": 14602, + "▁ME": 14603, + "▁surely": 14604, + "▁gard": 14605, + "puis": 14606, + "▁urg": 14607, + "imi": 14608, + "▁absence": 14609, + "▁winner": 14610, + "Language": 14611, + "▁HTTP": 14612, + "wt": 14613, + "▁translation": 14614, + "сс": 14615, + "▁Kind": 14616, + "Two": 14617, + "▁Revolution": 14618, + "Insert": 14619, + "Every": 14620, + "orient": 14621, + "▁тра": 14622, + "▁emotions": 14623, + "details": 14624, + "▁flu": 14625, + "▁operate": 14626, + "Ag": 14627, + "unning": 14628, + "▁partie": 14629, + "tri": 14630, + "▁golden": 14631, + "▁Би": 14632, + "▁foundation": 14633, + "isten": 14634, + "▁Carlos": 14635, + "Children": 14636, + "▁neighb": 14637, + "▁Cart": 14638, + "Begin": 14639, + "гда": 14640, + "▁scheduled": 14641, + "'>": 14642, + "▁observations": 14643, + "▁producer": 14644, + "athers": 14645, + "ному": 14646, + "▁expectations": 14647, + "oso": 14648, + "zh": 14649, + "mutable": 14650, + "▁writes": 14651, + "▁pushing": 14652, + "▁seats": 14653, + "▁breast": 14654, + "aping": 14655, + "▁Simple": 14656, + "▁socket": 14657, + "▁slave": 14658, + "iley": 14659, + "▁assistant": 14660, + "▁trim": 14661, + "▁landscape": 14662, + "▁association": 14663, + "quant": 14664, + "▁Palest": 14665, + "▁sweat": 14666, + "engers": 14667, + "?_": 14668, + "ép": 14669, + ">.": 14670, + "▁curious": 14671, + "▁Component": 14672, + "▁replacement": 14673, + "раль": 14674, + "▁Track": 14675, + "▁Remove": 14676, + "▁Size": 14677, + "peror": 14678, + "▁calculate": 14679, + "▁sessions": 14680, + "▁typed": 14681, + "▁submit": 14682, + "!!!": 14683, + "▁partition": 14684, + "eding": 14685, + "-----": 14686, + "azioni": 14687, + "ließ": 14688, + "onal": 14689, + "▁shru": 14690, + "▁REG": 14691, + "▁Fac": 14692, + "configuration": 14693, + "▁было": 14694, + "▁Among": 14695, + "__);": 14696, + "▁Server": 14697, + "▁LOG": 14698, + "▁cand": 14699, + "']);": 14700, + "gov": 14701, + "▁Six": 14702, + "undefined": 14703, + "▁ty": 14704, + "asa": 14705, + "▁particles": 14706, + "▁фор": 14707, + "``": 14708, + "Tube": 14709, + "eland": 14710, + "fold": 14711, + "ogo": 14712, + "▁approaches": 14713, + "onda": 14714, + "agr": 14715, + ",$": 14716, + "▁{{": 14717, + "▁Modern": 14718, + "▁Winter": 14719, + "available": 14720, + "▁Lud": 14721, + "▁casa": 14722, + "▁Could": 14723, + "▁fifteen": 14724, + "▁potentially": 14725, + "^^": 14726, + "▁seit": 14727, + "Animation": 14728, + "кого": 14729, + "Zone": 14730, + "elif": 14731, + "▁acknowled": 14732, + "▁ownership": 14733, + "▁describes": 14734, + "▁reverse": 14735, + "▁contest": 14736, + "▁scored": 14737, + "▁opposed": 14738, + "flex": 14739, + "kre": 14740, + "▁merge": 14741, + "▁covering": 14742, + "▁honestly": 14743, + "▁Mess": 14744, + "▁rarely": 14745, + "▁incredible": 14746, + "itage": 14747, + "▁victims": 14748, + "ными": 14749, + "wl": 14750, + "izza": 14751, + "dn": 14752, + "onde": 14753, + "▁przy": 14754, + "▁HTML": 14755, + "▁payload": 14756, + "Bus": 14757, + "usb": 14758, + "Fn": 14759, + "▁displayed": 14760, + "▁ocean": 14761, + "▁Avenue": 14762, + "acion": 14763, + "ghan": 14764, + "metric": 14765, + "ieties": 14766, + "▁attractive": 14767, + "▁fö": 14768, + "Creat": 14769, + "verter": 14770, + "▁Alice": 14771, + "пол": 14772, + "▁fraction": 14773, + "▁behaviour": 14774, + "▁Jersey": 14775, + "▁revenue": 14776, + "▁tres": 14777, + "ILD": 14778, + "▁Ét": 14779, + "▁sync": 14780, + "wich": 14781, + "▁ancest": 14782, + "ът": 14783, + "omo": 14784, + "▁Ide": 14785, + "▁gained": 14786, + "▁momentum": 14787, + "▁Ko": 14788, + "ieu": 14789, + "ielt": 14790, + "▁bonus": 14791, + "▁texture": 14792, + "Modal": 14793, + "NEXT": 14794, + "▁године": 14795, + "▁languages": 14796, + "vt": 14797, + "▁representing": 14798, + "▁Dream": 14799, + "curr": 14800, + "qual": 14801, + "▁js": 14802, + "burn": 14803, + "▁contributions": 14804, + "▁ric": 14805, + "}-\\": 14806, + "={{": 14807, + "cart": 14808, + "FB": 14809, + "jud": 14810, + "esp": 14811, + "▁electron": 14812, + "▁ell": 14813, + "▁Runtime": 14814, + "achel": 14815, + "\\_": 14816, + "week": 14817, + "packet": 14818, + "▁Secretary": 14819, + "▁Jahrhund": 14820, + "▁threshold": 14821, + "bage": 14822, + "▁concer": 14823, + "▁bone": 14824, + "▁Hollywood": 14825, + "Cursor": 14826, + "▁awarded": 14827, + "▁summary": 14828, + "aggio": 14829, + "▁stell": 14830, + "▁flesh": 14831, + "Pair": 14832, + "▁Age": 14833, + "ington": 14834, + "▁'.": 14835, + "aser": 14836, + "кова": 14837, + "▁quart": 14838, + "ryption": 14839, + "Alloc": 14840, + "ften": 14841, + "Operand": 14842, + "▁indicated": 14843, + "($_": 14844, + "getString": 14845, + "▁listener": 14846, + "spir": 14847, + ")_": 14848, + "vens": 14849, + "▁foods": 14850, + "anza": 14851, + "teil": 14852, + "DESC": 14853, + "▁notion": 14854, + "▁employment": 14855, + "▁swing": 14856, + "nbsp": 14857, + "▁pounds": 14858, + "tools": 14859, + "▁participate": 14860, + "▁Tax": 14861, + "▁скла": 14862, + "apol": 14863, + "▁fost": 14864, + "compat": 14865, + "▁publication": 14866, + "▁rapidly": 14867, + "▁Wis": 14868, + "EventListener": 14869, + "▁première": 14870, + "uso": 14871, + "extend": 14872, + "▁MERCHANTABILITY": 14873, + "UTF": 14874, + "▁experiments": 14875, + "single": 14876, + "zk": 14877, + "▁naj": 14878, + "}}}": 14879, + "Lin": 14880, + "▁interact": 14881, + "▁cms": 14882, + "▁Roger": 14883, + "▁Ру": 14884, + ">'": 14885, + "commit": 14886, + "лось": 14887, + "▁outcome": 14888, + "▁hits": 14889, + "▁им": 14890, + "▁spark": 14891, + "console": 14892, + "▁verw": 14893, + "▁като": 14894, + "agnostics": 14895, + "▁soci": 14896, + "▁dining": 14897, + "▁tech": 14898, + "št": 14899, + "folio": 14900, + "ultane": 14901, + "ктор": 14902, + "▁Brand": 14903, + "Join": 14904, + "▁ию": 14905, + "▁pros": 14906, + "▁posit": 14907, + "Public": 14908, + "AspNetCore": 14909, + "▁Shop": 14910, + "▁coinc": 14911, + "нием": 14912, + "▁references": 14913, + "about": 14914, + "namespace": 14915, + "DL": 14916, + "▁IR": 14917, + "▁cada": 14918, + "▁Jordan": 14919, + "▁gep": 14920, + "▁bron": 14921, + "andidate": 14922, + "EXPECT": 14923, + "amo": 14924, + "▁Deutsch": 14925, + "auc": 14926, + "▁райо": 14927, + "▁Labor": 14928, + "▁surrounded": 14929, + "тро": 14930, + "▁nome": 14931, + "▁underlying": 14932, + "▁educational": 14933, + "RIGHT": 14934, + "COUNT": 14935, + "inch": 14936, + "Typ": 14937, + "umph": 14938, + "four": 14939, + "Controls": 14940, + "▁cp": 14941, + "cost": 14942, + "▁mechanism": 14943, + "eness": 14944, + "équ": 14945, + "▁acquired": 14946, + "▁falls": 14947, + "▁Hou": 14948, + "▁LE": 14949, + "forEach": 14950, + "▁vertex": 14951, + "▁IF": 14952, + "curs": 14953, + "'=>": 14954, + "тери": 14955, + "▁SA": 14956, + "riers": 14957, + "▁uw": 14958, + "▁marks": 14959, + "▁energ": 14960, + "hof": 14961, + "ylvania": 14962, + "▁Allen": 14963, + "umpy": 14964, + "ого": 14965, + "ству": 14966, + "voice": 14967, + "▁engage": 14968, + "▁mant": 14969, + "orse": 14970, + "===": 14971, + "▁improvement": 14972, + "Opt": 14973, + "▁arrested": 14974, + "тия": 14975, + "▁сле": 14976, + "itched": 14977, + "socket": 14978, + "▁cycl": 14979, + "▁SM": 14980, + "▁Sex": 14981, + "▁neutral": 14982, + "вав": 14983, + "▁Jess": 14984, + "▁dip": 14985, + "▁opposition": 14986, + "▁borrow": 14987, + "спе": 14988, + "▁avant": 14989, + "кола": 14990, + "▁ta": 14991, + "Anim": 14992, + "▁Gall": 14993, + "rgb": 14994, + "▁guilty": 14995, + "▁buried": 14996, + "▁gy": 14997, + "Initial": 14998, + "▁accomp": 14999, + "▁breathing": 15000, + "berry": 15001, + "GRO": 15002, + "▁subsequent": 15003, + "roupe": 15004, + "ulpt": 15005, + "tb": 15006, + "▁ä": 15007, + "Pi": 15008, + "argv": 15009, + "▁Must": 15010, + ":'": 15011, + "svg": 15012, + "oup": 15013, + "▁precisely": 15014, + "▁Ta": 15015, + "rena": 15016, + "▁folder": 15017, + "▁Channel": 15018, + "▁revol": 15019, + "Miss": 15020, + "лом": 15021, + "reddit": 15022, + "adelph": 15023, + "▁discrim": 15024, + "▁ave": 15025, + "pleted": 15026, + "▁gently": 15027, + "FFFF": 15028, + "ropy": 15029, + "▁dial": 15030, + "NotFound": 15031, + "▁\"[": 15032, + "Home": 15033, + "onte": 15034, + "▁relie": 15035, + "▁Context": 15036, + "▁stats": 15037, + "▁Energy": 15038, + "ounced": 15039, + "▁grave": 15040, + "▁recip": 15041, + "лин": 15042, + "blog": 15043, + "▁naam": 15044, + "▁wo": 15045, + "▁directions": 15046, + "▁Lincoln": 15047, + "!)": 15048, + "unci": 15049, + "neq": 15050, + "Tags": 15051, + "▁tum": 15052, + "▁saving": 15053, + "aille": 15054, + "itemize": 15055, + "▁Famil": 15056, + "msm": 15057, + "news": 15058, + "FFER": 15059, + "▁Dead": 15060, + "▁territory": 15061, + "▁Kat": 15062, + "ocker": 15063, + "integer": 15064, + "▁sne": 15065, + "▁fails": 15066, + "▁français": 15067, + "▁introduction": 15068, + "▁Grant": 15069, + "ycle": 15070, + "'].": 15071, + "▁vier": 15072, + "native": 15073, + "▁Kle": 15074, + "quote": 15075, + "Users": 15076, + "▁advis": 15077, + "▁gym": 15078, + "▁protein": 15079, + "ال": 15080, + "▁Mai": 15081, + "▁providers": 15082, + "▁soil": 15083, + "gui": 15084, + "▁Nation": 15085, + "reation": 15086, + "▁Tab": 15087, + "ensis": 15088, + "inas": 15089, + "▁Scotland": 15090, + "▁dispatch": 15091, + "union": 15092, + "▁bere": 15093, + "▁Pow": 15094, + "▁Hig": 15095, + "▁studying": 15096, + "REF": 15097, + "SSL": 15098, + "▁fright": 15099, + "▁SORT": 15100, + "▁compr": 15101, + "▁Madrid": 15102, + "rowned": 15103, + "opes": 15104, + "pdev": 15105, + "▁wash": 15106, + "▁'../../": 15107, + "}}_": 15108, + "▁accum": 15109, + "rolling": 15110, + "▁NC": 15111, + "▁fiction": 15112, + "ipt": 15113, + "connected": 15114, + "limits": 15115, + "▁lap": 15116, + "▁whereas": 15117, + "prom": 15118, + "▁appointment": 15119, + "Program": 15120, + "▁Пер": 15121, + "nah": 15122, + "Validation": 15123, + "icons": 15124, + "äll": 15125, + "▁radical": 15126, + "▁exclusive": 15127, + "emony": 15128, + "▁challenging": 15129, + "▁ms": 15130, + "▁Private": 15131, + "▁vida": 15132, + "▁други": 15133, + "▁campus": 15134, + "forms": 15135, + "дно": 15136, + "plaat": 15137, + "bst": 15138, + "ATED": 15139, + "▁Abstract": 15140, + "▁intense": 15141, + "▁Ltd": 15142, + "▁controvers": 15143, + "óg": 15144, + "▁să": 15145, + "▁landing": 15146, + "!=": 15147, + "▁scenes": 15148, + "▁Chap": 15149, + "▁spoken": 15150, + "cred": 15151, + "▁pride": 15152, + "quet": 15153, + "▁meter": 15154, + "▁deutsch": 15155, + "uum": 15156, + "▁bless": 15157, + "▁Hann": 15158, + "▁inputs": 15159, + "▁Row": 15160, + "▁withdraw": 15161, + "Pal": 15162, + "acles": 15163, + "assets": 15164, + "▁vl": 15165, + "веде": 15166, + "▁Got": 15167, + "▁airport": 15168, + "wind": 15169, + "▁Columbia": 15170, + "▁chocolate": 15171, + "▁hö": 15172, + "▁alarm": 15173, + "FTWARE": 15174, + "▁Jay": 15175, + "▁sake": 15176, + "▁registration": 15177, + "vid": 15178, + "▁lake": 15179, + "▁username": 15180, + "▁hack": 15181, + "indexOf": 15182, + "cx": 15183, + "▁festival": 15184, + "▁clubs": 15185, + "cases": 15186, + "CTRL": 15187, + "];\r": 15188, + "▁Aud": 15189, + "▁primera": 15190, + "ват": 15191, + "▁brilliant": 15192, + "uther": 15193, + "▁difficulty": 15194, + "itals": 15195, + "▁scores": 15196, + "▁polít": 15197, + "database": 15198, + "aska": 15199, + "▁######": 15200, + "▁acid": 15201, + "aton": 15202, + "atomic": 15203, + "freq": 15204, + "▁WARRANTY": 15205, + "▁reporting": 15206, + ".),": 15207, + "▁nights": 15208, + "▁programme": 15209, + ")}{": 15210, + "xic": 15211, + "▁spo": 15212, + "lined": 15213, + "quarters": 15214, + "eree": 15215, + "mers": 15216, + "▁serves": 15217, + "cow": 15218, + "лько": 15219, + "enso": 15220, + "▁environ": 15221, + "Like": 15222, + "anche": 15223, + "▁crash": 15224, + "▁Kap": 15225, + "noindent": 15226, + "Conn": 15227, + "▁авто": 15228, + "▁infrastructure": 15229, + "IME": 15230, + "▁Room": 15231, + "need": 15232, + "orer": 15233, + "▁Dest": 15234, + "▁Domin": 15235, + "atherine": 15236, + "▁Sydney": 15237, + "▁gauge": 15238, + "▁jet": 15239, + "bably": 15240, + "▁commonly": 15241, + "▁stations": 15242, + "iah": 15243, + "nl": 15244, + "жу": 15245, + "eten": 15246, + "_)": 15247, + "iac": 15248, + "amos": 15249, + "nement": 15250, + "kon": 15251, + "Interval": 15252, + "▁cabin": 15253, + "▁eg": 15254, + "▁shots": 15255, + "▁Area": 15256, + "smith": 15257, + "parameter": 15258, + "'}": 15259, + "▁hem": 15260, + "▁singing": 15261, + "▁accessible": 15262, + "▁Prin": 15263, + "optional": 15264, + "ancial": 15265, + "ships": 15266, + "▁canvas": 15267, + "spe": 15268, + "▁addresses": 15269, + "▁xml": 15270, + "▁'\"": 15271, + "▁kar": 15272, + "öff": 15273, + "▁ages": 15274, + "ёр": 15275, + "zing": 15276, + "▁över": 15277, + "▁Clean": 15278, + "▁Silver": 15279, + "▁осо": 15280, + "health": 15281, + "Ali": 15282, + "▁ts": 15283, + "atern": 15284, + "▁choosing": 15285, + "▁burned": 15286, + "brid": 15287, + "rooms": 15288, + "ött": 15289, + "KERN": 15290, + "▁dish": 15291, + "Sa": 15292, + "Detail": 15293, + "▁Hind": 15294, + "▁Dans": 15295, + "ię": 15296, + "▁Jahren": 15297, + "extension": 15298, + "allas": 15299, + "▁Billy": 15300, + "usammen": 15301, + "itud": 15302, + "geon": 15303, + "Temp": 15304, + "Leg": 15305, + "ittel": 15306, + "addle": 15307, + "▁muscle": 15308, + "▁scared": 15309, + "sson": 15310, + "▁denote": 15311, + "ieurs": 15312, + "▁orange": 15313, + "▁hub": 15314, + "▁reb": 15315, + "edi": 15316, + "▁voices": 15317, + "Folder": 15318, + "▁suspend": 15319, + "▁Heart": 15320, + "▁scrap": 15321, + "▁aggreg": 15322, + "▁Guide": 15323, + "transaction": 15324, + "▁riding": 15325, + "▁vá": 15326, + "▁breed": 15327, + "▁concert": 15328, + "approx": 15329, + "▁chances": 15330, + "Tok": 15331, + "Eq": 15332, + "parts": 15333, + "▁scholar": 15334, + "offs": 15335, + "flush": 15336, + "!”": 15337, + "▁login": 15338, + "▁soort": 15339, + "▁Mand": 15340, + "▁functional": 15341, + "▁Bou": 15342, + "▁subjects": 15343, + "mys": 15344, + "▁extraord": 15345, + "▁Building": 15346, + "ikt": 15347, + "Bad": 15348, + "iami": 15349, + "Driver": 15350, + "ête": 15351, + "▁kv": 15352, + "▁timer": 15353, + "itionally": 15354, + "▁athlet": 15355, + "▁\");": 15356, + "wy": 15357, + "CFG": 15358, + "▁heaven": 15359, + "ов": 15360, + "▁experimental": 15361, + "▁bounds": 15362, + "ICK": 15363, + "▁excit": 15364, + "▁quit": 15365, + "▁universal": 15366, + "дь": 15367, + "▁SP": 15368, + "▁stub": 15369, + "▁kle": 15370, + "▁Bart": 15371, + "▁\"@": 15372, + "pel": 15373, + "▁(!(": 15374, + "▁selector": 15375, + "EB": 15376, + "▁coc": 15377, + "eted": 15378, + "ють": 15379, + "▁possess": 15380, + "▁Rick": 15381, + "▁unusual": 15382, + "termin": 15383, + "▁bags": 15384, + "▁loading": 15385, + "▁tf": 15386, + "▁)\r": 15387, + "provider": 15388, + "pletion": 15389, + "▁cursor": 15390, + "▁paused": 15391, + "им": 15392, + "▁counsel": 15393, + "]<": 15394, + "zech": 15395, + "▁tie": 15396, + "▁Moon": 15397, + "▁armed": 15398, + "▁observe": 15399, + "▁permet": 15400, + "▁Job": 15401, + "för": 15402, + "argument": 15403, + "▁eggs": 15404, + "ást": 15405, + "▁incredibly": 15406, + "werken": 15407, + "izard": 15408, + "▁painted": 15409, + "▁Vietnam": 15410, + "▁violent": 15411, + "Est": 15412, + "ierra": 15413, + "reader": 15414, + "weise": 15415, + "▁Josh": 15416, + "▁Him": 15417, + "ashes": 15418, + "origin": 15419, + "▁spir": 15420, + "▁Tree": 15421, + "▁niet": 15422, + "WIN": 15423, + "margin": 15424, + "▁involves": 15425, + "▁organis": 15426, + "▁Nacional": 15427, + "bara": 15428, + "▁depuis": 15429, + "pio": 15430, + "features": 15431, + "stru": 15432, + "▁Disney": 15433, + "▁restaurants": 15434, + "Mill": 15435, + "))\r": 15436, + "сла": 15437, + "remote": 15438, + "▁Third": 15439, + "▁baseball": 15440, + "▁algun": 15441, + "]$": 15442, + "▁employed": 15443, + "pot": 15444, + "▁UnityEngine": 15445, + "▁integration": 15446, + "▁risks": 15447, + "▁stro": 15448, + "▁agosto": 15449, + "including": 15450, + "▁Mind": 15451, + "▁stroke": 15452, + "▁deals": 15453, + "ajax": 15454, + "ёт": 15455, + "▁\\|": 15456, + "tar": 15457, + "adelphia": 15458, + "▁sab": 15459, + "pur": 15460, + "▁screw": 15461, + "▁inev": 15462, + "▁\\;": 15463, + "▁Donald": 15464, + "öd": 15465, + "cca": 15466, + "esis": 15467, + "▁separated": 15468, + "DBG": 15469, + "agent": 15470, + "▁packed": 15471, + "ння": 15472, + "intern": 15473, + "▁Monte": 15474, + "▁province": 15475, + "▁expanded": 15476, + "▁approached": 15477, + "▁Ep": 15478, + "CLK": 15479, + "▁ore": 15480, + "Batch": 15481, + "▁impressive": 15482, + "RM": 15483, + "▁Location": 15484, + "▁shame": 15485, + "wrapper": 15486, + "unwrap": 15487, + "peer": 15488, + "Bits": 15489, + "▁SN": 15490, + "scar": 15491, + "Come": 15492, + "▁council": 15493, + "▁shouted": 15494, + "making": 15495, + "▁Maur": 15496, + "▁wis": 15497, + "LETE": 15498, + "▁fs": 15499, + "▁dz": 15500, + "unque": 15501, + "uego": 15502, + "Random": 15503, + "Html": 15504, + "zem": 15505, + "▁Dutch": 15506, + "▁Golden": 15507, + "▁Tar": 15508, + "▁Herm": 15509, + "▁stretch": 15510, + "vard": 15511, + "▁tries": 15512, + "WI": 15513, + "▁disappeared": 15514, + "▁crusher": 15515, + "▁Kan": 15516, + "Mag": 15517, + "ør": 15518, + "▁Cambridge": 15519, + "▁dopo": 15520, + "atura": 15521, + "heart": 15522, + "▁Spiel": 15523, + "/**\r": 15524, + "Direction": 15525, + "atting": 15526, + "wig": 15527, + "▁codes": 15528, + "▁powder": 15529, + "alert": 15530, + "sembl": 15531, + "▁ye": 15532, + "Star": 15533, + "▁roots": 15534, + "▁Holl": 15535, + "Rele": 15536, + "▁constitu": 15537, + "nc": 15538, + "“.": 15539, + "reference": 15540, + "ificial": 15541, + "closure": 15542, + "▁figured": 15543, + "▁assumption": 15544, + "getElementById": 15545, + "▁AG": 15546, + "oses": 15547, + "▁_\"": 15548, + "epper": 15549, + "obre": 15550, + "enumerate": 15551, + "ографи": 15552, + "▁lessons": 15553, + "▁qualified": 15554, + "Person": 15555, + "anse": 15556, + "▁Mort": 15557, + "sylvania": 15558, + "▁cré": 15559, + "Binding": 15560, + "іс": 15561, + "▁Vari": 15562, + "▁reminded": 15563, + "▁membership": 15564, + "iper": 15565, + "zte": 15566, + "▁cref": 15567, + "▁PA": 15568, + "plaatst": 15569, + "▁Environment": 15570, + "boy": 15571, + "▁phrase": 15572, + "rivial": 15573, + "rag": 15574, + "води": 15575, + "▁pse": 15576, + "▁tournament": 15577, + ")},": 15578, + "▁Sound": 15579, + "▁Vel": 15580, + "▁Berg": 15581, + "elson": 15582, + "▁refuge": 15583, + "▁elsewhere": 15584, + "quality": 15585, + "▁abandoned": 15586, + "▁Flo": 15587, + "ibil": 15588, + "UAL": 15589, + "▁Platz": 15590, + "▁delta": 15591, + "▁Buy": 15592, + "rière": 15593, + "▁flour": 15594, + "▁laughing": 15595, + "▁Looking": 15596, + "Agent": 15597, + "▁wx": 15598, + "▁Wales": 15599, + "Ctx": 15600, + "▁cake": 15601, + "▁crate": 15602, + "▁кла": 15603, + "anga": 15604, + "Zero": 15605, + "▁amounts": 15606, + "Tra": 15607, + "ometric": 15608, + "▁constraints": 15609, + "▁temple": 15610, + "▁installation": 15611, + "stroke": 15612, + "▁Neder": 15613, + "ți": 15614, + "▁Ibid": 15615, + "▁obs": 15616, + "entries": 15617, + "▁jusqu": 15618, + "ORM": 15619, + "▁Sky": 15620, + "ikes": 15621, + "nak": 15622, + "▁modes": 15623, + "▁Hitler": 15624, + "▁belt": 15625, + "▁pointing": 15626, + "▁Ban": 15627, + "ignore": 15628, + "▁persu": 15629, + "▁Besides": 15630, + "ynom": 15631, + "▁legis": 15632, + "▁CPU": 15633, + "anded": 15634, + "uis": 15635, + "bsite": 15636, + "▁Euro": 15637, + "▁utter": 15638, + "eclipse": 15639, + "▁irre": 15640, + "▁Document": 15641, + "▁Meanwhile": 15642, + "▁familie": 15643, + "verify": 15644, + "▁Jason": 15645, + "▁Ort": 15646, + "▁ciudad": 15647, + "▁technologies": 15648, + "▁части": 15649, + "nica": 15650, + "cancel": 15651, + "Virtual": 15652, + "▁evident": 15653, + "aman": 15654, + "▁Supreme": 15655, + "atoes": 15656, + "▁steady": 15657, + "▁monthly": 15658, + "▁SOFTWARE": 15659, + "Die": 15660, + "▁applying": 15661, + "Dig": 15662, + "vier": 15663, + "▁горо": 15664, + "▁WH": 15665, + "▁minds": 15666, + "▁kam": 15667, + "▁expertise": 15668, + "▁notification": 15669, + ".-": 15670, + "▁deliber": 15671, + "▁HE": 15672, + "▁resist": 15673, + "outes": 15674, + "▁Howard": 15675, + "special": 15676, + "▁presentation": 15677, + "▁YouTube": 15678, + "mir": 15679, + "▁rust": 15680, + "▁nations": 15681, + "▁Gets": 15682, + "▁responses": 15683, + "arded": 15684, + "immer": 15685, + "▁reveal": 15686, + "▁Meg": 15687, + "▁todos": 15688, + "▁ade": 15689, + "ategories": 15690, + "▁payments": 15691, + "ôt": 15692, + "Enumer": 15693, + "▁platforms": 15694, + "▁lifetime": 15695, + "Complete": 15696, + "Quest": 15697, + "enders": 15698, + "▁cum": 15699, + "pler": 15700, + "▁appl": 15701, + "ährend": 15702, + "зь": 15703, + "enez": 15704, + "overty": 15705, + "ynchron": 15706, + "▁argued": 15707, + "▁Kath": 15708, + "▁synchron": 15709, + "▁Builder": 15710, + "Border": 15711, + "Plan": 15712, + "rieb": 15713, + "nm": 15714, + "FORMAT": 15715, + "usk": 15716, + "▁jumped": 15717, + "charg": 15718, + "▁contribute": 15719, + "Mesh": 15720, + "Univers": 15721, + "rell": 15722, + "▁polar": 15723, + "▁trois": 15724, + "icio": 15725, + "Groups": 15726, + "▁(%": 15727, + "Loop": 15728, + "▁gaz": 15729, + "dbg": 15730, + "LAY": 15731, + "John": 15732, + "blocks": 15733, + "▁lung": 15734, + "▁kön": 15735, + "through": 15736, + "▁fifth": 15737, + "lisher": 15738, + "▁involving": 15739, + "▁Deep": 15740, + "▁области": 15741, + "▁sull": 15742, + "Export": 15743, + "▁Kate": 15744, + "period": 15745, + "charge": 15746, + "GT": 15747, + "\">\r": 15748, + "тин": 15749, + "▁Ott": 15750, + "▁interactions": 15751, + "▁Toronto": 15752, + "TRACE": 15753, + "▁difer": 15754, + "▁liberal": 15755, + "▁particle": 15756, + "▁surve": 15757, + "alous": 15758, + "reason": 15759, + "▁depression": 15760, + "ал": 15761, + "▁flower": 15762, + "▁waar": 15763, + "▁hade": 15764, + "▁centuries": 15765, + "uty": 15766, + "party": 15767, + "▁approval": 15768, + "generate": 15769, + "▁Barn": 15770, + "▁marg": 15771, + "▁monde": 15772, + "▁ook": 15773, + "▁Clark": 15774, + "▁theoret": 15775, + "viously": 15776, + "?)": 15777, + "▁Rud": 15778, + "stmt": 15779, + "inction": 15780, + "▁tun": 15781, + "▁roads": 15782, + "▁rotation": 15783, + "ppen": 15784, + "sensor": 15785, + "▁Kol": 15786, + "idelines": 15787, + "▁є": 15788, + "▁composed": 15789, + "▁virus": 15790, + "'$": 15791, + "SN": 15792, + "▁Von": 15793, + "mont": 15794, + "lar": 15795, + "▁opinions": 15796, + "uction": 15797, + "rupal": 15798, + "underline": 15799, + "▁horror": 15800, + "Must": 15801, + "otto": 15802, + "Should": 15803, + "▁statist": 15804, + "▁gem": 15805, + "▁secre": 15806, + "▁strip": 15807, + "▁dirt": 15808, + "amazon": 15809, + "▁Round": 15810, + "▁discovery": 15811, + "▁GO": 15812, + "▁substantial": 15813, + "ibt": 15814, + "▁demands": 15815, + "▁everyday": 15816, + "▁besch": 15817, + "▁Bridge": 15818, + "▁HD": 15819, + "▁Dol": 15820, + "▁très": 15821, + "anni": 15822, + "roit": 15823, + "());\r": 15824, + "far": 15825, + "timestamp": 15826, + "▁bulk": 15827, + "Black": 15828, + "▁gan": 15829, + "setting": 15830, + "retval": 15831, + "ване": 15832, + "nung": 15833, + "▁talks": 15834, + "▁scientists": 15835, + "▁vig": 15836, + "▁quantity": 15837, + "▁Gard": 15838, + "▁movements": 15839, + "ähr": 15840, + "lings": 15841, + "▁Те": 15842, + "team": 15843, + "rito": 15844, + "▁assembly": 15845, + "ilst": 15846, + "▁happiness": 15847, + "▁leaf": 15848, + "▁assessment": 15849, + "Coord": 15850, + "irs": 15851, + "sam": 15852, + "▁attorney": 15853, + "▁geme": 15854, + "IDE": 15855, + "▁Vere": 15856, + "▁Anthony": 15857, + "amiento": 15858, + "▁Ast": 15859, + "▁circul": 15860, + "▁Frances": 15861, + "▁pent": 15862, + "▁mate": 15863, + "▁Transport": 15864, + "owo": 15865, + "чу": 15866, + "istes": 15867, + "TRAN": 15868, + "IMPORT": 15869, + "▁Break": 15870, + "▁sons": 15871, + "▁investors": 15872, + "▁Philipp": 15873, + "THOD": 15874, + "▁panic": 15875, + "▁:)": 15876, + "▁detection": 15877, + "▁simultane": 15878, + "nte": 15879, + "▁listened": 15880, + "кре": 15881, + "▁Brig": 15882, + "Optional": 15883, + "▁abund": 15884, + "▁criteria": 15885, + "▁chip": 15886, + "▁окру": 15887, + "▁Constant": 15888, + "▁mining": 15889, + "тал": 15890, + "mates": 15891, + "▁worship": 15892, + "router": 15893, + "CN": 15894, + "▁Match": 15895, + "▁Cole": 15896, + "▁downt": 15897, + "▁holes": 15898, + "▁grateful": 15899, + "RESULT": 15900, + "▁Europa": 15901, + "▁consent": 15902, + "lä": 15903, + "opter": 15904, + "▁colleagues": 15905, + "orous": 15906, + "▁enemies": 15907, + "hang": 15908, + "actual": 15909, + "Objects": 15910, + "▁як": 15911, + "▁fluid": 15912, + "fixed": 15913, + "▁Graph": 15914, + "▁scratch": 15915, + "cers": 15916, + "ribu": 15917, + "▁validation": 15918, + "▁completion": 15919, + "▁Begin": 15920, + "endpoint": 15921, + "rient": 15922, + "CM": 15923, + "▁Site": 15924, + "▁explains": 15925, + "tres": 15926, + "▁anybody": 15927, + "foreach": 15928, + "lon": 15929, + "Chain": 15930, + "▁Buff": 15931, + "ocal": 15932, + "▁Morgan": 15933, + "▁sang": 15934, + "▁passes": 15935, + "@@": 15936, + "ijd": 15937, + "Word": 15938, + "▁Hung": 15939, + "▁Fer": 15940, + "▁vý": 15941, + "bast": 15942, + "▁entertainment": 15943, + "hin": 15944, + "▁grat": 15945, + "▁Member": 15946, + "▁Minn": 15947, + "▁printed": 15948, + "▁Franklin": 15949, + "▁Imp": 15950, + "Machine": 15951, + "columns": 15952, + "▁deleted": 15953, + "▁manufacturing": 15954, + "▁rely": 15955, + "▁conse": 15956, + "▁fishing": 15957, + "blo": 15958, + "-$": 15959, + "▁.\"": 15960, + "▁clinical": 15961, + "▁Studies": 15962, + "▁Бу": 15963, + "definition": 15964, + "▁evaluation": 15965, + "▁attacked": 15966, + "▁frozen": 15967, + "zent": 15968, + "▁últ": 15969, + "▁rational": 15970, + "othe": 15971, + "Cancel": 15972, + "history": 15973, + "setText": 15974, + "▁alc": 15975, + "▁hydro": 15976, + "▁Theatre": 15977, + "▁Material": 15978, + "IOException": 15979, + "******/": 15980, + "spl": 15981, + "NODE": 15982, + "attrs": 15983, + "▁mie": 15984, + "▁offices": 15985, + "ró": 15986, + "▁jam": 15987, + "▁Ident": 15988, + "vé": 15989, + "Setting": 15990, + "▁Several": 15991, + "▁decay": 15992, + "Android": 15993, + "▁Save": 15994, + "unted": 15995, + "▁Mountain": 15996, + "usc": 15997, + "▁marzo": 15998, + "▁asleep": 15999, + "▁soldier": 16000, + "▁Double": 16001, + "PK": 16002, + "▁contrad": 16003, + "▁wins": 16004, + "ceiver": 16005, + "▁seasons": 16006, + "▁Chall": 16007, + "▁healthcare": 16008, + "ład": 16009, + "от": 16010, + "▁Five": 16011, + "▁Hell": 16012, + "▁worldwide": 16013, + "▁',": 16014, + "ян": 16015, + "made": 16016, + "▁responded": 16017, + "▁ay": 16018, + "▁procedures": 16019, + "тера": 16020, + "▁cleared": 16021, + "\"].": 16022, + "▁Target": 16023, + "▁Side": 16024, + "omin": 16025, + "▁deploy": 16026, + "▁Tell": 16027, + "▁ongoing": 16028, + "floor": 16029, + "▁bones": 16030, + "▁Delete": 16031, + "▁shrugged": 16032, + "Our": 16033, + "Der": 16034, + "▁initialize": 16035, + "▁Ted": 16036, + "MAGE": 16037, + "▁hire": 16038, + "▁tracking": 16039, + "▁ash": 16040, + "▁ceiling": 16041, + "ках": 16042, + "etti": 16043, + "▁courage": 16044, + "enschapp": 16045, + "ются": 16046, + "More": 16047, + "▁folg": 16048, + "▁Grace": 16049, + "▁Kelly": 16050, + "▁reven": 16051, + "▁Ali": 16052, + "▁disp": 16053, + "▁defeat": 16054, + "▁creature": 16055, + "▁Kennedy": 16056, + "▁Diego": 16057, + "EMP": 16058, + "▁steam": 16059, + "endance": 16060, + "rig": 16061, + "▁ignor": 16062, + "emen": 16063, + "▁Gru": 16064, + "▁proposal": 16065, + "▁weiter": 16066, + "▁лі": 16067, + "ibles": 16068, + "▁consideration": 16069, + "▁believes": 16070, + "▁Soph": 16071, + "“,": 16072, + "▁Matthew": 16073, + "▁circuit": 16074, + "▁singer": 16075, + "▁Square": 16076, + "ço": 16077, + "Edge": 16078, + "▁astr": 16079, + "▁representative": 16080, + "▁comprehensive": 16081, + "liga": 16082, + "▁mere": 16083, + "tbl": 16084, + "▁continuing": 16085, + "ographer": 16086, + "LED": 16087, + "▁/***/": 16088, + "▁sear": 16089, + "▁enormous": 16090, + "izi": 16091, + "Dit": 16092, + "there": 16093, + "ін": 16094, + "сите": 16095, + "▁guerra": 16096, + "▁endpoint": 16097, + "▁lesson": 16098, + "zon": 16099, + "variable": 16100, + "ис": 16101, + "▁researchers": 16102, + "▁attempted": 16103, + "▁enf": 16104, + "тура": 16105, + "▁defin": 16106, + "вест": 16107, + "▁awful": 16108, + "▁lowest": 16109, + "rules": 16110, + "▁unlike": 16111, + "interval": 16112, + "▁producing": 16113, + "▁Kam": 16114, + "▁IMP": 16115, + "General": 16116, + "▁faire": 16117, + "▁maxim": 16118, + "assemb": 16119, + "acent": 16120, + "?>": 16121, + "plica": 16122, + "▁ram": 16123, + "mate": 16124, + "цу": 16125, + "mn": 16126, + "▁Hi": 16127, + "▁stages": 16128, + "▁Editor": 16129, + "▁tang": 16130, + "RD": 16131, + "▁ich": 16132, + "▁dependent": 16133, + "lifer": 16134, + "ascript": 16135, + "▁exposure": 16136, + "рез": 16137, + "▁mart": 16138, + "▁Barcel": 16139, + "xspace": 16140, + "SESSION": 16141, + "▁prest": 16142, + "URCE": 16143, + "-.": 16144, + "▁село": 16145, + "have": 16146, + "▁observation": 16147, + "▁commands": 16148, + "▁eager": 16149, + "▁outdoor": 16150, + "▁DEBUG": 16151, + "▁hr": 16152, + "AX": 16153, + "▁puzz": 16154, + "blank": 16155, + "бур": 16156, + "▁kennis": 16157, + "▁regarded": 16158, + "▁}),": 16159, + "volume": 16160, + "▁произ": 16161, + "▁Training": 16162, + "añ": 16163, + "▁fois": 16164, + "▁три": 16165, + "вня": 16166, + "▁optimal": 16167, + "▁subscription": 16168, + "bridge": 16169, + "imental": 16170, + "▁Think": 16171, + "▁\";": 16172, + "▁legisl": 16173, + "▁Hop": 16174, + "▁branches": 16175, + "▁Veg": 16176, + "▁sprint": 16177, + "▁flux": 16178, + "▁Freder": 16179, + "sis": 16180, + "notify": 16181, + "▁Фран": 16182, + "som": 16183, + "nym": 16184, + "▁Ré": 16185, + "lett": 16186, + "ingham": 16187, + "▁Farm": 16188, + "DOM": 16189, + "▁shield": 16190, + "Here": 16191, + "▁Treat": 16192, + "▁Luke": 16193, + "▁unsafe": 16194, + "anton": 16195, + "▁Imper": 16196, + "▁telephone": 16197, + "▁unlock": 16198, + "Owner": 16199, + "collection": 16200, + "▁snd": 16201, + "▁suiv": 16202, + "▁entering": 16203, + "шен": 16204, + "▁Label": 16205, + "selector": 16206, + "▁GET": 16207, + "▁quando": 16208, + "▁fed": 16209, + "jQuery": 16210, + "Origin": 16211, + "▁Alan": 16212, + "mathscr": 16213, + "▁pregnant": 16214, + "Expect": 16215, + "resources": 16216, + "▁ersten": 16217, + "alia": 16218, + "▁retired": 16219, + "ût": 16220, + "Cred": 16221, + "▁méd": 16222, + "▁erh": 16223, + "Framework": 16224, + "Slot": 16225, + "duration": 16226, + "sal": 16227, + "▁composition": 16228, + "article": 16229, + "gpu": 16230, + "▁permitted": 16231, + "▁Font": 16232, + "▁Much": 16233, + "▁pending": 16234, + "▁agencies": 16235, + "Columns": 16236, + "▁klik": 16237, + "▁rating": 16238, + "mind": 16239, + "▁Pennsylvania": 16240, + "Java": 16241, + "abstract": 16242, + "▁dumb": 16243, + "▁VI": 16244, + "usa": 16245, + "Remote": 16246, + "▁YOU": 16247, + "▁Creek": 16248, + "мати": 16249, + "Bottom": 16250, + "▁rolling": 16251, + "▁bundle": 16252, + "▁golf": 16253, + "gpio": 16254, + "▁Chair": 16255, + "▁cls": 16256, + "$}": 16257, + "▁Parliament": 16258, + "führ": 16259, + "Many": 16260, + "▁Sep": 16261, + "▁badly": 16262, + "igi": 16263, + "▁Gemeinde": 16264, + "Ill": 16265, + "▁Ан": 16266, + "uart": 16267, + "itempty": 16268, + "▁Niger": 16269, + "▁immigr": 16270, + "Super": 16271, + "vá": 16272, + "istribute": 16273, + "Helpers": 16274, + "▁waters": 16275, + "▁joining": 16276, + "omitempty": 16277, + "▁Otherwise": 16278, + "▁Host": 16279, + "▁redd": 16280, + "▁dy": 16281, + "▁converted": 16282, + "▁prayer": 16283, + "▁Украї": 16284, + "▁elections": 16285, + "reb": 16286, + "erie": 16287, + "▁свя": 16288, + "Abs": 16289, + "iembre": 16290, + "holders": 16291, + "▁Rol": 16292, + "utschen": 16293, + "▁Gh": 16294, + "tery": 16295, + "анг": 16296, + "▁narrative": 16297, + "minus": 16298, + "▁Iron": 16299, + "=\"#": 16300, + "▁wand": 16301, + "▁wished": 16302, + "icode": 16303, + "orr": 16304, + "[[": 16305, + "▁detected": 16306, + "▁municipal": 16307, + "▁Pour": 16308, + "▁Serv": 16309, + "citet": 16310, + "▁grey": 16311, + "▁Rap": 16312, + "▁voy": 16313, + "▁lleg": 16314, + "▁currency": 16315, + "▁Script": 16316, + "strument": 16317, + "▁expecting": 16318, + "▁tickets": 16319, + "▁bucket": 16320, + "egr": 16321, + "▁jacket": 16322, + "drv": 16323, + "▁loans": 16324, + "▁kann": 16325, + "▁integral": 16326, + "▁characteristics": 16327, + "(\".": 16328, + "▁manual": 16329, + "▁dynamics": 16330, + ":*": 16331, + "sha": 16332, + "reens": 16333, + "onical": 16334, + "▁toile": 16335, + "aña": 16336, + "▁distant": 16337, + "▁handled": 16338, + "Bool": 16339, + "▁penal": 16340, + "▁Things": 16341, + "▁prominent": 16342, + "▁exped": 16343, + "▁Help": 16344, + "▁asp": 16345, + "lap": 16346, + "▁Auth": 16347, + "Basic": 16348, + "achuset": 16349, + "▁Bild": 16350, + "▁entitled": 16351, + "▁jag": 16352, + "▁rejected": 16353, + "▁memor": 16354, + "orts": 16355, + "▁applies": 16356, + "▁Language": 16357, + "specific": 16358, + "achusetts": 16359, + "HAND": 16360, + "▁Route": 16361, + "market": 16362, + "▁Ky": 16363, + "▁pose": 16364, + "ACHE": 16365, + "poll": 16366, + "▁rocks": 16367, + "bone": 16368, + "▁DIS": 16369, + "Watch": 16370, + "▁smiling": 16371, + "рио": 16372, + "Month": 16373, + "▁efter": 16374, + "construct": 16375, + "▁bands": 16376, + "▁collaboration": 16377, + "ними": 16378, + "glas": 16379, + "▁vy": 16380, + "▁engagement": 16381, + "__)": 16382, + "▁wings": 16383, + "ким": 16384, + "netje": 16385, + "ativa": 16386, + "▁Duke": 16387, + "лее": 16388, + "▁Within": 16389, + "▁dove": 16390, + "▁cb": 16391, + "yers": 16392, + "pow": 16393, + "[(": 16394, + "▁evaluate": 16395, + "Points": 16396, + "▁рі": 16397, + "odigd": 16398, + "onomy": 16399, + "▁Illinois": 16400, + "▁Typ": 16401, + "▁coordinates": 16402, + "pisode": 16403, + "ucked": 16404, + "▁flav": 16405, + "▁brands": 16406, + "▁calendar": 16407, + "Lib": 16408, + "▁uitgen": 16409, + "▁tale": 16410, + "▁briefly": 16411, + "▁mic": 16412, + "RESS": 16413, + "▁später": 16414, + "▁integrated": 16415, + "▁cookies": 16416, + "▁uitgenodigd": 16417, + "▁Priv": 16418, + "▁phenomen": 16419, + "▁voegen": 16420, + "Supp": 16421, + "▁refers": 16422, + "пад": 16423, + "▁Clinton": 16424, + "▁assignment": 16425, + "inals": 16426, + "▁asym": 16427, + "cycle": 16428, + "▁Anderson": 16429, + "▁binding": 16430, + "rique": 16431, + "hind": 16432, + "▁behalf": 16433, + "▁Fle": 16434, + "▁breaks": 16435, + "▁soap": 16436, + "вар": 16437, + "▁vä": 16438, + "▁crying": 16439, + "▁→": 16440, + "▁msm": 16441, + "▁boots": 16442, + "owing": 16443, + "▁bell": 16444, + "suite": 16445, + "▁Bundes": 16446, + "Year": 16447, + "ndef": 16448, + "Other": 16449, + "▁google": 16450, + "ENCE": 16451, + "WER": 16452, + "Les": 16453, + "Shared": 16454, + "▁ED": 16455, + "IFT": 16456, + "▁floating": 16457, + "ým": 16458, + "{},": 16459, + "Binary": 16460, + "▁roce": 16461, + "raj": 16462, + "▁bewerken": 16463, + "BF": 16464, + "▁Hur": 16465, + "cen": 16466, + "▁ere": 16467, + "▁camb": 16468, + "▁Pakistan": 16469, + "▁greatly": 16470, + "▁logging": 16471, + "/.": 16472, + "Tensor": 16473, + "▁opens": 16474, + "▁Rio": 16475, + "▁klikken": 16476, + "▁sculpt": 16477, + "apore": 16478, + "wx": 16479, + "▁Nich": 16480, + "nan": 16481, + "▁injured": 16482, + "compare": 16483, + "tha": 16484, + "Sample": 16485, + "Shell": 16486, + "▁commander": 16487, + "▁receiver": 16488, + "▁hopes": 16489, + "▁byl": 16490, + "▁proxy": 16491, + "▁gall": 16492, + "getId": 16493, + "▁Bab": 16494, + "feld": 16495, + "▁\"_": 16496, + "▁Hab": 16497, + "simple": 16498, + "▁executed": 16499, + "▁ate": 16500, + "▁animation": 16501, + "▁inhab": 16502, + "▁боль": 16503, + "▁router": 16504, + "▁glob": 16505, + "Geplaatst": 16506, + "▁beginnetje": 16507, + "▁Kur": 16508, + "▁Ха": 16509, + "aligned": 16510, + "▁certificate": 16511, + "▁Å": 16512, + ".).": 16513, + "▁soll": 16514, + "▁Import": 16515, + "реди": 16516, + "▁pandemic": 16517, + "▁nic": 16518, + "vä": 16519, + "▁Gree": 16520, + "▁Say": 16521, + "▁ді": 16522, + "▁Num": 16523, + "▁roughly": 16524, + "▁después": 16525, + "▁​": 16526, + "▁specify": 16527, + "Mapper": 16528, + "licht": 16529, + "▁thumb": 16530, + "wie": 16531, + "▁unlikely": 16532, + "▁Edd": 16533, + "Hey": 16534, + "▁Opt": 16535, + "BLOCK": 16536, + "вор": 16537, + "▁×": 16538, + "▁ba": 16539, + "▁periods": 16540, + "▁titles": 16541, + "Med": 16542, + "▁fon": 16543, + "▁bast": 16544, + "▁Forest": 16545, + "▁№": 16546, + "onds": 16547, + "▁fal": 16548, + "▁gesch": 16549, + "direction": 16550, + "IFY": 16551, + "▁LA": 16552, + "▁(((": 16553, + "GTH": 16554, + "itudes": 16555, + "▁destruction": 16556, + "▁Ja": 16557, + "▁stake": 16558, + "ifferent": 16559, + "▁identical": 16560, + "▁fog": 16561, + "▁Reb": 16562, + "ские": 16563, + "ступ": 16564, + "jax": 16565, + "▁Mars": 16566, + "▁historic": 16567, + "▁Vo": 16568, + "▁entrepre": 16569, + "▁tension": 16570, + "▁WHERE": 16571, + "▁Philadelphia": 16572, + "Counter": 16573, + "▁frames": 16574, + "▁muy": 16575, + "ej": 16576, + "öt": 16577, + "eu": 16578, + "▁челове": 16579, + "PROC": 16580, + "▁resolved": 16581, + "▁tape": 16582, + "цион": 16583, + "▁singular": 16584, + "▁personnel": 16585, + "▁Mun": 16586, + "▁Occ": 16587, + "▁scalar": 16588, + "dess": 16589, + "▁cable": 16590, + "being": 16591, + "▁Jenn": 16592, + "▁erst": 16593, + "Actions": 16594, + "Environment": 16595, + "via": 16596, + "▁struggling": 16597, + "▁DVD": 16598, + "whe": 16599, + "▁throwing": 16600, + "Bounds": 16601, + "▁MD": 16602, + "▁\"../": 16603, + "▁satisfy": 16604, + "▁Colorado": 16605, + "▁Active": 16606, + "Tasks": 16607, + "<>();": 16608, + "▁slipped": 16609, + "▁poison": 16610, + "zb": 16611, + "Dispatch": 16612, + "warning": 16613, + "▁ultimate": 16614, + "picture": 16615, + "expression": 16616, + "▁Talk": 16617, + "▁flick": 16618, + "▁raising": 16619, + "▁transactions": 16620, + "▁glance": 16621, + "▁gri": 16622, + "▁през": 16623, + "selection": 16624, + "ња": 16625, + "endl": 16626, + "▁Abb": 16627, + "▁bold": 16628, + "▁maintained": 16629, + "Exists": 16630, + "▁encouraged": 16631, + "Qual": 16632, + "▁essere": 16633, + "▁hired": 16634, + "letter": 16635, + "itches": 16636, + "others": 16637, + "▁woj": 16638, + "▁injuries": 16639, + "▁dil": 16640, + "execut": 16641, + "▁Steel": 16642, + "▁Garden": 16643, + "зя": 16644, + "\\,\\": 16645, + "▁Angel": 16646, + "prim": 16647, + ">:]<": 16648, + "gb": 16649, + "peat": 16650, + "inte": 16651, + "▁apolog": 16652, + "▁regulations": 16653, + "Src": 16654, + "kh": 16655, + "Upload": 16656, + "mapping": 16657, + "▁presents": 16658, + "▁poetry": 16659, + "▁stops": 16660, + "▁Tol": 16661, + "▁tower": 16662, + "▁OUT": 16663, + "Thank": 16664, + "▁organic": 16665, + "▁drei": 16666, + "▁pound": 16667, + "century": 16668, + "▁modules": 16669, + "▁дере": 16670, + "▁worn": 16671, + "▁parad": 16672, + "▁Cos": 16673, + "fic": 16674, + "▁без": 16675, + "▁Jimmy": 16676, + "▁lands": 16677, + "▁minist": 16678, + "vspace": 16679, + "▁lighting": 16680, + "▁naked": 16681, + "▁designer": 16682, + "▁Stream": 16683, + "TMP": 16684, + "Center": 16685, + "resentation": 16686, + "ONT": 16687, + "▁ers": 16688, + "▁measurement": 16689, + "▁muscles": 16690, + "▁Ign": 16691, + "▁COM": 16692, + "▁fru": 16693, + "▁genre": 16694, + "▁alpha": 16695, + "▁retirement": 16696, + "▁Gon": 16697, + "ől": 16698, + "contents": 16699, + "▁healing": 16700, + "▁sido": 16701, + "incipal": 16702, + "Permission": 16703, + "рак": 16704, + "▁Gordon": 16705, + "▁Rank": 16706, + "▁Autom": 16707, + "Constructor": 16708, + "wiki": 16709, + "▁concerning": 16710, + "rizona": 16711, + "▁variant": 16712, + "▁arranged": 16713, + "▁Spr": 16714, + "BPACK": 16715, + "Timestamp": 16716, + "restore": 16717, + "aware": 16718, + "▁Observ": 16719, + "▁SV": 16720, + "ipp": 16721, + "▁Executive": 16722, + "▁colleg": 16723, + "▁explicitly": 16724, + "written": 16725, + "▁Kön": 16726, + "irus": 16727, + "▁Hold": 16728, + "▁Pract": 16729, + "Character": 16730, + "▁redistribute": 16731, + "uerto": 16732, + "▁Student": 16733, + "▁elder": 16734, + "▁Dop": 16735, + "vp": 16736, + "▁Hub": 16737, + "▁grounds": 16738, + "▁Ry": 16739, + "▁signals": 16740, + "▁gifts": 16741, + "▁strengthen": 16742, + "▁Lyn": 16743, + "commun": 16744, + "▁най": 16745, + "▁finance": 16746, + "noc": 16747, + "helm": 16748, + "▁cuts": 16749, + "▁adventure": 16750, + "▁Ric": 16751, + "▁intellectual": 16752, + "▁Output": 16753, + "▁awk": 16754, + "▁concentration": 16755, + "▁guidance": 16756, + "Buff": 16757, + "▁filling": 16758, + "▁regul": 16759, + "▁delicious": 16760, + "([]": 16761, + "ших": 16762, + "▁tons": 16763, + "activity": 16764, + "GP": 16765, + "LOB": 16766, + "stadt": 16767, + "tal": 16768, + "▁img": 16769, + "▁rush": 16770, + "attice": 16771, + "▁pok": 16772, + "steps": 16773, + "▁lid": 16774, + "▁DNA": 16775, + "Browser": 16776, + "▁ladies": 16777, + "▁années": 16778, + "▁rescue": 16779, + "avity": 16780, + "rock": 16781, + "▁glasses": 16782, + "▁Bey": 16783, + ")}$": 16784, + "detail": 16785, + "▁dés": 16786, + "tax": 16787, + "▁favourite": 16788, + "▁precision": 16789, + "▁conoc": 16790, + "Ms": 16791, + "▁Native": 16792, + "▁Pil": 16793, + "InputStream": 16794, + "orp": 16795, + "▁Pap": 16796, + "▁picking": 16797, + "iph": 16798, + "Loading": 16799, + "▁priest": 16800, + "Hook": 16801, + "▁pist": 16802, + "▁Une": 16803, + "%,": 16804, + "▁bil": 16805, + "▁conservative": 16806, + "eval": 16807, + "iking": 16808, + "'},": 16809, + "▁sauce": 16810, + "▁Due": 16811, + "assen": 16812, + "▁occasionally": 16813, + "▁Дж": 16814, + "unknown": 16815, + "DED": 16816, + "▁drum": 16817, + "▁dub": 16818, + "ATURE": 16819, + "usage": 16820, + "getType": 16821, + "reply": 16822, + "▁strategic": 16823, + "▁kap": 16824, + "design": 16825, + "datetime": 16826, + "▁Prim": 16827, + "Master": 16828, + "▁Corps": 16829, + "▁considerable": 16830, + "▁Tu": 16831, + "▁ла": 16832, + "▁tous": 16833, + "▁clar": 16834, + "▁poem": 16835, + "album": 16836, + "]*": 16837, + "loaded": 16838, + "▁traveling": 16839, + "вые": 16840, + "▁Ferr": 16841, + "▁pharm": 16842, + "abi": 16843, + "▁}\\": 16844, + "collect": 16845, + "▁Bour": 16846, + "OC": 16847, + "▁measurements": 16848, + "▁Professional": 16849, + "▁sensor": 16850, + "utsche": 16851, + "▁demanded": 16852, + "▁accompanied": 16853, + "▁prend": 16854, + "▁encoding": 16855, + "▁Geschichte": 16856, + "▁mig": 16857, + "▁Gib": 16858, + "▁Reich": 16859, + "▁myster": 16860, + "▁Mock": 16861, + "▁physically": 16862, + "▁Bau": 16863, + "▁Single": 16864, + "▁managing": 16865, + "▁Kil": 16866, + "▁Temple": 16867, + "▁lev": 16868, + "▁lí": 16869, + "CPU": 16870, + "▁Premier": 16871, + "▁Give": 16872, + "iri": 16873, + "NV": 16874, + "▁AI": 16875, + "▁fp": 16876, + "лександ": 16877, + "▁tant": 16878, + "▁fot": 16879, + "Nullable": 16880, + "▁guards": 16881, + "Once": 16882, + "▁chamber": 16883, + "film": 16884, + "▁bias": 16885, + "▁Tai": 16886, + "insic": 16887, + "▁ml": 16888, + "▁Ka": 16889, + "вал": 16890, + "▁SER": 16891, + "▁Someone": 16892, + "}}_{": 16893, + "Fixed": 16894, + "▁bent": 16895, + "▁prohib": 16896, + "▁bid": 16897, + "▁fewer": 16898, + "кры": 16899, + "▁lugar": 16900, + "▁deserve": 16901, + "ssl": 16902, + "▁cfg": 16903, + "reck": 16904, + "▁stability": 16905, + "resize": 16906, + "▁assertThat": 16907, + "Trigger": 16908, + "▁станов": 16909, + "plugins": 16910, + "▁lets": 16911, + "хід": 16912, + "▁Laura": 16913, + "нер": 16914, + "▁brut": 16915, + "▁FI": 16916, + "isons": 16917, + "▁dyn": 16918, + "icher": 16919, + "rayed": 16920, + "▁frequent": 16921, + "▁jedoch": 16922, + "▁Marine": 16923, + "strings": 16924, + "▁Util": 16925, + "▁bos": 16926, + "Mus": 16927, + "▁Portugal": 16928, + "Strategy": 16929, + "▁посе": 16930, + "▁slice": 16931, + "▁insight": 16932, + "▁widget": 16933, + "▁général": 16934, + "messages": 16935, + "▁Hu": 16936, + "▁requirement": 16937, + "Side": 16938, + "emplates": 16939, + "▁ceremony": 16940, + "▁physics": 16941, + "▁graduate": 16942, + "para": 16943, + "▁preserv": 16944, + "▁shops": 16945, + "zek": 16946, + "▁ub": 16947, + "prepare": 16948, + "▁Oil": 16949, + "▁fib": 16950, + "▁runtime": 16951, + "▁hogy": 16952, + "Warning": 16953, + "▁Convert": 16954, + "bourne": 16955, + "▁emerged": 16956, + "▁Ди": 16957, + "ighth": 16958, + "guard": 16959, + "kal": 16960, + "validation": 16961, + "ência": 16962, + "▁drinks": 16963, + "theorem": 16964, + "HR": 16965, + "iev": 16966, + "ployee": 16967, + "Usage": 16968, + "▁спе": 16969, + "dispatch": 16970, + "▁instantly": 16971, + "obi": 16972, + "▁justify": 16973, + "▁Nev": 16974, + "▁явля": 16975, + "agra": 16976, + "▁transmission": 16977, + "fly": 16978, + ";';": 17789, + "▁cousin": 17790, + "createElement": 17791, + "Could": 17792, + "▁capac": 17793, + "▁pause": 17794, + "ArrayList": 17795, + "kte": 17796, + "ordered": 17797, + "▁shaking": 17798, + "labels": 17799, + "▁reducing": 17800, + "вых": 17801, + "USED": 17802, + "▁voting": 17803, + "▁Ministry": 17804, + "▁Mig": 17805, + "▁Chen": 17806, + "▁accompany": 17807, + "ulle": 17808, + "▁ga": 17809, + "▁equipped": 17810, + "▁nun": 17811, + "Bet": 17812, + "▁licensed": 17813, + "ARCH": 17814, + "FN": 17815, + "▁engines": 17816, + "▁ster": 17817, + "▁locale": 17818, + "▁въ": 17819, + "links": 17820, + "▁Capital": 17821, + "▁alien": 17822, + "Wr": 17823, + "ръ": 17824, + "Cart": 17825, + "▁Marketing": 17826, + "▁RT": 17827, + "FileName": 17828, + "▁ti": 17829, + "iji": 17830, + "▁versus": 17831, + "live": 17832, + "Sym": 17833, + "kor": 17834, + "▁emission": 17835, + "umm": 17836, + "ycz": 17837, + "▁climbed": 17838, + "▁plusieurs": 17839, + "кри": 17840, + "yar": 17841, + "osten": 17842, + "▁usb": 17843, + "▁crossing": 17844, + "▁polynom": 17845, + "▁removal": 17846, + "▁Adams": 17847, + "▁ihre": 17848, + "anden": 17849, + "▁Benj": 17850, + "▁Phill": 17851, + "▁wounded": 17852, + "▁Castle": 17853, + "bild": 17854, + "Annotation": 17855, + "Processor": 17856, + "▁tin": 17857, + "folg": 17858, + "▁Students": 17859, + "▁Mexican": 17860, + "▁administrative": 17861, + "ILED": 17862, + "▁conqu": 17863, + "▁cheer": 17864, + "▁Ces": 17865, + "Because": 17866, + "▁Juni": 17867, + "▁encontr": 17868, + "avi": 17869, + "VI": 17870, + "aku": 17871, + "▁Ton": 17872, + "▁smoking": 17873, + "▁bay": 17874, + "works": 17875, + "ат": 17876, + "attered": 17877, + "▁Boolean": 17878, + "▁Balt": 17879, + "defer": 17880, + "pathy": 17881, + "Ah": 17882, + "▁akt": 17883, + "▁governor": 17884, + "Pad": 17885, + "▁sisters": 17886, + "Lat": 17887, + "▁revel": 17888, + "▁SY": 17889, + "itos": 17890, + "▁filters": 17891, + "Chunk": 17892, + "consum": 17893, + "▁removing": 17894, + "▁Herr": 17895, + "▁generator": 17896, + "▁Cra": 17897, + "▁farmers": 17898, + "▁Members": 17899, + "▁overcome": 17900, + "▁Cin": 17901, + "igkeit": 17902, + "criptions": 17903, + "Tests": 17904, + "▁клу": 17905, + "▁shake": 17906, + "▁yy": 17907, + "placement": 17908, + "▁awards": 17909, + "▁episodes": 17910, + "▁Blood": 17911, + "▁bullet": 17912, + "▁viene": 17913, + "▁Financial": 17914, + "Future": 17915, + "▁rou": 17916, + "▁biologie": 17917, + "▁useState": 17918, + "iani": 17919, + "piece": 17920, + "▁speaker": 17921, + "▁refr": 17922, + "ARK": 17923, + "▁MIT": 17924, + "▁Tan": 17925, + "▁Based": 17926, + "▁cultiv": 17927, + "▁hungry": 17928, + "▁Ay": 17929, + "▁Hey": 17930, + "▁excitement": 17931, + "ibraries": 17932, + "Hit": 17933, + "▁Ende": 17934, + "NG": 17935, + "FIL": 17936, + ".\")": 17937, + "Family": 17938, + "inery": 17939, + "necess": 17940, + "velope": 17941, + "▁Bot": 17942, + "porter": 17943, + "▁climb": 17944, + "▁Eli": 17945, + "urent": 17946, + "▁mistakes": 17947, + "ában": 17948, + "marks": 17949, + "pkt": 17950, + "Library": 17951, + "sted": 17952, + "ublice": 17953, + "▁Administration": 17954, + "▁shapes": 17955, + "публи": 17956, + "God": 17957, + "innen": 17958, + "коло": 17959, + "<<<<": 17960, + "ibe": 17961, + "ês": 17962, + "▁США": 17963, + "▁Foreign": 17964, + "▁Margaret": 17965, + "▁gene": 17966, + "▁disturb": 17967, + "▁тер": 17968, + "▁onClick": 17969, + "▁Engineering": 17970, + "▁stopping": 17971, + "▁restrictions": 17972, + ",*": 17973, + "BUF": 17974, + "▁shadows": 17975, + "hci": 17976, + "▁Christians": 17977, + "▁fence": 17978, + "▁luxury": 17979, + "akh": 17980, + "coord": 17981, + "▁investigate": 17982, + "▁conventional": 17983, + "\"—": 17984, + "▁visits": 17985, + "isé": 17986, + "▁Sac": 17987, + "className": 17988, + "▁Psych": 17989, + "▁reflected": 17990, + "▁пло": 17991, + "▁Vice": 17992, + "ław": 17993, + "________________": 17994, + "▁Wolf": 17995, + "rente": 17996, + "▁Champion": 17997, + "▁simulation": 17998, + "esota": 17999, + "▁Soon": 18000, + "▁Cel": 18001, + "▁theories": 18002, + "▁STR": 18003, + "▁collective": 18004, + "▁coordinate": 18005, + "querySelector": 18006, + "emed": 18007, + "Break": 18008, + "▁gef": 18009, + "▁electricity": 18010, + "▁gathering": 18011, + "aters": 18012, + "exper": 18013, + "▁Roma": 18014, + "▁Cooper": 18015, + "SYMBOL": 18016, + "vd": 18017, + "iversary": 18018, + "aines": 18019, + "▁Grad": 18020, + "▁independence": 18021, + "woh": 18022, + "▁consequence": 18023, + "▁conversations": 18024, + "▁Rou": 18025, + "▁andere": 18026, + "▁Systems": 18027, + "гар": 18028, + "▁moist": 18029, + "flu": 18030, + "ція": 18031, + "ниш": 18032, + "▁rode": 18033, + "▁perd": 18034, + "▁szer": 18035, + "▁flood": 18036, + "▁intim": 18037, + "stderr": 18038, + "▁reflection": 18039, + "Scan": 18040, + "▁disaster": 18041, + "akespe": 18042, + "▁Invalid": 18043, + "▁humor": 18044, + "▁Friedrich": 18045, + "▁suggestions": 18046, + "uvud": 18047, + "Delay": 18048, + "brief": 18049, + "▁ис": 18050, + "glied": 18051, + "fas": 18052, + "▁Smart": 18053, + "▁medi": 18054, + "sdk": 18055, + "▁seus": 18056, + "▁Arizona": 18057, + "▁innocent": 18058, + "Warn": 18059, + "acious": 18060, + "▁Moscow": 18061, + "▁caps": 18062, + "Delegate": 18063, + "▁dramatic": 18064, + "books": 18065, + "▁shore": 18066, + "uki": 18067, + "▁Russell": 18068, + "▁correlation": 18069, + "Help": 18070, + "▁pubblic": 18071, + "zym": 18072, + "comb": 18073, + "EY": 18074, + "LENGTH": 18075, + "▁Mün": 18076, + "▁_.": 18077, + "▁ferm": 18078, + "▁Ian": 18079, + "▁Studio": 18080, + "▁affairs": 18081, + "los": 18082, + "Rules": 18083, + "running": 18084, + "▁Posted": 18085, + "Pixel": 18086, + "▁dancing": 18087, + "▁agreements": 18088, + "▁Pic": 18089, + "ancia": 18090, + "▁má": 18091, + "ationToken": 18092, + "descriptor": 18093, + "▁Carter": 18094, + "Release": 18095, + "************": 18096, + "▁outstanding": 18097, + "changes": 18098, + "ARRAY": 18099, + "▁Barbara": 18100, + "▁nurse": 18101, + "(\r": 18102, + "▁Douglas": 18103, + "▁nucle": 18104, + "ouri": 18105, + "▁Style": 18106, + "avo": 18107, + "▁painful": 18108, + "▁slic": 18109, + "▁seinem": 18110, + "SUPPORT": 18111, + "ogene": 18112, + "▁satell": 18113, + "tagon": 18114, + "▁collapse": 18115, + "velle": 18116, + "MON": 18117, + "aughters": 18118, + "▁threatened": 18119, + "▁Illegal": 18120, + "▁desperate": 18121, + "strict": 18122, + "rus": 18123, + "ститу": 18124, + "\\\":": 18125, + "▁conflic": 18126, + "download": 18127, + "atos": 18128, + "▁Position": 18129, + ".*;": 18130, + "▁theater": 18131, + "▁pleasant": 18132, + "▁Cette": 18133, + "▁Singapore": 18134, + "heet": 18135, + "▁pir": 18136, + "▁acquis": 18137, + "▁назва": 18138, + "теля": 18139, + "▁recru": 18140, + "жения": 18141, + "ёл": 18142, + "версите": 18143, + "▁respective": 18144, + "▁tunnel": 18145, + "▁Dean": 18146, + "Du": 18147, + "▁uncle": 18148, + "▁offensive": 18149, + "colo": 18150, + "▁Unlike": 18151, + "series": 18152, + "▁Arn": 18153, + "minute": 18154, + "▁descriptor": 18155, + "▁stones": 18156, + "ICATION": 18157, + "▁Pad": 18158, + "▁iPhone": 18159, + "ei": 18160, + "▁fantasy": 18161, + "▁Korean": 18162, + "\"}": 18163, + "▁orth": 18164, + "halten": 18165, + "deep": 18166, + "▁Kay": 18167, + "requency": 18168, + "▁duties": 18169, + "awt": 18170, + "▁nearest": 18171, + "▁disorder": 18172, + "стру": 18173, + "▁Chile": 18174, + "▁seq": 18175, + "▁transportation": 18176, + "OO": 18177, + "▁Dez": 18178, + "iju": 18179, + "▁Results": 18180, + "jed": 18181, + "ivel": 18182, + "HOST": 18183, + "▁€": 18184, + "▁Î": 18185, + "▁chin": 18186, + "▁matt": 18187, + "▁voted": 18188, + "▁gehör": 18189, + "▁▁▁▁▁▁▁▁▁▁▁": 18190, + "▁sue": 18191, + "▁legacy": 18192, + "вся": 18193, + "SOURCE": 18194, + "WORK": 18195, + "itis": 18196, + "▁$|": 18197, + "▁обо": 18198, + "▁nr": 18199, + "▁Tamb": 18200, + "▁snap": 18201, + "▁impressed": 18202, + "▁deposit": 18203, + "▁divid": 18204, + "Segment": 18205, + "▁кар": 18206, + "▁Gas": 18207, + "▁crimes": 18208, + "▁insult": 18209, + "▁Hum": 18210, + "▁bounded": 18211, + "▁kicked": 18212, + "▁Му": 18213, + "▁|\\": 18214, + "added": 18215, + "Produ": 18216, + "▁./": 18217, + "▁awkward": 18218, + "▁Кра": 18219, + "▁ї": 18220, + "▁CONTR": 18221, + "▁beim": 18222, + "▁placeholder": 18223, + "spi": 18224, + "▁Bei": 18225, + "▁Pf": 18226, + "ientes": 18227, + "disk": 18228, + "blk": 18229, + "neo": 18230, + "itarian": 18231, + "▁cogn": 18232, + "▁sout": 18233, + "▁trash": 18234, + "▁Rab": 18235, + "▁decline": 18236, + "tat": 18237, + "▁combine": 18238, + "▁Tot": 18239, + "▁drops": 18240, + "Times": 18241, + "cheduler": 18242, + "▁governments": 18243, + "Tex": 18244, + "▁Used": 18245, + "зан": 18246, + "▁pd": 18247, + "мет": 18248, + "▁&=&": 18249, + "▁Nag": 18250, + "▁дол": 18251, + "▁Always": 18252, + "rtc": 18253, + "ске": 18254, + "▁performances": 18255, + "rupted": 18256, + "▁два": 18257, + "▁managers": 18258, + "▁Pitt": 18259, + "▁mystery": 18260, + "▁settle": 18261, + "ulse": 18262, + "cross": 18263, + "question": 18264, + "asha": 18265, + "seed": 18266, + "urable": 18267, + "Final": 18268, + "++++": 18269, + "inputs": 18270, + "▁backup": 18271, + "▁Learning": 18272, + "▁*,": 18273, + "logo": 18274, + "▁seinen": 18275, + "▁vulnerable": 18276, + "directory": 18277, + "ië": 18278, + "▁friendship": 18279, + "tu": 18280, + "▁Vec": 18281, + "rifice": 18282, + "▁бра": 18283, + "▁involve": 18284, + "TON": 18285, + "▁corrid": 18286, + "separ": 18287, + "Destroy": 18288, + "▁jul": 18289, + "▁inequality": 18290, + "▁ain": 18291, + "hex": 18292, + "▁wider": 18293, + "тели": 18294, + "▁jack": 18295, + "▁quot": 18296, + "▁Glen": 18297, + "initely": 18298, + "ihood": 18299, + "▁waist": 18300, + "▁Manchester": 18301, + "regular": 18302, + "▁(&": 18303, + "▁masses": 18304, + "▁DEFAULT": 18305, + "▁chairs": 18306, + "▁Fast": 18307, + "▁citt": 18308, + "_{{\\": 18309, + "oa": 18310, + "▁$\\{": 18311, + "▁seeds": 18312, + "▁Ald": 18313, + "▁Batt": 18314, + "fab": 18315, + "▁democracy": 18316, + "DTO": 18317, + "▁Hij": 18318, + "PTR": 18319, + "Na": 18320, + "▁Harvard": 18321, + "sid": 18322, + "Pred": 18323, + "fers": 18324, + "▁spare": 18325, + "AMP": 18326, + "▁groupe": 18327, + "▁sender": 18328, + "▁Christopher": 18329, + "▁prisoners": 18330, + "▁Ker": 18331, + "▁Crist": 18332, + "▁ALL": 18333, + "rice": 18334, + "▁antes": 18335, + "natural": 18336, + "▁Susan": 18337, + "▁Juli": 18338, + "▁diab": 18339, + "ixon": 18340, + "icator": 18341, + "▁flexible": 18342, + "▁reserve": 18343, + "Contains": 18344, + "▁Hil": 18345, + "▁Isa": 18346, + "▁towns": 18347, + "GS": 18348, + "▁Trad": 18349, + "▁Lock": 18350, + "▁Grund": 18351, + "▁criticism": 18352, + "ню": 18353, + "▁că": 18354, + "▁politician": 18355, + "stable": 18356, + "Accept": 18357, + "Summary": 18358, + "▁também": 18359, + "}^{-": 18360, + "▁IM": 18361, + "idal": 18362, + "мор": 18363, + "Blue": 18364, + "GROUP": 18365, + "▁terminal": 18366, + "▁complexity": 18367, + "▁locally": 18368, + "DOWN": 18369, + "▁Near": 18370, + "Depth": 18371, + "▁pole": 18372, + "▁equality": 18373, + "Site": 18374, + "▁isinstance": 18375, + "Speed": 18376, + "ippi": 18377, + ",&": 18378, + "▁Enc": 18379, + "щен": 18380, + "▁mater": 18381, + "▁slaves": 18382, + "ACTION": 18383, + "usalem": 18384, + "▁haz": 18385, + "▁Beat": 18386, + "▁wrest": 18387, + "▁llam": 18388, + "Ins": 18389, + "мина": 18390, + "▁був": 18391, + "▁Frame": 18392, + "ushes": 18393, + "▁virtually": 18394, + "▁Perm": 18395, + "▁weights": 18396, + "▁llvm": 18397, + "▁cave": 18398, + "states": 18399, + "DMA": 18400, + "ellt": 18401, + "ifact": 18402, + "vendor": 18403, + "▁Emma": 18404, + "Locale": 18405, + "▁SET": 18406, + "▁geometry": 18407, + "Styles": 18408, + "▁Referee": 18409, + "▁weit": 18410, + "fica": 18411, + "▁ads": 18412, + "gray": 18413, + "▁Burg": 18414, + "iona": 18415, + "dagger": 18416, + "▁Januar": 18417, + "дей": 18418, + "isterschaft": 18419, + "ppo": 18420, + "oids": 18421, + "▁départ": 18422, + "Shader": 18423, + "▁constraint": 18424, + "Secret": 18425, + "▁Peters": 18426, + "▁eyeb": 18427, + "▁mesh": 18428, + "▁cookie": 18429, + "▁Pick": 18430, + "▁nick": 18431, + "bye": 18432, + "▁savings": 18433, + "Try": 18434, + "python": 18435, + "▁patri": 18436, + "▁multip": 18437, + "▁kinda": 18438, + "▁'_": 18439, + "▁Franz": 18440, + "▁cloth": 18441, + "зульта": 18442, + "▁fleet": 18443, + "▁humanity": 18444, + "resa": 18445, + "blob": 18446, + "▁TX": 18447, + "▁Buch": 18448, + "▁Lond": 18449, + "▁valley": 18450, + "▁murm": 18451, + "▁Trade": 18452, + "linewidth": 18453, + "▁especial": 18454, + "upper": 18455, + "▁hosp": 18456, + "▁tanto": 18457, + "▁oldest": 18458, + "▁Roose": 18459, + "▁hitting": 18460, + "dog": 18461, + "ovi": 18462, + "},\r": 18463, + "▁compatible": 18464, + "▁Website": 18465, + "poch": 18466, + "▁Bag": 18467, + "▁accomplish": 18468, + "Christ": 18469, + "asset": 18470, + "▁Until": 18471, + "▁geld": 18472, + "Listen": 18473, + "SB": 18474, + "Setup": 18475, + "icia": 18476, + "▁lum": 18477, + "▁janvier": 18478, + "PAGE": 18479, + "▁Nu": 18480, + "/\"": 18481, + "▁divorce": 18482, + "Execute": 18483, + "Depend": 18484, + "▁Scottish": 18485, + "▁Ts": 18486, + "ruppe": 18487, + "▁refuse": 18488, + "▁Oktober": 18489, + "ijk": 18490, + "▁Amy": 18491, + "▁dimin": 18492, + "▁gross": 18493, + "▁trat": 18494, + "isible": 18495, + "mixer": 18496, + "▁autres": 18497, + "▁neat": 18498, + "▁otros": 18499, + "Void": 18500, + "▁schol": 18501, + "▁Walker": 18502, + "▁tube": 18503, + "ologists": 18504, + "▁груп": 18505, + "▁haben": 18506, + "uber": 18507, + "ACTIVE": 18508, + "▁Attendance": 18509, + "▁оп": 18510, + "▁blade": 18511, + "oplus": 18512, + "▁Original": 18513, + "▁manufacturer": 18514, + "asz": 18515, + "âte": 18516, + "rer": 18517, + "▁Json": 18518, + "▁succeeded": 18519, + "uffle": 18520, + "▁backed": 18521, + "esian": 18522, + "tick": 18523, + "External": 18524, + "▁XIX": 18525, + "▁hearts": 18526, + "▁После": 18527, + "olu": 18528, + "▁лет": 18529, + "VICE": 18530, + "ário": 18531, + "▁fraud": 18532, + "edu": 18533, + "Primary": 18534, + "▁gaming": 18535, + "▁plt": 18536, + "igator": 18537, + "IES": 18538, + "Compiler": 18539, + "▁monument": 18540, + "agem": 18541, + "▁Rain": 18542, + "▁moins": 18543, + "oku": 18544, + "osex": 18545, + "▁Kansas": 18546, + "▁gepublice": 18547, + "▁Joy": 18548, + "Scene": 18549, + "▁kingdom": 18550, + "rices": 18551, + "▁juin": 18552, + "▁uncomfortable": 18553, + "▁Money": 18554, + "obb": 18555, + "expl": 18556, + "strcmp": 18557, + "▁dread": 18558, + "rition": 18559, + "▁Chi": 18560, + "▁demonstrated": 18561, + "▁vertices": 18562, + "чо": 18563, + "▁Culture": 18564, + "FX": 18565, + "Dictionary": 18566, + "▁Dru": 18567, + "trm": 18568, + "▁examine": 18569, + "▁therap": 18570, + "ième": 18571, + "мини": 18572, + "▁produces": 18573, + "▁photographs": 18574, + "▁threads": 18575, + "▁MI": 18576, + "▁extraordinary": 18577, + "ским": 18578, + "▁gepubliceerd": 18579, + "▁Poland": 18580, + "▁guaranteed": 18581, + "RG": 18582, + "osc": 18583, + "али": 18584, + "▁тех": 18585, + "errno": 18586, + "science": 18587, + "iffs": 18588, + "▁Tam": 18589, + "▁Beth": 18590, + "▁Travel": 18591, + "▁translate": 18592, + "ché": 18593, + "▁ling": 18594, + "▁belongs": 18595, + "▁electrical": 18596, + "ensk": 18597, + "▁Compet": 18598, + "cg": 18599, + "VC": 18600, + "topic": 18601, + "▁presum": 18602, + "вета": 18603, + "▁approximation": 18604, + "▁grim": 18605, + "▁Из": 18606, + "_{(": 18607, + "вин": 18608, + "ution": 18609, + "owych": 18610, + "åg": 18611, + "sterreich": 18612, + "▁characteristic": 18613, + "oming": 18614, + "▁/*!": 18615, + "▁prize": 18616, + "▁Minnesota": 18617, + "ted": 18618, + "цы": 18619, + "▁Om": 18620, + "▁indices": 18621, + "▁stem": 18622, + "regon": 18623, + "ниче": 18624, + "▁Salv": 18625, + "ése": 18626, + "▁aged": 18627, + "▁Past": 18628, + "▁internation": 18629, + "▁Vic": 18630, + "▁resume": 18631, + "akespeare": 18632, + "▁estado": 18633, + "▁abilities": 18634, + "▁brow": 18635, + "▁NFL": 18636, + "▁trends": 18637, + "▁Austin": 18638, + "▁LIMIT": 18639, + "▁Kor": 18640, + "▁folk": 18641, + "▁ward": 18642, + "▁nest": 18643, + "▁Junior": 18644, + "▁maintaining": 18645, + "Pub": 18646, + "OBJECT": 18647, + "▁bloody": 18648, + "▁sj": 18649, + "▁dtype": 18650, + "Pane": 18651, + "▁bacter": 18652, + "▁gradually": 18653, + "mr": 18654, + "Team": 18655, + "▁indicating": 18656, + "▁decrease": 18657, + "tek": 18658, + "▁Represent": 18659, + "▁developers": 18660, + "Guid": 18661, + "▁Diet": 18662, + "▁retr": 18663, + "Navigation": 18664, + "esi": 18665, + "▁lazy": 18666, + "Standard": 18667, + "Er": 18668, + "AW": 18669, + "▁États": 18670, + "▁assured": 18671, + "San": 18672, + "▁Andre": 18673, + "’,": 18674, + "fang": 18675, + "ération": 18676, + "▁industries": 18677, + "▁incon": 18678, + "Emit": 18679, + "▁где": 18680, + "▁retriev": 18681, + "eni": 18682, + "▁Turkey": 18683, + "izers": 18684, + "Angle": 18685, + "▁oc": 18686, + "▁palm": 18687, + "▁stan": 18688, + "льно": 18689, + "▁CSS": 18690, + "▁frances": 18691, + "▁grin": 18692, + "▁tiempo": 18693, + "▁Prix": 18694, + "]).": 18695, + "▁deput": 18696, + "▁Pin": 18697, + "▁sixt": 18698, + "▁predicted": 18699, + "azure": 18700, + "▁Motor": 18701, + "▁ihm": 18702, + "▁manus": 18703, + "apos": 18704, + "▁instruments": 18705, + "▁counts": 18706, + "▁aimed": 18707, + "profit": 18708, + "▁dok": 18709, + "обра": 18710, + "▁estud": 18711, + "iesz": 18712, + "▁piss": 18713, + "▁inaug": 18714, + "▁voters": 18715, + "▁packages": 18716, + "▁cute": 18717, + "▁fitness": 18718, + "▁leurs": 18719, + "▁sorted": 18720, + "phant": 18721, + "OPT": 18722, + "▁zip": 18723, + "season": 18724, + "emi": 18725, + "encoding": 18726, + "won": 18727, + "elect": 18728, + "▁tooth": 18729, + "▁upcoming": 18730, + "▁Graham": 18731, + "nut": 18732, + "▁Ark": 18733, + "ält": 18734, + "▁precious": 18735, + "agle": 18736, + "née": 18737, + "ница": 18738, + "aris": 18739, + "▁pile": 18740, + "cole": 18741, + "▁WITH": 18742, + "routing": 18743, + "▁***": 18744, + "Appearance": 18745, + "llvm": 18746, + "▁Oliver": 18747, + "▁PL": 18748, + "ifndef": 18749, + "etzt": 18750, + "skiego": 18751, + "▁pon": 18752, + "ARGET": 18753, + "kö": 18754, + "alled": 18755, + "▁=\\": 18756, + "sure": 18757, + "matches": 18758, + "▁temperatures": 18759, + "SEL": 18760, + "▁clone": 18761, + "▁eller": 18762, + "erna": 18763, + "▁поло": 18764, + "Management": 18765, + "company": 18766, + "▁lun": 18767, + "▁streaming": 18768, + "▁Ni": 18769, + "▁sí": 18770, + "Contact": 18771, + "▁Credit": 18772, + "▁Oak": 18773, + "▁представ": 18774, + "radius": 18775, + "cli": 18776, + "IENT": 18777, + "▁Lucy": 18778, + "▁calculation": 18779, + "▁pixel": 18780, + "▁mul": 18781, + "▁outcomes": 18782, + "▁centers": 18783, + "▁residence": 18784, + "Constraint": 18785, + "▁preserve": 18786, + "peon": 18787, + "uffix": 18788, + "▁Roberts": 18789, + "▁promot": 18790, + "?!": 18791, + "balance": 18792, + "▁courts": 18793, + "▁disg": 18794, + "PRINT": 18795, + "▁их": 18796, + "elfare": 18797, + "▁retreat": 18798, + "▁Ав": 18799, + "Cost": 18800, + "also": 18801, + "▁Für": 18802, + "▁März": 18803, + "DIO": 18804, + "▁bez": 18805, + "AUTH": 18806, + "Den": 18807, + "▁atom": 18808, + "▁roman": 18809, + "▁Pel": 18810, + "▁Roosevelt": 18811, + "▁Plant": 18812, + "Contents": 18813, + "▁Between": 18814, + "▁coupling": 18815, + "structure": 18816, + "▁Marshall": 18817, + "▁Career": 18818, + "▁railway": 18819, + "▁Bureau": 18820, + "▁possibilities": 18821, + "▁kor": 18822, + "){\r": 18823, + "mero": 18824, + "mov": 18825, + "англ": 18826, + "AIN": 18827, + "mund": 18828, + "lette": 18829, + "▁summar": 18830, + "▁describing": 18831, + "▁NAS": 18832, + "▁Emb": 18833, + "Instruction": 18834, + "liest": 18835, + "▁Sig": 18836, + "Bill": 18837, + "▁verd": 18838, + "plant": 18839, + "▁galaxies": 18840, + "\"])": 18841, + "▁PyObject": 18842, + "▁Gy": 18843, + "▁mě": 18844, + "▁organisation": 18845, + "Her": 18846, + "Sep": 18847, + "ocom": 18848, + "▁Same": 18849, + "▁bite": 18850, + "▁Seattle": 18851, + "зыва": 18852, + "Observer": 18853, + "’.": 18854, + "▁morph": 18855, + "urches": 18856, + "alph": 18857, + "reement": 18858, + "consin": 18859, + "^-": 18860, + "▁dann": 18861, + "translate": 18862, + "вих": 18863, + "React": 18864, + "▁cats": 18865, + "▁brew": 18866, + "▁ds": 18867, + "▁circles": 18868, + "▁drift": 18869, + "agma": 18870, + "▁Valent": 18871, + "PIN": 18872, + "ARM": 18873, + "▁surviv": 18874, + "alin": 18875, + "Pref": 18876, + "friendly": 18877, + "▁uncertainty": 18878, + "▁fd": 18879, + "▁engineer": 18880, + "Ben": 18881, + "icular": 18882, + "orest": 18883, + "▁horizontal": 18884, + "UTC": 18885, + "textrm": 18886, + "Live": 18887, + "Score": 18888, + "▁Germans": 18889, + "distance": 18890, + "uti": 18891, + "▁équ": 18892, + "▁numerical": 18893, + "▁reass": 18894, + "Activ": 18895, + "▁cod": 18896, + "bullet": 18897, + "ensing": 18898, + "▁Gem": 18899, + "▁navigation": 18900, + "addClass": 18901, + "▁simultaneously": 18902, + "вий": 18903, + "▁його": 18904, + "▁Hö": 18905, + "▁harsh": 18906, + "precated": 18907, + "ССР": 18908, + "▁Equip": 18909, + "adget": 18910, + "▁TYPE": 18911, + "▁mg": 18912, + "IGH": 18913, + "▁vin": 18914, + "▁findings": 18915, + "ivan": 18916, + "▁possession": 18917, + "▁того": 18918, + "▁parsed": 18919, + "riors": 18920, + "zeichnet": 18921, + "ников": 18922, + "Worker": 18923, + "▁enables": 18924, + "▁($\\": 18925, + "▁Copy": 18926, + "▁orientation": 18927, + "стре": 18928, + "▁Indians": 18929, + "▁Gary": 18930, + "▁Insurance": 18931, + "isan": 18932, + "Chat": 18933, + "▁comun": 18934, + "▁coron": 18935, + "ография": 18936, + "updated": 18937, + "▁Ин": 18938, + "These": 18939, + "SEC": 18940, + "▁boyfriend": 18941, + "Diagnostics": 18942, + "Hint": 18943, + "mul": 18944, + "▁inode": 18945, + "xA": 18946, + "eft": 18947, + "OPTION": 18948, + "unct": 18949, + "annon": 18950, + "ENS": 18951, + "strip": 18952, + "▁enthusi": 18953, + "▁Whit": 18954, + "▁Фи": 18955, + "aude": 18956, + "▁disagree": 18957, + "▁snapped": 18958, + "Phys": 18959, + "▁Syn": 18960, + "▁sour": 18961, + "▁Lux": 18962, + "ugar": 18963, + "tile": 18964, + "▁infection": 18965, + "▁Feb": 18966, + "▁Chem": 18967, + "dataset": 18968, + "chts": 18969, + "Dynamic": 18970, + "▁сред": 18971, + "▁queen": 18972, + "worker": 18973, + "swap": 18974, + "▁timestamp": 18975, + "▁Integr": 18976, + "▁interviews": 18977, + "such": 18978, + "▁laughter": 18979, + "prof": 18980, + "▁Bird": 18981, + "(|": 18982, + "ân": 18983, + "▁gra": 18984, + "&=": 18985, + "zens": 18986, + "getMessage": 18987, + "▁Ost": 18988, + "▁gab": 18989, + "▁mortgage": 18990, + "multicol": 18991, + "LEVEL": 18992, + "partition": 18993, + "seen": 18994, + "▁declar": 18995, + "AU": 18996, + "▁ox": 18997, + "▁ligger": 18998, + "▁Carm": 18999, + "geme": 19000, + "▁Vegas": 19001, + "▁Eug": 19002, + "orus": 19003, + "▁brick": 19004, + "▁así": 19005, + "▁Magazine": 19006, + "HasColumnType": 19007, + "VR": 19008, + "licher": 19009, + "▁Future": 19010, + "▁Jug": 19011, + "attan": 19012, + "constructor": 19013, + "VP": 19014, + "▁тур": 19015, + "чина": 19016, + "Comparator": 19017, + "▁authentic": 19018, + "▁monster": 19019, + "▁transformed": 19020, + "▁firms": 19021, + "FW": 19022, + "▁catalog": 19023, + "boards": 19024, + "▁diseases": 19025, + "▁Benjamin": 19026, + "▁horizon": 19027, + "▁Available": 19028, + "Mvc": 19029, + "Stud": 19030, + "▁lord": 19031, + "general": 19032, + "пар": 19033, + "▁cabinet": 19034, + "▁Basic": 19035, + "TestCase": 19036, + "ansk": 19037, + "▁Snow": 19038, + "ierten": 19039, + "▁vocal": 19040, + "Padding": 19041, + "halt": 19042, + "▁Alexand": 19043, + "▁Colomb": 19044, + "ivamente": 19045, + "▁artificial": 19046, + "▁Atlanta": 19047, + "▁mentre": 19048, + "▁estaba": 19049, + "jekt": 19050, + "▁slept": 19051, + "▁endless": 19052, + "éro": 19053, + "attery": 19054, + "uur": 19055, + "▁weakness": 19056, + "▁attempting": 19057, + "BYTE": 19058, + "▁founder": 19059, + "▁salv": 19060, + "▁Medicine": 19061, + "tid": 19062, + "▁Schwe": 19063, + "raction": 19064, + "▁¿": 19065, + "crate": 19066, + "SERVER": 19067, + "▁compound": 19068, + "▁conve": 19069, + "▁caf": 19070, + "▁handful": 19071, + "onne": 19072, + "ública": 19073, + "▁defensive": 19074, + "Alignment": 19075, + "▁préc": 19076, + "▁significance": 19077, + "élé": 19078, + "arta": 19079, + "Dam": 19080, + "▁perpet": 19081, + "▁caller": 19082, + "icients": 19083, + "cep": 19084, + "▁Multi": 19085, + "▁stolen": 19086, + "▁focusing": 19087, + "embed": 19088, + "▁bree": 19089, + "▁AB": 19090, + "▁occasions": 19091, + "sea": 19092, + "Prov": 19093, + "чение": 19094, + "▁Category": 19095, + "▁sq": 19096, + "▁Фе": 19097, + "VA": 19098, + "Diff": 19099, + "Tri": 19100, + "issement": 19101, + "▁actress": 19102, + "▁Пе": 19103, + "▁jej": 19104, + "▁twisted": 19105, + "▁Nicol": 19106, + "▁junior": 19107, + "Sound": 19108, + "▁Brasil": 19109, + "▁juice": 19110, + "▁>>>": 19111, + "▁Alb": 19112, + "▁softly": 19113, + "▁McK": 19114, + "▁Gren": 19115, + "▁italiano": 19116, + "▁creatures": 19117, + "▁residential": 19118, + "▁Instagram": 19119, + "ucks": 19120, + "▁killer": 19121, + "▁Johnny": 19122, + "▁enterprise": 19123, + "Dto": 19124, + "chestra": 19125, + "▁Tel": 19126, + "▁Activ": 19127, + "factor": 19128, + "oust": 19129, + "▁vacuum": 19130, + "рал": 19131, + "')->": 19132, + "▁Left": 19133, + "▁defect": 19134, + "▁ninete": 19135, + "fare": 19136, + "▁regret": 19137, + "▁shar": 19138, + "ctrine": 19139, + "mesh": 19140, + "city": 19141, + "icit": 19142, + "▁Fem": 19143, + "limited": 19144, + "oka": 19145, + "!\\!\\": 19146, + "Donald": 19147, + "зно": 19148, + "▁provision": 19149, + "▁discussions": 19150, + "Drag": 19151, + "▁Incl": 19152, + "Exit": 19153, + "▁Abd": 19154, + "story": 19155, + "ieve": 19156, + "▁był": 19157, + "olving": 19158, + "wohner": 19159, + "▁guidelines": 19160, + "▁straw": 19161, + "üss": 19162, + "▁було": 19163, + "▁burden": 19164, + "▁spatial": 19165, + "▁stretched": 19166, + "▁Inf": 19167, + "▁typedef": 19168, + "▁robot": 19169, + "▁Doc": 19170, + "pliers": 19171, + "wal": 19172, + "camp": 19173, + "▁diffé": 19174, + "▁McG": 19175, + "▁tel": 19176, + "arette": 19177, + "▁subsequently": 19178, + "▁honey": 19179, + "FUNC": 19180, + "▁establishment": 19181, + "tesy": 19182, + "▁który": 19183, + "▁сель": 19184, + "▁FO": 19185, + "▁Islands": 19186, + "▁mp": 19187, + "Scalar": 19188, + "▁Yan": 19189, + "cken": 19190, + "▁variation": 19191, + "ią": 19192, + "optim": 19193, + "azor": 19194, + "tuple": 19195, + "▁gravity": 19196, + "▁conclude": 19197, + "▁collections": 19198, + "ész": 19199, + "▁Liver": 19200, + "▁ethnic": 19201, + "compile": 19202, + "▁parl": 19203, + "Surface": 19204, + "{'": 19205, + "▁paragraph": 19206, + "posite": 19207, + "ítulo": 19208, + "oba": 19209, + "binary": 19210, + "rob": 19211, + "▁Pedro": 19212, + "▁fis": 19213, + "▁Grande": 19214, + "odox": 19215, + "▁posting": 19216, + "": 27113, + "olent": 27114, + "▁этого": 27115, + "▁Generic": 27116, + "▁*/,": 27117, + "▁combinations": 27118, + "▁rejo": 27119, + "спубли": 27120, + "capacity": 27121, + "▁traces": 27122, + "▁opacity": 27123, + "▁Official": 27124, + "icion": 27125, + "▁emotionally": 27126, + "▁Joel": 27127, + "ському": 27128, + "▁legendary": 27129, + "▁pam": 27130, + "▁También": 27131, + ".<": 27132, + "iba": 27133, + "midt": 27134, + "бом": 27135, + "▁ensuite": 27136, + "Authorization": 27137, + "Pag": 27138, + "▁helmet": 27139, + "▁territo": 27140, + "secondary": 27141, + "▁segunda": 27142, + "▁Wire": 27143, + "recated": 27144, + "▁invoked": 27145, + "▁ValueError": 27146, + "▁фо": 27147, + "ALIGN": 27148, + "CURRENT": 27149, + "\\+\\_\\": 27150, + "▁compilation": 27151, + "ær": 27152, + "▁Palmar": 27153, + "▁influences": 27154, + "/:": 27155, + "Mix": 27156, + "NOP": 27157, + "econom": 27158, + "▁tucked": 27159, + "▁});\r": 27160, + "ANK": 27161, + "reject": 27162, + "▁pension": 27163, + "▁generates": 27164, + "чё": 27165, + "▁incap": 27166, + "▁clicked": 27167, + "▁fus": 27168, + "ourses": 27169, + "▁Easter": 27170, + "%;": 27171, + "zin": 27172, + "▁obligations": 27173, + "▁Tips": 27174, + "};\r": 27175, + ".\"_": 27176, + "▁BSD": 27177, + "ática": 27178, + "▁expose": 27179, + "Pars": 27180, + "▁Amanda": 27181, + "куп": 27182, + "▁guessed": 27183, + "dsi": 27184, + "▁Leip": 27185, + "Broad": 27186, + "▁Hughes": 27187, + "ié": 27188, + "▁Wahl": 27189, + "▁formerly": 27190, + "Relative": 27191, + "▁Yu": 27192, + "▁Mountains": 27193, + "▁Enum": 27194, + "▁strang": 27195, + "_-": 27196, + "recht": 27197, + "viv": 27198, + "pause": 27199, + "▁Londres": 27200, + "▁elbow": 27201, + "▁Hawaii": 27202, + "▁Casino": 27203, + "Threshold": 27204, + "Units": 27205, + "Include": 27206, + "ито": 27207, + "asury": 27208, + "▁steht": 27209, + "▁damned": 27210, + "▁packets": 27211, + "▁Werk": 27212, + "▁elevator": 27213, + "iedad": 27214, + "govern": 27215, + "▁CONTRACT": 27216, + "mals": 27217, + "▁remem": 27218, + "▁entonces": 27219, + "▁vas": 27220, + "▁sympathy": 27221, + "▁befindet": 27222, + "incing": 27223, + "DataSet": 27224, + "▁additionally": 27225, + "▁musician": 27226, + "шего": 27227, + "▁listop": 27228, + ">\")": 27229, + "Printf": 27230, + "▁Felix": 27231, + "▁carved": 27232, + "▁nicely": 27233, + "гом": 27234, + "chap": 27235, + "▁Nieder": 27236, + "▁Lav": 27237, + "▁modifications": 27238, + "moment": 27239, + "▁balcon": 27240, + "▁dependency": 27241, + "CKET": 27242, + "▁vanished": 27243, + "▁fighters": 27244, + "▁zunächst": 27245, + "ioctl": 27246, + "▁defens": 27247, + "▁Nem": 27248, + "Utility": 27249, + "▁curv": 27250, + "▁DAMAGES": 27251, + "▁Rogers": 27252, + "▁gratitude": 27253, + "▁Denmark": 27254, + "рая": 27255, + "grpc": 27256, + "▁juni": 27257, + "▁октября": 27258, + "▁immense": 27259, + "▁prevented": 27260, + "▁foam": 27261, + "▁Extra": 27262, + "aimed": 27263, + "▁Criteria": 27264, + "▁Simply": 27265, + "boxes": 27266, + "▁Legend": 27267, + "▁Players": 27268, + "▁Mercedes": 27269, + "▁Branch": 27270, + "TERN": 27271, + "omena": 27272, + "▁incorporate": 27273, + "conde": 27274, + "▁Estado": 27275, + "▁wasted": 27276, + "▁complaining": 27277, + "▁warriors": 27278, + "oter": 27279, + "▁этом": 27280, + "▁conten": 27281, + "▁machinery": 27282, + "▁technological": 27283, + "▁TD": 27284, + "▁gras": 27285, + "▁minimize": 27286, + "▁Door": 27287, + "▁bzw": 27288, + "▁prac": 27289, + "TREE": 27290, + "▁Wing": 27291, + "▁Transaction": 27292, + "▁MVT": 27293, + "▁Klein": 27294, + "commons": 27295, + "▁}{": 27296, + "▁Heritage": 27297, + "▁fade": 27298, + "рок": 27299, + "setValue": 27300, + "▁Wallace": 27301, + "MX": 27302, + "▁ACT": 27303, + "▁footage": 27304, + "▁entstand": 27305, + "arga": 27306, + "▁nails": 27307, + "▁capitalism": 27308, + "▁Garc": 27309, + "▁suspension": 27310, + "ilis": 27311, + "▁Mov": 27312, + "uffled": 27313, + "Arc": 27314, + "▁Beautiful": 27315, + "WAY": 27316, + "Parallel": 27317, + "XXXX": 27318, + "diag": 27319, + "▁DT": 27320, + "mq": 27321, + "TextView": 27322, + "MLE": 27323, + "ennen": 27324, + "▁infected": 27325, + "▁therapist": 27326, + "INGS": 27327, + "▁cidade": 27328, + "ън": 27329, + "▁pdf": 27330, + "▁bump": 27331, + "CTX": 27332, + "▁INCLUDING": 27333, + "▁Gef": 27334, + "ENTIAL": 27335, + "▁handy": 27336, + "▁temporal": 27337, + "AtA": 27338, + "ISH": 27339, + "▁Pattern": 27340, + "▁lan": 27341, + "ependant": 27342, + "▁shining": 27343, + "idy": 27344, + "▁NT": 27345, + "▁Fran": 27346, + "▁nurses": 27347, + "▁betray": 27348, + "▁sensible": 27349, + "▁апреля": 27350, + "▁'[": 27351, + "▁thirteen": 27352, + ")}_{": 27353, + "▁Noah": 27354, + "INSERT": 27355, + "istically": 27356, + "▁Appendix": 27357, + "▁recher": 27358, + "Receiver": 27359, + "▁dernier": 27360, + "лла": 27361, + "лиза": 27362, + "▁Partido": 27363, + "▁maximal": 27364, + "snap": 27365, + "▁часть": 27366, + "STOP": 27367, + "▁ultra": 27368, + "▁développ": 27369, + "▁tegen": 27370, + "▁Чи": 27371, + "LIB": 27372, + "▁baseline": 27373, + "reload": 27374, + "▁Arbitro": 27375, + "▁kall": 27376, + "capture": 27377, + "Arm": 27378, + "quin": 27379, + "impse": 27380, + "zas": 27381, + "▁Cand": 27382, + "▁brains": 27383, + "▁hostile": 27384, + "▁marble": 27385, + "oons": 27386, + "▁Loss": 27387, + "MetaData": 27388, + "▁República": 27389, + "▁andra": 27390, + "oden": 27391, + "▁documented": 27392, + "▁Moses": 27393, + "odd": 27394, + "▁wax": 27395, + "usch": 27396, + "▁diagnosed": 27397, + "inkle": 27398, + "▁Xbox": 27399, + "▁seventy": 27400, + "cias": 27401, + "▁noviembre": 27402, + "Compute": 27403, + "});\r": 27404, + "▁Philippe": 27405, + "▁För": 27406, + "Leave": 27407, + "▁sage": 27408, + "▁unpre": 27409, + "▁Fortunately": 27410, + "▁apost": 27411, + "entities": 27412, + "▁ellos": 27413, + "authorized": 27414, + "GBT": 27415, + "▁insist": 27416, + "▁inspire": 27417, + "Mass": 27418, + "▁rôle": 27419, + "fee": 27420, + "ipart": 27421, + "цер": 27422, + "unate": 27423, + "▁CNN": 27424, + ":}": 27425, + "▁unhappy": 27426, + "▁imported": 27427, + "HIGH": 27428, + "rings": 27429, + "▁Instance": 27430, + "Bay": 27431, + "agles": 27432, + "mee": 27433, + "bery": 27434, + "▁Stories": 27435, + "▁Chase": 27436, + "▁carriage": 27437, + "▁misunder": 27438, + "▁imagin": 27439, + "pw": 27440, + "▁Meter": 27441, + "▁crowds": 27442, + "▁Fame": 27443, + "skill": 27444, + "▁comed": 27445, + "▁ranch": 27446, + "▁lacking": 27447, + "▁submar": 27448, + "iante": 27449, + "▁lanz": 27450, + "▁служ": 27451, + "-----------": 27452, + "▁obten": 27453, + "▁downstairs": 27454, + "YN": 27455, + "rotation": 27456, + "▁Jesse": 27457, + "$(\"#": 27458, + "▁puls": 27459, + "irling": 27460, + "▁Schaus": 27461, + "▁deployed": 27462, + "▁{}\",": 27463, + "▁Marvel": 27464, + "ENUM": 27465, + "▁Mathemat": 27466, + "▁nn": 27467, + "compet": 27468, + "ków": 27469, + "bil": 27470, + "Which": 27471, + "isine": 27472, + "▁rude": 27473, + "▁niveau": 27474, + "▁área": 27475, + "▁près": 27476, + "atis": 27477, + "▁[...]": 27478, + "fur": 27479, + "omm": 27480, + "packed": 27481, + "мене": 27482, + "scriptstyle": 27483, + "▁Ath": 27484, + "▁desp": 27485, + "eltemperaturen": 27486, + "▁talents": 27487, + "ocy": 27488, + "▁raises": 27489, + "LIMIT": 27490, + "▁editorial": 27491, + "▁Animal": 27492, + "drive": 27493, + "▁работа": 27494, + "bss": 27495, + "▁Sev": 27496, + "epoch": 27497, + "▁RC": 27498, + "UNUSED": 27499, + "▁mandatory": 27500, + "(?:": 27501, + "▁Bin": 27502, + "▁synthetic": 27503, + "▁gown": 27504, + "▁Dob": 27505, + "kap": 27506, + "▁harmon": 27507, + "▁liberty": 27508, + "▁Rice": 27509, + "▁prayers": 27510, + "▁mise": 27511, + "▁confusing": 27512, + "▁leap": 27513, + "▁arrives": 27514, + "kamp": 27515, + "▁thats": 27516, + "ACC": 27517, + "▁Parameters": 27518, + "▁одно": 27519, + "▁Bio": 27520, + "density": 27521, + "▁glimpse": 27522, + "FORE": 27523, + "▁Listen": 27524, + "Prev": 27525, + "}\\,\\": 27526, + "куль": 27527, + "▁SEC": 27528, + "▁explored": 27529, + "▁meantime": 27530, + "AIL": 27531, + "▁WP": 27532, + "▁raison": 27533, + "▁existe": 27534, + "▁lesser": 27535, + "▁Validate": 27536, + "▁caution": 27537, + "usta": 27538, + "heading": 27539, + "EFF": 27540, + ".'\"": 27541, + "▁Gilbert": 27542, + "▁limitation": 27543, + "▁retour": 27544, + "▁Commonwealth": 27545, + "▁gewann": 27546, + "▁miserable": 27547, + "▁networking": 27548, + "▁ottobre": 27549, + "▁Dise": 27550, + "edges": 27551, + "▁sede": 27552, + "вича": 27553, + "uniform": 27554, + "▁деятель": 27555, + "iros": 27556, + "▁desen": 27557, + "▁parc": 27558, + "▁Rico": 27559, + "Ns": 27560, + "guid": 27561, + "orio": 27562, + "avelength": 27563, + "▁Gle": 27564, + "inceton": 27565, + "Amaz": 27566, + "Construct": 27567, + "▁mx": 27568, + "▁Vern": 27569, + "▁Generation": 27570, + "Jack": 27571, + "romag": 27572, + "▁viagra": 27573, + "▁Peg": 27574, + "▁Updated": 27575, + "▁overlap": 27576, + "EventArgs": 27577, + "кро": 27578, + "▁*«": 27579, + "▁questioned": 27580, + "South": 27581, + "notice": 27582, + "▁permanently": 27583, + "lst": 27584, + "ficie": 27585, + "▁quella": 27586, + "▁colleges": 27587, + "▁disappointment": 27588, + "▁Luft": 27589, + "imgur": 27590, + "▁transitions": 27591, + "▁seller": 27592, + "▁июня": 27593, + "▁Og": 27594, + "▁ADD": 27595, + "▁Pays": 27596, + "COMMAND": 27597, + "grades": 27598, + "▁febbra": 27599, + "▁Cyr": 27600, + "▁febbraio": 27601, + "eti": 27602, + "▁arom": 27603, + "▁Claude": 27604, + "▁UEFA": 27605, + "▁живе": 27606, + "▁Victorian": 27607, + "keeping": 27608, + "ên": 27609, + "▁FIXME": 27610, + "itime": 27611, + "chestr": 27612, + "▁Samsung": 27613, + "▁doctrine": 27614, + "▁pear": 27615, + "▁Mediterranean": 27616, + "▁Ya": 27617, + "▁vault": 27618, + "▁Historic": 27619, + "▁sedan": 27620, + "▁heated": 27621, + "▁política": 27622, + "Proof": 27623, + ":{": 27624, + "fem": 27625, + "▁Frankfurt": 27626, + "pectives": 27627, + "MG": 27628, + "▁Eye": 27629, + "dai": 27630, + "▁reserves": 27631, + "NER": 27632, + "▁tobacco": 27633, + "▁fragments": 27634, + "icc": 27635, + "▁booth": 27636, + "▁cruise": 27637, + "▁Testament": 27638, + "cola": 27639, + "▁Leop": 27640, + "▁noon": 27641, + "▁terrified": 27642, + "vb": 27643, + "intel": 27644, + "alie": 27645, + "▁verification": 27646, + "yster": 27647, + "ADER": 27648, + "chied": 27649, + "▁datasets": 27650, + "▁зі": 27651, + "▁miem": 27652, + "ulates": 27653, + "▁uuid": 27654, + "▁Pictures": 27655, + "▁Brend": 27656, + "Billboard": 27657, + "▁stern": 27658, + "▁denom": 27659, + "▁accidents": 27660, + "сня": 27661, + "▁packing": 27662, + "ција": 27663, + "iblical": 27664, + "▁Так": 27665, + "▁whisk": 27666, + "▁luego": 27667, + "▁rectangle": 27668, + "▁hooks": 27669, + "▁neglect": 27670, + "▁sober": 27671, + "proposition": 27672, + "Multiple": 27673, + ":\",": 27674, + "▁bapt": 27675, + "Parts": 27676, + "▁Selection": 27677, + "▁Alpha": 27678, + "weights": 27679, + "hall": 27680, + "соб": 27681, + "▁lur": 27682, + "▁época": 27683, + "▁rested": 27684, + "ambigu": 27685, + "▁tastes": 27686, + "amazonaws": 27687, + "▁confess": 27688, + "▁diciembre": 27689, + "implement": 27690, + "▁absorption": 27691, + "Hal": 27692, + "LEAN": 27693, + "▁Zach": 27694, + "▁freeze": 27695, + "LBL": 27696, + "STM": 27697, + "▁calc": 27698, + "={()": 27699, + "=*/": 27700, + "▁bt": 27701, + "Reb": 27702, + "▁Wien": 27703, + "anska": 27704, + "▁surn": 27705, + "iative": 27706, + "▁invån": 27707, + "CY": 27708, + "▁là": 27709, + "amba": 27710, + "leen": 27711, + "wahl": 27712, + "▁functioning": 27713, + "ția": 27714, + "getContext": 27715, + "gart": 27716, + "▁обе": 27717, + "Pen": 27718, + "vik": 27719, + "Slider": 27720, + "▁Accept": 27721, + "Gap": 27722, + "▁Jorge": 27723, + "SIG": 27724, + "▁вос": 27725, + "▁голо": 27726, + "▁periodo": 27727, + "шта": 27728, + "▁patches": 27729, + "кої": 27730, + "äre": 27731, + "engono": 27732, + "lista": 27733, + "horn": 27734, + "▁Complex": 27735, + "Sent": 27736, + "trfs": 27737, + "▁convex": 27738, + "Generation": 27739, + "▁місце": 27740, + "compress": 27741, + "▁Sax": 27742, + "▁uid": 27743, + "▁Lebens": 27744, + "Completion": 27745, + "\\|_{": 27746, + "insky": 27747, + "▁schon": 27748, + "▁masters": 27749, + "independ": 27750, + "neys": 27751, + "▁lied": 27752, + "▁aspir": 27753, + "чні": 27754, + "▁breakdown": 27755, + "▁Harm": 27756, + "▁designing": 27757, + "hf": 27758, + "▁Angela": 27759, + "▁confer": 27760, + "▁partido": 27761, + "▁interference": 27762, + "mao": 27763, + "▁absorbed": 27764, + "▁Vall": 27765, + "ErrorCode": 27766, + "▁Publishing": 27767, + "vano": 27768, + "BITS": 27769, + "▁deer": 27770, + "▁Campaign": 27771, + "▁graz": 27772, + "CHANGE": 27773, + "▁feder": 27774, + "iffe": 27775, + "handed": 27776, + "cq": 27777, + "umbing": 27778, + "▁unre": 27779, + "▁siendo": 27780, + "▁simpler": 27781, + "why": 27782, + "arettes": 27783, + "anst": 27784, + "▁hass": 27785, + "▁Enterprise": 27786, + "▁mois": 27787, + "▁Fo": 27788, + "▁участ": 27789, + "ffen": 27790, + "▁MODULE": 27791, + "▁activated": 27792, + "▁internacional": 27793, + "▁Mittel": 27794, + "degree": 27795, + "▁откры": 27796, + "▁&(": 27797, + "getProperty": 27798, + "isz": 27799, + "cedure": 27800, + "▁enters": 27801, + "▁Sally": 27802, + "▁Train": 27803, + "▁logged": 27804, + "▁Rav": 27805, + "▁Avoid": 27806, + "▁Kaiser": 27807, + "▁expend": 27808, + "aphor": 27809, + "▁brass": 27810, + "▁melod": 27811, + "▁attitudes": 27812, + "*\"": 27813, + "Wall": 27814, + "▁owe": 27815, + "▁bamb": 27816, + "shader": 27817, + "cester": 27818, + "▁PP": 27819, + "▁migrations": 27820, + "entric": 27821, + "▁Setup": 27822, + "▁Artist": 27823, + "hre": 27824, + "▁polite": 27825, + "ahan": 27826, + "▁luglio": 27827, + "▁predecess": 27828, + "▁SIG": 27829, + "тів": 27830, + "▁RF": 27831, + "▁Dry": 27832, + "▁maker": 27833, + "шим": 27834, + "▁Sounds": 27835, + "▁implementing": 27836, + "▁ah": 27837, + "▁gev": 27838, + "▁duplicate": 27839, + "▁Logan": 27840, + "▁Grade": 27841, + "DUCT": 27842, + "íses": 27843, + "ért": 27844, + "▁nonsense": 27845, + "backup": 27846, + "Attachment": 27847, + "▁ecc": 27848, + "▁Squadron": 27849, + "learn": 27850, + "deprecated": 27851, + "▁Aub": 27852, + "▁Gol": 27853, + "▁overl": 27854, + "SERVICE": 27855, + "▁beautifully": 27856, + "REL": 27857, + "▁Gian": 27858, + "▁Papa": 27859, + "respond": 27860, + "▁Caribbean": 27861, + "rn": 27862, + "▁худож": 27863, + "Cfg": 27864, + "rai": 27865, + "▁sniff": 27866, + "tto": 27867, + "ологи": 27868, + "▁rb": 27869, + "▁incidents": 27870, + "▁duck": 27871, + "▁PROVIDED": 27872, + "Sources": 27873, + "▁Chelsea": 27874, + "▁tek": 27875, + "▁налази": 27876, + "▁pilots": 27877, + "тки": 27878, + "▁traded": 27879, + "▁Beijing": 27880, + "▁Gregory": 27881, + "scalar": 27882, + "▁inclined": 27883, + "▁Kamp": 27884, + "▁Marian": 27885, + "▁fierce": 27886, + "▁theft": 27887, + "ющих": 27888, + "▁Into": 27889, + "constraint": 27890, + "parentNode": 27891, + "idental": 27892, + "▁gouvernement": 27893, + "▁SND": 27894, + "▁Ruby": 27895, + "▁monaster": 27896, + "Records": 27897, + "▁Kab": 27898, + "▁Universe": 27899, + "▁approximate": 27900, + "Water": 27901, + "▁Physical": 27902, + "appers": 27903, + "oubtedly": 27904, + "ложен": 27905, + "▁towel": 27906, + "▁siblings": 27907, + "eph": 27908, + "icios": 27909, + "рами": 27910, + "▁outrage": 27911, + "▁també": 27912, + "SRC": 27913, + "телем": 27914, + "Vi": 27915, + ".');": 27916, + "LM": 27917, + "▁mitt": 27918, + "▁weed": 27919, + "▁crops": 27920, + "iman": 27921, + "Claim": 27922, + "insula": 27923, + "▁(“": 27924, + "▁Changes": 27925, + "▁invånare": 27926, + "again": 27927, + "▁cnt": 27928, + "▁Gaz": 27929, + "▁austral": 27930, + "overlay": 27931, + "▁Mechan": 27932, + "▁slammed": 27933, + "▁trailing": 27934, + "▁Biography": 27935, + "▁appealing": 27936, + "IVER": 27937, + "▁Ave": 27938, + "▁Plot": 27939, + "voj": 27940, + "▁sung": 27941, + "▁unos": 27942, + "Effects": 27943, + "vv": 27944, + "cook": 27945, + "Buttons": 27946, + "▁transm": 27947, + "ierto": 27948, + "CONTEXT": 27949, + "▁dignity": 27950, + "aired": 27951, + "javax": 27952, + "▁Alberto": 27953, + "▁Recently": 27954, + "▁facial": 27955, + "mathop": 27956, + "ało": 27957, + "вид": 27958, + "cott": 27959, + "Variables": 27960, + "▁Ran": 27961, + "▁bunk": 27962, + "amiliar": 27963, + "CAST": 27964, + "▁frü": 27965, + "VED": 27966, + "▁NOTICE": 27967, + "▁turno": 27968, + "validator": 27969, + "▁Portuguese": 27970, + "▁questioning": 27971, + "}})": 27972, + "▁lear": 27973, + "Xamarin": 27974, + "▁disadv": 27975, + "encoded": 27976, + "▁Kot": 27977, + "rated": 27978, + "▁Theory": 27979, + "cius": 27980, + "▁Darwin": 27981, + "ђе": 27982, + "▁décl": 27983, + "▁область": 27984, + "рович": 27985, + "▁mobility": 27986, + "VF": 27987, + "▁хи": 27988, + "until": 27989, + "▁barriers": 27990, + "gif": 27991, + "▁Roh": 27992, + "▁aging": 27993, + "▁Widget": 27994, + "olk": 27995, + "▁farms": 27996, + "Checker": 27997, + "Introduction": 27998, + "смо": 27999, + "▁Russians": 28000, + "naments": 28001, + "▁Insert": 28002, + "▁Whenever": 28003, + "erset": 28004, + "itori": 28005, + "▁Dort": 28006, + "▁costume": 28007, + "▁mathematical": 28008, + "▁Bast": 28009, + "▁nominated": 28010, + "▁restoration": 28011, + "posal": 28012, + "▁unfortunate": 28013, + "Ps": 28014, + "LIN": 28015, + "▁intact": 28016, + "▁provoc": 28017, + "▁située": 28018, + "▁ноября": 28019, + "ermo": 28020, + "▁fisher": 28021, + "гля": 28022, + "▁conting": 28023, + "▁Doug": 28024, + "\"?": 28025, + "▁Eva": 28026, + "▁tops": 28027, + "▁Remote": 28028, + "▁artwork": 28029, + "▁artillery": 28030, + "quick": 28031, + "▁Arabia": 28032, + "▁SDValue": 28033, + "▁Dakota": 28034, + "iated": 28035, + "▁Optim": 28036, + "buttons": 28037, + "▁cottage": 28038, + "▁wherein": 28039, + "▁tutorial": 28040, + "▁Scre": 28041, + "▁sweep": 28042, + "▁Coffee": 28043, + "})}": 28044, + "▁музы": 28045, + "hostname": 28046, + "▁Temp": 28047, + "▁Fut": 28048, + "respect": 28049, + "ocz": 28050, + "▁predomin": 28051, + "Indicator": 28052, + "encial": 28053, + "UMENT": 28054, + "▁SHALL": 28055, + "▁commanded": 28056, + "▁withdrawal": 28057, + "iour": 28058, + "REGION": 28059, + "sprintf": 28060, + "▁вме": 28061, + "▁Payment": 28062, + "▁Anim": 28063, + "publish": 28064, + "▁seeks": 28065, + "ouw": 28066, + "▁GM": 28067, + "rugu": 28068, + "ustain": 28069, + "▁))": 28070, + "▁consulting": 28071, + "▁Dialog": 28072, + "▁Lars": 28073, + "▁critique": 28074, + "▁circulation": 28075, + "▁landsc": 28076, + "managed": 28077, + "▁Craft": 28078, + "▁herman": 28079, + "afi": 28080, + "amy": 28081, + "▁discour": 28082, + "<>(": 28083, + "▁Steph": 28084, + "▁tolerance": 28085, + "typename": 28086, + "ventions": 28087, + "ział": 28088, + "стов": 28089, + "▁sticking": 28090, + "ASC": 28091, + "ISO": 28092, + "▁Spencer": 28093, + "▁Didn": 28094, + "gomery": 28095, + "imiter": 28096, + "dru": 28097, + "Clause": 28098, + "▁slides": 28099, + "###": 28100, + "▁Sugar": 28101, + "HY": 28102, + "▁эти": 28103, + "▁Edwards": 28104, + "▁cents": 28105, + "oya": 28106, + "serts": 28107, + "▁Hass": 28108, + "▁ingen": 28109, + "стри": 28110, + "▁saddle": 28111, + "solid": 28112, + "▁champions": 28113, + "-)": 28114, + "▁Slov": 28115, + "▁shiny": 28116, + "▁*)&": 28117, + "▁Define": 28118, + "če": 28119, + "▁scrut": 28120, + "onden": 28121, + "'\",": 28122, + "uffs": 28123, + "▁olymp": 28124, + "idential": 28125, + "wand": 28126, + "▁annually": 28127, + "▁Arkansas": 28128, + "▁saint": 28129, + "▁gleich": 28130, + "▁perfection": 28131, + ")>": 28132, + "▁shorts": 28133, + "▁justified": 28134, + "peated": 28135, + "packages": 28136, + "driven": 28137, + "▁Liberty": 28138, + "▁stripped": 28139, + "шение": 28140, + "▁fünf": 28141, + "▁ecosystem": 28142, + "ixa": 28143, + "▁Fresh": 28144, + "vart": 28145, + "▁treats": 28146, + "▁stance": 28147, + "чёт": 28148, + "▁pity": 28149, + "adém": 28150, + "▁окон": 28151, + "▁Chand": 28152, + "rab": 28153, + "вший": 28154, + "inski": 28155, + "▁continually": 28156, + "▁Daddy": 28157, + "▁nightmare": 28158, + "icional": 28159, + "▁efect": 28160, + "ueblo": 28161, + "▁lanç": 28162, + "▁Collections": 28163, + "due": 28164, + "ampton": 28165, + "▁memcpy": 28166, + "▁**(": 28167, + "issent": 28168, + "▁Insp": 28169, + "▁Glasgow": 28170, + "▁furono": 28171, + "▁kindness": 28172, + "Bi": 28173, + "▁competed": 28174, + "▁oak": 28175, + "Large": 28176, + "▁disgu": 28177, + "▁kings": 28178, + "тами": 28179, + "▁stuffed": 28180, + "▁hilar": 28181, + "published": 28182, + "▁stressed": 28183, + "▁Peak": 28184, + "▁loader": 28185, + "Keyboard": 28186, + "▁reconstruction": 28187, + "▁vod": 28188, + "▁dun": 28189, + "▁understands": 28190, + "tenant": 28191, + "▁chaque": 28192, + "▁prejud": 28193, + "utat": 28194, + "▁uso": 28195, + "▁Heavy": 28196, + "▁cuatro": 28197, + "▁sidewalk": 28198, + "▁Bug": 28199, + "▁månaden": 28200, + "geo": 28201, + "▁united": 28202, + "▁Files": 28203, + "▁Аль": 28204, + "▁rugby": 28205, + "▁financing": 28206, + "▁comply": 28207, + "&#": 28208, + "▁rushing": 28209, + "▁fen": 28210, + "mong": 28211, + "▁spé": 28212, + "▁presenting": 28213, + "INCLUDING": 28214, + "ěl": 28215, + "zeichnung": 28216, + "Backup": 28217, + "▁petit": 28218, + "▁allerg": 28219, + "нут": 28220, + "▁worrying": 28221, + "▁mamm": 28222, + "▁operand": 28223, + ":%.*]]": 28224, + "▁realise": 28225, + "Commands": 28226, + "▁Bew": 28227, + "▁assumes": 28228, + "▁Covid": 28229, + "▁quand": 28230, + "tyard": 28231, + "▁Mono": 28232, + "linked": 28233, + "MARK": 28234, + "Esp": 28235, + "▁blessing": 28236, + "▁eyebrows": 28237, + "▁NV": 28238, + "▁стру": 28239, + "▁modeling": 28240, + "▁greeted": 28241, + "Workspace": 28242, + "▁pedest": 28243, + "▁неза": 28244, + "lemagne": 28245, + "Statistics": 28246, + "▁aument": 28247, + "▁speeds": 28248, + "▁syndrome": 28249, + "CONNECT": 28250, + "zahl": 28251, + "verso": 28252, + "ército": 28253, + "▁astronom": 28254, + "▁aprile": 28255, + "žen": 28256, + "веро": 28257, + "draft": 28258, + "▁gioc": 28259, + "▁comport": 28260, + "▁variance": 28261, + "▁realizing": 28262, + "EDIT": 28263, + "олові": 28264, + "▁estar": 28265, + "▁sost": 28266, + "NORMAL": 28267, + "▁ó": 28268, + "▁Andr": 28269, + "ATTRIB": 28270, + "▁rede": 28271, + "▁toes": 28272, + "▁advances": 28273, + "▁Against": 28274, + "TOM": 28275, + "rss": 28276, + "MMMM": 28277, + "▁newest": 28278, + "▁VER": 28279, + "▁phrases": 28280, + "anter": 28281, + "Launch": 28282, + "▁chr": 28283, + "▁manufactured": 28284, + "$),": 28285, + "rollment": 28286, + "eston": 28287, + "▁peint": 28288, + "”)": 28289, + "endet": 28290, + "▁Hair": 28291, + "ivalent": 28292, + "▁upright": 28293, + "gren": 28294, + "anked": 28295, + "wright": 28296, + "▁mast": 28297, + "▁onChange": 28298, + "▁debris": 28299, + "▁grap": 28300, + "etry": 28301, + "▁(__": 28302, + "▁Commerce": 28303, + "BOX": 28304, + "Tax": 28305, + "▁отри": 28306, + "▁prevention": 28307, + "▁Feel": 28308, + "▁exotic": 28309, + "▁Bark": 28310, + "▁Steam": 28311, + "fon": 28312, + "olin": 28313, + "▁eliminated": 28314, + "▁bc": 28315, + "▁Cycl": 28316, + "▁$(\"#": 28317, + "▁Parl": 28318, + "manuel": 28319, + "ospher": 28320, + "WF": 28321, + "Analy": 28322, + "▁navig": 28323, + "▁renown": 28324, + "Rx": 28325, + "▁Walt": 28326, + "uffed": 28327, + "▁foster": 28328, + "$:": 28329, + "shore": 28330, + "Connector": 28331, + "фика": 28332, + "▁realization": 28333, + "Li": 28334, + "ctxt": 28335, + "ahoo": 28336, + "▁miracle": 28337, + "▁ET": 28338, + "▁GPS": 28339, + "▁Observable": 28340, + "▁hf": 28341, + "▁magnificent": 28342, + "него": 28343, + "BIN": 28344, + "▁Dorf": 28345, + "ieck": 28346, + "vee": 28347, + "▁Craw": 28348, + "/#": 28349, + "▁pci": 28350, + "ippet": 28351, + "▁Hillary": 28352, + "▁gir": 28353, + "▁rand": 28354, + "▁laying": 28355, + "▁Different": 28356, + "boys": 28357, + "virt": 28358, + "▁encryption": 28359, + "ász": 28360, + "пор": 28361, + "▁smelled": 28362, + "▁suscept": 28363, + "cluded": 28364, + "▁Carn": 28365, + "igten": 28366, + "▁Chuck": 28367, + "▁Provinc": 28368, + "▁perí": 28369, + "▁Marshal": 28370, + "мож": 28371, + "gfx": 28372, + "oshi": 28373, + "▁WHE": 28374, + "▁relaxation": 28375, + ",.": 28376, + "were": 28377, + "▁varieties": 28378, + "▁Won": 28379, + "▁gaps": 28380, + "▁stole": 28381, + "igua": 28382, + "ющие": 28383, + "▁Hampshire": 28384, + "phrase": 28385, + "▁película": 28386, + "Processing": 28387, + "▁initialization": 28388, + "oustic": 28389, + "▁Josef": 28390, + "icating": 28391, + "▁goodness": 28392, + "TES": 28393, + "▁cope": 28394, + "▁ignorance": 28395, + "▁Brist": 28396, + "▁paras": 28397, + "▁accidentally": 28398, + "▁tand": 28399, + "ittest": 28400, + "▁ули": 28401, + "▁shipped": 28402, + "▁ост": 28403, + "elseif": 28404, + "▁usize": 28405, + "horizontal": 28406, + "▁Carr": 28407, + "▁precip": 28408, + "roz": 28409, + "pathetic": 28410, + "rived": 28411, + "rok": 28412, + "▁digging": 28413, + "мом": 28414, + "▁Mull": 28415, + "▁XIII": 28416, + "▁peas": 28417, + "▁foul": 28418, + "▁travels": 28419, + "▁Ng": 28420, + "▁составе": 28421, + "Mont": 28422, + "arde": 28423, + "▁Stefan": 28424, + "^^^^": 28425, + "▁Kiss": 28426, + "▁Ek": 28427, + "▁oktober": 28428, + "▁memorable": 28429, + "')).": 28430, + "▁Vision": 28431, + "▁Nina": 28432, + "▁Solar": 28433, + "▁highlighted": 28434, + "▁memo": 28435, + "meisterschaft": 28436, + "sidebar": 28437, + "SEE": 28438, + "▁Nevada": 28439, + "Da": 28440, + "▁drawer": 28441, + "astically": 28442, + "elde": 28443, + "scribed": 28444, + "▁priests": 28445, + "▁hommes": 28446, + "▁instructor": 28447, + "клад": 28448, + "▁spett": 28449, + "\\-": 28450, + "▁мира": 28451, + "▁Looks": 28452, + "▁sleeve": 28453, + "▁strongest": 28454, + "▁tête": 28455, + "▁Nicole": 28456, + "imper": 28457, + "нача": 28458, + "ipper": 28459, + "▁inwon": 28460, + "ilers": 28461, + "▁Deputy": 28462, + "oge": 28463, + "▁depressed": 28464, + "▁arte": 28465, + "▁combining": 28466, + "LAST": 28467, + "inted": 28468, + "▁Average": 28469, + "▁pollution": 28470, + "▁Phillips": 28471, + "▁WM": 28472, + "}}}\\": 28473, + "Added": 28474, + "▁peripher": 28475, + "Creation": 28476, + "▁italien": 28477, + "▁Choice": 28478, + "▁EXPRESS": 28479, + "▁Struct": 28480, + "ysz": 28481, + "Resize": 28482, + "ARGS": 28483, + "▁repo": 28484, + "▁чтобы": 28485, + "▁pref": 28486, + "▁earthqu": 28487, + "▁Мекси": 28488, + "▁Finale": 28489, + "▁hecho": 28490, + "requests": 28491, + "Cut": 28492, + "▁deserved": 28493, + "гово": 28494, + "▁Recent": 28495, + "▁дивизи": 28496, + "▁supportive": 28497, + "прави": 28498, + "▁irrelevant": 28499, + "'\r": 28500, + "▁ctrl": 28501, + "▁Deal": 28502, + "izada": 28503, + "uo": 28504, + "▁nort": 28505, + "geometry": 28506, + "▁Individual": 28507, + "ereg": 28508, + "▁приня": 28509, + "cref": 28510, + "══": 28511, + "▁comerc": 28512, + "=_": 28513, + "bund": 28514, + "тах": 28515, + "ilen": 28516, + "чита": 28517, + "▁corporation": 28518, + "esz": 28519, + "▁==>": 28520, + "ablish": 28521, + "Apr": 28522, + "▁ripped": 28523, + "Vars": 28524, + "stret": 28525, + "▁Francesco": 28526, + "NaN": 28527, + "▁anytime": 28528, + "▁automated": 28529, + "ostream": 28530, + "▁drawings": 28531, + "▁enhancement": 28532, + "okrat": 28533, + "▁Issue": 28534, + "вра": 28535, + "Currency": 28536, + "▁wyn": 28537, + "izarre": 28538, + "ético": 28539, + "multiple": 28540, + "▁Rate": 28541, + "▁Ich": 28542, + "▁Auss": 28543, + "▁Former": 28544, + "Curve": 28545, + "▁marvel": 28546, + "attro": 28547, + "▁сп": 28548, + "BOOL": 28549, + "сия": 28550, + "gold": 28551, + "▁Nintendo": 28552, + "▁Salvador": 28553, + "▁Solution": 28554, + "ADC": 28555, + "бора": 28556, + "▁Bennett": 28557, + "▁FR": 28558, + "▁pueden": 28559, + "patient": 28560, + "▁PG": 28561, + "▁Jin": 28562, + "▁crashed": 28563, + "▁denen": 28564, + "▁Sample": 28565, + "▁Quebec": 28566, + "itories": 28567, + "▁blinked": 28568, + "▁lion": 28569, + "▁voce": 28570, + "▁Impact": 28571, + "▁Mau": 28572, + "▁Nie": 28573, + "▁lob": 28574, + "▁две": 28575, + "orneys": 28576, + "▁coastal": 28577, + "▁sensors": 28578, + "▁XII": 28579, + "▁illusion": 28580, + "oji": 28581, + "▁INC": 28582, + "▁Duncan": 28583, + "yk": 28584, + "▁affecting": 28585, + "pul": 28586, + "▁Napoleon": 28587, + "▁акаде": 28588, + "▁compt": 28589, + "▁profitable": 28590, + "loe": 28591, + "▁deuxième": 28592, + "▁WC": 28593, + "▁viable": 28594, + "▁Drug": 28595, + "TextBox": 28596, + "▁luminos": 28597, + "auté": 28598, + "yc": 28599, + "ště": 28600, + "▁affiliates": 28601, + "ilda": 28602, + "conduct": 28603, + "▁ebenfalls": 28604, + "▁AMD": 28605, + "▁Monitor": 28606, + "▁Companies": 28607, + "▁corrected": 28608, + "äck": 28609, + "SYSTEM": 28610, + "otherapy": 28611, + "▁перед": 28612, + "▁blues": 28613, + "atisf": 28614, + "although": 28615, + "rost": 28616, + "SCAN": 28617, + "▁RAM": 28618, + "ціональ": 28619, + "▁vendors": 28620, + "▁customs": 28621, + "▁activate": 28622, + "▁blogs": 28623, + "▁brace": 28624, + "▁strat": 28625, + "anje": 28626, + "щё": 28627, + "▁tide": 28628, + "▁Brigade": 28629, + "getOperand": 28630, + "▁aliment": 28631, + "▁achievements": 28632, + "▁suspicion": 28633, + "▁touchdown": 28634, + "broad": 28635, + "iore": 28636, + "Comparison": 28637, + "▁mum": 28638, + "English": 28639, + "▁Picture": 28640, + "▁Mouse": 28641, + "amd": 28642, + "▁[`": 28643, + "▁denomin": 28644, + "▁Aleks": 28645, + "▁prevents": 28646, + "ób": 28647, + "fed": 28648, + "▁Pray": 28649, + "▁shine": 28650, + "▁clutch": 28651, + "mux": 28652, + "Appro": 28653, + "▁notably": 28654, + "chio": 28655, + "nage": 28656, + "HAS": 28657, + "▁')": 28658, + "▁Miche": 28659, + "tg": 28660, + "::~": 28661, + "▁amely": 28662, + "▁rodz": 28663, + "zs": 28664, + "trait": 28665, + "▁klass": 28666, + "fö": 28667, + "▁destac": 28668, + "▁Clara": 28669, + "frequency": 28670, + "▁Git": 28671, + "▁поль": 28672, + "▁frequencies": 28673, + "▁febrero": 28674, + "▁stumbled": 28675, + "кою": 28676, + "▁Names": 28677, + "▁Flight": 28678, + "▁prey": 28679, + "▁medio": 28680, + "▁VAR": 28681, + "▁Float": 28682, + "▁Ernest": 28683, + "▁Marcatori": 28684, + "oport": 28685, + "▁cancellation": 28686, + "▁Bryan": 28687, + "————": 28688, + "Luc": 28689, + "▁libre": 28690, + "▁título": 28691, + "*>": 28692, + "▁Sandy": 28693, + "▁Marina": 28694, + "Been": 28695, + "▁wal": 28696, + "▁Kultur": 28697, + "▁explode": 28698, + "▁limiting": 28699, + "▁presumably": 28700, + "▁pb": 28701, + "▁Merc": 28702, + "▁реки": 28703, + "learning": 28704, + "Catalog": 28705, + "▁Census": 28706, + "lte": 28707, + "▁NET": 28708, + "raising": 28709, + "ське": 28710, + "staff": 28711, + "▁Quinn": 28712, + "▁memorial": 28713, + "пня": 28714, + "▁cuenta": 28715, + "▁XI": 28716, + "lbl": 28717, + "▁varies": 28718, + "▁fluctuations": 28719, + "▁долж": 28720, + "▁особи": 28721, + "▁warehouse": 28722, + "However": 28723, + "▁corrections": 28724, + "dhd": 28725, + "▁fals": 28726, + "▁controversy": 28727, + "▁curse": 28728, + "▁télé": 28729, + "řed": 28730, + "▁AU": 28731, + "▁тор": 28732, + "▁crít": 28733, + "idan": 28734, + "iliary": 28735, + "▁Panel": 28736, + "cule": 28737, + "▁Poor": 28738, + "▁BA": 28739, + "▁ignorant": 28740, + "èmes": 28741, + "▁aesthetic": 28742, + "Linked": 28743, + "getInt": 28744, + "Unicode": 28745, + "[@": 28746, + "▁Zent": 28747, + "Manifest": 28748, + "▁vars": 28749, + "PB": 28750, + "▁ву": 28751, + "▁Describe": 28752, + "▁Anything": 28753, + "oirs": 28754, + "▁socks": 28755, + "▁imped": 28756, + "▁neue": 28757, + "▁dispers": 28758, + "Collect": 28759, + "filer": 28760, + "▁Frau": 28761, + "▁Hockey": 28762, + "▁teens": 28763, + "▁Roberto": 28764, + "lauf": 28765, + "вать": 28766, + "▁ско": 28767, + "isArray": 28768, + "▁teenager": 28769, + "Built": 28770, + "▁loudly": 28771, + "Capacity": 28772, + "▁adventures": 28773, + "▁Molly": 28774, + "recogn": 28775, + "bars": 28776, + "▁Lor": 28777, + "▁può": 28778, + "▁mong": 28779, + "inement": 28780, + "Assignment": 28781, + "▁diz": 28782, + "lessness": 28783, + "▁Halloween": 28784, + "▁bitmap": 28785, + "Rom": 28786, + "нар": 28787, + "▁rebel": 28788, + "▁radial": 28789, + "measure": 28790, + "nit": 28791, + "▁Assume": 28792, + "▁assignments": 28793, + "▁Isn": 28794, + "▁altre": 28795, + "ßer": 28796, + "наль": 28797, + "▁flies": 28798, + "▁droit": 28799, + "▁thickness": 28800, + "▁enjo": 28801, + "▁dwell": 28802, + "▁homosexual": 28803, + "▁eval": 28804, + "$_{": 28805, + "asia": 28806, + "▁philos": 28807, + "getCurrent": 28808, + "▁veterans": 28809, + "▁Berkeley": 28810, + "▁wildlife": 28811, + "Cop": 28812, + "vern": 28813, + "▁Ú": 28814, + "tos": 28815, + "▁Led": 28816, + "▁keywords": 28817, + "▁medications": 28818, + "neum": 28819, + "▁jamais": 28820, + "▁Buc": 28821, + "▁PD": 28822, + "▁Statement": 28823, + "▁PI": 28824, + "▁Jackie": 28825, + "▁ordin": 28826, + "▁kör": 28827, + "enze": 28828, + "▁utilized": 28829, + "áct": 28830, + "azed": 28831, + "▁severely": 28832, + "▁även": 28833, + "▁libro": 28834, + "▁Eu": 28835, + "äst": 28836, + "PART": 28837, + "▁Butler": 28838, + "▁puzzle": 28839, + "Fall": 28840, + "Country": 28841, + "pfn": 28842, + "▁україн": 28843, + "▁Orchestra": 28844, + "▁alto": 28845, + "▁ancora": 28846, + "▁decomposition": 28847, + "▁م": 28848, + "▁appetite": 28849, + "adu": 28850, + "▁THAT": 28851, + "▁comenz": 28852, + "mina": 28853, + "▁initiated": 28854, + "▁Tat": 28855, + "▁sometime": 28856, + "rek": 28857, + "bread": 28858, + "▁Statistics": 28859, + "▁Cob": 28860, + "Follow": 28861, + "▁geometric": 28862, + "шла": 28863, + "▁proceedings": 28864, + "Dlg": 28865, + "seven": 28866, + "▁[-": 28867, + "▁Buffalo": 28868, + "▁blacks": 28869, + "▁sov": 28870, + "▁custody": 28871, + "▁ras": 28872, + "▁tattoo": 28873, + "öffentlicht": 28874, + "Blo": 28875, + "Austral": 28876, + "▁recuper": 28877, + "лев": 28878, + "▁bem": 28879, + "▁thou": 28880, + "oriented": 28881, + "vir": 28882, + "▁colony": 28883, + "▁Stanford": 28884, + "Absolute": 28885, + "adrat": 28886, + "▁Situ": 28887, + "▁souvent": 28888, + "EXEC": 28889, + "▁mű": 28890, + "▁apartments": 28891, + "▁случа": 28892, + "▁ano": 28893, + "WINDO": 28894, + "acci": 28895, + "▁Lau": 28896, + "court": 28897, + "▁manifold": 28898, + "▁coalition": 28899, + "▁XIV": 28900, + "Attrib": 28901, + "ascade": 28902, + "▁wheat": 28903, + "▁strengths": 28904, + "FREE": 28905, + "EMPTY": 28906, + "▁hey": 28907, + "ascular": 28908, + "▁plasma": 28909, + "▁bob": 28910, + "Separator": 28911, + "=\"${": 28912, + "▁Zag": 28913, + "▁projet": 28914, + "▁smoothly": 28915, + "SEQU": 28916, + "analy": 28917, + "attachment": 28918, + "▁ES": 28919, + "▁popped": 28920, + "ős": 28921, + "tom": 28922, + "▁són": 28923, + "▁rott": 28924, + "Utilities": 28925, + "hadoop": 28926, + "▁sotto": 28927, + "autor": 28928, + "▁Georges": 28929, + "▁který": 28930, + "▁gruppo": 28931, + "▁когда": 28932, + "▁меда": 28933, + "▁instrumental": 28934, + "▁Writer": 28935, + "▁setTimeout": 28936, + "ikk": 28937, + "▁Dopo": 28938, + "]);\r": 28939, + "▁practicing": 28940, + "▁Ronald": 28941, + "▁уби": 28942, + "▁agrees": 28943, + "▁denoted": 28944, + "ismiss": 28945, + "▁interviewed": 28946, + "templates": 28947, + "ři": 28948, + "administr": 28949, + "▁Butter": 28950, + "▁XVII": 28951, + "▁positioned": 28952, + "▁Fourth": 28953, + "▁overwhelmed": 28954, + "▁Regular": 28955, + "▁reprezent": 28956, + "кономи": 28957, + "▁expects": 28958, + "Indices": 28959, + "▁marijuana": 28960, + "▁zaj": 28961, + "▁Bren": 28962, + "▁begg": 28963, + "▁nahm": 28964, + "▁interrog": 28965, + "тие": 28966, + "▁Bun": 28967, + "▁серед": 28968, + "▁shelves": 28969, + "▁которых": 28970, + "▁Frauen": 28971, + "▁Sergeant": 28972, + "▁успе": 28973, + "matched": 28974, + "▁donne": 28975, + "▁touches": 28976, + "abort": 28977, + "▁vale": 28978, + "▁institutional": 28979, + "▁Mons": 28980, + "▁ambitious": 28981, + "▁nonetheless": 28982, + "jd": 28983, + "пей": 28984, + "▁backpack": 28985, + "dao": 28986, + "вия": 28987, + "▁surroundings": 28988, + "|_{": 28989, + "▁gegründ": 28990, + "disp": 28991, + "▁moisture": 28992, + "▁wyd": 28993, + "▁traders": 28994, + "▁Erst": 28995, + "▁Galaxy": 28996, + "▁воло": 28997, + "▁Peru": 28998, + "▁priorities": 28999, + "▁pronounced": 29000, + "▁CBS": 29001, + "▁Palm": 29002, + "▁expans": 29003, + "▁energet": 29004, + "▁Condition": 29005, + "▁Sver": 29006, + "nested": 29007, + "▁февраля": 29008, + "hero": 29009, + "▁коло": 29010, + "▁Films": 29011, + "Bon": 29012, + "éal": 29013, + "ployed": 29014, + "trained": 29015, + "▁első": 29016, + "▁lust": 29017, + "atinum": 29018, + "oyle": 29019, + "▁Jet": 29020, + "ждения": 29021, + "▁surveys": 29022, + "bee": 29023, + "workers": 29024, + "records": 29025, + "calendar": 29026, + "bbing": 29027, + "regation": 29028, + "dashboard": 29029, + "King": 29030, + "▁vista": 29031, + "▁depicted": 29032, + "▁occurring": 29033, + "▁офи": 29034, + "▁sandwich": 29035, + "rcu": 29036, + "kern": 29037, + "▁minut": 29038, + "▁смер": 29039, + "▁td": 29040, + "solete": 29041, + "Complex": 29042, + "▁tunn": 29043, + "▁scarc": 29044, + "stead": 29045, + "▁Fail": 29046, + "▁Rs": 29047, + "▁trails": 29048, + "kem": 29049, + "▁Romans": 29050, + "ativity": 29051, + "Previous": 29052, + "▁depress": 29053, + "▁resigned": 29054, + "getDefault": 29055, + "▁Tibet": 29056, + "▁Franco": 29057, + "\")));": 29058, + "▁injection": 29059, + "removed": 29060, + "▁praised": 29061, + "▁Asc": 29062, + "erase": 29063, + "▁commissioned": 29064, + "MAIL": 29065, + "▁Boh": 29066, + "Poly": 29067, + "▁cinq": 29068, + "▁Above": 29069, + "▁Joshua": 29070, + "ZERO": 29071, + "▁summit": 29072, + "▁Urs": 29073, + "▁curl": 29074, + "▁visa": 29075, + "▁resur": 29076, + "={'": 29077, + "feat": 29078, + "▁absorb": 29079, + "▁planets": 29080, + "▁princess": 29081, + "▁Jahrhunderts": 29082, + "xp": 29083, + "▁NBC": 29084, + "▁коми": 29085, + "▁FUN": 29086, + "▁neuen": 29087, + "▁déjà": 29088, + "▁Oz": 29089, + "bben": 29090, + "VIDEO": 29091, + "▁ejempl": 29092, + "▁considers": 29093, + "atri": 29094, + "▁arrog": 29095, + "ioso": 29096, + "▁hace": 29097, + "▁contacted": 29098, + "▁unple": 29099, + "▁sponsored": 29100, + "▁trainer": 29101, + "sbi": 29102, + "▁занима": 29103, + "Criterion": 29104, + "ното": 29105, + "scheme": 29106, + "ennial": 29107, + "perform": 29108, + "▁fixing": 29109, + "▁постро": 29110, + "arb": 29111, + "EXIT": 29112, + "▁café": 29113, + "ituted": 29114, + "riages": 29115, + "Tur": 29116, + "▁haber": 29117, + "elasticsearch": 29118, + "▁ал": 29119, + "rh": 29120, + "▁voll": 29121, + "CLU": 29122, + "Mil": 29123, + "▁membres": 29124, + "▁remarked": 29125, + "вана": 29126, + "=\"_": 29127, + "Less": 29128, + "(\"\");": 29129, + "▁Yale": 29130, + "berries": 29131, + "▁releasing": 29132, + "▁imports": 29133, + "idea": 29134, + "▁(+": 29135, + "▁arqu": 29136, + "ificación": 29137, + "▁пара": 29138, + "▁Rangers": 29139, + "Mic": 29140, + "▁nederbörd": 29141, + "▁imaginary": 29142, + "▁specialists": 29143, + "▁hoof": 29144, + "Modules": 29145, + "▁sadly": 29146, + "ceil": 29147, + "TabIndex": 29148, + "ationale": 29149, + "▁Partner": 29150, + "tbody": 29151, + "▁leverage": 29152, + "DN": 29153, + "▁Prec": 29154, + "▁Sé": 29155, + "▁Mam": 29156, + "▁afin": 29157, + "isValid": 29158, + "Pse": 29159, + "▁сторо": 29160, + "▁chopped": 29161, + "▁Minor": 29162, + "▁dabei": 29163, + "David": 29164, + "ussia": 29165, + "▁деревня": 29166, + "▁Identity": 29167, + "▁LGBT": 29168, + "ције": 29169, + "▁Orts": 29170, + "▁parti": 29171, + "▁Bachelor": 29172, + "uga": 29173, + "▁OPT": 29174, + "▁Seth": 29175, + "▁LIABLE": 29176, + "▁inaugur": 29177, + "▁Shanghai": 29178, + "▁relaxing": 29179, + "циона": 29180, + "\"%": 29181, + "▁obey": 29182, + "▁Airlines": 29183, + "Links": 29184, + "▁Celt": 29185, + "▁Admin": 29186, + "agation": 29187, + "▁worries": 29188, + "INTE": 29189, + "arith": 29190, + "Fatalf": 29191, + "]])": 29192, + "colm": 29193, + "▁archae": 29194, + "▁brushed": 29195, + "▁tät": 29196, + "▁structured": 29197, + "тии": 29198, + "▁homem": 29199, + "[:,": 29200, + "▁navy": 29201, + "getKey": 29202, + "powered": 29203, + "▁sucked": 29204, + "▁zomb": 29205, + "issant": 29206, + "▁Might": 29207, + "▁Pull": 29208, + "rir": 29209, + "▁пі": 29210, + "▁seas": 29211, + "▁Wrest": 29212, + "▁tense": 29213, + "▁atm": 29214, + "▁havet": 29215, + "▁pierws": 29216, + "▁tragic": 29217, + "▁Diff": 29218, + "▁confidential": 29219, + "successful": 29220, + "ęż": 29221, + "▁Chain": 29222, + "▁Kenya": 29223, + "Choice": 29224, + "ocur": 29225, + "aniu": 29226, + "▁consultant": 29227, + "▁Advis": 29228, + "Lif": 29229, + "▁Lors": 29230, + "avorite": 29231, + "▁utilizing": 29232, + "▁vintage": 29233, + "Matcher": 29234, + "▁membre": 29235, + "▁Expect": 29236, + "▁tracing": 29237, + "nog": 29238, + "▁dej": 29239, + "▁уче": 29240, + "▁loops": 29241, + "▁onclick": 29242, + "▁GPU": 29243, + "▁Albums": 29244, + "▁Archives": 29245, + "вата": 29246, + "▁stove": 29247, + "шли": 29248, + "ancies": 29249, + "▁gemeente": 29250, + "mob": 29251, + "PDF": 29252, + "eso": 29253, + "▁vég": 29254, + "Resolve": 29255, + "▁teaches": 29256, + "ложе": 29257, + "▁ство": 29258, + "▁Одна": 29259, + "▁fid": 29260, + "Something": 29261, + "▁nebo": 29262, + "▁Valentine": 29263, + "rowning": 29264, + "▁але": 29265, + "awi": 29266, + "ishi": 29267, + "▁SPI": 29268, + "▁spel": 29269, + "▁біль": 29270, + "▁participant": 29271, + "▁Ned": 29272, + "▁Gast": 29273, + "▁blond": 29274, + "▁saves": 29275, + "colored": 29276, + "▁ACTION": 29277, + "▁Politiker": 29278, + "}$)": 29279, + "▁Dum": 29280, + "dentry": 29281, + "Student": 29282, + "▁~=": 29283, + "loads": 29284, + "▁Foster": 29285, + "一个": 29286, + "▁PK": 29287, + "▁SB": 29288, + "▁Hern": 29289, + "▁Exhib": 29290, + "Listeners": 29291, + "Sun": 29292, + "plac": 29293, + "▁Bever": 29294, + "▁incluy": 29295, + "▁dc": 29296, + "argc": 29297, + "▁ged": 29298, + "спа": 29299, + "▁Formula": 29300, + "▁сем": 29301, + "▁empt": 29302, + "unregister": 29303, + "▁Queensland": 29304, + "ández": 29305, + "otive": 29306, + "▁alley": 29307, + "▁Democrat": 29308, + "▁travail": 29309, + "▁$,": 29310, + "RP": 29311, + "рое": 29312, + "personal": 29313, + "▁période": 29314, + "HOME": 29315, + "omes": 29316, + "▁recognised": 29317, + "heng": 29318, + "▁Jung": 29319, + "▁Roland": 29320, + "▁convicted": 29321, + "Locked": 29322, + "▁mari": 29323, + "▁Luxem": 29324, + "referto": 29325, + "Deleted": 29326, + "intent": 29327, + "▁Staats": 29328, + "▁області": 29329, + "ит": 29330, + "▁саве": 29331, + "▁Protocol": 29332, + "ając": 29333, + "chk": 29334, + "TypeInfo": 29335, + "▁pkt": 29336, + "▁scandal": 29337, + "▁individually": 29338, + "FMT": 29339, + "▁nj": 29340, + "abile": 29341, + "▁Rivers": 29342, + "PROPERTY": 29343, + "VB": 29344, + "wort": 29345, + "▁splitting": 29346, + "achten": 29347, + "▁ARISING": 29348, + "▁sip": 29349, + "▁fres": 29350, + "▁groom": 29351, + "Hol": 29352, + "▁canon": 29353, + "▁abruptly": 29354, + "▁afterward": 29355, + "▁Running": 29356, + "▁ji": 29357, + "▁%,": 29358, + "▁Palestinian": 29359, + "RW": 29360, + "pgfscope": 29361, + "▁countryside": 29362, + "▁fortunate": 29363, + "▁cél": 29364, + "▁Pointer": 29365, + "ensors": 29366, + "rating": 29367, + "▁buffers": 29368, + "▁remot": 29369, + "▁PropTypes": 29370, + "▁Nah": 29371, + "altern": 29372, + "▁easiest": 29373, + "▁invas": 29374, + "▁clk": 29375, + "copyright": 29376, + "▁blanc": 29377, + "SAMP": 29378, + "▁Cohen": 29379, + "▁Shell": 29380, + "▁destroying": 29381, + "▁Zel": 29382, + "dater": 29383, + "čen": 29384, + "▁filing": 29385, + "▁integrate": 29386, + "xit": 29387, + "▁RET": 29388, + "lene": 29389, + "calls": 29390, + "▁slaughter": 29391, + "initialized": 29392, + "unches": 29393, + "▁Trace": 29394, + "efficient": 29395, + "▁Woods": 29396, + "▁longitud": 29397, + "GN": 29398, + "▁Kont": 29399, + "▁chunks": 29400, + "ách": 29401, + "▁unemployment": 29402, + "acom": 29403, + "▁slowed": 29404, + "▁outlined": 29405, + "xffff": 29406, + "▁ikke": 29407, + "▁workspace": 29408, + "Mc": 29409, + "▁kicking": 29410, + "▁embedding": 29411, + "chnitt": 29412, + "erten": 29413, + "▁Interior": 29414, + "▁Songs": 29415, + "mmc": 29416, + "▁analyzed": 29417, + "▁Coupe": 29418, + "▁favorites": 29419, + "▁tt": 29420, + "▁той": 29421, + "Routing": 29422, + "▁Silva": 29423, + "▁anderem": 29424, + "▁honom": 29425, + "▁использова": 29426, + ".\"]": 29427, + "▁Wu": 29428, + "legt": 29429, + "▁spoon": 29430, + "▁jap": 29431, + "▁Extension": 29432, + "erne": 29433, + "▁vagy": 29434, + "▁села": 29435, + "▁функ": 29436, + "▁analytics": 29437, + "▁sug": 29438, + "▁Async": 29439, + "▁peaks": 29440, + "▁Gym": 29441, + "▁lawsuit": 29442, + "<>": 29443, + "ialis": 29444, + "etric": 29445, + "faced": 29446, + "▁disrupt": 29447, + "▁få": 29448, + "Inputs": 29449, + "`);": 29450, + "▁Mend": 29451, + "gon": 29452, + "▁\",\"": 29453, + "▁nerves": 29454, + "▁doubts": 29455, + "sap": 29456, + "▁sow": 29457, + ",\\,\\": 29458, + "▁BS": 29459, + "▁Glad": 29460, + "▁aster": 29461, + "œuvre": 29462, + "▁Bangl": 29463, + "▁iPad": 29464, + "useppe": 29465, + "▁conducting": 29466, + "▁({\\": 29467, + "▁Harbor": 29468, + "psz": 29469, + "▁FIFA": 29470, + "_**": 29471, + "emor": 29472, + "▁": 29473, + "e": 29474, + "t": 29475, + "a": 29476, + "o": 29477, + "i": 29478, + "n": 29479, + "r": 29480, + "s": 29481, + "l": 29482, + "d": 29483, + "h": 29484, + "c": 29485, + "u": 29486, + "m": 29487, + "p": 29488, + "g": 29489, + "f": 29490, + ".": 29491, + "y": 29492, + ",": 29493, + "b": 29494, + "w": 29495, + "v": 29496, + "k": 29497, + "_": 29498, + ")": 29499, + "(": 29500, + "-": 29501, + "0": 29502, + "S": 29503, + "*": 29504, + "I": 29505, + "T": 29506, + "\"": 29507, + "1": 29508, + "A": 29509, + "'": 29510, + "C": 29511, + "x": 29512, + ";": 29513, + "=": 29514, + ":": 29515, + "/": 29516, + "E": 29517, + "2": 29518, + "{": 29519, + "}": 29520, + "P": 29521, + "R": 29522, + "M": 29523, + "\\": 29524, + "D": 29525, + "L": 29526, + "N": 29527, + "B": 29528, + "о": 29529, + "O": 29530, + "а": 29531, + "z": 29532, + "F": 29533, + "|": 29534, + ">": 29535, + "j": 29536, + "H": 29537, + "3": 29538, + "#": 29539, + "и": 29540, + "е": 29541, + "9": 29542, + "q": 29543, + "$": 29544, + "G": 29545, + "н": 29546, + "U": 29547, + "W": 29548, + "4": 29549, + "5": 29550, + "8": 29551, + "6": 29552, + "р": 29553, + "т": 29554, + "7": 29555, + "с": 29556, + "<": 29557, + "V": 29558, + "в": 29559, + "[": 29560, + "]": 29561, + "л": 29562, + "к": 29563, + "K": 29564, + "é": 29565, + "J": 29566, + "д": 29567, + "&": 29568, + "\r": 29569, + "Y": 29570, + "м": 29571, + "?": 29572, + "у": 29573, + "+": 29574, + "п": 29575, + "!": 29576, + "’": 29577, + "г": 29578, + "я": 29579, + "з": 29580, + "і": 29581, + "X": 29582, + "^": 29583, + "–": 29584, + "б": 29585, + "@": 29586, + "й": 29587, + "á": 29588, + "—": 29589, + "ь": 29590, + "%": 29591, + "Q": 29592, + "ó": 29593, + "ч": 29594, + "í": 29595, + "Z": 29596, + "ы": 29597, + "ä": 29598, + "х": 29599, + "`": 29600, + "ц": 29601, + "ö": 29602, + "“": 29603, + "ж": 29604, + "ü": 29605, + "”": 29606, + "à": 29607, + "è": 29608, + "ш": 29609, + "ю": 29610, + "ł": 29611, + "С": 29612, + "~": 29613, + "ф": 29614, + "П": 29615, + "»": 29616, + "В": 29617, + "«": 29618, + "å": 29619, + "К": 29620, + "щ": 29621, + "·": 29622, + "ј": 29623, + "М": 29624, + "ç": 29625, + "А": 29626, + "Н": 29627, + "Р": 29628, + "Б": 29629, + "č": 29630, + "ú": 29631, + "ę": 29632, + "ã": 29633, + "ą": 29634, + "ă": 29635, + "Д": 29636, + "ї": 29637, + "ъ": 29638, + "ě": 29639, + "Г": 29640, + "š": 29641, + "О": 29642, + "Т": 29643, + "ê": 29644, + "ñ": 29645, + "…": 29646, + "ž": 29647, + "ß": 29648, + "ё": 29649, + "ż": 29650, + "ř": 29651, + "ś": 29652, + "Л": 29653, + "ő": 29654, + "„": 29655, + "э": 29656, + "ý": 29657, + "У": 29658, + "â": 29659, + "И": 29660, + "є": 29661, + "‘": 29662, + "î": 29663, + "З": 29664, + "Ф": 29665, + "ò": 29666, + "•": 29667, + "ć": 29668, + "É": 29669, + "°": 29670, + "ș": 29671, + "Х": 29672, + "ț": 29673, + "ô": 29674, + "Е": 29675, + "ń": 29676, + "Ч": 29677, + "Ш": 29678, + "ø": 29679, + "ù": 29680, + "ů": 29681, + "的": 29682, + "ا": 29683, + "æ": 29684, + "њ": 29685, + "љ": 29686, + "ë": 29687, + "ï": 29688, + "Э": 29689, + "£": 29690, + "−": 29691, + ",": 29692, + "õ": 29693, + "ћ": 29694, + "­": 29695, + "Ц": 29696, + "І": 29697, + "ā": 29698, + "ű": 29699, + "†": 29700, + "ل": 29701, + "ō": 29702, + "​": 29703, + "º": 29704, + "Я": 29705, + "′": 29706, + "Á": 29707, + "Ö": 29708, + "²": 29709, + "Ж": 29710, + "ì": 29711, + "。": 29712, + "数": 29713, + "×": 29714, + "ر": 29715, + "α": 29716, + "́": 29717, + "Ю": 29718, + "û": 29719, + "œ": 29720, + "ı": 29721, + "م": 29722, + "ن": 29723, + "ª": 29724, + "ź": 29725, + "ο": 29726, + "″": 29727, + "€": 29728, + "Ü": 29729, + "و": 29730, + "用": 29731, + "À": 29732, + "Č": 29733, + "Š": 29734, + "ت": 29735, + "د": 29736, + "一": 29737, + "¿": 29738, + "是": 29739, + "ي": 29740, + "ђ": 29741, + "®": 29742, + "ی": 29743, + "ν": 29744, + "đ": 29745, + "τ": 29746, + "─": 29747, + "ι": 29748, + "ε": 29749, + "→": 29750, + "ب": 29751, + "Å": 29752, + "ū": 29753, + "№": 29754, + "ş": 29755, + "不": 29756, + "џ": 29757, + "ー": 29758, + "中": 29759, + "Î": 29760, + "の": 29761, + ":": 29762, + "个": 29763, + "Й": 29764, + "ρ": 29765, + "有": 29766, + "Ä": 29767, + " ": 29768, + "ī": 29769, + "©": 29770, + "为": 29771, + "ه": 29772, + "י": 29773, + "ו": 29774, + "时": 29775, + "س": 29776, + "Ś": 29777, + "在": 29778, + "件": 29779, + "取": 29780, + "ς": 29781, + "™": 29782, + "이": 29783, + "σ": 29784, + "μ": 29785, + "定": 29786, + "文": 29787, + "据": 29788, + "置": 29789, + "Ž": 29790, + "±": 29791, + "表": 29792, + "成": 29793, + "ň": 29794, + "λ": 29795, + "¡": 29796, + "È": 29797, + "π": 29798, + "字": 29799, + "│": 29800, + "Ј": 29801, + "回": 29802, + "Є": 29803, + "到": 29804, + "行": 29805, + "§": 29806, + "½": 29807, + "ع": 29808, + "、": 29809, + "Ł": 29810, + "다": 29811, + "ン": 29812, + "κ": 29813, + "名": 29814, + "ה": 29815, + "入": 29816, + "η": 29817, + "大": 29818, + "对": 29819, + "可": 29820, + "Â": 29821, + "上": 29822, + "█": 29823, + "新": 29824, + "ف": 29825, + "加": 29826, + "要": 29827, + "Ż": 29828, + "下": 29829, + "分": 29830, + "值": 29831, + "ת": 29832, + "出": 29833, + "类": 29834, + "请": 29835, + "’": 29836, + "息": 29837, + "Ú": 29838, + "υ": 29839, + "获": 29840, + "示": 29841, + "以": 29842, + "ר": 29843, + "接": 29844, + "ל": 29845, + "を": 29846, + "存": 29847, + "信": 29848, + "设": 29849, + "方": 29850, + "ش": 29851, + "能": 29852, + "点": 29853, + "人": 29854, + "前": 29855, + "ğ": 29856, + "作": 29857, + "═": 29858, + "↘": 29859, + "ð": 29860, + "理": 29861, + "■": 29862, + "法": 29863, + "️": 29864, + "ˈ": 29865, + "果": 29866, + "发": 29867, + "ح": 29868, + "γ": 29869, + "ɵ": 29870, + "า": 29871, + "َ": 29872, + "了": 29873, + "户": 29874, + "Í": 29875, + "ə": 29876, + "ス": 29877, + "查": 29878, + "し": 29879, + "מ": 29880, + "单": 29881, + "ť": 29882, + "ق": 29883, + "る": 29884, + "间": 29885, + "如": 29886, + "本": 29887, + "后": 29888, + "ί": 29889, + "式": 29890, + "ト": 29891, + "Щ": 29892, + "Ó": 29893, + "す": 29894, + "א": 29895, + "生": 29896, + "动": 29897, + "ک": 29898, + "和": 29899, + "い": 29900, + "€": 29901, + "ა": 29902, + "가": 29903, + "하": 29904, + "�": 29905, + "小": 29906, + "返": 29907, + "否": 29908, + "ة": 29909, + "日": 29910, + "로": 29911, + "标": 29912, + "码": 29913, + "地": 29914, + "位": 29915, + "에": 29916, + " ": 29917, + "列": 29918, + "수": 29919, + "β": 29920, + "除": 29921, + "使": 29922, + "ש": 29923, + "ج": 29924, + "イ": 29925, + "δ": 29926, + "自": 29927, + "于": 29928, + "지": 29929, + "当": 29930, + "所": 29931, + "기": 29932, + "ი": 29933, + "ב": 29934, + "ร": 29935, + "★": 29936, + "子": 29937, + "号": 29938, + "ك": 29939, + "参": 29940, + "型": 29941, + "に": 29942, + "는": 29943, + "这": 29944, + "开": 29945, + "น": 29946, + "会": 29947, + "器": 29948, + "面": 29949, + "ル": 29950, + "图": 29951, + "度": 29952, + ")": 29953, + "(": 29954, + "의": 29955, + "内": 29956, + "을": 29957, + "最": 29958, + "”": 29959, + "化": 29960, + "建": 29961, + "니": 29962, + "量": 29963, + "😂": 29964, + "始": 29965, + "ē": 29966, + "خ": 29967, + "를": 29968, + "ά": 29969, + "过": 29970, + "³": 29971, + "´": 29972, + "组": 29973, + "功": 29974, + "‎": 29975, + "Ÿ": 29976, + "区": 29977, + "ز": 29978, + "ґ": 29979, + "ό": 29980, + "ッ": 29981, + "ω": 29982, + "Ç": 29983, + "选": 29984, + "通": 29985, + "结": 29986, + "录": 29987, + "改": 29988, + "ク": 29989, + "目": 29990, + "指": 29991, + "务": 29992, + "๐": 29993, + "输": 29994, + "た": 29995, + "อ": 29996, + "关": 29997, + "で": 29998, + "调": 29999, + "ा": 30000, + "정": 30001, + "合": 30002, + "已": 30003, + "시": 30004, + "部": 30005, + "页": 30006, + "━": 30007, + "ː": 30008, + "ま": 30009, + "我": 30010, + "求": 30011, + "市": 30012, + "次": 30013, + "נ": 30014, + "实": 30015, + "将": 30016, + "重": 30017, + "更": 30018, + "制": 30019, + "符": 30020, + "配": 30021, + "象": 30022, + "θ": 30023, + "ก": 30024, + "て": 30025, + "进": 30026, + "需": 30027, + "Đ": 30028, + "性": 30029, + "认": 30030, + "来": 30031, + "题": 30032, + "程": 30033, + "模": 30034, + "!": 30035, + "失": 30036, + "口": 30037, + "な": 30038, + "έ": 30039, + "": 30040, + "空": 30041, + "‍": 30042, + "期": 30043, + "者": 30044, + "は": 30045, + "Ђ": 30046, + "提": 30047, + "ή": 30048, + "ラ": 30049, + "한": 30050, + "态": 30051, + "复": 30052, + "ง": 30053, + "ე": 30054, + "Ø": 30055, + "리": 30056, + "修": 30057, + "‚": 30058, + "得": 30059, + "多": 30060, + "格": 30061, + "자": 30062, + "ע": 30063, + "่": 30064, + "函": 30065, + "应": 30066, + "↗": 30067, + "्": 30068, + "เ": 30069, + "正": 30070, + "注": 30071, + "스": 30072, + "서": 30073, + "リ": 30074, + "φ": 30075, + "ص": 30076, + "が": 30077, + "则": 30078, + "消": 30079, + "节": 30080, + "序": 30081, + "代": 30082, + "사": 30083, + "と": 30084, + "ד": 30085, + "้": 30086, + "र": 30087, + "此": 30088, + "保": 30089, + "ア": 30090, + "ư": 30091, + "인": 30092, + "ė": 30093, + "处": 30094, + "删": 30095, + "ɛ": 30096, + "容": 30097, + "ط": 30098, + "“": 30099, + "之": 30100, + "包": 30101, + "状": 30102, + "ド": 30103, + "İ": 30104, + "体": 30105, + "同": 30106, + "事": 30107, + "🙂": 30108, + "タ": 30109, + "χ": 30110, + "ʿ": 30111, + "Ș": 30112, + "主": 30113, + "品": 30114, + "ק": 30115, + "询": 30116, + "创": 30117, + "该": 30118, + " ": 30119, + "元": 30120, + "第": 30121, + "天": 30122, + "或": 30123, + "年": 30124, + "转": 30125, + "ח": 30126, + "传": 30127, + "ţ": 30128, + "路": 30129, + "例": 30130, + "机": 30131, + "Ã": 30132, + "ď": 30133, + "高": 30134, + "相": 30135, + "โ": 30136, + "片": 30137, + "―": 30138, + "操": 30139, + "ա": 30140, + "ม": 30141, + "全": 30142, + "无": 30143, + "月": 30144, + "称": 30145, + "ั": 30146, + "就": 30147, + "™": 30148, + "明": 30149, + "计": 30150, + "你": 30151, + "败": 30152, + "密": 30153, + "解": 30154, + "れ": 30155, + "أ": 30156, + "变": 30157, + "段": 30158, + "条": 30159, + "默": 30160, + "●": 30161, + "ล": 30162, + "色": 30163, + "断": 30164, + "商": 30165, + "ם": 30166, + "か": 30167, + "里": 30168, + "系": 30169, + "编": 30170, + "错": 30171, + "트": 30172, + "只": 30173, + "县": 30174, + "ს": 30175, + "常": 30176, + "初": 30177, + "ɔ": 30178, + "Α": 30179, + "フ": 30180, + "►": 30181, + "等": 30182, + "일": 30183, + "・": 30184, + "Ō": 30185, + "情": 30186, + "现": 30187, + "Ř": 30188, + "ِ": 30189, + "さ": 30190, + "ạ": 30191, + "용": 30192, + "证": 30193, + "해": 30194, + "手": 30195, + "支": 30196, + "입": 30197, + "服": 30198, + "்": 30199, + "道": 30200, + "어": 30201, + "送": 30202, + "载": 30203, + "限": 30204, + "线": 30205, + "属": 30206, + "—": 30207, + "他": 30208, + "放": 30209, + "记": 30210, + "公": 30211, + "没": 30212, + "添": 30213, + "显": 30214, + "บ": 30215, + "ย": 30216, + "რ": 30217, + "其": 30218, + "集": 30219, + "金": 30220, + "国": 30221, + "任": 30222, + "ە": 30223, + "话": 30224, + "并": 30225, + "被": 30226, + "ύ": 30227, + "都": 30228, + "گ": 30229, + "意": 30230, + "כ": 30231, + "经": 30232, + "성": 30233, + "看": 30234, + "פ": 30235, + "址": 30236, + "ס": 30237, + "드": 30238, + "交": 30239, + "¼": 30240, + "Џ": 30241, + "完": 30242, + "Δ": 30243, + "义": 30244, + "보": 30245, + "向": 30246, + "换": 30247, + "山": 30248, + "算": 30249, + "二": 30250, + "پ": 30251, + "⁄": 30252, + "判": 30253, + "级": 30254, + "工": 30255, + "ด": 30256, + "⠀": 30257, + "家": 30258, + "レ": 30259, + "三": 30260, + "原": 30261, + "】": 30262, + "长": 30263, + "া": 30264, + "管": 30265, + "ѝ": 30266, + "क": 30267, + "学": 30268, + "ロ": 30269, + "验": 30270, + "写": 30271, + "Œ": 30272, + "从": 30273, + "【": 30274, + "收": 30275, + "ả": 30276, + "未": 30277, + "登": 30278, + "고": 30279, + "源": 30280, + "每": 30281, + "µ": 30282, + "误": 30283, + "り": 30284, + "요": 30285, + "按": 30286, + "ว": 30287, + "权": 30288, + "根": 30289, + "プ": 30290, + "串": 30291, + "ส": 30292, + "›": 30293, + "제": 30294, + "シ": 30295, + "Ş": 30296, + "确": 30297, + "好": 30298, + "统": 30299, + "效": 30300, + "网": 30301, + "\u0001": 30302, + "物": 30303, + "아": 30304, + "也": 30305, + "은": 30306, + "ệ": 30307, + "न": 30308, + "项": 30309, + "资": 30310, + "こ": 30311, + "引": 30312, + "ジ": 30313, + "ค": 30314, + "版": 30315, + "ท": 30316, + "平": 30317, + "们": 30318, + "与": 30319, + "き": 30320, + "移": 30321, + "ि": 30322, + "素": 30323, + "执": 30324, + "주": 30325, + "‐": 30326, + "Ґ": 30327, + "ี": 30328, + "板": 30329, + "问": 30330, + "Ε": 30331, + "安": 30332, + "면": 30333, + "소": 30334, + "ต": 30335, + "ิ": 30336, + "持": 30337, + "습": 30338, + "Σ": 30339, + "ら": 30340, + "コ": 30341, + "心": 30342, + "Π": 30343, + "打": 30344, + "」": 30345, + "상": 30346, + "「": 30347, + "检": 30348, + "库": 30349, + "÷": 30350, + "으": 30351, + "测": 30352, + "ん": 30353, + "े": 30354, + "ُ": 30355, + "力": 30356, + "直": 30357, + "由": 30358, + "ى": 30359, + "试": 30360, + "必": 30361, + "端": 30362, + "ʻ": 30363, + "先": 30364, + "↑": 30365, + "命": 30366, + "도": 30367, + "전": 30368, + "ห": 30369, + "员": 30370, + "ɪ": 30371, + "있": 30372, + "比": 30373, + "ṣ": 30374, + "時": 30375, + "择": 30376, + "ذ": 30377, + "テ": 30378, + "‌": 30379, + "构": 30380, + "备": 30381, + "그": 30382, + "链": 30383, + "说": 30384, + "ლ": 30385, + "ן": 30386, + "签": 30387, + "う": 30388, + "غ": 30389, + "ế": 30390, + "ض": 30391, + "ḥ": 30392, + "启": 30393, + "력": 30394, + "ო": 30395, + "付": 30396, + "მ": 30397, + "索": 30398, + "特": 30399, + "ג": 30400, + "西": 30401, + "대": 30402, + "├": 30403, + "–": 30404, + "Ž": 30405, + "外": 30406, + "צ": 30407, + "头": 30408, + "连": 30409, + "流": 30410, + "◄": 30411, + "デ": 30412, + "カ": 30413, + "র": 30414, + "오": 30415, + "找": 30416, + "清": 30417, + "🤣": 30418, + "去": 30419, + "₹": 30420, + "경": 30421, + "グ": 30422, + "ْ": 30423, + "¢": 30424, + "因": 30425, + "": 30426, + "Κ": 30427, + "增": 30428, + "知": 30429, + "¶": 30430, + "像": 30431, + "♥": 30432, + "터": 30433, + "く": 30434, + "ậ": 30435, + "メ": 30436, + "Æ": 30437, + "省": 30438, + "स": 30439, + "म": 30440, + "❤": 30441, + "あ": 30442, + "样": 30443, + "起": 30444, + "台": 30445, + "读": 30446, + "角": 30447, + "南": 30448, + "整": 30449, + "订": 30450, + "\f": 30451, + "ט": 30452, + "マ": 30453, + "্": 30454, + "우": 30455, + "ն": 30456, + "您": 30457, + "ئ": 30458, + "基": 30459, + "水": 30460, + "생": 30461, + "‑": 30462, + "나": 30463, + "画": 30464, + "描": 30465, + "击": 30466, + "っ": 30467, + "라": 30468, + "ნ": 30469, + "ր": 30470, + "业": 30471, + "ბ": 30472, + "别": 30473, + "♦": 30474, + "ィ": 30475, + "त": 30476, + "给": 30477, + "문": 30478, + "形": 30479, + "控": 30480, + "然": 30481, + "동": 30482, + "Њ": 30483, + "⁠": 30484, + "东": 30485, + "ป": 30486, + "州": 30487, + "排": 30488, + "세": 30489, + "装": 30490, + "할": 30491, + "Ć": 30492, + "∞": 30493, + "海": 30494, + "城": 30495, + "键": 30496, + "径": 30497, + "호": 30498, + "화": 30499, + "្": 30500, + "料": 30501, + "ơ": 30502, + "ी": 30503, + "ウ": 30504, + "具": 30505, + "ブ": 30506, + "块": 30507, + "再": 30508, + "ố": 30509, + "电": 30510, + ";": 30511, + "위": 30512, + "两": 30513, + "而": 30514, + "장": 30515, + "آ": 30516, + "Ț": 30517, + "バ": 30518, + "还": 30519, + "令": 30520, + "キ": 30521, + "ّ": 30522, + "값": 30523, + "번": 30524, + "만": 30525, + "总": 30526, + "ल": 30527, + "▲": 30528, + "异": 30529, + "光": 30530, + "客": 30531, + "非": 30532, + "ị": 30533, + "": 30534, + "þ": 30535, + "設": 30536, + "述": 30537, + "합": 30538, + "?": 30539, + "✔": 30540, + "导": 30541, + "ṇ": 30542, + "부": 30543, + "˙": 30544, + "Τ": 30545, + "も": 30546, + "구": 30547, + "镇": 30548, + "작": 30549, + "░": 30550, + "步": 30551, + "ộ": 30552, + "活": 30553, + "พ": 30554, + "←": 30555, + "ǎ": 30556, + "จ": 30557, + "束": 30558, + "ـ": 30559, + "‘": 30560, + "那": 30561, + "प": 30562, + "エ": 30563, + "志": 30564, + "么": 30565, + "运": 30566, + "北": 30567, + "超": 30568, + "་": 30569, + "布": 30570, + "ώ": 30571, + "͡": 30572, + "少": 30573, + "파": 30574, + "ʃ": 30575, + "ム": 30576, + "•": 30577, + "卡": 30578, + "ন": 30579, + "Μ": 30580, + "ɑ": 30581, + "😉": 30582, + "辑": 30583, + "원": 30584, + "美": 30585, + "产": 30586, + "利": 30587, + "모": 30588, + "联": 30589, + "界": 30590, + "체": 30591, + "种": 30592, + "王": 30593, + "ľ": 30594, + "여": 30595, + "메": 30596, + "域": 30597, + "ვ": 30598, + "立": 30599, + "록": 30600, + "게": 30601, + "إ": 30602, + "ṭ": 30603, + "神": 30604, + "ո": 30605, + "音": 30606, + "☆": 30607, + "Ñ": 30608, + "조": 30609, + "動": 30610, + "缓": 30611, + "과": 30612, + "报": 30613, + "ʼ": 30614, + "ា": 30615, + "되": 30616, + "ե": 30617, + "视": 30618, + "ช": 30619, + "详": 30620, + "แ": 30621, + "¦": 30622, + "把": 30623, + "க": 30624, + "ি": 30625, + "출": 30626, + "비": 30627, + "边": 30628, + "框": 30629, + "व": 30630, + "サ": 30631, + "Ι": 30632, + "Ο": 30633, + "オ": 30634, + "¾": 30635, + "历": 30636, + "ŏ": 30637, + "门": 30638, + "ข": 30639, + "含": 30640, + "¬": 30641, + "周": 30642, + "填": 30643, + "待": 30644, + "ะ": 30645, + "დ": 30646, + "Ї": 30647, + "额": 30648, + "음": 30649, + "四": 30650, + "だ": 30651, + "회": 30652, + "止": 30653, + "率": 30654, + "环": 30655, + "パ": 30656, + "래": 30657, + "闭": 30658, + "̀": 30659, + "语": 30660, + "개": 30661, + "身": 30662, + "藏": 30663, + "य": 30664, + "된": 30665, + "即": 30666, + "拉": 30667, + "선": 30668, + "변": 30669, + "≥": 30670, + "ุ": 30671, + "些": 30672, + "🤷": 30673, + "せ": 30674, + "左": 30675, + "ợ": 30676, + "右": 30677, + "ể": 30678, + "내": 30679, + "ּ": 30680, + "ז": 30681, + "ে": 30682, + "告": 30683, + "ấ": 30684, + "白": 30685, + "账": 30686, + "费": 30687, + "江": 30688, + "み": 30689, + "‹": 30690, + "์": 30691, + "‡": 30692, + "造": 30693, + "但": 30694, + "十": 30695, + "它": 30696, + "ं": 30697, + "ŋ": 30698, + "ў": 30699, + "セ": 30700, + "女": 30701, + "⣿": 30702, + "ի": 30703, + "京": 30704, + "触": 30705, + "함": 30706, + "들": 30707, + "Ā": 30708, + "˜": 30709, + "石": 30710, + "よ": 30711, + "田": 30712, + "易": 30713, + "规": 30714, + "展": 30715, + "¯": 30716, + "做": 30717, + "星": 30718, + "უ": 30719, + "✓": 30720, + "თ": 30721, + "供": 30722, + "명": 30723, + "ξ": 30724, + "己": 30725, + "且": 30726, + "插": 30727, + "景": 30728, + "切": 30729, + "ไ": 30730, + "없": 30731, + "ョ": 30732, + "及": 30733, + "Ν": 30734, + "미": 30735, + "ث": 30736, + "데": 30737, + "价": 30738, + "乡": 30739, + "ह": 30740, + "チ": 30741, + "真": 30742, + "太": 30743, + "ู": 30744, + "ダ": 30745, + "局": 30746, + "♂": 30747, + "退": 30748, + "ு": 30749, + "ক": 30750, + "ி": 30751, + "何": 30752, + "😭": 30753, + "¥": 30754, + "": 30755, + "≈": 30756, + "司": 30757, + "层": 30758, + "실": 30759, + "站": 30760, + "首": 30761, + "款": 30762, + "រ": 30763, + "間": 30764, + "ָ": 30765, + "저": 30766, + "监": 30767, + "ァ": 30768, + "册": 30769, + "案": 30770, + "ो": 30771, + "反": 30772, + "听": 30773, + "族": 30774, + "析": 30775, + "ื": 30776, + "秒": 30777, + "공": 30778, + "œ": 30779, + "🚀": 30780, + "거": 30781, + "재": 30782, + "‚": 30783, + "場": 30784, + "广": 30785, + "播": 30786, + "║": 30787, + "⋅": 30788, + "技": 30789, + "贴": 30790, + "想": 30791, + "ʁ": 30792, + "ớ": 30793, + "ャ": 30794, + "중": 30795, + "》": 30796, + "速": 30797, + "频": 30798, + "队": 30799, + "ำ": 30800, + "け": 30801, + "ु": 30802, + "≤": 30803, + "↓": 30804, + "须": 30805, + "菜": 30806, + "̃": 30807, + "剪": 30808, + "버": 30809, + "ェ": 30810, + "Λ": 30811, + "细": 30812, + "選": 30813, + "द": 30814, + "¹": 30815, + "许": 30816, + "ầ": 30817, + "世": 30818, + "ュ": 30819, + "ء": 30820, + "‡": 30821, + "候": 30822, + "共": 30823, + "크": 30824, + "ธ": 30825, + "설": 30826, + "快": 30827, + "友": 30828, + "ְ": 30829, + "车": 30830, + "推": 30831, + "花": 30832, + "言": 30833, + "چ": 30834, + "至": 30835, + "開": 30836, + "校": 30837, + "個": 30838, + "村": 30839, + "つ": 30840, + "▌": 30841, + "ப": 30842, + "결": 30843, + "ņ": 30844, + "优": 30845, + "ន": 30846, + "达": 30847, + "核": 30848, + "ナ": 30849, + "场": 30850, + "影": 30851, + "🏻": 30852, + "钮": 30853, + "ظ": 30854, + "Þ": 30855, + "▼": 30856, + "お": 30857, + "份": 30858, + "微": 30859, + "ờ": 30860, + "识": 30861, + "행": 30862, + "《": 30863, + "ใ": 30864, + "ọ": 30865, + "预": 30866, + "ব": 30867, + "த": 30868, + "": 30869, + "ų": 30870, + "마": 30871, + "않": 30872, + "ɡ": 30873, + "계": 30874, + "연": 30875, + "五": 30876, + "Ź": 30877, + "め": 30878, + "很": 30879, + "간": 30880, + "無": 30881, + "ប": 30882, + "社": 30883, + "Ê": 30884, + "书": 30885, + "顶": 30886, + "ტ": 30887, + "才": 30888, + "云": 30889, + "└": 30890, + "ζ": 30891, + "،": 30892, + "搜": 30893, + "신": 30894, + "유": 30895, + "‏": 30896, + "✅": 30897, + "⭐": 30898, + "照": 30899, + "短": 30900, + "川": 30901, + "後": 30902, + "范": 30903, + "民": 30904, + "治": 30905, + "章": 30906, + "ề": 30907, + "바": 30908, + "ә": 30909, + "⚭": 30910, + "河": 30911, + "论": 30912, + "え": 30913, + "Ω": 30914, + "√": 30915, + "Ă": 30916, + "Γ": 30917, + "坐": 30918, + "적": 30919, + "停": 30920, + "추": 30921, + "受": 30922, + "♀": 30923, + "ʾ": 30924, + "树": 30925, + "林": 30926, + "치": 30927, + "fi": 30928, + "▒": 30929, + "张": 30930, + "着": 30931, + "访": 30932, + "考": 30933, + "教": 30934, + "ग": 30935, + "准": 30936, + "印": 30937, + "精": 30938, + "窗": 30939, + "宝": 30940, + "ち": 30941, + "围": 30942, + "ַ": 30943, + "致": 30944, + "モ": 30945, + "때": 30946, + "随": 30947, + "储": 30948, + "况": 30949, + "邮": 30950, + "武": 30951, + "⛔": 30952, + "维": 30953, + "ү": 30954, + "跳": 30955, + "ब": 30956, + "投": 30957, + "ủ": 30958, + "표": 30959, + "반": 30960, + "英": 30961, + "ʰ": 30962, + "👍": 30963, + "ज": 30964, + "带": 30965, + "為": 30966, + "续": 30967, + "ɨ": 30968, + "처": 30969, + "₂": 30970, + "클": 30971, + "群": 30972, + "현": 30973, + "风": 30974, + "购": 30975, + "ក": 30976, + "老": 30977, + "留": 30978, + "球": 30979, + "프": 30980, + "▄": 30981, + "史": 30982, + "Љ": 30983, + "⟩": 30984, + "분": 30985, + "გ": 30986, + "店": 30987, + "审": 30988, + "료": 30989, + "목": 30990, + "略": 30991, + "관": 30992, + "ִ": 30993, + "科": 30994, + "货": 30995, + "ம": 30996, + "络": 30997, + "阳": 30998, + "Ḥ": 30999, + "資": 31000, + "若": 31001, + "স": 31002, + "ہ": 31003, + "宽": 31004, + "见": 31005, + "ズ": 31006, + "游": 31007, + "방": 31008, + "ồ": 31009, + "ɾ": 31010, + "열": 31011, + "러": 31012, + "ך": 31013, + "\u001b": 31014, + "်": 31015, + "余": 31016, + "响": 31017, + "缩": 31018, + "ட": 31019, + "评": 31020, + "允": 31021, + "离": 31022, + "🤔": 31023, + "Ё": 31024, + "ʊ": 31025, + "黑": 31026, + "马": 31027, + "⟨": 31028, + "値": 31029, + "箱": 31030, + "야": 31031, + "ម": 31032, + "Ő": 31033, + "感": 31034, + "ツ": 31035, + "ụ": 31036, + "ポ": 31037, + "확": 31038, + "声": 31039, + "战": 31040, + "ѕ": 31041, + "変": 31042, + "와": 31043, + "父": 31044, + "ベ": 31045, + "助": 31046, + "업": 31047, + "ʲ": 31048, + "ÿ": 31049, + "充": 31050, + "强": 31051, + "博": 31052, + "ミ": 31053, + "销": 31054, + "당": 31055, + "記": 31056, + "什": 31057, + "匹": 31058, + "ւ": 31059, + "そ": 31060, + "코": 31061, + "ল": 31062, + "ŭ": 31063, + "午": 31064, + "ニ": 31065, + "\u0012": 31066, + "ʒ": 31067, + "შ": 31068, + "某": 31069, + "ォ": 31070, + "足": 31071, + "타": 31072, + "Ð": 31073, + "ხ": 31074, + "름": 31075, + "木": 31076, + "楼": 31077, + "최": 31078, + "红": 31079, + "¨": 31080, + "古": 31081, + "\u0006": 31082, + "단": 31083, + "今": 31084, + "ʔ": 31085, + "ट": 31086, + "ম": 31087, + "斯": 31088, + "語": 31089, + "Ÿ": 31090, + "🙄": 31091, + "牌": 31092, + "안": 31093, + "ស": 31094, + "颜": 31095, + "~": 31096, + "克": 31097, + "深": 31098, + "금": 31099, + "會": 31100, + "尔": 31101, + "释": 31102, + "批": 31103, + "산": 31104, + "野": 31105, + "防": 31106, + "Η": 31107, + "ө": 31108, + "ψ": 31109, + "ボ": 31110, + "š": 31111, + "各": 31112, + "진": 31113, + "追": 31114, + "句": 31115, + "警": 31116, + "Φ": 31117, + "ѣ": 31118, + "ḍ": 31119, + "词": 31120, + "男": 31121, + "글": 31122, + "식": 31123, + "隐": 31124, + "복": 31125, + "盘": 31126, + "Ì": 31127, + "申": 31128, + "议": 31129, + "ザ": 31130, + "近": 31131, + "능": 31132, + "য": 31133, + "東": 31134, + "這": 31135, + "ர": 31136, + "距": 31137, + "院": 31138, + "德": 31139, + "ǐ": 31140, + "针": 31141, + "▀": 31142, + "↔": 31143, + "房": 31144, + "青": 31145, + "政": 31146, + "😅": 31147, + "递": 31148, + "প": 31149, + "波": 31150, + "ソ": 31151, + "绑": 31152, + "ビ": 31153, + "ễ": 31154, + "포": 31155, + "\u0010": 31156, + "ử": 31157, + "등": 31158, + "환": 31159, + "士": 31160, + "ত": 31161, + "Θ": 31162, + "초": 31163, + "境": 31164, + "差": 31165, + "采": 31166, + "디": 31167, + "ĩ": 31168, + "升": 31169, + "背": 31170, + "배": 31171, + "龙": 31172, + "街": 31173, + "್": 31174, + "ṛ": 31175, + "ু": 31176, + "弹": 31177, + "魔": 31178, + "객": 31179, + "‰": 31180, + "⌁": 31181, + "ἐ": 31182, + "禁": 31183, + "ผ": 31184, + "қ": 31185, + "島": 31186, + "ா": 31187, + "♭": 31188, + "百": 31189, + "ứ": 31190, + "ネ": 31191, + "专": 31192, + "來": 31193, + "刷": 31194, + "필": 31195, + "յ": 31196, + "ắ": 31197, + "华": 31198, + "Β": 31199, + "श": 31200, + "¸": 31201, + "屏": 31202, + "死": 31203, + "遍": 31204, + "검": 31205, + "Χ": 31206, + "것": 31207, + "八": 31208, + "览": 31209, + "택": 31210, + "唯": 31211, + "∙": 31212, + "¤": 31213, + "페": 31214, + "让": 31215, + "锁": 31216, + "무": 31217, + "思": 31218, + "隔": 31219, + "Ô": 31220, + "\u0013": 31221, + "ṃ": 31222, + "ワ": 31223, + "低": 31224, + "션": 31225, + "半": 31226, + "较": 31227, + "ត": 31228, + "享": 31229, + "积": 31230, + "ˆ": 31231, + "😊": 31232, + "典": 31233, + "ǔ": 31234, + "六": 31235, + "便": 31236, + "ɐ": 31237, + "简": 31238, + "继": 31239, + "仅": 31240, + "尾": 31241, + "‹": 31242, + "வ": 31243, + "կ": 31244, + "ƒ": 31245, + "영": 31246, + "火": 31247, + "湖": 31248, + "書": 31249, + "발": 31250, + "ハ": 31251, + "循": 31252, + "术": 31253, + "結": 31254, + "ļ": 31255, + "乐": 31256, + "滤": 31257, + "종": 31258, + "ถ": 31259, + "ὶ": 31260, + "满": 31261, + "╝": 31262, + "わ": 31263, + "ど": 31264, + "็": 31265, + "형": 31266, + "國": 31267, + "ự": 31268, + "線": 31269, + "블": 31270, + "封": 31271, + "確": 31272, + "依": 31273, + "ս": 31274, + "永": 31275, + "색": 31276, + "歌": 31277, + "數": 31278, + "福": 31279, + "삭": 31280, + "実": 31281, + "레": 31282, + "ſ": 31283, + "千": 31284, + "\u000e": 31285, + "母": 31286, + "더": 31287, + "임": 31288, + "տ": 31289, + "ے": 31290, + "几": 31291, + "双": 31292, + "노": 31293, + "ณ": 31294, + "掉": 31295, + "Ρ": 31296, + "ἀ": 31297, + "標": 31298, + "長": 31299, + "档": 31300, + "태": 31301, + "ペ": 31302, + "본": 31303, + "Œ": 31304, + "底": 31305, + "终": 31306, + "請": 31307, + "კ": 31308, + "̯": 31309, + "예": 31310, + "▬": 31311, + "報": 31312, + "ピ": 31313, + "๏": 31314, + "暂": 31315, + "李": 31316, + "Υ": 31317, + "\u0005": 31318, + "\u0002": 31319, + "替": 31320, + "운": 31321, + "射": 31322, + "\u0018": 31323, + "매": 31324, + "\u0011": 31325, + "🏼": 31326, + "票": 31327, + "附": 31328, + "ノ": 31329, + "ũ": 31330, + "压": 31331, + "阿": 31332, + "Ò": 31333, + "테": 31334, + "∼": 31335, + "万": 31336, + "մ": 31337, + "후": 31338, + "普": 31339, + "截": 31340, + "속": 31341, + "括": 31342, + "😀": 31343, + "ை": 31344, + "▶": 31345, + "까": 31346, + "ট": 31347, + "曲": 31348, + "师": 31349, + "钱": 31350, + "栏": 31351, + "Ы": 31352, + "走": 31353, + "ữ": 31354, + "‬": 31355, + "归": 31356, + "점": 31357, + "🔥": 31358, + "었": 31359, + "連": 31360, + "私": 31361, + "청": 31362, + "刘": 31363, + "免": 31364, + "": 31365, + "奖": 31366, + "見": 31367, + "ֹ": 31368, + "☺": 31369, + "ケ": 31370, + "역": 31371, + "际": 31372, + "받": 31373, + "望": 31374, + "帝": 31375, + "减": 31376, + "두": 31377, + "领": 31378, + "„": 31379, + "钟": 31380, + "ガ": 31381, + "架": 31382, + "든": 31383, + "ல": 31384, + "松": 31385, + "□": 31386, + "越": 31387, + "答": 31388, + "ɕ": 31389, + "ῦ": 31390, + "染": 31391, + "": 31392, + "质": 31393, + "顺": 31394, + "气": 31395, + "╗": 31396, + "計": 31397, + "ქ": 31398, + "亮": 31399, + "🤦": 31400, + "̂": 31401, + "ٹ": 31402, + "座": 31403, + "ˌ": 31404, + "均": 31405, + "\u000b": 31406, + "官": 31407, + "适": 31408, + "护": 31409, + "久": 31410, + "春": 31411, + "曹": 31412, + "皇": 31413, + "脚": 31414, + "池": 31415, + "延": 31416, + "키": 31417, + "품": 31418, + "現": 31419, + "檔": 31420, + "ば": 31421, + "ⴰ": 31422, + "希": 31423, + "玩": 31424, + "固": 31425, + "黄": 31426, + "": 31427, + "☽": 31428, + "银": 31429, + "\u0003": 31430, + "┃": 31431, + "👏": 31432, + "불": 31433, + "攻": 31434, + "へ": 31435, + "决": 31436, + "⊙": 31437, + "宁": 31438, + "च": 31439, + "機": 31440, + "義": 31441, + "ɲ": 31442, + "\u0015": 31443, + "했": 31444, + "ẩ": 31445, + "愛": 31446, + "矩": 31447, + "패": 31448, + "ặ": 31449, + "郎": 31450, + "Ь": 31451, + "绘": 31452, + "负": 31453, + "ổ": 31454, + "ய": 31455, + "汉": 31456, + "編": 31457, + "ێ": 31458, + "്": 31459, + "じ": 31460, + "카": 31461, + "似": 31462, + "ں": 31463, + "や": 31464, + "認": 31465, + "\u000f": 31466, + "過": 31467, + "통": 31468, + "▪": 31469, + "约": 31470, + "香": 31471, + "买": 31472, + "住": 31473, + "╚": 31474, + "😁": 31475, + "扩": 31476, + "静": 31477, + "려": 31478, + "학": 31479, + "钥": 31480, + "증": 31481, + "ỉ": 31482, + "她": 31483, + "食": 31484, + "往": 31485, + "點": 31486, + "偏": 31487, + "康": 31488, + "\u0014": 31489, + "į": 31490, + "준": 31491, + "\u0004": 31492, + "ฟ": 31493, + "♣": 31494, + "戏": 31495, + "ʂ": 31496, + "井": 31497, + "军": 31498, + "爱": 31499, + "ٱ": 31500, + "七": 31501, + "차": 31502, + "币": 31503, + "♠": 31504, + "哈": 31505, + "阅": 31506, + "介": 31507, + "观": 31508, + "區": 31509, + "˜": 31510, + "ً": 31511, + "又": 31512, + "冲": 31513, + "朝": 31514, + "姓": 31515, + "课": 31516, + "龍": 31517, + "각": 31518, + "∈": 31519, + "米": 31520, + "ƒ": 31521, + "喜": 31522, + "夜": 31523, + "团": 31524, + "⇒": 31525, + "远": 31526, + "\u001a": 31527, + "ὐ": 31528, + "承": 31529, + "ಿ": 31530, + "室": 31531, + "ʀ": 31532, + "ង": 31533, + "अ": 31534, + "罗": 31535, + "🙏": 31536, + "软": 31537, + "🟡": 31538, + "건": 31539, + "؟": 31540, + "း": 31541, + "ᴇ": 31542, + "ユ": 31543, + "토": 31544, + "策": 31545, + "̄": 31546, + "국": 31547, + "ֶ": 31548, + "协": 31549, + "营": 31550, + "関": 31551, + "吉": 31552, + "💀": 31553, + "奇": 31554, + "滚": 31555, + "轴": 31556, + "処": 31557, + "土": 31558, + "划": 31559, + "ड": 31560, + "临": 31561, + "ֵ": 31562, + "航": 31563, + "浏": 31564, + "ゴ": 31565, + "別": 31566, + "寺": 31567, + "於": 31568, + "進": 31569, + "ὸ": 31570, + "風": 31571, + "ன": 31572, + "班": 31573, + "◼": 31574, + "九": 31575, + "̥": 31576, + "號": 31577, + "류": 31578, + "础": 31579, + "般": 31580, + "︙": 31581, + "̈": 31582, + "番": 31583, + "✨": 31584, + "😎": 31585, + "ো": 31586, + "😍": 31587, + "單": 31588, + "帧": 31589, + "授": 31590, + "赋": 31591, + "巴": 31592, + "占": 31593, + "假": 31594, + "ṅ": 31595, + "透": 31596, + "項": 31597, + "ħ": 31598, + "馬": 31599, + "🟢": 31600, + "Ľ": 31601, + "լ": 31602, + "券": 31603, + "같": 31604, + "類": 31605, + "對": 31606, + "월": 31607, + "激": 31608, + "\u0017": 31609, + "戦": 31610, + "独": 31611, + "訊": 31612, + "ិ": 31613, + "套": 31614, + "ʷ": 31615, + "跟": 31616, + "ở": 31617, + "渲": 31618, + "顯": 31619, + "降": 31620, + "ာ": 31621, + "尼": 31622, + "血": 31623, + "언": 31624, + "牛": 31625, + "將": 31626, + "ศ": 31627, + "拍": 31628, + "刻": 31629, + "ზ": 31630, + "╔": 31631, + "藤": 31632, + "్": 31633, + "ῶ": 31634, + "🟠": 31635, + "良": 31636, + "김": 31637, + "দ": 31638, + "Ṣ": 31639, + "録": 31640, + "伊": 31641, + "落": 31642, + "雄": 31643, + "雪": 31644, + "映": 31645, + "著": 31646, + "른": 31647, + "ფ": 31648, + "対": 31649, + "智": 31650, + "译": 31651, + "┬": 31652, + "抽": 31653, + "ῖ": 31654, + "酒": 31655, + "Ћ": 31656, + "股": 31657, + "់": 31658, + "순": 31659, + "직": 31660, + "भ": 31661, + "谷": 31662, + "물": 31663, + "ǒ": 31664, + "⠄": 31665, + "热": 31666, + "終": 31667, + "夹": 31668, + "干": 31669, + "彩": 31670, + "敗": 31671, + "ќ": 31672, + "♯": 31673, + "̣": 31674, + "վ": 31675, + "轮": 31676, + "阵": 31677, + "夏": 31678, + "幕": 31679, + "吧": 31680, + "港": 31681, + "益": 31682, + "儿": 31683, + "액": 31684, + "售": 31685, + "兵": 31686, + "惠": 31687, + "欢": 31688, + "›": 31689, + "零": 31690, + "學": 31691, + "ž": 31692, + "員": 31693, + "ỗ": 31694, + "玉": 31695, + "逻": 31696, + "᥀": 31697, + "吗": 31698, + "沒": 31699, + "≠": 31700, + "너": 31701, + "ச": 31702, + "\u0016": 31703, + "夫": 31704, + "წ": 31705, + "堂": 31706, + "電": 31707, + "≡": 31708, + "陆": 31709, + "져": 31710, + "研": 31711, + "荐": 31712, + "健": 31713, + "碼": 31714, + "练": 31715, + "検": 31716, + "송": 31717, + "ै": 31718, + "哪": 31719, + "圆": 31720, + "Ա": 31721, + "↩": 31722, + "托": 31723, + "̪": 31724, + "ू": 31725, + "缀": 31726, + "네": 31727, + "沙": 31728, + "兴": 31729, + "病": 31730, + "\u0007": 31731, + "ល": 31732, + "ừ": 31733, + "Ἀ": 31734, + "강": 31735, + "항": 31736, + "\u0019": 31737, + "換": 31738, + "温": 31739, + "帖": 31740, + "ទ": 31741, + "込": 31742, + "削": 31743, + "알": 31744, + "征": 31745, + "习": 31746, + "법": 31747, + "栈": 31748, + "绝": 31749, + "": 31750, + "ڕ": 31751, + "圖": 31752, + "苏": 31753, + "発": 31754, + "ု": 31755, + "町": 31756, + "互": 31757, + "়": 31758, + "ც": 31759, + "守": 31760, + "새": 31761, + "侧": 31762, + "草": 31763, + "ས": 31764, + "扫": 31765, + "‒": 31766, + "恢": 31767, + "ң": 31768, + "ण": 31769, + "ற": 31770, + "째": 31771, + "්": 31772, + "拟": 31773, + "派": 31774, + "🏽": 31775, + "呼": 31776, + "Š": 31777, + "演": 31778, + "究": 31779, + "교": 31780, + "ɣ": 31781, + "ए": 31782, + "ី": 31783, + "ף": 31784, + "富": 31785, + "駅": 31786, + "ず": 31787, + "♪": 31788, + "😆": 31789, + "접": 31790, + "ғ": 31791, + "▓": 31792, + "존": 31793, + "ಾ": 31794, + "旋": 31795, + "ゃ": 31796, + "补": 31797, + "ץ": 31798, + "門": 31799, + "ច": 31800, + "날": 31801, + "ภ": 31802, + "ག": 31803, + "傳": 31804, + "∆": 31805, + "†": 31806, + "ׁ": 31807, + "缺": 31808, + "頭": 31809, + "怪": 31810, + "組": 31811, + "별": 31812, + "Ъ": 31813, + "發": 31814, + "雷": 31815, + "ರ": 31816, + "ซ": 31817, + "び": 31818, + "翻": 31819, + "ھ": 31820, + "პ": 31821, + "題": 31822, + "居": 31823, + "집": 31824, + "🌍": 31825, + "˚": 31826, + "避": 31827, + "줄": 31828, + "ុ": 31829, + "滑": 31830, + "故": 31831, + "ญ": 31832, + "〜": 31833, + "ನ": 31834, + "양": 31835, + "완": 31836, + "ள": 31837, + "倍": 31838, + "宗": 31839, + "択": 31840, + "브": 31841, + "ɴ": 31842, + "効": 31843, + "尺": 31844, + "視": 31845, + "ẽ": 31846, + "覆": 31847, + "ध": 31848, + "骨": 31849, + "달": 31850, + "ᴛ": 31851, + "蓝": 31852, + "關": 31853, + "額": 31854, + "Õ": 31855, + "∗": 31856, + "卷": 31857, + "갑": 31858, + "르": 31859, + "众": 31860, + "ᴀ": 31861, + "態": 31862, + "ٰ": 31863, + "暗": 31864, + "君": 31865, + "錯": 31866, + "ɒ": 31867, + "យ": 31868, + "ḫ": 31869, + "ῆ": 31870, + "亚": 31871, + "♡": 31872, + "割": 31873, + "鼠": 31874, + "̶": 31875, + "Ë": 31876, + "読": 31877, + "격": 31878, + "ゲ": 31879, + "眼": 31880, + "Ý": 31881, + "ژ": 31882, + "雨": 31883, + "宮": 31884, + "쪽": 31885, + "ष": 31886, + "複": 31887, + "剩": 31888, + "早": 31889, + "杂": 31890, + "焦": 31891, + "贝": 31892, + "突": 31893, + "워": 31894, + "另": 31895, + "摄": 31896, + "\b": 31897, + "‭": 31898, + "府": 31899, + "외": 31900, + "盖": 31901, + "\u001c": 31902, + "ษ": 31903, + "佛": 31904, + "概": 31905, + "與": 31906, + "經": 31907, + "-": 31908, + "һ": 31909, + "問": 31910, + "ು": 31911, + "ἰ": 31912, + "話": 31913, + "倒": 31914, + "葛": 31915, + "べ": 31916, + "ろ": 31917, + "\u001e": 31918, + "।": 31919, + "ေ": 31920, + "ᴏ": 31921, + "训": 31922, + "體": 31923, + "👌": 31924, + "內": 31925, + "က": 31926, + "企": 31927, + "약": 31928, + "찾": 31929, + "ོ": 31930, + "破": 31931, + "輸": 31932, + "림": 31933, + "塔": 31934, + "턴": 31935, + "杀": 31936, + "』": 31937, + "味": 31938, + "浮": 31939, + "┆": 31940, + "ġ": 31941, + "郡": 31942, + "┐": 31943, + "『": 31944, + "阶": 31945, + "雅": 31946, + "┈": 31947, + "园": 31948, + ".": 31949, + "吃": 31950, + "남": 31951, + " ": 31952, + "ར": 31953, + "帮": 31954, + "毛": 31955, + "耗": 31956, + "举": 31957, + "ర": 31958, + "拿": 31959, + "밀": 31960, + "ご": 31961, + "够": 31962, + "礼": 31963, + "ព": 31964, + "ね": 31965, + "‰": 31966, + "兰": 31967, + "❌": 31968, + "折": 31969, + "십": 31970, + "💎": 31971, + "業": 31972, + "诸": 31973, + "孙": 31974, + "བ": 31975, + "😳": 31976, + "種": 31977, + "Ï": 31978, + "ึ": 31979, + "⁣": 31980, + "医": 31981, + "拼": 31982, + "↵": 31983, + "⅓": 31984, + "\u001f": 31985, + "မ": 31986, + "叫": 31987, + "জ": 31988, + "予": 31989, + "寸": 31990, + "梅": 31991, + "醒": 31992, + "津": 31993, + "န": 31994, + "ి": 31995, + "厂": 31996, + "屋": 31997, + "ख": 31998, + "師": 31999, + "👀": 32000, + "ỏ": 32001, + "ヤ": 32002, + "ὰ": 32003, + "\u001d": 32004, + "◆": 32005, + "ដ": 32006, + "材": 32007, + "ホ": 32008, + "張": 32009, + "洞": 32010, + "餐": 32011, + "천": 32012, + "হ": 32013, + "達": 32014, + "們": 32015, + "斗": 32016, + "横": 32017, + "백": 32018, + "ំ": 32019, + "ۆ": 32020, + "말": 32021, + "গ": 32022, + "佳": 32023, + "랜": 32024, + "仁": 32025, + "陈": 32026, + "飞": 32027, + "极": 32028, + "": 32029, + "및": 32030, + "仓": 32031, + "⬛": 32032, + "昌": 32033, + "錢": 32034, + "殊": 32035, + "┴": 32036, + "○": 32037, + "길": 32038, + "泉": 32039, + "甲": 32040, + "활": 32041, + "ひ": 32042, + "শ": 32043, + "ን": 32044, + "Ť": 32045, + "ღ": 32046, + "皮": 32047, + "強": 32048, + "赛": 32049, + "ా": 32050, + "預": 32051, + "င": 32052, + "튼": 32053, + "플": 32054, + "ყ": 32055, + "⋆": 32056, + "ք": 32057, + "ા": 32058, + "尚": 32059, + "또": 32060, + "բ": 32061, + "┌": 32062, + "節": 32063, + "森": 32064, + "आ": 32065, + "办": 32066, + "園": 32067, + "牙": 32068, + "庆": 32069, + "隆": 32070, + "😔": 32071, + "叉": 32072, + "գ": 32073, + "피": 32074, + "ギ": 32075, + "啊": 32076, + "続": 32077, + "灵": 32078, + "ヒ": 32079, + "忽": 32080, + "ʌ": 32081, + "량": 32082, + "油": 32083, + "讯": 32084, + "ⵉ": 32085, + "릭": 32086, + "刚": 32087, + "氏": 32088, + "ိ": 32089, + "Ī": 32090, + "誤": 32091, + "齐": 32092, + "末": 32093, + "🙌": 32094, + "̞": 32095, + "圈": 32096, + "念": 32097, + "숫": 32098, + "毫": 32099, + "當": 32100, + "規": 32101, + "판": 32102, + "ు": 32103, + "旧": 32104, + "卖": 32105, + "ฉ": 32106, + "幸": 32107, + "署": 32108, + "근": 32109, + "ই": 32110, + "岛": 32111, + "դ": 32112, + "觉": 32113, + "害": 32114, + "毕": 32115, + "ฐ": 32116, + "威": 32117, + "育": 32118, + "呢": 32119, + "峰": 32120, + "职": 32121, + "陽": 32122, + "ි": 32123, + "亞": 32124, + "ұ": 32125, + "₃": 32126, + "따": 32127, + "施": 32128, + "泰": 32129, + "載": 32130, + "…": 32131, + "笑": 32132, + "華": 32133, + "迎": 32134, + "됩": 32135, + "豆": 32136, + "嘉": 32137, + "🤡": 32138, + "ĕ": 32139, + "庄": 32140, + "級": 32141, + "Ψ": 32142, + "ི": 32143, + "気": 32144, + "责": 32145, + "հ": 32146, + "អ": 32147, + "乱": 32148, + "休": 32149, + "約": 32150, + "ฆ": 32151, + "∑": 32152, + "察": 32153, + "온": 32154, + "😬": 32155, + "ড": 32156, + "乘": 32157, + "람": 32158, + "इ": 32159, + "Ά": 32160, + "ந": 32161, + "ើ": 32162, + "亲": 32163, + "េ": 32164, + "委": 32165, + "赤": 32166, + "됨": 32167, + "勝": 32168, + "怎": 32169, + "감": 32170, + "宋": 32171, + "調": 32172, + "짜": 32173, + "ী": 32174, + "难": 32175, + "못": 32176, + "티": 32177, + "備": 32178, + "塞": 32179, + "វ": 32180, + "险": 32181, + "旅": 32182, + "虚": 32183, + "↳": 32184, + "笔": 32185, + "馆": 32186, + "Қ": 32187, + "⚡": 32188, + "ೆ": 32189, + "※": 32190, + "唐": 32191, + "律": 32192, + "稍": 32193, + "散": 32194, + "ર": 32195, + "ヴ": 32196, + "副": 32197, + "尽": 32198, + "挂": 32199, + "県": 32200, + "⚠": 32201, + "洋": 32202, + "鬼": 32203, + "암": 32204, + "孩": 32205, + "℃": 32206, + "並": 32207, + "ց": 32208, + "ូ": 32209, + "ℓ": 32210, + "ⵏ": 32211, + "扣": 32212, + "铁": 32213, + "闻": 32214, + "ˆ": 32215, + "戳": 32216, + "む": 32217, + "秀": 32218, + "細": 32219, + "ပ": 32220, + "御": 32221, + "拖": 32222, + "좌": 32223, + "ؤ": 32224, + "绍": 32225, + "ỹ": 32226, + "참": 32227, + "향": 32228, + "Ď": 32229, + "끝": 32230, + "민": 32231, + "ძ": 32232, + "贵": 32233, + "纪": 32234, + "秋": 32235, + "ಕ": 32236, + "ӏ": 32237, + "網": 32238, + "铺": 32239, + "恋": 32240, + "fl": 32241, + "兼": 32242, + "羽": 32243, + "창": 32244, + "啟": 32245, + "弟": 32246, + "년": 32247, + "慢": 32248, + "효": 32249, + "許": 32250, + "硬": 32251, + "잘": 32252, + "템": 32253, + "્": 32254, + "න": 32255, + "術": 32256, + "ڈ": 32257, + "溪": 32258, + "": 32259, + "暴": 32260, + "混": 32261, + "夢": 32262, + "랑": 32263, + "আ": 32264, + "還": 32265, + "探": 32266, + "祖": 32267, + "织": 32268, + "軍": 32269, + "թ": 32270, + "務": 32271, + "艺": 32272, + "ད": 32273, + "ት": 32274, + "ṁ": 32275, + "應": 32276, + "擇": 32277, + "🥰": 32278, + "ķ": 32279, + "渡": 32280, + "葉": 32281, + "령": 32282, + "決": 32283, + "刀": 32284, + "從": 32285, + "變": 32286, + "올": 32287, + "💪": 32288, + "灣": 32289, + "ር": 32290, + "평": 32291, + "衣": 32292, + "😄": 32293, + "ി": 32294, + "ჩ": 32295, + "ὁ": 32296, + "ほ": 32297, + "Û": 32298, + "চ": 32299, + "ර": 32300, + "製": 32301, + "隊": 32302, + "₱": 32303, + "纳": 32304, + "赖": 32305, + "农": 32306, + "桥": 32307, + "ỳ": 32308, + "🏾": 32309, + "阻": 32310, + "ជ": 32311, + "秘": 32312, + "박": 32313, + "伤": 32314, + "稿": 32315, + "ం": 32316, + "拦": 32317, + "넣": 32318, + "💕": 32319, + "₁": 32320, + "宿": 32321, + "錄": 32322, + "镜": 32323, + "채": 32324, + "Ə": 32325, + "ང": 32326, + "⇔": 32327, + "☼": 32328, + "ུ": 32329, + "党": 32330, + "급": 32331, + "洲": 32332, + "ղ": 32333, + "說": 32334, + "ĭ": 32335, + "尝": 32336, + "담": 32337, + "फ": 32338, + "哥": 32339, + "圣": 32340, + "萨": 32341, + "😏": 32342, + "ʏ": 32343, + "ெ": 32344, + "丁": 32345, + "虎": 32346, + "권": 32347, + "善": 32348, + "岩": 32349, + "커": 32350, + "◦": 32351, + "抛": 32352, + "석": 32353, + "Έ": 32354, + "宣": 32355, + "拳": 32356, + "팅": 32357, + "枚": 32358, + "洛": 32359, + "証": 32360, + "陵": 32361, + "佐": 32362, + "館": 32363, + "누": 32364, + "돌": 32365, + "₄": 32366, + "稱": 32367, + "聊": 32368, + "車": 32369, + "루": 32370, + "״": 32371, + "ಠ": 32372, + "庫": 32373, + "མ": 32374, + "統": 32375, + "련": 32376, + "़": 32377, + "ṯ": 32378, + "ക": 32379, + "旗": 32380, + "励": 32381, + "紀": 32382, + "忠": 32383, + "າ": 32384, + "杨": 32385, + "丹": 32386, + "Ù": 32387, + "ฝ": 32388, + "却": 32389, + "舞": 32390, + "轉": 32391, + "တ": 32392, + "丽": 32393, + "借": 32394, + "ා": 32395, + "ょ": 32396, + "옵": 32397, + "편": 32398, + "蒙": 32399, + "衡": 32400, + "ʋ": 32401, + "叶": 32402, + "̇": 32403, + "⬜": 32404, + "🇺": 32405, + "Հ": 32406, + "谢": 32407, + "Ą": 32408, + "ே": 32409, + "ằ": 32410, + "既": 32411, + "济": 32412, + "≯": 32413, + "準": 32414, + "답": 32415, + "ಲ": 32416, + "残": 32417, + "虑": 32418, + "̆": 32419, + "┘": 32420, + "急": 32421, + "招": 32422, + "막": 32423, + "≮": 32424, + "產": 32425, + "Ṭ": 32426, + "😢": 32427, + "垂": 32428, + "親": 32429, + "ģ": 32430, + "־": 32431, + "猫": 32432, + "ʟ": 32433, + "☃": 32434, + "✪": 32435, + "刪": 32436, + "胡": 32437, + "☉": 32438, + "晚": 32439, + "군": 32440, + "승": 32441, + "న": 32442, + "ὴ": 32443, + "曾": 32444, + "論": 32445, + "ɯ": 32446, + "త": 32447, + "戰": 32448, + "鱼": 32449, + "ǧ": 32450, + "寶": 32451, + "특": 32452, + "💯": 32453, + "崎": 32454, + "甘": 32455, + "該": 32456, + "링": 32457, + "😡": 32458, + "उ": 32459, + "ែ": 32460, + "頁": 32461, + "큰": 32462, + "➤": 32463, + "총": 32464, + "💰": 32465, + "∂": 32466, + "毁": 32467, + "聖": 32468, + "麻": 32469, + "ʐ": 32470, + "敏": 32471, + "運": 32472, + "될": 32473, + "쓰": 32474, + "ಸ": 32475, + "စ": 32476, + "✦": 32477, + "젝": 32478, + "復": 32479, + "寻": 32480, + "茶": 32481, + "ਾ": 32482, + "竹": 32483, + "遇": 32484, + "順": 32485, + "며": 32486, + "累": 32487, + "ĝ": 32488, + "ˇ": 32489, + "覧": 32490, + "এ": 32491, + "株": 32492, + "취": 32493, + "ስ": 32494, + "争": 32495, + "势": 32496, + "宇": 32497, + "橋": 32498, + "Ӏ": 32499, + "堆": 32500, + "ⵙ": 32501, + "丶": 32502, + "棋": 32503, + "肉": 32504, + "የ": 32505, + "": 32506, + "❶": 32507, + "季": 32508, + "ል": 32509, + "殿": 32510, + "優": 32511, + "試": 32512, + "첫": 32513, + "Ό": 32514, + "戶": 32515, + "ண": 32516, + "羅": 32517, + "桃": 32518, + "립": 32519, + "浪": 32520, + "脑": 32521, + "😛": 32522, + "弃": 32523, + "炮": 32524, + "轻": 32525, + "울": 32526, + "": 32527, + "ヘ": 32528, + "奥": 32529, + "💜": 32530, + "忘": 32531, + "遠": 32532, + "飛": 32533, + "魏": 32534, + "Ē": 32535, + "汇": 32536, + "央": 32537, + "逆": 32538, + "露": 32539, + "須": 32540, + "ѐ": 32541, + "ḷ": 32542, + "ದ": 32543, + "✭": 32544, + "寄": 32545, + "盟": 32546, + "财": 32547, + "際": 32548, + "ἔ": 32549, + "ǫ": 32550, + "थ": 32551, + "ാ": 32552, + "宫": 32553, + "巨": 32554, + "途": 32555, + "ʹ": 32556, + "ಗ": 32557, + "帐": 32558, + "‪": 32559, + "拒": 32560, + "药": 32561, + "🙃": 32562, + "ŕ": 32563, + "亡": 32564, + "壁": 32565, + "ም": 32566, + "參": 32567, + "😩": 32568, + "շ": 32569, + "ವ": 32570, + "ណ": 32571, + "丰": 32572, + "獲": 32573, + "莉": 32574, + "좋": 32575, + "ရ": 32576, + "₦": 32577, + "겠": 32578, + "👉": 32579, + "吴": 32580, + "岡": 32581, + "诉": 32582, + "읽": 32583, + "🥺": 32584, + "爆": 32585, + "🇸": 32586, + "ভ": 32587, + "迭": 32588, + "엔": 32589, + "ἄ": 32590, + "捷": 32591, + "納": 32592, + "邀": 32593, + "ಯ": 32594, + "爾": 32595, + "船": 32596, + "赞": 32597, + "胜": 32598, + "므": 32599, + "သ": 32600, + "構": 32601, + "磁": 32602, + "冰": 32603, + "딩": 32604, + "ે": 32605, + "媒": 32606, + "繁": 32607, + "☠": 32608, + "❒": 32609, + "仪": 32610, + "렬": 32611, + "昭": 32612, + "珠": 32613, + "離": 32614, + "ན": 32615, + "ల": 32616, + "ತ": 32617, + "拷": 32618, + "粉": 32619, + "벤": 32620, + "⇽": 32621, + "乌": 32622, + "拥": 32623, + "ҳ": 32624, + "ය": 32625, + "ེ": 32626, + "仙": 32627, + "塊": 32628, + "幅": 32629, + "🎉": 32630, + "Մ": 32631, + "跨": 32632, + "ٔ": 32633, + "恩": 32634, + "损": 32635, + "养": 32636, + "奈": 32637, + "ǀ": 32638, + "严": 32639, + "卫": 32640, + "迟": 32641, + "様": 32642, + "裡": 32643, + "난": 32644, + "았": 32645, + "͜": 32646, + "Ζ": 32647, + "ਰ": 32648, + "պ": 32649, + "ং": 32650, + "丢": 32651, + "伝": 32652, + "컨": 32653, + "ව": 32654, + "ြ": 32655, + "冷": 32656, + "遗": 32657, + "銀": 32658, + "̌": 32659, + "ᴜ": 32660, + "瑞": 32661, + "ฌ": 32662, + "❍": 32663, + "ふ": 32664, + "聚": 32665, + "碎": 32666, + "衛": 32667, + "অ": 32668, + "ញ": 32669, + "퍼": 32670, + "Ս": 32671, + "ນ": 32672, + "ẓ": 32673, + "✌": 32674, + "孝": 32675, + "陳": 32676, + "히": 32677, + "ක": 32678, + "黒": 32679, + "💖": 32680, + "ḩ": 32681, + "応": 32682, + "饰": 32683, + "∪": 32684, + "宜": 32685, + "樂": 32686, + "則": 32687, + "勇": 32688, + "徐": 32689, + "ⵓ": 32690, + "權": 32691, + "鲁": 32692, + "‟": 32693, + "庭": 32694, + "苗": 32695, + "🔴": 32696, + "闲": 32697, + "독": 32698, + "ɹ": 32699, + "ҽ": 32700, + "ថ": 32701, + "宏": 32702, + "尊": 32703, + "總": 32704, + "裝": 32705, + "ම": 32706, + "▸": 32707, + "測": 32708, + "ಮ": 32709, + "አ": 32710, + "轩": 32711, + "兄": 32712, + "剑": 32713, + "ન": 32714, + "朱": 32715, + "ǝ": 32716, + "Ḩ": 32717, + "担": 32718, + "灰": 32719, + "讲": 32720, + "롤": 32721, + "︎": 32722, + "😤": 32723, + "ោ": 32724, + "애": 32725, + "였": 32726, + "질": 32727, + "振": 32728, + "灯": 32729, + "ĉ": 32730, + "ස": 32731, + "閉": 32732, + "램": 32733, + "ಂ": 32734, + "げ": 32735, + "̧": 32736, + "狂": 32737, + "融": 32738, + "仍": 32739, + "實": 32740, + "楽": 32741, + "範": 32742, + "ٌ": 32743, + "వ": 32744, + "嵌": 32745, + "摩": 32746, + "袁": 32747, + "ষ": 32748, + "乎": 32749, + "규": 32750, + "岗": 32751, + "糊": 32752, + "క": 32753, + "雲": 32754, + "심": 32755, + "ई": 32756, + "འ": 32757, + "ἡ": 32758, + "丝": 32759, + "Ħ": 32760, + "ٍ": 32761, + "ٓ": 32762, + "အ": 32763, + "執": 32764, + "벨": 32765, + "ゼ": 32766, + "梦": 32767 + }, + "merges": [ + "▁ t", + "i n", + "e r", + "▁ a", + "h e", + "o n", + "r e", + "▁ s", + "e n", + "a t", + "o r", + "▁t he", + "▁th e", + "▁ the", + "e s", + "▁ w", + "a n", + "▁ c", + "i s", + "i t", + "o u", + "▁ d", + "a l", + "a r", + "▁ p", + "▁ f", + "e d", + "▁ b", + "in g", + "i ng", + "▁ o", + "▁ m", + "l e", + "n d", + "a s", + "i c", + "▁ h", + "io n", + "i on", + "▁i n", + "▁ in", + "▁t o", + "▁ to", + "e t", + "o m", + "e l", + "▁o f", + "▁ of", + "s t", + "▁a nd", + "▁an d", + "▁ and", + "▁ l", + "▁t h", + "▁ th", + "▁ n", + "en t", + "e nt", + "i l", + "c t", + "r o", + "▁r e", + "▁ re", + "i d", + "a m", + "▁ I", + "a d", + "▁ e", + "▁ S", + "▁ g", + "▁ T", + "i m", + "o t", + "a c", + "u r", + "▁ (", + "i g", + "▁ =", + "o l", + "u t", + "▁ A", + "s e", + "▁ u", + "v e", + "▁ C", + "i f", + "o w", + "▁ y", + "c h", + "a y", + "▁d e", + "▁ de", + "▁s t", + "▁ st", + "▁ |", + "ve r", + "v er", + ") ;", + "▁ \"", + "l y", + "▁b e", + "▁ be", + "* *", + "▁i s", + "▁ is", + "o d", + "▁ M", + "at ion", + "ati on", + "atio n", + "u l", + "▁f or", + "▁fo r", + "▁ for", + "▁o n", + "▁ on", + "a g", + "c e", + "te r", + "t er", + "i r", + "t h", + "▁ v", + "q u", + "▁ B", + "e m", + "▁ P", + "▁y ou", + "▁yo u", + "▁ you", + "▁t hat", + "▁th at", + "▁ that", + "u n", + "▁ {", + "it h", + "i th", + "r i", + "es t", + "e st", + "a b", + "- -", + "a p", + "▁i t", + "▁ it", + "▁c on", + "▁co n", + "▁ con", + "at e", + "a te", + "u s", + "▁ H", + "u m", + "▁ D", + "o s", + "p e", + "▁ -", + "▁w h", + "▁ wh", + "▁a l", + "▁ al", + "▁a s", + "▁ as", + "an d", + "a nd", + "is t", + "i st", + "▁ L", + "▁ W", + "▁w ith", + "▁ with", + "▁a n", + "▁ an", + "er e", + "e re", + "▁ *", + "▁ R", + "▁h e", + "▁ he", + "▁ F", + "o c", + "▁w as", + "▁wa s", + "▁ was", + "er s", + "e rs", + "k e", + "ou t", + "o ut", + "h t", + "▁ r", + "es s", + "e ss", + "o p", + "re s", + "r es", + "i e", + "▁ E", + "▁ \\", + "▁T he", + "▁Th e", + "▁ The", + "en d", + "e nd", + "l d", + "▁ N", + "or t", + "o rt", + "▁ G", + "/ /", + "▁ #", + "ou r", + "o ur", + "t e", + "il l", + "i ll", + "ai n", + "a in", + "▁s e", + "▁ se", + "▁ $", + "▁p ro", + "▁pr o", + "▁ pro", + "or e", + "o re", + "▁c om", + "▁co m", + "▁ com", + "am e", + "a me", + "t r", + "▁n e", + "▁ ne", + "ro m", + "r om", + "u b", + "▁a t", + "▁ at", + "▁e x", + "▁ ex", + "an t", + "a nt", + "u e", + "▁o r", + "▁ or", + "▁ }", + "ar t", + "a rt", + "ct ion", + "▁ k", + "p t", + "n t", + "i v", + "d e", + "▁ O", + "p l", + "ur n", + "u rn", + "ig ht", + "igh t", + "i ght", + "al l", + "a ll", + "▁t his", + "▁th is", + "▁ this", + "se r", + "s er", + "av e", + "a ve", + "▁n ot", + "▁no t", + "▁ not", + "▁a re", + "▁ar e", + "▁ are", + "▁ j", + "▁l e", + "▁ le", + "i z", + "▁ '", + "ag e", + "a ge", + "me nt", + "men t", + "m ent", + "▁t r", + "▁ tr", + "ac k", + "a ck", + "us t", + "u st", + "( )", + "- >", + "it y", + "i ty", + "in e", + "i ne", + "ou ld", + "oul d", + "o uld", + "▁ J", + "o g", + "▁f rom", + "▁fr om", + "▁fro m", + "▁ from", + "▁w e", + "▁ we", + "el l", + "e ll", + "▁s h", + "▁ sh", + "▁e n", + "▁ en", + "ur e", + "u re", + "por t", + "po rt", + "p ort", + "▁c h", + "▁ ch", + "n e", + "▁b y", + "▁ by", + "pe r", + "p er", + "ar d", + "a rd", + "as s", + "a ss", + "g e", + "a k", + "ar e", + "a re", + "o k", + "a v", + "iv e", + "i ve", + "f f", + "ie s", + "i es", + "at h", + "a th", + "tu rn", + "t urn", + "▁ U", + "in t", + "i nt", + "-- --", + "--- -", + "- ---", + "▁i m", + "▁ im", + "os t", + "o st", + "ia l", + "i al", + "▁h ave", + "▁ha ve", + "▁hav e", + "▁ have", + "in d", + "i nd", + "i p", + "an s", + "a ns", + "x t", + "▁d o", + "▁ do", + "c l", + "▁i f", + "▁ if", + "co n", + "c on", + "i a", + "▁h is", + "▁hi s", + "▁ his", + "ul t", + "u lt", + "ro u", + "r ou", + "▁s u", + "▁ su", + "r a", + "▁u n", + "▁ un", + "ab le", + "abl e", + "a ble", + "▁ <", + "▁ K", + "om e", + "o me", + "▁q u", + "▁ qu", + "ge t", + "g et", + "▁m e", + "▁ me", + "as t", + "a st", + "ec t", + "e ct", + "▁# #", + "▁ ##", + "t o", + "▁c l", + "▁ cl", + "▁a b", + "▁ ab", + "ic e", + "i ce", + "ir e", + "i re", + "be r", + "b er", + "on e", + "o ne", + "ic h", + "i ch", + "he n", + "h en", + "▁c an", + "▁ca n", + "▁ can", + "▁T h", + "▁ Th", + "▁l a", + "▁ la", + "▁a ll", + "▁al l", + "▁ all", + "im e", + "i me", + "il e", + "i le", + "id e", + "i de", + "\" ,", + "▁p l", + "▁ pl", + "▁ V", + "r u", + "or m", + "o rm", + "▁h ad", + "▁ha d", + "▁ had", + "u d", + "as e", + "a se", + "or d", + "o rd", + ") ,", + "▁h er", + "▁he r", + "▁ her", + "▁I n", + "▁ In", + "ac e", + "a ce", + "▁b ut", + "▁bu t", + "▁ but", + "at a", + "a ta", + ": :", + "** **", + "*** *", + "* ***", + "on g", + "o ng", + "▁ &", + ". .", + "it e", + "i te", + "yp e", + "y pe", + "ac t", + "a ct", + "od e", + "o de", + "▁y our", + "▁you r", + "▁yo ur", + "▁ your", + "▁o ut", + "▁ou t", + "▁ out", + "▁g o", + "▁ go", + "li c", + "l ic", + "al ly", + "all y", + "▁s o", + "▁ so", + "or k", + "a u", + "▁u p", + "▁ up", + "▁ _", + "l l", + "= =", + "▁m y", + "▁ my", + "p p", + "c c", + "▁/ /", + "▁ //", + "▁the y", + "▁th ey", + "▁ they", + "g h", + "▁u s", + "▁ us", + "i b", + "ion s", + "io ns", + "i ons", + "ac h", + "a ch", + "en s", + "e ns", + "▁a r", + "▁ ar", + "o b", + "el f", + "oo k", + "o ok", + "at ed", + "ate d", + "a ted", + "an g", + "a ng", + "ig n", + "i gn", + "▁re turn", + "▁r eturn", + "▁ret urn", + "▁ return", + "▁re s", + "▁r es", + "▁ res", + "c k", + "ou s", + "o us", + "с т", + ") .", + "▁ п", + ". \"", + "н а", + "▁ i", + "ai l", + "a il", + "e p", + "▁a d", + "▁ ad", + "an ce", + "anc e", + "( \"", + "▁* *", + "▁ **", + "th er", + "the r", + "t her", + "ak e", + "a ke", + "▁w ill", + "▁ will", + "▁c omp", + "▁com p", + "▁co mp", + "▁ comp", + "▁o ne", + "▁on e", + "▁ one", + "▁g et", + "▁ge t", + "▁ get", + "o v", + "▁ Y", + "ar y", + "a ry", + "oc k", + "o ck", + "▁s he", + "▁sh e", + "▁ she", + "ch e", + "c he", + "f t", + "▁n ew", + "▁ne w", + "▁ new", + "▁d es", + "▁de s", + "▁ des", + "▁l i", + "▁ li", + "en ce", + "enc e", + "▁s a", + "▁ sa", + "re ss", + "res s", + "r ess", + "▁e l", + "▁ el", + "▁u nd", + "▁un d", + "▁ und", + "e g", + "fe r", + "f er", + "r y", + "ea r", + "e ar", + "os e", + "o se", + "ve ry", + "ver y", + "v ery", + "' ,", + "▁ +", + "▁ в", + "▁H e", + "▁ He", + "ub lic", + "ubl ic", + "u blic", + "▁the ir", + "iz e", + "i ze", + "▁w ere", + "▁we re", + "▁wer e", + "▁ were", + "in k", + "ow n", + "o wn", + "I n", + "{ \\", + "▁h as", + "▁ha s", + "▁ has", + "▁p er", + "▁pe r", + "▁ per", + "▁I t", + "▁ It", + "▁S t", + "▁ St", + "he r", + "h er", + "je ct", + "j ect", + "р а", + "il d", + "i ld", + "s o", + "▁s p", + "▁ sp", + "н и", + "d u", + "ro w", + "r ow", + "al ue", + "alu e", + "se t", + "s et", + "fo rm", + "for m", + "f orm", + "co m", + "c om", + "▁m an", + "▁ma n", + "▁ man", + "on t", + "o nt", + "ul l", + "u ll", + "▁c ont", + "▁con t", + "▁co nt", + "▁ cont", + "▁m ore", + "▁mor e", + "▁mo re", + "▁ more", + "ic k", + "i ck", + "▁w ould", + "▁wo uld", + "▁e v", + "▁ ev", + "▁ab out", + "▁ about", + "it ion", + "iti on", + "▁ z", + "ou nd", + "oun d", + "o und", + "re e", + "r ee", + "▁C h", + "▁ Ch", + "▁wh ich", + "▁ which", + "i o", + "() ;", + "( );", + "▁w ho", + "▁wh o", + "▁ who", + "er r", + "e rr", + "or y", + "o ry", + "ou nt", + "oun t", + "o unt", + "at ions", + "ation s", + "ati ons", + "atio ns", + "▁ с", + "ri ng", + "rin g", + "r ing", + "< /", + "▁f e", + "▁ fe", + "к о", + "н о", + "▁d is", + "▁di s", + "▁ dis", + "m a", + "▁t hem", + "▁the m", + "▁th em", + "▁a ny", + "▁an y", + "▁ any", + "▁n o", + "▁ no", + "-- ------", + "---- ----", + "--- -----", + "----- ---", + "------ --", + "------- -", + "- -------", + "▁p re", + "▁pr e", + "▁ pre", + "▁t e", + "▁ te", + "▁r o", + "▁ ro", + "▁h im", + "▁hi m", + "▁ him", + "▁ :", + "u p", + "▁in t", + "▁i nt", + "▁ int", + "▁a g", + "▁ ag", + "S t", + "ar k", + "e x", + "p h", + "ie nt", + "ien t", + "i ent", + "el y", + "e ly", + "▁p r", + "▁ pr", + "E R", + "▁im port", + "▁imp ort", + "▁ import", + "▁t ime", + "▁tim e", + "▁ti me", + "▁ time", + "р о", + "pr o", + "p ro", + "Us er", + "Use r", + "U ser", + "l o", + "▁ /", + "▁ [", + "or s", + "o rs", + "= \"", + "▁t here", + "▁the re", + "▁th ere", + "▁ther e", + "▁ there", + "▁l ike", + "▁li ke", + "▁lik e", + "▁ like", + "ol d", + "o ld", + "▁w hen", + "▁wh en", + "▁whe n", + "▁ when", + "ve rs", + "ver s", + "v ers", + "▁s ome", + "▁so me", + "▁som e", + "▁ some", + "in gs", + "ing s", + ") )", + "▁p art", + "▁par t", + "▁pa rt", + "▁ part", + "ic al", + "ica l", + "i cal", + "▁f un", + "▁fu n", + "▁ fun", + "▁k n", + "▁ kn", + "ay s", + "a ys", + "ie r", + "i er", + "▁b een", + "▁be en", + "ov e", + "o ve", + "▁s c", + "▁ sc", + "ia n", + "i an", + "▁o ver", + "▁ov er", + "▁ over", + "ie l", + "i el", + "▁p e", + "▁ pe", + "ri b", + "r ib", + "pu t", + "p ut", + "e c", + "et h", + "e th", + "ar am", + "ara m", + "a ram", + "ap p", + "a pp", + "▁ –", + "▁s tat", + "▁st at", + "▁sta t", + "▁ stat", + "po n", + "p on", + "▁w hat", + "▁wh at", + "▁ what", + "pt ion", + "w e", + "ad e", + "a de", + "▁w ork", + "▁wor k", + "▁ work", + "te xt", + "tex t", + "t ext", + "▁s aid", + "▁sa id", + "▁# ##", + "▁## #", + "▁ ###", + "I N", + "▁j ust", + "▁ju st", + "▁ just", + "ir st", + "irs t", + "▁in to", + "▁int o", + "▁ into", + "▁con st", + "▁cons t", + "▁ const", + "our ce", + "t t", + "p s", + "p r", + "er v", + "e rv", + "it t", + "i tt", + "u g", + "_ {", + "en ts", + "ent s", + "is h", + "i sh", + "en er", + "ene r", + "e ner", + "▁in ter", + "▁int er", + "▁inte r", + "▁ inter", + "pl e", + "p le", + "ol l", + "o ll", + "me r", + "m er", + "at er", + "ate r", + "a ter", + "oo l", + "o ol", + "e f", + "▁p ublic", + "▁pub lic", + "▁pu blic", + "▁publi c", + "▁ public", + "▁o ther", + "▁ot her", + "▁ other", + "р е", + "▁d ef", + "▁de f", + "▁ def", + "▁ @", + "г о", + "oin t", + "oi nt", + "o int", + "▁o ff", + "▁of f", + "▁ off", + "oi d", + "o id", + "re turn", + "ret urn", + "r eturn", + "▁s et", + "▁se t", + "▁ set", + "w o", + "ft er", + "fte r", + "f ter", + "s h", + "** ******", + "**** ****", + "****** **", + "▁o ur", + "▁ou r", + "▁ our", + "ri v", + "r iv", + "is s", + "i ss", + "▁W e", + "▁ We", + "n g", + "▁o b", + "▁ ob", + "s s", + "g r", + "▁t han", + "▁th an", + "▁ than", + "pe ct", + "pec t", + "p ect", + "ie d", + "i ed", + "s c", + "ie w", + "i ew", + "de r", + "d er", + "ys t", + "y st", + "e v", + "▁c ould", + "▁co uld", + "▁cou ld", + "▁ could", + "an n", + "a nn", + "en c", + "e nc", + "O N", + "i x", + "an c", + "a nc", + "▁al so", + "▁als o", + "▁ also", + "re at", + "rea t", + "▁a m", + "▁ am", + "▁b ec", + "▁be c", + "▁ bec", + "▁ и", + "ua l", + "u al", + "pe c", + "p ec", + "▁ .", + "▁b l", + "▁ bl", + "le ct", + "l ect", + "op le", + "opl e", + "o ple", + "y s", + "▁g r", + "▁ gr", + "ic t", + "i ct", + "i k", + "tr ing", + "tri ng", + "t ring", + "▁T his", + "▁Th is", + "▁ This", + "▁b ack", + "▁ba ck", + "▁ back", + "▁ о", + "▁f in", + "▁fi n", + "▁ fin", + "at ch", + "Co n", + "C on", + "( '", + "er m", + "e rm", + "▁= =", + "▁ ==", + "_ _", + "na me", + "nam e", + "n ame", + ", \"", + "▁d id", + "▁di d", + "▁ did", + "is e", + "i se", + "▁on ly", + "▁ only", + "ru ct", + "r uct", + "le s", + "l es", + "▁t hen", + "▁the n", + "▁th en", + "▁ then", + "au se", + "aus e", + "a use", + "в а", + "▁it s", + "▁i ts", + "▁ its", + "ri t", + "r it", + "▁k now", + "▁kn ow", + "▁ know", + "ie ld", + "iel d", + "i eld", + "▁c lass", + "▁cl ass", + "▁clas s", + "▁ class", + "▁ >", + "▁e m", + "▁ em", + "▁$ \\", + "▁ $\\", + "▁y ear", + "▁ye ar", + "▁ year", + "w n", + "} ,", + "▁d el", + "▁de l", + "▁ del", + "al e", + "a le", + "t y", + "fi g", + "f ig", + "s p", + "he d", + "h ed", + "ro und", + "rou nd", + "r ound", + "e w", + "▁d i", + "▁ di", + "▁d er", + "▁de r", + "▁ der", + "р и", + "re d", + "r ed", + "th is", + "t his", + "le t", + "l et", + "R E", + "a x", + "f r", + "ess age", + "essa ge", + "ou gh", + "o ugh", + "▁c omm", + "▁com m", + "▁co mm", + "▁ comm", + "f o", + "uc h", + "u ch", + "o y", + "▁pe ople", + "▁ people", + "yst em", + "ys tem", + "▁f irst", + "▁fir st", + "▁ first", + "▁f unction", + "▁fun ction", + "▁ function", + "an ge", + "ang e", + "▁h ow", + "▁ho w", + "▁ how", + "▁e t", + "▁ et", + "a h", + "▁l ook", + "▁lo ok", + "▁ look", + "т о", + "un d", + "u nd", + "▁u nder", + "▁un der", + "▁und er", + "▁ under", + "к а", + "▁ !", + "ra y", + "r ay", + "S T", + "if ic", + "ifi c", + "i fic", + "л и", + "re ad", + "rea d", + "r ead", + "▁b et", + "▁be t", + "▁ bet", + "io us", + "i ous", + "ar g", + "a rg", + "▁n eed", + "▁ne ed", + "▁ need", + "ma th", + "mat h", + "m ath", + "▁н а", + "▁ на", + "er t", + "e rt", + "▁o p", + "▁ op", + "▁a cc", + "▁ac c", + "▁ acc", + "Pr o", + "P ro", + "▁e st", + "▁es t", + "▁ est", + "▁U n", + "▁ Un", + "▁e nt", + "▁en t", + "▁ ent", + "▁re c", + "▁r ec", + "▁ rec", + "▁u se", + "▁us e", + "▁ use", + "е н", + "▁p ar", + "▁pa r", + "▁ par", + "a z", + "▁ д", + "▁W h", + "▁ Wh", + "sel f", + "s elf", + "▁k e", + "▁ ke", + "т а", + "▁w ant", + "▁wa nt", + "▁ want", + "▁e nd", + "▁en d", + "▁ end", + "▁d on", + "▁do n", + "▁ don", + "e k", + "re n", + "r en", + "Na me", + "N ame", + "▁= >", + "▁ =>", + "▁a pp", + "▁ap p", + "▁ app", + "▁qu e", + "▁q ue", + "▁ que", + "ig h", + "i gh", + "▁b u", + "▁ bu", + "eq u", + "e qu", + "ve l", + "v el", + "▁a ct", + "▁ac t", + "▁ act", + "cr e", + "c re", + "A T", + "▁v ar", + "▁va r", + "▁ var", + "ce ss", + "ces s", + "c ess", + "== ==", + "=== =", + "= ===", + "E x", + "▁a dd", + "▁ad d", + "▁ add", + "▁m od", + "▁mo d", + "▁ mod", + "un g", + "u ng", + "▁w here", + "▁wh ere", + "▁whe re", + "▁ where", + "ni ng", + "n ing", + "▁f l", + "▁ fl", + "al s", + "a ls", + "ter n", + "te rn", + "t ern", + "} }", + "▁A l", + "▁ Al", + "▁p os", + "▁po s", + "▁ pos", + "an k", + "▁a p", + "▁ ap", + "en g", + "e ng", + "▁ “", + "bl e", + "b le", + "▁re g", + "▁r eg", + "▁ reg", + "^ {", + "▁S he", + "▁Sh e", + "▁ She", + "▁* /", + "▁ */", + "ud e", + "u de", + "ad d", + "a dd", + "▁t wo", + "▁tw o", + "▁ two", + "▁c ol", + "▁co l", + "▁ col", + "▁s m", + "▁ sm", + "ai r", + "a ir", + "▁m ay", + "▁ma y", + "▁ may", + "fo re", + "for e", + "f ore", + "▁Y ou", + "▁ You", + "ro ugh", + "rou gh", + "r ough", + "▁c he", + "▁ch e", + "▁ che", + "▁a tt", + "▁at t", + "▁ att", + "ot h", + "o th", + "л а", + "▁c o", + "▁ co", + "at es", + "ate s", + "a tes", + "▁re m", + "▁r em", + "▁ rem", + "oo d", + "o od", + "Ty pe", + "Typ e", + "T ype", + "le d", + "l ed", + "fu l", + "f ul", + "▁s elf", + "▁sel f", + "▁ self", + "o f", + "▁A r", + "▁ Ar", + "qu e", + "q ue", + "▁e very", + "▁ev ery", + "▁ever y", + "▁ every", + "re f", + "r ef", + "Th e", + "T he", + "▁A nd", + "▁An d", + "▁ And", + "▁re l", + "▁r el", + "▁ rel", + "O R", + "I d", + "▁e ven", + "▁ev en", + "▁ even", + "E N", + "▁h and", + "▁ha nd", + "▁han d", + "▁ hand", + "ai t", + "a it", + "▁sh ould", + "▁ should", + "▁a fter", + "▁af ter", + "▁ after", + "▁d if", + "▁di f", + "gh t", + "g ht", + "if e", + "i fe", + "at or", + "ato r", + "a tor", + "as h", + "a sh", + "ri but", + "rib ut", + "ribu t", + "um ber", + "umb er", + "u mber", + "▁s ee", + "▁se e", + "▁ see", + "m s", + "▁c all", + "▁cal l", + "▁ca ll", + "▁ call", + "y n", + "d d", + "▁e s", + "▁ es", + "▁m ake", + "▁ma ke", + "▁ make", + "ot her", + "oth er", + "othe r", + "o ther", + "▁ —", + "\") ;", + "\" );", + "st r", + "s tr", + "▁l ong", + "▁lo ng", + "▁lon g", + "▁ long", + "le ment", + "lem ent", + "l ement", + "▁w or", + "▁wo r", + "▁ wor", + "it s", + "i ts", + "▁I f", + "▁ If", + "al se", + "als e", + "л ь", + "wa rd", + "war d", + "w ard", + "▁п о", + "▁ по", + "va l", + "v al", + "on s", + "o ns", + "▁ Z", + "▁n ow", + "▁no w", + "▁ now", + "da ta", + "dat a", + "d ata", + "am p", + "a mp", + "en se", + "ens e", + "▁th rough", + "▁thr ough", + "▁thro ugh", + "▁ through", + "▁d own", + "▁do wn", + "▁dow n", + "▁ down", + "at t", + "a tt", + "▁st atic", + "▁stat ic", + "▁ static", + "ic s", + "i cs", + "# #", + "po s", + "p os", + "▁v oid", + "▁vo id", + "▁ void", + "a w", + "ou n", + "o un", + "▁w ay", + "▁wa y", + "▁ way", + "ib le", + "i ble", + "ve nt", + "ven t", + "v ent", + "ow er", + "owe r", + "o wer", + "▁th ink", + "▁thin k", + "▁ think", + "t s", + "* /", + "▁a gain", + "▁ag ain", + "▁ again", + "at ing", + "ati ng", + "atin g", + "a ting", + "т е", + "ne r", + "n er", + "▁m ost", + "▁mo st", + "▁mos t", + "▁ most", + "li ne", + "lin e", + "l ine", + "y m", + "▁s ub", + "▁su b", + "▁ sub", + "er son", + "ers on", + "▁re qu", + "▁r equ", + "▁req u", + "▁ requ", + "A L", + "A R", + "ab el", + "abe l", + "a bel", + "on d", + "o nd", + ")) ;", + ") );", + "▁S e", + "▁ Se", + "▁B ut", + "▁Bu t", + "▁ But", + "al k", + "▁A n", + "▁ An", + "ne w", + "n ew", + "▁b ecause", + "▁bec ause", + "▁ because", + "ge r", + "g er", + "ul ar", + "ula r", + "u lar", + "ro up", + "rou p", + "r oup", + "t a", + ".. .", + ". ..", + "▁c ons", + "▁con s", + "▁co ns", + "▁ cons", + "▁r ight", + "▁ri ght", + "▁rig ht", + "▁ right", + "▁f r", + "▁ fr", + "b e", + "il y", + "i ly", + "к и", + "▁p h", + "▁ ph", + "ea d", + "e ad", + "? \"", + "▁g u", + "▁ gu", + "▁el se", + "▁els e", + "▁ else", + "▁s om", + "▁so m", + "▁ som", + "re nt", + "ren t", + "r ent", + "c o", + "em ent", + "eme nt", + "emen t", + "e ment", + "▁s tr", + "▁st r", + "▁ str", + "au lt", + "aul t", + "a ult", + "▁ з", + "л о", + "se rt", + "ser t", + "s ert", + "va r", + "v ar", + "ty pe", + "typ e", + "t ype", + "▁C om", + "▁Co m", + "▁ Com", + "л е", + "in s", + "i ns", + "m e", + "wa y", + "w ay", + "id ent", + "ide nt", + "iden t", + "▁p rov", + "▁pro v", + "▁pr ov", + "▁ prov", + "▁ м", + "▁tr ue", + "▁ true", + "▁P ro", + "▁Pr o", + "▁ Pro", + "f l", + "▁s l", + "▁ sl", + "▁A s", + "▁ As", + "} \\", + "I D", + "ue s", + "u es", + "▁in st", + "▁ins t", + "▁ inst", + "▁n ame", + "▁na me", + "▁nam e", + "▁ name", + "o x", + "▁ )", + "l i", + "am es", + "ame s", + "a mes", + "Re s", + "R es", + "▁s ur", + "▁su r", + "▁ sur", + "par am", + "pa ram", + "para m", + "p aram", + "▁st art", + "▁star t", + "▁sta rt", + "▁ start", + "a j", + "S E", + "as k", + "a sk", + "I T", + "St ring", + "Str ing", + "S tring", + "▁a ss", + "▁as s", + "▁ ass", + "▁p lay", + "▁pl ay", + "▁ play", + "ti ng", + "t ing", + "to n", + "t on", + "▁b efore", + "▁be fore", + "▁bef ore", + "▁ before", + "▁p ol", + "▁po l", + "▁ pol", + "ar ch", + "arc h", + "▁w ell", + "▁we ll", + "▁wel l", + "▁ well", + "Co m", + "C om", + "an y", + "a ny", + "ol og", + "olo g", + "o log", + "▁e rr", + "▁er r", + "▁ err", + "▁the se", + "▁th ese", + "ar s", + "a rs", + "e b", + "▁b r", + "▁ br", + "▁in cl", + "▁inc l", + "▁ incl", + "▁h el", + "▁he l", + "▁ hel", + "er n", + "e rn", + "od y", + "o dy", + "в о", + "▁in d", + "▁i nd", + "▁ ind", + "-- --------------", + "---- ------------", + "-------- --------", + "--- -------------", + "------------ ----", + "----- -----------", + "---------- ------", + "------ ----------", + "------------- ---", + "-------------- --", + "--------- -------", + "------- ---------", + "----------- -----", + "▁d ata", + "▁da ta", + "▁dat a", + "▁ data", + "▁g ood", + "▁go od", + "▁ good", + "L E", + "] ,", + "▁a v", + "▁ av", + "▁a c", + "▁ ac", + "id er", + "ide r", + "i der", + "н е", + "▁ Q", + "▁m in", + "▁mi n", + "▁ min", + "▁m uch", + "▁mu ch", + "c i", + "el s", + "e ls", + "▁c ur", + "▁cu r", + "▁ cur", + "▁v alue", + "▁val ue", + "▁ value", + "er y", + "e ry", + "u f", + "▁l oc", + "▁lo c", + "▁ loc", + "re ak", + "rea k", + "at ive", + "ati ve", + "ativ e", + "im es", + "ime s", + "i mes", + "C l", + "▁ ,", + "▁s er", + "▁se r", + "▁ ser", + "▁d ie", + "▁di e", + "▁ die", + "▁tr ans", + "▁tra ns", + "▁ trans", + "▁res ult", + "▁ result", + "ex t", + "e xt", + "▁a ut", + "▁au t", + "▁ aut", + "la nd", + "lan d", + "l and", + "▁& &", + "▁ &&", + "C h", + "te n", + "t en", + "} $", + "▁t ype", + "▁typ e", + "▁ty pe", + "▁ type", + "con d", + "co nd", + "c ond", + "ic es", + "ice s", + "i ces", + "▁v ery", + "▁ver y", + "▁ve ry", + "▁ very", + "▁o wn", + "▁ own", + "▁f il", + "▁fi l", + "▁ fil", + "it ies", + "iti es", + "i ties", + "▁p rodu", + "▁pro du", + "▁prod u", + "▁ produ", + "▁re ad", + "▁r ead", + "▁ read", + "▁f orm", + "▁for m", + "▁fo rm", + "▁ form", + "▁c ase", + "▁cas e", + "▁ca se", + "▁ case", + "at her", + "ath er", + "a ther", + "т и", + "д а", + "е р", + "T h", + "au t", + "a ut", + "▁s pec", + "▁sp ec", + "▁spe c", + "▁ spec", + "i j", + "b l", + "il ity", + "ili ty", + "▁ é", + "▁e r", + "▁ er", + "▁d oes", + "▁do es", + "▁ does", + "▁h ere", + "▁he re", + "▁her e", + "▁ here", + "th e", + "t he", + "ur es", + "ure s", + "u res", + "▁ %", + "mi n", + "m in", + "▁n ull", + "▁nu ll", + "▁ null", + "ra p", + "r ap", + "\" )", + "r r", + "Li st", + "L ist", + "ri ght", + "rig ht", + "r ight", + "▁U ser", + "▁Us er", + "▁Use r", + "▁ User", + "U L", + "at ional", + "ation al", + "ati onal", + "atio nal", + "▁b eing", + "▁be ing", + "▁bei ng", + "▁ being", + "A N", + "s k", + "▁c ar", + "▁ca r", + "▁ car", + "ol e", + "o le", + "▁d ist", + "▁dis t", + "▁di st", + "▁ dist", + "pl ic", + "p lic", + "ol low", + "oll ow", + "▁p res", + "▁pre s", + "▁pr es", + "▁ pres", + "▁s uch", + "▁su ch", + "▁suc h", + "▁ such", + "re am", + "rea m", + "in ce", + "inc e", + "ga n", + "g an", + "▁F or", + "▁Fo r", + "▁ For", + "\" :", + "so n", + "s on", + "riv ate", + "▁y ears", + "▁year s", + "▁ye ars", + "▁s erv", + "▁se rv", + "▁ser v", + "▁ serv", + "▁m ade", + "▁ma de", + "▁mad e", + "▁ made", + "de f", + "d ef", + "; \r", + "▁g l", + "▁ gl", + "▁b el", + "▁be l", + "▁ bel", + "▁l ist", + "▁li st", + "▁ list", + "▁c or", + "▁co r", + "▁ cor", + "▁d et", + "▁de t", + "▁ det", + "ce ption", + "cept ion", + "eg in", + "e gin", + "▁ б", + "▁c har", + "▁ch ar", + "▁cha r", + "▁ char", + "tr ans", + "tra ns", + "▁f am", + "▁fa m", + "▁! =", + "▁ !=", + "ou se", + "ous e", + "o use", + "▁d ec", + "▁de c", + "▁ dec", + "ic a", + "i ca", + "▁m any", + "▁man y", + "▁ma ny", + "▁ many", + "ak ing", + "aki ng", + "a king", + "▁ à", + "▁s im", + "▁si m", + "▁ sim", + "ag es", + "age s", + "a ges", + "uf f", + "u ff", + "as ed", + "ase d", + "a sed", + "ma n", + "m an", + "▁S h", + "▁ Sh", + "ie t", + "i et", + "ir ect", + "ire ct", + "i rect", + "▁R e", + "▁ Re", + "▁d iffer", + "▁dif fer", + "▁diff er", + "▁f ind", + "▁fin d", + "▁fi nd", + "▁ find", + "eth od", + "▁ \r", + "in es", + "ine s", + "i nes", + "▁in v", + "▁i nv", + "▁ inv", + "▁p oint", + "▁po int", + "▁poi nt", + "▁ point", + "▁The y", + "▁Th ey", + "▁ They", + "▁u sed", + "▁us ed", + "▁use d", + "▁ used", + "ct ions", + "ction s", + "▁st ill", + "i ó", + "in ed", + "ine d", + "i ned", + "▁wh ile", + "▁ while", + "I t", + "em ber", + "emb er", + "e mber", + "▁s ay", + "▁sa y", + "▁ say", + "▁he lp", + "▁hel p", + "▁ help", + "▁c re", + "▁cr e", + "▁ cre", + "▁ x", + "▁T r", + "▁ Tr", + "um ent", + "ume nt", + "umen t", + "u ment", + "▁s k", + "▁ sk", + "ou ght", + "ough t", + "ual ly", + "u ally", + "m essage", + "▁C on", + "▁Co n", + "▁ Con", + "▁m on", + "▁mo n", + "▁ mon", + "ar ed", + "are d", + "a red", + "wor k", + "w ork", + ") :", + "is ter", + "ist er", + "iste r", + "i ster", + "ar n", + "a rn", + "iz ed", + "ize d", + "i zed", + "Dat a", + "Da ta", + "D ata", + "or n", + "o rn", + "▁h ead", + "▁he ad", + "▁ head", + "D E", + "▁L e", + "▁ Le", + "▁p erson", + "▁per son", + "▁pers on", + "▁ person", + "ment s", + "men ts", + "m ents", + "eng th", + "e ngth", + "▁f alse", + "▁fal se", + "▁fals e", + "▁ false", + "▁m ed", + "▁me d", + "▁ med", + "▁D e", + "▁ De", + "ac he", + "ach e", + "a che", + "it ed", + "ite d", + "i ted", + "▁l et", + "▁le t", + "▁ let", + "▁s how", + "▁sh ow", + "▁ show", + "▁s ame", + "▁sa me", + "▁sam e", + "▁ same", + "us s", + "u ss", + "▁g ener", + "▁gen er", + "▁ge ner", + "▁gene r", + "▁ gener", + "▁ у", + "cu r", + "c ur", + "▁re al", + "▁ real", + "ce d", + "c ed", + "\" >", + "st ruct", + "str uct", + "stru ct", + "be gin", + "b egin", + "ce pt", + "cep t", + "▁b o", + "▁ bo", + "ir ed", + "ire d", + "i red", + "▁F r", + "▁ Fr", + "▁st ud", + "▁ stud", + "de v", + "d ev", + "A r", + "( \\", + "▁C l", + "▁ Cl", + "we en", + "w een", + "▁t oo", + "▁to o", + "▁ too", + "▁t est", + "▁te st", + "▁ test", + "▁d ay", + "▁da y", + "▁ day", + "o h", + "▁f ollow", + "▁fol low", + "▁ follow", + "at ure", + "atur e", + "atu re", + "z e", + "ie n", + "i en", + "re g", + "r eg", + "ce s", + "c es", + "ur ing", + "uri ng", + "u ring", + "am b", + "a mb", + "in a", + "i na", + "cr i", + "c ri", + "▁e d", + "▁ ed", + "S S", + "uc k", + "u ck", + "▁/ *", + "▁ /*", + "C T", + "▁T here", + "▁The re", + "▁Th ere", + "▁Ther e", + "▁ There", + "▁t ake", + "▁tak e", + "▁ta ke", + "▁ take", + "pa r", + "p ar", + "ul e", + "u le", + "ca l", + "c al", + "fo r", + "f or", + "** **************", + "**** ************", + "******** ********", + "************ ****", + "************** **", + "s ource", + "▁th ose", + "co l", + "c ol", + "▁e ff", + "▁ eff", + "mo d", + "m od", + "con t", + "co nt", + "c ont", + "} {", + "▁a round", + "▁ar ound", + "▁ around", + "pr ess", + "pre ss", + "pres s", + "p ress", + "b y", + "▁go ing", + "▁ going", + "pon se", + "pons e", + "▁ С", + "▁l ine", + "▁li ne", + "▁lin e", + "▁ line", + "da te", + "dat e", + "d ate", + "co de", + "cod e", + "c ode", + "[ '", + "▁l ife", + "▁li fe", + "▁lif e", + "▁ life", + "as on", + "a son", + "▁u sing", + "▁us ing", + "▁ using", + "▁v al", + "▁va l", + "▁ val", + "▁d u", + "▁ du", + "y p", + "▁O n", + "▁ On", + "▁f ound", + "▁fo und", + "▁fou nd", + "▁ found", + "ol ut", + "olu t", + "' ]", + "ar ent", + "are nt", + "aren t", + "a rent", + "▁s tring", + "▁st ring", + "▁str ing", + "▁stri ng", + "▁ string", + "▁m et", + "▁me t", + "▁ met", + "▁w r", + "▁ wr", + "us h", + "u sh", + "st ring", + "str ing", + "stri ng", + "s tring", + "si ze", + "s ize", + "▁v er", + "▁ve r", + "▁ ver", + "▁e ach", + "▁ each", + "val ue", + "v alue", + "▁l ast", + "▁la st", + "▁las t", + "▁ last", + "▁g ot", + "▁go t", + "▁ got", + "ve n", + "v en", + "ba ck", + "b ack", + "Se t", + "S et", + "e y", + "ro l", + "r ol", + "▁c r", + "▁ cr", + "th ing", + "t hing", + "re t", + "r et", + "é s", + "is m", + "i sm", + "▁bet ween", + "▁ between", + "O b", + "et hing", + "eth ing", + "e thing", + "m p", + "▁l o", + "▁ lo", + "at s", + "a ts", + "▁N ew", + "▁Ne w", + "▁ New", + "в и", + "ad o", + "a do", + "de x", + "d ex", + "д и", + "▁p ass", + "▁pas s", + "▁pa ss", + "▁ pass", + "w h", + "▁d en", + "▁de n", + "▁ den", + "Ge t", + "G et", + "ap t", + "a pt", + "▁a sk", + "▁as k", + "▁ ask", + "▁s up", + "▁su p", + "▁ sup", + "Val ue", + "V alue", + "н ы", + "▁t ry", + "▁tr y", + "▁ try", + "lat ion", + "l ation", + "da y", + "d ay", + "ne ss", + "nes s", + "n ess", + "et s", + "e ts", + "▁ex per", + "▁exp er", + "▁ exper", + "T r", + "▁M ar", + "▁Ma r", + "▁ Mar", + "se rv", + "ser v", + "s erv", + "b r", + "▁n umber", + "▁num ber", + "▁nu mber", + "▁ number", + "in al", + "ina l", + "i nal", + "ce nt", + "cen t", + "c ent", + "/ *", + "no t", + "n ot", + "ion al", + "io nal", + "iona l", + "i onal", + "▁f inal", + "▁fin al", + "▁fi nal", + "▁ final", + "' )", + "▁r un", + "▁ru n", + "▁ run", + "ov er", + "ove r", + "o ver", + "▁n ever", + "▁ne ver", + "▁ never", + "u c", + "▁h igh", + "▁hig h", + "▁hi gh", + "▁ high", + "yl e", + "y le", + "▁in s", + "▁i ns", + "▁ ins", + "▁b est", + "▁be st", + "▁bes t", + "▁ best", + "it tle", + "itt le", + "ri c", + "r ic", + "▁s ign", + "▁si gn", + "▁sig n", + "▁ sign", + "▁d em", + "▁de m", + "▁ dem", + "in ess", + "ine ss", + "ines s", + "i ness", + "g y", + "▁w ar", + "▁wa r", + "▁ war", + "is hed", + "ish ed", + "▁g iv", + "▁gi v", + "ke y", + "k ey", + "▁ X", + "( $", + "▁ch ild", + "▁chi ld", + "▁ child", + "le ss", + "les s", + "l ess", + "way s", + "wa ys", + "w ays", + "in cl", + "inc l", + "ro p", + "r op", + "ra w", + "r aw", + ": //", + "▁ «", + "n o", + "ind ow", + "indo w", + "f e", + "ri end", + "rie nd", + "rien d", + "▁l es", + "▁le s", + "▁ les", + "▁l os", + "▁lo s", + "▁ los", + "fil e", + "fi le", + "f ile", + "form ation", + "format ion", + "cc ess", + "c cess", + "▁ В", + "n a", + "▁i l", + "▁ il", + "is ion", + "isi on", + "le r", + "l er", + "▁a rt", + "▁ar t", + "▁ art", + "Con t", + "Co nt", + "C ont", + "▁w orld", + "▁wor ld", + "▁ world", + "▁t urn", + "▁tu rn", + "▁tur n", + "▁ turn", + "▁re ally", + "▁real ly", + "▁E x", + "▁ Ex", + "м а", + "▁ П", + "ter s", + "te rs", + "t ers", + "ar get", + "arg et", + "arge t", + "Er r", + "E rr", + "▁h app", + "▁ha pp", + "ti me", + "tim e", + "t ime", + "▁S o", + "▁ So", + "di v", + "d iv", + "▁did n", + "▁di dn", + "ad a", + "a da", + "oo t", + "o ot", + "} )", + "▁s ch", + "▁sc h", + "▁ sch", + "▁c le", + "▁cl e", + "▁ cle", + "▁some thing", + "▁som ething", + "▁somet hing", + "▁ something", + "() .", + "( ).", + "▁c our", + "▁co ur", + "▁cou r", + "ev er", + "eve r", + "e ver", + "an ts", + "ant s", + "▁ ?", + "T o", + "▁ `", + "tr y", + "t ry", + "u x", + "ai s", + "a is", + "ro ss", + "ros s", + "r oss", + "hi p", + "h ip", + "▁re p", + "▁r ep", + "▁ rep", + "la bel", + "lab el", + "l abel", + "▁b oth", + "▁bo th", + "▁bot h", + "▁ both", + "* ,", + "ot t", + "o tt", + "м и", + "an e", + "a ne", + "▁o pen", + "▁op en", + "▁ open", + "w w", + "▁c ome", + "▁com e", + "▁co me", + "▁ come", + "▁e xt", + "▁ex t", + "▁ ext", + "re m", + "r em", + "_{ \\", + "_ {\\", + "▁o ld", + "▁ol d", + "▁ old", + "ch ed", + "che d", + "c hed", + ". _", + "M E", + "if y", + "i fy", + "g g", + "Co l", + "C ol", + "vi ew", + "v iew", + "▁b us", + "▁bu s", + "▁ bus", + "▁m ust", + "▁mus t", + "▁mu st", + "▁ must", + "▁d ifferent", + "▁differ ent", + "lo g", + "l og", + "is ts", + "ist s", + "i sts", + "ro ll", + "rol l", + "r oll", + "a i", + "▁з а", + "▁ за", + "▁s ystem", + "▁sys tem", + "▁syst em", + "▁ system", + "iv ers", + "ive rs", + "iver s", + "i vers", + "at us", + "atu s", + "ot e", + "o te", + "me d", + "m ed", + "] .", + "ak es", + "ake s", + "a kes", + "R O", + "▁c ent", + "▁ce nt", + "▁ cent", + "gr am", + "gra m", + "g ram", + "▁p rivate", + "▁priv ate", + "▁ private", + "▁g reat", + "▁gre at", + "\" ;", + "op y", + "o py", + "▁fe el", + "▁fee l", + "▁H ow", + "▁Ho w", + "▁ How", + "// //", + "/// /", + "/ ///", + "I C", + "▁d r", + "▁ dr", + "ain s", + "ai ns", + "a ins", + "lo ck", + "loc k", + "l ock", + "E n", + "▁S ch", + "▁Sc h", + "▁ Sch", + "▁m at", + "▁ma t", + "▁ mat", + "▁h ome", + "▁hom e", + "▁ho me", + "▁ home", + "per ty", + "pert y", + "te st", + "tes t", + "t est", + "lo c", + "l oc", + "▁w om", + "▁wo m", + "s w", + "ar ly", + "arl y", + "▁E n", + "▁ En", + "▁к о", + "▁ ко", + "de n", + "d en", + "ст а", + "с та", + "▁ а", + "et er", + "ete r", + "e ter", + "▁incl ud", + "▁inclu d", + "UL L", + "U LL", + "▁m em", + "▁me m", + "▁ mem", + "▁p o", + "▁ po", + "▁l ittle", + "▁lit tle", + "▁litt le", + "▁a rg", + "▁ar g", + "▁ arg", + "▁} ,", + "▁ },", + "in clude", + "incl ude", + "et a", + "e ta", + "▁p lace", + "▁pl ace", + "▁plac e", + "▁ place", + "id th", + "us tom", + "ust om", + "▁| |", + "▁ ||", + "▁t em", + "▁te m", + "▁ tem", + "ri ed", + "rie d", + "r ied", + "▁f act", + "▁fac t", + "▁fa ct", + "▁ fact", + "ien ce", + "i ence", + "▁P l", + "▁ Pl", + "op t", + "o pt", + "el e", + "e le", + "g o", + "A C", + "in ter", + "int er", + "inte r", + "==== ====", + "() ,", + "( ),", + "ot s", + "o ts", + "ra l", + "r al", + "iqu e", + "iq ue", + "i que", + "av ing", + "avi ng", + "a ving", + "m l", + "▁th ought", + "▁though t", + "▁thou ght", + "fr ac", + "f rac", + "▁c are", + "▁car e", + "▁ca re", + "▁ care", + "() );", + "()) ;", + "( ));", + "▁p ut", + "▁pu t", + "▁ put", + "▁m ight", + "▁mi ght", + "▁mig ht", + "▁A mer", + "▁Am er", + "▁ Amer", + "▁( !", + "▁ (!", + "am ple", + "amp le", + "al th", + "alt h", + "▁f ew", + "▁fe w", + "▁st ate", + "▁stat e", + "▁sta te", + "▁ state", + "su b", + "s ub", + "▁O r", + "▁ Or", + "] ;", + "▁s ize", + "▁si ze", + "▁ size", + "▁S p", + "▁ Sp", + "▁with out", + "▁ without", + "▁p oss", + "▁pos s", + "▁po ss", + "▁ poss", + "e q", + "pl ay", + "p lay", + "▁ex pect", + "▁exp ect", + "▁ expect", + "▁se cond", + "▁sec ond", + "▁ second", + "▁S tring", + "▁St ring", + "▁Str ing", + "▁ String", + "ui ld", + "u ild", + "▁n ext", + "▁ne xt", + "▁ next", + "+ +", + "re qu", + "req u", + "r equ", + "▁A ll", + "▁Al l", + "▁ All", + "▁m en", + "▁me n", + "▁ men", + "▁W hen", + "▁Wh en", + "▁Whe n", + "▁ When", + "it er", + "ite r", + "i ter", + "am ent", + "ame nt", + "amen t", + "a ment", + "ne t", + "n et", + "▁ К", + "ro n", + "r on", + "ain t", + "ai nt", + "a int", + "▁I s", + "▁ Is", + "в е", + "pe nd", + "pen d", + "p end", + "trans lation", + "transl ation", + "▁г о", + "▁ го", + "ч е", + "▁v an", + "▁va n", + "▁ van", + "▁an other", + "▁ano ther", + "▁re t", + "▁r et", + "▁ ret", + "▁L a", + "▁ La", + "Mo d", + "M od", + "IO N", + "I ON", + "li st", + "l ist", + "▁p ost", + "▁pos t", + "▁po st", + "▁ post", + "d a", + "wa re", + "war e", + "w are", + "▁w ord", + "▁wor d", + "▁wo rd", + "▁ word", + "Err or", + "Er ror", + "▁se em", + "▁see m", + "▁cont in", + "▁ contin", + "at ic", + "ati c", + "▁th ree", + "▁thr ee", + "▁ three", + "Ob ject", + "Obj ect", + "▁part ic", + "▁parti c", + "$ .", + "▁m ark", + "▁mar k", + "▁ mark", + "▁v is", + "▁vi s", + "▁ vis", + "r c", + "▁s w", + "▁ sw", + "pt ions", + "ption s", + "▁b reak", + "▁bre ak", + "▁ break", + "▁th ings", + "▁thing s", + "▁thin gs", + "ut e", + "u te", + "u i", + "▁T hat", + "▁Th at", + "▁ That", + "ur s", + "u rs", + "g l", + "р у", + "▁f ile", + "▁fil e", + "▁fi le", + "▁ file", + "us e", + "u se", + "ig ned", + "ign ed", + "igne d", + "par t", + "pa rt", + "p art", + "U n", + "▁e qu", + "▁eq u", + "▁ equ", + "( &", + "▁l ead", + "▁le ad", + "r m", + "ain ed", + "ai ned", + "aine d", + "a ined", + "▁B e", + "▁ Be", + "pat h", + "pa th", + "p ath", + "▁sm all", + "▁ small", + "ag er", + "age r", + "a ger", + "▁al ways", + "▁ always", + "▁E l", + "▁ El", + "▁or der", + "▁ord er", + "▁ order", + "▁e y", + "▁ ey", + "▁w on", + "▁wo n", + "▁ won", + "ap e", + "a pe", + "▁l eft", + "▁le ft", + "▁ left", + "av a", + "a va", + "it em", + "ite m", + "i tem", + "ho r", + "h or", + "▁a way", + "▁aw ay", + "▁ away", + "b b", + "fu n", + "f un", + "▁I nd", + "▁In d", + "▁ Ind", + "m b", + "▁st ruct", + "▁str uct", + "▁stru ct", + "▁ struct", + "▁pro cess", + "▁proc ess", + "▁proces s", + "▁ process", + "▁s upport", + "▁sup port", + "▁supp ort", + "▁ support", + "); \r", + ") ;\r", + "ió n", + "i ón", + "L O", + "▁o per", + "▁op er", + "▁ oper", + "U T", + "▁ ·", + "P E", + "lo ad", + "l oad", + "of f", + "o ff", + "▁N o", + "▁ No", + "iv es", + "ive s", + "i ves", + "ic an", + "ica n", + "i can", + "▁v e", + "▁ ve", + "act ion", + "a ction", + "' ;", + "▁v o", + "▁ vo", + "$ ,", + "▁G r", + "▁ Gr", + "pr e", + "p re", + "n y", + "ain ing", + "ai ning", + "a ining", + "io r", + "i or", + "in it", + "ini t", + "i nit", + "le ction", + "lect ion", + "l ection", + "ar m", + "a rm", + "um n", + "u mn", + "ag s", + "a gs", + "ц и", + "ск о", + "с ко", + "vers ion", + "v ersion", + "▁T o", + "▁ To", + "▁re f", + "▁r ef", + "▁ ref", + "st and", + "sta nd", + "stan d", + "▁A t", + "▁ At", + "if t", + "i ft", + "▁e in", + "fa ce", + "fac e", + "f ace", + "b o", + "if ied", + "ifi ed", + "ve d", + "v ed", + "su m", + "s um", + "un e", + "u ne", + "it al", + "ita l", + "i tal", + "um p", + "u mp", + "com m", + "co mm", + "c omm", + "▁m ov", + "▁mo v", + "▁ mov", + "el t", + "e lt", + "▁v on", + "▁vo n", + "vel op", + "ct or", + "c tor", + "he ad", + "h ead", + "cl e", + "c le", + "▁b uild", + "▁bu ild", + "▁ build", + "in c", + "i nc", + ". '", + "b s", + "in fo", + "inf o", + "ch n", + "c hn", + "▁we ek", + "▁ week", + "▁b ook", + "▁bo ok", + "▁ book", + "H E", + "ba r", + "b ar", + "ic ense", + "▁W hat", + "▁Wh at", + "▁ What", + "▁qu est", + "▁que st", + "▁q uest", + "▁ quest", + "ur ch", + "at o", + "a to", + "le ft", + "l eft", + "▁m ar", + "▁ma r", + "▁ mar", + "▁t op", + "▁to p", + "▁ top", + "F F", + "▁f riend", + "▁ friend", + "▁b eh", + "▁be h", + "▁f ield", + "▁fi eld", + "▁ field", + "▁again st", + "ra ct", + "rac t", + "r act", + "iz ation", + "us er", + "use r", + "u ser", + "ch en", + "che n", + "c hen", + "▁ke ep", + "▁ keep", + "A D", + "it or", + "ito r", + "i tor", + "▁n on", + "▁no n", + "▁ non", + "ir d", + "i rd", + "op e", + "o pe", + "▁re st", + "▁r est", + "▁res t", + "▁ rest", + "▁d ev", + "▁de v", + "▁ dev", + "▁_ _", + "▁ __", + "▁u na", + "▁un a", + "▁ una", + "▁t erm", + "▁te rm", + "▁ter m", + "▁ term", + "I S", + "▁p op", + "▁po p", + "▁ pop", + "ri st", + "ris t", + "r ist", + "▁s ince", + "▁sin ce", + "▁sinc e", + "▁ since", + "ve s", + "v es", + "▁h ard", + "▁ha rd", + "▁har d", + "▁ hard", + "p i", + "ut il", + "uti l", + "u til", + "▁s oc", + "▁so c", + "▁ soc", + "en e", + "e ne", + "Ex ception", + "▁l ocal", + "▁loc al", + "▁lo cal", + "▁ local", + "▁d irect", + "▁di rect", + "▁dire ct", + "▁dir ect", + "▁ direct", + "▁s ure", + "▁su re", + "▁sur e", + "▁ sure", + "▁b ro", + "▁br o", + "▁ bro", + "▁d a", + "▁ da", + "▁< /", + "▁ ", + "ai m", + "a im", + "▁s ervice", + "▁serv ice", + "▁ service", + "▁with in", + "an gu", + "ang u", + "▁ Д", + "uf fer", + "uff er", + "A G", + "▁D o", + "▁ Do", + "▁in cre", + "▁inc re", + "▁under stand", + "} ^", + "▁look ed", + "▁lo oked", + "ge n", + "g en", + "ail ed", + "ai led", + "a iled", + "▁ е", + "ay er", + "aye r", + "a yer", + "▁O ne", + "▁On e", + "▁ One", + "▁b as", + "▁ba s", + "▁ bas", + "▁j ob", + "▁jo b", + "▁ job", + "m u", + "bu t", + "b ut", + "el ta", + "elt a", + "▁Ch rist", + "▁Chris t", + "▁ Christ", + "ur ation", + "▁re cord", + "▁rec ord", + "▁ record", + "▁Un ivers", + "▁ Univers", + "iv id", + "ivi d", + "i vid", + "val id", + "▁ Р", + "▁h old", + "▁hol d", + "▁ho ld", + "▁ hold", + "▁t able", + "▁tab le", + "▁ta ble", + "▁ table", + "on es", + "one s", + "o nes", + "lin k", + "l ink", + "▁G e", + "▁ Ge", + "▁of fer", + "▁off er", + "st er", + "ste r", + "s ter", + "For m", + "F orm", + "= {", + "▁н е", + "▁ не", + "st ance", + "stan ce", + "▁g overn", + "▁go vern", + "▁gover n", + "▁ govern", + "▁te chn", + "▁tech n", + "▁ techn", + "▁p rim", + "▁pr im", + "▁pri m", + "▁ prim", + "* .", + "ch o", + "c ho", + "ma x", + "m ax", + "▁f ore", + "▁for e", + "▁fo re", + "▁ fore", + "▁C an", + "▁Ca n", + "▁ Can", + "▁pol it", + "▁po lit", + "▁ polit", + "or ies", + "ori es", + "orie s", + "o ries", + "▁t imes", + "▁time s", + "▁tim es", + "▁ti mes", + "▁ times", + "▁d ans", + "▁da ns", + "▁dan s", + "▁a ir", + "▁ai r", + "▁ air", + "▁any thing", + "▁s ever", + "▁se ver", + "ac y", + "a cy", + "} _", + "H e", + "▁l east", + "▁le ast", + "ip s", + "i ps", + "EN T", + "E NT", + "d o", + "▁о т", + "▁ от", + "▁c ost", + "▁co st", + "▁cos t", + "▁ cost", + ". ”", + "▁child ren", + "▁ children", + "ab ility", + "abil ity", + "Bu t", + "B ut", + "▁p ath", + "▁pat h", + "▁pa th", + "▁ path", + "res ult", + "ac ter", + "act er", + "▁e lement", + "▁el ement", + "▁ele ment", + "▁elem ent", + "▁ element", + "e e", + "▁w ait", + "▁wa it", + "▁ wait", + "▁m oney", + "▁mon ey", + "▁mo ney", + "Ma p", + "M ap", + "t d", + "oi n", + "o in", + "iv ing", + "ivi ng", + "i ving", + "ic ht", + "ich t", + "i cht", + "ic y", + "i cy", + "sc h", + "s ch", + "st e", + "s te", + "д у", + "or ed", + "ore d", + "o red", + "ou d", + "o ud", + "il le", + "ill e", + "i lle", + "is ed", + "ise d", + "i sed", + "pl ication", + "plic ation", + "▁c ustom", + "▁cust om", + "▁ custom", + "▁h aving", + "▁ha ving", + "▁hav ing", + "pon ent", + "po nent", + "▁B y", + "▁ By", + "ul es", + "ule s", + "u les", + "ue d", + "u ed", + "at ter", + "att er", + "atte r", + "An d", + "A nd", + "it ive", + "iti ve", + "De f", + "D ef", + "▁m oment", + "▁mom ent", + "▁mo ment", + "▁ moment", + "at erial", + "ate rial", + "ater ial", + "Cl ass", + "C lass", + "og raph", + "ograp h", + "o graph", + "ik e", + "i ke", + "▁l arge", + "▁larg e", + "▁ large", + "▁# ###", + "▁## ##", + "▁### #", + "▁ ####", + "▁e ither", + "du ct", + "duc t", + "d uct", + "▁T hen", + "▁The n", + "▁Th en", + "▁ Then", + "▁G u", + "▁ Gu", + "ole an", + "o lean", + "pe rt", + "per t", + "p ert", + "▁G et", + "▁Ge t", + "▁ Get", + "▁A b", + "▁ Ab", + "▁sh ort", + "▁ short", + "O n", + "im ent", + "ime nt", + "imen t", + "i ment", + "▁pro ject", + "▁ project", + "cri pt", + "cr ipt", + "c ript", + "▁incl uding", + "▁includ ing", + "▁inclu ding", + "▁ including", + "ни я", + "▁m aking", + "▁ma king", + "▁ making", + "▁some one", + "▁F l", + "▁ Fl", + "▁s at", + "▁sa t", + "▁ sat", + "▁comp any", + "▁compan y", + "▁ company", + "oc us", + "p u", + "▁G od", + "▁Go d", + "▁ God", + "if ication", + "ific ation", + "N o", + "▁s n", + "▁ sn", + "an o", + "a no", + "g a", + "▁a u", + "▁ au", + "▁c ou", + "▁co u", + "▁ cou", + "á s", + "en ded", + "end ed", + "ende d", + "т у", + "ob er", + "obe r", + "o ber", + "▁n othing", + "▁not hing", + "▁no thing", + "▁n et", + "▁ne t", + "▁ net", + "▁p ot", + "▁po t", + "▁ pot", + "▁t yp", + "▁ty p", + "▁ typ", + "▁it em", + "▁i tem", + "▁ item", + "re w", + "r ew", + "At t", + "A tt", + "▁you ng", + "▁yo ung", + "} \r", + "nd er", + "nde r", + "n der", + "st art", + "sta rt", + "star t", + "▁S c", + "▁ Sc", + "* )", + "▁e nc", + "▁en c", + "▁ enc", + "▁w omen", + "▁wom en", + "▁wo men", + "▁look ing", + "▁lo oking", + "▁ looking", + "▁р о", + "▁ ро", + "▁he alth", + "▁heal th", + "▁ health", + "Pat h", + "P ath", + "▁A fter", + "▁Af ter", + "▁ After", + "▁m ult", + "▁mu lt", + "▁mul t", + "▁ mult", + "▁{ \\", + "▁ {\\", + "▁l and", + "▁la nd", + "▁lan d", + "▁ land", + "or ld", + "▁D es", + "▁De s", + "▁ Des", + "▁e ng", + "▁en g", + "▁ eng", + "in put", + "▁P ol", + "▁Po l", + "▁ Pol", + "\" \"", + "Co de", + "C ode", + "▁s upp", + "▁su pp", + "▁sup p", + "▁ supp", + "ain er", + "ai ner", + "aine r", + "a iner", + "he ck", + "▁m or", + "▁mo r", + "▁ mor", + "▁m ill", + "▁mil l", + "▁mi ll", + "▁ mill", + "▁a w", + "▁ aw", + "f s", + "▁do ing", + "ting s", + "t ings", + "ad es", + "ade s", + "a des", + "▁to get", + "▁c ertain", + "▁cert ain", + "▁cer tain", + "▁t ogether", + "▁toget her", + "C E", + "ide o", + "▁Amer ican", + "▁America n", + "▁ American", + "on y", + "o ny", + "id d", + "i dd", + "I I", + "ge d", + "g ed", + "ab les", + "able s", + "abl es", + "a bles", + "▁ide nt", + "▁id ent", + "▁ ident", + "io d", + "i od", + "▁p arent", + "▁par ent", + "▁pa rent", + "▁pare nt", + "▁ parent", + "F or", + "amb da", + "an do", + "and o", + "= \\", + "ag ed", + "age d", + "a ged", + "en ding", + "end ing", + "In t", + "I nt", + "▁poss ible", + "▁ possible", + "▁с о", + "▁ со", + "iv ity", + "ivi ty", + "nu m", + "n um", + "r t", + "aj or", + "ajo r", + "a jor", + "cre ate", + "creat e", + "c reate", + "ri de", + "rid e", + "r ide", + "▁k new", + "▁kn ew", + "▁kne w", + "bi t", + "b it", + "it ional", + "ition al", + "iti onal", + "▁l ik", + "▁li k", + "▁ lik", + "▁H er", + "▁He r", + "▁ Her", + "ens ion", + "\" .", + "ot o", + "o to", + "▁ex ist", + "▁ exist", + "ak en", + "ake n", + "a ken", + "▁act ually", + "▁actual ly", + "c a", + "▁ Г", + "х о", + "in n", + "i nn", + "Al l", + "A ll", + "bu f", + "b uf", + "▁M e", + "▁ Me", + "▁s een", + "▁se en", + "▁see n", + "▁ seen", + "op s", + "o ps", + "No t", + "N ot", + "▁cont rol", + "▁contr ol", + "▁contro l", + "▁ control", + "▁res pon", + "▁resp on", + "▁ respon", + "} ;", + "il t", + "i lt", + "is k", + "i sk", + "▁b ad", + "▁ba d", + "▁ bad", + "▁o ften", + "▁of ten", + "▁p ast", + "▁pas t", + "▁pa st", + "ap er", + "ape r", + "a per", + "▁re ason", + "▁ reason", + "et ers", + "eter s", + "ete rs", + "e ters", + "▁w anted", + "▁want ed", + "ur a", + "u ra", + "ta ble", + "tab le", + "t able", + "or mal", + "orm al", + "wid th", + "w idth", + "г а", + "pt r", + "p tr", + "▁d est", + "▁de st", + "▁des t", + "▁ dest", + "▁de sign", + "▁des ign", + "▁ design", + "▁s ound", + "▁so und", + "▁sou nd", + "▁ sound", + "▁p lan", + "▁pl an", + "▁ plan", + "▁b ase", + "▁bas e", + "▁ba se", + "▁ base", + "ha nd", + "han d", + "h and", + "g s", + "▁s ays", + "▁sa ys", + "▁say s", + "fun ction", + "f unction", + "▁t ri", + "▁tr i", + "▁ tri", + "m t", + "▁in vest", + "▁inv est", + "▁av ailable", + "▁ available", + "ay out", + "a yout", + "▁o ch", + "▁oc h", + "▁ och", + "▁l as", + "▁la s", + "▁ las", + "il led", + "ill ed", + "ille d", + "V al", + "▁ ф", + "ie ty", + "iet y", + "i ety", + "mo n", + "m on", + "Ha nd", + "H and", + "F r", + "ia m", + "i am", + "pa ce", + "p ace", + "▁O b", + "▁ Ob", + "▁p ara", + "▁par a", + "▁pa ra", + "▁ para", + "▁me et", + "▁s um", + "▁su m", + "▁ sum", + "M essage", + "ic i", + "i ci", + "▁k nown", + "▁kn own", + "▁know n", + "▁ known", + "▁g en", + "▁ge n", + "▁ gen", + "am ma", + "amm a", + "a mma", + "ar r", + "a rr", + "▁t re", + "▁tr e", + "▁ tre", + "ok e", + "o ke", + "ut h", + "u th", + "~ \\", + "▁exper ience", + "▁experi ence", + "ic le", + "icl e", + "i cle", + "▁I l", + "▁ Il", + "▁s ent", + "▁se nt", + "▁sen t", + "▁ sent", + "▁o thers", + "▁other s", + "▁ others", + "▁s oft", + "▁so ft", + "▁ soft", + "I P", + "▁m ax", + "▁ma x", + "▁ max", + "ba ll", + "bal l", + "b all", + "▁mark et", + "▁mar ket", + "▁ market", + "▁p our", + "▁po ur", + "▁pou r", + "pr ession", + "press ion", + "p ression", + "ep s", + "e ps", + "▁s aw", + "▁sa w", + "▁a cross", + "▁ac ross", + "▁S u", + "▁ Su", + "O ver", + "ни е", + "ul ation", + "u lation", + "▁R eg", + "▁Re g", + "▁ Reg", + "▁+ =", + "▁ +=", + "bo dy", + "b ody", + ") \\", + "▁pr int", + "▁pri nt", + "▁prin t", + "▁ print", + "▁п ри", + "▁пр и", + "▁ при", + "d b", + "our ces", + "ource s", + "ward s", + "war ds", + "w ards", + "▁bl ack", + "▁ black", + "с о", + "il i", + "i li", + "▁E d", + "▁ Ed", + "▁com plet", + "▁comp let", + "▁compl et", + "▁s ingle", + "▁sing le", + "▁sin gle", + "▁ single", + "▁I N", + "▁ IN", + "ac hed", + "ach ed", + "ache d", + "a ched", + "b t", + "▁c ode", + "▁co de", + "▁cod e", + "▁ code", + "▁b ool", + "▁bo ol", + "▁ bool", + "▁a rea", + "▁are a", + "▁ar ea", + "▁ area", + "▁re quire", + "▁requ ire", + "▁ require", + "▁pro blem", + "▁proble m", + "▁prob lem", + "ac ed", + "ace d", + "a ced", + "Eq u", + "E qu", + "▁con fig", + "▁conf ig", + "▁ config", + "ve c", + "v ec", + "ne y", + "n ey", + "c y", + "A l", + "▁acc ount", + "▁ac count", + "▁ account", + "ym bol", + "▁s te", + "▁st e", + "▁ ste", + "ge s", + "g es", + "Ar ray", + "Arr ay", + "em pl", + "emp l", + "con text", + "cont ext", + "De s", + "D es", + "Res ult", + "ec ut", + "e cut", + "▁t arget", + "▁tar get", + "▁ target", + "▁get ting", + "\" />", + "og le", + "o gle", + "▁him self", + "▁was n", + "▁wa sn", + "▁b lock", + "▁bl ock", + "▁blo ck", + "▁ block", + "▁a nt", + "▁an t", + "▁ ant", + "▁Y ork", + "▁be come", + "▁bec ome", + "if f", + "i ff", + "port s", + "por ts", + "p orts", + "re ate", + "reat e", + "rea te", + "= '", + "c d", + "loc ation", + "l ocation", + "е т", + "▁a ccess", + "▁acc ess", + "▁ac cess", + "▁ access", + "gr ess", + "gre ss", + "gres s", + "g ress", + "ro s", + "r os", + "U p", + "▁work ing", + "▁wor king", + "▁ working", + "▁A m", + "▁ Am", + "iq u", + "i qu", + "ce r", + "c er", + "▁( (", + "▁ ((", + "▁P er", + "▁Pe r", + "▁ Per", + "▁f unc", + "▁fun c", + "▁fu nc", + "▁ func", + "▁g irl", + "▁gi rl", + "▁gir l", + "▁ girl", + "▁ab ove", + "pe n", + "p en", + "п и", + "id o", + "i do", + "▁v ersion", + "▁vers ion", + "▁ version", + "T Y", + "▁ ;", + "ma ry", + "mar y", + "m ary", + "ab led", + "able d", + "abl ed", + "a bled", + "an nel", + "ann el", + "anne l", + "▁ex ample", + "▁exam ple", + "▁ example", + "▁con text", + "▁cont ext", + "▁ context", + "O P", + "▁re d", + "▁r ed", + "▁ red", + "▁c ir", + "▁ci r", + "▁ cir", + "s m", + "Lo g", + "L og", + "▁s pace", + "▁sp ace", + "▁ space", + "▁f ut", + "▁fu t", + "▁G ener", + "▁Ge ner", + "▁Gen er", + "▁Gene r", + "▁ Gener", + "il ls", + "ill s", + "▁d ri", + "▁dr i", + "_ .", + "▁f elt", + "▁fe lt", + "▁fel t", + "▁o ffic", + "▁of fic", + "▁off ic", + "▁= ==", + "▁== =", + "▁ ===", + "i i", + "▁start ed", + "▁star ted", + "▁ Т", + "▁} );", + "▁}) ;", + "▁ });", + "j s", + "▁fr ont", + "▁fro nt", + "▁ front", + "▁al most", + "ir m", + "i rm", + "! \"", + "sign ed", + "sig ned", + "s igned", + "▁y et", + "▁ye t", + "▁t rad", + "▁tr ad", + "▁tra d", + "ient s", + "ien ts", + "i ents", + "am a", + "a ma", + "▁in put", + "▁ input", + "li m", + "l im", + "п а", + "▁к а", + "▁ ка", + "▁c amp", + "▁cam p", + "▁ca mp", + "▁ camp", + "ib r", + "i br", + "fe ct", + "f ect", + "un t", + "u nt", + "▁h alf", + "▁hal f", + "▁ half", + "▁c over", + "▁co ver", + "▁cov er", + "▁ cover", + "angu age", + "▁b en", + "▁be n", + "▁ ben", + "h a", + "▁d iff", + "▁di ff", + "▁dif f", + "▁ diff", + "_ \\", + "▁о б", + "▁ об", + "] )", + "od es", + "ode s", + "o des", + "he l", + "h el", + "io s", + "i os", + "▁ О", + "▁m ot", + "▁mo t", + "▁ mot", + "▁s ocial", + "▁so cial", + "▁soc ial", + "▁soci al", + "▁ social", + "//// ////", + "▁s tre", + "▁st re", + "▁str e", + "▁ stre", + "gr ound", + "gro und", + "g round", + "і в", + "ob ject", + "obj ect", + "pl es", + "ple s", + "p les", + "re ed", + "ree d", + "r eed", + "▁e en", + "▁ een", + "▁b ased", + "▁bas ed", + "▁base d", + "▁ba sed", + "▁ based", + "▁r ange", + "▁ran ge", + "▁rang e", + "▁ range", + "A n", + "ur g", + "u rg", + "▁le arn", + "▁lear n", + "▁ learn", + "▁e xc", + "▁ex c", + "▁ exc", + "▁im p", + "▁i mp", + "▁ imp", + "▁me ans", + "▁mean s", + "▁w ur", + "en ds", + "end s", + "vo id", + "v oid", + "▁s td", + "▁st d", + "▁ std", + "▁part icular", + "▁partic ular", + "▁particul ar", + "▁parti cular", + "j a", + "▁s ource", + "▁sour ce", + "▁ source", + "def ault", + "p y", + "▁a ls", + "▁al s", + "▁ als", + "sc ri", + "scr i", + "s cri", + "st atus", + "stat us", + "▁st ory", + "▁stor y", + "▁sto ry", + "▁ story", + "▁b egin", + "▁be gin", + "▁beg in", + "▁ begin", + "▁pos ition", + "▁posit ion", + "▁ position", + "▁spec ial", + "▁spe cial", + "▁ special", + "ph p", + "p hp", + "▁b ar", + "▁ba r", + "▁ bar", + "▁p ract", + "▁pr act", + "▁pra ct", + "▁prac t", + "cal l", + "ca ll", + "c all", + "▁d as", + "▁da s", + "▁ das", + "▁r ad", + "▁ra d", + "▁ rad", + "▁cl ose", + "▁clos e", + "▁clo se", + "▁ close", + "ww w", + "w ww", + "ер е", + "е ре", + "g u", + "▁E r", + "▁ Er", + "▁d om", + "▁do m", + "▁ dom", + "A M", + "▁b ed", + "▁be d", + "▁ bed", + "▁sever al", + "au l", + "a ul", + "bo x", + "b ox", + "▁l ow", + "▁lo w", + "▁ low", + "pa ck", + "p ack", + "Re g", + "R eg", + "O f", + "at ures", + "ature s", + "atur es", + "atu res", + "é n", + "ed er", + "ede r", + "e der", + "uild er", + "ca st", + "cas t", + "c ast", + "con om", + "co nom", + "c onom", + "ra ft", + "raf t", + "r aft", + "▁m akes", + "▁make s", + "▁ma kes", + "Lo c", + "L oc", + "ht tp", + "htt p", + "h ttp", + "▁a bs", + "▁ab s", + "▁ abs", + "re sh", + "res h", + "r esh", + "▁W ill", + "▁Wil l", + "▁Wi ll", + "▁ Will", + "bre ak", + "b reak", + "▁o ptions", + "▁opt ions", + "▁option s", + "▁ options", + "fo rt", + "for t", + "f ort", + "▁и з", + "▁ из", + "▁a nal", + "▁an al", + "▁ anal", + "▁e nv", + "▁en v", + "▁ env", + "( {", + "ev ent", + "even t", + "eve nt", + "e vent", + "▁p age", + "▁pa ge", + "▁pag e", + "▁ page", + "ter nal", + "tern al", + "▁d istribut", + "▁dist ribut", + "▁f ood", + "▁fo od", + "▁foo d", + "▁ food", + "che ck", + "c heck", + "C K", + "▁в о", + "▁ во", + "as sert", + "ass ert", + "asse rt", + "á n", + "ba se", + "bas e", + "b ase", + "▁w hole", + "▁wh ole", + "▁who le", + "ac ión", + "ació n", + "aci ón", + "a ción", + "O D", + "▁turn ed", + "▁tur ned", + "ig ma", + "▁res ponse", + "▁respon se", + "▁respons e", + "▁ response", + "▁Univers ity", + "▁d iv", + "▁di v", + "▁ div", + "ap ter", + "apt er", + "▁result s", + "▁ results", + "▁re present", + "▁rep resent", + "▁every thing", + "▁C ent", + "▁Ce nt", + "▁ Cent", + "ut es", + "ute s", + "u tes", + "ri x", + "r ix", + "▁S ome", + "▁So me", + "▁Som e", + "▁ Some", + "▁be hind", + "▁beh ind", + "▁c reat", + "▁cre at", + "▁ creat", + "pl ace", + "plac e", + "p lace", + "s u", + "▁P art", + "▁Par t", + "▁Pa rt", + "▁ Part", + "um b", + "u mb", + "math bb", + "pi ng", + "pin g", + "p ing", + "▁m atch", + "▁mat ch", + "▁ match", + "O ut", + "do m", + "d om", + "▁s itu", + "▁sit u", + "▁si tu", + "d r", + "ar a", + "a ra", + "▁w indow", + "▁wind ow", + "▁ window", + "n s", + "lish ed", + "l ished", + "▁V er", + "▁Ve r", + "▁ Ver", + "▁m essage", + "▁mess age", + "▁ message", + "▁E m", + "▁ Em", + "▁h uman", + "▁hum an", + "▁ human", + "per ties", + "pert ies", + "л у", + "le m", + "l em", + "OR T", + "O RT", + "▁e arly", + "▁ear ly", + "▁qu ick", + "▁qui ck", + "▁ quick", + "▁т а", + "▁ та", + "ro id", + "r oid", + "▁c ountry", + "▁coun try", + "▁count ry", + "▁countr y", + "▁ country", + "▁d ue", + "▁du e", + "▁ due", + "▁D ie", + "▁Di e", + "▁ Die", + "▁t rying", + "▁tr ying", + "▁try ing", + "▁l ive", + "▁li ve", + "▁liv e", + "▁ live", + "▁p ress", + "▁pre ss", + "▁pr ess", + "▁pres s", + "▁ press", + "IN T", + "I NT", + "W ith", + "ov ed", + "ove d", + "o ved", + "▁spec ific", + "▁ specific", + "▁f all", + "▁fa ll", + "▁fal l", + "▁ fall", + "u k", + "y l", + "▁gener al", + "▁gen eral", + "▁gene ral", + "▁ general", + "м у", + "н у", + "▁n ames", + "▁name s", + "▁na mes", + "▁nam es", + "▁ names", + "wh ere", + "whe re", + "w here", + "▁The se", + "▁Th ese", + "▁ These", + "▁s il", + "▁si l", + "▁ sil", + "é t", + "▁e ner", + "▁en er", + "▁ ener", + "▁N ow", + "▁No w", + "▁ Now", + "▁add ress", + "▁addr ess", + "▁ address", + "Res ponse", + "▁M r", + "▁ Mr", + "▁an sw", + "▁ans w", + "▁fil m", + "▁fi lm", + "▁ film", + "▁str ong", + "▁stro ng", + "▁ strong", + "▁b ring", + "▁br ing", + "▁Un ited", + "▁Unit ed", + "▁g e", + "▁ ge", + "▁w oman", + "▁wom an", + "▁wo man", + "▁ woman", + "Ne w", + "N ew", + "et t", + "e tt", + ". )", + "en ame", + "ena me", + "e name", + "▁A N", + "▁ AN", + "▁de scrib", + "▁desc rib", + "з а", + "is ing", + "isi ng", + "i sing", + "E L", + "q l", + "▁f ur", + "▁fu r", + "▁ fur", + "y ing", + "▁C al", + "▁Ca l", + "▁ Cal", + "▁D r", + "▁ Dr", + "ER R", + "E RR", + "▁\\ \\", + "▁ \\\\", + "an gle", + "ang le", + "ur ope", + "uro pe", + "urop e", + "▁c ity", + "▁cit y", + "▁ci ty", + "▁ city", + "▁in dex", + "▁ind ex", + "▁inde x", + "▁ index", + "▁a ction", + "▁act ion", + "▁ action", + "▁How ever", + "▁ However", + "▁f ig", + "▁fi g", + "▁ fig", + "ia s", + "i as", + "▁quest ion", + "▁ question", + "▁J an", + "▁Ja n", + "▁ Jan", + "▁M ed", + "▁Me d", + "▁ Med", + "▁C ont", + "▁Con t", + "▁Co nt", + "▁ Cont", + "am ed", + "ame d", + "a med", + "Cal l", + "C all", + "pl ied", + "tt y", + "t ty", + "▁ind ivid", + "pa ge", + "pag e", + "p age", + "▁c omb", + "▁com b", + "▁co mb", + "▁ comb", + "se ction", + "sect ion", + "s ection", + "▁C omm", + "▁Com m", + "▁Co mm", + "▁ Comm", + "ue l", + "u el", + "▁h et", + "▁he t", + "▁ het", + "▁B ar", + "▁Ba r", + "▁ Bar", + "ag ement", + "age ment", + "agem ent", + "fi n", + "f in", + "▁m ajor", + "▁ma jor", + "▁maj or", + "▁ major", + "op er", + "ope r", + "o per", + "ap i", + "a pi", + "ro om", + "r oom", + "▁ „", + "▁h ab", + "▁ha b", + "▁ hab", + "з и", + "▁a uf", + "▁au f", + "▁ auf", + "cur rent", + "curr ent", + "n i", + "▁in clude", + "▁incl ude", + "▁includ e", + "▁inclu de", + "▁ include", + "▁qu i", + "▁q ui", + "v a", + "U E", + "▁ide a", + "▁id ea", + "▁ idea", + ", '", + "▁requ ired", + "▁require d", + "▁ required", + "▁he art", + "▁hear t", + "▁ heart", + "ib ility", + "ibil ity", + "ict ion", + "i ction", + "Mod el", + "Mode l", + "Mo del", + "wr ite", + "writ e", + "w rite", + "▁cont ent", + "▁conten t", + "▁ content", + "▁w er", + "▁we r", + "▁ wer", + "▁h ands", + "▁hand s", + "▁han ds", + "ze n", + "z en", + "ch ar", + "cha r", + "c har", + "}^ {", + "} ^{", + "▁m ass", + "▁ma ss", + "▁mas s", + "▁ mass", + "pl y", + "p ly", + "▁n at", + "▁na t", + "▁ nat", + "re l", + "r el", + "▁d at", + "▁da t", + "▁ dat", + "==== ============", + "======== ========", + "============ ====", + "im al", + "ima l", + "i mal", + "▁pro bably", + "▁prob ably", + "un ch", + "unc h", + "▁m er", + "▁me r", + "▁ mer", + "il ar", + "ila r", + "i lar", + "ir es", + "ire s", + "i res", + "▁w atch", + "▁wat ch", + "▁ watch", + "S I", + "▁c ult", + "▁cu lt", + "▁cul t", + "▁m other", + "▁mot her", + "▁mo ther", + "▁ mother", + "▁govern ment", + "or ding", + "ord ing", + "▁( )", + "▁ ()", + "▁p ri", + "▁pr i", + "▁l ink", + "▁lin k", + "▁ link", + "gr oup", + "gro up", + "g roup", + "O L", + "▁n ear", + "▁ne ar", + "▁S er", + "▁Se r", + "▁ Ser", + "Se r", + "S er", + "it o", + "i to", + "▁value s", + "▁val ues", + "▁ values", + "▁j ava", + "▁ja va", + "▁ java", + "ful ly", + "full y", + "f ully", + "Co unt", + "C ount", + "++ )", + "▁v i", + "▁ vi", + "▁wh ite", + "▁ white", + "ma t", + "m at", + "ct x", + "c tx", + "▁con c", + "▁co nc", + "▁ conc", + "▁st ay", + "▁sta y", + "gi ng", + "gin g", + "g ing", + "▁c lear", + "▁cl ear", + "▁cle ar", + "▁ clear", + "▁c opy", + "▁co py", + "▁cop y", + "▁ copy", + "sel ves", + "▁prov ide", + "▁w ords", + "▁wor ds", + "▁word s", + "▁ words", + "com p", + "co mp", + "c omp", + "ar gs", + "arg s", + "▁p ick", + "▁pi ck", + "▁pic k", + "▁ pick", + "ul y", + "u ly", + "▁v ari", + "▁var i", + "▁va ri", + "▁ vari", + "▁bel ieve", + "▁belie ve", + "▁C o", + "▁ Co", + "Pro perty", + "Gr oup", + "G roup", + "▁t en", + "▁te n", + "▁ ten", + "is chen", + "isch en", + "ische n", + "isc hen", + "i schen", + "et urn", + "e turn", + "iv al", + "iva l", + "i val", + "Sys tem", + "S ystem", + "C L", + "be d", + "b ed", + "▁t otal", + "▁to tal", + "▁tot al", + "▁ total", + "▁is t", + "▁i st", + "▁ ist", + "In put", + "um ents", + "ument s", + "umen ts", + "u ments", + "Man ager", + "ш и", + "▁w in", + "▁ win", + "le ep", + "lee p", + "P I", + "но го", + "н ого", + "ru ction", + "ruct ion", + "r uction", + "▁in te", + "▁i nte", + "▁int e", + "▁ inte", + "Ap p", + "A pp", + "av or", + "avo r", + "a vor", + "▁re spect", + "▁res pect", + "▁resp ect", + "▁ respect", + "at ors", + "ator s", + "ato rs", + "▁c omo", + "▁com o", + "▁co mo", + "▁c ut", + "▁cu t", + "▁ cut", + "F A", + "▁s us", + "▁su s", + "▁A pp", + "▁Ap p", + "▁ App", + "re ct", + "rec t", + "r ect", + "F I", + "▁be gan", + "▁beg an", + "op h", + "o ph", + "▁s ort", + "▁so rt", + "▁sor t", + "▁ sort", + "th ough", + "ј е", + "ic ro", + "i cro", + "Tr ans", + "Tra ns", + "л і", + "▁In st", + "▁Ins t", + "▁ Inst", + "re quest", + "requ est", + "req uest", + "о р", + "▁rel ations", + "▁relation s", + "- \\", + "St atus", + "Stat us", + "ж и", + "▁f ather", + "▁fa ther", + "▁fat her", + "▁ father", + "c s", + "▁s ex", + "▁se x", + "▁ sex", + "is ch", + "isc h", + "i sch", + "v o", + "}_ {", + "} _{", + "ave n", + "av en", + "a ven", + "▁N e", + "▁ Ne", + "AT E", + "A TE", + "it ten", + "itt en", + "itte n", + "▁e ss", + "▁es s", + "▁ ess", + "T H", + "ight s", + "igh ts", + "▁h om", + "▁ho m", + "▁ hom", + "▁t oday", + "▁to day", + "▁tod ay", + "▁toda y", + "▁z u", + "▁ zu", + "it a", + "i ta", + "▁is n", + "▁i sn", + "▁o pt", + "▁op t", + "▁ opt", + "og n", + "o gn", + "é r", + "▁wh ether", + "▁whe ther", + "ix ed", + "ph i", + "p hi", + "id ence", + "iden ce", + "al d", + "a ld", + "Cl ient", + "A t", + "▁de ath", + "▁L et", + "▁Le t", + "▁ Let", + "iu s", + "i us", + "г и", + "▁р е", + "▁ ре", + "be n", + "b en", + ") \r", + "b a", + ">< /", + "> ", + "▁ ->", + "▁J ust", + "▁Ju st", + "▁ Just", + "Wh at", + "W hat", + "at al", + "ata l", + "a tal", + "▁M in", + "▁Mi n", + "▁ Min", + "▁C or", + "▁Co r", + "▁ Cor", + "▁d ark", + "▁dar k", + "▁ dark", + "r l", + "▁l arg", + "▁la rg", + "▁ larg", + "di ng", + "d ing", + "ó n", + "ou ch", + "o uch", + "▁u m", + "▁ um", + "▁e lect", + "▁el ect", + "▁ele ct", + "▁ elect", + "▁d am", + "▁da m", + "▁ dam", + "▁ne eds", + "▁need s", + "▁m atter", + "▁mat ter", + "▁matt er", + "▁r ather", + "▁rat her", + "▁ra ther", + "fr om", + "f rom", + "ra m", + "r am", + "▁ і", + "▁t aken", + "▁take n", + "▁tak en", + "▁ta ken", + "▁de al", + "▁per iod", + "▁ period", + "▁M on", + "▁Mo n", + "▁ Mon", + "▁ Л", + "▁A ug", + "▁Au g", + "▁ Aug", + "ru n", + "r un", + "m m", + "el le", + "ell e", + "e lle", + "▁ex port", + "▁exp ort", + "▁ export", + "S c", + "vi s", + "v is", + "ab or", + "a bor", + "▁aut hor", + "▁auth or", + "▁ author", + "è re", + "▁re member", + "▁rem ember", + "▁remem ber", + "▁re du", + "▁r edu", + "▁red u", + "▁ redu", + "▁L ist", + "▁Li st", + "▁Lis t", + "▁ List", + "▁f ocus", + "▁ focus", + "▁char acter", + "▁ character", + "Tab le", + "T able", + "▁individ ual", + "▁need ed", + "bu m", + "b um", + "▁st yle", + "▁sty le", + "▁ style", + "in ary", + "ina ry", + "inar y", + "ers ion", + "ou te", + "out e", + "o ute", + "▁P e", + "▁ Pe", + "▁h on", + "▁ho n", + "▁ hon", + "mu t", + "m ut", + "se e", + "s ee", + "▁bec ame", + "▁d ire", + "▁di re", + "▁dir e", + "▁ dire", + "▁d ocument", + "▁doc ument", + "▁ document", + "se c", + "s ec", + "en ing", + "eni ng", + "e ning", + "▁vis it", + "▁ visit", + "▁f ac", + "▁fa c", + "▁ fac", + "t x", + "do wn", + "d own", + "pl it", + "p lit", + "▁ph ys", + "▁ phys", + "it ting", + "itt ing", + "jo y", + "j oy", + "▁h ig", + "▁hi g", + "Th is", + "T his", + "A d", + "▁B rit", + "▁Br it", + "▁em ploy", + "▁r é", + "▁ ré", + "▁ т", + "l ambda", + "▁im pro", + "▁imp ro", + "▁B o", + "▁ Bo", + "id ing", + "idi ng", + "i ding", + "▁on line", + "▁ online", + "me m", + "m em", + "at form", + "▁W ar", + "▁Wa r", + "▁ War", + "▁c as", + "▁ca s", + "▁ cas", + "as ure", + "a sure", + "▁p ur", + "▁pu r", + "▁ pur", + "me di", + "med i", + "m edi", + "Di s", + "D is", + "▁G erm", + "▁Ge rm", + "▁Ger m", + "p c", + "с а", + "▁friend s", + "▁M c", + "▁ Mc", + "D I", + "▁pl us", + "▁ plus", + "▁S et", + "▁Se t", + "▁ Set", + "idd le", + "it ut", + "itu t", + "▁de pend", + "▁dep end", + "▁ depend", + "re st", + "res t", + "r est", + "▁J e", + "▁ Je", + "▁h or", + "▁ho r", + "▁ hor", + "▁ent ire", + "Qu ery", + "Que ry", + "▁re fer", + "▁ref er", + "▁ refer", + "▁h ot", + "▁ho t", + "▁ hot", + "▁A ust", + "▁Aus t", + "▁Au st", + "▁com mon", + "▁comm on", + "▁ common", + "ц і", + "▁p ull", + "▁pu ll", + "▁pul l", + "▁ pull", + "▁A dd", + "▁Ad d", + "▁ Add", + "▁se ason", + "▁sea son", + "▁seas on", + "▁ season", + "▁in vol", + "▁inv ol", + "▁W orld", + "▁Wor ld", + "▁ World", + "cl ient", + "cli ent", + "no w", + "n ow", + "tr ue", + "ap pend", + "app end", + "appe nd", + "appen d", + "it ted", + "itt ed", + "itte d", + "em pt", + "emp t", + ") {", + "// /", + "/ //", + "▁p rop", + "▁pro p", + "▁pr op", + "▁ prop", + "im ate", + "ima te", + "imat e", + "i mate", + "S C", + "▁h ours", + "▁hour s", + "▁ho urs", + "▁h ope", + "▁hop e", + "▁ho pe", + "an dom", + "and om", + "ando m", + "і д", + "ist ic", + "isti c", + "▁pro perty", + "▁proper ty", + "▁ property", + "s g", + "> (", + "▁w rite", + "▁wr ite", + "▁writ e", + "▁ write", + "mar k", + "m ark", + "fin d", + "fi nd", + "f ind", + "▁person al", + "▁pers onal", + "▁persona l", + "▁ personal", + "] [", + "ro wn", + "row n", + "r own", + "P h", + "▁f oot", + "▁fo ot", + "▁foo t", + "▁ foot", + "▁re search", + "▁res earch", + "iron ment", + "▁n om", + "▁no m", + "▁ nom", + "▁in stance", + "▁inst ance", + "▁ instance", + "▁h eld", + "▁he ld", + "▁hel d", + "▁ held", + "D e", + "▁mem bers", + "▁member s", + "▁ members", + "▁f ire", + "▁fi re", + "▁fir e", + "▁ fire", + "▁hist ory", + "▁histor y", + "▁hi story", + "▁ history", + "▁m ap", + "▁ma p", + "▁ map", + "▁dis cuss", + "▁disc uss", + "▁e spec", + "▁es pec", + "▁esp ec", + "▁ espec", + "▁t aking", + "▁tak ing", + "▁ta king", + "▁s ervices", + "▁serv ices", + "▁service s", + "▁ services", + "▁ind ust", + "▁indu st", + "▁ indust", + "ig en", + "ige n", + "i gen", + "▁A ss", + "▁As s", + "▁ Ass", + "▁e xpected", + "▁ex pected", + "▁expect ed", + "▁ expected", + "▁wur de", + "di r", + "d ir", + "▁a mong", + "▁am ong", + "▁s ugg", + "▁su gg", + "▁sug g", + "re c", + "r ec", + "In ter", + "Int er", + "bl ock", + "blo ck", + "b lock", + "▁R ep", + "▁Re p", + "▁ Rep", + "▁p ain", + "▁pa in", + "▁f ive", + "▁fi ve", + "▁ five", + "▁f und", + "▁fun d", + "▁fu nd", + "▁ fund", + "ri d", + "r id", + "ar row", + "arr ow", + "▁t reat", + "▁tre at", + "▁he ard", + "▁hear d", + "▁de term", + "▁det erm", + "▁deter m", + "ic ult", + "▁s ense", + "▁sens e", + "▁sen se", + "es e", + "e se", + "F un", + "▁month s", + "▁mont hs", + "js on", + "j son", + ", ”", + "T I", + "or age", + "ora ge", + "o rage", + "▁ У", + "▁every one", + "▁c los", + "▁cl os", + "▁clo s", + "▁ clos", + "ie rs", + "ier s", + "i ers", + "air s", + "ai rs", + "a irs", + "def ine", + "I f", + "os p", + "o sp", + "▁w onder", + "▁won der", + "▁wo nder", + "N A", + "qu ery", + "que ry", + "quer y", + "p g", + "it es", + "ite s", + "i tes", + "▁m aterial", + "▁mat erial", + "▁mate rial", + "▁mater ial", + "▁ material", + "y d", + "Re ad", + "R ead", + "ht ml", + "h tml", + "T E", + "P r", + "^{ \\", + "^ {\\", + "▁g ave", + "▁ga ve", + "▁I S", + "▁ IS", + "▁s uggest", + "▁sugg est", + "▁sug gest", + "Over ride", + "ro du", + "rod u", + "Fr om", + "F rom", + "▁E urope", + "▁Europ e", + "▁Euro pe", + "▁ Europe", + "P O", + "▁s oon", + "▁so on", + "ho st", + "hos t", + "h ost", + "▁B er", + "▁Be r", + "▁ Ber", + ".. ..", + "... .", + ". ...", + "▁H ar", + "▁Ha r", + "▁ Har", + "▁e nergy", + "▁ener gy", + "▁energ y", + "▁ energy", + "> <", + "ave s", + "av es", + "a ves", + "▁e asy", + "▁eas y", + "▁b re", + "▁br e", + "▁ bre", + "fr ame", + "▁g round", + "▁gr ound", + "▁gro und", + "▁ ground", + "wi th", + "w ith", + "▁in side", + "▁ins ide", + "ie f", + "i ef", + "▁m o", + "▁ mo", + "p m", + "pa n", + "p an", + "ig r", + "i gr", + "▁o m", + "▁ om", + "ne xt", + "nex t", + "n ext", + "om et", + "ome t", + "o met", + "▁st atus", + "▁stat us", + "▁ status", + "▁} \r", + "▁ }\r", + "▁mus ic", + "or a", + "o ra", + "il es", + "ile s", + "i les", + "k i", + "▁e sc", + "▁es c", + "▁ esc", + "▁b es", + "▁be s", + "▁ bes", + "▁D is", + "▁Di s", + "▁ Dis", + "▁h ost", + "▁ho st", + "▁ host", + "▁c omes", + "▁com es", + "▁co mes", + "▁come s", + "▁ comes", + "us ed", + "use d", + "u sed", + "▁f uture", + "▁fut ure", + "▁ future", + "lic k", + "li ck", + "l ick", + "ai d", + "a id", + "▁com pet", + "▁comp et", + "▁ compet", + "▁v oice", + "▁vo ice", + "▁ voice", + "▁l oad", + "▁lo ad", + "▁ load", + "ev el", + "eve l", + "e vel", + "▁n eg", + "▁ne g", + "▁ neg", + "▁com mand", + "▁comm and", + "▁ command", + "▁f ür", + "▁p ie", + "▁pi e", + "▁ pie", + "▁qu ite", + "▁qui te", + "▁quit e", + "▁b lo", + "▁bl o", + "▁ blo", + "ag n", + "a gn", + "il on", + "ilo n", + "i lon", + "▁cl aim", + "▁ claim", + "▁t each", + "▁te ach", + "▁tea ch", + "▁pre vious", + "▁prev ious", + "▁ previous", + "▁s ite", + "▁sit e", + "▁si te", + "▁ site", + "co lor", + "col or", + "colo r", + "at tr", + "att r", + "▁ac cept", + "▁ accept", + "▁ex act", + ") }", + "af t", + "a ft", + "rol ler", + "roll er", + "о н", + "o o", + "Dat e", + "Da te", + "D ate", + "▁o u", + "▁ ou", + "s y", + "▁pre tty", + "▁pret ty", + "▁im age", + "▁imag e", + "▁ image", + "B U", + "▁term s", + "▁ter ms", + "▁s earch", + "▁se arch", + "▁sear ch", + "▁ search", + "▁ è", + "▁V al", + "▁Va l", + "▁ Val", + "▁ ‘", + "▁D av", + "▁Da v", + "M S", + "sr c", + "s rc", + "ma r", + "m ar", + "in cip", + "inc ip", + "▁could n", + "ad os", + "ado s", + "▁d ro", + "▁dr o", + "▁ dro", + "be ta", + "bet a", + "b eta", + "im um", + "▁min utes", + "▁minute s", + "▁minut es", + "▁g rand", + "▁gr and", + "▁gran d", + "▁gra nd", + "▁ grand", + "▁ »", + "▁O ur", + "▁ Our", + "St r", + "S tr", + "VE R", + "V ER", + "ma z", + "m az", + "▁or iginal", + "▁orig inal", + "▁origin al", + "▁ original", + "in i", + "i ni", + "▁c oll", + "▁col l", + "▁co ll", + "▁ coll", + "lo at", + "▁o s", + "▁ os", + "}) ;", + "} );", + "sum mary", + "▁w all", + "▁wa ll", + "▁wal l", + "▁ wall", + "Col or", + "Co lor", + "▁v ers", + "▁ver s", + "▁ve rs", + "▁ vers", + "▁d ella", + "▁de lla", + "▁del la", + "▁dell a", + "▁\" \"\"", + "▁\"\" \"", + "▁ \"\"\"", + "math bf", + "ze r", + "z er", + "au r", + "a ur", + "▁tr ack", + "▁tra ck", + "▁ track", + "▁ass oci", + "▁ associ", + "▁s uff", + "▁su ff", + "▁in de", + "▁i nde", + "▁ind e", + "▁ inde", + "ag ue", + "agu e", + "a gue", + "▁A pr", + "▁Ap r", + "▁ Apr", + "L e", + "ro ups", + "rou ps", + "roup s", + "bo ard", + "b oard", + "▁att ack", + "▁s eries", + "▁se ries", + "▁ser ies", + "▁serie s", + "▁ series", + "▁in stead", + "▁inst ead", + "ha m", + "h am", + "bo ok", + "b ook", + "▁s ix", + "▁si x", + "▁ six", + "▁R ec", + "▁Re c", + "▁ Rec", + "▁c oming", + "▁com ing", + "▁co ming", + "▁ coming", + "ur t", + "u rt", + "▁gl obal", + "▁glob al", + "▁glo bal", + "▁ global", + "▁ne cess", + "▁neces s", + "▁ necess", + "le ge", + "leg e", + "Po s", + "P os", + "▁le ave", + "▁ leave", + "▁p od", + "▁po d", + "▁ pod", + "ateg ory", + "ategor y", + "u z", + "▁de ep", + "▁ deep", + "▁k m", + "▁ km", + "▁out side", + "▁outs ide", + "ha s", + "h as", + "opt ions", + "option s", + "o ptions", + "▁S m", + "▁ Sm", + "Su b", + "S ub", + "ro ws", + "row s", + "r ows", + "▁в и", + "▁ ви", + "▁St ates", + "▁State s", + "▁Stat es", + "▁Sta tes", + "▁ States", + "▁wr ong", + "▁how ever", + "▁s em", + "▁se m", + "▁ sem", + "▁c atch", + "▁cat ch", + "▁ catch", + "\") ,", + "\" ),", + "mod el", + "mode l", + "mo del", + "▁h ttp", + "▁htt p", + "▁ http", + "▁o ption", + "▁opt ion", + "▁ option", + "ri e", + "r ie", + "▁с та", + "▁ст а", + "▁ ста", + "▁ä r", + "▁ är", + "▁en joy", + "▁enjo y", + "n u", + "▁p as", + "▁pa s", + "▁ pas", + "▁a mount", + "▁am ount", + "▁ amount", + "▁res pons", + "▁respon s", + "▁resp ons", + "▁ respons", + "▁In tern", + "▁Inter n", + "▁Int ern", + "▁ Intern", + "▁my self", + "▁o pp", + "▁op p", + "▁ opp", + "▁S im", + "▁Si m", + "▁ Sim", + "▁s ens", + "▁se ns", + "▁sen s", + "E d", + "▁( \\", + "▁ (\\", + "▁stud ents", + "▁student s", + "но в", + "н ов", + "▁point s", + "▁ points", + "ar ning", + "arn ing", + "U P", + "el ling", + "ell ing", + "elli ng", + "▁c annot", + "▁can not", + "B e", + "▁l ength", + "▁le ngth", + "▁ length", + "nu ll", + "n ull", + "ui nt", + "u int", + "wi se", + "w ise", + "▁d ouble", + "▁dou ble", + "▁doub le", + "▁ double", + "ig e", + "i ge", + "is ta", + "ist a", + "i sta", + "▁est ab", + "▁es tab", + "▁esta b", + "an ch", + "anc h", + "▁a go", + "▁ag o", + "▁ ago", + "▁b ound", + "▁bo und", + "▁bou nd", + "▁ bound", + "▁f a", + "▁ fa", + "▁c lean", + "▁cle an", + "▁ clean", + "▁sim ple", + "▁simpl e", + "▁ simple", + "m i", + "#### ####", + "if ier", + "ifi er", + "▁Gener al", + "▁Gen eral", + "▁Gene ral", + "▁ General", + "▁se emed", + "▁see med", + "▁seem ed", + "en a", + "e na", + "▁a ge", + "▁ag e", + "▁ age", + "но й", + "end if", + "A A", + "▁c aus", + "▁ca us", + "▁e duc", + "▁ed uc", + "▁ educ", + "▁c ell", + "▁ce ll", + "▁cel l", + "▁ cell", + "Ge ner", + "Gen er", + "G ener", + "sp ace", + "s pace", + "▁Y our", + "▁You r", + "▁ Your", + "▁be aut", + "g t", + "▁l imit", + "▁li mit", + "▁lim it", + "▁ limit", + "▁d ate", + "▁da te", + "▁dat e", + "▁ date", + "Ut il", + "U til", + "▁N ational", + "▁Nat ional", + "▁Nation al", + "▁ National", + "ow s", + "o ws", + "pa t", + "p at", + "qu ad", + "▁o k", + "▁ ok", + "▁ И", + "ar th", + "art h", + "ha t", + "h at", + "▁comm unity", + "▁commun ity", + "ou l", + "o ul", + "▁e conom", + "▁ec onom", + "▁ econom", + "Com ponent", + "bo r", + "b or", + "us ion", + "▁be low", + "▁bel ow", + "ear ch", + "e arch", + "or es", + "ore s", + "o res", + "ba n", + "b an", + "▁Aug ust", + "▁fur ther", + "sig ma", + "s igma", + "▁h a", + "▁ ha", + "j i", + "▁com put", + "▁comp ut", + "▁ comput", + "г ра", + "▁N one", + "▁No ne", + "▁Non e", + "▁ None", + "▁t er", + "▁te r", + "▁ ter", + "▁any one", + "▁t ask", + "▁ta sk", + "▁ task", + "en te", + "ent e", + "e nte", + "pos ition", + "pp ed", + "ppe d", + "p ped", + "▁a us", + "▁au s", + "▁ aus", + "Att ribute", + "Attrib ute", + "re q", + "r eq", + "ad dr", + "add r", + "li ght", + "lig ht", + "l ight", + "ш е", + "▁a rm", + "▁ar m", + "▁ arm", + "co ver", + "cov er", + "c over", + "up port", + "upp ort", + "▁G l", + "▁ Gl", + "▁S an", + "▁Sa n", + "▁ San", + "▁wr iting", + "▁writ ing", + "▁ writing", + "▁l ost", + "▁lo st", + "▁los t", + "▁M ark", + "▁Mar k", + "▁ Mark", + "▁g re", + "▁gr e", + "▁ gre", + "TY PE", + "T YPE", + "▁S outh", + "▁So uth", + "▁Sou th", + "▁Sout h", + "▁ South", + "▁per fect", + "▁perf ect", + "▁pack age", + "▁ package", + "▁in fl", + "▁inf l", + "▁ infl", + "ha ps", + "h aps", + "▁A ng", + "▁An g", + "▁ Ang", + "res pon", + "resp on", + "ri s", + "r is", + "pt ember", + "pte mber", + "▁build ing", + "▁ building", + "VA L", + "V AL", + "fr ee", + "fre e", + "f ree", + "▁c e", + "▁ ce", + "H T", + "▁F rom", + "▁Fr om", + "▁Fro m", + "▁ From", + "d s", + "ro y", + "r oy", + "ach ine", + "achi ne", + "no wn", + "now n", + "n own", + "▁sa ying", + "▁say ing", + "▁б ы", + "▁ бы", + "o e", + "Re f", + "R ef", + "▁net work", + "▁ network", + "par ent", + "pa rent", + "pare nt", + "paren t", + "p arent", + "ug e", + "u ge", + "▁sim ilar", + "> \r", + "Build er", + "B uilder", + "▁l iving", + "▁li ving", + "▁liv ing", + "▁contin ue", + "▁continu e", + "▁ continue", + "an ger", + "ang er", + "ange r", + "▁R ed", + "▁Re d", + "▁ Red", + "▁h air", + "▁ha ir", + "an ced", + "ance d", + "anc ed", + "ia ns", + "ian s", + "i ans", + "▁d ead", + "▁de ad", + "▁ dead", + "▁bo olean", + "▁ boolean", + "ic ation", + "▁д е", + "▁ де", + "▁cl ient", + "▁ client", + "uc t", + "u ct", + "▁ •", + "S P", + "ol der", + "old er", + "п е", + "ud io", + "udi o", + "▁d eg", + "▁de g", + "▁ deg", + "as ing", + "asi ng", + "a sing", + "▁st ep", + "▁ste p", + "▁ step", + "▁p ers", + "▁per s", + "▁pe rs", + "▁ pers", + "ç ão", + "ob j", + "o z", + "ul a", + "u la", + "▁r ound", + "▁ro und", + "▁rou nd", + "▁ round", + "▁u pon", + "▁up on", + "▁re source", + "▁res ource", + "▁ resource", + "▁val id", + "▁ valid", + "▁I I", + "▁ II", + "bu g", + "b ug", + "st d", + "s td", + "▁a ng", + "▁an g", + "▁ ang", + "sp an", + "s pan", + "po l", + "p ol", + "ial og", + "ia log", + "▁p hot", + "▁ph ot", + "? '", + "D B", + "▁F in", + "▁Fi n", + "▁ Fin", + "V E", + "E m", + "▁c am", + "▁ca m", + "▁ cam", + "tar get", + "t arget", + "pe cted", + "pect ed", + "pec ted", + "He l", + "H el", + "▁u t", + "▁ ut", + "▁T est", + "▁Te st", + "▁Tes t", + "▁ Test", + "▁t own", + "▁to wn", + "▁tow n", + "▁ town", + "al ign", + "ali gn", + "▁we bs", + "▁web s", + "in ner", + "inn er", + "au gh", + "aug h", + "a ugh", + "▁ex cept", + "▁ except", + "▁init ial", + "▁initi al", + "▁ initial", + "en ty", + "ent y", + "lic h", + "li ch", + "l ich", + "▁A ut", + "▁Au t", + "▁ Aut", + "to p", + "t op", + "▁f ail", + "▁fa il", + "▁ fail", + "on a", + "o na", + "▁ben ef", + "an ks", + "ank s", + "is che", + "isch e", + "isc he", + "i sche", + ". *", + "▁sign ific", + "▁cont act", + "▁ contact", + "Re c", + "R ec", + "ar io", + "ari o", + "a rio", + "ot tom", + "ott om", + "otto m", + "▁rel ationship", + "▁relations hip", + "▁relation ship", + "]) ;", + "] );", + "▁Н а", + "▁ На", + "He ad", + "H ead", + "form at", + "for mat", + "▁é t", + "▁ ét", + "▁M ore", + "▁Mor e", + "▁Mo re", + "▁ More", + "act ory", + "actor y", + "port un", + "+ \\", + "▁sim ply", + "▁simpl y", + "▁e p", + "▁ ep", + "▁R uss", + "▁Ru ss", + "▁Rus s", + "n í", + "u a", + "er c", + "e rc", + "▁long er", + "▁lon ger", + "in ition", + "init ion", + "ect or", + "ec tor", + "e ctor", + "apt ion", + "a ption", + "▁prof ess", + "▁profes s", + "▁M us", + "▁Mu s", + "▁ Mus", + "il ities", + "ili ties", + "è s", + "▁A ct", + "▁Ac t", + "▁ Act", + "off set", + "offs et", + "▁i ll", + "▁il l", + "▁ ill", + "ba nd", + "ban d", + "b and", + "▁A g", + "▁ Ag", + "▁П о", + "▁ По", + "б и", + "cont ent", + "ic on", + "ico n", + "i con", + "▁work s", + "▁wor ks", + "▁ works", + "yn am", + "yna m", + "y nam", + "pl ement", + "ple ment", + "p lement", + "Res ource", + "Re source", + "Act ion", + "A ction", + "▁diff icult", + "▁W est", + "▁We st", + "▁Wes t", + "▁ West", + "▁v ideo", + "▁vide o", + "▁ video", + "▁T HE", + "▁TH E", + "▁ THE", + "▁de cl", + "▁dec l", + "▁ decl", + "on don", + "ond on", + "ondo n", + "de d", + "d ed", + "}{ \\", + "} {\\", + "oc r", + "o cr", + "▁C ity", + "▁Cit y", + "▁Ci ty", + "▁ City", + "▁ я", + "ue r", + "u er", + "c z", + "▁im ag", + "▁i mag", + "▁ imag", + "c r", + "et e", + "e te", + "id get", + "idge t", + "▁M od", + "▁Mo d", + "▁ Mod", + "▁for ward", + "▁ forward", + "▁p ict", + "▁pi ct", + "▁pic t", + "or ge", + "org e", + "▁sub ject", + "▁ subject", + "up date", + "at tle", + "att le", + "s a", + "▁A nt", + "▁An t", + "▁ Ant", + "▁r unning", + "▁run ning", + "▁ running", + "▁s al", + "▁sa l", + "▁ sal", + "con ne", + "conn e", + "c onne", + "▁out put", + "▁ output", + "ad ata", + "ada ta", + "a data", + "M L", + "Che ck", + "C heck", + "led ge", + "l edge", + "▁p aper", + "▁pa per", + "▁pap er", + "▁ paper", + "param s", + "par ams", + "para ms", + "av y", + "a vy", + "▁a f", + "▁ af", + "▁e ine", + "▁ein e", + "▁j our", + "▁jo ur", + "▁jou r", + "▁ jour", + "A Y", + "▁it self", + "▁its elf", + "▁S tr", + "▁St r", + "▁ Str", + "st yle", + "sty le", + "Th at", + "T hat", + "▁m illion", + "▁mill ion", + "▁l anguage", + "▁ language", + "O S", + "vi ng", + "vin g", + "v ing", + "▁м а", + "▁ ма", + "▁т о", + "▁ то", + ") (", + "▁b uy", + "▁bu y", + ". /", + "▁. ..", + "▁.. .", + "▁ ...", + "▁t ried", + "▁tr ied", + "▁tri ed", + "▁com pl", + "▁comp l", + "▁act iv", + "▁ activ", + "ap ped", + "app ed", + "appe d", + "a pped", + "But ton", + "B utton", + "To ken", + "Tok en", + "T oken", + "▁prov ided", + "▁provide d", + "ib er", + "ibe r", + "i ber", + "▁c reated", + "▁cre ated", + "▁create d", + "▁creat ed", + "▁ created", + "cur ity", + "c urity", + "En d", + "E nd", + "a ł", + "us ter", + "ust er", + "u ster", + "iz ing", + "izi ng", + "i zing", + "om b", + "o mb", + "▁s ich", + "▁si ch", + "▁com pon", + "▁comp on", + "▁S ee", + "▁Se e", + "▁ See", + "▁u int", + "▁ui nt", + "▁ uint", + "▁l abel", + "▁la bel", + "▁lab el", + "▁ label", + "vo l", + "v ol", + "ó w", + "oc ol", + "oco l", + "o col", + "▁re ceived", + "▁rece ived", + "▁receive d", + "▁in tern", + "▁int ern", + "▁inter n", + "▁inte rn", + "▁ intern", + "ц е", + "R un", + "▁r oad", + "▁ro ad", + "▁ road", + "▁O ct", + "▁ Oct", + "▁C omp", + "▁Com p", + "▁Co mp", + "▁ Comp", + "▁stud y", + "▁т е", + "▁ те", + "Ac t", + "A ct", + "▁t our", + "▁to ur", + "▁tou r", + "▁St ate", + "▁Stat e", + "▁Sta te", + "▁ State", + "▁ad ded", + "▁add ed", + "▁ added", + "htt ps", + "http s", + "st ream", + "stre am", + "▁l ower", + "▁lo wer", + "▁low er", + "▁ lower", + "▁b ox", + "▁bo x", + "▁ box", + "▁S k", + "▁ Sk", + "▁them selves", + "▁c ross", + "▁cr oss", + "▁cro ss", + "▁ cross", + "▁e cho", + "▁ec ho", + "▁ echo", + "▁dev ice", + "▁ device", + "pos e", + "po se", + "p ose", + "▁g ames", + "▁game s", + "▁gam es", + "▁ga mes", + "P L", + "W indow", + "is es", + "ise s", + "i ses", + "ti tle", + "tit le", + "t itle", + "St ream", + "z t", + "▁S w", + "▁ Sw", + "▁r ole", + "▁ro le", + "▁ role", + "ia nt", + "ian t", + "i ant", + "k u", + "se qu", + "seq u", + "s equ", + "▁l ate", + "▁la te", + "▁lat e", + "▁ late", + "▁s old", + "▁so ld", + "▁sol d", + "р я", + "Com m", + "Co mm", + "C omm", + "▁en tre", + "▁ent re", + "▁entr e", + "▁ entre", + "▁d og", + "▁do g", + "▁ dog", + "dev ice", + "P ar", + "▁like ly", + "▁lik ely", + "▁ likely", + "^{ -", + "^ {-", + "▁l en", + "▁le n", + "▁ len", + "▁P aul", + "▁Pa ul", + "▁ Paul", + "▁t ool", + "▁to ol", + "▁too l", + "▁ tool", + "Of f", + "O ff", + "▁f amil", + "▁fam il", + "▁fa mil", + "▁d raw", + "▁dr aw", + "▁ draw", + "ap ping", + "app ing", + "a pping", + "▁ev ents", + "▁even ts", + "▁event s", + "▁ events", + "cre t", + "cr et", + "c ret", + "rou ght", + "rough t", + "r ought", + "Cont ent", + "▁soft ware", + "ri a", + "r ia", + "ms g", + "m sg", + "ga mma", + "g amma", + "▁h ear", + "▁he ar", + "Op er", + "O per", + "▁your self", + "▁yours elf", + "▁l iter", + "▁li ter", + "▁lit er", + "▁ liter", + "em p", + "e mp", + "▁se par", + "▁sep ar", + "▁ separ", + "▁ З", + "▁t itle", + "▁tit le", + "▁ti tle", + "▁ title", + "M ethod", + "math rm", + "▁s low", + "▁sl ow", + "▁R om", + "▁Ro m", + "▁ Rom", + "! !", + "▁t ax", + "▁ta x", + "▁ tax", + "ск а", + "с ка", + "empl ate", + "emp late", + "o i", + "▁A rt", + "▁Ar t", + "▁ Art", + "f alse", + "ast ic", + "ст ь", + "с ть", + "oc ket", + "ock et", + "▁e ns", + "▁en s", + "▁ ens", + "T O", + "am ente", + "ame nte", + "ament e", + "amen te", + "a mente", + "lo cal", + "loc al", + "l ocal", + "ch ie", + "chi e", + "▁p an", + "▁pa n", + "▁ pan", + "ни й", + "ch ema", + "che ma", + "chem a", + "▁N orth", + "▁Nor th", + "▁Nort h", + "з о", + "▁> =", + "▁ >=", + "A ut", + "▁d ig", + "▁di g", + "▁ dig", + "▁se ems", + "▁see ms", + "▁seem s", + "▁mor ning", + "so le", + "sol e", + "s ole", + "um er", + "ume r", + "u mer", + "del ta", + "d elta", + "it é", + "i té", + "ab ase", + "aba se", + "a base", + "ra f", + "r af", + "▁ob serv", + "▁obs erv", + "▁ observ", + "▁E st", + "▁Es t", + "▁ Est", + "▁s eg", + "▁se g", + "▁ seg", + "▁[ ]", + "▁ []", + "▁P res", + "▁Pr es", + "▁Pre s", + "▁ Pres", + "if ul", + "i ful", + "pu sh", + "pus h", + "p ush", + "▁O ff", + "▁Of f", + "▁ Off", + "ip e", + "i pe", + "at i", + "a ti", + "▁d im", + "▁di m", + "▁ dim", + "ce ed", + "c eed", + "En t", + "E nt", + "__ __", + "___ _", + "_ ___", + "en try", + "ent ry", + "entr y", + "▁f ight", + "▁fig ht", + "▁fi ght", + "▁c red", + "▁cre d", + "▁cr ed", + "▁ cred", + "▁O R", + "▁ OR", + "▁D ep", + "▁De p", + "▁ Dep", + "$ {", + "ле н", + "л ен", + "Creat e", + "C reate", + "▁Apr il", + "▁Ap ril", + "min istr", + "F L", + "▁A p", + "▁ Ap", + "▁H ere", + "▁He re", + "▁Her e", + "▁ Here", + "priv ate", + "p rivate", + "In stance", + "Inst ance", + "ie m", + "i em", + "▁off ice", + "▁offic e", + "▁th ird", + "▁ third", + "▁up date", + "▁ update", + "Lin e", + "Li ne", + "L ine", + "ta g", + "t ag", + "▁e specially", + "▁espec ially", + "▁especial ly", + "▁ especially", + "▁го да", + "▁год а", + "▁c u", + "▁ cu", + "▁k ill", + "▁kil l", + "▁ki ll", + "▁ kill", + "au ght", + "augh t", + "aug ht", + "▁s we", + "▁sw e", + "Option s", + "Opt ions", + "O ptions", + "I M", + "C C", + "▁com pan", + "▁comp an", + "ju st", + "j ust", + "▁Wh ile", + "▁ While", + "iz er", + "ize r", + "i zer", + "▁м о", + "▁ мо", + "к е", + "▁a uto", + "▁aut o", + "▁au to", + "▁ auto", + "▁b and", + "▁ban d", + "▁ba nd", + "▁ band", + "ме н", + "м ен", + "ique s", + "iqu es", + "iq ues", + "i ques", + "▁p le", + "▁pl e", + "▁ ple", + "N O", + "▁O F", + "▁ OF", + "▁s ong", + "▁so ng", + "▁son g", + "▁A cc", + "▁Ac c", + "▁ Acc", + "EX T", + "E XT", + "en sor", + "ens or", + "enso r", + "in ing", + "ini ng", + "i ning", + "▁l at", + "▁la t", + "▁ lat", + "bi g", + "b ig", + "▁K ing", + "▁Ki ng", + "▁Kin g", + "▁ King", + "oc h", + "o ch", + "s i", + "▁H ist", + "▁His t", + "▁Hi st", + "▁ Hist", + "▁qu ality", + "▁qual ity", + "▁ quality", + "mod e", + "mo de", + "m ode", + "▁op portun", + "▁would n", + ":* *", + ": **", + "out put", + "▁fe et", + "▁fee t", + "▁m is", + "▁mi s", + "d f", + "ag ing", + "agi ng", + "a ging", + "▁м е", + "▁ ме", + "▁t ro", + "▁tr o", + "▁d efined", + "▁def ined", + "▁define d", + "▁defin ed", + "▁ defined", + "▁re view", + "▁rev iew", + "▁ review", + "▁F il", + "▁Fi l", + "▁ Fil", + "> >", + "▁pr incip", + "▁prin cip", + "Bas e", + "B ase", + "di ct", + "d ict", + "ve rage", + "ver age", + "ic ient", + "ici ent", + "I F", + "▁h it", + "▁hi t", + "▁ hit", + "Pag e", + "P age", + "▁p erm", + "▁per m", + "▁pe rm", + "▁ perm", + "ce l", + "c el", + "í t", + "▁ex press", + "▁exp ress", + "▁expr ess", + "▁ express", + "▁ind ic", + "▁Se ptember", + "▁Sept ember", + "im age", + "ima ge", + "imag e", + "▁product s", + "▁ products", + "▁m edia", + "▁med ia", + "▁medi a", + "▁ media", + "ch ange", + "chan ge", + "ig ger", + "igg er", + "▁s end", + "▁se nd", + "▁sen d", + "▁ send", + "la st", + "las t", + "l ast", + "min g", + "mi ng", + "m ing", + "p a", + "ua ry", + "uar y", + "u ary", + "▁spe ak", + "ны й", + "щ е", + "ys is", + "y sis", + "ly ing", + "l ying", + "▁ ч", + "li ke", + "lik e", + "l ike", + "р ы", + "в і", + "▁M ich", + "▁Mic h", + "▁Mi ch", + "M O", + "▁J ah", + "▁Ja h", + "ens ive", + "▁sh are", + "▁shar e", + "▁sha re", + "▁ share", + "▁develop ment", + "C P", + "sp ec", + "spe c", + "s pec", + "▁f ast", + "▁fa st", + "▁ fast", + "he t", + "h et", + "H O", + "▁part icip", + "▁partic ip", + "▁parti cip", + "Bl ock", + "Blo ck", + "B lock", + "▁vi ol", + "▁fr ame", + "▁fra me", + "▁fram e", + "▁ frame", + "▁qu al", + "▁q ual", + "▁ qual", + "tr e", + "t re", + "▁ Ф", + "▁to ward", + "▁tow ard", + "f g", + "Bo x", + "B ox", + "Col umn", + "▁mil it", + "▁mi lit", + "▁M arch", + "▁Mar ch", + "▁Marc h", + "▁var ious", + "▁vari ous", + "pa ss", + "pas s", + "p ass", + "▁P ark", + "▁Par k", + "▁B en", + "▁Be n", + "▁ Ben", + "Fr ame", + "▁n ormal", + "▁nor mal", + "▁norm al", + "▁ normal", + "op en", + "ope n", + "o pen", + "p x", + "▁ph one", + "▁ phone", + "▁E ven", + "▁Ev en", + "▁Eve n", + "▁ Even", + "▁m a", + "▁ ma", + "ibr ary", + "St art", + "Star t", + "id den", + "idd en", + "rh o", + "r ho", + "gr aph", + "gra ph", + "g raph", + "ac ing", + "aci ng", + "a cing", + "' .", + "ar ter", + "art er", + "arte r", + "me s", + "m es", + "in st", + "ins t", + "▁i r", + "▁ ir", + "act ive", + "activ e", + "▁f em", + "▁fe m", + "▁ fem", + "▁m oved", + "▁mov ed", + "▁move d", + "▁mo ved", + "▁st ore", + "▁stor e", + "▁sto re", + "▁ store", + "▁p rice", + "▁pr ice", + "▁pri ce", + "▁ price", + "\") .", + "\" ).", + "ber g", + "be rg", + "b erg", + "▁n ov", + "▁no v", + "▁ nov", + "▁c ard", + "▁car d", + "▁ca rd", + "▁ card", + "el low", + "ell ow", + "ello w", + "▁part y", + "▁par ty", + "▁ party", + "▁M or", + "▁Mo r", + "ae l", + "a el", + "▁per cent", + "▁ percent", + "▁tr aining", + "▁tra ining", + "▁train ing", + "▁ training", + "▁in g", + "▁i ng", + "▁ ing", + "im er", + "ime r", + "i mer", + "▁S am", + "▁Sa m", + "▁ Sam", + "Def ault", + "▁f uck", + "▁fu ck", + "▁com plete", + "▁comp lete", + "▁complet e", + "▁compl ete", + "▁ complete", + "ui d", + "u id", + "▁det ails", + "▁detail s", + "▁ details", + "▁l ed", + "▁le d", + "▁ led", + "Po int", + "P oint", + "▁C ount", + "▁Co unt", + "▁Coun t", + "▁Cou nt", + "▁ Count", + "▁reg ard", + "z o", + "▁B ro", + "▁Br o", + "▁ Bro", + "▁rec ogn", + "▁ recogn", + "▁H ol", + "▁Ho l", + "▁ Hol", + "U M", + "el ement", + "ele ment", + "elem ent", + "e lement", + "Mod e", + "Mo de", + "M ode", + "▁ex am", + "▁E X", + "▁ EX", + "Im age", + "ver se", + "vers e", + "ri ter", + "rit er", + "rite r", + "r iter", + "so ft", + "s oft", + "▁int rodu", + "▁intro du", + "▁sur pr", + "Buf fer", + "Buff er", + "B uffer", + "le ctor", + "lect or", + "l ector", + "ar en", + "are n", + "a ren", + "an ged", + "ang ed", + "ange d", + "▁P at", + "▁Pa t", + "▁ Pat", + "▁P al", + "▁Pa l", + "▁ Pal", + "▁con tr", + "▁cont r", + "▁ contr", + "Hand ler", + "Handle r", + "▁fe atures", + "▁feature s", + "▁feat ures", + "▁ features", + "ip le", + "i ple", + "▁C ON", + "▁CO N", + "▁ CON", + "Fi l", + "F il", + "▁P ort", + "▁Po rt", + "▁Por t", + "▁ Port", + "▁th inking", + "▁think ing", + "▁thin king", + "do c", + "d oc", + "we r", + "w er", + "▁work ed", + "▁wor ked", + "P C", + "c m", + "da t", + "d at", + "PR O", + "P RO", + "▁E very", + "▁Ev ery", + "▁Ever y", + "▁Eve ry", + "▁ Every", + "▁e ra", + "▁er a", + "▁ era", + "▁F irst", + "▁ First", + "g n", + "▁im medi", + "▁imm edi", + "ov ember", + "ove mber", + "ap an", + "apa n", + "a pan", + "▁ex tra", + "▁ext ra", + "▁extr a", + "▁ extra", + "▁s ection", + "▁se ction", + "▁sect ion", + "▁ section", + "▁J une", + "▁Jun e", + "▁Ju ne", + "▁v ia", + "▁vi a", + "▁ via", + "▁g one", + "▁go ne", + "com e", + "co me", + "c ome", + "▁s tri", + "▁st ri", + "▁str i", + "▁ stri", + "^ \\", + "ant ly", + "▁ar ch", + "▁arc h", + "▁ arch", + "S ource", + "▁con v", + "▁co nv", + "▁ conv", + "▁L ondon", + "▁Lond on", + "▁ London", + "Num ber", + "N umber", + "▁quest ions", + "▁question s", + "an did", + "and id", + "▁play ed", + "en v", + "e nv", + "▁Sch ool", + "▁nat ural", + "▁natur al", + "▁ natural", + "ca n", + "c an", + "▁ne ws", + "▁new s", + "▁ news", + "D R", + "▁c hall", + "▁ch all", + "▁cha ll", + "▁S oc", + "▁So c", + "▁ э", + "▁att empt", + "* }", + "N ull", + "ro te", + "rot e", + "r ote", + "▁b i", + "▁ bi", + "▁wr itten", + "▁writ ten", + "▁ written", + "▁bl ood", + "▁blo od", + "▁happ ened", + "▁happen ed", + "▁c ause", + "▁caus e", + "▁ca use", + "as hing", + "ash ing", + "ashi ng", + "▁Will iam", + "ad em", + "ade m", + "a dem", + "▁b rought", + "▁br ought", + "▁dis play", + "▁displ ay", + "▁disp lay", + "▁ display", + "im a", + "i ma", + "▁fin ally", + "▁final ly", + "ta b", + "t ab", + "▁return ed", + "ны х", + "ni e", + "n ie", + "▁ q", + "▁h ers", + "▁he rs", + "▁her s", + "▁P re", + "▁Pr e", + "▁ Pre", + "▁d ou", + "▁do u", + "buf fer", + "buff er", + "b uffer", + "▁eff ort", + "ain e", + "ai ne", + "a ine", + "x y", + "▁his tor", + "▁hist or", + "en u", + "e nu", + "▁ar riv", + "▁arr iv", + "▁D em", + "▁De m", + "▁ Dem", + "▁f avor", + "▁fa vor", + "▁fav or", + "▁hand le", + "▁ handle", + "SE T", + "S ET", + "▁P ublic", + "▁Pub lic", + "▁Pu blic", + "▁ Public", + "ru pt", + "rup t", + "r upt", + "▁u r", + "▁ ur", + "▁for ce", + "▁ force", + "▁é s", + "▁ és", + "ub e", + "u be", + "Pr e", + "P re", + "р і", + "in y", + "i ny", + "th eta", + "the ta", + "is f", + "i sf", + "▁n ational", + "▁nat ional", + "▁nation al", + "Equ al", + "Eq ual", + "E qual", + "ren ch", + "▁w ife", + "▁c apt", + "▁cap t", + "▁ca pt", + "▁In ter", + "▁Int er", + "▁ Inter", + "ta u", + "t au", + "▁s leep", + "▁sle ep", + "▁ sleep", + "../ ../", + "▁iss ue", + "▁ issue", + "▁m ember", + "▁me mber", + "▁mem ber", + "▁ member", + "▁a wait", + "▁aw ait", + "▁ await", + "▁D an", + "▁Da n", + "▁ Dan", + "z i", + "in ate", + "ina te", + "i nate", + "▁s ym", + "▁sy m", + "▁ sym", + "ch an", + "cha n", + "c han", + "▁J ack", + "▁Jac k", + "▁Ja ck", + "▁ Jack", + "▁Eng lish", + "▁ English", + "▁s z", + "▁ sz", + "rib utes", + "ribut es", + "ribute s", + "ribu tes", + "▁i gn", + "▁ig n", + "▁ ign", + "á l", + "▁app ear", + "▁appe ar", + "ra d", + "r ad", + "id ge", + "▁co uple", + "▁cou ple", + "▁coup le", + "▁s hip", + "▁sh ip", + "▁ ship", + "li g", + "l ig", + "we b", + "w eb", + "▁us ually", + "▁usual ly", + "▁re ady", + "▁read y", + "▁ ready", + "▁v ill", + "▁vi ll", + "▁vil l", + "▁W hy", + "▁Wh y", + "▁ Why", + "eb ru", + "e bru", + "▁g rad", + "▁gr ad", + "▁gra d", + "▁ grad", + "or ds", + "ord s", + "▁in f", + "▁i nf", + "▁ inf", + "▁l oss", + "▁lo ss", + "▁los s", + "▁ loss", + "▁o d", + "▁ od", + "▁Ph il", + "▁ Phil", + "ser ver", + "serv er", + "serve r", + "▁U p", + "▁ Up", + "▁b uff", + "▁bu ff", + "▁buf f", + "▁ buff", + "▁fil ename", + "▁file name", + "▁ filename", + "AB LE", + "it ing", + "iti ng", + "i ting", + "ef ore", + "e fore", + "() ->", + "( )->", + "▁cond itions", + "▁condition s", + "▁ conditions", + "v m", + "el d", + "e ld", + "it z", + "i tz", + "▁Tr ans", + "▁Tra ns", + "▁ Trans", + "▁w eight", + "▁we ight", + "▁weigh t", + "▁ weight", + "▁high er", + "▁hig her", + "▁r ate", + "▁rat e", + "▁ra te", + "▁ rate", + "▁acc om", + "▁ac com", + "vi der", + "vid er", + "v ider", + "O M", + "▁w ays", + "▁way s", + "▁wa ys", + "▁ ways", + "com ing", + "co ming", + "c oming", + "▁l ock", + "▁loc k", + "▁lo ck", + "▁ lock", + "▁e tc", + "▁et c", + "▁ etc", + "▁a vec", + "▁av ec", + "▁ave c", + "▁t akes", + "▁take s", + "▁tak es", + "▁ta kes", + "▁C har", + "▁Ch ar", + "▁Cha r", + "▁ Char", + "▁N ovember", + "▁Nov ember", + "m ethod", + "▁A ustral", + "▁Aust ral", + "▁ Austral", + "▁Amer ica", + "▁ America", + "lo ng", + "lon g", + "l ong", + "ce mber", + "c ember", + "▁polit ical", + "fl ow", + "f low", + "▁may be", + "▁ maybe", + "▁a mb", + "▁am b", + "▁ amb", + "La yout", + "L ayout", + "il ed", + "ile d", + "i led", + "om en", + "ome n", + "o men", + "ol a", + "o la", + "ic ip", + "ici p", + "i cip", + "part ial", + "Tr ue", + "▁f loor", + "▁fl oor", + "▁flo or", + "▁ floor", + "▁D ef", + "▁De f", + "▁ Def", + "▁conc ern", + "▁conce rn", + "▁concer n", + "y r", + "▁sh ows", + "▁show s", + "i h", + "▁an swer", + "▁answ er", + "▁ans wer", + "▁ answer", + "ac c", + "a cc", + "▁b all", + "▁bal l", + "▁ba ll", + "▁ ball", + "▁R ev", + "▁Re v", + "▁ Rev", + "▁s un", + "▁su n", + "▁ sun", + "▁quick ly", + "▁s omet", + "▁so met", + "▁some t", + "▁som et", + "ment e", + "me nte", + "men te", + "m ente", + "▁M al", + "▁Ma l", + "▁ Mal", + "und red", + "▁iss ues", + "▁issue s", + "▁ issues", + "ec ause", + "eca use", + "pe s", + "p es", + "▁p layer", + "▁pl ayer", + "▁play er", + "▁ player", + "▁par ents", + "▁parent s", + "▁ parents", + "▁pop ular", + "▁popula r", + "▁popul ar", + "▁m ode", + "▁mod e", + "▁mo de", + "▁ mode", + "▁m ention", + "▁ment ion", + "N E", + "Lo ad", + "L oad", + "▁reg ular", + "▁regul ar", + "▁ regular", + "ave d", + "av ed", + "a ved", + "? :", + "ye ar", + "y ear", + "fun c", + "fu nc", + "f unc", + "▁per formance", + "▁perform ance", + "▁J uly", + "▁Jul y", + "▁Ju ly", + "th ern", + "ther n", + "the rn", + "▁we bsite", + "▁webs ite", + "▁web site", + "fo rd", + "for d", + "f ord", + "P R", + "el a", + "e la", + "le vel", + "lev el", + "l evel", + "ui t", + "u it", + "fl ags", + "flag s", + "▁w orth", + "▁wor th", + "▁ worth", + "▁cor respon", + "▁Brit ish", + "si m", + "s im", + "▁al one", + "▁ alone", + "▁h ar", + "▁ha r", + "▁ har", + "▁o nes", + "▁on es", + "▁one s", + "▁ ones", + "ob ile", + "obi le", + "obil e", + "▁d ru", + "▁dr u", + "▁ dru", + "ch i", + "c hi", + "▁D avid", + "▁Dav id", + "▁Da vid", + "▁ David", + "▁proble ms", + "▁problem s", + "▁col umn", + "▁ column", + "() ;\r", + "(); \r", + "( );\r", + "Z E", + "▁re lig", + "▁rel ig", + "▁reli g", + "olog ical", + "▁reg ion", + "▁ region", + "ad y", + "a dy", + "I O", + "an der", + "and er", + "ande r", + "a nder", + "Ne t", + "N et", + "▁bu ilt", + "▁ built", + "▁inst all", + "▁ install", + "▁appro ach", + "C ur", + "▁f ine", + "▁fin e", + "▁fi ne", + "▁talk ing", + "▁tal king", + "▁ch anges", + "▁chang es", + "▁change s", + "▁ changes", + "St yle", + "▁M art", + "▁Mar t", + "▁Ma rt", + "▁ Mart", + "л ю", + "res ponse", + "respon se", + "respons e", + "te ger", + "{ \r", + "ir it", + "iri t", + "i rit", + "▁prote cted", + "▁protect ed", + "▁ protected", + "▁re le", + "▁r ele", + "▁rel e", + "er ship", + "ers hip", + "те ль", + "тел ь", + "un signed", + "uns igned", + "ial ize", + "▁htt ps", + "▁http s", + "▁ https", + "T ag", + "▁$ (", + "▁ $(", + "mo re", + "mor e", + "m ore", + "ype s", + "yp es", + "y pes", + "▁st ream", + "▁stre am", + "▁ stream", + "et ch", + "etc h", + "▁eng ine", + "▁ engine", + "K E", + "cm d", + "c md", + "sc ript", + "scri pt", + "scr ipt", + "s cript", + "tt p", + "t tp", + "▁a void", + "▁av oid", + "▁t err", + "▁te rr", + "▁ter r", + "▁r ock", + "▁ro ck", + "▁ rock", + "▁f ul", + "▁fu l", + "▁ ful", + "Up date", + "▁env ironment", + "▁environ ment", + "▁ environment", + "▁p rec", + "▁pre c", + "▁pr ec", + "▁ prec", + "▁с а", + "▁ са", + "▁c ases", + "▁case s", + "▁cas es", + "▁ca ses", + "▁ cases", + "▁off set", + "▁ offset", + "▁r ais", + "▁ra is", + "▁ rais", + "li b", + "l ib", + "ée s", + "é es", + "a a", + "y t", + "▁a rr", + "▁ar r", + "▁ arr", + "opy right", + "f irst", + "▁u til", + "▁ut il", + "▁ util", + "▁fe ature", + "▁feat ure", + "▁ feature", + "pos ed", + "po sed", + "pose d", + "p osed", + "ff ect", + "f fect", + "ж а", + "it ude", + "itu de", + "itud e", + "em ents", + "ement s", + "emen ts", + "e ments", + "as c", + "a sc", + "ad or", + "ado r", + "le ctions", + "lect ions", + "lection s", + "▁cl ub", + "▁ club", + "] {", + "▁* )", + "▁ *)", + "ст во", + "ств о", + "с тво", + "▁im m", + "▁i mm", + "▁ imm", + "▁for mer", + "▁form er", + "▁forme r", + "▁ former", + "▁r ights", + "▁right s", + "▁dec ided", + "▁decide d", + "▁decid ed", + "▁re v", + "▁r ev", + "▁ rev", + "▁m ent", + "▁me nt", + "▁men t", + "▁ ment", + "an i", + "a ni", + "▁st ru", + "▁str u", + "▁ stru", + "▁att ention", + "art ment", + "▁I tal", + "▁It al", + "al le", + "all e", + "a lle", + "▁b is", + "▁bi s", + "▁ bis", + "ge ner", + "gen er", + "g ener", + "▁in tegr", + "▁int egr", + "▁inte gr", + "▁ integr", + "el lo", + "ell o", + "ry pt", + "▁a chie", + "ne s", + "n es", + "▁s tra", + "▁st ra", + "▁str a", + "▁ stra", + "s b", + "▁t ypes", + "▁type s", + "▁typ es", + "▁ty pes", + "▁ types", + "▁R E", + "▁ RE", + "In it", + "I nit", + "▁com ment", + "▁comm ent", + "▁comme nt", + "▁ comment", + "▁add ition", + "▁I D", + "▁ ID", + "AR T", + "A RT", + "F O", + "щ и", + "Con ne", + "Conn e", + "C onne", + "▁s qu", + "▁sq u", + "▁consider ed", + "▁consid ered", + "id ad", + "ida d", + "▁Oct ober", + "ci al", + "cia l", + "c ial", + "▁O f", + "▁ Of", + "▁tr avel", + "▁tra vel", + "▁trav el", + "▁b oy", + "▁bo y", + "▁ boy", + "') .", + "' ).", + "u y", + "il la", + "ill a", + "i lla", + "is try", + "ist ry", + "istr y", + "▁v a", + "▁ va", + "▁C he", + "▁Ch e", + "▁ Che", + "ER T", + "E RT", + "en de", + "end e", + "e nde", + "un gen", + "ung en", + "unge n", + "ab y", + "a by", + "▁R ober", + "▁Ro ber", + "▁Rob er", + "▁play ing", + "il s", + "i ls", + "▁s am", + "▁sa m", + "▁ sam", + "▁ex ecut", + "▁exec ut", + "▁ execut", + "▁U s", + "▁ Us", + "▁m ut", + "▁mu t", + "▁ mut", + "▁b al", + "▁ba l", + "▁ bal", + "as se", + "ass e", + "▁k ids", + "▁kid s", + "▁ki ds", + "▁fin anc", + "go r", + "g or", + "▁S ec", + "▁Se c", + "▁ Sec", + "ber t", + "be rt", + "b ert", + "▁H igh", + "▁Hig h", + "▁Hi gh", + "▁ High", + "▁ је", + "▁ke pt", + "but ton", + "b utton", + "it ory", + "itor y", + "ito ry", + "▁R em", + "▁Re m", + "▁ Rem", + "▁D E", + "▁ DE", + "▁re ach", + "▁r each", + "▁ reach", + "▁b ur", + "▁bu r", + "▁ bur", + "La bel", + "L abel", + "á t", + "ag o", + "a go", + "▁pass ed", + "▁pas sed", + "▁be hav", + "▁beh av", + "xF F", + "x FF", + "▁R eturn", + "▁Re turn", + "▁Ret urn", + "▁ Return", + "ST R", + "S TR", + "▁L es", + "▁Le s", + "▁ Les", + "▁o rd", + "▁or d", + "▁ ord", + "al a", + "a la", + "in ger", + "ing er", + "inge r", + "▁S ince", + "▁Sin ce", + "▁ Since", + "▁exper i", + "▁exp eri", + "▁s hall", + "▁sh all", + "▁sha ll", + "▁ shall", + "▁s tar", + "▁st ar", + "▁sta r", + "▁ star", + "no n", + "n on", + "▁g un", + "▁gu n", + "▁ gun", + "▁B el", + "▁Be l", + "▁ Bel", + "▁ob j", + "▁ obj", + "ar es", + "are s", + "a res", + "r s", + "▁we eks", + "▁week s", + "ne n", + "n en", + "▁S tre", + "▁St re", + "▁Str e", + "or ing", + "ori ng", + "o ring", + "▁ î", + "▁ser ious", + "time s", + "ti mes", + "tim es", + "t imes", + "▁H ouse", + "▁Ho use", + "▁Hou se", + "▁r oll", + "▁ro ll", + "▁ roll", + "▁reg ister", + "▁ register", + "▁mod ule", + "▁mo dule", + "▁ module", + "▁app lic", + "▁ap plic", + "▁appl ic", + "I R", + "▁c ook", + "▁co ok", + "▁ cook", + "au x", + "a ux", + "▁s ave", + "▁sa ve", + "▁sav e", + "▁ save", + "▁C r", + "▁ Cr", + ", \r", + "▁st ates", + "▁stat es", + "▁state s", + "▁sta tes", + "▁ states", + "▁em pty", + "▁emp ty", + "▁empt y", + "▁ empty", + "▁aut om", + "▁au tom", + "▁auto m", + "▁ autom", + "fig ure", + "ian ce", + "i ance", + "▁h appy", + "▁happ y", + "▁f n", + "▁ fn", + "▁j ud", + "▁ju d", + "▁ jud", + "▁h at", + "▁ha t", + "▁ hat", + "AC K", + "A CK", + "▁F e", + "▁ Fe", + "$ -", + "iv il", + "ivi l", + "i vil", + "ot ed", + "ote d", + "o ted", + "▁size of", + "▁ sizeof", + "▁sit uation", + "▁situ ation", + "▁l ives", + "▁li ves", + "▁live s", + "▁liv es", + "▁fe eling", + "▁feel ing", + "▁fee ling", + "▁r isk", + "▁ri sk", + "▁ris k", + "▁Jan uary", + "▁Januar y", + "▁Ob ject", + "▁ Object", + "▁re comm", + "▁rec omm", + "▁в ы", + "▁ вы", + "▁pot ential", + "ea h", + "e ah", + "▁com plex", + "▁comp lex", + "▁compl ex", + "▁ complex", + "print f", + "ist ance", + "istan ce", + "i stance", + "ir th", + "irt h", + "li k", + "l ik", + "as te", + "ast e", + "a ste", + "▁wh ose", + "▁who se", + "Ar g", + "A rg", + "▁mod ern", + "▁mo dern", + "▁mode rn", + "▁moder n", + "ion es", + "io nes", + "ione s", + "i ones", + "▁ч е", + "▁ че", + "▁s ett", + "▁se tt", + "▁set t", + "▁M ag", + "▁Ma g", + "▁ Mag", + "a e", + "▁cond ition", + "▁ condition", + "Le ngth", + "L ength", + "▁f it", + "▁fi t", + "▁ fit", + "ound s", + "oun ds", + "▁ch anged", + "▁chang ed", + "▁change d", + "▁ changed", + "▁g uy", + "▁gu y", + "fil ter", + "at ever", + "ate ver", + "é d", + "re move", + "rem ove", + "▁h op", + "▁ho p", + "▁ hop", + "▁O ut", + "▁ Out", + "▁R ich", + "▁Ric h", + "▁ Rich", + "ch ild", + "chi ld", + "▁in cluded", + "▁incl uded", + "▁includ ed", + "▁include d", + "▁inclu ded", + "$ \\", + "▁T om", + "▁To m", + "▁ Tom", + "el ine", + "eli ne", + "elin e", + "e line", + "▁s ometimes", + "▁some times", + "▁somet imes", + "▁sometime s", + "▁dr ink", + "▁qu ant", + "▁ quant", + "▁p lease", + "▁ple ase", + "▁I nt", + "▁In t", + "▁ Int", + "ri ef", + "rie f", + "r ief", + "▁ex actly", + "▁exact ly", + "ci ng", + "cin g", + "c ing", + "▁all owed", + "▁allow ed", + "▁ allowed", + "bu ild", + "b uild", + "▁beaut iful", + "▁W ell", + "▁We ll", + "▁Wel l", + "▁ Well", + "▁look s", + "▁lo oks", + "▁ ü", + "▁ch ance", + "▁w rote", + "▁wr ote", + "▁n or", + "▁no r", + "▁ nor", + "▁f ailed", + "▁fa iled", + "▁fail ed", + "▁ failed", + "Me t", + "M et", + "▁p rior", + "▁pr ior", + "▁pri or", + "▁h undred", + "ско й", + "с кой", + "or ia", + "ori a", + "o ria", + "▁c y", + "▁ cy", + "▁w eb", + "▁we b", + "▁ web", + "▁m ess", + "▁me ss", + "▁mes s", + "le q", + "l eq", + "d y", + "te x", + "t ex", + "▁a nim", + "▁an im", + "▁ anim", + "at ur", + "atu r", + "▁str ucture", + "▁struct ure", + "▁ structure", + "opt ion", + "o ption", + "▁act ual", + "▁ actual", + "▁Fr anc", + "▁Fra nc", + "▁Fran c", + "en ced", + "ence d", + "enc ed", + ".< /", + ". ", + "▁ />", + "▁p roduction", + "▁produ ction", + "▁product ion", + "▁prod uction", + "▁ production", + "ig er", + "ige r", + "i ger", + "▁с т", + "▁ ст", + "sh ow", + "s how", + "▁pop ulation", + "▁popul ation", + "▁p ark", + "▁par k", + "▁ park", + "▁Z e", + "▁necess ary", + "▁ necessary", + "▁t rust", + "▁tr ust", + "▁sh own", + "▁show n", + "mod ule", + "mo dule", + "G E", + "▁l ay", + "▁la y", + "▁ lay", + "▁ann oun", + "▁class Name", + "▁ className", + "▁cal cul", + "▁calc ul", + "Fun ction", + "F unction", + "▁S al", + "▁Sa l", + "▁ Sal", + "O K", + "T P", + "▁en try", + "▁ent ry", + "▁entr y", + "▁ entry", + "▁St ud", + "▁ Stud", + "▁it ems", + "▁item s", + "▁ items", + "▁se curity", + "▁sec urity", + "▁secur ity", + "▁ security", + "En try", + "Ent ry", + "f loat", + "l s", + "ib ly", + "▁cont ribut", + "▁C heck", + "▁Che ck", + "▁ Check", + "M D", + "▁impro ve", + "Par t", + "P art", + "▁system s", + "▁syst ems", + "B l", + "▁pol icy", + "▁polic y", + "▁ policy", + "▁s creen", + "▁sc reen", + "▁scr een", + "▁ screen", + "▁A ny", + "▁An y", + "▁ Any", + "▁op ened", + "▁open ed", + "al loc", + "all oc", + "allo c", + "▁De cember", + "▁Dec ember", + "▁ É", + "▁e mail", + "▁em ail", + "▁ email", + "ad er", + "ade r", + "a der", + "= >", + "▁H en", + "▁He n", + "▁ Hen", + "▁in fo", + "▁inf o", + "▁ info", + "▁f loat", + "▁flo at", + "▁ float", + "▁sw itch", + "▁ switch", + "ра н", + "р ан", + "ur ance", + "▁as sum", + "▁ass um", + "us tr", + "ust r", + "u str", + "▁g roups", + "▁group s", + "▁gro ups", + "▁ groups", + "▁R ead", + "▁Re ad", + "▁ Read", + "▁w at", + "▁wa t", + "S p", + "ве р", + "в ер", + "RA N", + "R AN", + "hi b", + "h ib", + "AL L", + "A LL", + "▁h us", + "▁ hus", + "Sp ec", + "Spe c", + "S pec", + "\") )", + "\" ))", + "▁F rench", + "▁C lass", + "▁Cl ass", + "▁ Class", + "▁pres ident", + "▁presid ent", + "▁def init", + "▁defin it", + "▁N or", + "▁No r", + "▁T hom", + "▁Th om", + "ai gn", + "a ign", + "W idth", + "D o", + "▁{ @", + "ag on", + "ago n", + "a gon", + "▁L u", + "▁ Lu", + "▁follow ed", + "M M", + "as ons", + "ason s", + "tm p", + "t mp", + "▁th rows", + "▁throw s", + "▁thr ows", + "▁thro ws", + "▁ throws", + "IT Y", + "I TY", + "но м", + "▁f air", + "▁fa ir", + "▁p en", + "▁pe n", + "▁ pen", + "é g", + "▁inter face", + "▁ interface", + "▁s af", + "▁sa f", + "oo n", + "o on", + "B ack", + "▁s peed", + "▁sp eed", + "▁spe ed", + "▁ speed", + "▁ext ends", + "▁extend s", + "em pty", + "empt y", + "emp ty", + "▁п ере", + "▁пер е", + "▁пе ре", + "▁pro per", + "▁pr oper", + "▁prop er", + "▁d riv", + "▁dr iv", + "▁dri v", + "ф и", + "▁c enter", + "▁cent er", + "▁ center", + "he ader", + "head er", + "▁} )", + "▁ })", + "w a", + "▁m iddle", + "▁ middle", + "▁ch oose", + "▁cho ose", + "▁St ad", + "▁Sta d", + "S O", + "Fact ory", + "Factor y", + "F actory", + "De v", + "D ev", + "ic les", + "icle s", + "icl es", + "i cles", + "▁ap plication", + "▁applic ation", + "▁appl ication", + "▁ application", + "▁mod els", + "▁model s", + "▁mode ls", + "▁ models", + "pi te", + "pit e", + "p ite", + "ca p", + "c ap", + "x i", + "osp ital", + "▁d ream", + "▁dre am", + "EN D", + "E ND", + "▁con tract", + "▁cont ract", + "▁contr act", + "▁contra ct", + "▁ contract", + "icro soft", + "▁th ous", + "▁thou s", + "iz es", + "ize s", + "i zes", + "▁д а", + "▁ да", + "▁C O", + "▁ CO", + "▁d irection", + "▁di rection", + "▁direct ion", + "▁dire ction", + "▁dir ection", + "▁ direction", + "▁` `", + "▁ ``", + "▁d rive", + "▁dr ive", + "▁dri ve", + "▁driv e", + "▁ drive", + "Ma x", + "M ax", + "ci a", + "c ia", + "▁contin u", + "▁A lex", + "▁Al ex", + "▁Ale x", + "▁ Alex", + "▁g old", + "▁go ld", + "▁gol d", + "▁ gold", + "▁p rep", + "▁pre p", + "▁pr ep", + "▁or igin", + "▁orig in", + "▁ origin", + "▁r ap", + "▁ra p", + "▁ rap", + "O p", + "ous ly", + "▁are as", + "▁area s", + "PO RT", + "P ORT", + "он а", + "о на", + "▁sa fe", + "▁saf e", + "▁ safe", + "▁profess ional", + "▁profession al", + "ap ache", + "apa che", + "▁t emper", + "▁tem per", + "▁temp er", + "s z", + "▁u nit", + "▁un it", + "▁ unit", + "▁c op", + "▁co p", + "▁ cop", + "eq n", + "List ener", + "Listen er", + "▁for mat", + "▁form at", + "▁forma t", + "▁ format", + "se lect", + "sel ect", + "s elect", + "▁com fort", + "▁ comfort", + "▁me ant", + "▁mean t", + "id ay", + "ida y", + "i day", + "em e", + "e me", + "▁act ive", + "▁activ e", + "▁ active", + "▁n ote", + "▁not e", + "▁no te", + "▁ note", + "▁M il", + "▁Mi l", + "▁ Mil", + "on ly", + "▁< =", + "▁ <=", + "▁ne igh", + "▁nei gh", + "a o", + "▁bl ue", + "▁ blue", + "▁T V", + "▁ TV", + "Ch ild", + "▁re ached", + "▁reach ed", + "Add ress", + "Addr ess", + "ст в", + "▁cl osed", + "▁close d", + "▁clos ed", + "▁clo sed", + "▁ closed", + "in der", + "ind er", + "inde r", + "i nder", + "ol o", + "o lo", + "▁a lt", + "▁al t", + "▁ alt", + "▁a dm", + "▁ad m", + "Form at", + "For mat", + "U I", + "▁H am", + "▁Ha m", + "▁f requ", + "▁fr equ", + "▁fre qu", + "▁in depend", + "▁inde pend", + "▁ independ", + "▁eas ily", + "▁L and", + "▁La nd", + "▁Lan d", + "▁ Land", + "▁t or", + "▁to r", + "▁ tor", + "ograph y", + "ograp hy", + "in fty", + "inf ty", + "▁W ork", + "▁Wor k", + "▁ Work", + "iv en", + "ive n", + "i ven", + "▁Count y", + "▁Coun ty", + "▁s rc", + "▁ src", + "}$ ,", + "} $,", + "par se", + "pars e", + "p arse", + "C D", + "▁C our", + "▁Co ur", + "▁Cou r", + "▁f ol", + "▁fo l", + "▁ fol", + "Ent ity", + "pg f", + "▁Ch ina", + "▁Chi na", + "▁S ub", + "▁Su b", + "▁ Sub", + "ho od", + "h ood", + "▁field s", + "▁ fields", + "▁y es", + "▁ye s", + "▁ yes", + "re nd", + "ren d", + "r end", + "▁to wards", + "▁toward s", + "▁tow ards", + "▁st aff", + "▁sta ff", + "▁ staff", + "▁A ir", + "▁ Air", + "▁st ation", + "▁stat ion", + "▁ station", + "at ives", + "ative s", + "ati ves", + "ativ es", + "▁imp act", + "в ы", + "▁direct ly", + "iss ions", + "ission s", + "iv a", + "i va", + "| \\", + "Pt r", + "P tr", + "▁S ant", + "▁San t", + "▁Sa nt", + "Po l", + "P ol", + "▁pro gress", + "▁ progress", + "it ar", + "ita r", + "i tar", + "▁p arts", + "▁part s", + "▁par ts", + "▁ parts", + "▁pl ant", + "▁plan t", + "▁ plant", + "▁abs olut", + "▁gu ess", + "eq ref", + "▁t im", + "▁ti m", + "▁ tim", + "▁L ou", + "▁Lo u", + "▁ Lou", + "▁c ool", + "▁co ol", + "al u", + "a lu", + "▁m outh", + "▁mo uth", + "▁mou th", + "▁ mouth", + "ни х", + "▁h eight", + "▁he ight", + "▁ height", + "ge st", + "ges t", + "g est", + "▁P ost", + "▁Po st", + "▁Pos t", + "▁ Post", + "▁b oard", + "▁bo ard", + "▁ board", + "▁t it", + "▁ti t", + "▁ tit", + "▁h our", + "▁ho ur", + "▁ hour", + "▁ser ver", + "▁serv er", + "▁serve r", + "▁ server", + "▁p layers", + "▁play ers", + "▁player s", + "ri er", + "rie r", + "r ier", + "Lin k", + "L ink", + "▁Pres ident", + "] (", + "▁con struct", + "▁const ruct", + "▁constr uct", + "▁constru ct", + "▁ construct", + "hand le", + "}$ .", + "} $.", + "ry ing", + "r ying", + "▁s hop", + "▁sh op", + "▁ shop", + "ia na", + "ian a", + "i ana", + "ex p", + "e xp", + "Hel per", + "Help er", + "Off set", + "ac hes", + "ach es", + "ache s", + "a ches", + "▁conne ction", + "▁connect ion", + "▁conn ection", + "▁ connection", + "▁d ifference", + "▁dif ference", + "▁differ ence", + "serv ice", + "s ervice", + "▁g as", + "▁ga s", + "▁ gas", + "▁p riv", + "▁pr iv", + "▁pri v", + "▁ priv", + "▁un ivers", + "▁ univers", + "▁w ish", + "▁wis h", + "Re m", + "R em", + "U rl", + "ge b", + "g eb", + "S o", + "ens ions", + "ension s", + "Mod ule", + "Mo dule", + "SI ZE", + "▁p rem", + "▁pre m", + "▁pr em", + "wind ow", + "w indow", + "▁d ies", + "▁di es", + "▁die s", + "de l", + "d el", + "▁r ow", + "▁ro w", + "▁ row", + "▁a verage", + "▁aver age", + "▁ave rage", + "xi m", + "x im", + "▁p u", + "▁ pu", + "an ç", + "De t", + "D et", + "ke r", + "k er", + "y a", + "▁D et", + "▁De t", + "▁ Det", + "▁p å", + "▁n amed", + "▁name d", + "▁na med", + "▁nam ed", + "▁ named", + "▁dec ision", + "▁decis ion", + "wi n", + "w in", + "▁Ge orge", + "▁Georg e", + "ar ily", + "ari ly", + "▁s olution", + "▁sol ution", + "▁mult iple", + "▁multi ple", + "▁multip le", + "▁ multiple", + "at egy", + "ate gy", + "ateg y", + "▁le arning", + "▁learn ing", + "▁lear ning", + "▁ learning", + "▁se cret", + "▁sec ret", + "▁secre t", + "▁ secret", + "D O", + "▁n ice", + "▁ni ce", + "▁nic e", + "▁ nice", + "//////// ////////", + "S u", + "it ation", + "itat ion", + "▁j oin", + "▁jo in", + "▁ join", + "▁el ements", + "▁element s", + "▁ele ments", + "▁elem ents", + "▁ elements", + "▁e mer", + "▁em er", + "til de", + "t ilde", + "▁d ep", + "▁de p", + "▁ dep", + "▁s hot", + "▁sh ot", + "▁ shot", + "▁pl atform", + "▁plat form", + "▁ platform", + "ot hing", + "oth ing", + "o thing", + "M y", + "ed ia", + "edi a", + "om s", + "o ms", + "ail y", + "ai ly", + "a ily", + "( [", + "▁d ress", + "▁dr ess", + "▁dre ss", + "▁off icial", + "▁offic ial", + "es tern", + "est ern", + "ester n", + "este rn", + "▁dis cover", + "▁disc over", + "▁disco ver", + "▁m i", + "▁ mi", + "ны е", + "C A", + "od ing", + "odi ng", + "o ding", + "▁F ound", + "▁Fou nd", + "▁Fo und", + "▁ Found", + "▁a ffect", + "▁aff ect", + "▁af fect", + "Vi s", + "V is", + "st ract", + "str act", + "stra ct", + "s tract", + "ic ed", + "ice d", + "i ced", + "de bug", + "d ebug", + "▁rel ated", + "▁relate d", + "▁ related", + "▁s pect", + "▁sp ect", + "▁spec t", + "▁spe ct", + "▁ spect", + "us hed", + "ush ed", + "сь ко", + "▁b ank", + "▁ban k", + "▁ bank", + "▁c ele", + "▁ce le", + "▁cel e", + "AN D", + "A ND", + "ol f", + "е м", + "▁f ill", + "▁fil l", + "▁fi ll", + "▁ fill", + "▁g ives", + "▁giv es", + "▁give s", + "▁gi ves", + "▁б у", + "▁ бу", + "ar on", + "aro n", + "a ron", + "▁J es", + "▁Je s", + "RE G", + "▁s udd", + "▁su dd", + "▁sud d", + "date d", + "da ted", + "dat ed", + "d ated", + "v i", + "▁g i", + "▁ gi", + "se nd", + "sen d", + "s end", + "cp p", + "c pp", + "▁s pent", + "▁sp ent", + "▁spe nt", + "an de", + "and e", + "a nde", + "▁oper ation", + "▁ operation", + "pro cess", + "proc ess", + "▁in form", + "▁inf orm", + "▁info rm", + "▁F ree", + "▁Fr ee", + "▁Fre e", + "▁ Free", + "yo nd", + "y ond", + "▁per haps", + "▁su rv", + "▁sur v", + "▁L oc", + "▁Lo c", + "▁ Loc", + "▁con cl", + "▁conc l", + "▁ра з", + "▁ раз", + "▁O ver", + "▁ Over", + "ho l", + "h ol", + "ra z", + "r az", + "Wr ite", + "Writ e", + "W rite", + "▁g iving", + "▁giv ing", + "▁gi ving", + "r d", + "in stance", + "inst ance", + "▁re leased", + "▁rele ased", + "▁release d", + "▁R o", + "▁ Ro", + "R A", + "▁pract ice", + "▁g raph", + "▁gr aph", + "▁gra ph", + "▁grap h", + "▁ graph", + "▁incre ase", + "▁fig ure", + "▁ figure", + "Fil ter", + "HE CK", + "id x", + "i dx", + "▁g lass", + "▁gl ass", + "▁ glass", + "sk i", + "s ki", + "com es", + "co mes", + "come s", + "c omes", + "▁c at", + "▁ca t", + "▁ cat", + "▁c old", + "▁col d", + "▁co ld", + "go to", + "got o", + "g oto", + "uf act", + "u fact", + "▁C opyright", + "▁Copy right", + "▁ Copyright", + "}} \\", + "} }\\", + "▁str eng", + "▁stre ng", + "▁d ir", + "▁di r", + "▁ dir", + "to ken", + "tok en", + "t oken", + "▁occ ur", + "▁oc cur", + "arl ier", + "▁me asure", + "▁meas ure", + "▁ measure", + "▁s ec", + "▁se c", + "▁ sec", + "▁m ás", + "▁má s", + "▁N et", + "▁Ne t", + "▁ Net", + "▁arg ument", + "▁ argument", + "▁s ou", + "▁so u", + "▁m oving", + "▁mov ing", + "▁mo ving", + "▁p refer", + "▁pre fer", + "▁pref er", + "ma sk", + "mas k", + "m ask", + "< <", + "▁bre ath", + "▁breat h", + "▁phys ical", + "▁pos itive", + "▁posit ive", + "▁s or", + "▁so r", + "▁ sor", + "▁de part", + "▁dep art", + "▁re move", + "▁rem ove", + "▁ remove", + "▁k it", + "▁ki t", + "▁ kit", + "▁me eting", + "▁meet ing", + "▁D ata", + "▁Da ta", + "▁Dat a", + "▁ Data", + "og raf", + "act ions", + "action s", + "a ctions", + "▁param eters", + "▁parameter s", + "▁ parameters", + "▁A tt", + "▁At t", + "▁ Att", + "es ch", + "esc h", + "e sch", + "▁inv olved", + "▁invol ved", + "▁involve d", + "ä t", + "L L", + "B ar", + "▁с и", + "▁ си", + "ec h", + "e ch", + "GE T", + "G ET", + "▁pre vent", + "▁pr event", + "▁prev ent", + "▁ prevent", + "▁be yond", + "▁O ther", + "▁Ot her", + "▁ Other", + "ä n", + "by te", + "▁sudd en", + "▁sud den", + "ol ve", + "olv e", + "▁н о", + "▁ но", + "LO G", + "L OG", + "un it", + "uni t", + "u nit", + "▁tr uth", + "ra t", + "r at", + "S D", + "▁e at", + "▁M ad", + "▁Ma d", + "▁ Mad", + "▁prov ides", + "▁provide s", + "▁s ession", + "▁ session", + "De le", + "Del e", + "D ele", + "▁con vers", + "▁conv ers", + "▁conver s", + "▁conve rs", + "cent er", + "cen ter", + "c enter", + "▁contin ued", + "▁continue d", + "▁continu ed", + "ot ion", + "oti on", + "ca che", + "c ache", + "dis play", + "disp lay", + "▁prote ct", + "▁prot ect", + "am s", + "a ms", + "▁p ow", + "▁po w", + "▁ pow", + "CT ION", + "C TION", + "▁M ac", + "▁Ma c", + "▁ Mac", + "m o", + "х а", + "▁d istance", + "▁di stance", + "▁dist ance", + "▁ distance", + "▁T ime", + "▁Tim e", + "▁Ti me", + "▁ Time", + "g i", + "▁s equ", + "▁se qu", + "▁seq u", + "▁ sequ", + "T arget", + "с ле", + "Ser ver", + "Serv er", + "▁w ide", + "▁wid e", + "▁ wide", + "cl ose", + "clos e", + "▁c ru", + "▁cr u", + "Ex t", + "E xt", + "▁s elect", + "▁se lect", + "▁sel ect", + "▁sele ct", + "▁ select", + "▁pat tern", + "▁ pattern", + "\") );", + "\")) ;", + "\" ));", + "Pro vider", + "Prov ider", + "UR L", + "U RL", + "▁g reen", + "▁gr een", + "▁gre en", + "▁ green", + "▁wait ing", + "▁wa iting", + "pro to", + "pr oto", + "prot o", + "▁immedi ately", + "▁immediate ly", + "com mon", + "comm on", + "az ione", + "azi one", + "a zione", + "ri ver", + "riv er", + "rive r", + "r iver", + "▁s en", + "▁se n", + "▁ sen", + "▁! ==", + "▁!= =", + "▁Febru ary", + "▁Februar y", + "ur b", + "u rb", + "▁S en", + "▁Se n", + "de st", + "des t", + "d est", + "< ?", + "▁ed ge", + "▁ edge", + "▁m ais", + "▁ma is", + "▁mai s", + "gor ith", + "cp u", + "c pu", + "▁educ ation", + "▁associ ated", + "▁associate d", + "No ne", + "Non e", + "N one", + "h i", + "▁p oor", + "▁po or", + "se m", + "s em", + "▁W il", + "▁Wi l", + "▁b ud", + "▁bu d", + "▁ bud", + "▁a uch", + "▁au ch", + "▁ auch", + "el ler", + "ell er", + "elle r", + "▁L ife", + "▁Li fe", + "▁ Life", + "▁f iles", + "▁fil es", + "▁file s", + "▁fi les", + "▁ files", + "▁le ading", + "▁lead ing", + "▁ leading", + "▁ob tain", + "▁obt ain", + "▁J ul", + "▁Ju l", + "at ory", + "ator y", + "ato ry", + "г у", + "it able", + "ita ble", + "i table", + "▁on to", + "▁ont o", + "▁ onto", + "▁b orn", + "▁bo rn", + "▁bor n", + "▁ born", + "or em", + "ore m", + "o rem", + "▁Stre et", + "▁m aint", + "▁main t", + "▁ma int", + "▁mai nt", + "Param s", + "Par ams", + "ri p", + "r ip", + "▁S T", + "▁ ST", + "u v", + "ma in", + "m ain", + "▁re cent", + "▁rec ent", + "▁rece nt", + "We b", + "W eb", + "ov a", + "o va", + "ц а", + "ais e", + "ai se", + "a ise", + "yle s", + "yl es", + "y les", + "▁de scribed", + "▁desc ribed", + "▁describ ed", + "▁describe d", + "▁begin ning", + "▁D ay", + "▁Da y", + "▁ Day", + "▁V ol", + "▁Vo l", + "▁ Vol", + "▁h uge", + "▁hug e", + "Ha s", + "H as", + "an cy", + "anc y", + "He ader", + "Head er", + "▁a ren", + "▁are n", + "▁ar en", + "▁ aren", + "ва н", + "в ан", + "▁en sure", + "▁ens ure", + "▁ ensure", + "▁p et", + "▁pe t", + "▁ pet", + "mu lt", + "mul t", + "m ult", + "▁L ike", + "▁Li ke", + "▁ Like", + "▁man agement", + "▁manage ment", + "▁ management", + "P S", + "wh ile", + "▁back ground", + "▁ background", + "ount er", + "oun ter", + "o unter", + "bo ol", + "b ool", + "F C", + "N um", + "R L", + "▁ex cl", + "▁exc l", + "▁e ye", + "▁ey e", + "im g", + "i mg", + "▁r om", + "▁ro m", + "▁ rom", + "▁H el", + "▁He l", + "▁ Hel", + "Opt ion", + "O ption", + "▁stop ped", + "▁sto pped", + "▁th read", + "▁thr ead", + "▁ thread", + "to type", + "tot ype", + "t otype", + ")) )", + ") ))", + "▁st age", + "▁stag e", + "▁sta ge", + "▁ stage", + "▁ü ber", + "▁ über", + "▁al though", + "▁ although", + "Type s", + "Ty pes", + "Typ es", + "T ypes", + "▁O h", + "▁ Oh", + "▁e ight", + "▁ eight", + "▁de scription", + "▁des cription", + "▁ description", + "' '", + "ö n", + "▁sur face", + "▁surf ace", + "▁ surface", + "▁Intern ational", + "▁ch arg", + "▁char g", + "▁cha rg", + "▁ charg", + "▁col lection", + "▁coll ection", + "▁collect ion", + "▁colle ction", + "▁ collection", + "▁us ers", + "▁use rs", + "▁user s", + "▁ users", + "▁ob vious", + "▁cent ury", + "▁ century", + "ic ks", + "ick s", + "i cks", + "▁art icle", + "▁artic le", + "▁ article", + "▁\" \\", + "▁ \"\\", + "di m", + "d im", + "▁s in", + "▁si n", + "▁ sin", + "en ge", + "eng e", + "Cont rol", + "▁com mit", + "▁comm it", + "▁ commit", + "ens ity", + "▁t ra", + "▁tr a", + "▁ tra", + "cript or", + "▁N OT", + "▁NO T", + "▁ NOT", + "we ll", + "w ell", + "▁M ichael", + "▁Mich ael", + "▁n od", + "▁no d", + "▁ nod", + "▁m ort", + "▁mor t", + "▁mo rt", + "iv o", + "i vo", + "is ation", + "▁P o", + "▁ Po", + "▁P aris", + "▁Par is", + "▁Pa ris", + "▁ad ministr", + "▁admin istr", + "▁ administr", + "bu rg", + "bur g", + "b urg", + "cd ot", + "c dot", + "▁mil itary", + "▁milit ary", + "▁militar y", + "▁B est", + "▁Be st", + "▁Bes t", + "▁ Best", + "▁К а", + "▁ Ка", + "IN E", + "I NE", + "▁through out", + "S l", + "▁im pl", + "▁imp l", + "▁ impl", + "cont rol", + "contr ol", + "▁ Ч", + "▁u it", + "▁ui t", + "▁ uit", + "▁un signed", + "▁uns igned", + "▁ unsigned", + "▁M ary", + "▁Mar y", + "▁Ma ry", + "Ch ar", + "C har", + "м і", + "▁th reat", + "▁c ourt", + "▁co urt", + "▁cour t", + "▁cou rt", + "▁ court", + "vi lle", + "vil le", + "v ille", + "▁ ш", + "▁C am", + "▁Ca m", + "▁ Cam", + ". \r", + "▁current ly", + "▁curr ently", + "ro t", + "r ot", + "▁D ate", + "▁Da te", + "▁Dat e", + "▁ Date", + "▁s hit", + "▁sh it", + "▁ shit", + "▁$ {\\", + "▁${ \\", + "un n", + "u nn", + "U s", + "▁b uffer", + "▁buff er", + "▁buf fer", + "▁ buffer", + "▁s ont", + "▁so nt", + "▁son t", + "▁let ter", + "▁lett er", + "▁ letter", + "in ated", + "ina ted", + "inate d", + "Ch ange", + "▁h ref", + "▁hr ef", + "▁ href", + "▁l ack", + "▁la ck", + "▁lac k", + "▁o il", + "▁C ons", + "▁Con s", + "▁Co ns", + "▁ Cons", + "▁J er", + "▁Je r", + "BU G", + "B UG", + "if orn", + "▁pro perties", + "▁proper ties", + "▁ properties", + "▁r andom", + "▁ran dom", + "▁rand om", + "▁ random", + "▁br other", + "▁bro ther", + "▁p iece", + "▁pie ce", + "▁ piece", + "б у", + "ist ics", + "istic s", + "isti cs", + "▁techn ology", + "gl obal", + "glob al", + "▁trans form", + "▁ transform", + "er d", + "e rd", + "▁B ecause", + "▁ Because", + "PE CT", + "P ECT", + "pr et", + "pre t", + "p ret", + "▁го ду", + "▁год у", + "▁M et", + "▁Me t", + "▁ Met", + "▁p sy", + "▁ps y", + "▁ psy", + "▁о д", + "▁g od", + "▁go d", + "▁ god", + "▁D el", + "▁De l", + "▁ Del", + "base d", + "ba sed", + "bas ed", + "b ased", + "▁v oor", + "▁vo or", + "▁C all", + "▁Cal l", + "▁Ca ll", + "▁ Call", + "S A", + "▁fil ter", + "▁ filter", + "▁incl udes", + "▁includ es", + "▁include s", + "▁inclu des", + "▁ includes", + "olut ions", + "olution s", + "f d", + "▁w ind", + "▁win d", + "▁ wind", + "▁б о", + "▁ бо", + "▁ab ility", + "▁ ability", + "ca rd", + "car d", + "c ard", + "▁n umer", + "▁num er", + "▁nu mer", + "▁ numer", + "add ress", + "addr ess", + "▁go al", + "ash ington", + "ashing ton", + "▁s light", + "▁sl ight", + "ab a", + "a ba", + "▁L og", + "▁Lo g", + "▁ Log", + "Set tings", + "Setting s", + "ad ow", + "ado w", + "▁p i", + "▁ pi", + "ir ing", + "iri ng", + "i ring", + "F T", + "▁number s", + "▁num bers", + "con f", + "co nf", + "ta sk", + "t ask", + "▁î n", + "т ы", + "▁re ceive", + "▁rece ive", + "▁r oot", + "▁ro ot", + "▁ root", + "▁Ind ia", + "pat ch", + "p atch", + "é l", + "▁sum mer", + "▁method s", + "▁ methods", + "▁pl aces", + "▁place s", + "▁plac es", + "▁М а", + "▁ Ма", + "▁cap ital", + "▁capit al", + "▁ev idence", + "▁G erman", + "▁Germ an", + "▁Ger man", + "\\ ,", + "D A", + "ec ute", + "ecut e", + "col umn", + "▁fun ctions", + "▁function s", + "▁ functions", + "▁c ounter", + "▁co unter", + "▁coun ter", + "▁count er", + "▁ counter", + "▁ar ms", + "▁arm s", + "▁ arms", + "▁f eed", + "▁fe ed", + "▁fee d", + "▁ feed", + "ve y", + "v ey", + "he nt", + "hen t", + "h ent", + "MA X", + "M AX", + "▁ac qu", + "▁app ly", + "▁ap ply", + "▁appl y", + "▁ apply", + "▁hus band", + "▁k illed", + "▁kill ed", + "▁kil led", + "▁S pec", + "▁Sp ec", + "▁Spe c", + "▁ Spec", + "ent ity", + "enti ty", + "▁e arlier", + "▁M iss", + "▁Mi ss", + "▁Mis s", + "▁ Miss", + "▁set ting", + "▁sett ing", + "▁ setting", + "it ect", + "ite ct", + "▁d ed", + "▁de d", + "▁ ded", + "Ro w", + "R ow", + "▁r an", + "▁ra n", + "▁ ran", + "▁Y es", + "▁Ye s", + "▁ Yes", + "▁fin ancial", + "▁financ ial", + "s ession", + "le ar", + "l ear", + "is hing", + "ish ing", + "ishi ng", + "▁ne arly", + "▁near ly", + "▁d ur", + "▁du r", + "▁m achine", + "▁mach ine", + "▁ machine", + "xf f", + "x ff", + "br o", + "b ro", + "▁s ymbol", + "▁sym bol", + "▁ symbol", + "land s", + "lan ds", + "l ands", + "Ac c", + "A cc", + "d i", + "▁Rober t", + "▁Ro bert", + "▁Rob ert", + "pro p", + "pr op", + "p rop", + "ur ity", + "uri ty", + "▁# ####", + "▁## ###", + "▁### ##", + "▁#### #", + "▁walk ed", + "▁wal ked", + "▁intern ational", + "▁internation al", + "▁ Е", + "Y es", + "▁re lease", + "▁rele ase", + "▁ release", + "▁start ing", + "▁star ting", + "st atic", + "stat ic", + "▁b ei", + "▁be i", + "al low", + "all ow", + "allo w", + "▁Pe ople", + "▁ People", + "e z", + "▁param eter", + "▁ parameter", + "C ache", + "▁$ $", + "▁ $$", + "amp ions", + "ampion s", + "▁M er", + "▁Me r", + "▁ Mer", + "▁k om", + "▁ko m", + "▁ kom", + "le ted", + "let ed", + "lete d", + "l eted", + "oi s", + "o is", + "▁O pen", + "▁Op en", + "▁ Open", + "ty pes", + "type s", + "typ es", + "t ypes", + "▁f ue", + "▁fu e", + "ac ters", + "act ers", + "acter s", + "▁re ference", + "▁refer ence", + "▁ reference", + "Equ als", + "Equal s", + "Eq uals", + "▁a ware", + "▁aw are", + "▁ aware", + "▁h ol", + "▁ho l", + "▁ hol", + "▁de mand", + "▁dem and", + "lo r", + "l or", + "▁v eh", + "▁ve h", + "▁ veh", + "▁not ice", + "▁ notice", + "▁com ponent", + "▁compon ent", + "▁ component", + "f n", + "▁anal ysis", + "▁analy sis", + "▁analys is", + "▁ analysis", + "mat ch", + "m atch", + "▁effect ive", + "▁ effective", + "pro duct", + "produ ct", + "prod uct", + "ни к", + "▁le gal", + "▁leg al", + "▁ legal", + "е й", + "se mb", + "sem b", + "s emb", + "▁loc ated", + "▁locate d", + "▁с у", + "▁ су", + "Q L", + "in ct", + "inc t", + "et o", + "e to", + "Dr aw", + "D raw", + "▁sc ale", + "▁scal e", + "▁ scale", + "ро в", + "р ов", + "▁w ants", + "▁want s", + "H ow", + "▁w el", + "▁we l", + "is ions", + "ision s", + "isi ons", + "▁de liver", + "▁del iver", + "un der", + "und er", + "unde r", + "u nder", + "▁d eb", + "▁de b", + "▁j u", + "▁ ju", + "val ues", + "value s", + "▁s ister", + "▁si ster", + "▁sist er", + "ко в", + "к ов", + "▁C reate", + "▁Creat e", + "▁Cre ate", + "▁ Create", + "▁I nc", + "▁In c", + "▁a ux", + "▁au x", + "▁ aux", + "▁Wh ite", + "▁Whit e", + "▁ White", + "Me nu", + "Men u", + "M enu", + "au d", + "a ud", + "re source", + "res ource", + "▁c ab", + "▁ca b", + "▁l if", + "▁li f", + "▁ lif", + "▁c ulture", + "▁cult ure", + "ic he", + "ich e", + "i che", + "▁wh atever", + "▁what ever", + "▁de signed", + "▁des igned", + "▁design ed", + "▁re pe", + "▁rep e", + "▁M ont", + "▁Mon t", + "▁Mo nt", + "▁ Mont", + "▁ch arge", + "▁char ge", + "▁charg e", + "▁ charge", + "Name s", + "Na mes", + "N ames", + "▁in sp", + "▁ins p", + "▁custom ers", + "▁customer s", + "os a", + "o sa", + "▁d aughter", + "▁E ast", + "E Q", + "▁o pin", + "▁op in", + "▁F re", + "▁Fr e", + "▁se ek", + "▁see k", + "▁ seek", + "▁p ush", + "▁pu sh", + "▁ push", + "▁n av", + "▁na v", + "▁ nav", + "▁b urn", + "▁bu rn", + "▁bur n", + "▁ burn", + "ar den", + "ard en", + "arde n", + "ha sh", + "has h", + "h ash", + "▁opportun ity", + "▁M at", + "▁Ma t", + "▁ Mat", + "oy al", + "oya l", + "o yal", + "▁p un", + "▁pu n", + "sc ale", + "scal e", + "yn amic", + "ynam ic", + "yna mic", + "▁T ype", + "▁Ty pe", + "▁Typ e", + "▁ Type", + "il ing", + "ili ng", + "i ling", + "▁qu ery", + "▁que ry", + "▁quer y", + "▁ query", + "▁m ist", + "▁mis t", + "▁mi st", + "ro r", + "r or", + "for ce", + "▁On ce", + "▁ Once", + "▁med ical", + "▁medic al", + "▁medi cal", + "li e", + "l ie", + "▁stud ent", + "▁ student", + "ed eral", + "eder al", + "ede ral", + "▁l ov", + "▁lo v", + "▁ lov", + "if orm", + "i form", + "▁al tern", + "▁alt ern", + "▁alter n", + "▁ altern", + "bi n", + "b in", + "od er", + "ode r", + "o der", + "▁return s", + "▁ returns", + "reg ister", + "ut s", + "u ts", + "C I", + "▁T or", + "▁To r", + "▁ Tor", + "C R", + "▁L os", + "▁Lo s", + "▁ Los", + "am ily", + "ami ly", + "amil y", + "air e", + "ai re", + "a ire", + "++ ;", + "Cont roller", + "Control ler", + "wi de", + "wid e", + "w ide", + "x x", + "row ser", + "rows er", + "▁B ook", + "▁Bo ok", + "▁ Book", + "Cont ainer", + "pl oad", + "plo ad", + "p load", + "▁E v", + "▁ Ev", + "▁t al", + "▁ta l", + "▁ tal", + "▁the ory", + "eqn array", + "б е", + "▁rep orted", + "▁report ed", + "▁me aning", + "▁mean ing", + "▁s y", + "▁ sy", + "ri be", + "rib e", + "r ibe", + "ic ate", + "ica te", + "ho ld", + "hol d", + "h old", + "▁of fers", + "▁off ers", + "▁offer s", + "▁t empl", + "▁tem pl", + "▁temp l", + "cs s", + "c ss", + "▁p icture", + "▁pict ure", + "▁ picture", + "▁a sync", + "▁as ync", + "▁ async", + "▁st ock", + "▁sto ck", + "▁ stock", + "▁in ternal", + "▁inter nal", + "▁intern al", + "▁ internal", + "t i", + "B O", + "V er", + "с по", + "▁d emon", + "▁de mon", + "▁dem on", + "▁demo n", + "▁l augh", + "▁la ugh", + "▁laug h", + "▁E nd", + "▁En d", + "▁ End", + "▁k on", + "▁ko n", + "▁ kon", + "▁ide as", + "▁idea s", + "▁c andid", + "▁can did", + "▁cand id", + "Me m", + "M em", + "iz z", + "i zz", + "re fix", + "ref ix", + "▁A ND", + "▁AN D", + "▁ AND", + "eg en", + "e gen", + "E l", + "▁camp aign", + "H ttp", + "▁R ob", + "▁Ro b", + "▁ Rob", + "д і", + "▁b ul", + "▁bu l", + "▁ bul", + "▁К о", + "▁ Ко", + "▁count ries", + "▁countr ies", + "» .", + "▁ex pression", + "▁exp ression", + "▁express ion", + "▁expr ession", + "▁ expression", + "▁Eng land", + "s f", + "▁certain ly", + "ag en", + "age n", + "a gen", + "▁ч а", + "▁ ча", + "▁A NY", + "▁AN Y", + "▁ ANY", + "▁conne ct", + "▁conn ect", + "▁ connect", + "F E", + "▁and roid", + "▁ android", + "▁G old", + "▁Go ld", + "▁Gol d", + "▁ Gold", + "▁op pos", + "▁opp os", + "ov ern", + "ove rn", + "over n", + "o vern", + "▁Com mun", + "▁Comm un", + ", _", + "as ion", + "asi on", + "L a", + "▁f irm", + "▁fi rm", + "▁fir m", + "▁Al though", + "▁G ood", + "▁Go od", + "▁ Good", + "▁L aw", + "▁La w", + "er ve", + "erv e", + "▁b rand", + "▁br and", + "▁bra nd", + "▁ brand", + "M in", + "fil l", + "fi ll", + "f ill", + "'] ,", + "' ],", + "▁J ew", + "▁Je w", + "il er", + "ile r", + "i ler", + "in gle", + "ing le", + "it hub", + "ith ub", + "▁D iv", + "▁Di v", + "▁ Div", + "▁c ert", + "▁ce rt", + "▁cer t", + "▁ cert", + "He ight", + "H eight", + "ra el", + "r ael", + "The re", + "Th ere", + "T here", + "it ute", + "itut e", + "itu te", + "▁a maz", + "▁am az", + "▁ amaz", + "lo ok", + "l ook", + "▁S E", + "▁ SE", + "▁j o", + "▁ jo", + "▁pull ed", + "▁pul led", + "▁re sources", + "▁res ources", + "▁resource s", + "▁ resources", + "▁M ax", + "▁Ma x", + "▁ Max", + "▁ag reed", + "▁agree d", + "▁agre ed", + "as y", + "a sy", + "▁treat ment", + "\"> < /", + "\" > >", + "▁ >>", + "com mand", + "comm and", + "at z", + "a tz", + "▁m al", + "▁ma l", + "▁ mal", + "ста в", + "▁P ress", + "▁Pr ess", + "▁Pres s", + "▁Pre ss", + "▁ Press", + "▁char acters", + "▁character s", + "▁z ero", + "▁ze ro", + "▁ zero", + "AG E", + "A GE", + "rap per", + "▁kit chen", + "am ing", + "ami ng", + "amin g", + "a ming", + "▁re str", + "▁r estr", + "▁res tr", + "▁rest r", + "X X", + "▁Col lege", + "▁Ar ray", + "▁Arr ay", + "▁ Array", + "▁f resh", + "▁fr esh", + "▁fre sh", + "▁fres h", + "▁sh ift", + "▁ shift", + "▁spec ified", + "pl ete", + "ple te", + "plet e", + "p lete", + "IT E", + "I TE", + "▁C amp", + "▁Cam p", + "▁Ca mp", + "▁ Camp", + "ri al", + "ria l", + "r ial", + "c b", + "▁T H", + "▁ TH", + "I B", + "os en", + "ose n", + "o sen", + "▁ ú", + "▁par ams", + "▁param s", + "▁para ms", + "▁ params", + "ign ment", + "ad ding", + "add ing", + "▁deg ree", + "▁ degree", + "Loc al", + "Lo cal", + "L ocal", + "O h", + "▁z ur", + "▁zu r", + "▁level s", + "▁lev els", + "C S", + "fin ished", + "finish ed", + "C ase", + "ri age", + "ria ge", + "Vec tor", + "V ector", + "▁s ea", + "▁se a", + "▁ sea", + "ant ic", + "anti c", + "▁Le ague", + "▁there fore", + "▁ther efore", + "On e", + "O ne", + "Re turn", + "Ret urn", + "R eturn", + "Acc ess", + "Ac cess", + "A ccess", + "va s", + "v as", + "▁о с", + "▁r at", + "▁ra t", + "▁ rat", + "Bi g", + "B ig", + "▁be havior", + "▁behav ior", + "▁behavi or", + "k r", + "▁un defined", + "▁und efined", + "▁ undefined", + "▁E s", + "▁ Es", + "▁appe ared", + "▁appear ed", + "el es", + "ele s", + "e les", + "▁W AR", + "▁WA R", + "▁ WAR", + "St at", + "S tat", + "▁Go ogle", + "▁ Google", + "▁c redit", + "▁cre dit", + "▁cr edit", + "▁cred it", + "▁F ile", + "▁Fil e", + "▁Fi le", + "▁ File", + "an ging", + "ang ing", + "ho use", + "hou se", + "h ouse", + "rom ise", + "ge nt", + "gen t", + "g ent", + "▁hab it", + "▁ha bit", + "▁soc iety", + "▁soci ety", + "▁societ y", + "▁enc our", + "▁p aint", + "▁pain t", + "▁pa int", + "pe t", + "p et", + "▁U K", + "▁ UK", + "aw s", + "a ws", + "on om", + "ono m", + "o nom", + "G l", + "}_ {\\", + "}_{ \\", + "} _{\\", + "el ess", + "ele ss", + "eles s", + "e less", + "em y", + "e my", + "▁C ong", + "▁Con g", + "▁Co ng", + "▁develop ed", + "▁im ages", + "▁image s", + "▁imag es", + "▁ images", + "▁ ö", + "▁f ont", + "▁fo nt", + "▁fon t", + "▁ font", + "cl ear", + "cle ar", + "c lear", + "gi n", + "g in", + "▁L ord", + "▁Lo rd", + "▁Lor d", + "▁trans port", + "▁ transport", + "▁: :", + "▁ ::", + "▁c up", + "▁cu p", + "▁ cup", + "ul ate", + "ula te", + "u late", + "▁D uring", + "▁Du ring", + "▁Dur ing", + "pr iv", + "p riv", + "▁ext rem", + "▁extr em", + "▁D i", + "▁ Di", + "▁d oubt", + "▁dou bt", + "▁doub t", + "P y", + "if ying", + "ify ing", + "sp lit", + "spl it", + "s plit", + "eg o", + "e go", + "git hub", + "g ithub", + "▁) ,", + "▁ ),", + "RO M", + "R OM", + "▁ch air", + "▁cha ir", + "▁ chair", + "▁t rade", + "▁tr ade", + "▁trad e", + "▁tra de", + "▁n icht", + "▁ni cht", + "▁nic ht", + "To p", + "T op", + "St ore", + "▁p arte", + "▁part e", + "▁par te", + "pro ject", + "ni a", + "n ia", + "▁в ід", + "▁ві д", + "wa r", + "w ar", + "▁Pro f", + "▁Pr of", + "▁c aught", + "Th read", + "ст ва", + "ств а", + "с тва", + "aut hor", + "auth or", + "▁d oll", + "▁do ll", + "▁dol l", + "▁h arm", + "▁ha rm", + "▁har m", + "▁ harm", + "▁G en", + "▁Ge n", + "▁ Gen", + "tr ee", + "tre e", + "t ree", + "et ime", + "eti me", + "e time", + "cf g", + "c fg", + "▁gu ys", + "▁guy s", + "▁Cal ifornia", + "▁G reen", + "▁Gr een", + "▁Gre en", + "▁Gree n", + "▁ Green", + "▁mov ement", + "▁move ment", + "▁mo vement", + "ie j", + "i ej", + "▁stat ement", + "▁state ment", + "▁ statement", + "▁se eing", + "▁see ing", + "▁h aven", + "▁have n", + "▁ha ven", + "▁hav en", + "vent ion", + "v ention", + "S L", + "ched ul", + "ie rt", + "ier t", + "i ert", + "▁pr imary", + "▁prim ary", + "▁pri mary", + "▁prima ry", + "▁ primary", + "▁c ivil", + "▁ci vil", + "▁civ il", + "ri an", + "ria n", + "r ian", + "▁b utton", + "▁but ton", + "▁butt on", + "▁ button", + "▁l ived", + "▁li ved", + "▁live d", + "▁liv ed", + "P ass", + "so r", + "s or", + "▁watch ing", + "▁wat ching", + "▁sk ills", + "▁skill s", + "te e", + "t ee", + "Le vel", + "L evel", + "▁sc ient", + "h s", + "▁a gre", + "▁ag re", + "ca t", + "c at", + "▁t end", + "▁te nd", + "▁ten d", + "▁M ill", + "▁Mil l", + "▁Mi ll", + "▁ Mill", + "▁C ap", + "▁Ca p", + "▁ Cap", + "OR D", + "O RD", + "gl e", + "g le", + "▁с во", + "» ,", + "▁a head", + "▁ah ead", + "ve st", + "ves t", + "v est", + "▁J ose", + "▁Jo se", + "▁Jos e", + "is cher", + "isch er", + "ische r", + "isc her", + "ș i", + "▁le aving", + "▁д ля", + "▁s outh", + "▁so uth", + "▁sou th", + "▁sout h", + "▁con sum", + "▁cons um", + "▁ consum", + "R ange", + "▁activ ities", + "Se c", + "S ec", + "▁s ales", + "▁sa les", + "▁sal es", + "▁sale s", + "▁f ix", + "▁fi x", + "▁ fix", + "▁j ed", + "▁je d", + "▁ jed", + "ru m", + "r um", + "ve ctor", + "vec tor", + "v ector", + "▁s pot", + "▁sp ot", + "▁spo t", + "▁ spot", + "▁man ufact", + "к т", + "or row", + "orr ow", + "si gn", + "sig n", + "s ign", + "▁col lege", + "▁colle ge", + "▁colleg e", + "▁d river", + "▁dr iver", + "▁dri ver", + "▁driv er", + "▁drive r", + "▁ driver", + "▁def initely", + "▁definit ely", + "▁s pend", + "▁sp end", + "▁spe nd", + "miss ion", + "m ission", + "з у", + "at ively", + "ative ly", + "ativ ely", + "b i", + "Call back", + "▁particular ly", + "▁particul arly", + "▁h ell", + "▁he ll", + "▁hel l", + "▁ hell", + "▁p ool", + "▁po ol", + "▁ pool", + "PR E", + "P RE", + "▁cle arly", + "▁clear ly", + "P T", + "ot hes", + "oth es", + "othe s", + "▁I d", + "▁ Id", + "Loc ation", + "L ocation", + "▁R un", + "▁Ru n", + "▁ Run", + "▁f ixed", + "▁fix ed", + "▁ fixed", + "▁H and", + "▁Ha nd", + "▁Han d", + "▁ Hand", + "ba l", + "b al", + "d ouble", + "C an", + "Om ega", + "▁chall eng", + "▁stand ing", + "▁stan ding", + "▁ standing", + "it en", + "ite n", + "i ten", + "▁me chan", + "▁d urch", + "▁dur ch", + "▁d ell", + "▁de ll", + "▁del l", + "▁rais ed", + "▁raise d", + "▁ra ised", + "▁we ak", + "▁ weak", + "▁D u", + "▁ Du", + "gr ad", + "gra d", + "g rad", + "▁sc ene", + "▁scen e", + "▁ scene", + "pos s", + "po ss", + "p oss", + "▁t on", + "▁to n", + "▁ ton", + "▁e arth", + "▁ear th", + "ul ations", + "ulation s", + "▁str ength", + "▁stre ngth", + "▁streng th", + "ak ed", + "ake d", + "a ked", + "▁re main", + "▁rem ain", + "▁B i", + "▁ Bi", + "▁custom er", + "▁cust omer", + "▁ customer", + "ran ge", + "r ange", + "▁inter ested", + "▁interest ed", + "ON E", + "O NE", + "▁c off", + "▁co ff", + "re quire", + "requ ire", + "▁On ly", + "▁ Only", + "▁W eb", + "▁We b", + "▁ Web", + "▁f arm", + "▁far m", + "▁fa rm", + "▁act ivity", + "▁activ ity", + "▁ activity", + "▁r out", + "▁ro ut", + "▁rou t", + "bl ing", + "b ling", + "S Y", + "▁Rich ard", + "▁Ric hard", + "▁R ef", + "▁Re f", + "▁ Ref", + "▁ко н", + "▁к он", + "▁ кон", + "▁j un", + "▁ju n", + "bo rn", + "bor n", + "b orn", + "ij n", + "Config uration", + "um an", + "uma n", + "u man", + "E E", + "▁mar ried", + "▁З а", + "▁ За", + "▁f at", + "▁fa t", + "▁k id", + "▁ki d", + "▁T ur", + "▁Tu r", + "▁ Tur", + "▁off ered", + "▁offer ed", + "ni c", + "n ic", + "▁B ig", + "▁Bi g", + "▁ Big", + "Ga mma", + "G amma", + "▁He alth", + "▁ Health", + "▁T R", + "▁ TR", + "▁s ię", + "▁si ę", + "▁const ruction", + "▁construct ion", + "▁constr uction", + "▁constru ction", + "▁ construction", + "▁Ch urch", + "▁B et", + "▁Be t", + "▁ Bet", + "bu s", + "b us", + "▁e arn", + "▁ear n", + "ri ct", + "ric t", + "r ict", + "▁п ра", + "▁пр а", + "▁ пра", + "▁br ain", + "▁bra in", + "▁f ra", + "▁fr a", + "▁O p", + "▁ Op", + "FI G", + "F IG", + "em a", + "e ma", + "▁Europe an", + "▁S aint", + "▁Sa int", + "▁ Saint", + "AR E", + "A RE", + "ur i", + "u ri", + "▁R iver", + "{ }", + "▁s itting", + "▁sit ting", + "▁under standing", + "▁understand ing", + "▁pl ans", + "▁plan s", + "rop ri", + "▁old er", + "▁ol der", + "▁ older", + "▁pres sure", + "▁press ure", + "Im pl", + "Imp l", + "▁pe ace", + "Conne ction", + "Conn ection", + "Connect ion", + "▁f i", + "▁ fi", + "ri ch", + "ric h", + "r ich", + "▁sh ut", + "ap ers", + "ape rs", + "aper s", + "a pers", + "Po rt", + "P ort", + "▁L ook", + "▁Lo ok", + "▁ Look", + "ri m", + "r im", + "au th", + "aut h", + "a uth", + "au to", + "aut o", + "a uto", + "▁high ly", + "▁un less", + "▁W al", + "▁Wa l", + "▁re n", + "▁r en", + "▁ ren", + "w s", + "▁c ore", + "▁co re", + "▁cor e", + "▁ core", + "( -", + "▁c lim", + "▁cl im", + "ru it", + "r uit", + "▁call back", + "▁ callback", + "he st", + "hes t", + "h est", + "▁Char les", + "▁Charl es", + "▁L ong", + "▁Lo ng", + "▁ Long", + "} =", + "ъ р", + "▁sh ared", + "▁share d", + "▁shar ed", + "▁sha red", + "▁ shared", + "ul ated", + "ula ted", + "ulate d", + "gorith m", + "▁H ome", + "▁Ho me", + "▁Hom e", + "▁ Home", + "▁vill age", + "▁vil lage", + "ee s", + "e es", + "s v", + "▁rest aur", + "re y", + "r ey", + "▁C ast", + "▁Cas t", + "▁Ca st", + "▁ Cast", + "▁P erson", + "▁Per son", + "▁Pers on", + "▁ Person", + "ки й", + "▁organ iz", + "▁R ad", + "▁Ra d", + "▁ Rad", + "pon ents", + "ponent s", + "▁wer den", + "▁werd en", + "▁b ow", + "▁bo w", + "▁ bow", + "se n", + "s en", + "am i", + "a mi", + "Inter face", + "▁b asis", + "▁bas is", + "▁ba sis", + "▁Comp any", + "▁Compan y", + "▁ Company", + "er nel", + "ern el", + "erne l", + "it u", + "i tu", + "Has h", + "Ha sh", + "H ash", + "▁a an", + "▁ х", + "▁s mile", + "▁sm ile", + "x ml", + "▁s cen", + "▁sc en", + "am m", + "a mm", + "to ol", + "too l", + "t ool", + "ar ia", + "ari a", + "a ria", + "▁acc ur", + "▁ac cur", + "▁ accur", + "set tings", + "setting s", + "▁Jes us", + "ac ement", + "ace ment", + "po wer", + "pow er", + "p ower", + "( !", + "▁c alls", + "▁call s", + "▁cal ls", + "▁ calls", + "▁bas ic", + "▁ basic", + "▁set tings", + "▁sett ings", + "▁setting s", + "▁ settings", + "ri pt", + "rip t", + "r ipt", + "po ol", + "p ool", + "ct ors", + "ctor s", + "▁Found ation", + "▁ Foundation", + "▁we ap", + "KE Y", + "K EY", + "fo ot", + "foo t", + "f oot", + "▁r adio", + "▁rad io", + "▁radi o", + "▁ radio", + "▁hel ped", + "▁help ed", + "ma nn", + "man n", + "m ann", + "▁j ump", + "▁ju mp", + "▁t ick", + "▁ti ck", + "▁ tick", + "▁gr owing", + "▁grow ing", + "▁gro wing", + "at en", + "ate n", + "a ten", + "re al", + "rea l", + "▁incre asing", + "Dev ice", + "var epsilon", + "vare psilon", + "▁s ets", + "▁se ts", + "▁set s", + "▁ sets", + "▁adv ant", + "Op en", + "O pen", + "▁re asons", + "▁reason s", + "▁sup posed", + "▁supp osed", + "▁suppose d", + "oe s", + "o es", + "ed e", + "e de", + "te en", + "tee n", + "t een", + "if def", + "▁de lete", + "▁del ete", + "▁delet e", + "▁ delete", + "▁& =", + "▁ &=", + "▁B ill", + "▁Bi ll", + "▁Bil l", + "▁ Bill", + "▁a im", + "▁ai m", + "▁ aim", + "▁O k", + "▁ Ok", + "▁A v", + "▁ Av", + "re ci", + "rec i", + "ac ks", + "ack s", + "a cks", + "is te", + "ist e", + "i ste", + "Pro perties", + "▁t mp", + "▁tm p", + "▁ tmp", + "▁d ei", + "▁de i", + "PE R", + "P ER", + "D C", + "st a", + "s ta", + "ни и", + "▁lim ited", + "▁limit ed", + "▁ limited", + "▁great er", + "▁gre ater", + "de scription", + "des cription", + "or i", + "o ri", + "ain ts", + "aint s", + "▁h y", + "▁ hy", + "▁M el", + "▁Me l", + "▁C H", + "▁ CH", + "con s", + "co ns", + "c ons", + "▁sur round", + "▁W ho", + "▁Wh o", + "▁ Who", + "ar c", + "a rc", + "▁te lev", + "▁tele v", + "▁tel ev", + "it ution", + "itut ion", + "▁e qual", + "▁equ al", + "▁eq ual", + "▁ equal", + "к і", + "▁Is rael", + "ä h", + "▁C aption", + "▁Capt ion", + "▁Ca ption", + "▁ex erc", + "em por", + "emp or", + "▁+ +", + "▁ ++", + "▁l ib", + "▁li b", + "▁ lib", + "ma ke", + "m ake", + "▁M A", + "▁ MA", + "co py", + "cop y", + "c opy", + "f riend", + "▁ко то", + "▁ кото", + "▁dam age", + "▁\\ ,", + "▁ \\,", + "od ed", + "ode d", + "o ded", + "▁n one", + "▁no ne", + "▁non e", + "▁ none", + "▁ev alu", + "▁eval u", + "▁ evalu", + "st on", + "sto n", + "s ton", + "> ,", + "FO R", + "F OR", + "▁n orm", + "▁no rm", + "▁nor m", + "▁ norm", + "ap pe", + "app e", + "a ppe", + "S ession", + "▁ad ult", + "▁h ospital", + "▁hosp ital", + "▁recomm end", + "pro perty", + "ste in", + "fin al", + "fi nal", + "f inal", + "▁n u", + "▁ nu", + "se cond", + "sec ond", + "▁a spect", + "▁as pect", + "▁asp ect", + "\") ]", + "\" )]", + "же н", + "ж ен", + "am ento", + "ament o", + "amen to", + "▁r ac", + "▁ra c", + "▁ rac", + "sa ve", + "s ave", + "▁foot ball", + "A b", + "un gs", + "ung s", + "ab il", + "abi l", + "a bil", + "▁Ar ch", + "▁Arc h", + "▁ Arch", + "sys tem", + "s ystem", + "hi st", + "his t", + "h ist", + "▁l uck", + "▁lu ck", + "▁luc k", + "re nder", + "ren der", + "rend er", + "r ender", + "▁se in", + "▁sei n", + "ion i", + "io ni", + "i oni", + "▁r ot", + "▁ro t", + "▁ rot", + "▁cor ner", + "▁corn er", + "▁app ropri", + "▁ap propri", + "▁ appropri", + "▁Soft ware", + "▁t ele", + "▁te le", + "▁tel e", + "▁ tele", + "De lete", + "Dele te", + "Del ete", + "▁Acc ording", + "▁pr ison", + "▁pri son", + "▁ prison", + "▁l ic", + "▁li c", + "▁ lic", + "▁м и", + "▁ ми", + "ter m", + "te rm", + "t erm", + "se ts", + "set s", + "s ets", + "▁v el", + "▁ve l", + "▁ vel", + "▁r ank", + "▁ran k", + "▁ rank", + "▁ex isting", + "▁exist ing", + "▁ existing", + "▁V ir", + "▁Vi r", + "▁t rip", + "▁tr ip", + "▁tri p", + "▁м у", + "▁ му", + "av ax", + "ava x", + "▁r is", + "▁ri s", + "▁ ris", + "▁def ine", + "▁defin e", + "▁ define", + "▁he at", + "ca r", + "c ar", + "▁con vert", + "▁conv ert", + "▁conver t", + "▁conve rt", + "▁ convert", + "em ail", + "ema il", + "e mail", + "▁U nder", + "▁Un der", + "▁Und er", + "▁ Under", + "▁ Ш", + "▁G rand", + "▁Gr and", + "▁Gran d", + "▁Gra nd", + "▁ex ists", + "▁exist s", + "▁ exists", + "sy s", + "s ys", + "ef f", + "e ff", + "▁T op", + "▁To p", + "▁ Top", + "▁ č", + "▁t empor", + "▁tem por", + "▁temp or", + "▁tempo r", + "▁arg uments", + "▁argument s", + "▁ arguments", + "▁support ed", + "▁supp orted", + "▁ supported", + "en sed", + "ens ed", + "ense d", + "▁Franc is", + "▁co ord", + "▁ coord", + "▁achie ve", + "▁N ame", + "▁Na me", + "▁Nam e", + "▁ Name", + "▁J ahr", + "▁Jah r", + "▁Ja hr", + "▁G i", + "sh e", + "s he", + "▁D ev", + "▁De v", + "▁ Dev", + "▁a lla", + "▁al la", + "▁all a", + "▁ alla", + "▁W IT", + "ag ment", + "c ustom", + "al ls", + "all s", + "& &", + "W E", + "▁h olding", + "▁hold ing", + "▁hol ding", + "pro totype", + "proto type", + "prot otype", + "▁f ing", + "▁fin g", + "▁fi ng", + "▁b ag", + "▁ba g", + "▁ bag", + "▁Par ty", + "▁Part y", + "st ack", + "sta ck", + "▁econom ic", + "▁G al", + "▁Ga l", + "id ents", + "ident s", + "iden ts", + "▁J un", + "▁Ju n", + "▁sh owed", + "▁show ed", + "os h", + "o sh", + "▁B ay", + "▁Ba y", + "▁ Bay", + "ma il", + "m ail", + "▁S O", + "▁ SO", + "▁\" <", + "graph ics", + "▁f u", + "▁ fu", + "cl ick", + "cli ck", + "c lick", + "▁b attle", + "▁batt le", + "▁bat tle", + "{ {", + "▁E vent", + "▁Even t", + "▁Ev ent", + "▁Eve nt", + "▁ Event", + "ri or", + "rio r", + "r ior", + "ch aft", + "cha ft", + "▁f avorite", + "▁favor ite", + "us ive", + "sup port", + "supp ort", + "s upport", + "b m", + "K ind", + "▁saf ety", + "▁safe ty", + "▁E nt", + "▁En t", + "▁ Ent", + "cu p", + "c up", + "▁Austral ia", + "▁dest roy", + "▁destro y", + "▁ destroy", + "▁organ ization", + "▁organiz ation", + "id en", + "ide n", + "i den", + "######## ########", + "de c", + "d ec", + "▁z a", + "▁ za", + "▁s even", + "▁se ven", + "▁ seven", + "ar ely", + "are ly", + "arel y", + "▁f lag", + "▁fl ag", + "▁ flag", + "Di r", + "D ir", + "▁C arl", + "▁Car l", + "▁Ca rl", + "▁do ctor", + "▁doc tor", + "▁var iety", + "▁vari ety", + "▁L in", + "▁Li n", + "▁ Lin", + "▁t om", + "▁to m", + "▁ tom", + "^{ (", + "^ {(", + "B o", + "an tes", + "ant es", + "ante s", + "▁m ine", + "▁min e", + "▁mi ne", + "▁ mine", + "▁M it", + "▁Mi t", + "▁de scribe", + "▁desc ribe", + "▁describ e", + "Ar gs", + "Arg s", + "L S", + "AP I", + "A PI", + "▁L uc", + "▁Lu c", + "▁ Luc", + "ph one", + "▁sc ience", + "▁ science", + "▁O per", + "▁Op er", + "▁ Oper", + "Ne xt", + "N ext", + "▁invest ig", + "▁demon str", + "▁G overn", + "▁Go vern", + "▁object s", + "▁ objects", + "▁Lou is", + "▁Lo uis", + "▁Return s", + "▁ Returns", + "▁h an", + "▁ha n", + "▁ han", + "na m", + "n am", + "▁com me", + "▁comm e", + "▁pres ence", + "▁p el", + "▁pe l", + "▁ pel", + "▁det ect", + "▁ detect", + ") =", + "▁Ch inese", + "▁r ich", + "▁ri ch", + "▁ric h", + "▁ rich", + "▁class es", + "▁classe s", + "▁clas ses", + "▁ classes", + "▁exp and", + "▁ expand", + "▁D om", + "▁Do m", + "▁ Dom", + "▁D ec", + "▁De c", + "▁ Dec", + "s n", + "pe ed", + "p eed", + "▁J im", + "▁Ji m", + "sh ould", + "▁Sm ith", + "▁p ages", + "▁page s", + "▁pa ges", + "▁pag es", + "▁ pages", + "▁Je an", + "ri cs", + "ric s", + "r ics", + "▁S und", + "▁Su nd", + "▁Sun d", + "ad s", + "a ds", + "▁The ir", + "un icip", + "uni cip", + "unic ip", + "в у", + "▁down load", + "▁ download", + "▁st ress", + "▁str ess", + "▁stre ss", + "▁P et", + "▁Pe t", + "▁ Pet", + "me nu", + "men u", + "m enu", + "re me", + "rem e", + "r eme", + "▁com pared", + "▁comp ared", + "▁compar ed", + "▁compare d", + "St e", + "S te", + "IN D", + "I ND", + "cont ainer", + "▁Ind ian", + "▁India n", + "or en", + "ore n", + "o ren", + "▁s es", + "▁se s", + "▁ ses", + "▁W he", + "▁Wh e", + "▁ Whe", + "▁r oku", + "▁ro ku", + "▁estab lished", + "▁establish ed", + "▁gener ally", + "▁general ly", + "▁f le", + "▁fl e", + "__ (", + "_ _(", + "=\" +", + "= \"+", + "V ar", + "▁M ake", + "▁Ma ke", + "▁Mak e", + "▁ Make", + "▁rem oved", + "▁remove d", + "▁ removed", + "z z", + "ü n", + "▁m ix", + "▁mi x", + "▁ mix", + "er k", + "iat ion", + "i ation", + "ou ter", + "out er", + "oute r", + "o uter", + "S K", + "▁be comes", + "▁bec omes", + "▁become s", + "▁H all", + "▁Ha ll", + "▁Hal l", + "sc ious", + "▁w atched", + "▁watch ed", + "▁wat ched", + "▁g ather", + "▁ga ther", + "▁ gather", + "▁Res ult", + "▁ Result", + "pro of", + "pa y", + "p ay", + "▁produ ced", + "▁produce d", + "▁prod uced", + "▁| =", + "▁b order", + "▁bord er", + "▁bor der", + "▁ border", + "▁d in", + "▁di n", + "▁s cript", + "▁sc ript", + "▁scr ipt", + "▁ script", + "▁a ctions", + "▁act ions", + "▁action s", + "▁ actions", + "▁m as", + "▁ma s", + "▁ mas", + "щ а", + "oot h", + "oo th", + "o oth", + "▁Te chn", + "▁Tech n", + "Js on", + "J son", + "▁f illed", + "▁fil led", + "▁fill ed", + "▁ filled", + "де н", + "д ен", + "und le", + "ст у", + "с ту", + "To ol", + "Too l", + "T ool", + "▁k ing", + "▁ki ng", + "▁kin g", + "▁ king", + "▁v en", + "▁ve n", + "▁ ven", + "st ra", + "str a", + "s tra", + "▁pre dict", + "▁pred ict", + "▁ predict", + "▁l ui", + "▁lu i", + "▁WAR RAN", + "▁F un", + "▁Fu n", + "▁ Fun", + "Sc ript", + "S cript", + "▁power ful", + "▁l ose", + "▁lo se", + "▁los e", + "at ically", + "atic ally", + "▁d aily", + "▁da ily", + "▁dai ly", + "▁r ing", + "▁ri ng", + "▁ ring", + "▁ar rived", + "▁arriv ed", + "▁arr ived", + "▁arrive d", + "St ack", + "sc ope", + "s cope", + "▁B ack", + "▁Ba ck", + "▁ Back", + "el ij", + "eli j", + "e lij", + "▁z e", + "▁ ze", + "ke ys", + "key s", + "{ \"", + "VI D", + "V ID", + "▁l icense", + "▁lic ense", + "▁ license", + "wh at", + "w hat", + "▁pro ced", + "▁proc ed", + "ra nt", + "ran t", + "r ant", + "est ival", + "ag ram", + "agr am", + "agra m", + "a gram", + "▁L O", + "▁ LO", + "▁Hen ry", + "▁fl ags", + "▁flag s", + "▁ flags", + "Do wn", + "D own", + "scri ption", + "script ion", + "s cription", + "▁famil ies", + "▁familie s", + "is se", + "iss e", + "bo ur", + "b our", + "▁B ur", + "▁Bu r", + "— \"", + "▁b rief", + "▁br ief", + "▁ brief", + "▁cre ating", + "▁creat ing", + "▁cl ients", + "▁client s", + "ran gle", + "r angle", + "▁amaz ing", + "▁s ind", + "▁si nd", + "▁sin d", + "▁cover ed", + "▁cov ered", + "▁ covered", + "We ll", + "W ell", + "ст е", + "с те", + "то р", + "т ор", + "▁B as", + "▁Ba s", + "▁ Bas", + "to tal", + "tot al", + "t otal", + "▁I nit", + "▁In it", + "▁ Init", + "▁s and", + "▁sa nd", + "▁san d", + "Un it", + "U nit", + "▁mur der", + "▁b right", + "▁br ight", + "▁brig ht", + "▁t rav", + "▁tr av", + "▁tra v", + "ic ans", + "ica ns", + "ican s", + "▁att ribute", + "▁attribut e", + "▁ attribute", + "f c", + "▁pl aced", + "▁place d", + "▁plac ed", + "ES T", + "E ST", + "Var i", + "V ari", + "▁c os", + "▁co s", + "▁ cos", + "▁at tract", + "▁att ract", + "▁attr act", + "▁attra ct", + "an el", + "ane l", + "a nel", + "}) .", + "} ).", + "by tes", + "byte s", + "▁p arse", + "▁par se", + "▁ parse", + "▁be long", + "▁bel ong", + "B N", + "▁S ol", + "▁So l", + "P o", + "` ,", + "▁c alling", + "▁call ing", + "▁cal ling", + "▁? >", + "▁ ?>", + "▁it er", + "▁i ter", + "▁ iter", + "▁u rl", + "▁ur l", + "▁ url", + "▁ev ening", + "▁even ing", + "re ek", + "ree k", + "▁hon est", + "▁direct or", + "▁dire ctor", + "▁dir ector", + "R C", + "▁s olid", + "▁sol id", + "▁ solid", + "▁ph il", + "ie ne", + "ien e", + "i ene", + "FA ULT", + "co pe", + "cop e", + "c ope", + "▁Hist ory", + "▁Histor y", + "▁Hi story", + "▁ History", + "▁Te am", + "▁ Team", + "ree dom", + "reed om", + "▁r u", + "▁ ru", + "U B", + "▁w orse", + "▁wor se", + "im o", + "i mo", + "Ma t", + "M at", + "▁M ex", + "▁Me x", + "ac tor", + "act or", + "a ctor", + "▁v or", + "▁vo r", + "▁ vor", + "ть ся", + "▁exper iment", + "▁experi ment", + "▁P lay", + "▁Pl ay", + "▁ Play", + "▁An other", + "▁happ ens", + "▁happen s", + "ua n", + "u an", + "▁pat ients", + "▁patient s", + "▁re nd", + "▁r end", + "▁ren d", + "▁ rend", + "▁M o", + "▁ Mo", + "▁T ex", + "▁Te x", + "▁ Tex", + "▁w ed", + "▁we d", + "▁ wed", + "t n", + "in sert", + "ins ert", + "▁п а", + "▁ па", + "▁an ti", + "▁ant i", + "▁ anti", + "Mat ch", + "M atch", + "ampions hip", + "ampion ship", + "▁for ces", + "▁force s", + "▁H ot", + "▁Ho t", + "▁ Hot", + "▁ph ase", + "▁ phase", + "▁t emplate", + "▁templ ate", + "▁temp late", + "▁ template", + "st op", + "sto p", + "s top", + "ic ated", + "ica ted", + "icate d", + "▁man aged", + "▁manage d", + "▁ managed", + "wa it", + "w ait", + "▁* (", + "▁ *(", + "G B", + "▁app oint", + "▁ap point", + "▁ appoint", + "ł a", + "▁s tick", + "▁st ick", + "▁ stick", + "▁F OR", + "▁FO R", + "▁ FOR", + "▁V is", + "▁Vi s", + "▁ Vis", + "to r", + "t or", + "▁p ř", + "qu est", + "que st", + "ques t", + "q uest", + "us es", + "use s", + "u ses", + "\"); \r", + "\") ;\r", + "\" );\r", + "▁sudden ly", + "▁sud denly", + "é c", + "N D", + "ur op", + "uro p", + "u rop", + "ре д", + "▁ins urance", + "ac cess", + "acc ess", + "a ccess", + "un finished", + "▁t amb", + "▁ta mb", + "▁tam b", + "▁s ac", + "▁sa c", + "▁C ourt", + "▁Co urt", + "▁Cour t", + "▁Cou rt", + "▁miss ing", + "▁mis sing", + "▁ missing", + "▁W here", + "▁Wh ere", + "▁Whe re", + "▁ Where", + "▁S um", + "▁Su m", + "▁ Sum", + "}^ {\\", + "}^{ \\", + "} ^{\\", + "▁s ua", + "▁su a", + "_ ,", + "▁th ick", + "▁Tr ump", + "▁Tru mp", + "▁oper ations", + "▁operation s", + "▁ operations", + "F S", + "▁de ux", + "d z", + "Temp late", + "T emplate", + "▁\" /", + "▁o dd", + "▁od d", + "▁ odd", + "▁re ality", + "▁real ity", + "▁te ams", + "▁team s", + "▁tea ms", + "▁c er", + "▁ce r", + "▁ cer", + "om a", + "o ma", + "▁ și", + "▁cl oud", + "▁clo ud", + "▁ cloud", + "▁Dep artment", + "N e", + "▁requ ires", + "▁require s", + "it ems", + "ite ms", + "item s", + "▁I II", + "▁II I", + "▁ III", + "right arrow", + ")- >", + ") ->", + "▁w riter", + "▁wr iter", + "▁writ er", + "▁write r", + "▁ writer", + "re place", + "rep lace", + "▁t hr", + "▁th r", + "je n", + "j en", + "▁o t", + "▁ ot", + "▁occ up", + "▁oc cup", + "▁ occup", + "▁event ually", + "▁M ath", + "▁Mat h", + "▁Ma th", + "▁ Math", + "▁con serv", + "▁cons erv", + "▁conse rv", + "am er", + "ame r", + "a mer", + "▁F ort", + "▁For t", + "▁Fo rt", + "▁d ry", + "▁dr y", + "▁sex ual", + "▁co sts", + "▁cost s", + "▁cos ts", + "▁for ms", + "▁form s", + "▁ forms", + "▁V ict", + "▁Vi ct", + "▁Vic t", + "PA R", + "P AR", + "frame work", + "▁д и", + "▁ ди", + "Oper ation", + "з на", + "wh ich", + "▁t ight", + "▁ti ght", + "In valid", + "▁part ner", + "▁п ред", + "▁пре д", + "▁th ank", + "▁than k", + "▁gu ard", + "▁ guard", + "he m", + "h em", + "Bo dy", + "B ody", + "▁e mot", + "▁em ot", + "I X", + "fa st", + "fas t", + "f ast", + "щ о", + "ñ o", + "ni ght", + "n ight", + "▁S ci", + "▁Sc i", + "ни ка", + "ник а", + "▁T O", + "▁ TO", + "▁individ uals", + "▁individual s", + "сс и", + "с си", + "}) ,", + "} ),", + "F alse", + "(\" %", + "( \"%", + "▁op tim", + "▁opt im", + "▁ optim", + "▁- ->", + "▁-- >", + "▁ -->", + "▁f actor", + "▁fact or", + "▁fac tor", + "▁fa ctor", + "▁ factor", + "▁sm aller", + "▁small er", + "▁con tain", + "▁cont ain", + "sp ect", + "spec t", + "spe ct", + "s pect", + "Eng ine", + "▁ann ounced", + "▁announ ced", + "▁announce d", + "▁Dem ocr", + "▁r ob", + "▁ro b", + "▁ rob", + "▁f lat", + "▁fl at", + "▁ flat", + "os oph", + "oso ph", + "Se arch", + "S earch", + "ah l", + "a hl", + "▁Ex ception", + "▁Except ion", + "▁ Exception", + "▁O l", + "equ als", + "eq uals", + "equal s", + "▁un ter", + "▁unt er", + "▁ unter", + "sh ape", + "sha pe", + "N S", + "Ob j", + "▁spec ies", + "▁spe cies", + "we ight", + "wei ght", + "w eight", + "yo u", + "y ou", + "▁e ste", + "▁est e", + "▁es te", + "▁ este", + "▁V iew", + "▁Vi ew", + "▁ View", + "▁m ission", + "▁miss ion", + "▁ mission", + "▁j ournal", + "▁jour nal", + "▁ journal", + "Value s", + "Val ues", + "▁ein em", + "▁eine m", + "is mo", + "ism o", + "▁project s", + "▁ projects", + "▁D as", + "▁Da s", + "ri ble", + "rib le", + "r ible", + "▁s erve", + "▁ser ve", + "▁serv e", + "▁ serve", + "▁op ening", + "▁open ing", + "▁h ur", + "▁program s", + "▁U SA", + "▁US A", + "▁ USA", + "il iar", + "ili ar", + "ilia r", + "id os", + "ido s", + "B r", + "est amp", + "esta mp", + "▁t ools", + "▁to ols", + "▁too ls", + "▁tool s", + "▁ tools", + "an ner", + "ann er", + "anne r", + "R T", + "▁St art", + "▁Star t", + "▁Sta rt", + "▁ Start", + "▁b ath", + "▁bat h", + "▁ba th", + "▁coff ee", + "or ter", + "ort er", + "orte r", + "in ternal", + "inter nal", + "intern al", + "file s", + "fil es", + "fi les", + "f iles", + "IN VAL", + "ak o", + "a ko", + "d t", + "▁Se cond", + "▁Sec ond", + "▁ Second", + "▁al loc", + "▁all oc", + "▁ alloc", + "▁en ded", + "▁end ed", + "▁ende d", + "▁ ended", + "ac ional", + "aci onal", + "acion al", + "acio nal", + "▁man ager", + "▁manage r", + "▁ manager", + "▁S un", + "▁Su n", + "▁ Sun", + "ag g", + "a gg", + "▁le ader", + "▁lead er", + "ol ved", + "olve d", + "olv ed", + "▁ч то", + "▁trad itional", + "▁tradition al", + "sh ot", + "s hot", + "ru p", + "r up", + "C F", + "▁E ach", + "▁ Each", + "w r", + "▁S om", + "▁So m", + "▁ Som", + "▁material s", + "▁mater ials", + "▁m sg", + "▁ms g", + "▁ msg", + "▁s yn", + "▁sy n", + "▁ syn", + "▁produ ce", + "▁prod uce", + "▁st orage", + "▁stor age", + "▁sto rage", + "▁ storage", + "sub section", + "▁S ie", + "▁Si e", + "▁I P", + "▁ IP", + "CE SS", + "▁w a", + "▁ wa", + "Re cord", + "Rec ord", + "▁mark eting", + "▁market ing", + "pl et", + "ple t", + "p let", + "D ialog", + "▁mention ed", + "▁ment ioned", + "▁N a", + "▁ Na", + "▁Un ion", + "▁ Union", + "▁A PI", + "▁AP I", + "▁ API", + "▁neg ative", + "▁ negative", + "tx t", + "t xt", + "▁eas ier", + "le gal", + "leg al", + "De p", + "D ep", + "▁no vel", + "▁nov el", + "▁nove l", + "eu r", + "e ur", + "ac ió", + "aci ó", + "a ció", + "▁B ud", + "▁Bu d", + "▁c arry", + "▁car ry", + "sch aft", + "s chaft", + "▁br oken", + "▁bro ken", + "▁broke n", + "▁t rees", + "▁tr ees", + "▁tre es", + "▁tree s", + ">( );", + ">() ;", + "> ();", + "▁e mb", + "▁em b", + "▁ emb", + "ie der", + "ied er", + "i eder", + "▁r oute", + "▁ro ute", + "▁rout e", + "▁rou te", + "▁ route", + "ik el", + "ike l", + "i kel", + "▁l isten", + "▁li sten", + "▁list en", + "▁ listen", + "ash ion", + "ashi on", + "▁M rs", + "▁Mr s", + "▁equip ment", + "ag ger", + "agg er", + "▁T hus", + "▁Th us", + "▁mat rix", + "▁ matrix", + "al la", + "all a", + "a lla", + "▁T our", + "▁To ur", + "▁con versation", + "▁convers ation", + "Mo n", + "M on", + "our nal", + "▁min ute", + "▁minut e", + "▁ minute", + "A m", + "Ap i", + "A pi", + "▁for get", + "▁forg et", + "M e", + "lev ant", + "te mp", + "tem p", + "t emp", + "▁t elling", + "▁tell ing", + "▁tel ling", + "mo ve", + "mov e", + "m ove", + "▁in dependent", + "▁independ ent", + "to String", + "ed it", + "edi t", + "e dit", + "▁J ac", + "▁Ja c", + "az z", + "a zz", + "re act", + "rea ct", + "▁c in", + "▁ci n", + "▁ cin", + "▁P rov", + "▁Pro v", + "▁Pr ov", + "▁ Prov", + "is ted", + "ist ed", + "iste d", + "i sted", + "▁h ash", + "▁has h", + "▁ha sh", + "▁ hash", + "on na", + "ik i", + "i ki", + "▁gener ated", + "▁generate d", + "▁gene rated", + "▁ generated", + "Re nder", + "Rend er", + "R ender", + "▁psy ch", + "▁ps ych", + "na v", + "n av", + "▁en tr", + "▁ent r", + "▁ entr", + "п ра", + "r x", + "AT H", + "A TH", + "▁ass ume", + "▁assum e", + "Tr ee", + "T ree", + "semb ly", + "sembl y", + "▁M att", + "▁Mat t", + "▁Ma tt", + "ca ption", + "c aption", + "▁s olutions", + "▁solution s", + "▁fa ith", + "▁fait h", + "▁dig ital", + "▁digit al", + "▁ex cell", + "▁exc ell", + "▁V ersion", + "▁Vers ion", + "▁ Version", + "De bug", + "D ebug", + "▁ж и", + "▁ жи", + "▁car ried", + "re set", + "res et", + "▁slow ly", + "an cing", + "anc ing", + "▁own er", + "▁ owner", + "▁T er", + "▁Te r", + "▁D id", + "▁Di d", + "▁ Did", + "▁g est", + "▁ge st", + "▁ges t", + "▁ gest", + "▁é té", + "▁ét é", + "▁ été", + "▁pro of", + "▁ proof", + "F ont", + "▁n ob", + "▁no b", + "▁ nob", + "C o", + "▁G NU", + "▁l iber", + "▁li ber", + "▁lib er", + "it ness", + "▁h ij", + "▁hi j", + "▁v ert", + "▁ver t", + "▁ve rt", + "▁ vert", + "ш а", + "FL AG", + "ME NT", + "M ENT", + "▁S on", + "▁So n", + "Mu lt", + "M ult", + "▁d istrict", + "▁di strict", + "▁dist rict", + "conne ct", + "conn ect", + "ject ion", + "je ction", + "j ection", + "ly mp", + "▁real ized", + "▁realize d", + "▁realiz ed", + "mo s", + "m os", + "y e", + "▁re nder", + "▁r ender", + "▁ren der", + "▁rend er", + "▁ render", + "ri o", + "r io", + "▁inter pret", + "▁ interpret", + "▁slight ly", + "fi x", + "f ix", + "▁stud ies", + "▁r id", + "▁ri d", + "▁ rid", + "at re", + "atr e", + "a tre", + "▁benef its", + "▁benefit s", + "▁F ace", + "▁Fa ce", + "▁Fac e", + "▁ Face", + "iv ery", + "ive ry", + "iver y", + "i very", + "ри я", + "doc ument", + "d ocument", + "▁as king", + "▁ask ing", + "La st", + "L ast", + "ar ante", + "ara nte", + "aran te", + "▁Mart in", + "▁E ll", + "▁El l", + "▁v ector", + "▁ve ctor", + "▁vec tor", + "▁ vector", + "▁for ced", + "▁force d", + "▁ forced", + "о ло", + "P H", + "W R", + "▁K l", + "▁s ky", + "▁sk y", + "▁ sky", + "▁str ategy", + "▁strateg y", + "▁strat egy", + "oc ked", + "ock ed", + "▁ne ck", + "ś ci", + "O UT", + ")) ,", + ") ),", + "C ustom", + "▁w ie", + "▁ wie", + "▁s weet", + "▁swe et", + "▁t emp", + "▁te mp", + "▁tem p", + "▁ temp", + "▁fore ign", + "▁h all", + "▁ha ll", + "▁hal l", + "▁ hall", + "as tr", + "ast r", + "a str", + "As s", + "A ss", + "MO DE", + "MOD E", + "▁max imum", + "▁maxim um", + "an nels", + "ann els", + "annel s", + "anne ls", + "▁t ip", + "▁ti p", + "▁ tip", + "▁second s", + "▁sec onds", + "▁ seconds", + "▁st ack", + "▁sta ck", + "▁ stack", + "ig a", + "i ga", + "▁r aise", + "▁rais e", + "▁ra ise", + "▁ raise", + "en able", + "ena ble", + "oi r", + "o ir", + "▁s oul", + "▁so ul", + "▁sou l", + "K e", + ")$ .", + ") $.", + "▁T im", + "▁Ti m", + "▁ Tim", + "AL SE", + "is er", + "ise r", + "i ser", + "cont in", + "be l", + "b el", + "▁m ad", + "▁ma d", + "▁ mad", + "lic hen", + "li chen", + "lich en", + "liche n", + "l ichen", + "ab e", + "a be", + "sa fe", + "▁con cent", + "▁conc ent", + "▁conce nt", + "bo und", + "b ound", + "▁R equ", + "▁Re qu", + "▁ Requ", + "sw itch", + "▁st one", + "▁sto ne", + "▁ stone", + "▁trans l", + "▁ transl", + "▁v ac", + "▁va c", + "an don", + "and on", + "ando n", + "▁F ore", + "▁For e", + "▁Fo re", + "▁ Fore", + "▁s ounds", + "▁sound s", + "▁P op", + "▁Po p", + "▁ Pop", + "▁H T", + "▁ HT", + "li a", + "l ia", + "en ter", + "ent er", + "ente r", + "▁hel ps", + "▁help s", + "ed y", + "e dy", + "ст вен", + "ств ен", + "стве н", + "an ted", + "ant ed", + "ante d", + "▁I ts", + "▁It s", + "▁St ep", + "▁Ste p", + "▁ Step", + "I con", + "▁EX PECT", + "▁ EXPECT", + "ial ized", + "ialize d", + "Pos t", + "Po st", + "P ost", + "az e", + "a ze", + "▁Car ol", + "▁Ca rol", + "▁re q", + "▁r eq", + "▁ req", + "▁crit ical", + "▁critic al", + "D S", + "▁se at", + "▁sea t", + "ap ed", + "ape d", + "a ped", + "▁up per", + "▁upp er", + "▁ upper", + "▁S y", + "▁ Sy", + "▁ex plain", + "▁expl ain", + "▁' ./", + "▁'. /", + "ut ils", + "util s", + "uti ls", + "poss ible", + "▁d ont", + "▁do nt", + "▁don t", + "H ost", + "▁appro xim", + "▁approx im", + "As ync", + "A sync", + "▁g rab", + "▁gr ab", + "▁gra b", + "▁s ources", + "▁source s", + "▁sour ces", + "▁ sources", + "▁M os", + "▁Mo s", + "▁Germ any", + "▁German y", + "▁Ger many", + "▁r ub", + "▁ru b", + "▁ rub", + "CH AN", + "▁r ain", + "▁ra in", + "▁tr uly", + "▁join ed", + "▁jo ined", + "▁< ?", + "▁ ", + "_ ->", + "ag nost", + "agn ost", + "▁pro posed", + "▁prop osed", + "▁propos ed", + "▁propose d", + "▁G ame", + "▁Ga me", + "▁Gam e", + "▁ Game", + "▁eff orts", + "▁effort s", + "в я", + "t c", + "с к", + "▁int ent", + "▁inte nt", + "▁ intent", + "▁B re", + "▁Br e", + "is c", + "i sc", + "▁pro test", + "▁prote st", + "▁prot est", + "▁h olds", + "▁hold s", + "▁hol ds", + "▁ holds", + "om etry", + "ome try", + "omet ry", + "o metry", + "▁H ave", + "▁Ha ve", + "▁Hav e", + "▁ Have", + "▁de tail", + "▁det ail", + "▁ detail", + "▁WIT HOUT", + "▁WITH OUT", + "ye r", + "y er", + "▁K on", + "▁Ko n", + "▁not iced", + "▁notice d", + "▁require ments", + "▁requirement s", + "DE BUG", + "ki ns", + "kin s", + "k ins", + "▁S pan", + "▁Sp an", + "▁ Span", + "▁c ars", + "▁car s", + "▁ca rs", + "me ta", + "met a", + "m eta", + "▁k il", + "▁ki l", + "▁ kil", + "▁B ron", + "▁Br on", + "▁Bro n", + "▁experience d", + "▁experi enced", + "▁re mind", + "▁rem ind", + "our se", + "ours e", + "▁W estern", + "▁West ern", + "▁Wes tern", + "ter ed", + "te red", + "tere d", + "t ered", + "▁dev ices", + "▁device s", + "▁ devices", + "▁pict ures", + "▁picture s", + "▁t ut", + "▁tu t", + "\" `", + "▁im possible", + "▁r ail", + "▁ra il", + "▁fe els", + "▁feel s", + "▁fee ls", + "ic as", + "ica s", + "i cas", + "il ling", + "ill ing", + "▁acc ident", + "▁' @", + "____ ____", + "▁n otes", + "▁not es", + "▁no tes", + "▁note s", + "▁ notes", + "om an", + "oma n", + "o man", + "Par ser", + "Parse r", + "Pars er", + "▁dis covered", + "▁discover ed", + "▁R oman", + "▁Rom an", + "▁Ro man", + "▁Roma n", + "▁bud get", + "▁gu ide", + "▁guid e", + "ki ng", + "kin g", + "k ing", + "▁in cred", + "▁inc red", + "▁incre d", + "ol ar", + "ola r", + "o lar", + "en den", + "end en", + "ende n", + "Des c", + "De sc", + "D esc", + "▁w ave", + "▁wa ve", + "▁ wave", + "б ли", + "ig t", + "i gt", + "▁re strict", + "▁rest rict", + "▁restr ict", + "▁R et", + "▁Re t", + "▁ Ret", + "▁m ac", + "▁ma c", + "▁ mac", + "у р", + "B S", + "í s", + "▁gener ation", + "de m", + "d em", + "al o", + "a lo", + "б ра", + "▁order ed", + "▁ord ered", + "▁ ordered", + "dr op", + "dro p", + "d rop", + "▁p p", + "▁ pp", + "▁Re view", + "▁Rev iew", + "▁ Review", + "▁liter ally", + "▁literal ly", + "▁S ir", + "▁Si r", + "▁ Sir", + "▁Y eah", + "▁Ye ah", + "▁ Yeah", + "▁d ensity", + "▁dens ity", + "▁ density", + "ri z", + "r iz", + "in de", + "ind e", + "i nde", + "▁g ain", + "▁ga in", + "▁ gain", + "▁p anel", + "▁pan el", + "▁pa nel", + "▁ panel", + "je t", + "j et", + "▁T imes", + "▁Time s", + "▁Tim es", + "▁Ti mes", + "▁ Times", + "▁n ella", + "▁ne lla", + "▁nel la", + "▁nell a", + "▁pre viously", + "▁previous ly", + "▁prev iously", + "point s", + "Se nd", + "S end", + "▁B rown", + "▁Br own", + "▁Bro wn", + "▁Brow n", + "ea ch", + "e ach", + "▁tr igger", + "▁ trigger", + "ome times", + "omet imes", + "ic os", + "ico s", + "i cos", + "G R", + "Pane l", + "Pan el", + "P anel", + "og en", + "oge n", + "o gen", + "▁c m", + "▁ cm", + "ru ctions", + "ruct ions", + "ruction s", + "▁k iss", + "▁ki ss", + "▁s olo", + "▁so lo", + "▁sol o", + "▁f amous", + "▁fam ous", + "ra n", + "r an", + "п ро", + "▁th ro", + "▁thr o", + "Gr aph", + "G raph", + "im it", + "imi t", + "i mit", + "▁V alue", + "▁Val ue", + "▁ Value", + "▁st arts", + "▁start s", + "▁star ts", + "ip eline", + "ipe line", + "h d", + "T C", + "▁dis cussion", + "▁discuss ion", + "▁tr uck", + "ak a", + "a ka", + "On ly", + "▁E qu", + "▁Eq u", + "▁ Equ", + "▁k ö", + "▁ kö", + "▁B es", + "▁Be s", + "▁crit ic", + "▁pro pos", + "▁prop os", + "▁b att", + "▁bat t", + "▁ba tt", + "▁S ection", + "▁Se ction", + "▁ Section", + "Sh ow", + "S how", + "g p", + "ST ATE", + "STAT E", + "PO ST", + "POS T", + "P OST", + "▁N ord", + "▁No rd", + "▁Nor d", + "▁in nov", + "▁inn ov", + "▁c rim", + "▁cr im", + "▁cri m", + "▁ crim", + "ax is", + "a xis", + "▁T urn", + "▁Tur n", + "▁Tu rn", + "▁ Turn", + "con n", + "co nn", + "Run time", + "▁rem aining", + "▁remain ing", + "os ton", + "ost on", + "osto n", + "o ston", + "▁ Э", + "▁window s", + "▁wind ows", + "▁ windows", + "▁R oyal", + "▁Ro yal", + "▁Roy al", + "▁v ide", + "▁vi de", + "▁vid e", + "P P", + "ch ron", + "chr on", + "▁s an", + "▁sa n", + "▁ san", + "▁r ise", + "▁ri se", + "▁ris e", + "▁ rise", + "▁d elle", + "▁de lle", + "▁del le", + "▁dell e", + "▁D ur", + "▁Du r", + "▁rap id", + "▁ra pid", + "ce rt", + "cer t", + "c ert", + "L A", + "ed ge", + "▁\\ ]", + "▁ \\]", + "▁en tered", + "▁ent ered", + "▁enter ed", + "▁l aws", + "▁la ws", + "▁law s", + "▁ph oto", + "▁phot o", + "▁ photo", + "▁ap plications", + "▁applic ations", + "▁application s", + "▁appl ications", + "▁Ber lin", + "▁ar rest", + "▁arr est", + "▁f ederal", + "▁fed eral", + "▁feder al", + "▁R ussia", + "▁Russ ia", + "▁us ual", + "▁r aw", + "▁ra w", + "▁ raw", + "▁pi ù", + "êt re", + "ê tre", + "JS ON", + "J SON", + "SI ON", + "S ION", + "xt ure", + "ist ent", + "iste nt", + "isten t", + "▁P ower", + "▁Po wer", + "▁Pow er", + "▁ Power", + "Bi t", + "B it", + "▁cap acity", + "▁capac ity", + "▁ capacity", + "▁c ards", + "▁car ds", + "▁card s", + "▁ cards", + "UI D", + "U ID", + "im ents", + "iment s", + "imen ts", + "i ments", + "▁d ar", + "▁da r", + "▁ dar", + "▁Ch icago", + "▁comfort able", + "ti p", + "t ip", + "ba s", + "b as", + "▁m u", + "▁ mu", + "▁en emy", + "▁enem y", + "ya n", + "y an", + "▁ф и", + "▁ фи", + "▁up dated", + "▁update d", + "▁ updated", + "an go", + "ang o", + "E v", + "E ffect", + "os ing", + "osi ng", + "o sing", + "ren ce", + "r ence", + "▁Con gress", + "▁Cong ress", + "▁d efe", + "▁de fe", + "▁def e", + "▁i p", + "▁ ip", + "▁t out", + "▁to ut", + "▁tou t", + "▁f reedom", + "▁free dom", + "▁freed om", + "▁a o", + "▁ ao", + "▁There fore", + "▁Ther efore", + "Ed it", + "E dit", + "▁Vir gin", + "RE E", + "R EE", + "ar go", + "arg o", + "▁D am", + "▁Da m", + "▁ Dam", + "▁tra ffic", + "▁traff ic", + "ño s", + "ñ os", + "▁a lle", + "▁al le", + "▁all e", + "▁ alle", + "▁dep th", + "▁ depth", + "No w", + "N ow", + "▁s ides", + "▁side s", + "▁si des", + "▁sid es", + "▁го ди", + "▁год и", + "Des criptor", + "▁art ikel", + "▁n arrow", + "▁narr ow", + "▁nar row", + "__ _", + "_ __", + "k w", + "ut o", + "u to", + "▁Face book", + "▁Fac ebook", + "te gr", + "t egr", + "bo olean", + "ni k", + "n ik", + "b d", + "Tr ack", + "Tra ck", + "▁g ran", + "▁gr an", + "▁gra n", + "res hold", + "resh old", + "ве т", + "в ет", + "wr ap", + "w rap", + "▁n oise", + "▁no ise", + "ig u", + "i gu", + "▁B on", + "▁Bo n", + "▁ Bon", + "▁w y", + "▁ wy", + "lin ux", + "ck s", + "c ks", + "▁f ans", + "▁fa ns", + "▁fan s", + "▁m ach", + "▁ma ch", + "▁mac h", + "▁p rices", + "▁pr ices", + "▁pri ces", + "▁price s", + "é v", + "ou ts", + "out s", + "o uts", + "stand ing", + "stan ding", + "▁c ateg", + "▁cat eg", + "; \\", + "▁de cre", + "▁dec re", + "▁S aturday", + "▁m enu", + "▁me nu", + "▁men u", + "▁ menu", + "▁N ov", + "▁No v", + "▁Y et", + "▁Ye t", + "▁та к", + "lic he", + "li che", + "lich e", + "l iche", + "▁Ac adem", + "▁commun ication", + "us ing", + "u sing", + "▁Soc iety", + "▁Soci ety", + "▁n uc", + "▁nu c", + "pect ive", + "or ial", + "oria l", + "ori al", + "o rial", + "▁af raid", + "▁an imal", + "▁anim al", + "▁turn ing", + "▁tur ning", + "ds t", + "d st", + "math frak", + "le rs", + "ler s", + "l ers", + "▁l ots", + "▁lo ts", + "▁lot s", + "▁ á", + "▁T ra", + "▁Tr a", + "▁ Tra", + "n p", + "▁r ose", + "▁ro se", + "▁ rose", + "▁G L", + "▁ GL", + "▁hel ping", + "▁help ing", + "▁w inter", + "▁win ter", + "▁ко м", + "▁ ком", + "Mo ck", + "M ock", + "▁invest ment", + "Us e", + "U se", + "▁Can ad", + "н д", + "Co py", + "Cop y", + "C opy", + "▁f ly", + "▁fl y", + "▁ fly", + "SE R", + "S ER", + "▁F ar", + "▁Fa r", + "▁R os", + "▁Ro s", + "am il", + "ami l", + "a mil", + "▁fight ing", + "▁rel igious", + "▁relig ious", + "su per", + "sup er", + "s uper", + "sc reen", + "scr een", + "s creen", + "▁f urn", + "▁fur n", + "▁fu rn", + "▁surpr ised", + "▁surprise d", + "▁re plied", + "▁repl ied", + "Act ivity", + "Activ ity", + "▁D own", + "▁Do wn", + "▁Dow n", + "▁ Down", + "▁in sert", + "▁ins ert", + "▁ insert", + "▁O lymp", + "▁point ed", + "▁po inted", + "▁C ard", + "▁Car d", + "▁Ca rd", + "▁ Card", + "dr iver", + "drive r", + "d river", + "▁D a", + "▁ Da", + "! --", + "ro ud", + "rou d", + "r oud", + "un do", + "und o", + "▁m essages", + "▁message s", + "▁mess ages", + "▁ messages", + "▁P oint", + "▁Po int", + "▁ Point", + "V M", + "▁p lane", + "▁pl ane", + "▁plan e", + "▁ plane", + "x c", + "▁telev ision", + "▁tele vision", + "▁televis ion", + "ё н", + "▁thous ands", + "▁thousand s", + "▁c ris", + "▁cr is", + "▁cri s", + "▁de lay", + "▁del ay", + "▁ delay", + "▁N ext", + "▁Ne xt", + "▁ Next", + "▁no mbre", + "▁nom bre", + "▁t u", + "▁ tu", + "▁sk ip", + "▁ski p", + "▁ skip", + "ro ad", + "r oad", + "istr ation", + "▁t ur", + "▁tu r", + "▁De velop", + "▁Devel op", + "▁П а", + "▁д ру", + "▁др у", + "▁wonder ful", + "> &", + "▁L iber", + "▁Li ber", + "▁Lib er", + "▁s cope", + "▁sc ope", + "▁ scope", + "▁man age", + "▁ma nage", + "▁d ass", + "▁da ss", + "▁das s", + "▁re call", + "▁rec all", + "P M", + "▁re levant", + "▁relev ant", + "▁E arth", + "▁ка к", + "▁a pr", + "▁ap r", + "▁A SS", + "▁AS S", + "▁ ASS", + "ié n", + "i én", + "▁S H", + "▁ SH", + "oo m", + "o om", + "it et", + "ite t", + "no ne", + "non e", + "n one", + "as i", + "a si", + "▁mot or", + "▁mo tor", + "▁S how", + "▁Sh ow", + "▁ Show", + "n b", + "▁fact ors", + "▁fa ctors", + "▁factor s", + "▁f orest", + "▁for est", + "▁fore st", + "▁fo rest", + "▁в ре", + "th m", + "t hm", + "▁m unicip", + "▁turn s", + "▁tur ns", + "▁Div ision", + "▁Di vision", + "E C", + "▁dis appe", + "struct or", + "stru ctor", + "▁some where", + "▁Afr ican", + "▁Africa n", + "▁Inst itute", + "▁Institut e", + "Gr id", + "G rid", + "▁te acher", + "▁teach er", + "▁tea cher", + "ur ies", + "uri es", + "u ries", + "▁respect ively", + "▁respective ly", + "▁S D", + "▁ SD", + "▁a live", + "▁al ive", + "▁ali ve", + "▁p ou", + "▁po u", + "▁W ater", + "▁Wat er", + "▁Wa ter", + "▁ Water", + "ф е", + "▁ch anging", + "▁chang ing", + "▁ changing", + "▁after noon", + "▁or ders", + "▁order s", + "▁ord ers", + "▁ orders", + "Re t", + "R et", + "Point er", + "Po inter", + "▁s av", + "▁sa v", + "er g", + "e rg", + "ok ed", + "oke d", + "o ked", + "ess ions", + "ession s", + "▁F ire", + "▁Fi re", + "▁ Fire", + "ar et", + "are t", + "a ret", + "im m", + "i mm", + "▁des ire", + "▁ що", + "▁De sign", + "▁Des ign", + "▁ Design", + "ut ure", + "▁Off ice", + "▁c md", + "▁cm d", + "▁ cmd", + "▁e ating", + "▁eat ing", + "Net work", + "▁r ough", + "▁ro ugh", + "▁rou gh", + "▁ rough", + "oper ator", + "IG N", + "I GN", + "▁s ports", + "▁sp orts", + "▁sport s", + "▁w eren", + "▁we ren", + "▁were n", + "▁wer en", + "▁n oted", + "▁not ed", + "▁no ted", + "▁note d", + "▁tw ice", + "II I", + "I II", + "▁a nx", + "▁an x", + "▁e lim", + "▁el im", + "▁а в", + "▁i o", + "▁ io", + "▁spe ech", + "▁con du", + "▁cond u", + "el les", + "ell es", + "elle s", + "id ade", + "ida de", + "idad e", + "▁adv ance", + "R I", + "oc a", + "o ca", + "/ \\", + "ap shot", + "aps hot", + "▁t ail", + "▁ta il", + "▁ tail", + "mod els", + "model s", + "mode ls", + "og y", + "o gy", + "▁J eff", + "▁Je ff", + "ir ation", + "irat ion", + "▁K ore", + "▁Ko re", + "▁Kor e", + "▁le ads", + "▁lead s", + "ba t", + "b at", + "Ad apter", + "c ategory", + "ang ular", + "angu lar", + "▁s aved", + "▁sa ved", + "▁save d", + "▁sav ed", + "▁ saved", + "▁un iform", + "▁ uniform", + "▁n é", + "▁ né", + "▁business es", + "His t", + "Hi st", + "H ist", + "▁а р", + "▁ ар", + "do main", + "dom ain", + "▁S i", + "▁ Si", + "ra ise", + "rais e", + "rai se", + "r aise", + "▁w arn", + "▁war n", + "▁wa rn", + "▁ warn", + "het ic", + "h etic", + "▁G ro", + "▁Gr o", + ")) .", + ") ).", + "} >", + "з е", + "▁Amaz on", + "▁Or gan", + "▁ Organ", + "▁L ake", + "▁La ke", + "▁ag reement", + "▁agree ment", + "▁agre ement", + "x a", + "▁p erman", + "▁per man", + "▁perm an", + "▁cont aining", + "▁contain ing", + "▁st range", + "▁str ange", + "▁strang e", + "ст і", + "с ті", + "▁st upid", + "▁spe aking", + "▁speak ing", + "▁Intern et", + "▁Inter net", + "pre fix", + "pref ix", + "p refix", + "es c", + "e sc", + "As sert", + "Ass ert", + "pro te", + "pr ote", + "prot e", + "p rote", + "▁m anner", + "▁man ner", + "▁S z", + "un te", + "unt e", + "u nte", + "io t", + "i ot", + "Pro file", + "ov en", + "ove n", + "o ven", + "▁for med", + "▁form ed", + "▁forme d", + "▁ formed", + "▁l it", + "▁li t", + "▁ lit", + "▁econom y", + "▁ec onomy", + "▁c z", + "▁ cz", + "wi d", + "w id", + "RE Q", + "R EQ", + "▁ch osen", + "▁cho sen", + "▁chose n", + "▁P rodu", + "▁Pro du", + "▁ Produ", + "os ter", + "ost er", + "o ster", + "st ances", + "stance s", + "stan ces", + "aw a", + "a wa", + "▁R en", + "▁Re n", + "▁conf irm", + "▁ confirm", + "▁Б о", + "▁b illion", + "▁bill ion", + "▁d éc", + "▁dé c", + "ý ch", + "▁ill ustr", + "TI ES", + "T IES", + "▁P ub", + "▁Pu b", + "▁ Pub", + "▁b an", + "▁ba n", + "▁ ban", + "ad ed", + "ade d", + "a ded", + "ah n", + "a hn", + "▁C ath", + "▁Cat h", + "▁Ca th", + "no number", + "non umber", + "▁wor st", + "▁М е", + "▁sugg ested", + "▁suggest ed", + "st ats", + "stat s", + "sta ts", + "▁c ant", + "▁can t", + "▁ca nt", + "▁al ign", + "▁ali gn", + "▁ align", + "kap pa", + "k appa", + "▁h en", + "▁he n", + "▁ hen", + "▁in iti", + "▁init i", + "'] )", + "' ])", + "B I", + "▁g arden", + "▁gar den", + "▁gard en", + "▁sec ure", + "▁secur e", + "▁ secure", + "▁\\ [", + "▁ \\[", + "hand ler", + "handle r", + "el li", + "ell i", + "e lli", + "ld ots", + "l dots", + "se cut", + "sec ut", + "s ecut", + "▁ext ended", + "▁extend ed", + "} -", + "an ie", + "ani e", + "a nie", + "▁F ind", + "▁Fin d", + "▁Fi nd", + "▁ Find", + "▁M useum", + "▁Muse um", + "▁C onne", + "▁Con ne", + "▁ Conne", + "y y", + "▁pass ion", + "ak ers", + "ake rs", + "aker s", + "a kers", + "ah r", + "a hr", + "olog ies", + "ologie s", + "▁equ ation", + "▁eq uation", + "▁ equation", + "▁occ asion", + "▁occas ion", + "Le t", + "L et", + "'] ['", + "'][ '", + "' ]['", + "Pr int", + "an es", + "ane s", + "a nes", + "ie nte", + "ient e", + "ien te", + "i ente", + "▁T oday", + "▁To day", + "▁Tod ay", + "LE CT", + "L ECT", + "▁A f", + "▁ Af", + ", ,", + "▁Т а", + "▁` ``", + "▁`` `", + "ev en", + "eve n", + "e ven", + "si n", + "s in", + "ur er", + "ure r", + "u rer", + "▁ °", + "ot imes", + "oti mes", + "o times", + "▁I O", + "▁ IO", + "▁po et", + "() ));", + "()) );", + "())) ;", + "( )));", + "▁ −", + "▁ad opt", + "ph ere", + "pher e", + "p here", + "# [", + "▁c entre", + "▁cent re", + "ov es", + "ove s", + "o ves", + "▁a ns", + "▁an s", + "▁ ans", + "d p", + "▁K ir", + "▁Ki r", + "▁applic able", + "f p", + "▁vis ual", + "▁ok ay", + "or o", + "o ro", + "▁opportun ities", + "Re pository", + "Rep ository", + "▁l l", + "▁ ll", + "▁R od", + "▁Ro d", + "▁s hel", + "▁sh el", + "▁she l", + "▁la unch", + "▁con ven", + "▁conv en", + "▁conve n", + "▁S pe", + "▁Sp e", + "▁ Spe", + "Am er", + "A mer", + "▁c ette", + "▁cet te", + "Con d", + "Co nd", + "C ond", + "de p", + "d ep", + "O wn", + "▁h ook", + "▁ho ok", + "▁ hook", + "▁d ict", + "▁di ct", + "▁dic t", + "▁ dict", + "▁Th ose", + "▁f ellow", + "▁fell ow", + "▁fel low", + "▁phil osoph", + "▁philos oph", + "vi n", + "v in", + "fer ences", + "ference s", + "ha v", + "h av", + "▁ad ding", + "▁add ing", + "▁ adding", + "ivers e", + "iver se", + "i verse", + "ga me", + "g ame", + "▁Bl ue", + "▁ Blue", + "▁c lin", + "▁cl in", + "not e", + "no te", + "n ote", + "▁R am", + "▁Ra m", + "ме р", + "м ер", + "co very", + "cover y", + "cov ery", + "c overy", + "ñ a", + "▁б и", + "▁ би", + "▁f ashion", + "▁b roke", + "▁br oke", + "▁bro ke", + "▁' \\", + "▁ '\\", + "▁re ader", + "▁read er", + "▁ reader", + "но е", + "но сти", + "ност и", + "▁pay ment", + "▁ payment", + "▁L ic", + "▁Li c", + "▁l ips", + "▁li ps", + "▁lip s", + "▁ac adem", + "▁M ot", + "▁Mo t", + "el ls", + "ell s", + "C HECK", + "▁р у", + "▁ ру", + "▁M S", + "▁ MS", + "Ed itor", + "Edit or", + "▁z one", + "▁zo ne", + "▁ zone", + "it ure", + "itu re", + "▁I T", + "▁ IT", + "run time", + "▁pro ceed", + "▁proc eed", + "ло в", + "л ов", + "▁M aria", + "▁Mar ia", + "▁Ma ria", + "ol ver", + "olve r", + "olv er", + "▁Th anks", + "▁Thank s", + "▁ Thanks", + "▁should n", + "▁J oh", + "▁Jo h", + "▁Mod el", + "▁Mo del", + "▁Mode l", + "▁ Model", + "▁S ov", + "▁So v", + "! '", + "D i", + "▁c ancer", + "▁can cer", + "Id ent", + "▁ex change", + "il ler", + "ill er", + "ille r", + "in f", + "i nf", + "LE N", + "L EN", + "() {", + "( ){", + "ag a", + "a ga", + "\"] ,", + "\" ],", + "u h", + "▁K en", + "▁Ke n", + "▁ph otos", + "▁phot os", + "▁photo s", + "▁t iny", + "▁ti ny", + "▁tin y", + "▁ tiny", + "▁g ent", + "▁gen t", + "▁ge nt", + "▁ gent", + "ü l", + "▁T ake", + "▁Ta ke", + "▁Tak e", + "▁ Take", + "id el", + "ide l", + "i del", + "ou ting", + "out ing", + "In ternal", + "Inter nal", + "Intern al", + "▁c ells", + "▁cell s", + "▁cel ls", + "ни м", + "н им", + "ha rd", + "har d", + "h ard", + "▁T own", + "▁To wn", + "▁Tow n", + "ob e", + "o be", + "pl ex", + "ple x", + "p lex", + "те р", + "т ер", + "to ns", + "ton s", + "t ons", + "▁conc entr", + "▁concent r", + "mo ck", + "m ock", + "v c", + "á z", + "▁Ch ampionship", + "▁Champion ship", + "▁Champions hip", + "▁б е", + "▁ бе", + "? ?", + "ér i", + "é ri", + "al y", + "a ly", + "▁ Ц", + "ier te", + "iert e", + "▁tot ally", + "▁total ly", + "▁A uf", + "▁Au f", + "▁our selves", + "▁S elf", + "▁Sel f", + "▁ Self", + "Form s", + "For ms", + "ight er", + "igh ter", + "▁is land", + "fm t", + "f mt", + "▁r c", + "▁ rc", + "▁t ells", + "▁tell s", + "▁tel ls", + "B B", + "di t", + "d it", + "▁vari ables", + "▁variable s", + "▁ variables", + "▁int ended", + "▁intend ed", + "iz ont", + "izon t", + "izo nt", + "▁pl ays", + "▁play s", + "da m", + "d am", + "se q", + "s eq", + "▁S up", + "▁Su p", + "▁ Sup", + "▁c ultural", + "▁cult ural", + "▁sc ream", + "__ ,", + "_ _,", + "ci pl", + "cip l", + "Time out", + "▁ ж", + "or te", + "ort e", + "▁repl aced", + "▁replace d", + "E M", + "▁ab andon", + "▁Spec ial", + "▁Spe cial", + "▁ Special", + "el len", + "ell en", + "elle n", + "▁B ru", + "▁Br u", + "ir med", + "irm ed", + "T e", + "ol t", + "o lt", + "j u", + "Arg ument", + "▁ne ut", + "▁neu t", + "▁ neut", + "sc ape", + "▁R ay", + "▁Ra y", + "▁ Ray", + "▁Pol it", + "▁Po lit", + "▁crow d", + "▁cro wd", + "▁Window s", + "▁Wind ows", + "▁ Windows", + "ie go", + "ieg o", + "i ego", + "▁e scape", + "▁esc ape", + "▁ escape", + "▁Ap ache", + "sy nc", + "syn c", + "s ync", + "eb en", + "e ben", + "if ies", + "ifi es", + "et her", + "eth er", + "ethe r", + "e ther", + "Met a", + "Me ta", + "M eta", + "▁big gest", + "Ga me", + "G ame", + "▁trans action", + "▁ transaction", + "En v", + "E nv", + "▁М о", + "▁pl enty", + "▁m el", + "▁me l", + "▁ mel", + "п ре", + "▁mot iv", + "▁о р", + "▁ ор", + "or gan", + "org an", + "▁m ock", + "▁mo ck", + "▁ mock", + "▁$ _", + "▁ $_", + "ен е", + "е не", + "▁N umber", + "▁Num ber", + "▁Nu mber", + "▁ Number", + "ck now", + "c know", + "▁Up date", + "▁ Update", + "ze ro", + "zer o", + "z ero", + "▁sur prise", + "▁surpr ise", + "ce an", + "pd f", + "p df", + "Gl obal", + "▁att end", + "▁f ond", + "▁fo nd", + "▁fon d", + "▁under stood", + "Na v", + "N av", + "▁M ic", + "▁Mi c", + "▁ Mic", + "= $", + "ok ing", + "oki ng", + "o king", + "▁Stad ium", + "Cl ose", + "▁compet ition", + "▁sold iers", + "▁soldier s", + "▁O P", + "▁ OP", + "ag ne", + "agn e", + "▁An ton", + "▁Ant on", + "Ma in", + "M ain", + "á k", + "▁# [", + "▁ #[", + "▁Com mit", + "▁Comm it", + "▁ Commit", + "py x", + "▁e ast", + "▁eas t", + "▁ east", + "▁Or der", + "▁Ord er", + "▁ Order", + "F loat", + "▁accept ed", + "▁mon itor", + "▁ monitor", + "▁p ad", + "▁pa d", + "▁ pad", + "on ic", + "oni c", + "o nic", + "▁p ushed", + "▁push ed", + "▁re place", + "▁rep lace", + "▁repl ace", + "▁ replace", + "CR E", + "C RE", + "▁r ide", + "▁ri de", + "▁rid e", + "▁ ride", + "fo und", + "f ound", + "= %", + "во й", + "▁mat ches", + "▁match es", + "▁ matches", + "▁L ie", + "▁Li e", + "▁exper iences", + "▁experience s", + "▁experi ences", + "Po ol", + "P ool", + "up s", + "u ps", + "A V", + "▁ex istence", + "▁exist ence", + "▁t hin", + "▁th in", + "▁m agn", + "▁mag n", + "▁ma gn", + "CO MP", + "COM P", + "ho me", + "hom e", + "h ome", + "▁n i", + "▁ ni", + "▁wur den", + "▁wurde n", + "ла в", + "▁te eth", + "▁S tan", + "▁St an", + "▁Sta n", + "ap pro", + "app ro", + "an ny", + "ann y", + "if ts", + "ift s", + "▁un known", + "▁ unknown", + "▁h omes", + "▁home s", + "▁hom es", + "▁ho mes", + "▁ent ity", + "▁ entity", + "ci e", + "c ie", + "ле ние", + "ia r", + "i ar", + "▁compl iance", + "▁focus ed", + "uz z", + "u zz", + "=\\ \"", + "= \\\"", + "com ponents", + "component s", + "Att r", + "At tr", + "all ery", + "alle ry", + "aller y", + "▁ident ify", + "O k", + "pi e", + "p ie", + "▁St ill", + "▁off ering", + "▁offer ing", + "▁bu sy", + "▁bus y", + "ct l", + "c tl", + "it ors", + "itor s", + "ito rs", + "▁concern ed", + "▁concer ned", + "▁b rown", + "▁br own", + "▁bro wn", + "▁brow n", + "cl k", + "Se lected", + "Select ed", + "▁B lock", + "▁Bl ock", + "▁Blo ck", + "▁ Block", + "▁e gy", + "▁eg y", + "▁ egy", + "ic ing", + "ici ng", + "i cing", + "▁U RL", + "▁ URL", + "▁t opic", + "▁to pic", + "▁top ic", + "▁ topic", + "▁Pro duct", + "▁Produ ct", + "▁ Product", + "▁ч и", + "▁ чи", + "▁t rial", + "▁tr ial", + "▁tri al", + "▁week end", + "l u", + "▁I V", + "▁ IV", + "▁E gy", + "▁Eg y", + "x C", + "▁n ove", + "▁no ve", + "▁nov e", + "▁l ett", + "▁le tt", + "▁let t", + "▁ lett", + "en ne", + "enn e", + "() ).", + "()) .", + "( )).", + ".* *", + ". **", + "▁p romise", + "▁prom ise", + "el ection", + "ele ction", + "elect ion", + "e lection", + "Aut h", + "A uth", + "r v", + "ri l", + "r il", + "▁con duct", + "▁cond uct", + "▁condu ct", + "▁ conduct", + "▁main tain", + "▁maint ain", + "▁bo at", + "▁ boat", + "▁op posite", + "▁oppos ite", + "sp in", + "spi n", + "s pin", + "web pack", + "an ta", + "ant a", + "▁o rient", + "▁or ient", + "▁ orient", + "▁s uc", + "▁su c", + "▁ex ercise", + "▁exerc ise", + "▁eff icient", + "▁ efficient", + "▁trad ition", + "▁z w", + "▁ zw", + "▁S ud", + "▁Su d", + "go ing", + "▁P ier", + "▁Pi er", + "in v", + "i nv", + "ip es", + "ipe s", + "i pes", + "ensure math", + "▁con ver", + "▁conv er", + "▁conve r", + "cre en", + "cr een", + "c reen", + "▁t error", + "▁ter ror", + "▁terr or", + "▁D ou", + "▁Do u", + "▁in valid", + "▁ invalid", + "ce ived", + "ceive d", + "▁A rab", + "▁Ar ab", + "▁w ire", + "▁wir e", + "▁ wire", + "ap plication", + "sh ift", + "Gener ic", + "▁P lan", + "▁Pl an", + "▁ Plan", + "▁W all", + "▁Wal l", + "▁Wa ll", + "▁ Wall", + "▁direct ory", + "▁director y", + "▁ directory", + "▁e gg", + "▁eg g", + "▁we alth", + "▁ wealth", + "ran dom", + "rand om", + "r andom", + "att ribute", + "▁h ide", + "▁hi de", + "▁hid e", + "▁ hide", + "Se rial", + "Ser ial", + "S erial", + "ca m", + "c am", + "▁it al", + "▁i tal", + "▁ ital", + "▁L ine", + "▁Lin e", + "▁Li ne", + "▁ Line", + "▁C HECK", + "▁ CHECK", + "ploy ment", + "▁mass ive", + "▁ex tract", + "▁ext ract", + "▁extra ct", + "▁extr act", + "▁ extract", + "ch ain", + "cha in", + "Res t", + "Re st", + "R est", + "▁L as", + "▁La s", + "▁b ear", + "▁be ar", + "▁ bear", + "▁l inks", + "▁link s", + "▁lin ks", + "▁ links", + "▁new sp", + "▁news p", + "▁F C", + "▁ FC", + "Car d", + "C ard", + "ak s", + "a ks", + "▁v isible", + "▁vis ible", + "▁ visible", + "▁M arc", + "▁Mar c", + "▁Ma rc", + "▁B oston", + "▁Bo ston", + "▁Bos ton", + "▁res erved", + "▁reserv ed", + "▁reserve d", + "▁ro of", + "lic enses", + "license s", + "d c", + "▁In formation", + "▁ Information", + "▁w itness", + "S k", + "*) ,", + "* ),", + "Sc ope", + "S cope", + "'] ;", + "' ];", + "▁M ir", + "▁Mi r", + "▁ Mir", + "ud ing", + "udi ng", + "u ding", + "▁t rend", + "▁tr end", + "▁tre nd", + "▁tren d", + "re p", + "r ep", + "▁mus ical", + "▁music al", + "▁ne ither", + "▁nei ther", + "▁C reat", + "▁Cre at", + "▁ Creat", + "▁pos itions", + "▁position s", + "▁posit ions", + "L C", + "rid ge", + "r idge", + "▁offic ers", + "▁office rs", + "▁officer s", + "▁vi olence", + "▁viol ence", + "▁T em", + "▁Te m", + "▁S us", + "▁Su s", + "▁W ay", + "▁Wa y", + "Af ter", + "A fter", + "ac ket", + "ack et", + "▁S ou", + "▁So u", + "ac er", + "ace r", + "a cer", + "| |", + "▁re mark", + "▁r emark", + "▁rem ark", + "▁ remark", + "wa ter", + "w ater", + "n ě", + "▁С а", + "▁s ed", + "▁se d", + "▁ sed", + "E ach", + "▁phot ograph", + "▁photo graph", + "▁let ters", + "▁letter s", + "▁lett ers", + "▁in vent", + "▁inv ent", + "▁M as", + "▁Ma s", + "▁s ongs", + "▁son gs", + "▁song s", + "ó l", + "ki nd", + "kin d", + "k ind", + "▁N on", + "▁No n", + "▁ Non", + "▁d ust", + "▁du st", + "** :", + "* *:", + "nab la", + ".\" ,", + ". \",", + "Loc k", + "Lo ck", + "L ock", + "▁Д о", + "▁cl uster", + "▁ cluster", + "lo ss", + "los s", + "l oss", + "▁ASS ERT", + "▁ ASSERT", + "fa ll", + "f all", + "▁re ject", + "▁ reject", + "▁Sp ring", + "▁Spr ing", + "▁ Spring", + "▁wed ding", + "▁g rav", + "▁gr av", + "▁gra v", + "▁ grav", + "ress ion", + "r ession", + "li mit", + "lim it", + "l imit", + "RE S", + "R ES", + "] }", + "▁l isted", + "▁li sted", + "▁list ed", + "▁ listed", + "▁T ele", + "▁Te le", + "▁Tel e", + "▁ Tele", + "hl ine", + "h line", + "▁ch ief", + "▁chi ef", + "ME M", + "M EM", + "да р", + "д ар", + "▁exp ensive", + "tr ace", + "tra ce", + "▁R og", + "▁Ro g", + "▁C oll", + "▁Col l", + "▁Co ll", + "▁ Coll", + "▁Aut hor", + "▁Auth or", + "▁ Author", + "▁B oard", + "▁Bo ard", + "▁ Board", + "▁C apt", + "▁Cap t", + "▁Ca pt", + "▁ Capt", + "TE XT", + "T EXT", + "▁re con", + "▁rec on", + "es ta", + "est a", + "e sta", + "▁proper ly", + "▁& \\", + "▁ &\\", + "le ton", + "let on", + "l eton", + "ik er", + "ike r", + "i ker", + "G u", + "▁K om", + "▁Ko m", + "oc o", + "o co", + "▁any more", + "▁t aste", + "▁ta ste", + "▁tast e", + "▁S anta", + "▁San ta", + "▁Sant a", + "ge x", + "g ex", + "▁Se cret", + "▁Sec ret", + "▁ Secret", + "▁tal ent", + "▁tale nt", + "▁mom ents", + "▁moment s", + "▁mo ments", + "▁B a", + "▁ex tr", + "▁ext r", + "▁ extr", + "▁Com mission", + "▁Comm ission", + "▁mod ify", + "▁Fig ure", + "▁ Figure", + "▁d omin", + "▁do min", + "▁dom in", + "▁ domin", + "▁p lot", + "▁pl ot", + "▁ plot", + "en ger", + "eng er", + "enge r", + "ut ch", + "▁c ities", + "▁cit ies", + "▁ci ties", + "▁n ut", + "▁nu t", + "▁ nut", + "pro file", + "prof ile", + "▁S tat", + "▁St at", + "▁Sta t", + "▁ Stat", + "▁n odes", + "▁no des", + "▁node s", + "▁nod es", + "▁ nodes", + "▁n s", + "▁ ns", + "ess ages", + "essage s", + "essa ges", + "im pl", + "imp l", + "ic ker", + "ick er", + "i cker", + "▁ex amples", + "▁example s", + "▁exam ples", + "ab eth", + "abe th", + "abet h", + "▁st ated", + "▁stat ed", + "▁state d", + "▁sta ted", + "fi re", + "f ire", + "bu l", + "b ul", + "▁danger ous", + "▁P ay", + "▁Pa y", + "▁ Pay", + "▁G re", + "▁Gr e", + "▁ Gre", + "▁Mon day", + "▁Mond ay", + "es ome", + "eso me", + "e some", + "ig an", + "iga n", + "i gan", + "ru nd", + "run d", + "r und", + "pr ise", + "p rise", + "fa il", + "f ail", + "▁N ever", + "▁Ne ver", + "▁Nev er", + "▁ Never", + "A v", + "▁line ar", + "▁lin ear", + "▁ linear", + "▁u l", + "▁ ul", + "WA R", + "W AR", + "ре н", + "р ен", + "▁A T", + "▁ AT", + "▁d op", + "▁do p", + "▁n ou", + "▁no u", + "Des t", + "De st", + "D est", + "▁claim s", + "en da", + "end a", + "▁c razy", + "▁cr azy", + "ge l", + "g el", + "og gle", + "ogg le", + "▁rep resentation", + "▁represent ation", + "in en", + "ine n", + "i nen", + "▁altern ative", + "▁alter native", + "D M", + "AB ILITY", + "face s", + "fa ces", + "fac es", + "f aces", + "▁do ors", + "▁door s", + "▁ doors", + "at iv", + "ati v", + "Lo ok", + "L ook", + "▁J SON", + "▁JS ON", + "▁ JSON", + "▁appe arance", + "▁appear ance", + "б ря", + "S QL", + "▁sil ence", + "ud o", + "u do", + "▁Direct or", + "▁Dire ctor", + "▁Dir ector", + "State ment", + "Stat ement", + "se lected", + "select ed", + "hi gh", + "h igh", + "pr ime", + "prim e", + "▁ign ore", + "▁ignor e", + "▁ ignore", + "▁col ors", + "▁color s", + "▁ colors", + "us hing", + "ush ing", + "▁v irt", + "▁vi rt", + "▁vir t", + "▁ virt", + "man ager", + "▁rem ote", + "▁remot e", + "▁ remote", + "ł o", + "sm all", + "▁cr ime", + "▁crim e", + "▁cri me", + "r b", + "▁c reation", + "▁cre ation", + "▁creat ion", + "▁f light", + "▁fl ight", + "▁S ign", + "▁Si gn", + "▁Sig n", + "▁ Sign", + "IL E", + "I LE", + "▁D O", + "▁ DO", + "com ment", + "comm ent", + "▁C ost", + "▁Co st", + "▁Cos t", + "▁ Cost", + "._ _", + ". __", + "▁C op", + "▁Co p", + "▁ Cop", + "▁v om", + "▁vo m", + "▁Sc ience", + "▁Sci ence", + "ле ния", + "oo p", + "o op", + "inter face", + "▁WARRAN TIES", + "▁P age", + "▁Pa ge", + "▁ Page", + "** ****", + "**** **", + "*** ***", + "ско м", + "с ком", + "TR UE", + "▁re peated", + "▁repe ated", + "▁repeat ed", + "▁е го", + "ш о", + "▁r oz", + "▁ro z", + "▁ roz", + "P e", + "▁IS BN", + "ir ts", + "irt s", + "pos es", + "po ses", + "pose s", + "p oses", + "}) $", + "} )$", + "▁ І", + "child ren", + "ble s", + "bl es", + "b les", + "EC T", + "E CT", + "▁i z", + "▁ iz", + "▁b uilder", + "▁build er", + "▁ builder", + "▁M edia", + "▁Med ia", + "▁ Media", + "ia t", + "i at", + "▁contr ast", + "▁contra st", + "” ,", + "▁L ink", + "▁Lin k", + "▁ Link", + "▁Educ ation", + "▁j oint", + "▁join t", + "▁jo int", + "▁ joint", + "▁ex ternal", + "▁extern al", + "▁ external", + "▁ро з", + "▁b its", + "▁bit s", + "▁bi ts", + "▁ bits", + "FO RM", + "FOR M", + "F ORM", + "er man", + "erm an", + "w p", + "▁M ike", + "▁Mi ke", + "▁Mik e", + "▁M aster", + "▁Ma ster", + "▁Mas ter", + "▁ Master", + "▁sen ior", + "▁N av", + "▁Na v", + "▁ Nav", + "▁record ed", + "el ing", + "eli ng", + "elin g", + "e ling", + "es h", + "e sh", + "f x", + "ка н", + "к ан", + "▁t all", + "▁tal l", + "▁ta ll", + "▁John son", + "▁s ono", + "▁so no", + "▁son o", + "▁an che", + "▁anc he", + "▁anch e", + "▁ anche", + "ic ken", + "ick en", + "i cken", + "lo op", + "l oop", + "ici ency", + "empor ary", + "▁D oes", + "▁Do es", + "▁ Does", + "▁re lation", + "▁rel ation", + "▁ relation", + "м ы", + "wa s", + "w as", + "lo w", + "l ow", + "ich te", + "icht e", + "i chte", + "▁J ones", + "▁Jo nes", + "▁Jon es", + "▁bed room", + "DI S", + "D IS", + "▁mag net", + "▁magn et", + "▁Eng ine", + "▁ Engine", + "▁feel ings", + "▁feeling s", + "▁fee lings", + "G C", + "▁t orn", + "▁to rn", + "▁tor n", + "▁relationship s", + "▁relation ships", + "▁Р е", + "▁p roud", + "▁pro ud", + "▁pr oud", + "▁t we", + "▁tw e", + "ov al", + "ova l", + "o val", + "▁w aste", + "▁was te", + "▁wa ste", + "▁red uced", + "▁redu ced", + "▁reduce d", + "il ton", + "ilt on", + "B P", + "▁for got", + "▁forg ot", + "▁bod ies", + "▁H aw", + "▁Ha w", + "la g", + "l ag", + "▁w ww", + "▁ www", + "do or", + "d oor", + "▁s ufficient", + "▁suff icient", + "▁doll ars", + "▁dollar s", + "Le n", + "L en", + "▁talk ed", + "▁tal ked", + "▁b ond", + "▁bo nd", + "▁bon d", + "▁B or", + "▁Bo r", + "}} {", + "} }{", + "ro d", + "r od", + "Pass word", + "qu are", + "▁l ights", + "▁light s", + "▁ lights", + "er en", + "ere n", + "e ren", + "▁th irty", + "N C", + "▁T ODO", + "▁TO DO", + "▁res pond", + "▁respon d", + "▁resp ond", + "▁ respond", + "ки х", + "dir ect", + "di rect", + "dire ct", + "d irect", + "a ção", + "▁he av", + "Med ia", + "M edia", + "ex it", + "e xit", + "L icense", + "` .", + "▁m ixed", + "▁mix ed", + "▁d esk", + "▁de sk", + "▁des k", + "▁te aching", + "▁teach ing", + "▁tea ching", + "▁m aj", + "▁ma j", + "▁n erv", + "▁ne rv", + "▁ner v", + "in ations", + "ination s", + "type of", + "▁co ast", + "▁ж е", + "▁ же", + "▁be side", + "▁bes ide", + "um my", + "umm y", + "Do c", + "D oc", + "▁sche dule", + "▁schedul e", + "▁sched ule", + "▁ schedule", + "▁re cover", + "▁rec over", + "▁Fur ther", + "▁ste el", + "bo ot", + "b oot", + "▁Per haps", + "▁с ъ", + "▁O s", + "▁ Os", + "ri ck", + "ric k", + "r ick", + "▁В и", + "Supp ort", + "Sup port", + "S upport", + "▁( _", + "▁ (_", + "ni l", + "n il", + "pi s", + "p is", + "x pected", + "▁process ing", + "▁proces sing", + "▁ processing", + "Bu ild", + "B uild", + "ar ian", + "ari an", + "aria n", + "a rian", + "▁i con", + "▁ic on", + "▁ icon", + "▁C A", + "▁ CA", + "wi ck", + "w ick", + "= (", + "▁al gorithm", + "▁ algorithm", + "▁You ng", + "▁Man agement", + "▁ Management", + "▁anc ient", + "▁anci ent", + "но сть", + "ност ь", + "ot i", + "o ti", + "▁comb ination", + "wor ld", + "w orld", + "n n", + "▁d ram", + "▁dr am", + "en abled", + "ena bled", + "enable d", + "A c", + "C CESS", + "ar ation", + "▁bl ocks", + "▁block s", + "▁blo cks", + "▁ blocks", + "▁Ang eles", + "▁Angel es", + "▁Q ual", + "▁Qu al", + "▁ Qual", + "▁suc ceed", + "▁succ eed", + "net work", + "▁ob lig", + "spring framework", + "▁T re", + "▁Tr e", + "ok es", + "oke s", + "o kes", + "mu n", + "m un", + "▁Net work", + "▁ Network", + "De l", + "D el", + "▁e state", + "▁est ate", + "▁esta te", + "▁l iqu", + "▁li qu", + "▁p ob", + "▁po b", + "▁d ad", + "▁da d", + "▁dist inct", + "▁T it", + "▁Ti t", + "▁L ear", + "▁Le ar", + "fer red", + "and roid", + "andro id", + "▁sub sequ", + "▁subs equ", + "▁Flor ida", + "sub set", + "▁whis per", + "Vo l", + "V ol", + "ul ous", + "ulo us", + "▁c rew", + "▁cre w", + "▁cr ew", + "▁l ug", + "▁lu g", + "pi d", + "p id", + "oc ity", + "oci ty", + "o city", + "sk b", + "s kb", + "▁t ea", + "▁te a", + "у н", + "▁hon or", + "▁ho nor", + "▁I ns", + "▁In s", + "▁ Ins", + "▁g ew", + "▁ge w", + "▁ gew", + "Det ails", + "Detail s", + "ene ath", + "e neath", + "at ar", + "ata r", + "a tar", + "▁_ {", + "▁ _{", + "am en", + "ame n", + "a men", + "▁set up", + "▁ setup", + "Trans action", + "▁bl ank", + "▁ blank", + "Fail ed", + "F ailed", + "jo b", + "j ob", + "▁p ret", + "▁pre t", + "▁pr et", + "▁ pret", + "ß e", + "lo or", + "l oor", + "ř í", + "nc ia", + "n cia", + "▁any where", + "▁L ight", + "▁Li ght", + "▁ Light", + "▁A k", + "B D", + "▁exc ited", + "▁excit ed", + "ag ers", + "age rs", + "ager s", + "a gers", + "▁w arning", + "▁war ning", + "▁warn ing", + "▁ warning", + "▁process es", + "▁proces ses", + "h u", + "▁y outh", + "▁you th", + "▁yo uth", + "▁d ogs", + "▁do gs", + "▁dog s", + "▁o ct", + "▁oc t", + "▁ oct", + "▁n ine", + "▁ni ne", + "▁nin e", + "Write r", + "Wr iter", + "Writ er", + "W riter", + "gr id", + "g rid", + "▁import ance", + "est ic", + "▁care fully", + "▁careful ly", + "ma ster", + "mas ter", + "m aster", + "▁dec isions", + "▁decision s", + "▁decis ions", + "▁p in", + "▁pi n", + "▁ pin", + "▁cr ack", + "TE ST", + "TES T", + "T EST", + "▁L ocal", + "▁Loc al", + "▁Lo cal", + "▁ Local", + "▁R ight", + "▁ Right", + "▁v ast", + "▁va st", + "▁vas t", + "▁f aster", + "▁fa ster", + "▁fast er", + "▁inst itut", + "▁ann ual", + "LA N", + "L AN", + "▁e pisode", + "▁epis ode", + "▁X V", + "▁del ivery", + "▁deliver y", + "t l", + "F P", + "ci rc", + "cir c", + "▁typ ically", + "▁typical ly", + "ig o", + "i go", + "▁int el", + "▁inte l", + "▁ intel", + "na t", + "n at", + "x b", + "ст ро", + "с тро", + ") -", + "▁B al", + "▁Ba l", + "▁ Bal", + "▁J os", + "▁Jo s", + "▁g onna", + "▁R est", + "▁Re st", + "▁Res t", + "▁ Rest", + "jo r", + "j or", + "on ia", + "oni a", + "o nia", + "or ship", + "ors hip", + "ov ery", + "ove ry", + "over y", + "o very", + "LI NE", + "LIN E", + "L INE", + "] :", + "Que ue", + "▁com pare", + "▁comp are", + "▁compar e", + "▁ compare", + "▁ap artment", + "▁apart ment", + "▁r ul", + "▁ru l", + "D r", + "gen cy", + "g ency", + "▁ob viously", + "▁obvious ly", + "zi e", + "z ie", + "yc l", + "y cl", + "fort unately", + "fortun ately", + "fortunate ly", + "▁ste pped", + "▁step ped", + "▁S eg", + "▁Se g", + "▁ Seg", + "▁Wh ich", + "▁ Which", + "▁P C", + "▁ PC", + "▁a st", + "▁as t", + "▁ ast", + "end or", + "endo r", + "▁per mission", + "▁perm ission", + "▁ permission", + "CO L", + "C OL", + "▁T EST", + "▁TE ST", + "▁ TEST", + "P ay", + "ère s", + "è res", + "▁stud ied", + "▁accom pl", + "▁accomp l", + "ro le", + "rol e", + "r ole", + "Wh ere", + "Whe re", + "W here", + "proto buf", + "met adata", + "meta data", + "Jo b", + "J ob", + "▁F our", + "▁Fou r", + "▁Fo ur", + "pl ements", + "ple ments", + "plement s", + "dis able", + "▁l oud", + "▁lo ud", + "▁lou d", + "▁happ ening", + "▁happen ing", + "▁U sing", + "▁Us ing", + "▁ Using", + "ro g", + "r og", + "▁depend s", + "▁dep ends", + "í m", + "' \\", + "▁t aught", + "sh ared", + "sha red", + "share d", + "▁att ributes", + "▁attribute s", + "▁attribut es", + "▁ attributes", + "▁A ction", + "▁Act ion", + "▁ Action", + "▁d ess", + "▁de ss", + "▁des s", + "▁ dess", + "▁h ouses", + "▁house s", + "▁hous es", + "▁ho uses", + "▁re set", + "▁res et", + "▁ reset", + "▁b ien", + "▁bi en", + "▁ex plicit", + "▁expl icit", + "LO W", + "-> _", + "▁P M", + "▁ PM", + "C ategory", + "oi ce", + "o ice", + "in to", + "int o", + "▁m ail", + "▁ma il", + "▁mai l", + "▁ mail", + "▁author ity", + "▁un able", + "▁una ble", + "file name", + "fil ename", + "é k", + "ле й", + "л ей", + "▁s ector", + "▁se ctor", + "▁sec tor", + "▁sect or", + "ap point", + "app oint", + "▁h ang", + "▁ha ng", + "▁han g", + "▁ hang", + "▁c el", + "▁ce l", + "▁ cel", + "rel ated", + "it ate", + "ita te", + "itat e", + "▁' <", + "am ber", + "amb er", + "a mber", + "▁c heap", + "▁che ap", + "▁en abled", + "▁enable d", + "▁ enabled", + "▁di vision", + "▁div ision", + "▁divis ion", + "An y", + "A ny", + "▁h ier", + "▁hi er", + "▁H ead", + "▁He ad", + "▁ Head", + "nt ax", + "n tax", + "ud a", + "u da", + "▁lim itations", + "▁limit ations", + "▁limitation s", + "▁st udio", + "▁stud io", + "med ia", + "medi a", + "m edia", + "▁cir cle", + "▁circ le", + "▁ circle", + "но ва", + "нов а", + "▁l aug", + "▁la ug", + "ac ts", + "act s", + "▁В о", + "ó d", + "pl ed", + "ple d", + "p led", + "LO C", + "L OC", + "Ex pr", + "Exp r", + "> :", + "▁pr és", + "▁pré s", + "▁ prés", + "▁laugh ed", + "▁laug hed", + "▁Th ree", + "▁ Three", + "л ы", + "▁en ds", + "▁end s", + "▁ ends", + "▁fund ament", + "▁in her", + "▁ inher", + "▁l iv", + "▁li v", + "▁ liv", + "bi d", + "b id", + "▁respons ibility", + "▁check ed", + "▁ checked", + "▁P ac", + "▁Pa c", + "▁f ault", + "▁fa ult", + "▁y ellow", + "▁s alt", + "▁sa lt", + "▁sal t", + "▁Franc isco", + "▁Francis co", + "▁ ^", + "▁O N", + "▁ ON", + "▁beaut y", + "y g", + "▁A ff", + "▁Af f", + "▁ Aff", + "▁E q", + "▁ Eq", + "▁mag ic", + "▁hand ler", + "▁handle r", + "▁ handler", + "x E", + "▁numer ous", + "▁numero us", + "▁h ole", + "▁hol e", + "▁ho le", + "▁ hole", + "▁ro oms", + "▁room s", + "▁ rooms", + "cc ión", + "cció n", + "c ción", + "▁A rm", + "▁Ar m", + "▁ Arm", + "per son", + "pers on", + "p erson", + "▁build ings", + "▁building s", + "▁p late", + "▁pl ate", + "▁plat e", + "ble d", + "bl ed", + "b led", + "er rors", + "err ors", + "error s", + "▁A gain", + "▁Ag ain", + "▁Def ault", + "▁ Default", + "▁H ard", + "▁Har d", + "▁Ha rd", + "▁ Hard", + "t ó", + "hu s", + "h us", + "▁dim ension", + "ial e", + "ia le", + "i ale", + "▁M ult", + "▁Mu lt", + "▁Mul t", + "▁ Mult", + "▁Govern ment", + "Fun c", + "F unc", + "▁b low", + "▁bl ow", + "▁blo w", + "▁re ct", + "▁r ect", + "▁rec t", + "▁ rect", + "er ra", + "err a", + "conne ction", + "connect ion", + "conn ection", + "▁pass ing", + "▁pas sing", + "ße n", + "ß en", + "ph as", + "pha s", + "p has", + "ens ional", + "ension al", + "re cord", + "rec ord", + "co hol", + "▁H arry", + "▁Har ry", + "▁Harr y", + "izont al", + "izon tal", + "▁f inger", + "▁fin ger", + "▁fing er", + "▁young er", + "▁S C", + "▁ SC", + "oper ation", + "B Y", + "he im", + "▁B ad", + "▁Ba d", + "▁ Bad", + "▁st orm", + "▁stor m", + "▁sto rm", + "▁ storm", + "▁N at", + "▁Na t", + "▁bu ying", + "▁buy ing", + "▁S ometimes", + "▁Some times", + "▁С та", + "es sed", + "ess ed", + "esse d", + "▁da mn", + "▁dam n", + "▁m eg", + "▁me g", + "um es", + "ume s", + "u mes", + "ün d", + "ü nd", + "т ра", + "▁sil ver", + "w d", + "hid den", + "h idden", + "ar do", + "ard o", + "▁commun ities", + "▁d iet", + "▁di et", + "▁die t", + "ot ted", + "ott ed", + "otte d", + "▁b at", + "▁ba t", + "▁ bat", + "an cer", + "ance r", + "anc er", + "▁f mt", + "▁ fmt", + "▁P en", + "▁Pe n", + "▁ Pen", + "▁t il", + "▁ti l", + "▁ til", + "En um", + "E num", + "PA TH", + "P ATH", + "▁mat ters", + "▁matter s", + "▁matt ers", + "time out", + "-- ----------", + "---- --------", + "-------- ----", + "--- ---------", + "----- -------", + "---------- --", + "------ ------", + "--------- ---", + "------- -----", + "----------- -", + "- -----------", + "ka n", + "k an", + "▁Cor por", + "=\" ../../", + "=\"../ ../", + "▁A le", + "▁Al e", + "hent ication", + "hentic ation", + "▁com plic", + "▁comp lic", + "▁compl ic", + "▁Se curity", + "▁Sec urity", + "▁ Security", + "OF F", + "O FF", + "R ad", + "ap se", + "aps e", + "a pse", + "▁d ance", + "▁dan ce", + "▁perm issions", + "▁permission s", + "▁war rant", + "▁l ad", + "▁la d", + "▁ lad", + "▁is ol", + "▁i sol", + "d l", + "▁A u", + "ye s", + "y es", + "▁t v", + "▁ tv", + "▁pro vider", + "▁prov ider", + "▁provide r", + "▁ provider", + "▁ter rible", + "▁terr ible", + "▁dep artment", + "▁depart ment", + "er al", + "era l", + "e ral", + "▁implement ation", + "S R", + "▁h earing", + "▁he aring", + "▁hear ing", + "▁K n", + "F R", + "t v", + "▁d iss", + "▁dis s", + "▁di ss", + "F UN", + "▁dur ante", + "▁durant e", + "os is", + "osi s", + "o sis", + "▁task s", + "▁ tasks", + "▁B lo", + "▁Bl o", + "▁ Blo", + "во д", + "▁br anch", + "▁ branch", + "▁polit ics", + "▁E lle", + "▁El le", + "▁Ell e", + "▁lead ership", + "▁leader ship", + "▁leaders hip", + "ex pr", + "exp r", + "▁techn iques", + "▁technique s", + "pr ec", + "pre c", + "p rec", + "Sig ma", + "S igma", + "im ately", + "imate ly", + "imat ely", + "t k", + "ach ment", + "▁En ter", + "▁Ent er", + "▁ Enter", + "▁cre ative", + "▁creat ive", + "▁з на", + "▁ зна", + "ap py", + "app y", + "un ched", + "unch ed", + "unc hed", + "▁' ',", + "▁'' ,", + "on der", + "ond er", + "onde r", + "o nder", + "{ -", + "NU M", + "N UM", + "▁n arr", + "▁na rr", + "▁nar r", + "Mem ory", + "▁win ning", + "▁ winning", + "▁F ollow", + "▁Fol low", + "▁ Follow", + "*/ \r", + "vis ion", + "v ision", + "res ents", + "resent s", + "zi one", + "z ione", + "▁l atter", + "▁lat ter", + "▁requ ests", + "▁request s", + "▁ requests", + "▁m argin", + "▁mar gin", + "▁marg in", + "▁ margin", + "▁{ \"", + "▁ {\"", + "v ideo", + "c n", + "▁Im age", + "▁ Image", + "T im", + "CON FIG", + "CONF IG", + "▁all owing", + "▁allow ing", + "▁comb ined", + "▁combine d", + "PU T", + "P UT", + "▁instance of", + "ig in", + "igi n", + "i gin", + "▁p ero", + "▁per o", + "▁pe ro", + "▁' '", + "▁ ''", + "▁conf idence", + "▁equ ivalent", + "▁equival ent", + "pa d", + "p ad", + "ef fect", + "eff ect", + "e ffect", + "R X", + "▁l ang", + "▁la ng", + "▁lan g", + "▁ lang", + "str ong", + "▁b ridge", + "▁br idge", + "▁ bridge", + "ay a", + "a ya", + "▁t reated", + "▁tre ated", + "▁treat ed", + "▁f orth", + "▁for th", + "▁fort h", + "S W", + "▁account s", + "▁P O", + "▁ PO", + "▁list ening", + "▁listen ing", + "Ro ute", + "R oute", + "() ))", + "()) )", + "( )))", + "cp y", + "c py", + "▁re form", + "▁ref orm", + "▁g ate", + "▁ga te", + "▁ gate", + "▁W alk", + "▁Wal k", + "▁ Walk", + "▁some how", + "t f", + "▁l ayout", + "▁la yout", + "▁lay out", + "▁ layout", + "um in", + "umi n", + "u min", + "▁consider ing", + "▁consid ering", + "▁pre mi", + "▁pr emi", + "▁prem i", + "▁M om", + "▁Mo m", + "at han", + "ath an", + "a than", + "Ge n", + "G en", + "▁plan et", + "▁plane t", + "am ples", + "amp les", + "ample s", + "▁M O", + "▁ MO", + "sh op", + "s hop", + "▁prem ier", + "▁premi er", + "▁s impl", + "▁sim pl", + "▁s egu", + "▁se gu", + "▁seg u", + "L Y", + "Su m", + "S um", + "▁t ables", + "▁table s", + "▁tab les", + "▁ta bles", + "▁ tables", + "sk a", + "s ka", + "▁ ž", + "p d", + "▁s ous", + "▁so us", + "▁sou s", + "▁con ference", + "▁confer ence", + "▁D at", + "▁Da t", + "▁ Dat", + "Sc roll", + "▁stand ards", + "▁standard s", + "▁г ру", + "es se", + "ess e", + "▁citiz ens", + "▁citizen s", + "▁occur red", + "▁dem ocr", + "▁demo cr", + "▁e lev", + "▁el ev", + "▁ele v", + "▁S em", + "▁Se m", + "▁ Sem", + "ens us", + "he aders", + "head ers", + "header s", + "▁Ch ris", + "im ento", + "iment o", + "imen to", + "ko m", + "k om", + "Co r", + "C or", + "MI N", + "M IN", + "us her", + "ush er", + "Data base", + "Dat abase", + "▁f ormal", + "▁for mal", + "▁form al", + "▁forma l", + "ig ne", + "ign e", + "▁organ izations", + "▁organiz ations", + "▁organization s", + "▁I re", + "▁Ir e", + "X ml", + "и з", + "▁p ray", + "▁pr ay", + "▁pra y", + "▁b omb", + "▁bo mb", + "▁bom b", + "▁m and", + "▁man d", + "▁ma nd", + "▁ mand", + "er ts", + "ert s", + "▁c lock", + "▁cl ock", + "▁clo ck", + "▁ clock", + "▁b uck", + "▁bu ck", + "ва ли", + "вал и", + "в али", + "en sch", + "ens ch", + "▁v olt", + "▁vo lt", + "▁vol t", + "▁ volt", + "▁fil ms", + "▁film s", + "▁pl ants", + "▁plan ts", + "▁plant s", + "in ode", + "ino de", + "i node", + "Bo olean", + "▁restaur ant", + "ía n", + "í an", + "▁de but", + "▁deb ut", + "page s", + "pa ges", + "pag es", + "p ages", + "▁wor dt", + "▁word t", + "▁Б а", + "▁great est", + "(\" /", + "▁c opyright", + "▁copy right", + "▁ copyright", + "▁r it", + "▁ri t", + "▁ rit", + "size of", + "Tr ace", + "Tra ce", + "ue nt", + "uen t", + "u ent", + "ту р", + "т ур", + "▁k o", + "▁ ko", + ": \\", + "▁b igger", + "▁big ger", + "▁perfect ly", + "ten ance", + "MA SK", + "M ASK", + "r é", + "▁e tt", + "▁et t", + "▁ ett", + "▁n ose", + "▁no se", + "▁nos e", + "▁c raft", + "▁cr aft", + "▁ craft", + "it eral", + "ite ral", + "iter al", + "▁discuss ed", + "▁Jew ish", + "C ap", + "▁Un less", + "▁Jack son", + "Att ributes", + "Attribute s", + "Attrib utes", + "▁l unch", + "▁lun ch", + "ö l", + "at r", + "a tr", + "▁pay ing", + "▁pa ying", + "Par se", + "Pars e", + "P arse", + "() \r", + "( )\r", + "la d", + "l ad", + "▁r are", + "▁ra re", + "▁[ ];", + "▁[] ;", + "▁ [];", + "st one", + "ston e", + "sto ne", + "▁u nc", + "▁un c", + "▁ unc", + "▁def ense", + "▁defens e", + "} +", + "▁Gl obal", + "▁ Global", + "▁Sov iet", + "▁Austral ian", + "▁Australia n", + "▁g li", + "▁gl i", + "var iant", + "vari ant", + "▁R on", + "▁Ro n", + "▁lo an", + "St ep", + "Ste p", + "me mber", + "mem ber", + "m ember", + "Sc h", + "S ch", + "▁Commit tee", + "▁s pending", + "▁sp ending", + "▁spend ing", + "▁T ri", + "▁Tr i", + "▁ Tri", + "▁J ournal", + "▁Jour nal", + "▁ Journal", + "▁s ugar", + "▁su gar", + "▁sug ar", + "el ly", + "ell y", + "HT ML", + "▁ad vent", + "▁adv ent", + "win g", + "wi ng", + "w ing", + "▁Wh ether", + "▁Whe ther", + "or ation", + "▁N E", + "▁ NE", + "iv eness", + "ive ness", + "iven ess", + "▁h av", + "▁ha v", + "▁ hav", + "▁con scious", + "▁ conscious", + "ee n", + "e en", + "Sym bol", + "S ymbol", + "▁к у", + "▁ ку", + "Log ger", + "▁L ittle", + "▁Lit tle", + "wide t", + "wi det", + "wid et", + "oc ation", + "pi n", + "p in", + "▁sym met", + "▁A D", + "▁ AD", + "▁pos ts", + "▁po sts", + "▁post s", + "▁ posts", + "sh al", + "sha l", + "s hal", + "▁Con f", + "▁Co nf", + "▁ Conf", + "▁ch ose", + "▁cho se", + "ma l", + "m al", + "ul o", + "u lo", + "▁M ethod", + "▁ Method", + "▁miss ed", + "▁mis sed", + "Re move", + "Rem ove", + "Aut o", + "A uto", + "VAL UE", + "th let", + "▁For ce", + "▁ Force", + "p f", + "▁ Я", + "la te", + "lat e", + "l ate", + "▁p ul", + "▁pu l", + "▁ pul", + "Po p", + "P op", + "▁adv anced", + "▁advance d", + "air es", + "ai res", + "aire s", + "a ires", + "res sed", + "ress ed", + "resse d", + "r essed", + "AM E", + "A ME", + "be ll", + "bel l", + "b ell", + "ac hing", + "ach ing", + "achi ng", + "a ching", + "i ć", + "ec ho", + "ech o", + "e cho", + "H S", + "▁fun ny", + "ри и", + "▁e er", + "▁ve get", + "▁four th", + "c f", + "trans form", + "▁g rown", + "▁gr own", + "▁grow n", + "▁gro wn", + "▁Mc C", + "si te", + "s ite", + "▁b eneath", + "▁be neath", + "▁s hell", + "▁sh ell", + "▁she ll", + "▁shel l", + "▁ shell", + "x d", + "Pl ay", + "P lay", + "sh ort", + "Ro le", + "R ole", + "▁relig ion", + "in ator", + "ina tor", + "} <", + "\" ><", + "as p", + "a sp", + "aj o", + "a jo", + "ex ports", + "exp orts", + "export s", + "▁N ode", + "▁No de", + "▁ Node", + "▁j ako", + "▁ja ko", + "▁jak o", + "▁y a", + "▁ ya", + "▁success fully", + "▁successful ly", + "▁friend ly", + "▁ friendly", + "buf f", + "bu ff", + "b uff", + "DE FAULT", + "▁pre gn", + "▁preg n", + "Requ ired", + "Require d", + "▁b inary", + "▁bin ary", + "▁ binary", + "is ting", + "ist ing", + "isti ng", + "▁st ared", + "▁star ed", + "▁stare d", + "▁sta red", + "▁circum stances", + "▁х о", + "▁ хо", + "re i", + "r ei", + "▁Г о", + "Trans form", + "cn t", + "c nt", + "▁E xt", + "▁Ex t", + "▁ Ext", + "re port", + "rep ort", + "repo rt", + "VER SION", + "▁an aly", + "▁anal y", + "▁ analy", + "▁M arg", + "▁Mar g", + "▁Ma rg", + "▁al leg", + "▁all eg", + "▁alle g", + "build er", + "b uilder", + "To String", + "La yer", + "L ayer", + "ís t", + "í st", + "Pro p", + "Pr op", + "P rop", + "▁E mp", + "▁Em p", + "▁ Emp", + "} ]", + "▁s elling", + "▁sell ing", + "▁sel ling", + "▁ selling", + "▁que ue", + "▁ queue", + "▁ser iously", + "▁serious ly", + "▁L ead", + "▁Le ad", + "▁ Lead", + "text it", + "tex tit", + "test ing", + "tes ting", + "▁П ре", + "se curity", + "sec urity", + "ia ł", + "i ał", + "ú n", + "ch ip", + "chi p", + "c hip", + "▁c andidate", + "▁candid ate", + "▁min ister", + "▁mini ster", + "▁minist er", + "▁ minister", + "er ia", + "eri a", + "e ria", + "▁H et", + "▁He t", + "ди н", + "д ин", + "▁Brit ain", + "▁b arely", + "▁bar ely", + "▁bare ly", + "▁s ty", + "▁st y", + "▁ sty", + "▁Span ish", + "▁V en", + "▁Ve n", + "time r", + "ti mer", + "tim er", + "t imer", + "кі в", + "к ів", + "▁document s", + "▁doc uments", + "(' .", + "( '.", + "▁d ebug", + "▁de bug", + "▁deb ug", + "▁ debug", + "▁cont ro", + "▁contr o", + "сто я", + "▁j oy", + "▁jo y", + "▁ joy", + "S n", + "In v", + "I nv", + "▁pro tocol", + "▁proto col", + "▁prot ocol", + "▁ protocol", + "▁f aces", + "▁face s", + "▁fac es", + "▁fa ces", + "▁ faces", + "▁Des pite", + "se d", + "s ed", + "Con f", + "Co nf", + "AR G", + "A RG", + "▁e volution", + "▁ev olution", + "▁t od", + "▁to d", + "▁P romise", + "▁Prom ise", + "▁ Promise", + "▁pos ted", + "▁po sted", + "▁post ed", + "Per m", + "Pe rm", + "P erm", + "be t", + "b et", + "An g", + "A ng", + "J ust", + "▁r um", + "▁ru m", + "▁ rum", + "la yer", + "lay er", + "l ayer", + "▁beh avi", + "▁behav i", + "ip ping", + "ipp ing", + "ippi ng", + "i pping", + "▁d ynam", + "▁dy nam", + "▁dyn am", + "▁sch eme", + "▁sche me", + "▁ scheme", + "▁pro to", + "▁pr oto", + "▁prot o", + "▁ proto", + ") /", + "Col lections", + "Collection s", + "Collect ions", + "ri ev", + "rie v", + "r iev", + "▁C lick", + "▁Cl ick", + "▁ Click", + "▁u ns", + "▁un s", + "▁ uns", + "wide tilde", + "widet ilde", + "▁remember ed", + "г і", + "in ates", + "ina tes", + "inate s", + "▁incor por", + "▁De scription", + "▁Des cription", + "▁ Description", + "▁pre pare", + "▁prep are", + "▁prepar e", + "▁ prepare", + "▁F inal", + "▁Fin al", + "▁Fi nal", + "▁ Final", + "u ation", + "▁Qu een", + "▁Que en", + "> ;", + "▁autom atically", + "▁automatic ally", + "▁sh arp", + "▁shar p", + "▁sha rp", + "▁me at", + "at eur", + "ate ur", + "as tern", + "ast ern", + "aster n", + "aste rn", + "▁st uck", + "ASS ERT", + "▁pl anned", + "▁plan ned", + "do ts", + "dot s", + "d ots", + "ook ie", + "oo kie", + "▁His tor", + "▁Hist or", + "▁re views", + "▁review s", + "IM P", + "I MP", + "▁answ ered", + "▁answer ed", + "To tal", + "T otal", + "▁s au", + "▁sa u", + "▁Me xico", + "▁Mex ico", + "contin ue", + "▁App le", + "▁Ap ple", + "like ly", + "lik ely", + "з ва", + "us ers", + "use rs", + "user s", + "▁ident ified", + "▁L ev", + "▁Le v", + "▁m ol", + "▁mo l", + "▁Is lam", + "▁com mitted", + "▁comm itted", + "▁commit ted", + "wr it", + "w rit", + "бе р", + "б ер", + "ri ft", + "rif t", + "r ift", + "▁inter rupt", + "▁ interrupt", + "▁read only", + "sch ema", + "sche ma", + "s chema", + "S m", + "D ouble", + "az a", + "a za", + "▁H al", + "▁Ha l", + "▁ Hal", + "Mo ve", + "M ove", + "▁S eries", + "▁Se ries", + "▁Ser ies", + "▁Serie s", + "▁ Series", + "in line", + "▁кото ры", + "so c", + "s oc", + "▁t ent", + "▁te nt", + "▁ten t", + "▁a mer", + "▁am er", + "▁ amer", + "ak i", + "a ki", + "▁l ady", + "▁la dy", + "▁lad y", + "▁t ired", + "▁ti red", + "▁tire d", + "▁tir ed", + "if i", + "i fi", + "▁m ême", + "▁ même", + "ou ver", + "▁a side", + "▁as ide", + "Di d", + "D id", + "', \r", + "' ,\r", + "▁br inging", + "▁bring ing", + "Draw ing", + "ar o", + "a ro", + "▁R h", + "▁N az", + "▁Na z", + "es so", + "ess o", + "▁re action", + "▁react ion", + "mit ted", + "mitt ed", + "m itted", + "▁abs olute", + "▁absolut e", + "▁ absolute", + "ha ust", + "haus t", + "(( )", + "( ()", + "▁T ask", + "▁Ta sk", + "▁ Task", + "ER S", + "E RS", + "▁^ {", + "▁ ^{", + "V D", + "▁t one", + "▁to ne", + "▁ton e", + "dis t", + "di st", + "d ist", + "v s", + "▁whe el", + "▁ wheel", + "▁administr ation", + "▁admin istration", + "▁inter ests", + "▁interest s", + "▁point er", + "▁po inter", + "▁ pointer", + "▁en counter", + "▁enc ounter", + "ave r", + "av er", + "a ver", + "▁n ord", + "▁no rd", + "▁nor d", + "ke t", + "k et", + "▁b each", + "▁be ach", + "▁enjoy ed", + "cont ains", + "▁app end", + "▁ap pend", + "▁appe nd", + "▁ append", + "W ait", + "▁s quad", + "▁squ ad", + "ze l", + "z el", + "▁med ium", + "▁medi um", + "▁ medium", + "▁s ending", + "▁send ing", + "▁sen ding", + "▁L ady", + "▁La dy", + "▁Lad y", + "ç ões", + "▁dest ination", + "▁destin ation", + "▁ destination", + "ny ch", + "n ych", + "▁conf lict", + "▁conflic t", + "▁L y", + "▁v ul", + "▁vu l", + "▁bas ically", + "▁basic ally", + "re ated", + "reat ed", + "reate d", + "rea ted", + "bl ack", + "ug ins", + "ugin s", + "▁cal m", + "▁ca lm", + "ér ie", + "éri e", + "é rie", + "ha r", + "h ar", + "ла н", + "л ан", + "▁С е", + "w atch", + "▁P ut", + "▁Pu t", + "▁ Put", + "▁d ump", + "▁du mp", + "▁ dump", + "ac her", + "ach er", + "ache r", + "a cher", + "sc roll", + "scr oll", + "▁cl aimed", + "▁claim ed", + "▁ claimed", + "▁Cont rol", + "▁ Control", + "▁bl ind", + "en ti", + "ent i", + "▁Ke ep", + "▁ Keep", + "▁Develop ment", + "im ages", + "image s", + "ima ges", + "imag es", + "▁t ough", + "▁to ugh", + "▁tou gh", + "ge bra", + "geb ra", + "▁se pt", + "▁sep t", + "he w", + "h ew", + "▁s kill", + "▁sk ill", + "▁ski ll", + "▁ skill", + "▁T ay", + "▁Ta y", + "▁k tó", + "ow ner", + "own er", + "par e", + "pa re", + "p are", + "▁f ee", + "▁fe e", + "▁ fee", + "▁contin ues", + "▁continue s", + "▁continu es", + "▁k an", + "▁ka n", + "▁ kan", + "be s", + "b es", + "▁c ha", + "▁ch a", + "▁ cha", + "ov o", + "o vo", + "▁N ight", + "▁Ni ght", + "ict ure", + "sh ire", + "s hire", + "▁es say", + "▁ess ay", + "▁sup pose", + "▁supp ose", + "et ic", + "eti c", + "Ar t", + "A rt", + "ac on", + "aco n", + "a con", + "ll a", + "l la", + "word s", + "wor ds", + "w ords", + "▁compar ison", + "▁B E", + "▁ BE", + "▁challeng es", + "▁challenge s", + "▁o l", + "▁ ol", + "cite p", + "cit ep", + "▁F oot", + "▁Fo ot", + "▁ Foot", + "▁S uch", + "▁Su ch", + "▁ Such", + "▁p apers", + "▁paper s", + "▁pa pers", + "▁pap ers", + "act iv", + "qu er", + "que r", + "q uer", + "т я", + "▁Т о", + "сь кий", + "th ur", + "do ne", + "don e", + "d one", + "▁sh ock", + "▁ded icated", + "▁dedic ated", + "▁cor respond", + "▁correspon d", + "Se cond", + "Sec ond", + "▁b ull", + "▁bu ll", + "▁bul l", + "li fe", + "lif e", + "l ife", + "ind ent", + "inde nt", + "inden t", + "▁fig ures", + "▁figure s", + "▁And rew", + "▁Andre w", + "▁Andr ew", + "is p", + "i sp", + "▁fav our", + "зд а", + "з да", + "▁E lect", + "▁El ect", + "▁Ele ct", + "F ull", + "▁near by", + "▁Reg ister", + "▁ Register", + "Sc ale", + "Scal e", + "ic ations", + "ication s", + "и н", + "▁A M", + "▁ AM", + "pa ir", + "p air", + "▁pers pective", + "▁n os", + "▁no s", + "▁ nos", + "ap a", + "a pa", + "ost ał", + "osta ł", + "▁P ers", + "▁Per s", + "▁Pe rs", + "▁ Pers", + "ic er", + "ice r", + "i cer", + "▁pl astic", + "до в", + "д ов", + "ci ples", + "cipl es", + "cip les", + "z ą", + "cl os", + "c los", + "▁у ча", + "▁ Á", + "pl ugin", + "plug in", + "▁an gle", + "▁ang le", + "▁angl e", + "▁ angle", + "▁com mission", + "▁comm ission", + "▁fun ds", + "▁fund s", + "▁in du", + "▁ind u", + "▁d rawn", + "▁dr awn", + "▁draw n", + "á m", + "▁develop ing", + "▁seg ment", + "▁ segment", + "is me", + "ism e", + "sc r", + "s cr", + "▁l ies", + "▁li es", + "▁lie s", + "▁I L", + "▁ IL", + "▁a pi", + "▁ap i", + "▁ api", + "Ext ension", + "▁s cal", + "▁sc al", + "▁ scal", + "inst all", + "▁We ek", + "▁ Week", + "▁gen tle", + "▁gent le", + "▁Canad ian", + "▁d ialog", + "▁dial og", + "▁dia log", + "▁ dialog", + "▁art icles", + "▁article s", + "▁artic les", + "The me", + "Th eme", + "S M", + "▁B ul", + "▁Bu l", + "▁ Bul", + "▁l eur", + "▁le ur", + "▁s tom", + "▁st om", + "▁sto m", + "Pl ugin", + "▁по сле", + "▁пос ле", + "▁st ead", + "▁ste ad", + "▁ stead", + "▁ ś", + "ip her", + "iph er", + "i pher", + "▁pr ze", + "▁prz e", + "▁d raft", + "▁dr aft", + "▁ draft", + "bot tom", + "b ottom", + "▁{ };", + "▁{} ;", + "▁stay ed", + "fe ature", + "feat ure", + "▁v ot", + "▁vo t", + "▁fab ric", + "ç a", + "(' #", + "re a", + "r ea", + "▁re put", + "▁rep ut", + "▁C ir", + "▁Ci r", + "▁ Cir", + "▁A L", + "▁ AL", + "▁assert Equals", + "▁ assertEquals", + "result s", + "▁C ross", + "▁Cr oss", + "▁Cro ss", + "▁ Cross", + "urs day", + "▁a udio", + "▁aud io", + "▁ audio", + "▁g ap", + "▁ga p", + "▁stre ets", + "▁street s", + "▁scient ific", + "pl atform", + "▁a uss", + "▁au ss", + "▁aus s", + "▁C ro", + "▁Cr o", + "▁part ial", + "▁parti al", + "▁ partial", + "un c", + "u nc", + "▁cho ices", + "▁choice s", + "▁и ли", + "pr ed", + "pre d", + "p red", + "▁he ads", + "▁head s", + "▁ heads", + "ter day", + "▁N ick", + "▁Nic k", + "▁Ni ck", + "▁we ird", + "as ant", + "asa nt", + "▁represent ed", + "▁п и", + "▁ пи", + "D P", + "or ders", + "ord ers", + "order s", + "cl ock", + "c lock", + "▁H o", + "ar ters", + "art ers", + "arter s", + "arte rs", + "C md", + "og a", + "o ga", + "Key s", + "Ke ys", + "Re port", + "Rep ort", + "Repo rt", + "▁V ill", + "▁Vi ll", + "▁Vil l", + "▁M u", + "▁ Mu", + "▁own ed", + "▁ owned", + "SU CCESS", + "▁type of", + "▁ typeof", + "hd r", + "h dr", + "ua ble", + "u able", + "▁neighbor hood", + "▁A P", + "▁ AP", + "▁result ing", + "▁sh adow", + "▁ shadow", + "STR ING", + "▁video s", + "▁vide os", + "ле ння", + "лен ня", + "ex pect", + "exp ect", + "▁Val ley", + "▁Vall ey", + "▁g oto", + "▁go to", + "▁got o", + "▁ goto", + "▁S her", + "▁She r", + "▁Sh er", + "fr astr", + "▁oper ating", + "▁opera ting", + "▁э то", + "▁License d", + "▁Lic ensed", + "Var iable", + "Vari able", + "▁P R", + "▁ PR", + "▁H ans", + "▁Ha ns", + "▁Han s", + "cl one", + "▁G esch", + "▁Ge sch", + "▁Ges ch", + "▁B and", + "▁Ba nd", + "▁Ban d", + "▁ Band", + "... .....", + ".... ....", + "..... ...", + "ui ng", + "u ing", + "▁hundred s", + "▁о к", + "▁emot ional", + "▁emotion al", + "▁Ind ust", + ") +", + "▁Egy pt", + "▁fr anç", + "▁ š", + "▁f asc", + "▁fa sc", + "on to", + "ont o", + "▁A dam", + "▁Ad am", + "▁l aid", + "▁la id", + "▁r ig", + "▁ri g", + "▁ rig", + "▁det ailed", + "▁detail ed", + "▁im plements", + "▁implement s", + "▁impl ements", + "▁univers ity", + "▁H y", + "▁ Hy", + "▁g rid", + "▁gr id", + "▁gri d", + "▁ grid", + "▁reg ions", + "▁region s", + "St op", + "S top", + "▁s lot", + "▁sl ot", + "▁ slot", + "▁ang ry", + "▁- =", + "▁wait ed", + "▁wa ited", + "Ver t", + "V ert", + "\": \"", + "\" :\"", + "▁e lem", + "▁el em", + "▁ele m", + "▁ elem", + "▁r ég", + "▁ré g", + "ow ed", + "owe d", + "o wed", + "Mem ber", + "Me mber", + "M ember", + "▁r atio", + "▁rat io", + "▁ ratio", + "is en", + "ise n", + "i sen", + "▁L em", + "▁Le m", + "ge ry", + "ger y", + "g ery", + "▁c ream", + "▁cre am", + "▁ét ait", + "▁ était", + "▁g eb", + "▁ge b", + "▁ geb", + "un ique", + "uni que", + "▁D eb", + "▁De b", + "▁f actory", + "▁fact ory", + "▁factor y", + "▁ factory", + "ż e", + "d ialog", + "▁Con fig", + "▁Conf ig", + "▁ Config", + "Sy nc", + "S ync", + "an gers", + "ang ers", + "ange rs", + "anger s", + "▁gover ning", + "▁govern ing", + "▁H un", + "▁Hu n", + "Sp ace", + "S pace", + "▁j est", + "▁je st", + "ic ious", + "ici ous", + "icio us", + "▁em phas", + "▁emp has", + "um ps", + "ump s", + "▁E sp", + "▁Es p", + "▁ Esp", + "▁s ul", + "▁su l", + "▁histor ical", + "▁historic al", + "ij a", + "i ja", + "▁l ying", + "▁ly ing", + "▁ lying", + "▁St eve", + "▁Ste ve", + "▁me asures", + "▁measure s", + "▁meas ures", + "os to", + "ost o", + "o sto", + "? ”", + "▁p ocket", + "▁poc ket", + "▁S at", + "▁Sa t", + "▁p itch", + "▁pit ch", + "▁n atur", + "▁nat ur", + "▁hum ans", + "▁human s", + "▁Sim on", + "▁Si mon", + "ad ores", + "ado res", + "ador es", + "(\" \\", + "( \"\\", + "in king", + "ink ing", + "▁ex pos", + "▁exp os", + "mat erial", + "mate rial", + "m aterial", + "▁app arently", + "▁apparent ly", + "▁appar ently", + "▁C amb", + "▁Cam b", + "▁Ca mb", + "▁B ox", + "▁Bo x", + "▁ Box", + "▁s paces", + "▁sp aces", + "▁space s", + "ex ists", + "exist s", + "▁act ing", + "▁ac ting", + "OR Y", + "зо ва", + "Go od", + "G ood", + "ien ne", + "i enne", + "▁William s", + "▁f ruit", + "▁fr uit", + "▁fru it", + "ie ra", + "ier a", + "i era", + "▁L im", + "▁Li m", + "▁ Lim", + "▁t rait", + "▁tr ait", + "▁tra it", + "▁ trait", + "▁art ists", + "▁artist s", + "▁ab sor", + "▁abs or", + "ra it", + "rai t", + "r ait", + "LO AD", + "▁mov ies", + "▁movie s", + "▁d ynamic", + "▁dynam ic", + "▁dyn amic", + "▁ dynamic", + "as ts", + "ast s", + "a sts", + "▁In teger", + "▁ Integer", + "▁sm oke", + "п і", + "an gel", + "ang el", + "ange l", + ">( \"", + "> (\"", + "▁in strument", + "▁instr ument", + "▁f uel", + "▁fue l", + "▁fu el", + "но ї", + "atal ogue", + "atalog ue", + "▁s erial", + "▁se rial", + "▁ser ial", + "▁ serial", + "File s", + "Fil es", + "Fi les", + "F iles", + "▁bath room", + "il o", + "i lo", + "es to", + "est o", + "e sto", + "▁p m", + "▁ pm", + "ent ials", + "ential s", + "enti als", + "▁On line", + "wh ite", + "▁t ips", + "▁tip s", + "▁ti ps", + "▁cap able", + "Fi g", + "F ig", + "T V", + "▁о н", + "▁ он", + "k é", + "bit r", + "bi tr", + "b itr", + "Map ping", + "Ma pping", + "M apping", + "▁t ak", + "▁ta k", + "ю щи", + "в ля", + ")\" ,", + ") \",", + "▁K arl", + "▁Kar l", + "▁Ka rl", + "▁H uman", + "▁Hu man", + "▁Hum an", + "▁P ot", + "▁Po t", + "▁rep resents", + "▁represent s", + "▁cons istent", + "▁consist ent", + "_ (", + "we n", + "w en", + "▁R ose", + "▁Ro se", + "▁Ros e", + "la w", + "l aw", + "▁F ROM", + "▁FR OM", + "▁ FROM", + "▁beg ins", + "▁begin s", + "▁e dit", + "▁ed it", + "▁ edit", + "▁mount ain", + "▁ch apter", + "▁chap ter", + "▁wonder ed", + "▁indust rial", + "▁M ajor", + "▁Ma jor", + "▁Maj or", + "▁g es", + "▁ge s", + "▁ ges", + "▁direct ed", + "▁dire cted", + "er os", + "ero s", + "e ros", + "▁W ild", + "▁Wil d", + "▁Wi ld", + "li ament", + "lia ment", + "Bo ok", + "B ook", + "user name", + "ho t", + "h ot", + "▁n am", + "▁na m", + "▁ nam", + "▁le ague", + "br a", + "b ra", + "ко н", + "к он", + "▁T al", + "▁Ta l", + "▁В а", + "▁ex ports", + "▁exp orts", + "▁export s", + "▁ exports", + "( @", + "▁sh aring", + "▁shar ing", + "▁sha ring", + "▁T ro", + "▁Tr o", + "ś ć", + "ues day", + "yl v", + "y lv", + "▁gu itar", + "el en", + "ele n", + "e len", + "Se lection", + "Select ion", + "S election", + "▁conf ident", + "ry pto", + "rypt o", + "▁h ors", + "▁hor s", + "▁ho rs", + "ed itor", + "edit or", + "edi tor", + "▁should ers", + "▁shoulder s", + "get Name", + "en cing", + "enc ing", + "enci ng", + "SE LECT", + "SEL ECT", + "в ши", + "▁kind s", + "▁kin ds", + "▁W el", + "▁We l", + "▁pur poses", + "▁purpose s", + "Mat rix", + "in valid", + "▁own ers", + "▁owner s", + "▁ owners", + "▁Rec ords", + "▁Record s", + "▁ Records", + "▁Pro cess", + "▁ Process", + "▁c hat", + "▁ch at", + "▁cha t", + "▁ chat", + "▁D or", + "▁Do r", + "▁b in", + "▁bi n", + "▁ bin", + "re dit", + "red it", + "r edit", + "oi re", + "oir e", + "o ire", + "▁T otal", + "▁To tal", + "▁Tot al", + "▁ Total", + "▁F amily", + "▁Famil y", + "▁ Family", + "AR Y", + "▁b read", + "▁br ead", + "▁bre ad", + "▁ bread", + "▁com pre", + "▁comp re", + "▁compr e", + "▁sh oes", + "▁shoe s", + "▁r az", + "▁ra z", + "▁ raz", + "▁tr ace", + "▁tra ce", + "▁ trace", + "ne j", + "n ej", + "or ted", + "ort ed", + "orte d", + "h n", + "▁pro cedure", + "▁proced ure", + "pro perties", + "pl ier", + "▁h ero", + "▁he ro", + "▁her o", + "▁ hero", + "pan el", + "pa nel", + "p anel", + "▁mark ed", + "▁mar ked", + "▁wor ried", + "\\ |", + "pt s", + "p ts", + "▁S upport", + "▁Sup port", + "▁Supp ort", + "▁ Support", + "▁ser ving", + "▁serv ing", + "F ail", + "▁dis appoint", + "▁Sc ot", + "▁ple asure", + "▁j udge", + "▁jud ge", + "▁judg e", + "ze ich", + "▁for ever", + "▁fore ver", + "▁Ze it", + "uo us", + "u ous", + "in ent", + "ine nt", + "inen t", + "i nent", + "▁d w", + "▁ dw", + "▁w aren", + "▁war en", + "▁wa ren", + "▁ware n", + "▁fl ash", + "▁ flash", + "▁tro ops", + "▁dr ugs", + "▁dru gs", + "▁drug s", + "▁d iam", + "▁di am", + "▁dia m", + ". ~", + "im p", + "i mp", + "in ned", + "inn ed", + "▁E V", + "▁ EV", + "St ruct", + "Str uct", + "▁just ice", + "▁offic ials", + "▁official s", + "ff ff", + "fff f", + "f fff", + "▁Com mon", + "▁Comm on", + "▁ Common", + "▁C at", + "▁Ca t", + "▁ Cat", + "▁tom orrow", + "▁é l", + "▁ él", + "Text ure", + "Te xture", + "qp oint", + "q point", + "▁F ried", + "▁Fr ied", + "▁T erm", + "▁Te rm", + "▁Ter m", + "▁ Term", + "pgf qpoint", + "▁n em", + "▁ne m", + "▁ nem", + "no rm", + "nor m", + "n orm", + "▁hard ly", + "od a", + "o da", + "ze ta", + "zet a", + "z eta", + "em ic", + "emi c", + "e mic", + "▁по лу", + "▁пол у", + "▁lo aded", + "▁load ed", + "▁ loaded", + "ke s", + "k es", + "ci ó", + "c ió", + "▁f ool", + "▁fo ol", + "▁foo l", + "▁t rick", + "▁tr ick", + "▁tri ck", + "▁d st", + "▁ds t", + "▁ dst", + "Fin d", + "Fi nd", + "F ind", + "▁в се", + "}} ,", + "} },", + "▁frame work", + "▁ framework", + "▁mer ely", + "▁mere ly", + "▁un ion", + "▁ union", + "▁Ed ward", + "ri f", + "r if", + "Fl ag", + "F lag", + "▁cris is", + "▁cri sis", + "▁fin ite", + "▁ finite", + "▁l ol", + "▁lo l", + "▁K im", + "▁Ki m", + "на та", + "sin ce", + "s ince", + "▁com pat", + "▁comp at", + "▁ compat", + "▁p ert", + "▁per t", + "▁pe rt", + "▁ pert", + "ib ilities", + "ibil ities", + "▁tamb ién", + "ib li", + "▁t een", + "▁te en", + "▁ teen", + "▁sym pt", + "or al", + "ora l", + "o ral", + "de rs", + "der s", + "d ers", + "ot te", + "ott e", + "п ри", + "▁J ane", + "▁Jan e", + "▁Ja ne", + "▁original ly", + "▁origin ally", + "▁thro at", + "ma g", + "m ag", + "su p", + "s up", + "un i", + "u ni", + "$ $", + "▁L ibrary", + "▁ Library", + "▁att acks", + "▁attack s", + "in gen", + "ing en", + "inge n", + "(' /", + "▁h es", + "▁he s", + "▁ hes", + "co in", + "c oin", + "oun ce", + "▁Academ y", + "MOD ULE", + "is ms", + "ism s", + "▁A dv", + "▁Ad v", + "▁ Adv", + "▁B ol", + "▁Bo l", + "▁inc ident", + ")^ {", + ") ^{", + "▁b ij", + "▁bi j", + "▁R ome", + "▁Rom e", + "▁Ro me", + "▁It aly", + "▁Ital y", + "ev ents", + "event s", + "even ts", + "▁F ern", + "▁Fe rn", + "▁Fer n", + "▁b er", + "▁be r", + "▁ ber", + "▁sil ent", + "▁p ier", + "▁pie r", + "▁pi er", + "▁Y O", + "▁pl ain", + "▁ plain", + "B as", + "▁p ill", + "▁pi ll", + "▁pil l", + "ra se", + "ras e", + "r ase", + "▁car rying", + "▁carry ing", + "▁re sp", + "▁r esp", + "▁res p", + "▁ resp", + "ну ю", + "▁typ ical", + "Wrap per", + "W rapper", + "▁g au", + "▁ga u", + "▁chem ical", + "▁h al", + "▁ha l", + "▁ hal", + "th row", + "Cl uster", + "▁G ab", + "▁Ga b", + "▁G irl", + "▁Gi rl", + "▁Gir l", + "qu ir", + "▁A rg", + "▁Ar g", + "▁ Arg", + "▁rel ief", + "▁relie f", + "▁reli ef", + "▁В е", + "d m", + "▁fr ustr", + "▁fru str", + "\\ %", + "▁st ores", + "▁store s", + "▁stor es", + "▁sto res", + "▁bott le", + "▁bot tle", + "▁L ew", + "▁Le w", + "tw o", + "t wo", + "st ad", + "sta d", + "▁che ek", + "▁concern s", + "▁concer ns", + "▁help ful", + "▁co verage", + "▁cover age", + "is i", + "i si", + "AD D", + "A DD", + "as ync", + "asy nc", + "a sync", + "▁approxim ately", + "▁approx imately", + "▁approximate ly", + "if fer", + "iff er", + "iffe r", + "ho ok", + "h ook", + "▁e num", + "▁en um", + "▁ enum", + "ov á", + "o vá", + "▁e vil", + "▁ev il", + "▁const antly", + "▁constant ly", + "ap ply", + "app ly", + "▁si è", + "▁pract ices", + "▁practice s", + "▁te achers", + "▁teach ers", + "▁teacher s", + "▁S n", + "▁ Sn", + "▁A wards", + "▁Award s", + "▁Aw ards", + "▁sub stant", + "▁subst ant", + "▁$ .", + "▁ $.", + "d k", + "▁m ob", + "▁mo b", + "▁ mob", + "▁ing red", + "ve re", + "ver e", + "v ere", + "Mult i", + "пе р", + "п ер", + "st al", + "sta l", + "s tal", + "ya rd", + "yar d", + "y ard", + "requ ired", + "require d", + "ve ment", + "v ement", + "▁int elligence", + "▁intellig ence", + "▁th inks", + "▁think s", + "▁thin ks", + "▁person ally", + "▁personal ly", + "▁tr ained", + "▁tra ined", + "▁train ed", + "▁ trained", + "or ney", + "orn ey", + "orne y", + ") \\", + "an al", + "ana l", + "a nal", + "Se ction", + "S ection", + "pl us", + "ü t", + "▁em bed", + "▁emb ed", + "▁ embed", + "▁st rings", + "▁str ings", + "▁string s", + "▁ strings", + "Be fore", + "B efore", + "pro c", + "pr oc", + "p roc", + "▁с по", + "▁сп о", + "▁ спо", + "tr l", + "t rl", + "v r", + "Back ground", + "log ger", + "ag raph", + "agr aph", + "agra ph", + "a graph", + "ie st", + "ies t", + "i est", + "▁good s", + "bat ch", + "b atch", + "▁opt ional", + "▁option al", + "▁ optional", + "▁Tay lor", + "▁recogn ize", + "wal k", + "w alk", + "▁H it", + "▁Hi t", + "▁ Hit", + "▁Eliz abeth", + "} :", + "▁care ful", + "кра ї", + "▁loc ations", + "▁location s", + "▁struct ures", + "▁structure s", + "▁d isk", + "▁dis k", + "▁di sk", + "▁ disk", + "▁sh ips", + "▁ship s", + "▁ ships", + "▁s uo", + "▁su o", + "▁s owie", + "▁so wie", + "▁sow ie", + "▁E ss", + "▁Es s", + "▁H ash", + "▁Ha sh", + "▁Has h", + "▁ Hash", + "▁reason able", + "▁More over", + "▁form ula", + "▁C entre", + "▁Cent re", + "▁res idents", + "▁resident s", + "▁resid ents", + "R S", + "Id s", + "I ds", + "▁K now", + "▁Kn ow", + "▁t rib", + "▁tr ib", + "▁tri b", + "▁r és", + "▁ré s", + "▁s table", + "▁st able", + "▁sta ble", + "▁stab le", + "▁ stable", + "▁W ould", + "▁Wo uld", + "▁ Would", + "▁break ing", + "▁bre aking", + "▁ breaking", + "▁me al", + "▁p hen", + "▁ph en", + "▁f el", + "▁fe l", + "▁ fel", + "▁F red", + "▁Fr ed", + "▁Fre d", + "Aut hor", + "Auth or", + "▁c apture", + "▁capt ure", + "▁ capture", + "op ts", + "opt s", + "o pts", + "▁every where", + "▁s que", + "▁squ e", + "▁sq ue", + "▁m oder", + "▁mod er", + "▁mo der", + "▁mode r", + "set up", + "▁S upp", + "▁Su pp", + "▁Sup p", + "▁ Supp", + "▁when ever", + "▁whe never", + "{ (", + "wa rt", + "war t", + "w art", + "▁t oe", + "▁to e", + "Pre fix", + "Pref ix", + "P refix", + "ho u", + "h ou", + "ga ge", + "g age", + "> \"", + "▁f rag", + "▁fr ag", + "▁fra g", + "▁ frag", + "▁The orem", + "mem ory", + "▁cont ents", + "▁content s", + "▁conten ts", + "▁ contents", + "do cs", + "doc s", + "} '", + "▁Ir ish", + "The n", + "Th en", + "T hen", + "aa ts", + "aat s", + "a ats", + "Sa ve", + "S ave", + "▁a gency", + "▁ag ency", + "▁и ме", + "▁им е", + "до ва", + "дов а", + "▁F unction", + "▁Fun ction", + "▁ Function", + "N N", + "dest roy", + "▁M essage", + "▁Mess age", + "▁ Message", + "▁c ancel", + "▁can cel", + "▁ cancel", + "▁super ior", + "▁e c", + "▁ ec", + "▁liter ature", + "▁P ART", + "▁PA RT", + "▁PAR T", + "▁ PART", + "I l", + "▁C ab", + "▁Ca b", + "eng ine", + "▁b asket", + "▁bas ket", + "wor th", + "wort h", + "w orth", + "▁S el", + "▁Se l", + "f etch", + "▁St adt", + "▁Stad t", + "▁Sta dt", + "▁К и", + "▁con j", + "▁se iner", + "▁sein er", + "▁seine r", + "▁sei ner", + "▁conf irmed", + "▁confirm ed", + "▁Ar gent", + "▁Arg ent", + "am ar", + "ama r", + "a mar", + "pgf path", + "▁strugg le", + "Pat tern", + "▁M iddle", + "it an", + "ita n", + "i tan", + "▁m oon", + "▁mo on", + "or ough", + "oro ugh", + "o rough", + "▁Cath olic", + "▁str uck", + "▁stru ck", + "] ->", + "▁we apon", + "▁weap on", + "▁su bst", + "▁sub st", + "▁subs t", + "▁inst ructions", + "▁instruct ions", + "▁instruction s", + "▁occ as", + "▁oc cas", + "prote cted", + "▁L ess", + "▁Le ss", + "▁Les s", + "▁ Less", + "▁b atch", + "▁bat ch", + "▁ batch", + "▁con tra", + "▁cont ra", + "▁contr a", + "▁de ck", + "▁dec k", + "▁ deck", + "▁ign ored", + "▁ignore d", + "▁ignor ed", + "▁ref used", + "▁refuse d", + "tr igger", + "▁crim inal", + "G A", + "ol ly", + "oll y", + "▁B ell", + "▁Be ll", + "▁Bel l", + "▁ Ю", + "for ward", + "▁p refix", + "▁pre fix", + "▁pref ix", + "▁ prefix", + "▁im mediate", + "▁immedi ate", + "▁as signed", + "▁ass igned", + "▁assign ed", + "▁e lected", + "▁elect ed", + "▁ele cted", + "▁to night", + "▁ton ight", + "▁D ies", + "▁Die s", + "▁Di es", + "▁B each", + "▁Be ach", + "▁pre ced", + "▁prec ed", + "ow ał", + "owa ł", + "▁gal ax", + "▁log ic", + "en za", + "enz a", + "▁Cap tain", + "▁Capt ain", + "▁H ay", + "▁Ha y", + "▁f acts", + "▁fact s", + "▁fac ts", + "▁н и", + "▁ ни", + "t é", + "▁s b", + "▁ sb", + "op ed", + "ope d", + "o ped", + "▁com bat", + "▁comb at", + "▁expl ore", + "▁explo re", + "▁( -", + "▁ (-", + "Load er", + "Lo ader", + "▁Wil son", + "▁l ocked", + "▁loc ked", + "▁lock ed", + "▁ locked", + ": )", + "▁qu el", + "▁que l", + "▁q uel", + "▁ quel", + "▁Г а", + "T y", + "▁tem ps", + "▁temp s", + "▁g host", + "Mat erial", + "M aterial", + "ER CHANT", + "point er", + "po inter", + "ж да", + "ah a", + "a ha", + "ul f", + "▁sup plement", + "▁supp lement", + "▁d ismiss", + "▁dis miss", + "▁cl osing", + "▁clos ing", + "▁clo sing", + "▁vul ner", + "▁ap rès", + "▁apr ès", + "▁over whel", + "ско е", + "▁dis ag", + "ac ia", + "aci a", + "a cia", + "ou red", + "our ed", + "o ured", + "ru ption", + "rupt ion", + "▁P S", + "▁ PS", + "End point", + "Re al", + "▁T ag", + "▁Ta g", + "▁ Tag", + "▁st airs", + "▁sta irs", + "▁stair s", + "▁ stairs", + "ly n", + "l yn", + "▁e leg", + "▁el eg", + "▁ele g", + "▁v eter", + "▁ve ter", + "▁vet er", + "factor y", + "fact ory", + "f actory", + "an ne", + "ann e", + "▁B at", + "▁Ba t", + "▁fr anc", + "▁fra nc", + "lu ng", + "l ung", + "▁\" '", + ".' ,", + ". ',", + "▁C ountry", + "▁Count ry", + "▁Coun try", + "▁ Country", + "^{ [", + "▁y ours", + "▁you rs", + "▁your s", + "▁yo urs", + "ail ability", + "Cl ear", + "C lear", + "ät t", + "ä tt", + "пи с", + "п ис", + "▁j oke", + "▁jo ke", + "▁ann oy", + "▁r ag", + "▁ra g", + "▁ rag", + "var i", + "va ri", + "v ari", + "ле кс", + "лек с", + "▁P sy", + "il ty", + "ilt y", + "mo unt", + "m ount", + "▁c ual", + "▁cu al", + "▁s olar", + "▁so lar", + "▁sol ar", + "}^ {(", + "}^{ (", + "} ^{(", + "Sh ort", + "▁tax es", + "App end", + "Ap pend", + "Appe nd", + "W in", + "est yle", + "esty le", + "e style", + "▁fac il", + "▁fa cil", + "в ро", + "▁s ought", + "▁sou ght", + "▁b are", + "▁bar e", + "▁ba re", + "▁re act", + "▁ react", + "ja r", + "j ar", + "MA C", + "M AC", + "lo v", + "l ov", + "wa rn", + "war n", + "w arn", + "▁cru cial", + "▁m useum", + "ни ц", + "▁K ent", + "▁Ke nt", + "▁Ken t", + "May be", + "▁b ike", + "▁bi ke", + "▁Add ress", + "▁ Address", + "X ML", + "▁ad mitted", + "▁adm itted", + "▁admit ted", + "▁$ (\\", + "▁$( \\", + "▁sp ell", + "▁spe ll", + "▁spel l", + "▁ spell", + "▁v ic", + "▁vi c", + "gr e", + "g re", + "▁p roc", + "▁pro c", + "▁pr oc", + "▁ proc", + "th eless", + "the less", + "▁N om", + "▁No m", + "▁R ail", + "▁Ra il", + "▁acc eler", + "▁con vin", + "▁conv in", + "▁Pro perty", + "▁ Property", + "▁D A", + "▁ DA", + "▁cl ip", + "▁ clip", + "▁pl ugin", + "▁plug in", + "▁ plugin", + "Lim it", + "Li mit", + "L imit", + "view s", + "br u", + "b ru", + "▁p ra", + "▁pr a", + "▁a k", + "▁ ak", + "▁e j", + "▁ ej", + "▁o pts", + "▁op ts", + "▁opt s", + "▁ opts", + "▁sl ip", + "▁g ang", + "▁gan g", + "▁ga ng", + "▁ gang", + "as ted", + "ast ed", + "aste d", + "a sted", + "ual s", + "ua ls", + "u als", + "▁d ying", + "▁dy ing", + "Col l", + "Co ll", + "C oll", + "am men", + "amm en", + "▁Pol icy", + "▁ Policy", + "ERCHANT ABILITY", + "▁Col lection", + "▁Coll ection", + "▁Collect ion", + "▁ Collection", + "▁v ec", + "▁ve c", + "▁ vec", + "▁D ick", + "▁Di ck", + "st ud", + "▁la yers", + "▁lay ers", + "▁layer s", + "▁ layers", + "▁t ied", + "▁tie d", + "▁ti ed", + "}\\ \\", + "} \\\\", + "▁al ors", + "▁j ou", + "▁jo u", + "▁ch icken", + "▁chi cken", + "▁chick en", + "▁perman ent", + "▁Every thing", + "▁L ow", + "▁Lo w", + "▁ Low", + "▁C ook", + "▁Co ok", + "▁pe ak", + "▁PARTIC ULAR", + "▁d ear", + "▁de ar", + "i č", + "▁introdu ce", + "▁caus ing", + "▁ca using", + "пи са", + "пис а", + "Bo und", + "B ound", + "hu nd", + "h und", + "mult i", + "mul ti", + "▁p are", + "▁par e", + "▁pa re", + "▁ pare", + "an nt", + "ann t", + "▁b reat", + "▁bre at", + "▁commit ment", + "▁increasing ly", + "ко й", + "▁F riend", + "▁ Friend", + "▁stat istics", + "▁statist ics", + "▁Man ager", + "▁ Manager", + "pl icate", + "plic ate", + "plica te", + "Cl oud", + "ac i", + "a ci", + "▁Con ference", + "Sp an", + "S pan", + "▁C EO", + "▁CE O", + "▁W ait", + "▁Wa it", + "▁ Wait", + "▁O ber", + "▁Ob er", + "if ting", + "ift ing", + "im iento", + "imi ento", + "get Element", + "▁g le", + "▁gl e", + "▁ gle", + "ли я", + "▁w ieder", + "▁wie der", + "▁inst ruction", + "▁instr uction", + "▁instruct ion", + "gl y", + "g ly", + "▁bl ame", + "▁list ade", + "▁lista de", + "▁a apt", + "▁Lew is", + "Fr agment", + "▁g ear", + "▁ge ar", + "mi ll", + "mil l", + "m ill", + "pro d", + "pr od", + "p rod", + "▁bur ning", + "▁burn ing", + "є ться", + "▁m é", + "▁ mé", + "è ne", + "▁com plicated", + "▁compl icated", + "▁complic ated", + "b h", + "▁Just ice", + "▁t ested", + "▁te sted", + "▁test ed", + "▁st aring", + "▁star ing", + "▁sta ring", + "▁surv ive", + "▁surviv e", + "▁c ous", + "▁co us", + "▁cou s", + "▁r ib", + "▁ri b", + "▁ rib", + "am l", + "a ml", + "▁T rust", + "▁Tr ust", + "▁Tru st", + "▁c ad", + "▁ca d", + "▁T err", + "▁Te rr", + "▁Ter r", + "▁m apping", + "▁map ping", + "▁ma pping", + "▁ mapping", + "▁tw elve", + "▁g rant", + "▁gr ant", + "▁gran t", + "▁gra nt", + "▁th orough", + "▁ Ü", + "▁fol ks", + "▁folk s", + "▁Cont ent", + "▁ Content", + "▁child hood", + "ck er", + "cke r", + "c ker", + "с но", + "RE CT", + "REC T", + "R ECT", + "▁f inale", + "▁fin ale", + "▁final e", + "▁sh ower", + "▁show er", + "ér ic", + "éri c", + "é ric", + "▁s pat", + "▁sp at", + "od ge", + "р ь", + "▁p es", + "▁pe s", + "▁ pes", + "ed a", + "e da", + "D b", + "▁Ant onio", + "▁Anton io", + "▁eng aged", + "▁engage d", + "▁v ess", + "▁ve ss", + "val s", + "va ls", + "v als", + "▁elect ronic", + "▁electron ic", + "▁electro nic", + "le mma", + "lem ma", + "▁W y", + "ma d", + "m ad", + "mer ge", + "ap on", + "a pon", + "▁priv ile", + "▁nov embre", + "▁nove mbre", + "▁S ports", + "▁Sp orts", + "▁Sport s", + "wi ll", + "w ill", + "▁control s", + "▁contr ols", + "▁contro ls", + "▁ controls", + "▁c ategories", + "▁categ ories", + "▁categor ies", + "▁ categories", + "▁Georg ia", + "ip edia", + "▁A V", + "▁ AV", + "at ori", + "ator i", + "ato ri", + "▁_ __", + "▁__ _", + "▁ ___", + "▁ À", + "▁R yan", + "▁Ry an", + "▁Char lie", + "▁Charl ie", + "▁и сто", + "▁ис то", + "▁em otion", + "▁emot ion", + "▁co oking", + "▁cook ing", + "▁attempt s", + "▁FIT NESS", + "ät er", + "ä ter", + "En able", + "D T", + "▁Ch ange", + "▁ Change", + "Asp Net", + "▁г а", + "▁ га", + "▁ord inary", + "▁ordin ary", + "▁S QL", + "▁ SQL", + "pl ane", + "plan e", + "p lane", + "% .", + "▁Sum mer", + "▁av ait", + "up p", + "u pp", + "▁ill ness", + "UI NT", + "U INT", + "> {", + "▁zw ischen", + "▁hard ware", + "▁sound ed", + "equ iv", + "▁p iano", + "▁pi ano", + "▁pian o", + "us et", + "use t", + "u set", + "k n", + "TR Y", + "▁b ab", + "▁ba b", + "не н", + "н ен", + "▁rel iable", + "▁reli able", + "▁Bron nen", + "▁St ore", + "▁Sto re", + "▁ Store", + "A z", + "▁» ,", + "▁ »,", + "St atic", + "Stat ic", + "d w", + "gr een", + "gre en", + "g reen", + "▁' ';", + "▁'' ;", + "li j", + "l ij", + "ev a", + "e va", + "ні й", + "▁S yd", + "▁Sy d", + "in ois", + "ino is", + "con vert", + "conv ert", + "▁decl are", + "▁declar e", + "br es", + "bre s", + "b res", + "IN K", + "it led", + "itle d", + "▁acc ord", + "▁ac cord", + "▁m ars", + "▁mar s", + "▁ma rs", + "Sequ ence", + "zi p", + "z ip", + "▁Braz il", + "▁meet ings", + "▁meeting s", + "▁accur acy", + "▁M achine", + "▁Mach ine", + "▁ Machine", + "▁aut or", + "▁au tor", + "▁auto r", + "▁ autor", + "▁a insi", + "▁ain si", + "Sim ple", + "Res ources", + "Re sources", + "Resource s", + "ка за", + "каз а", + "▁M P", + "▁ MP", + "th ey", + "the y", + "▁B ang", + "▁Ba ng", + "▁Ban g", + "▁e ing", + "▁ein g", + "▁ eing", + "ate ful", + "▁Some thing", + "▁Som ething", + "▁ Something", + "▁up set", + "Hist ory", + "Hi story", + "dim ensional", + "▁explan ation", + "▁c iv", + "▁ci v", + "▁c once", + "▁con ce", + "▁conc e", + "▁kö z", + "▁prom ised", + "▁promise d", + "ж ду", + "we d", + "w ed", + "For e", + "F ore", + "Am ount", + "A mount", + "ab b", + "a bb", + "▁cl othing", + "▁cloth ing", + "▁clo thing", + "ли сь", + "oe n", + "o en", + "▁Pr int", + "▁Pri nt", + "▁Prin t", + "▁ Print", + "▁s izes", + "▁size s", + "▁si zes", + "▁b anks", + "▁bank s", + "▁ban ks", + "ri bed", + "rib ed", + "ribe d", + "▁' ../", + "▁'. ./", + "FI X", + "F IX", + "▁H ug", + "▁Hu g", + "▁z n", + "▁ zn", + "▁I NT", + "▁IN T", + "▁ INT", + "▁in stances", + "▁inst ances", + "▁instance s", + "▁along side", + "Name space", + "Names pace", + "▁re new", + "▁ren ew", + "▁a sc", + "▁as c", + "▁ asc", + "▁w aves", + "▁wa ves", + "▁wave s", + "▁p om", + "▁po m", + "D uration", + "day s", + "da ys", + "d ays", + "$ (", + "▁grab bed", + "▁sur gery", + "▁surge ry", + "▁surg ery", + "▁re store", + "▁rest ore", + "▁ restore", + "Norm al", + "N ormal", + "▁L eb", + "▁Le b", + "▁anal yt", + "▁analy t", + "Lite ral", + "L iteral", + "H A", + "▁sh ares", + "▁share s", + "▁shar es", + "▁sha res", + "il let", + "ill et", + "ille t", + "ol s", + "o ls", + "▁D og", + "▁Do g", + "or no", + "orn o", + "▁man ip", + "ja v", + "j av", + "▁ess entially", + "▁essential ly", + "▁cas ual", + "op l", + "o pl", + "▁ р", + "▁S U", + "▁ SU", + "▁engine ering", + "▁engineer ing", + "▁Pr ime", + "▁Pri me", + "▁Prim e", + "▁S W", + "▁ SW", + "▁re aching", + "▁reach ing", + "▁в ла", + "▁Ро сси", + "▁K re", + "▁Kr e", + "er ry", + "err y", + "▁op pon", + "▁opp on", + "pro gram", + "pr ogram", + "em per", + "emp er", + "is Empty", + "▁U nit", + "▁Un it", + "▁ Unit", + "IN TER", + "INT ER", + "INTE R", + "et he", + "eth e", + "e the", + "z d", + "CU R", + "C UR", + "▁v m", + "▁ vm", + "con v", + "co nv", + "ro pol", + "rop ol", + "r opol", + "▁Co ast", + "▁S elect", + "▁Se lect", + "▁Sel ect", + "▁ Select", + "▁бы ла", + "▁был а", + "▁V e", + "ow y", + "o wy", + "▁my th", + "ce ptions", + "ception s", + "cept ions", + "class es", + "▁w orden", + "▁wor den", + "▁word en", + "▁ass ault", + "▁d ual", + "▁du al", + "OR K", + "▁in ches", + "▁inc hes", + "▁inch es", + "▁F A", + "▁ FA", + "▁St ation", + "▁Stat ion", + "▁ Station", + "▁person ality", + "▁personal ity", + "▁s car", + "▁sc ar", + "▁ scar", + "▁reg ime", + "▁not en", + "▁no ten", + "▁note n", + "▁r ural", + "▁ru ral", + "iz a", + "i za", + "Aud io", + "A udio", + "▁dis put", + "▁disp ut", + "▁a ver", + "▁av er", + "▁ave r", + "▁ aver", + "▁o bst", + "▁ob st", + "▁obs t", + "▁Reg ion", + "▁ Region", + "ut f", + "u tf", + "▁C ass", + "▁Cas s", + "▁Ca ss", + "hs pace", + "h space", + "▁sh ipping", + "▁ship ping", + "ik o", + "i ko", + "ic ked", + "ick ed", + "num er", + "nu mer", + "n umer", + "д на", + "ri el", + "rie l", + "r iel", + "dis abled", + "disable d", + "op ol", + "o pol", + "lo oking", + "look ing", + "▁class ical", + "▁classic al", + "▁construct ed", + "▁constru cted", + "▁refer enties", + "] +", + "▁capt ured", + "▁capture d", + "▁min imal", + "▁minim al", + "▁mini mal", + "▁s ock", + "▁so ck", + "▁soc k", + "▁ sock", + "fa ther", + "f ather", + "is ión", + "isi ón", + "▁equ ally", + "▁equal ly", + "▁eq ually", + "▁red uction", + "▁redu ction", + "An t", + "A nt", + "ais on", + "ai son", + "a ison", + "▁ar gue", + "▁arg ue", + "cir cle", + "circ le", + "▁t oler", + "▁to ler", + "}\" ,", + "} \",", + "▁prim arily", + "us al", + "usa l", + "u sal", + "▁al gebra", + "▁gather ed", + "▁Re member", + "▁Rem ember", + "_) ;", + "_ );", + "UT E", + "U TE", + "▁K it", + "▁Ki t", + "▁ Kit", + "S y", + "HE AD", + "▁re cipe", + "▁rec ipe", + "▁recip e", + "▁sc enario", + "▁scen ario", + "▁Follow ing", + "VA R", + "V AR", + "▁y ard", + "▁ya rd", + "▁ yard", + "▁st ad", + "▁sta d", + "▁ stad", + "* (", + "▁valid ate", + "▁ validate", + "DE X", + "D EX", + "▁commit tee", + "▁t emporary", + "▁tempor ary", + "▁consequ ences", + "▁consequence s", + "▁égal ement", + "кти в", + "к тив", + "▁r a", + "▁ ra", + "▁dis pl", + "▁di spl", + "▁disp l", + "▁app s", + "▁ap ps", + "▁ apps", + "▁Te il", + "▁» .", + "▁ ».", + "▁adopt ed", + "ten sor", + "t ensor", + "▁fe min", + "▁fem in", + "▁м ар", + "▁ма р", + "ло ги", + "te ch", + "t ech", + "▁R ot", + "▁Ro t", + "▁ Rot", + "▁kn ees", + "▁kne es", + "▁knee s", + "ph ys", + "phy s", + "ow ej", + "owe j", + "▁Ox ford", + "ан д", + "а нд", + "he ll", + "hel l", + "h ell", + "ograf ia", + "▁ex posed", + "▁exp osed", + "▁expos ed", + "▁expose d", + "kt op", + "k top", + "ob y", + "o by", + "lo wer", + "low er", + "l ower", + "▁Se nate", + "▁Sen ate", + "▁s word", + "▁sw ord", + "▁swo rd", + "Fl ow", + "F low", + "▁Un fortunately", + "▁box es", + "▁ boxes", + "▁cu ando", + "▁pi lot", + "▁pil ot", + "▁Al bum", + "▁Alb um", + "B al", + "So rt", + "S ort", + "FI ELD", + "▁de sert", + "▁des ert", + "CO MM", + "COM M", + "ro ns", + "ron s", + "r ons", + "ad ows", + "ado ws", + "adow s", + "▁l oyal", + "▁lo yal", + "▁as set", + "▁ass et", + "▁ asset", + "▁m ud", + "▁mu d", + "ф а", + "▁second ary", + "▁ secondary", + "▁А р", + "▁c ul", + "▁cu l", + "▁ cul", + "▁As ian", + "▁Asia n", + "▁stay ing", + "▁sta ying", + "▁data set", + "▁dat aset", + "▁ dataset", + "▁U SE", + "▁US E", + "▁ USE", + "▁l oves", + "▁lo ves", + "▁love s", + "▁lov es", + "▁vel ocity", + "▁veloc ity", + "á v", + "▁purch ased", + "▁purchase d", + "SO C", + "S OC", + "▁compet itive", + "▁Foot ball", + "is ka", + "isk a", + "i ska", + "▁kn ock", + "st airs", + "sta irs", + "az y", + "a zy", + "▁v end", + "▁ve nd", + "▁ven d", + "▁ar ts", + "▁art s", + "▁ arts", + "▁B ras", + "▁Br as", + "▁Bra s", + "ue la", + "uel a", + "u ela", + "кт о", + "к то", + "tr im", + "tri m", + "t rim", + "▁d irty", + "▁dir ty", + "▁dirt y", + "▁ dirty", + "▁webs ites", + "▁website s", + "▁In dep", + "▁Ind ep", + "▁с тра", + "▁ст ра", + "▁ стра", + "s r", + "▁t icket", + "▁tick et", + "at ile", + "ati le", + "a tile", + "▁implement ed", + "▁вре мя", + "▁bo wl", + "▁bow l", + "DA TE", + "DAT E", + "D ATE", + "▁al ter", + "▁alt er", + "▁ alter", + "▁S pace", + "▁Sp ace", + "▁ Space", + "▁accom pan", + "▁accomp an", + "or don", + "ord on", + "▁do ctors", + "▁doctor s", + "ist as", + "ista s", + "C ast", + "до м", + "CT L", + "C TL", + "ur ers", + "ure rs", + "urer s", + "▁ingred ients", + "▁calcul ated", + "▁calculate d", + "▁calc ulated", + "▁le ather", + "▁s ensitive", + "▁sens itive", + "▁sus pic", + "▁susp ic", + "st an", + "sta n", + "s tan", + "▁an ni", + "▁ann i", + "▁ anni", + "aw ait", + "awa it", + "a wait", + "▁Fr anç", + "▁Fran ç", + "▁ab ort", + "▁ abort", + "▁Sp irit", + "▁W alter", + "▁Wal ter", + "▁Walt er", + "un kt", + "unk t", + "▁vert ical", + "▁ vertical", + "OR S", + "O RS", + "be st", + "bes t", + "b est", + "▁Cl ient", + "▁ Client", + "it ated", + "ita ted", + "itate d", + "itat ed", + "▁в а", + "▁ ва", + "▁ Č", + "▁v ille", + "▁vi lle", + "▁vill e", + "▁vil le", + "▁ ville", + "▁di plom", + "or ne", + "orn e", + "▁b ars", + "▁bar s", + "▁ba rs", + "▁ bars", + "U ri", + "AP TER", + "pon s", + "po ns", + "p ons", + "ut z", + "u tz", + "Pro to", + "Pr oto", + "▁st ir", + "▁ц е", + "▁ це", + "▁pr imer", + "▁prim er", + "▁pri mer", + "▁prime r", + "ig ible", + "igi ble", + "ex tra", + "ext ra", + "extr a", + "▁Bo oks", + "▁Book s", + "▁B os", + "▁Bo s", + "▁E t", + "▁W elt", + "▁We lt", + "▁Wel t", + "▁Kore a", + "▁Ko rea", + "▁Kor ea", + "ри то", + "р ито", + "▁v ibr", + "▁vi br", + "S elf", + "line ar", + "lin ear", + "о б", + "▁L ang", + "▁La ng", + "▁Lan g", + "▁ Lang", + "▁de eper", + "▁deep er", + "▁term in", + "▁ter min", + "▁ termin", + "en schaft", + "ens chaft", + "ensch aft", + "▁ро ці", + "am med", + "amm ed", + "vis ible", + "v isible", + "▁IO Exception", + "▁ IOException", + "▁W ind", + "▁Win d", + "▁Wi nd", + "us qu", + "▁S top", + "▁St op", + "▁Sto p", + "▁ Stop", + "▁ор га", + "IN VALID", + "INVAL ID", + "▁c ub", + "▁cu b", + "▁j ew", + "▁je w", + "▁cap tain", + "▁capt ain", + "з і", + "ch unk", + "apt ure", + "ash board", + "▁div ided", + "▁divid ed", + "▁divide d", + "▁ext ensive", + "▁extens ive", + "▁s uffer", + "▁suff er", + "▁he ading", + "▁head ing", + "▁ heading", + "cre ated", + "create d", + "creat ed", + "c reated", + "▁quiet ly", + "▁n y", + "▁ ny", + "▁по л", + "▁ пол", + "\" +", + "ik an", + "ika n", + "i kan", + "▁design s", + "z u", + "}+ \\", + "} +\\", + "Oper ator", + "▁Le mma", + "▁Lem ma", + "▁на у", + "ac ji", + "ло ве", + "лов е", + "Serv let", + "▁K evin", + "▁Ke vin", + "st age", + "sta ge", + "b n", + "text width", + "fa iled", + "fail ed", + "f ailed", + "▁St aff", + "▁Sta ff", + "▁e nem", + "▁en em", + "un de", + "und e", + "u nde", + "ен ь", + "е нь", + "Pack et", + "P acket", + "▁A ls", + "▁Al s", + "ka r", + "k ar", + "][ '", + "] ['", + "ke d", + "k ed", + "Per s", + "Pe rs", + "P ers", + ">: :", + "> ::", + "▁a rc", + "▁ar c", + "▁ arc", + "▁sy nt", + "▁syn t", + "SP E", + "S PE", + "▁Д а", + "▁M i", + "▁M oh", + "▁Mo h", + "▁De ath", + "b rowser", + "▁D ave", + "▁Dav e", + "▁Da ve", + "▁s ucc", + "▁su cc", + "▁suc c", + "t oggle", + "▁t ack", + "▁ta ck", + "Com ment", + "Comm ent", + "er on", + "ero n", + "e ron", + "▁aware ness", + "▁h ug", + "▁cont emporary", + "▁contempor ary", + "ul ating", + "ula ting", + "▁T itle", + "▁Tit le", + "▁Ti tle", + "▁ Title", + "▁TH IS", + "hav ior", + "ran k", + "r ank", + "▁do zen", + "▁che ese", + "co ln", + "col n", + "▁rad ius", + "▁radi us", + "▁ radius", + "▁dim ensions", + "▁dimension s", + "rodu ction", + "rod uction", + "▁ad ds", + "▁add s", + "▁house hold", + "▁D avis", + "▁Dav is", + "▁Da vis", + "pk g", + "p kg", + "{ $", + "▁cas ino", + "▁P ierre", + "▁Pier re", + "▁Pi erre", + "▁object ive", + "tr ain", + "tra in", + "▁Mich igan", + "pay load", + "▁r ug", + "▁ru g", + "▁ rug", + "▁se vere", + "▁sever e", + "me an", + "▁t oss", + "▁to ss", + "▁embar rass", + "▁V ery", + "▁Ver y", + "▁Ve ry", + "▁ Very", + "▁appe al", + "▁Com put", + "▁Comp ut", + "▁ Comput", + "▁forgot ten", + "▁k ernel", + "▁ker nel", + "▁ kernel", + "▁car bon", + "▁carb on", + "f w", + "▁С у", + "▁Emp ire", + "▁qu ote", + "▁quot e", + "▁ quote", + "et z", + "e tz", + "▁m ini", + "▁min i", + "▁mi ni", + "▁p ipe", + "▁pi pe", + "▁pip e", + "▁ pipe", + "▁n ous", + "▁no us", + "▁nou s", + "▁M ove", + "▁Mo ve", + "▁Mov e", + "▁ Move", + "▁д у", + "▁ ду", + "▁nerv ous", + "▁М ар", + "▁Ма р", + "* \r", + "▁B ush", + "▁Bus h", + "▁Bu sh", + "▁pe er", + "▁ peer", + "▁W rit", + "▁Wr it", + "▁ Writ", + "▁satisf ied", + "▁pull ing", + "▁pul ling", + "▁P ur", + "▁Pu r", + "▁M iller", + "▁Mil ler", + "▁Mill er", + "▁F L", + "▁ FL", + "am az", + "ama z", + "a maz", + "▁m ile", + "▁mil e", + "▁mi le", + "▁ mile", + "▁N eed", + "▁Ne ed", + "▁ Need", + "▁sup plies", + "▁a ño", + "▁p ace", + "▁pa ce", + "▁pac e", + "▁ pace", + "▁Vict oria", + "▁Victor ia", + "▁ou ght", + "▁ ought", + "▁P layer", + "▁Pl ayer", + "▁Play er", + "▁ Player", + "agnost ic", + "▁v iv", + "▁vi v", + "▁ viv", + "▁Pat rick", + "▁Patri ck", + "▁ Š", + "▁St ory", + "▁Sto ry", + "ac a", + "a ca", + "▁mount ains", + "▁mountain s", + "CL ASS", + "▁fr agment", + "▁frag ment", + "▁ fragment", + "▁sett lement", + "▁settle ment", + "▁Further more", + "▁dr ivers", + "▁dri vers", + "▁driv ers", + "▁drive rs", + "▁driver s", + "▁J u", + "▁бы ли", + "▁был и", + "Row s", + "Ro ws", + "R ows", + "▁im pression", + "▁imp ression", + "▁impress ion", + "▁in fer", + "▁inf er", + "▁Ex pl", + "▁Exp l", + "ol ute", + "olut e", + "olu te", + "ov an", + "ova n", + "o van", + "ar ance", + "aran ce", + "CA P", + "C AP", + "▁en force", + "▁B urn", + "▁Bur n", + "▁Bu rn", + "Res et", + "Re set", + "mo ther", + "mot her", + "m other", + "▁B attle", + "▁Bat tle", + "▁Batt le", + "▁ Battle", + "pad ding", + "p adding", + "ia te", + "iat e", + "i ate", + "▁c ried", + "▁cr ied", + "▁cri ed", + "A K", + "un s", + "u ns", + "▁siè cle", + "▁Cont in", + "▁ Contin", + "ban k", + "b ank", + "ju nit", + "j unit", + "object s", + "Ro t", + "R ot", + "is sa", + "iss a", + "▁be gun", + "▁beg un", + "* -", + "▁vis iting", + "▁visit ing", + "ж де", + "▁target s", + "▁tar gets", + "▁L atin", + "▁Lat in", + "у т", + "▁E sc", + "▁Es c", + "* ;", + "ån g", + "å ng", + "▁( {", + "▁ ({", + "▁di agram", + "▁dia gram", + "Mod els", + "Model s", + "Mode ls", + "▁part nership", + "▁partner ship", + "▁partners hip", + "▁fr ån", + "ul ty", + "ult y", + "Po d", + "P od", + "CA LL", + "CAL L", + "C ALL", + "mod al", + "mo dal", + "si g", + "s ig", + "it zer", + "itz er", + "it el", + "ite l", + "▁convin ced", + "▁convince d", + "ab l", + "a bl", + "ст ве", + "ств е", + "▁c ot", + "▁co t", + "▁re peat", + "▁repe at", + "▁ repeat", + "▁l ists", + "▁li sts", + "▁list s", + "▁ lists", + "so und", + "s ound", + "▁r oyal", + "▁ro yal", + "▁gr ace", + "▁gra ce", + "▁o raz", + "▁or az", + "Not ification", + "pr ite", + "prit e", + "p rite", + "▁arriv al", + "▁arr ival", + "an cell", + "ance ll", + "anc ell", + "ancel l", + "hent ic", + "de code", + "dec ode", + "▁fant astic", + "pro gress", + "pro xy", + "pr oxy", + "z ő", + "ke l", + "k el", + "▁conven ient", + "aqu e", + "a que", + "ri et", + "rie t", + "r iet", + "▁Dig ital", + "io rs", + "ior s", + "i ors", + "▁B udd", + "▁Bud d", + "▁Bu dd", + "and ra", + "ad dy", + "add y", + "▁o vers", + "▁over s", + "▁ov ers", + "▁consum ers", + "▁consumer s", + "▁consume rs", + "p n", + "mo use", + "m ouse", + "▁B C", + "▁ BC", + "de g", + "d eg", + "pe rm", + "per m", + "p erm", + "it és", + "ité s", + "▁и спо", + "▁ис по", + "he ast", + "h east", + "ho ur", + "hou r", + "h our", + "PAR AM", + "con scious", + "▁w ing", + "▁win g", + "▁ wing", + "▁atmos phere", + "▁g ig", + "▁gi g", + "▁con tre", + "▁cont re", + "▁contr e", + "▁dr ama", + "▁dram a", + "я т", + "▁Fr ont", + "▁Fro nt", + "▁ Front", + "▁philosoph y", + "▁H art", + "▁Har t", + "▁Ha rt", + "▁n urs", + "▁nu rs", + "▁nur s", + "ur as", + "ura s", + "u ras", + "▁T ru", + "▁Tr u", + "▁s ud", + "▁su d", + "▁per forming", + "▁perform ing", + "п ы", + "▁conf used", + "▁che cks", + "▁check s", + "am t", + "a mt", + "Ma ke", + "M ake", + "▁R O", + "▁ RO", + "▁d f", + "▁ df", + "iz ations", + "ization s", + "▁deg li", + "▁architect ure", + "Render er", + "▁Л а", + "▁p tr", + "▁pt r", + "▁ ptr", + "▁die ser", + "▁dies er", + "▁diese r", + "sub mit", + "▁top ics", + "▁topic s", + "▁princip les", + "▁prin ciples", + "▁principle s", + "var s", + "va rs", + "v ars", + "so ck", + "soc k", + "s ock", + "▁ton gue", + "▁tong ue", + "▁percent age", + "▁S S", + "▁ SS", + "▁d ol", + "▁do l", + "▁r ice", + "▁ri ce", + "▁ric e", + "▁ rice", + "í o", + "▁E astern", + "▁East ern", + "▁Easter n", + "▁recogn ition", + "▁E rn", + "▁Er n", + "▁U t", + "▁ Ut", + "▁c aut", + "▁ca ut", + "▁Cl oud", + "▁ Cloud", + "▁con version", + "▁conv ersion", + "▁convers ion", + "▁Oh io", + "▁M E", + "▁ ME", + "▁sur ely", + "▁sure ly", + "▁g ard", + "▁gar d", + "▁ga rd", + "pu is", + "p uis", + "▁u rg", + "▁ur g", + "▁ urg", + "im i", + "i mi", + "▁abs ence", + "▁w inner", + "▁win ner", + "L anguage", + "▁HT TP", + "▁ HTTP", + "w t", + "▁trans lation", + "▁transl ation", + "▁ translation", + "с с", + "▁K ind", + "▁Ki nd", + "▁Kin d", + "▁ Kind", + "Tw o", + "T wo", + "▁Re volution", + "▁Rev olution", + "In sert", + "Ins ert", + "Ev ery", + "E very", + "or ient", + "ori ent", + "orie nt", + "o rient", + "▁т ра", + "▁ тра", + "▁emot ions", + "▁emotion s", + "det ails", + "detail s", + "▁f lu", + "▁fl u", + "▁ flu", + "▁oper ate", + "▁opera te", + "A g", + "un ning", + "unn ing", + "▁part ie", + "▁parti e", + "tr i", + "t ri", + "▁gold en", + "▁gol den", + "▁Б и", + "▁found ation", + "is ten", + "ist en", + "iste n", + "i sten", + "▁Car los", + "▁Carl os", + "▁Carlo s", + "Child ren", + "▁neigh b", + "▁C art", + "▁Car t", + "▁Ca rt", + "▁ Cart", + "Be gin", + "B egin", + "г да", + "▁s cheduled", + "▁schedule d", + "▁schedul ed", + "' >", + "▁observ ations", + "▁observation s", + "▁produ cer", + "▁produce r", + "ath ers", + "ather s", + "a thers", + "но му", + "ном у", + "▁expect ations", + "▁expectation s", + "os o", + "o so", + "z h", + "mu table", + "mut able", + "▁wr ites", + "▁writ es", + "▁write s", + "▁p ushing", + "▁push ing", + "▁se ats", + "▁sea ts", + "▁seat s", + "▁br east", + "▁bre ast", + "ap ing", + "api ng", + "a ping", + "▁Sim ple", + "▁ Simple", + "▁s ocket", + "▁soc ket", + "▁sock et", + "▁ socket", + "▁sl ave", + "▁sla ve", + "▁ slave", + "il ey", + "ile y", + "i ley", + "▁ass istant", + "▁assist ant", + "▁t rim", + "▁tr im", + "▁tri m", + "▁ trim", + "▁land scape", + "▁landsc ape", + "▁associ ation", + "qu ant", + "▁Pal est", + "▁swe at", + "en gers", + "eng ers", + "enge rs", + "enger s", + "? _", + "é p", + "> .", + "▁c urious", + "▁cur ious", + "▁Com ponent", + "▁ Component", + "▁re placement", + "▁repl acement", + "▁replace ment", + "ра ль", + "рал ь", + "р аль", + "▁Tr ack", + "▁Tra ck", + "▁ Track", + "▁Re move", + "▁Rem ove", + "▁ Remove", + "▁S ize", + "▁Si ze", + "▁ Size", + "pe ror", + "per or", + "▁cal culate", + "▁calcul ate", + "▁calc ulate", + "▁s essions", + "▁session s", + "▁type d", + "▁typ ed", + "▁ty ped", + "▁sub mit", + "▁subm it", + "▁ submit", + "!! !", + "! !!", + "▁part ition", + "▁ partition", + "ed ing", + "edi ng", + "e ding", + "-- ---", + "---- -", + "--- --", + "- ----", + "az ioni", + "azi oni", + "lie ß", + "on al", + "ona l", + "o nal", + "▁sh ru", + "▁shr u", + "▁RE G", + "▁ REG", + "▁F ac", + "▁Fa c", + "▁ Fac", + "config uration", + "▁бы ло", + "▁был о", + "▁A mong", + "▁Am ong", + "__ );", + "__) ;", + "_ _);", + "▁Ser ver", + "▁Serv er", + "▁ Server", + "▁L OG", + "▁LO G", + "▁ LOG", + "▁c and", + "▁can d", + "▁ca nd", + "'] );", + "']) ;", + "' ]);", + "go v", + "g ov", + "▁S ix", + "▁Si x", + "un defined", + "und efined", + "undef ined", + "▁t y", + "▁ ty", + "as a", + "a sa", + "▁part icles", + "▁partic les", + "▁particle s", + "▁parti cles", + "▁ф ор", + "▁фо р", + "▁ фор", + "` `", + "T ube", + "el and", + "ela nd", + "e land", + "fo ld", + "fol d", + "f old", + "og o", + "o go", + "▁appro aches", + "▁approach es", + "on da", + "ond a", + "ag r", + "a gr", + ", $", + "▁{ {", + "▁ {{", + "▁Mod ern", + "▁Mo dern", + "▁Mode rn", + "▁W inter", + "▁Win ter", + "av ailable", + "▁L ud", + "▁Lu d", + "▁c asa", + "▁cas a", + "▁ca sa", + "▁C ould", + "▁Co uld", + "▁Cou ld", + "▁ Could", + "▁fif teen", + "▁pot entially", + "▁potential ly", + "^ ^", + "▁se it", + "▁sei t", + "An imation", + "Anim ation", + "ко го", + "к ого", + "Z one", + "el if", + "eli f", + "e lif", + "▁acknow led", + "▁own ership", + "▁owner ship", + "▁owners hip", + "▁describ es", + "▁describe s", + "▁re verse", + "▁revers e", + "▁rever se", + "▁ reverse", + "▁con test", + "▁cont est", + "▁sc ored", + "▁score d", + "▁op posed", + "▁opp osed", + "▁oppos ed", + "fl ex", + "f lex", + "kr e", + "k re", + "▁mer ge", + "▁ merge", + "▁cover ing", + "▁cov ering", + "▁hon estly", + "▁honest ly", + "▁M ess", + "▁Me ss", + "▁Mes s", + "▁r arely", + "▁rare ly", + "▁incred ible", + "it age", + "ita ge", + "▁vict ims", + "▁victim s", + "ны ми", + "ным и", + "w l", + "iz za", + "izz a", + "i zza", + "d n", + "on de", + "ond e", + "o nde", + "▁pr zy", + "▁prz y", + "▁HT ML", + "▁ HTML", + "▁pay load", + "▁ payload", + "Bu s", + "B us", + "us b", + "u sb", + "F n", + "▁display ed", + "▁o cean", + "▁A venue", + "▁Av enue", + "ac ion", + "aci on", + "acio n", + "gh an", + "g han", + "met ric", + "m etric", + "ie ties", + "iet ies", + "▁attract ive", + "▁attr active", + "▁f ö", + "▁ fö", + "C reat", + "ver ter", + "vert er", + "▁Al ice", + "▁Ali ce", + "по л", + "▁f raction", + "▁fr action", + "▁fra ction", + "▁fract ion", + "▁behav iour", + "▁behavi our", + "▁Jer sey", + "▁re venue", + "▁rev enue", + "▁reven ue", + "▁t res", + "▁tr es", + "▁tre s", + "▁ tres", + "IL D", + "I LD", + "▁É t", + "▁s ync", + "▁sy nc", + "▁syn c", + "▁ sync", + "wi ch", + "w ich", + "▁anc est", + "ъ т", + "om o", + "o mo", + "▁I de", + "▁Id e", + "▁g ained", + "▁gain ed", + "▁ga ined", + "▁moment um", + "▁K o", + "ie u", + "i eu", + "ie lt", + "iel t", + "i elt", + "▁bon us", + "▁te xture", + "▁text ure", + "▁ texture", + "Mod al", + "Mo dal", + "NE XT", + "N EXT", + "▁годи не", + "▁l anguages", + "▁language s", + "v t", + "▁represent ing", + "▁D ream", + "▁Dre am", + "cur r", + "cu rr", + "qu al", + "q ual", + "▁j s", + "▁ js", + "bu rn", + "bur n", + "b urn", + "▁contribut ions", + "▁contribution s", + "▁r ic", + "▁ri c", + "▁ ric", + "}- \\", + "} -\\", + "={ {", + "= {{", + "ca rt", + "car t", + "c art", + "F B", + "ju d", + "j ud", + "es p", + "e sp", + "▁elect ron", + "▁electro n", + "▁e ll", + "▁el l", + "▁ ell", + "▁Run time", + "▁ Runtime", + "ac hel", + "ach el", + "ache l", + "a chel", + "\\ _", + "we ek", + "pack et", + "p acket", + "▁Secret ary", + "▁Jahr hund", + "▁th reshold", + "▁ threshold", + "ba ge", + "bag e", + "b age", + "▁con cer", + "▁conc er", + "▁conce r", + "▁b one", + "▁bo ne", + "▁bon e", + "▁ bone", + "▁Holly wood", + "Cur sor", + "C ursor", + "▁aw arded", + "▁award ed", + "▁sum mary", + "▁summar y", + "▁ summary", + "ag gio", + "agg io", + "aggi o", + "▁st ell", + "▁ste ll", + "▁ stell", + "▁f lesh", + "▁fl esh", + "▁fle sh", + "P air", + "▁A ge", + "▁Ag e", + "ing ton", + "▁' .", + "▁ '.", + "as er", + "ase r", + "a ser", + "ко ва", + "ков а", + "▁qu art", + "▁q uart", + "▁quar t", + "ry ption", + "rypt ion", + "All oc", + "Al loc", + "ft en", + "fte n", + "f ten", + "Oper and", + "▁ind icated", + "▁indic ated", + "▁indicate d", + "($ _", + "( $_", + "get String", + "▁list ener", + "▁listen er", + "▁ listener", + "sp ir", + "spi r", + ") _", + "ve ns", + "ven s", + "v ens", + "▁food s", + "▁foo ds", + "an za", + "anz a", + "te il", + "DE SC", + "▁n otion", + "▁not ion", + "▁em ployment", + "▁employ ment", + "▁s wing", + "▁sw ing", + "▁ swing", + "nb sp", + "▁p ounds", + "▁pound s", + "to ols", + "tool s", + "too ls", + "t ools", + "▁particip ate", + "▁T ax", + "▁Ta x", + "▁ Tax", + "▁с кла", + "ap ol", + "a pol", + "▁f ost", + "▁fo st", + "▁fos t", + "com pat", + "comp at", + "▁public ation", + "▁rapid ly", + "▁W is", + "▁Wi s", + "Event Listener", + "▁prem ière", + "▁premi ère", + "us o", + "u so", + "ext end", + "▁M ERCHANTABILITY", + "UT F", + "U TF", + "▁exper iments", + "▁experi ments", + "▁experiment s", + "sin gle", + "sing le", + "s ingle", + "z k", + "▁n aj", + "▁na j", + "}} }", + "} }}", + "Li n", + "L in", + "▁inter act", + "▁inte ract", + "▁c ms", + "▁cm s", + "▁Ro ger", + "▁Rog er", + "▁Р у", + "> '", + "com mit", + "comm it", + "ло сь", + "▁out come", + "▁h its", + "▁hit s", + "▁hi ts", + "▁и м", + "▁ им", + "▁s park", + "▁sp ark", + "con sole", + "cons ole", + "▁ver w", + "▁ve rw", + "▁ка то", + "agnost ics", + "agnostic s", + "▁s oci", + "▁so ci", + "▁soc i", + "▁d ining", + "▁di ning", + "▁din ing", + "▁t ech", + "▁te ch", + "▁ tech", + "š t", + "fo lio", + "fol io", + "ult ane", + "ultan e", + "кт ор", + "кто р", + "к тор", + "▁B rand", + "▁Br and", + "▁Bra nd", + "Jo in", + "J oin", + "▁и ю", + "▁p ros", + "▁pro s", + "▁pr os", + "▁pos it", + "Pub lic", + "P ublic", + "AspNet Core", + "▁S hop", + "▁Sh op", + "▁ Shop", + "▁co inc", + "▁coin c", + "ни ем", + "ние м", + "▁re ferences", + "▁refer ences", + "▁reference s", + "ab out", + "name space", + "names pace", + "D L", + "▁I R", + "▁ IR", + "▁c ada", + "▁ca da", + "▁cad a", + "▁Jord an", + "▁g ep", + "▁ge p", + "▁b ron", + "▁br on", + "▁bro n", + "andid ate", + "EX PECT", + "EXP ECT", + "am o", + "a mo", + "▁De utsch", + "au c", + "a uc", + "▁ра йо", + "▁рай о", + "▁L abor", + "▁La bor", + "▁Lab or", + "▁surround ed", + "т ро", + "▁n ome", + "▁no me", + "▁nom e", + "▁under lying", + "▁educ ational", + "▁education al", + "R IGHT", + "CO UNT", + "in ch", + "inc h", + "Ty p", + "T yp", + "um ph", + "ump h", + "fo ur", + "f our", + "Control s", + "▁c p", + "▁ cp", + "co st", + "cos t", + "c ost", + "▁mechan ism", + "en ess", + "ene ss", + "enes s", + "e ness", + "é qu", + "▁acqu ired", + "▁acquire d", + "▁f alls", + "▁fall s", + "▁fal ls", + "▁ falls", + "▁H ou", + "▁Ho u", + "▁L E", + "▁ LE", + "for Each", + "▁ver tex", + "▁vert ex", + "▁ vertex", + "▁I F", + "▁ IF", + "cur s", + "cu rs", + "c urs", + "' =>", + "те ри", + "тер и", + "▁S A", + "▁ SA", + "ri ers", + "rie rs", + "rier s", + "r iers", + "▁u w", + "▁ uw", + "▁m arks", + "▁mark s", + "▁mar ks", + "▁ marks", + "▁en erg", + "▁ener g", + "ho f", + "h of", + "ylv ania", + "▁Al len", + "▁All en", + "um py", + "ump y", + "о го", + "ст ву", + "ств у", + "vo ice", + "v oice", + "▁en gage", + "▁eng age", + "▁m ant", + "▁man t", + "▁ma nt", + "or se", + "ors e", + "== =", + "= ==", + "▁impro vement", + "▁improve ment", + "Op t", + "O pt", + "▁arr ested", + "▁arrest ed", + "ти я", + "▁с ле", + "▁ сле", + "it ched", + "itch ed", + "soc ket", + "sock et", + "s ocket", + "▁c ycl", + "▁cy cl", + "▁ cycl", + "▁S M", + "▁ SM", + "▁S ex", + "▁Se x", + "▁neut ral", + "▁neutr al", + "ва в", + "▁J ess", + "▁Je ss", + "▁Jes s", + "▁d ip", + "▁di p", + "▁op position", + "▁oppos ition", + "▁b orrow", + "▁bor row", + "с пе", + "▁av ant", + "ко ла", + "▁t a", + "▁ ta", + "An im", + "A nim", + "▁G all", + "▁Gal l", + "▁Ga ll", + "rg b", + "r gb", + "▁gu ilty", + "▁guilt y", + "▁bu ried", + "▁bur ied", + "▁g y", + "▁ gy", + "Init ial", + "▁acc omp", + "▁ac comp", + "▁accom p", + "▁breath ing", + "▁breat hing", + "ber ry", + "b erry", + "GR O", + "G RO", + "▁subsequ ent", + "rou pe", + "roup e", + "ul pt", + "ulp t", + "t b", + "▁ ä", + "P i", + "arg v", + "▁M ust", + "▁Mus t", + "▁Mu st", + "▁ Must", + ": '", + "sv g", + "ou p", + "o up", + "▁prec isely", + "▁precise ly", + "▁T a", + "re na", + "ren a", + "r ena", + "▁f older", + "▁fol der", + "▁fold er", + "▁ folder", + "▁Ch annel", + "▁ Channel", + "▁re vol", + "▁rev ol", + "M iss", + "ло м", + "red dit", + "adel ph", + "▁dis crim", + "▁disc rim", + "▁a ve", + "▁av e", + "▁ ave", + "pl eted", + "ple ted", + "plete d", + "plet ed", + "p leted", + "▁g ently", + "▁gent ly", + "FF FF", + "ro py", + "rop y", + "r opy", + "▁d ial", + "▁di al", + "▁dia l", + "Not Found", + "▁\" [", + "Hom e", + "H ome", + "on te", + "ont e", + "o nte", + "▁re lie", + "▁rel ie", + "▁reli e", + "▁Con text", + "▁Cont ext", + "▁ Context", + "▁st ats", + "▁stat s", + "▁sta ts", + "▁ stats", + "▁E nergy", + "oun ced", + "ounce d", + "▁gr ave", + "▁grav e", + "▁gra ve", + "▁re cip", + "▁rec ip", + "ли н", + "л ин", + "bl og", + "blo g", + "b log", + "▁na am", + "▁w o", + "▁ wo", + "▁direct ions", + "▁dire ctions", + "▁direction s", + "▁Lin coln", + "! )", + "un ci", + "unc i", + "ne q", + "n eq", + "Tag s", + "T ags", + "▁t um", + "▁tu m", + "▁s aving", + "▁sa ving", + "▁sav ing", + "ail le", + "ai lle", + "a ille", + "item ize", + "▁F amil", + "▁Fa mil", + "ms m", + "m sm", + "ne ws", + "new s", + "FF ER", + "F FER", + "▁D ead", + "▁De ad", + "▁ Dead", + "▁terr itory", + "▁territor y", + "▁territo ry", + "▁K at", + "▁Ka t", + "oc ker", + "ock er", + "o cker", + "in teger", + "inte ger", + "▁s ne", + "▁sn e", + "▁f ails", + "▁fa ils", + "▁fail s", + "▁franç ais", + "▁int roduction", + "▁introdu ction", + "▁G rant", + "▁Gr ant", + "▁Gran t", + "▁Gra nt", + "ycl e", + "yc le", + "y cle", + "'] .", + "' ].", + "▁v ier", + "▁vi er", + "▁vie r", + "▁ vier", + "nat ive", + "n ative", + "▁K le", + "▁Kl e", + "qu ote", + "quot e", + "User s", + "Us ers", + "Use rs", + "▁ad vis", + "▁adv is", + "▁g ym", + "▁gy m", + "▁prote in", + "ا ل", + "▁M ai", + "▁Ma i", + "▁prov iders", + "▁provide rs", + "▁provider s", + "▁so il", + "gu i", + "g ui", + "▁N ation", + "▁Nat ion", + "re ation", + "reat ion", + "▁T ab", + "▁Ta b", + "▁ Tab", + "en sis", + "ens is", + "in as", + "ina s", + "i nas", + "▁Scot land", + "▁dis patch", + "▁disp atch", + "▁ dispatch", + "un ion", + "uni on", + "▁b ere", + "▁be re", + "▁ber e", + "▁ bere", + "▁P ow", + "▁Po w", + "▁H ig", + "▁Hi g", + "▁stud ying", + "▁study ing", + "RE F", + "R EF", + "SS L", + "S SL", + "▁f right", + "▁fr ight", + "▁S ORT", + "▁SO RT", + "▁com pr", + "▁comp r", + "▁Mad rid", + "row ned", + "rown ed", + "r owned", + "op es", + "ope s", + "o pes", + "pd ev", + "p dev", + "▁w ash", + "▁was h", + "▁wa sh", + "▁' ../../", + "▁'../ ../", + "}} _", + "} }_", + "▁acc um", + "rol ling", + "roll ing", + "▁N C", + "▁ NC", + "▁f iction", + "▁fi ction", + "▁fict ion", + "ip t", + "i pt", + "conne cted", + "connect ed", + "lim its", + "limit s", + "▁l ap", + "▁la p", + "▁ lap", + "▁where as", + "pro m", + "pr om", + "p rom", + "▁appoint ment", + "Pro gram", + "Pr ogram", + "▁П ер", + "▁Пе р", + "na h", + "n ah", + "Valid ation", + "ic ons", + "ico ns", + "icon s", + "i cons", + "äl l", + "ä ll", + "▁rad ical", + "▁radi cal", + "▁ex clusive", + "▁excl usive", + "▁exclus ive", + "em ony", + "emon y", + "▁challeng ing", + "▁m s", + "▁ ms", + "▁P rivate", + "▁Priv ate", + "▁ Private", + "▁v ida", + "▁vi da", + "▁vid a", + "▁дру ги", + "▁camp us", + "▁cam pus", + "form s", + "for ms", + "д но", + "pl aat", + "bs t", + "b st", + "AT ED", + "ATE D", + "▁Ab stract", + "▁Abs tract", + "▁ Abstract", + "▁int ense", + "▁intens e", + "▁L td", + "▁contro vers", + "ó g", + "▁s ă", + "▁land ing", + "▁lan ding", + "! =", + "▁sc enes", + "▁scene s", + "▁scen es", + "▁Ch ap", + "▁Cha p", + "▁sp oken", + "▁spoke n", + "▁spo ken", + "cre d", + "cr ed", + "c red", + "▁p ride", + "▁pr ide", + "▁pri de", + "qu et", + "que t", + "▁m eter", + "▁me ter", + "▁met er", + "▁de utsch", + "uu m", + "u um", + "▁b less", + "▁bl ess", + "▁ble ss", + "▁H ann", + "▁Ha nn", + "▁Han n", + "▁input s", + "▁ inputs", + "▁R ow", + "▁Ro w", + "▁ Row", + "▁with draw", + "▁withd raw", + "P al", + "ac les", + "acle s", + "acl es", + "a cles", + "as sets", + "ass ets", + "asse ts", + "asset s", + "▁v l", + "▁ vl", + "ве де", + "вед е", + "▁G ot", + "▁Go t", + "▁air port", + "win d", + "wi nd", + "w ind", + "▁Columb ia", + "▁ch ocolate", + "▁h ö", + "▁ hö", + "▁al arm", + "FT WARE", + "▁J ay", + "▁Ja y", + "▁s ake", + "▁sa ke", + "▁reg istration", + "▁registr ation", + "vi d", + "v id", + "▁l ake", + "▁la ke", + "▁user name", + "▁ username", + "▁h ack", + "▁ha ck", + "index Of", + "c x", + "▁f estival", + "▁fest ival", + "▁club s", + "case s", + "ca ses", + "cas es", + "c ases", + "CT RL", + "]; \r", + "] ;\r", + "▁A ud", + "▁Au d", + "▁ Aud", + "▁prim era", + "▁prime ra", + "▁primer a", + "ва т", + "в ат", + "▁brill iant", + "ut her", + "uth er", + "u ther", + "▁difficult y", + "it als", + "ital s", + "ita ls", + "▁sc ores", + "▁score s", + "▁pol ít", + "data base", + "dat abase", + "as ka", + "ask a", + "a ska", + "▁## ####", + "▁### ###", + "▁#### ##", + "▁##### #", + "▁a cid", + "▁ac id", + "at on", + "ato n", + "a ton", + "at omic", + "ato mic", + "atom ic", + "fr eq", + "fre q", + "f req", + "▁WARRAN TY", + "▁report ing", + ".) ,", + ". ),", + "▁n ights", + "▁night s", + "▁program me", + ")} {", + ") }{", + "xi c", + "x ic", + "▁s po", + "▁sp o", + "line d", + "li ned", + "lin ed", + "l ined", + "qu arters", + "er ee", + "ere e", + "e ree", + "mer s", + "me rs", + "m ers", + "▁s erves", + "▁ser ves", + "▁serv es", + "▁serve s", + "co w", + "c ow", + "ль ко", + "en so", + "ens o", + "▁env iron", + "▁ environ", + "Li ke", + "L ike", + "an che", + "anc he", + "anch e", + "▁cr ash", + "▁K ap", + "▁Ka p", + "no indent", + "Con n", + "Co nn", + "▁ав то", + "▁in frastructure", + "IM E", + "I ME", + "▁R oom", + "▁Ro om", + "▁ Room", + "ne ed", + "n eed", + "or er", + "ore r", + "o rer", + "▁D est", + "▁De st", + "▁Des t", + "▁ Dest", + "▁D omin", + "▁Do min", + "▁Dom in", + "ather ine", + "▁Syd ney", + "▁g auge", + "▁gau ge", + "▁ga uge", + "▁j et", + "▁je t", + "▁ jet", + "b ably", + "▁comm only", + "▁common ly", + "▁st ations", + "▁stat ions", + "▁station s", + "ia h", + "i ah", + "n l", + "ж у", + "et en", + "ete n", + "e ten", + "_ )", + "ia c", + "i ac", + "am os", + "amo s", + "a mos", + "ne ment", + "nem ent", + "n ement", + "ko n", + "k on", + "Inter val", + "▁cab in", + "▁ca bin", + "▁e g", + "▁ eg", + "▁sh ots", + "▁shot s", + "▁ shots", + "▁A rea", + "▁Ar ea", + "▁Are a", + "▁ Area", + "sm ith", + "param eter", + "' }", + "▁h em", + "▁he m", + "▁ hem", + "▁s inging", + "▁sing ing", + "▁sin ging", + "▁access ible", + "▁P rin", + "▁Pr in", + "▁Pri n", + "opt ional", + "option al", + "an cial", + "anc ial", + "ancia l", + "sh ips", + "ship s", + "▁can vas", + "▁ canvas", + "sp e", + "s pe", + "▁address es", + "▁x ml", + "▁ xml", + "▁' \"", + "▁ '\"", + "▁k ar", + "▁ka r", + "▁ kar", + "ö ff", + "▁a ges", + "▁ag es", + "▁age s", + "▁ ages", + "ё р", + "zi ng", + "zin g", + "z ing", + "▁ö ver", + "▁C lean", + "▁Cle an", + "▁ Clean", + "▁Sil ver", + "▁о со", + "▁ос о", + "he alth", + "Al i", + "A li", + "▁t s", + "▁ ts", + "at ern", + "ate rn", + "ater n", + "a tern", + "▁cho osing", + "▁bur ned", + "▁burn ed", + "br id", + "b rid", + "ro oms", + "room s", + "öt t", + "ö tt", + "K ERN", + "▁d ish", + "▁dis h", + "▁di sh", + "S a", + "De tail", + "Det ail", + "▁H ind", + "▁Hi nd", + "▁D ans", + "▁Dan s", + "▁Da ns", + "i ę", + "▁J ahren", + "▁Jah ren", + "▁Jahr en", + "▁Jahre n", + "▁Ja hren", + "ext ension", + "al las", + "all as", + "alla s", + "▁B illy", + "▁Bill y", + "▁Bil ly", + "us ammen", + "it ud", + "itu d", + "ge on", + "geo n", + "Te mp", + "T emp", + "Le g", + "L eg", + "itt el", + "itte l", + "add le", + "▁mus cle", + "▁sc ared", + "▁scar ed", + "ss on", + "s son", + "▁de note", + "▁den ote", + "ie urs", + "ieu rs", + "ieur s", + "i eurs", + "▁o range", + "▁or ange", + "▁h ub", + "▁ hub", + "▁re b", + "▁r eb", + "▁ reb", + "ed i", + "e di", + "▁vo ices", + "▁voice s", + "F older", + "▁s uspend", + "▁sus pend", + "▁susp end", + "▁ suspend", + "▁He art", + "▁sc rap", + "▁scr ap", + "▁a ggreg", + "▁ag greg", + "▁Gu ide", + "trans action", + "▁r iding", + "▁ri ding", + "▁rid ing", + "▁v á", + "▁ vá", + "▁b reed", + "▁br eed", + "▁bre ed", + "▁bree d", + "▁con cert", + "▁conc ert", + "▁conce rt", + "▁concer t", + "appro x", + "▁ch ances", + "▁chance s", + "To k", + "T ok", + "E q", + "par ts", + "part s", + "p arts", + "▁sch olar", + "▁schol ar", + "of fs", + "off s", + "fl ush", + "flu sh", + "! ”", + "▁lo gin", + "▁log in", + "▁ login", + "▁so ort", + "▁M and", + "▁Man d", + "▁Ma nd", + "▁function al", + "▁B ou", + "▁Bo u", + "▁subject s", + "my s", + "m ys", + "▁extra ord", + "▁Build ing", + "ik t", + "i kt", + "B ad", + "ia mi", + "iam i", + "i ami", + "Dr iver", + "D river", + "êt e", + "ê te", + "▁k v", + "▁ kv", + "▁t imer", + "▁time r", + "▁tim er", + "▁ti mer", + "▁ timer", + "ition ally", + "itional ly", + "▁a thlet", + "▁ath let", + "▁\" );", + "▁\") ;", + "▁ \");", + "w y", + "CF G", + "▁he aven", + "▁heav en", + "о в", + "▁exper imental", + "▁experiment al", + "▁b ounds", + "▁bound s", + "▁ bounds", + "IC K", + "I CK", + "▁ex cit", + "▁exc it", + "▁qu it", + "▁qui t", + "▁q uit", + "▁univers al", + "д ь", + "▁S P", + "▁ SP", + "▁st ub", + "▁ stub", + "▁k le", + "▁kl e", + "▁ kle", + "▁B art", + "▁Bar t", + "▁Ba rt", + "▁\" @", + "pe l", + "p el", + "▁( !(", + "▁(! (", + "▁se lector", + "▁select or", + "▁sel ector", + "▁sele ctor", + "▁ selector", + "E B", + "▁c oc", + "▁co c", + "et ed", + "ete d", + "e ted", + "ют ь", + "ю ть", + "▁poss ess", + "▁R ick", + "▁Ric k", + "▁unus ual", + "ter min", + "term in", + "▁b ags", + "▁bag s", + "▁ba gs", + "▁lo ading", + "▁load ing", + "▁ loading", + "▁t f", + "▁ tf", + "▁) \r", + "▁ )\r", + "pro vider", + "prov ider", + "plet ion", + "▁c ursor", + "▁cur sor", + "▁ cursor", + "▁pa used", + "▁paus ed", + "▁pause d", + "и м", + "▁coun sel", + "] <", + "ze ch", + "zec h", + "z ech", + "▁t ie", + "▁ti e", + "▁M oon", + "▁Mo on", + "▁ar med", + "▁arm ed", + "▁ armed", + "▁ob serve", + "▁observ e", + "▁obs erve", + "▁per met", + "▁perm et", + "▁J ob", + "▁Jo b", + "▁ Job", + "fö r", + "f ör", + "arg ument", + "▁egg s", + "▁eg gs", + "ás t", + "á st", + "▁incred ibly", + "wer ken", + "werk en", + "iz ard", + "izar d", + "iza rd", + "▁p ainted", + "▁pain ted", + "▁pa inted", + "▁paint ed", + "▁Viet nam", + "▁vi olent", + "▁viol ent", + "Es t", + "E st", + "ier ra", + "i erra", + "re ader", + "read er", + "rea der", + "we ise", + "wei se", + "▁J osh", + "▁Jo sh", + "▁Jos h", + "▁H im", + "▁Hi m", + "as hes", + "ash es", + "or igin", + "orig in", + "ori gin", + "▁sp ir", + "▁ spir", + "▁T ree", + "▁Tr ee", + "▁Tre e", + "▁ Tree", + "▁n iet", + "▁nie t", + "▁ni et", + "WI N", + "W IN", + "mar gin", + "m argin", + "▁inv olves", + "▁invol ves", + "▁involve s", + "▁organ is", + "▁N acional", + "bar a", + "ba ra", + "b ara", + "▁de puis", + "▁dep uis", + "pi o", + "p io", + "fe atures", + "feature s", + "feat ures", + "st ru", + "str u", + "▁Dis ney", + "▁restaur ants", + "▁restaurant s", + "Mil l", + "M ill", + ")) \r", + ") )\r", + "с ла", + "rem ote", + "▁Th ird", + "▁base ball", + "▁al gun", + "▁alg un", + "] $", + "▁em ployed", + "▁employ ed", + "po t", + "p ot", + "▁Un ityEngine", + "▁ UnityEngine", + "▁integr ation", + "▁risk s", + "▁ris ks", + "▁st ro", + "▁str o", + "▁ag osto", + "▁ago sto", + "incl uding", + "▁M ind", + "▁Min d", + "▁Mi nd", + "▁st roke", + "▁str oke", + "▁stro ke", + "▁ stroke", + "▁de als", + "▁deal s", + "aj ax", + "aja x", + "a jax", + "ё т", + "▁\\ |", + "▁ \\|", + "ta r", + "t ar", + "adelph ia", + "▁s ab", + "▁sa b", + "pu r", + "p ur", + "▁sc rew", + "▁scr ew", + "▁in ev", + "▁\\ ;", + "▁Don ald", + "▁ Donald", + "ö d", + "cc a", + "c ca", + "es is", + "esi s", + "e sis", + "▁separ ated", + "▁separate d", + "DB G", + "D BG", + "ag ent", + "age nt", + "agen t", + "a gent", + "▁p acked", + "▁pack ed", + "▁pac ked", + "▁ packed", + "н ня", + "in tern", + "int ern", + "inter n", + "inte rn", + "▁M onte", + "▁Mon te", + "▁Mont e", + "▁Mo nte", + "▁prov ince", + "▁provinc e", + "▁provin ce", + "▁exp anded", + "▁expand ed", + "▁appro ached", + "▁approach ed", + "▁E p", + "CL K", + "▁o re", + "▁or e", + "▁ ore", + "B atch", + "▁impress ive", + "R M", + "▁L ocation", + "▁Loc ation", + "▁ Location", + "▁sh ame", + "▁sha me", + "wrap per", + "w rapper", + "un wrap", + "pe er", + "Bit s", + "Bi ts", + "B its", + "▁S N", + "▁ SN", + "sc ar", + "s car", + "Com e", + "Co me", + "C ome", + "▁coun cil", + "▁shout ed", + "ma king", + "m aking", + "▁M aur", + "▁Ma ur", + "▁Mau r", + "▁w is", + "LE TE", + "LET E", + "▁f s", + "▁ fs", + "▁d z", + "▁ dz", + "un que", + "ue go", + "u ego", + "R andom", + "H tml", + "ze m", + "z em", + "▁D utch", + "▁Gold en", + "▁Gol den", + "▁T ar", + "▁Ta r", + "▁H erm", + "▁He rm", + "▁Her m", + "▁str etch", + "▁stret ch", + "var d", + "va rd", + "v ard", + "▁t ries", + "▁tr ies", + "▁tri es", + "W I", + "▁disappe ared", + "▁disappear ed", + "▁cr usher", + "▁crush er", + "▁K an", + "▁Ka n", + "Ma g", + "M ag", + "ø r", + "▁Cam bridge", + "▁Camb ridge", + "▁do po", + "▁dop o", + "at ura", + "atur a", + "atu ra", + "he art", + "▁Sp iel", + "/* *\r", + "/** \r", + "Dir ection", + "Direct ion", + "Di rection", + "D irection", + "at ting", + "att ing", + "atti ng", + "wi g", + "w ig", + "▁c odes", + "▁co des", + "▁code s", + "▁cod es", + "▁ codes", + "▁pow der", + "al ert", + "ale rt", + "aler t", + "sem bl", + "semb l", + "▁y e", + "▁ ye", + "St ar", + "S tar", + "▁ro ots", + "▁root s", + "▁H oll", + "▁Hol l", + "▁Ho ll", + "Re le", + "Rel e", + "R ele", + "▁const itu", + "n c", + "“ .", + "re ference", + "refer ence", + "if icial", + "ific ial", + "ifi cial", + "clos ure", + "▁fig ured", + "▁figure d", + "▁assum ption", + "getElement ById", + "▁A G", + "▁ AG", + "os es", + "ose s", + "o ses", + "▁_ \"", + "ep per", + "ob re", + "o bre", + "en umerate", + "о графи", + "▁less ons", + "▁lesson s", + "▁qual ified", + "Per son", + "Pers on", + "P erson", + "an se", + "ans e", + "▁M ort", + "▁Mor t", + "▁Mo rt", + "s ylvania", + "▁c ré", + "▁cr é", + "Bind ing", + "Bin ding", + "B inding", + "і с", + "▁V ari", + "▁Var i", + "▁Va ri", + "▁ Vari", + "▁re minded", + "▁remind ed", + "▁members hip", + "▁member ship", + "ip er", + "ipe r", + "i per", + "zt e", + "z te", + "▁c ref", + "▁cre f", + "▁cr ef", + "▁ cref", + "▁P A", + "▁ PA", + "plaat st", + "▁Env ironment", + "▁ Environment", + "bo y", + "b oy", + "▁ph rase", + "▁phr ase", + "▁ phrase", + "riv ial", + "ra g", + "r ag", + "во ди", + "вод и", + "▁p se", + "▁ps e", + "▁ pse", + "▁tour nament", + ")} ,", + ") },", + "▁S ound", + "▁So und", + "▁Sou nd", + "▁ Sound", + "▁V el", + "▁Ve l", + "▁ Vel", + "▁B erg", + "▁Be rg", + "▁Ber g", + "el son", + "els on", + "▁ref uge", + "▁else where", + "qu ality", + "qual ity", + "▁abandon ed", + "▁F lo", + "▁Fl o", + "ib il", + "i bil", + "UA L", + "U AL", + "▁Pl atz", + "▁d elta", + "▁del ta", + "▁ delta", + "▁B uy", + "▁Bu y", + "ri ère", + "r ière", + "▁fl our", + "▁flo ur", + "▁laugh ing", + "▁laug hing", + "▁Look ing", + "▁Lo oking", + "Ag ent", + "A gent", + "▁w x", + "▁ wx", + "▁W ales", + "▁Wal es", + "▁Wa les", + "C tx", + "▁c ake", + "▁ca ke", + "▁c rate", + "▁cr ate", + "▁ crate", + "▁к ла", + "▁ кла", + "an ga", + "ang a", + "Z ero", + "▁amount s", + "Tr a", + "T ra", + "om etric", + "omet ric", + "o metric", + "▁con straints", + "▁constr aints", + "▁constraint s", + "▁tem ple", + "▁templ e", + "▁temp le", + "▁install ation", + "st roke", + "str oke", + "▁N eder", + "▁Ne der", + "▁Ned er", + "ț i", + "▁I bid", + "▁o bs", + "▁ob s", + "▁ obs", + "ent ries", + "entr ies", + "▁j usqu", + "OR M", + "O RM", + "▁S ky", + "▁Sk y", + "ik es", + "ike s", + "i kes", + "na k", + "n ak", + "▁m odes", + "▁mod es", + "▁mo des", + "▁mode s", + "▁Hit ler", + "▁b elt", + "▁be lt", + "▁bel t", + "▁point ing", + "▁B an", + "▁Ba n", + "ign ore", + "▁per su", + "▁pers u", + "▁Bes ides", + "yn om", + "y nom", + "▁leg is", + "▁C PU", + "▁CP U", + "▁ CPU", + "an ded", + "and ed", + "ande d", + "ui s", + "u is", + "bs ite", + "b site", + "▁E uro", + "▁Eu ro", + "▁ut ter", + "▁ utter", + "e clipse", + "▁ir re", + "▁irr e", + "▁D ocument", + "▁Doc ument", + "▁ Document", + "▁Mean while", + "▁famil ie", + "ver ify", + "▁J ason", + "▁Ja son", + "▁O rt", + "▁Or t", + "▁ci udad", + "▁techn ologies", + "▁ча сти", + "▁част и", + "▁час ти", + "ni ca", + "nic a", + "n ica", + "can cel", + "c ancel", + "V irtual", + "▁ev ident", + "am an", + "ama n", + "a man", + "▁Sup reme", + "at oes", + "ato es", + "▁ste ady", + "▁stead y", + "▁month ly", + "▁SO FTWARE", + "Di e", + "D ie", + "▁app lying", + "▁apply ing", + "▁appl ying", + "Di g", + "D ig", + "vi er", + "v ier", + "▁го ро", + "▁W H", + "▁ WH", + "▁min ds", + "▁mind s", + "▁k am", + "▁ka m", + "▁expert ise", + "▁not ification", + "▁ notification", + ". -", + "▁del iber", + "▁H E", + "▁ HE", + "▁res ist", + "ou tes", + "out es", + "oute s", + "o utes", + "▁How ard", + "▁Ho ward", + "spec ial", + "spe cial", + "▁p resentation", + "▁present ation", + "▁You Tube", + "mi r", + "m ir", + "▁r ust", + "▁ru st", + "▁rus t", + "▁ rust", + "▁n ations", + "▁nat ions", + "▁nation s", + "▁G ets", + "▁Ge ts", + "▁Get s", + "▁respon ses", + "▁response s", + "▁respons es", + "ar ded", + "ard ed", + "arde d", + "im mer", + "imm er", + "▁reve al", + "▁M eg", + "▁Me g", + "▁tod os", + "▁todo s", + "▁a de", + "▁ad e", + "▁ ade", + "ateg ories", + "ategor ies", + "▁pay ments", + "▁payment s", + "ô t", + "En umer", + "Enum er", + "E numer", + "▁platform s", + "▁plat forms", + "▁life time", + "▁lif etime", + "Com plete", + "Comp lete", + "Qu est", + "Que st", + "Q uest", + "en ders", + "end ers", + "ender s", + "ende rs", + "▁c um", + "▁cu m", + "pl er", + "ple r", + "p ler", + "▁app l", + "▁ap pl", + "äh rend", + "ähr end", + "з ь", + "en ez", + "ene z", + "e nez", + "over ty", + "yn chron", + "▁arg ued", + "▁argue d", + "▁K ath", + "▁Kat h", + "▁Ka th", + "▁s ynchron", + "▁syn chron", + "▁B uilder", + "▁Build er", + "▁ Builder", + "B order", + "Pl an", + "P lan", + "ri eb", + "rie b", + "r ieb", + "n m", + "FOR MAT", + "FORM AT", + "us k", + "u sk", + "▁j umped", + "▁jump ed", + "ch arg", + "char g", + "cha rg", + "▁cont ribute", + "▁contribut e", + "Me sh", + "M esh", + "Un ivers", + "re ll", + "rel l", + "r ell", + "▁p olar", + "▁pol ar", + "▁po lar", + "▁tr ois", + "▁tro is", + "ic io", + "ici o", + "i cio", + "Group s", + "G roups", + "▁( %", + "▁ (%", + "Lo op", + "L oop", + "▁g az", + "▁ga z", + "db g", + "d bg", + "LA Y", + "L AY", + "Jo hn", + "J ohn", + "bl ocks", + "block s", + "blo cks", + "▁l ung", + "▁lu ng", + "▁lun g", + "▁ lung", + "▁k ön", + "▁kö n", + "th rough", + "▁fif th", + "lish er", + "l isher", + "▁inv olving", + "▁invol ving", + "▁De ep", + "▁ Deep", + "▁обла сти", + "▁s ull", + "▁su ll", + "▁sul l", + "Ex port", + "Exp ort", + "▁K ate", + "▁Kat e", + "▁Ka te", + "per iod", + "ch arge", + "char ge", + "charg e", + "G T", + "\"> \r", + "\" >\r", + "ти н", + "т ин", + "▁O tt", + "▁Ot t", + "▁inter actions", + "▁interaction s", + "▁interact ions", + "▁Tor onto", + "TR ACE", + "TRA CE", + "▁d ifer", + "▁di fer", + "▁dif er", + "▁lib eral", + "▁liber al", + "▁p article", + "▁part icle", + "▁partic le", + "▁parti cle", + "▁sur ve", + "▁surv e", + "al ous", + "alo us", + "re ason", + "rea son", + "▁de pression", + "▁dep ression", + "▁depress ion", + "а л", + "▁f lower", + "▁fl ower", + "▁flo wer", + "▁flow er", + "▁wa ar", + "▁h ade", + "▁had e", + "▁ha de", + "▁cent uries", + "ut y", + "u ty", + "par ty", + "part y", + "▁appro val", + "gener ate", + "▁B arn", + "▁Bar n", + "▁Ba rn", + "▁m arg", + "▁mar g", + "▁ma rg", + "▁m onde", + "▁mon de", + "▁mo nde", + "▁mond e", + "▁o ok", + "▁ ook", + "▁Cl ark", + "▁Clar k", + "▁the oret", + "vious ly", + "vi ously", + "v iously", + "? )", + "▁R ud", + "▁Ru d", + "st mt", + "in ction", + "inct ion", + "▁t un", + "▁tu n", + "▁ro ads", + "▁road s", + "▁rot ation", + "▁ rotation", + "pp en", + "ppe n", + "p pen", + "sen sor", + "s ensor", + "▁K ol", + "▁Ko l", + "id elines", + "ide lines", + "idel ines", + "▁ є", + "▁com posed", + "▁comp osed", + "▁compos ed", + "▁v irus", + "▁vi rus", + "▁vir us", + "' $", + "S N", + "▁V on", + "▁Vo n", + "mon t", + "mo nt", + "m ont", + "la r", + "l ar", + "▁opin ions", + "▁opinion s", + "uct ion", + "u ction", + "ru pal", + "rup al", + "under line", + "▁hor ror", + "Mus t", + "Mu st", + "M ust", + "ot to", + "ott o", + "o tto", + "Sh ould", + "▁stat ist", + "▁g em", + "▁ge m", + "▁ gem", + "▁se cre", + "▁sec re", + "▁st rip", + "▁str ip", + "▁stri p", + "▁ strip", + "▁d irt", + "▁di rt", + "▁dir t", + "ama zon", + "amaz on", + "▁R ound", + "▁Ro und", + "▁Rou nd", + "▁ Round", + "▁dis covery", + "▁disc overy", + "▁discover y", + "▁disco very", + "▁G O", + "▁ GO", + "▁substant ial", + "ib t", + "i bt", + "▁dem ands", + "▁demand s", + "▁every day", + "▁b esch", + "▁be sch", + "▁bes ch", + "▁B ridge", + "▁Br idge", + "▁H D", + "▁ HD", + "▁D ol", + "▁Do l", + "▁t rès", + "▁tr ès", + "an ni", + "ann i", + "ro it", + "() );\r", + "()); \r", + "()) ;\r", + "( ));\r", + "fa r", + "f ar", + "tim estamp", + "▁bul k", + "Bl ack", + "▁g an", + "▁ga n", + "▁ gan", + "set ting", + "ret val", + "ва не", + "ван е", + "nu ng", + "n ung", + "▁talk s", + "▁tal ks", + "▁scient ists", + "▁scientist s", + "▁v ig", + "▁vi g", + "▁quant ity", + "▁G ard", + "▁Gar d", + "▁Ga rd", + "▁mov ements", + "▁move ments", + "▁movement s", + "äh r", + "ä hr", + "ling s", + "lin gs", + "l ings", + "▁Т е", + "te am", + "ri to", + "rit o", + "r ito", + "▁as sembly", + "▁ assembly", + "il st", + "ils t", + "i lst", + "▁happ iness", + "▁le af", + "▁ leaf", + "▁ass essment", + "▁assess ment", + "Co ord", + "ir s", + "i rs", + "sa m", + "s am", + "▁att orney", + "▁g eme", + "▁ge me", + "▁gem e", + "▁ geme", + "ID E", + "I DE", + "▁V ere", + "▁Ver e", + "▁Ve re", + "▁Anth ony", + "am iento", + "ami ento", + "▁A st", + "▁As t", + "▁cir cul", + "▁circ ul", + "▁Fr ances", + "▁Franc es", + "▁France s", + "▁Fran ces", + "▁p ent", + "▁pe nt", + "▁pen t", + "▁ pent", + "▁m ate", + "▁mat e", + "▁ma te", + "▁ mate", + "▁Trans port", + "▁ Transport", + "ow o", + "o wo", + "ч у", + "is tes", + "ist es", + "iste s", + "TR AN", + "TRA N", + "T RAN", + "IM PORT", + "IMP ORT", + "▁B reak", + "▁Bre ak", + "▁ Break", + "▁s ons", + "▁so ns", + "▁son s", + "▁invest ors", + "▁Phil ipp", + "▁Philip p", + "TH OD", + "▁pan ic", + "▁pa nic", + "▁ panic", + "▁: )", + "▁d etection", + "▁det ection", + "▁detect ion", + "▁sim ultane", + "nt e", + "n te", + "▁list ened", + "▁listen ed", + "к ре", + "▁B rig", + "▁Br ig", + "Option al", + "Opt ional", + "▁a bund", + "▁ab und", + "▁c riteria", + "▁crit eria", + "▁c hip", + "▁ch ip", + "▁chi p", + "▁ chip", + "▁ок ру", + "▁Con stant", + "▁Const ant", + "▁ Constant", + "▁m ining", + "▁min ing", + "▁mi ning", + "▁mini ng", + "та л", + "т ал", + "ma tes", + "mat es", + "mate s", + "m ates", + "▁w orship", + "▁wor ship", + "ro uter", + "rou ter", + "route r", + "r outer", + "C N", + "▁M atch", + "▁Mat ch", + "▁ Match", + "▁C ole", + "▁Col e", + "▁Co le", + "▁down t", + "▁dow nt", + "▁h oles", + "▁hol es", + "▁ho les", + "▁hole s", + "▁gr ateful", + "RES ULT", + "▁Europ a", + "▁Euro pa", + "▁con sent", + "▁cons ent", + "▁conse nt", + "l ä", + "op ter", + "opt er", + "▁colle agues", + "or ous", + "oro us", + "o rous", + "▁enem ies", + "ha ng", + "han g", + "h ang", + "act ual", + "Object s", + "▁я к", + "▁fl uid", + "▁flu id", + "fix ed", + "f ixed", + "▁G raph", + "▁Gr aph", + "▁Gra ph", + "▁ Graph", + "▁scr atch", + "ce rs", + "cer s", + "c ers", + "ri bu", + "rib u", + "▁valid ation", + "▁ validation", + "▁com pletion", + "▁complet ion", + "▁B egin", + "▁Be gin", + "▁Beg in", + "▁ Begin", + "end point", + "ri ent", + "rie nt", + "rien t", + "r ient", + "C M", + "▁S ite", + "▁Si te", + "▁ Site", + "▁expl ains", + "▁explain s", + "tr es", + "tre s", + "t res", + "▁any body", + "fo reach", + "fore ach", + "for each", + "lo n", + "l on", + "Ch ain", + "▁B uff", + "▁Bu ff", + "▁ Buff", + "oc al", + "oca l", + "o cal", + "▁M organ", + "▁Mor gan", + "▁s ang", + "▁sa ng", + "▁san g", + "▁pass es", + "▁pas ses", + "@ @", + "ij d", + "i jd", + "W ord", + "▁H ung", + "▁Hun g", + "▁Hu ng", + "▁F er", + "▁Fe r", + "▁v ý", + "ba st", + "bas t", + "b ast", + "▁enter tainment", + "▁entertain ment", + "hi n", + "h in", + "▁g rat", + "▁gr at", + "▁gra t", + "▁M ember", + "▁Me mber", + "▁Mem ber", + "▁ Member", + "▁M inn", + "▁Min n", + "▁Mi nn", + "▁pr inted", + "▁print ed", + "▁prin ted", + "▁Frank lin", + "▁I mp", + "▁Im p", + "▁ Imp", + "M achine", + "column s", + "▁de leted", + "▁del eted", + "▁delete d", + "▁delet ed", + "▁ deleted", + "▁manufact uring", + "▁re ly", + "▁r ely", + "▁rel y", + "▁con se", + "▁cons e", + "▁f ishing", + "▁fish ing", + "▁fis hing", + "bl o", + "b lo", + "- $", + "▁. \"", + "▁ .\"", + "▁clin ical", + "▁clinic al", + "▁Stud ies", + "▁Б у", + "def inition", + "▁evalu ation", + "▁eval uation", + "▁att acked", + "▁attack ed", + "▁fro zen", + "ze nt", + "zen t", + "z ent", + "▁ú lt", + "▁r ational", + "▁rat ional", + "▁ratio nal", + "ot he", + "oth e", + "o the", + "Can cel", + "C ancel", + "hi story", + "hist ory", + "set Text", + "▁a lc", + "▁al c", + "▁h ydro", + "▁hy dro", + "▁hyd ro", + "▁The atre", + "▁M aterial", + "▁Mat erial", + "▁ Material", + "IO Exception", + "**** **/", + "****** /", + "sp l", + "s pl", + "NO DE", + "att rs", + "attr s", + "▁m ie", + "▁mi e", + "▁off ices", + "▁offic es", + "▁office s", + "r ó", + "▁j am", + "▁ja m", + "▁Id ent", + "▁Ide nt", + "▁ Ident", + "v é", + "Set ting", + "▁Sever al", + "▁Sev eral", + "▁dec ay", + "And roid", + "▁S ave", + "▁Sa ve", + "▁Sav e", + "▁ Save", + "un ted", + "unt ed", + "unte d", + "▁Mount ain", + "us c", + "u sc", + "▁mar zo", + "▁a sleep", + "▁as leep", + "▁sold ier", + "▁D ouble", + "▁Dou ble", + "▁ Double", + "P K", + "▁cont rad", + "▁contr ad", + "▁contra d", + "▁w ins", + "▁win s", + "ce iver", + "ceive r", + "▁se asons", + "▁season s", + "▁seas ons", + "▁C hall", + "▁Ch all", + "▁Cha ll", + "▁health care", + "ła d", + "ł ad", + "о т", + "▁F ive", + "▁Fi ve", + "▁H ell", + "▁He ll", + "▁Hel l", + "▁world wide", + "▁' ,", + "▁ ',", + "я н", + "ma de", + "mad e", + "m ade", + "▁respon ded", + "▁respond ed", + "▁a y", + "▁ ay", + "▁proced ures", + "▁procedure s", + "те ра", + "тер а", + "▁cle ared", + "▁clear ed", + "\"] .", + "\" ].", + "▁T arget", + "▁Tar get", + "▁ Target", + "▁S ide", + "▁Si de", + "▁Sid e", + "▁ Side", + "om in", + "omi n", + "o min", + "▁de ploy", + "▁T ell", + "▁Te ll", + "▁Tel l", + "▁ Tell", + "▁on going", + "fl oor", + "f loor", + "▁b ones", + "▁bo nes", + "▁bon es", + "▁bone s", + "▁De lete", + "▁Del ete", + "▁ Delete", + "▁shru gged", + "O ur", + "De r", + "D er", + "▁init ialize", + "▁initial ize", + "▁ initialize", + "▁T ed", + "▁Te d", + "MA GE", + "MAG E", + "M AGE", + "▁h ire", + "▁hi re", + "▁ hire", + "▁tr acking", + "▁track ing", + "▁a sh", + "▁as h", + "▁ ash", + "▁ce iling", + "ка х", + "et ti", + "ett i", + "e tti", + "▁cour age", + "▁cou rage", + "ensch app", + "ют ся", + "ю тся", + "Mo re", + "M ore", + "▁fol g", + "▁fo lg", + "▁ folg", + "▁Gr ace", + "▁Gra ce", + "▁K elly", + "▁Kel ly", + "▁re ven", + "▁r even", + "▁rev en", + "▁reve n", + "▁A li", + "▁Al i", + "▁ Ali", + "▁d isp", + "▁dis p", + "▁di sp", + "▁ disp", + "▁de feat", + "▁defe at", + "▁cre ature", + "▁creat ure", + "▁Kenn edy", + "▁D iego", + "▁Die go", + "▁Di ego", + "EM P", + "E MP", + "▁s team", + "▁ste am", + "end ance", + "ri g", + "r ig", + "▁ign or", + "▁ig nor", + "em en", + "eme n", + "e men", + "▁G ru", + "▁Gr u", + "▁pro posal", + "▁propos al", + "▁we iter", + "▁weit er", + "▁ лі", + "ib les", + "ible s", + "i bles", + "▁consider ation", + "▁belie ves", + "▁believe s", + "▁S oph", + "▁So ph", + "“ ,", + "▁Matt hew", + "▁circ uit", + "▁s inger", + "▁sing er", + "▁sin ger", + "▁S quare", + "ç o", + "Ed ge", + "▁a str", + "▁as tr", + "▁ast r", + "▁ astr", + "▁represent ative", + "▁comprehens ive", + "li ga", + "lig a", + "l iga", + "▁m ere", + "▁me re", + "▁mer e", + "tb l", + "t bl", + "▁contin uing", + "▁continu ing", + "ograph er", + "ograp her", + "LE D", + "L ED", + "▁/* **/", + "▁/** */", + "▁s ear", + "▁se ar", + "▁sea r", + "▁enorm ous", + "iz i", + "i zi", + "Di t", + "D it", + "th ere", + "ther e", + "the re", + "t here", + "і н", + "си те", + "▁gu erra", + "▁end point", + "▁ endpoint", + "▁le sson", + "▁les son", + "▁less on", + "zo n", + "z on", + "var iable", + "vari able", + "и с", + "▁research ers", + "▁attempt ed", + "▁e nf", + "▁en f", + "ту ра", + "тур а", + "▁de fin", + "▁def in", + "ве ст", + "▁aw ful", + "▁lo west", + "▁low est", + "ru les", + "rule s", + "r ules", + "▁un like", + "inter val", + "▁produ cing", + "▁K am", + "▁Ka m", + "▁I MP", + "▁IM P", + "▁ IMP", + "Gener al", + "Gen eral", + "▁f aire", + "▁fa ire", + "▁fair e", + "▁max im", + "▁ma xim", + "as semb", + "ass emb", + "asse mb", + "assem b", + "ac ent", + "ace nt", + "a cent", + "? >", + "pl ica", + "plic a", + "p lica", + "▁r am", + "▁ra m", + "▁ ram", + "ma te", + "mat e", + "m ate", + "ц у", + "m n", + "▁H i", + "▁ Hi", + "▁st ages", + "▁stage s", + "▁stag es", + "▁sta ges", + "▁Ed itor", + "▁Edit or", + "▁ Editor", + "▁t ang", + "▁tan g", + "▁ta ng", + "R D", + "▁i ch", + "▁ic h", + "▁ ich", + "▁depend ent", + "▁dep endent", + "▁ dependent", + "li fer", + "life r", + "lif er", + "l ifer", + "as cript", + "asc ript", + "a script", + "▁expos ure", + "ре з", + "▁m art", + "▁mar t", + "▁ma rt", + "▁ mart", + "▁Bar cel", + "xs pace", + "x space", + "SE SSION", + "▁p rest", + "▁pre st", + "▁pr est", + "▁pres t", + "UR CE", + "- .", + "▁се ло", + "ha ve", + "hav e", + "h ave", + "▁observ ation", + "▁obs ervation", + "▁comm ands", + "▁command s", + "▁ commands", + "▁e ager", + "▁out door", + "▁DE BUG", + "▁ DEBUG", + "▁h r", + "▁ hr", + "A X", + "▁p uzz", + "▁pu zz", + "bl ank", + "бу р", + "б ур", + "▁k ennis", + "▁reg arded", + "▁regard ed", + "▁} ),", + "▁}) ,", + "▁ }),", + "vol ume", + "▁про из", + "▁Tr aining", + "▁Tra ining", + "▁Train ing", + "a ñ", + "▁f ois", + "▁foi s", + "▁fo is", + "▁т ри", + "▁ три", + "в ня", + "▁opt imal", + "▁optim al", + "▁sub scription", + "▁subs cription", + "▁ subscription", + "br idge", + "brid ge", + "b ridge", + "im ental", + "iment al", + "imen tal", + "▁Th ink", + "▁\" ;", + "▁ \";", + "▁leg isl", + "▁legis l", + "▁H op", + "▁Ho p", + "▁br anches", + "▁branch es", + "▁V eg", + "▁Ve g", + "▁s print", + "▁spr int", + "▁fl ux", + "▁flu x", + "▁Fr eder", + "▁Fre der", + "▁Fred er", + "si s", + "s is", + "not ify", + "▁Ф ран", + "so m", + "s om", + "ny m", + "n ym", + "▁R é", + "le tt", + "let t", + "l ett", + "ing ham", + "▁F arm", + "▁Far m", + "▁Fa rm", + "DO M", + "D OM", + "▁sh ield", + "He re", + "Her e", + "H ere", + "▁T reat", + "▁Tre at", + "▁Lu ke", + "▁un safe", + "an ton", + "ant on", + "anto n", + "▁Im per", + "▁Imp er", + "▁tele phone", + "▁un lock", + "▁ unlock", + "Own er", + "col lection", + "coll ection", + "collect ion", + "▁s nd", + "▁sn d", + "▁ snd", + "▁su iv", + "▁ent ering", + "▁enter ing", + "ше н", + "ш ен", + "▁L abel", + "▁La bel", + "▁Lab el", + "▁ Label", + "se lector", + "sel ector", + "select or", + "▁G ET", + "▁ GET", + "▁qu ando", + "▁quand o", + "▁f ed", + "▁fe d", + "▁ fed", + "j Query", + "Or igin", + "▁A lan", + "▁Al an", + "math scr", + "▁pregn ant", + "▁preg nant", + "Ex pect", + "Exp ect", + "re sources", + "res ources", + "resource s", + "▁er sten", + "▁erst en", + "▁ers ten", + "▁erste n", + "al ia", + "ali a", + "a lia", + "▁ret ired", + "▁retire d", + "û t", + "Cr ed", + "C red", + "▁m éd", + "▁mé d", + "▁e rh", + "▁er h", + "Frame work", + "Sl ot", + "S lot", + "d uration", + "sa l", + "s al", + "▁com position", + "▁compos ition", + "art icle", + "gp u", + "g pu", + "▁per mitted", + "▁perm itted", + "▁permit ted", + "▁F ont", + "▁Fo nt", + "▁ Font", + "▁M uch", + "▁Mu ch", + "▁p ending", + "▁pen ding", + "▁ pending", + "▁ag encies", + "Column s", + "▁k lik", + "▁kl ik", + "▁r ating", + "▁rat ing", + "▁ra ting", + "▁ rating", + "min d", + "mi nd", + "m ind", + "▁Penn sylvania", + "J ava", + "ab stract", + "abs tract", + "▁d umb", + "▁du mb", + "▁V I", + "▁ VI", + "us a", + "u sa", + "Rem ote", + "▁YO U", + "▁C reek", + "▁Cre ek", + "ма ти", + "мат и", + "Bot tom", + "B ottom", + "▁roll ing", + "▁ rolling", + "▁b undle", + "▁bund le", + "▁ bundle", + "▁g olf", + "▁gol f", + "gp io", + "g pio", + "▁Ch air", + "▁Cha ir", + "▁c ls", + "▁cl s", + "▁ cls", + "$ }", + "▁Par liament", + "f ühr", + "Man y", + "Ma ny", + "M any", + "▁S ep", + "▁Se p", + "▁ Sep", + "▁bad ly", + "ig i", + "i gi", + "▁Geme inde", + "Il l", + "I ll", + "▁А н", + "ua rt", + "uar t", + "u art", + "it empty", + "item pty", + "▁N iger", + "▁Ni ger", + "▁im migr", + "▁imm igr", + "Su per", + "Sup er", + "S uper", + "v á", + "ist ribute", + "istribut e", + "Hel pers", + "Helper s", + "Help ers", + "▁w aters", + "▁water s", + "▁wat ers", + "▁wa ters", + "▁join ing", + "▁jo ining", + "om itempty", + "▁Other wise", + "▁H ost", + "▁Ho st", + "▁ Host", + "▁re dd", + "▁red d", + "▁d y", + "▁ dy", + "▁con verted", + "▁convert ed", + "▁conver ted", + "▁pr ayer", + "▁pray er", + "▁pra yer", + "▁У краї", + "▁Укра ї", + "▁e lections", + "▁elect ions", + "▁ele ctions", + "▁election s", + "re b", + "r eb", + "er ie", + "eri e", + "e rie", + "▁с вя", + "Ab s", + "A bs", + "ie mbre", + "iem bre", + "i embre", + "hol ders", + "hold ers", + "holder s", + "▁R ol", + "▁Ro l", + "ut schen", + "uts chen", + "utsch en", + "utsche n", + "▁G h", + "ter y", + "te ry", + "t ery", + "ан г", + "а нг", + "▁narr ative", + "min us", + "m inus", + "▁I ron", + "▁Ir on", + "=\" #", + "▁w and", + "▁wa nd", + "▁ wand", + "▁w ished", + "▁wish ed", + "▁wis hed", + "ic ode", + "ico de", + "i code", + "or r", + "o rr", + "[ [", + "▁detect ed", + "▁municip al", + "▁P our", + "▁Po ur", + "▁S erv", + "▁Se rv", + "▁Ser v", + "▁ Serv", + "cite t", + "cit et", + "c itet", + "▁g rey", + "▁gr ey", + "▁gre y", + "▁R ap", + "▁Ra p", + "▁v oy", + "▁vo y", + "▁l leg", + "▁ll eg", + "▁cur rency", + "▁curr ency", + "▁ currency", + "▁S cript", + "▁Sc ript", + "▁ Script", + "str ument", + "stru ment", + "▁expect ing", + "▁t ickets", + "▁tick ets", + "▁ticket s", + "▁b ucket", + "▁buck et", + "▁ bucket", + "eg r", + "e gr", + "▁j acket", + "▁jack et", + "dr v", + "d rv", + "▁lo ans", + "▁loan s", + "▁k ann", + "▁kan n", + "▁ka nn", + "▁integr al", + "▁character istics", + "▁characteristic s", + "(\" .", + "( \".", + "▁man ual", + "▁d ynamics", + "▁dynam ics", + "▁dynamic s", + ": *", + "sh a", + "s ha", + "re ens", + "ree ns", + "reen s", + "on ical", + "oni cal", + "onic al", + "▁to ile", + "añ a", + "a ña", + "▁d istant", + "▁di stant", + "▁dist ant", + "▁hand led", + "▁handle d", + "Bo ol", + "B ool", + "▁pe nal", + "▁pen al", + "▁Th ings", + "▁prom inent", + "▁ex ped", + "▁exp ed", + "▁He lp", + "▁Hel p", + "▁ Help", + "▁a sp", + "▁as p", + "▁ asp", + "la p", + "l ap", + "▁A uth", + "▁Aut h", + "▁Au th", + "▁ Auth", + "Bas ic", + "ach uset", + "▁B ild", + "▁Bi ld", + "▁Bil d", + "▁ent itled", + "▁j ag", + "▁ja g", + "▁reject ed", + "▁m emor", + "▁me mor", + "▁mem or", + "▁memo r", + "or ts", + "ort s", + "▁ap plies", + "▁appl ies", + "▁L anguage", + "▁ Language", + "spec ific", + "achuset ts", + "HA ND", + "H AND", + "▁R oute", + "▁Ro ute", + "▁Rou te", + "▁ Route", + "mark et", + "mar ket", + "▁K y", + "▁p ose", + "▁pos e", + "▁po se", + "▁ pose", + "AC HE", + "ACH E", + "po ll", + "pol l", + "p oll", + "▁r ocks", + "▁ro cks", + "▁rock s", + "bo ne", + "bon e", + "b one", + "▁D IS", + "▁DI S", + "▁ DIS", + "W atch", + "▁sm iling", + "ри о", + "Mon th", + "Mont h", + "▁e fter", + "con struct", + "const ruct", + "▁b ands", + "▁band s", + "▁ban ds", + "▁ bands", + "▁collabor ation", + "ни ми", + "ним и", + "gl as", + "g las", + "▁v y", + "▁ vy", + "▁eng agement", + "▁engage ment", + "__ )", + "_ _)", + "▁w ings", + "▁win gs", + "▁wing s", + "ки м", + "к им", + "net je", + "at iva", + "ati va", + "ativ a", + "▁Du ke", + "ле е", + "▁With in", + "▁d ove", + "▁do ve", + "▁c b", + "▁ cb", + "ye rs", + "yer s", + "y ers", + "po w", + "p ow", + "[ (", + "▁evalu ate", + "▁eval uate", + "Point s", + "▁р і", + "▁ рі", + "od igd", + "odi gd", + "on omy", + "ono my", + "onom y", + "▁Ill inois", + "▁T yp", + "▁Ty p", + "▁ Typ", + "▁coord inates", + "▁coordinate s", + "pis ode", + "uck ed", + "uc ked", + "▁f lav", + "▁fl av", + "▁br ands", + "▁brand s", + "▁cal endar", + "▁ calendar", + "Li b", + "L ib", + "▁uit gen", + "▁t ale", + "▁tal e", + "▁ta le", + "▁brief ly", + "▁m ic", + "▁mi c", + "▁ mic", + "RE SS", + "RES S", + "▁sp äter", + "▁integr ated", + "▁integrate d", + "▁cook ies", + "▁cookie s", + "▁uitgen odigd", + "▁P riv", + "▁Pr iv", + "▁Pri v", + "▁ Priv", + "▁phen omen", + "▁vo egen", + "Su pp", + "Sup p", + "S upp", + "▁re fers", + "▁ref ers", + "▁refer s", + "па д", + "▁Cl inton", + "▁Clin ton", + "▁ass ignment", + "▁assign ment", + "in als", + "ina ls", + "inal s", + "i nals", + "▁a sym", + "▁as ym", + "cy cle", + "cycl e", + "c ycle", + "▁And erson", + "▁Anders on", + "▁b inding", + "▁bin ding", + "▁bind ing", + "▁ binding", + "ri que", + "r ique", + "hi nd", + "hin d", + "h ind", + "▁be half", + "▁beh alf", + "▁F le", + "▁Fl e", + "▁break s", + "▁bre aks", + "▁so ap", + "▁ soap", + "ва р", + "в ар", + "▁v ä", + "▁ vä", + "▁c rying", + "▁cr ying", + "▁cry ing", + "▁ →", + "▁m sm", + "▁ms m", + "▁ msm", + "▁bo ots", + "▁boot s", + "ow ing", + "owi ng", + "o wing", + "▁b ell", + "▁be ll", + "▁bel l", + "▁ bell", + "su ite", + "suit e", + "▁Bund es", + "▁Bun des", + "Y ear", + "nd ef", + "nde f", + "n def", + "O ther", + "▁go ogle", + "▁goog le", + "▁ google", + "EN CE", + "ENC E", + "WE R", + "W ER", + "Le s", + "L es", + "Sh ared", + "Share d", + "▁E D", + "▁ ED", + "IF T", + "I FT", + "▁flo ating", + "▁float ing", + "ý m", + "{} ,", + "{ },", + "Bin ary", + "B inary", + "▁ro ce", + "ra j", + "r aj", + "▁be werken", + "B F", + "▁H ur", + "▁Hu r", + "ce n", + "c en", + "▁e re", + "▁er e", + "▁ ere", + "▁c amb", + "▁cam b", + "▁ca mb", + "▁Pak istan", + "▁great ly", + "▁log ging", + "▁ logging", + "/ .", + "Ten sor", + "T ensor", + "▁op ens", + "▁open s", + "▁ opens", + "▁R io", + "▁klik ken", + "▁sc ulpt", + "ap ore", + "apor e", + "w x", + "▁N ich", + "▁Nic h", + "▁Ni ch", + "na n", + "n an", + "▁inj ured", + "com pare", + "comp are", + "compar e", + "th a", + "t ha", + "Sam ple", + "S ample", + "Sh ell", + "She ll", + "S hell", + "▁comm ander", + "▁command er", + "▁re ceiver", + "▁rece iver", + "▁receive r", + "▁h opes", + "▁hope s", + "▁hop es", + "▁ho pes", + "▁b yl", + "▁by l", + "▁pro xy", + "▁pr oxy", + "▁ proxy", + "▁g all", + "▁gal l", + "▁ga ll", + "get Id", + "▁B ab", + "▁Ba b", + "fe ld", + "fel d", + "f eld", + "▁\" _", + "▁H ab", + "▁Ha b", + "sim ple", + "▁execut ed", + "▁execute d", + "▁a te", + "▁at e", + "▁ ate", + "▁an imation", + "▁anim ation", + "▁ animation", + "▁in hab", + "▁бо ль", + "▁r outer", + "▁ro uter", + "▁rout er", + "▁route r", + "▁rou ter", + "▁ router", + "▁gl ob", + "▁glo b", + "▁ glob", + "Ge plaatst", + "▁begin netje", + "▁K ur", + "▁Ku r", + "▁Х а", + "al igned", + "align ed", + "▁cert ificate", + "▁ Å", + ".) .", + ". ).", + "▁s oll", + "▁so ll", + "▁sol l", + "▁Im port", + "▁Imp ort", + "▁ Import", + "ре ди", + "ред и", + "р еди", + "▁pand emic", + "▁n ic", + "▁ni c", + "▁ nic", + "v ä", + "▁G ree", + "▁Gr ee", + "▁Gre e", + "▁S ay", + "▁Sa y", + "▁д і", + "▁ ді", + "▁N um", + "▁Nu m", + "▁ Num", + "▁rough ly", + "▁des pués", + "▁ ​", + "▁spec ify", + "Map per", + "lic ht", + "li cht", + "lich t", + "l icht", + "▁th umb", + "▁ thumb", + "wi e", + "w ie", + "▁un likely", + "▁unlike ly", + "▁ unlikely", + "▁E dd", + "▁Ed d", + "He y", + "H ey", + "▁O pt", + "▁Op t", + "▁ Opt", + "B LOCK", + "во р", + "в ор", + "▁ ×", + "▁b a", + "▁ ba", + "▁period s", + "▁title s", + "▁tit les", + "Me d", + "M ed", + "▁f on", + "▁fo n", + "▁ fon", + "▁b ast", + "▁bas t", + "▁ba st", + "▁ bast", + "▁F orest", + "▁For est", + "▁Fore st", + "▁Fo rest", + "▁ №", + "on ds", + "ond s", + "▁f al", + "▁fa l", + "▁g esch", + "▁ge sch", + "▁ges ch", + "▁ gesch", + "dir ection", + "di rection", + "direct ion", + "dire ction", + "d irection", + "IF Y", + "▁L A", + "▁ LA", + "▁( ((", + "▁(( (", + "▁ (((", + "GT H", + "G TH", + "it udes", + "itude s", + "itu des", + "itud es", + "▁dest ruction", + "▁destruct ion", + "▁J a", + "▁s take", + "▁st ake", + "▁sta ke", + "iffer ent", + "iffe rent", + "▁ident ical", + "▁f og", + "▁fo g", + "▁R eb", + "▁Re b", + "▁ Reb", + "ски е", + "сту п", + "ja x", + "j ax", + "▁M ars", + "▁Mar s", + "▁Ma rs", + "▁hist oric", + "▁histor ic", + "▁V o", + "▁ Vo", + "▁entre pre", + "▁t ension", + "▁tens ion", + "▁W HERE", + "▁WH ERE", + "▁WHE RE", + "▁Phil adelphia", + "Count er", + "Co unter", + "C ounter", + "▁fr ames", + "▁frame s", + "▁fra mes", + "▁fram es", + "▁ frames", + "▁m uy", + "▁mu y", + "e j", + "ö t", + "e u", + "▁че лове", + "PRO C", + "PR OC", + "▁res olved", + "▁resolve d", + "▁ resolved", + "▁t ape", + "▁tap e", + "▁ta pe", + "ци он", + "▁sing ular", + "▁person nel", + "▁M un", + "▁Mu n", + "▁O cc", + "▁ Occ", + "▁scal ar", + "▁ scalar", + "de ss", + "des s", + "d ess", + "▁c able", + "▁cab le", + "▁ca ble", + "be ing", + "b eing", + "▁J enn", + "▁Je nn", + "▁Jen n", + "▁er st", + "▁ers t", + "▁ erst", + "Action s", + "Act ions", + "A ctions", + "Env ironment", + "vi a", + "v ia", + "▁strugg ling", + "▁D VD", + "wh e", + "w he", + "▁throw ing", + "▁thr owing", + "▁thro wing", + "Bound s", + "B ounds", + "▁M D", + "▁ MD", + "▁\" ../", + "▁\". ./", + "▁satisf y", + "▁Color ado", + "▁Act ive", + "▁Activ e", + "▁ Active", + "Task s", + "<>( );", + "<> ();", + "< >();", + "▁sl ipped", + "▁slip ped", + "▁po ison", + "▁poi son", + "z b", + "Dis patch", + "war ning", + "warn ing", + "w arning", + "▁ult imate", + "p icture", + "ex pression", + "exp ression", + "expr ession", + "express ion", + "▁T alk", + "▁Tal k", + "▁f lick", + "▁fl ick", + "▁rais ing", + "▁ra ising", + "▁ raising", + "▁trans actions", + "▁transaction s", + "▁gl ance", + "▁g ri", + "▁gr i", + "▁п рез", + "▁пре з", + "se lection", + "sel ection", + "select ion", + "s election", + "њ а", + "en dl", + "end l", + "▁A bb", + "▁Ab b", + "▁b old", + "▁bo ld", + "▁bol d", + "▁ bold", + "▁maint ained", + "▁maintain ed", + "Ex ists", + "▁encour aged", + "▁encourage d", + "Qu al", + "Q ual", + "▁ess ere", + "▁h ired", + "▁hi red", + "▁hire d", + "let ter", + "lett er", + "lette r", + "it ches", + "itch es", + "oth ers", + "other s", + "othe rs", + "o thers", + "▁w oj", + "▁wo j", + "▁inj uries", + "▁d il", + "▁di l", + "ex ecut", + "exec ut", + "▁Ste el", + "▁G arden", + "▁Gar den", + "▁Gard en", + "з я", + "\\, \\", + "\\ ,\\", + "▁An gel", + "▁Ang el", + "pr im", + "p rim", + ">: ]<", + "g b", + "pe at", + "in te", + "int e", + "i nte", + "▁ap olog", + "▁reg ulations", + "▁regul ations", + "▁regulation s", + "S rc", + "k h", + "Up load", + "U pload", + "ma pping", + "map ping", + "m apping", + "▁p resents", + "▁pres ents", + "▁present s", + "▁po etry", + "▁poet ry", + "▁st ops", + "▁stop s", + "▁sto ps", + "▁T ol", + "▁To l", + "▁t ower", + "▁to wer", + "▁tow er", + "▁O UT", + "▁ OUT", + "Th ank", + "Than k", + "▁organ ic", + "▁d rei", + "▁dr ei", + "▁dre i", + "▁p ound", + "▁po und", + "▁pou nd", + "cent ury", + "▁mod ules", + "▁module s", + "▁ modules", + "▁д ере", + "▁де ре", + "▁w orn", + "▁wor n", + "▁wo rn", + "▁par ad", + "▁para d", + "▁pa rad", + "▁C os", + "▁Co s", + "fi c", + "f ic", + "▁бе з", + "▁Jim my", + "▁l ands", + "▁land s", + "▁lan ds", + "▁ lands", + "▁min ist", + "▁mini st", + "vs pace", + "v space", + "▁light ing", + "▁n aked", + "▁na ked", + "▁design er", + "▁St ream", + "▁Stre am", + "▁ Stream", + "TM P", + "T MP", + "Cent er", + "C enter", + "resent ation", + "ON T", + "O NT", + "▁e rs", + "▁er s", + "▁ ers", + "▁measure ment", + "▁mus cles", + "▁muscle s", + "▁I gn", + "▁ Ign", + "▁C OM", + "▁CO M", + "▁ COM", + "▁f ru", + "▁fr u", + "▁gen re", + "▁al pha", + "▁ alpha", + "▁ret irement", + "▁retire ment", + "▁G on", + "▁Go n", + "ő l", + "cont ents", + "content s", + "▁he aling", + "▁heal ing", + "▁s ido", + "▁si do", + "▁sid o", + "incip al", + "Per mission", + "Perm ission", + "ра к", + "▁G ordon", + "▁Gor don", + "▁R ank", + "▁Ran k", + "▁ Rank", + "▁Aut om", + "▁Au tom", + "▁Auto m", + "▁ Autom", + "Con structor", + "Construct or", + "wi ki", + "wik i", + "w iki", + "▁concern ing", + "▁concer ning", + "riz ona", + "▁var iant", + "▁vari ant", + "▁ variant", + "▁arr anged", + "▁arrang ed", + "▁arrange d", + "▁S pr", + "▁Sp r", + "BP ACK", + "B PACK", + "Tim estamp", + "re store", + "rest ore", + "aw are", + "awa re", + "a ware", + "▁Ob serv", + "▁ Observ", + "▁S V", + "▁ SV", + "ip p", + "i pp", + "▁Execut ive", + "▁col leg", + "▁coll eg", + "▁colle g", + "▁explicit ly", + "wr itten", + "writ ten", + "▁K ön", + "▁Kö n", + "ir us", + "i rus", + "▁H old", + "▁Hol d", + "▁Ho ld", + "▁P ract", + "▁Pr act", + "▁Pra ct", + "Char acter", + "▁red istribute", + "uer to", + "▁Stud ent", + "▁ Student", + "▁el der", + "▁D op", + "▁Do p", + "v p", + "▁H ub", + "▁Hu b", + "▁ Hub", + "▁gr ounds", + "▁ground s", + "▁R y", + "▁sign als", + "▁sig nals", + "▁signal s", + "▁g ifts", + "▁gift s", + "▁streng then", + "▁strength en", + "▁L yn", + "▁Ly n", + "com mun", + "comm un", + "▁на й", + "▁fin ance", + "▁financ e", + "no c", + "n oc", + "he lm", + "hel m", + "h elm", + "▁c uts", + "▁cut s", + "▁cu ts", + "▁advent ure", + "▁R ic", + "▁intellect ual", + "▁Out put", + "▁ Output", + "▁aw k", + "▁ awk", + "▁concentr ation", + "▁guid ance", + "Buf f", + "Bu ff", + "B uff", + "▁f illing", + "▁fil ling", + "▁fill ing", + "▁reg ul", + "▁del icious", + "([ ]", + "( []", + "ши х", + "▁t ons", + "▁to ns", + "▁ton s", + "▁ tons", + "act ivity", + "activ ity", + "G P", + "LO B", + "L OB", + "st adt", + "sta dt", + "stad t", + "ta l", + "t al", + "▁im g", + "▁i mg", + "▁ img", + "▁r ush", + "▁ru sh", + "▁rus h", + "att ice", + "atti ce", + "▁p ok", + "▁po k", + "st eps", + "ste ps", + "step s", + "▁l id", + "▁li d", + "▁D NA", + "B rowser", + "▁lad ies", + "▁an nées", + "▁ann ées", + "▁resc ue", + "av ity", + "avi ty", + "ro ck", + "roc k", + "r ock", + "▁glass es", + "▁B ey", + "▁Be y", + ")} $", + ") }$", + "de tail", + "det ail", + "▁d és", + "▁dé s", + "ta x", + "t ax", + "▁favour ite", + "▁prec ision", + "▁con oc", + "▁co noc", + "M s", + "▁N ative", + "▁Nat ive", + "▁ Native", + "▁P il", + "▁Pi l", + "Input Stream", + "or p", + "o rp", + "▁P ap", + "▁Pa p", + "▁p icking", + "▁pick ing", + "▁pic king", + "ip h", + "i ph", + "Load ing", + "Lo ading", + "▁pr iest", + "▁pri est", + "H ook", + "▁p ist", + "▁pi st", + "▁U ne", + "▁Un e", + "▁ Une", + "% ,", + "▁b il", + "▁bi l", + "▁ bil", + "▁conserv ative", + "ev al", + "eva l", + "e val", + "ik ing", + "iki ng", + "i king", + "'} ,", + "' },", + "▁sa uce", + "▁sau ce", + "▁D ue", + "▁Du e", + "as sen", + "ass en", + "asse n", + "▁occasion ally", + "▁occasional ly", + "▁Д ж", + "un known", + "unk nown", + "DE D", + "D ED", + "▁d rum", + "▁dr um", + "▁dru m", + "▁d ub", + "▁du b", + "AT URE", + "us age", + "usa ge", + "get Type", + "re ply", + "rep ly", + "▁strateg ic", + "▁k ap", + "▁ka p", + "▁ kap", + "de sign", + "des ign", + "date time", + "dat etime", + "▁P rim", + "▁Pr im", + "▁Pri m", + "▁ Prim", + "Ma ster", + "M aster", + "▁Cor ps", + "▁consider able", + "▁T u", + "▁ ла", + "▁t ous", + "▁to us", + "▁tou s", + "▁c lar", + "▁cl ar", + "▁po em", + "al bum", + "] *", + "lo aded", + "load ed", + "▁travel ing", + "▁trav eling", + "вы е", + "▁F err", + "▁Fe rr", + "▁Fer r", + "▁p harm", + "▁ph arm", + "ab i", + "a bi", + "▁} \\", + "▁ }\\", + "col lect", + "coll ect", + "▁B our", + "▁Bo ur", + "▁Bou r", + "O C", + "▁measure ments", + "▁measurement s", + "▁Profess ional", + "▁s ensor", + "▁sens or", + "▁sen sor", + "▁ sensor", + "ut sche", + "uts che", + "utsch e", + "▁dem anded", + "▁demand ed", + "▁accompan ied", + "▁p rend", + "▁pre nd", + "▁pr end", + "▁enc oding", + "▁ encoding", + "▁Gesch ichte", + "▁m ig", + "▁mi g", + "▁G ib", + "▁Gi b", + "▁Re ich", + "▁m yster", + "▁my ster", + "▁myst er", + "▁M ock", + "▁Mo ck", + "▁ Mock", + "▁phys ically", + "▁physical ly", + "▁B au", + "▁Ba u", + "▁S ingle", + "▁Sing le", + "▁Sin gle", + "▁ Single", + "▁man aging", + "▁K il", + "▁Ki l", + "▁Tem ple", + "▁Temp le", + "▁l ev", + "▁le v", + "▁ lev", + "▁l í", + "CP U", + "C PU", + "▁Prem ier", + "▁G ive", + "▁Gi ve", + "ir i", + "i ri", + "N V", + "▁A I", + "▁ AI", + "▁f p", + "▁ fp", + "лекс анд", + "▁t ant", + "▁tan t", + "▁ta nt", + "▁f ot", + "▁fo t", + "Null able", + "▁gu ards", + "▁guard s", + "On ce", + "▁ch amber", + "▁cha mber", + "fil m", + "fi lm", + "▁b ias", + "▁bi as", + "▁ bias", + "▁T ai", + "▁Ta i", + "ins ic", + "insi c", + "▁m l", + "▁ ml", + "▁K a", + "ва л", + "в ал", + "▁S ER", + "▁SE R", + "▁ SER", + "▁Some one", + "}} _{", + "}}_ {", + "} }_{", + "Fix ed", + "F ixed", + "▁b ent", + "▁be nt", + "▁ben t", + "▁pro hib", + "▁b id", + "▁bi d", + "▁ bid", + "▁fe wer", + "▁few er", + "к ры", + "▁l ugar", + "▁lug ar", + "▁lu gar", + "▁de serve", + "▁des erve", + "ss l", + "s sl", + "▁c fg", + "▁cf g", + "▁ cfg", + "re ck", + "rec k", + "▁st ability", + "▁stabil ity", + "▁stab ility", + "re size", + "res ize", + "▁assert That", + "Tr igger", + "▁ста нов", + "▁стан ов", + "▁ станов", + "pl ugins", + "plugin s", + "plug ins", + "▁l ets", + "▁le ts", + "▁let s", + "▁ lets", + "хі д", + "х ід", + "▁La ura", + "▁Lau ra", + "не р", + "н ер", + "▁br ut", + "▁bru t", + "▁F I", + "▁ FI", + "is ons", + "ison s", + "iso ns", + "▁d yn", + "▁dy n", + "▁ dyn", + "ic her", + "ich er", + "iche r", + "i cher", + "ray ed", + "▁frequ ent", + "▁jed och", + "▁Mar ine", + "st rings", + "str ings", + "string s", + "▁U til", + "▁Ut il", + "▁ Util", + "▁b os", + "▁bo s", + "Mu s", + "M us", + "▁Portug al", + "Str ategy", + "▁по се", + "▁пос е", + "▁sl ice", + "▁slic e", + "▁ slice", + "▁ins ight", + "▁w idget", + "▁wid get", + "▁ widget", + "▁gén éral", + "message s", + "m essages", + "▁H u", + "▁requ irement", + "▁require ment", + "Si de", + "S ide", + "empl ates", + "emplate s", + "▁cer emony", + "▁ceremon y", + "▁phys ics", + "▁grad uate", + "▁gradu ate", + "▁ graduate", + "par a", + "pa ra", + "p ara", + "▁pre serv", + "▁pres erv", + "▁sh ops", + "▁shop s", + "▁ shops", + "ze k", + "z ek", + "▁u b", + "▁ ub", + "pre pare", + "▁O il", + "▁f ib", + "▁fi b", + "▁run time", + "▁ runtime", + "▁h ogy", + "▁ho gy", + "Warn ing", + "War ning", + "W arning", + "▁Con vert", + "▁ Convert", + "bour ne", + "▁emer ged", + "▁emerge d", + "▁Д и", + "ight h", + "igh th", + "gu ard", + "ka l", + "k al", + "valid ation", + "ên cia", + "ê ncia", + "▁dr inks", + "▁drink s", + "the orem", + "H R", + "ie v", + "i ev", + "ploy ee", + "Us age", + "▁с пе", + "▁сп е", + "▁ спе", + "dis patch", + "disp atch", + "▁inst antly", + "▁instant ly", + "ob i", + "o bi", + "▁just ify", + "▁N ev", + "▁Ne v", + "▁я вля", + "ag ra", + "agr a", + "a gra", + "▁trans mission", + "▁transm ission", + "fl y", + "f ly", + "; ' ;", + "> ';", + "▁cou sin", + "▁cous in", + "create Element", + "Co uld", + "C ould", + "▁cap ac", + "▁p ause", + "▁pa use", + "▁paus e", + "▁ pause", + "Array List", + "kt e", + "k te", + "ord ered", + "order ed", + "▁sh aking", + "▁sha king", + "label s", + "lab els", + "▁redu cing", + "вы х", + "US ED", + "USE D", + "U SED", + "▁v oting", + "▁vo ting", + "▁vot ing", + "▁Min istry", + "▁M ig", + "▁Mi g", + "▁C hen", + "▁Ch en", + "▁Che n", + "▁ac company", + "▁accompan y", + "▁accomp any", + "ul le", + "ull e", + "u lle", + "▁g a", + "▁ ga", + "▁equ ipped", + "▁equip ped", + "▁n un", + "▁nu n", + "Be t", + "B et", + "▁lic ensed", + "▁license d", + "AR CH", + "F N", + "▁eng ines", + "▁engine s", + "▁s ter", + "▁st er", + "▁ste r", + "▁ ster", + "▁loc ale", + "▁local e", + "▁ locale", + "▁в ъ", + "lin ks", + "link s", + "l inks", + "▁Cap ital", + "▁al ien", + "▁ali en", + "W r", + "р ъ", + "Car t", + "C art", + "▁Mark eting", + "▁Market ing", + "▁R T", + "▁ RT", + "File Name", + "▁t i", + "▁ ti", + "ij i", + "i ji", + "▁vers us", + "li ve", + "liv e", + "l ive", + "Sy m", + "S ym", + "ko r", + "k or", + "▁e mission", + "▁em ission", + "um m", + "u mm", + "yc z", + "y cz", + "▁clim bed", + "▁climb ed", + "▁plus ieurs", + "к ри", + "ya r", + "y ar", + "os ten", + "ost en", + "o sten", + "▁u sb", + "▁us b", + "▁ usb", + "▁cross ing", + "▁pol ynom", + "▁poly nom", + "▁rem oval", + "▁Ad ams", + "▁Adam s", + "▁i hre", + "▁ih re", + "▁ihr e", + "an den", + "and en", + "ande n", + "▁Ben j", + "▁P hill", + "▁Ph ill", + "▁Phil l", + "▁wound ed", + "▁Cast le", + "▁Cas tle", + "bi ld", + "bil d", + "b ild", + "An notation", + "Process or", + "▁t in", + "▁ti n", + "fo lg", + "fol g", + "▁Stud ents", + "▁Student s", + "▁Mex ican", + "▁administr ative", + "IL ED", + "ILE D", + "I LED", + "▁con qu", + "▁che er", + "▁C es", + "▁Ce s", + "B ecause", + "▁J uni", + "▁Jun i", + "▁Ju ni", + "▁en contr", + "av i", + "a vi", + "V I", + "ak u", + "a ku", + "▁T on", + "▁To n", + "▁sm oking", + "▁b ay", + "▁ba y", + "work s", + "wor ks", + "а т", + "at tered", + "att ered", + "atter ed", + "atte red", + "▁Bo olean", + "▁ Boolean", + "▁B alt", + "▁Ba lt", + "▁Bal t", + "de fer", + "def er", + "path y", + "pat hy", + "pa thy", + "A h", + "▁a kt", + "▁ak t", + "▁ akt", + "▁gover nor", + "▁govern or", + "P ad", + "▁si sters", + "▁sister s", + "▁sist ers", + "La t", + "L at", + "▁re vel", + "▁r evel", + "▁rev el", + "▁reve l", + "▁S Y", + "▁ SY", + "it os", + "ito s", + "i tos", + "▁fil ters", + "▁filter s", + "▁ filters", + "Ch unk", + "con sum", + "cons um", + "▁rem oving", + "▁H err", + "▁He rr", + "▁Her r", + "▁gener ator", + "▁ generator", + "▁C ra", + "▁Cr a", + "▁far mers", + "▁farm ers", + "▁farmer s", + "▁Mem bers", + "▁Member s", + "▁ Members", + "▁over come", + "▁C in", + "▁Ci n", + "ig keit", + "cri ptions", + "cription s", + "cript ions", + "Test s", + "Te sts", + "T ests", + "▁к лу", + "▁sh ake", + "▁sha ke", + "▁ shake", + "▁y y", + "▁ yy", + "pl acement", + "place ment", + "plac ement", + "▁a wards", + "▁aw ards", + "▁award s", + "▁epis odes", + "▁episode s", + "▁Bl ood", + "▁Blo od", + "▁bul let", + "▁bull et", + "▁ bullet", + "▁v iene", + "▁vi ene", + "▁vie ne", + "▁Fin ancial", + "F uture", + "▁r ou", + "▁ro u", + "▁ rou", + "▁bi ologie", + "▁use State", + "ia ni", + "ian i", + "i ani", + "pie ce", + "p iece", + "▁spe aker", + "▁speak er", + "▁re fr", + "▁ref r", + "AR K", + "▁M IT", + "▁MI T", + "▁ MIT", + "▁T an", + "▁Ta n", + "▁B ased", + "▁Bas ed", + "▁Base d", + "▁Ba sed", + "▁ Based", + "▁cult iv", + "▁hung ry", + "▁A y", + "▁H ey", + "▁He y", + "▁ Hey", + "▁excit ement", + "ibr aries", + "Hi t", + "H it", + "▁E nde", + "▁En de", + "▁End e", + "N G", + "FI L", + "F IL", + ".\" )", + ". \")", + "F amily", + "in ery", + "ine ry", + "iner y", + "ne cess", + "ve lope", + "vel ope", + "velop e", + "▁B ot", + "▁Bo t", + "▁ Bot", + "port er", + "por ter", + "porte r", + "p orter", + "▁cl imb", + "▁clim b", + "▁E li", + "▁El i", + "ur ent", + "ure nt", + "uren t", + "u rent", + "▁mist akes", + "▁mistake s", + "áb an", + "á ban", + "mark s", + "mar ks", + "m arks", + "pk t", + "p kt", + "L ibrary", + "st ed", + "ste d", + "s ted", + "ublic e", + "ubl ice", + "▁Administr ation", + "▁Admin istration", + "▁sh apes", + "▁shape s", + "▁sha pes", + "пу бли", + "Go d", + "G od", + "in nen", + "inn en", + "ко ло", + "к оло", + "<< <<", + "ib e", + "i be", + "ê s", + "▁С ША", + "▁Fore ign", + "▁ Foreign", + "▁Marg aret", + "▁g ene", + "▁gen e", + "▁ge ne", + "▁dist urb", + "▁т ер", + "▁те р", + "▁ тер", + "▁on Click", + "▁Engine ering", + "▁stop ping", + "▁sto pping", + "▁restr ictions", + "▁restrict ions", + "▁restriction s", + ", *", + "BU F", + "▁sh adows", + "▁shadow s", + "hc i", + "h ci", + "▁Christ ians", + "▁Christian s", + "▁f ence", + "▁fen ce", + "▁lux ury", + "ak h", + "a kh", + "co ord", + "▁invest igate", + "▁investig ate", + "▁convent ional", + "▁convention al", + "\" —", + "▁vis its", + "▁visit s", + "is é", + "▁S ac", + "▁Sa c", + "class Name", + "▁Psy ch", + "▁ref lected", + "▁reflect ed", + "▁п ло", + "▁ пло", + "▁V ice", + "▁Vi ce", + "▁Vic e", + "ła w", + "ł aw", + "________ ________", + "▁W olf", + "▁Wol f", + "re nte", + "ren te", + "rent e", + "r ente", + "▁Ch ampion", + "▁sim ulation", + "es ota", + "eso ta", + "▁S oon", + "▁So on", + "▁C el", + "▁Ce l", + "▁the ories", + "▁S TR", + "▁ST R", + "▁ STR", + "▁collect ive", + "▁coord inate", + "query Selector", + "em ed", + "eme d", + "e med", + "B reak", + "▁g ef", + "▁ge f", + "▁electric ity", + "▁gather ing", + "at ers", + "ate rs", + "ater s", + "a ters", + "ex per", + "exp er", + "▁R oma", + "▁Rom a", + "▁Ro ma", + "▁Co oper", + "SY MBOL", + "v d", + "ivers ary", + "ain es", + "ai nes", + "aine s", + "a ines", + "▁G rad", + "▁Gr ad", + "▁Gra d", + "▁ Grad", + "▁independ ence", + "wo h", + "w oh", + "▁con sequence", + "▁consequ ence", + "▁convers ations", + "▁conversation s", + "▁R ou", + "▁Ro u", + "▁and ere", + "▁ander e", + "▁System s", + "га р", + "г ар", + "▁mo ist", + "▁mois t", + "fl u", + "f lu", + "ці я", + "ни ш", + "▁r ode", + "▁ro de", + "▁rod e", + "▁p erd", + "▁per d", + "▁pe rd", + "▁s zer", + "▁sz er", + "▁fl ood", + "▁flo od", + "▁in tim", + "▁int im", + "std err", + "▁ref lection", + "▁reflect ion", + "Sc an", + "S can", + "▁dis aster", + "ake spe", + "akes pe", + "▁In valid", + "▁ Invalid", + "▁hum or", + "▁Fried rich", + "▁suggest ions", + "▁suggestion s", + "uv ud", + "De lay", + "Del ay", + "br ief", + "b rief", + "▁и с", + "▁ ис", + "gl ied", + "fa s", + "f as", + "▁S mart", + "▁Sm art", + "▁m edi", + "▁me di", + "▁med i", + "▁ medi", + "sd k", + "s dk", + "▁se us", + "▁seu s", + "▁A rizona", + "▁innoc ent", + "War n", + "W arn", + "ac ious", + "aci ous", + "acio us", + "▁Mos cow", + "▁c aps", + "▁cap s", + "▁ca ps", + "▁ caps", + "Dele gate", + "▁dram atic", + "bo oks", + "book s", + "▁sh ore", + "▁ shore", + "uk i", + "u ki", + "▁Russ ell", + "▁cor relation", + "▁corre lation", + "▁correl ation", + "He lp", + "Hel p", + "▁pub blic", + "zy m", + "z ym", + "com b", + "co mb", + "c omb", + "E Y", + "LEN GTH", + "▁M ün", + "▁_ .", + "▁ _.", + "▁f erm", + "▁fe rm", + "▁fer m", + "▁I an", + "▁St udio", + "▁Stud io", + "▁aff airs", + "▁affair s", + "lo s", + "l os", + "Rule s", + "R ules", + "run ning", + "r unning", + "▁Post ed", + "▁Po sted", + "▁Pos ted", + "P ixel", + "▁d ancing", + "▁dan cing", + "▁agree ments", + "▁agre ements", + "▁agreement s", + "▁P ic", + "▁Pi c", + "an cia", + "anc ia", + "a ncia", + "▁m á", + "ation Token", + "des criptor", + "▁C arter", + "▁Car ter", + "▁Cart er", + "Re lease", + "Rele ase", + "**** ********", + "******** ****", + "****** ******", + "▁out standing", + "ch anges", + "change s", + "chan ges", + "AR RAY", + "▁Bar bara", + "▁Barb ara", + "▁nur se", + "▁nurs e", + "( \r", + "▁Dou glas", + "▁Doug las", + "▁nu cle", + "▁nuc le", + "ou ri", + "our i", + "o uri", + "▁St yle", + "▁ Style", + "av o", + "a vo", + "▁pain ful", + "▁s lic", + "▁sl ic", + "▁sein em", + "▁seine m", + "▁sei nem", + "SUP PORT", + "og ene", + "ogen e", + "oge ne", + "▁sat ell", + "ta gon", + "tag on", + "t agon", + "▁coll apse", + "▁ collapse", + "ve lle", + "vel le", + "v elle", + "MO N", + "M ON", + "augh ters", + "aught ers", + "aughter s", + "▁threat ened", + "▁Il legal", + "▁desper ate", + "st rict", + "str ict", + "stri ct", + "ru s", + "r us", + "сти ту", + "\\\" :", + "\\ \":", + "▁conf lic", + "down load", + "at os", + "ato s", + "a tos", + "▁Pos ition", + "▁ Position", + ".* ;", + ". *;", + "▁the ater", + "▁ple asant", + "▁C ette", + "▁Sing apore", + "he et", + "▁p ir", + "▁pi r", + "▁ac quis", + "▁acqu is", + "▁на зва", + "те ля", + "тел я", + "▁rec ru", + "же ния", + "ё л", + "вер сите", + "▁res pective", + "▁respect ive", + "▁t unnel", + "▁tun nel", + "▁tunn el", + "▁De an", + "D u", + "▁un cle", + "▁unc le", + "▁off ensive", + "co lo", + "col o", + "c olo", + "▁Un like", + "se ries", + "ser ies", + "serie s", + "s eries", + "▁A rn", + "▁Ar n", + "min ute", + "▁des criptor", + "▁ descriptor", + "▁st ones", + "▁stone s", + "▁sto nes", + "IC ATION", + "▁P ad", + "▁Pa d", + "▁ Pad", + "▁i Phone", + "e i", + "▁fant asy", + "▁Kore an", + "▁Korea n", + "\" }", + "▁or th", + "▁ orth", + "hal ten", + "halt en", + "de ep", + "▁K ay", + "▁Ka y", + "requ ency", + "▁du ties", + "▁dut ies", + "aw t", + "a wt", + "▁ne arest", + "▁near est", + "▁dis order", + "ст ру", + "▁Ch ile", + "▁Chi le", + "▁s eq", + "▁se q", + "▁ seq", + "▁transport ation", + "O O", + "▁D ez", + "▁De z", + "ij u", + "i ju", + "▁Result s", + "▁ Results", + "je d", + "j ed", + "iv el", + "ive l", + "i vel", + "HO ST", + "H OST", + "▁ €", + "▁ Î", + "▁c hin", + "▁ch in", + "▁chi n", + "▁m att", + "▁mat t", + "▁ma tt", + "▁v oted", + "▁vo ted", + "▁vote d", + "▁vot ed", + "▁ge hör", + "▁s ue", + "▁su e", + "▁leg acy", + "в ся", + "SO URCE", + "W ORK", + "it is", + "iti s", + "▁$ |", + "▁о бо", + "▁об о", + "▁n r", + "▁ nr", + "▁T amb", + "▁Ta mb", + "▁Tam b", + "▁sn ap", + "▁ snap", + "▁im pressed", + "▁imp ressed", + "▁impress ed", + "▁depos it", + "▁d ivid", + "▁di vid", + "▁div id", + "Seg ment", + "▁к ар", + "▁ка р", + "▁ кар", + "▁G as", + "▁Ga s", + "▁cr imes", + "▁crim es", + "▁crime s", + "▁cri mes", + "▁ins ult", + "▁H um", + "▁Hu m", + "▁bound ed", + "▁k icked", + "▁kick ed", + "▁М у", + "▁| \\", + "▁ |\\", + "ad ded", + "add ed", + "Pro du", + "P rodu", + "▁. /", + "▁ ./", + "▁awk ward", + "▁К ра", + "▁ ї", + "▁CON TR", + "▁be im", + "▁bei m", + "▁place holder", + "▁ placeholder", + "sp i", + "s pi", + "▁B ei", + "▁Be i", + "▁P f", + "ient es", + "ien tes", + "iente s", + "i entes", + "dis k", + "di sk", + "d isk", + "bl k", + "ne o", + "it arian", + "ita rian", + "itar ian", + "▁c ogn", + "▁co gn", + "▁s out", + "▁so ut", + "▁sou t", + "▁tr ash", + "▁tra sh", + "▁tras h", + "▁R ab", + "▁Ra b", + "▁dec line", + "▁decl ine", + "ta t", + "t at", + "▁comb ine", + "▁T ot", + "▁To t", + "▁dr ops", + "▁dro ps", + "▁drop s", + "Time s", + "Tim es", + "T imes", + "ched uler", + "chedul er", + "▁govern ments", + "▁government s", + "Te x", + "T ex", + "▁U sed", + "▁Us ed", + "▁Use d", + "▁ Used", + "за н", + "з ан", + "▁p d", + "▁ pd", + "ме т", + "м ет", + "▁&= &", + "▁N ag", + "▁Na g", + "▁до л", + "▁ дол", + "▁Al ways", + "rt c", + "r tc", + "ск е", + "с ке", + "▁perform ances", + "▁performance s", + "rupt ed", + "rup ted", + "▁д ва", + "▁man agers", + "▁manager s", + "▁manage rs", + "▁P itt", + "▁Pi tt", + "▁myst ery", + "▁myster y", + "▁set tle", + "▁sett le", + "ul se", + "uls e", + "cr oss", + "cro ss", + "c ross", + "quest ion", + "as ha", + "ash a", + "a sha", + "se ed", + "see d", + "s eed", + "ur able", + "ura ble", + "Fin al", + "Fi nal", + "F inal", + "++ ++", + "input s", + "▁back up", + "▁ backup", + "▁Le arning", + "▁Lear ning", + "▁Learn ing", + "▁* ,", + "▁ *,", + "lo go", + "log o", + "l ogo", + "▁se inen", + "▁sein en", + "▁seine n", + "▁sei nen", + "▁vulner able", + "direct ory", + "i ë", + "▁friend ship", + "▁friends hip", + "t u", + "▁V ec", + "▁Ve c", + "▁ Vec", + "rif ice", + "rific e", + "▁б ра", + "▁ бра", + "▁inv olve", + "▁invol ve", + "TO N", + "T ON", + "▁cor rid", + "se par", + "sep ar", + "Dest roy", + "▁j ul", + "▁ju l", + "▁inequ ality", + "▁a in", + "▁ai n", + "▁ ain", + "he x", + "h ex", + "▁w ider", + "▁wide r", + "▁wid er", + "те ли", + "тел и", + "▁j ack", + "▁ja ck", + "▁ jack", + "▁qu ot", + "▁ quot", + "▁G len", + "▁Gl en", + "▁Gle n", + "init ely", + "ih ood", + "i hood", + "▁wa ist", + "▁Man chester", + "reg ular", + "▁( &", + "▁ (&", + "▁mass es", + "▁mas ses", + "▁DE FAULT", + "▁ DEFAULT", + "▁ch airs", + "▁chair s", + "▁cha irs", + "▁F ast", + "▁Fa st", + "▁ Fast", + "▁c itt", + "▁cit t", + "▁ci tt", + "_{ {\\", + "_ {{\\", + "o a", + "▁$ \\{", + "▁$\\ {", + "▁se eds", + "▁see ds", + "▁seed s", + "▁A ld", + "▁Al d", + "▁B att", + "▁Ba tt", + "▁Bat t", + "fa b", + "f ab", + "▁democr acy", + "DT O", + "D TO", + "▁H ij", + "▁Hi j", + "PT R", + "P TR", + "N a", + "▁Har vard", + "si d", + "s id", + "Pr ed", + "Pre d", + "P red", + "fer s", + "fe rs", + "f ers", + "▁s pare", + "▁sp are", + "AM P", + "A MP", + "▁g roupe", + "▁group e", + "▁s ender", + "▁se nder", + "▁send er", + "▁sen der", + "▁ sender", + "▁Christ opher", + "▁prison ers", + "▁prisoner s", + "▁K er", + "▁Ke r", + "▁C rist", + "▁Cr ist", + "▁Cris t", + "▁A LL", + "▁AL L", + "▁ ALL", + "ri ce", + "ric e", + "r ice", + "▁an tes", + "▁ant es", + "▁ante s", + "▁ antes", + "nat ural", + "▁Su san", + "▁Sus an", + "▁J uli", + "▁Jul i", + "▁Ju li", + "▁di ab", + "▁dia b", + "ix on", + "ic ator", + "ica tor", + "▁flex ible", + "▁re serve", + "▁res erve", + "▁reserv e", + "Cont ains", + "▁H il", + "▁Hi l", + "▁I sa", + "▁Is a", + "▁town s", + "▁tow ns", + "G S", + "▁T rad", + "▁Tr ad", + "▁Tra d", + "▁L ock", + "▁Loc k", + "▁Lo ck", + "▁ Lock", + "▁G rund", + "▁Gr und", + "▁Gru nd", + "▁crit icism", + "▁critic ism", + "н ю", + "▁c ă", + "▁polit ician", + "st able", + "sta ble", + "s table", + "Ac cept", + "Sum mary", + "▁tamb ém", + "▁també m", + "}^ {-", + "}^{ -", + "} ^{-", + "▁I M", + "▁ IM", + "id al", + "ida l", + "i dal", + "мо р", + "м ор", + "Bl ue", + "GRO UP", + "▁term inal", + "▁termin al", + "▁complex ity", + "▁loc ally", + "▁local ly", + "DO WN", + "▁N ear", + "▁Ne ar", + "Dep th", + "▁p ole", + "▁pol e", + "▁po le", + "▁e quality", + "▁equ ality", + "▁equal ity", + "Si te", + "S ite", + "▁is instance", + "Sp eed", + "Spe ed", + "S peed", + "ip pi", + "ipp i", + ", &", + "▁E nc", + "▁En c", + "▁ Enc", + "ще н", + "щ ен", + "▁m ater", + "▁mat er", + "▁ma ter", + "▁mate r", + "▁sl aves", + "▁slave s", + "▁sla ves", + "AC TION", + "ACT ION", + "A CTION", + "usal em", + "usa lem", + "▁h az", + "▁ha z", + "▁Be at", + "▁w rest", + "▁wr est", + "▁l lam", + "▁ll am", + "In s", + "I ns", + "ми на", + "▁бу в", + "▁Fr ame", + "▁Fra me", + "▁ Frame", + "us hes", + "ush es", + "▁virtual ly", + "▁virt ually", + "▁P erm", + "▁Per m", + "▁Pe rm", + "▁ Perm", + "▁we ights", + "▁weight s", + "▁weigh ts", + "▁ weights", + "▁ll vm", + "▁ llvm", + "▁c ave", + "▁ca ve", + "▁cav e", + "st ates", + "state s", + "stat es", + "sta tes", + "DM A", + "D MA", + "el lt", + "ell t", + "if act", + "ifa ct", + "i fact", + "v endor", + "▁E mma", + "▁Em ma", + "Loc ale", + "Local e", + "▁S ET", + "▁SE T", + "▁ SET", + "▁ge ometry", + "▁ geometry", + "St yles", + "Style s", + "▁Ref eree", + "▁Refer ee", + "▁we it", + "fi ca", + "fic a", + "f ica", + "▁a ds", + "▁ad s", + "▁ ads", + "gr ay", + "gra y", + "g ray", + "▁B urg", + "▁Bur g", + "▁Bu rg", + "ion a", + "io na", + "i ona", + "dag ger", + "d agger", + "▁Jan uar", + "де й", + "д ей", + "ister schaft", + "pp o", + "p po", + "oid s", + "oi ds", + "o ids", + "▁dé part", + "Sh ader", + "▁con straint", + "▁constr aint", + "▁ constraint", + "Se cret", + "Sec ret", + "▁P eters", + "▁Pe ters", + "▁Peter s", + "▁Pet ers", + "▁Pete rs", + "▁ey eb", + "▁eye b", + "▁m esh", + "▁me sh", + "▁mes h", + "▁ mesh", + "▁c ookie", + "▁cook ie", + "▁ cookie", + "▁P ick", + "▁Pic k", + "▁Pi ck", + "▁n ick", + "▁ni ck", + "▁nic k", + "▁ nick", + "by e", + "b ye", + "▁sav ings", + "▁saving s", + "Tr y", + "T ry", + "py thon", + "▁p atri", + "▁pat ri", + "▁pa tri", + "▁mult ip", + "▁multi p", + "▁mul tip", + "▁ multip", + "▁k inda", + "▁kind a", + "▁kin da", + "▁' _", + "▁ '_", + "▁Fr anz", + "▁Fran z", + "▁cl oth", + "▁clo th", + "зу льта", + "▁fle et", + "▁human ity", + "re sa", + "res a", + "r esa", + "bl ob", + "blo b", + "▁T X", + "▁ TX", + "▁B uch", + "▁Bu ch", + "▁Buc h", + "▁L ond", + "▁Lo nd", + "▁val ley", + "▁m urm", + "▁mur m", + "▁mu rm", + "▁T rade", + "▁Tr ade", + "▁Tra de", + "▁Trad e", + "line width", + "▁e special", + "▁espec ial", + "up per", + "upp er", + "▁h osp", + "▁ho sp", + "▁t anto", + "▁tan to", + "▁tant o", + "▁old est", + "▁ol dest", + "▁R oose", + "▁Ro ose", + "▁h itting", + "▁hit ting", + "do g", + "d og", + "ov i", + "o vi", + "}, \r", + "} ,\r", + "▁compat ible", + "▁ compatible", + "▁We bsite", + "▁Web site", + "po ch", + "p och", + "▁B ag", + "▁Ba g", + "▁ Bag", + "▁accompl ish", + "▁accomp lish", + "Ch rist", + "as set", + "ass et", + "asse t", + "▁U ntil", + "▁Un til", + "▁ Until", + "▁g eld", + "▁ge ld", + "▁gel d", + "List en", + "Li sten", + "L isten", + "S B", + "Set up", + "ic ia", + "ici a", + "i cia", + "▁l um", + "▁lu m", + "▁jan vier", + "PA GE", + "P AGE", + "▁N u", + "/ \"", + "▁divor ce", + "Ex ecute", + "Execut e", + "Exec ute", + "De pend", + "Dep end", + "▁Scott ish", + "▁T s", + "ru ppe", + "rup pe", + "▁ref use", + "▁Ok tober", + "ij k", + "i jk", + "▁A my", + "▁Am y", + "▁di min", + "▁dim in", + "▁g ross", + "▁gr oss", + "▁gro ss", + "▁t rat", + "▁tr at", + "▁tra t", + "is ible", + "isi ble", + "mix er", + "m ixer", + "▁aut res", + "▁au tres", + "▁autre s", + "▁ autres", + "▁ne at", + "▁ot ros", + "▁otro s", + "Vo id", + "V oid", + "▁sc hol", + "▁sch ol", + "▁Wal ker", + "▁Walk er", + "▁t ube", + "▁tu be", + "▁tub e", + "olog ists", + "ologist s", + "▁г руп", + "▁гру п", + "▁h aben", + "▁hab en", + "▁ha ben", + "ub er", + "ube r", + "u ber", + "ACT IVE", + "▁Att endance", + "▁о п", + "▁bl ade", + "opl us", + "o plus", + "▁Or iginal", + "▁Origin al", + "▁ Original", + "▁manufact urer", + "as z", + "a sz", + "ât e", + "â te", + "re r", + "r er", + "▁J son", + "▁ Json", + "▁succeed ed", + "uff le", + "▁b acked", + "▁back ed", + "es ian", + "esi an", + "ti ck", + "t ick", + "Ex ternal", + "▁X IX", + "▁XI X", + "▁he arts", + "▁heart s", + "▁hear ts", + "▁По сле", + "ol u", + "o lu", + "▁ле т", + "▁ лет", + "VI CE", + "V ICE", + "ár io", + "á rio", + "▁fr aud", + "▁fra ud", + "ed u", + "e du", + "Pr imary", + "Prim ary", + "▁g aming", + "▁gam ing", + "▁ga ming", + "▁p lt", + "▁pl t", + "ig ator", + "iga tor", + "IE S", + "I ES", + "Comp iler", + "▁mon ument", + "ag em", + "age m", + "a gem", + "▁R ain", + "▁Ra in", + "▁mo ins", + "ok u", + "o ku", + "os ex", + "ose x", + "o sex", + "▁K ansas", + "▁gep ublice", + "▁J oy", + "▁Jo y", + "Sc ene", + "▁king dom", + "ri ces", + "ric es", + "rice s", + "r ices", + "▁ju in", + "▁uncomfort able", + "▁M oney", + "▁Mon ey", + "▁Mo ney", + "ob b", + "o bb", + "ex pl", + "exp l", + "str cmp", + "▁d read", + "▁dr ead", + "▁dre ad", + "rit ion", + "r ition", + "▁C hi", + "▁Ch i", + "▁demonstr ated", + "▁demonstrate d", + "▁vert ices", + "ч о", + "▁C ulture", + "▁ Culture", + "F X", + "D ictionary", + "▁D ru", + "▁Dr u", + "tr m", + "t rm", + "▁ex amine", + "▁exam ine", + "▁the rap", + "▁ther ap", + "i ème", + "ми ни", + "▁produ ces", + "▁produce s", + "▁photograph s", + "▁thread s", + "▁ threads", + "▁M I", + "▁ MI", + "▁extraord inary", + "ски м", + "ск им", + "с ким", + "▁gepublice erd", + "▁Pol and", + "▁Po land", + "▁guarante ed", + "▁guarantee d", + "R G", + "os c", + "o sc", + "ал и", + "а ли", + "▁те х", + "err no", + "sc ience", + "if fs", + "iff s", + "▁T am", + "▁Ta m", + "▁B eth", + "▁Be th", + "▁Bet h", + "▁Tr avel", + "▁Tra vel", + "▁trans late", + "▁transl ate", + "▁ translate", + "ch é", + "▁l ing", + "▁li ng", + "▁lin g", + "▁ ling", + "▁bel ongs", + "▁belong s", + "▁elect rical", + "▁electric al", + "en sk", + "ens k", + "▁Com pet", + "▁Comp et", + "c g", + "V C", + "to pic", + "top ic", + "t opic", + "▁pre sum", + "▁pres um", + "ве та", + "вет а", + "▁approxim ation", + "▁approx imation", + "▁g rim", + "▁gr im", + "▁gri m", + "▁И з", + "_{ (", + "_ {(", + "ви н", + "в ин", + "ut ion", + "uti on", + "ow ych", + "owy ch", + "å g", + "ster reich", + "▁character istic", + "om ing", + "omin g", + "omi ng", + "o ming", + "▁/* !", + "▁ /*!", + "▁pr ize", + "▁pri ze", + "▁Minn esota", + "te d", + "t ed", + "ц ы", + "▁O m", + "▁ Om", + "▁ind ices", + "▁indic es", + "▁ indices", + "▁s tem", + "▁st em", + "▁ste m", + "re gon", + "reg on", + "ни че", + "▁Sal v", + "▁Sa lv", + "és e", + "é se", + "▁a ged", + "▁ag ed", + "▁age d", + "▁ aged", + "▁P ast", + "▁Pa st", + "▁Pas t", + "▁intern ation", + "▁V ic", + "▁Vi c", + "▁res ume", + "▁ resume", + "akespe are", + "▁est ado", + "▁esta do", + "▁estad o", + "▁ab ilities", + "▁ abilities", + "▁b row", + "▁br ow", + "▁bro w", + "▁N FL", + "▁tr ends", + "▁trend s", + "▁tren ds", + "▁Aust in", + "▁L IMIT", + "▁LI MIT", + "▁ LIMIT", + "▁K or", + "▁Ko r", + "▁f olk", + "▁fol k", + "▁ folk", + "▁w ard", + "▁war d", + "▁wa rd", + "▁ ward", + "▁n est", + "▁ne st", + "▁Jun ior", + "▁Juni or", + "▁maint aining", + "▁maintain ing", + "P ub", + "OB JECT", + "▁blo ody", + "▁blood y", + "▁s j", + "▁d type", + "▁dt ype", + "▁ dtype", + "Pan e", + "P ane", + "▁b acter", + "▁grad ually", + "▁gradu ally", + "m r", + "Te am", + "▁ind icating", + "▁indic ating", + "▁decre ase", + "te k", + "t ek", + "▁Re present", + "▁Rep resent", + "▁develop ers", + "▁developer s", + "Gu id", + "Gui d", + "G uid", + "▁D iet", + "▁Die t", + "▁Di et", + "▁re tr", + "▁r etr", + "▁ret r", + "Nav igation", + "es i", + "e si", + "▁l azy", + "▁la zy", + "Stand ard", + "E r", + "A W", + "▁Ét ats", + "▁ass ured", + "▁assure d", + "Sa n", + "S an", + "▁And re", + "▁Andr e", + "’ ,", + "fa ng", + "fan g", + "f ang", + "ér ation", + "▁indust ries", + "▁in con", + "▁inc on", + "Em it", + "E mit", + "▁г де", + "▁ret riev", + "▁retr iev", + "en i", + "e ni", + "▁Tur key", + "▁Turk ey", + "iz ers", + "ize rs", + "izer s", + "An gle", + "Ang le", + "▁o c", + "▁ oc", + "▁pal m", + "▁pa lm", + "▁s tan", + "▁st an", + "▁sta n", + "▁ stan", + "ль но", + "▁C SS", + "▁CS S", + "▁ CSS", + "▁fr ances", + "▁franc es", + "▁g rin", + "▁gr in", + "▁gri n", + "▁tiem po", + "▁P rix", + "▁Pr ix", + "▁Pri x", + "]) .", + "] ).", + "▁de put", + "▁dep ut", + "▁P in", + "▁Pi n", + "▁ Pin", + "▁si xt", + "▁six t", + "▁predict ed", + "▁pred icted", + "az ure", + "azu re", + "▁Mo tor", + "▁Mot or", + "▁i hm", + "▁ih m", + "▁man us", + "ap os", + "a pos", + "▁instr uments", + "▁instrument s", + "▁co unts", + "▁coun ts", + "▁count s", + "▁aim ed", + "▁ai med", + "▁ aimed", + "pro fit", + "prof it", + "▁d ok", + "▁do k", + "об ра", + "о бра", + "▁e stud", + "▁est ud", + "ie sz", + "ies z", + "i esz", + "▁p iss", + "▁pi ss", + "▁in aug", + "▁vo ters", + "▁vote rs", + "▁vot ers", + "▁pack ages", + "▁package s", + "▁ packages", + "▁c ute", + "▁cut e", + "▁cu te", + "▁f itness", + "▁fit ness", + "▁l eurs", + "▁le urs", + "▁leur s", + "▁s orted", + "▁sort ed", + "▁sor ted", + "ph ant", + "pha nt", + "phan t", + "OP T", + "O PT", + "▁z ip", + "▁ zip", + "se ason", + "sea son", + "em i", + "e mi", + "enc oding", + "wo n", + "w on", + "el ect", + "ele ct", + "e lect", + "▁t ooth", + "▁to oth", + "▁too th", + "▁up coming", + "▁G raham", + "▁Gra ham", + "nu t", + "n ut", + "▁Ar k", + "äl t", + "ä lt", + "▁prec ious", + "ag le", + "a gle", + "né e", + "n ée", + "ни ца", + "ниц а", + "ar is", + "ari s", + "a ris", + "▁p ile", + "▁pi le", + "▁pil e", + "co le", + "col e", + "c ole", + "▁W ITH", + "▁WIT H", + "▁ WITH", + "rou ting", + "r outing", + "▁* **", + "▁** *", + "▁ ***", + "Appe arance", + "ll vm", + "▁O liver", + "▁Ol iver", + "▁P L", + "▁ PL", + "if ndef", + "et zt", + "etz t", + "sk iego", + "ski ego", + "▁p on", + "▁po n", + "▁ pon", + "AR GET", + "ARG ET", + "k ö", + "al led", + "all ed", + "alle d", + "▁= \\", + "▁ =\\", + "su re", + "sur e", + "s ure", + "mat ches", + "match es", + "▁temper atures", + "▁temperature s", + "SE L", + "S EL", + "▁cl one", + "▁clo ne", + "▁ clone", + "▁el ler", + "▁elle r", + "▁ell er", + "▁ eller", + "er na", + "ern a", + "▁п оло", + "▁по ло", + "▁пол о", + "Man agement", + "comp any", + "▁l un", + "▁lu n", + "▁stre aming", + "▁stream ing", + "▁N i", + "▁s í", + "Cont act", + "▁C redit", + "▁Cr edit", + "▁Cre dit", + "▁O ak", + "▁пред став", + "rad ius", + "cl i", + "c li", + "IE NT", + "I ENT", + "▁Lu cy", + "▁Luc y", + "▁calcul ation", + "▁calc ulation", + "▁p ixel", + "▁ pixel", + "▁m ul", + "▁mu l", + "▁ mul", + "▁out comes", + "▁outcome s", + "▁cent ers", + "▁center s", + "▁res idence", + "▁resid ence", + "Con straint", + "▁pre serve", + "▁pres erve", + "▁preserv e", + "pe on", + "uf fix", + "uff ix", + "▁Rober ts", + "▁Robert s", + "▁Rob erts", + "▁pro mot", + "▁pr omot", + "▁prom ot", + "? !", + "bal ance", + "▁cour ts", + "▁court s", + "▁dis g", + "▁di sg", + "PR INT", + "PRI NT", + "▁и х", + "el fare", + "elf are", + "▁ret reat", + "▁А в", + "Co st", + "C ost", + "al so", + "als o", + "▁F ür", + "▁Mär z", + "DI O", + "D IO", + "▁b ez", + "▁be z", + "▁ bez", + "AUT H", + "AU TH", + "De n", + "D en", + "▁a tom", + "▁at om", + "▁ atom", + "▁r oman", + "▁ro man", + "▁rom an", + "▁P el", + "▁Pe l", + "▁Roose velt", + "▁Pl ant", + "▁Plan t", + "Cont ents", + "Content s", + "▁Bet ween", + "▁cou pling", + "▁coup ling", + "str ucture", + "struct ure", + "▁Mar shall", + "▁Mars hall", + "▁Marshal l", + "▁Care er", + "▁rail way", + "▁B ureau", + "▁Bur eau", + "▁poss ibilities", + "▁k or", + "▁ko r", + "▁ kor", + "){ \r", + ") {\r", + "mer o", + "me ro", + "m ero", + "mo v", + "m ov", + "анг л", + "AI N", + "A IN", + "mu nd", + "mun d", + "m und", + "let te", + "lett e", + "l ette", + "▁sum mar", + "▁describ ing", + "▁N AS", + "▁NA S", + "▁E mb", + "▁Em b", + "▁ Emb", + "Inst ruction", + "li est", + "lie st", + "l iest", + "▁S ig", + "▁Si g", + "▁ Sig", + "Bi ll", + "B ill", + "▁v erd", + "▁ver d", + "▁ve rd", + "pl ant", + "plan t", + "▁galax ies", + "\"] )", + "\" ])", + "▁Py Object", + "▁ PyObject", + "▁G y", + "▁m ě", + "▁organ isation", + "▁organis ation", + "He r", + "H er", + "Se p", + "S ep", + "oc om", + "oco m", + "o com", + "▁S ame", + "▁Sam e", + "▁Sa me", + "▁ Same", + "▁b ite", + "▁bit e", + "▁bi te", + "▁Se attle", + "зы ва", + "Ob server", + "Observ er", + "’ .", + "▁m orph", + "▁mor ph", + "ur ches", + "urch es", + "al ph", + "re ement", + "ree ment", + "con sin", + "cons in", + "^ -", + "▁d ann", + "▁da nn", + "▁dan n", + "trans late", + "transl ate", + "ви х", + "Re act", + "▁c ats", + "▁cat s", + "▁ca ts", + "▁b rew", + "▁br ew", + "▁bre w", + "▁ brew", + "▁d s", + "▁ ds", + "▁cir cles", + "▁circ les", + "▁circle s", + "▁d rift", + "▁dr ift", + "▁dri ft", + "ag ma", + "▁Val ent", + "PI N", + "P IN", + "AR M", + "A RM", + "▁sur viv", + "▁surv iv", + "al in", + "ali n", + "a lin", + "Pr ef", + "Pre f", + "P ref", + "friend ly", + "▁uncertain ty", + "▁f d", + "▁ fd", + "▁engine er", + "Be n", + "B en", + "ic ular", + "i cular", + "or est", + "ore st", + "ores t", + "o rest", + "▁hor izontal", + "▁horizon tal", + "▁ horizontal", + "UT C", + "U TC", + "text rm", + "tex trm", + "Li ve", + "L ive", + "Sc ore", + "S core", + "▁Germ ans", + "▁German s", + "▁Ger mans", + "di stance", + "dist ance", + "d istance", + "ut i", + "u ti", + "▁é qu", + "▁ équ", + "▁numer ical", + "▁re ass", + "Act iv", + "▁c od", + "▁co d", + "▁ cod", + "bul let", + "en sing", + "ens ing", + "▁G em", + "▁Ge m", + "▁nav igation", + "▁navig ation", + "▁ navigation", + "add Class", + "▁simultane ously", + "ви й", + "▁йо го", + "▁й ого", + "▁H ö", + "▁har sh", + "prec ated", + "p recated", + "С СР", + "▁Equ ip", + "ad get", + "▁T YPE", + "▁ TYPE", + "▁m g", + "▁ mg", + "IG H", + "▁v in", + "▁vi n", + "▁ vin", + "▁fin dings", + "▁find ings", + "▁finding s", + "iv an", + "iva n", + "i van", + "▁pos session", + "▁poss ession", + "▁possess ion", + "▁т ого", + "▁то го", + "▁ того", + "▁par sed", + "▁parse d", + "▁ parsed", + "ri ors", + "rior s", + "rio rs", + "r iors", + "zeich net", + "ни ков", + "ник ов", + "Work er", + "▁en ables", + "▁enable s", + "▁( $\\", + "▁($ \\", + "▁C opy", + "▁Co py", + "▁Cop y", + "▁ Copy", + "▁orient ation", + "ст ре", + "с тре", + "▁Ind ians", + "▁India ns", + "▁Indian s", + "▁G ary", + "▁Gar y", + "▁Ga ry", + "▁Ins urance", + "is an", + "isa n", + "i san", + "Ch at", + "C hat", + "▁com un", + "▁co mun", + "▁co ron", + "▁cor on", + "ографи я", + "up dated", + "update d", + "▁И н", + "The se", + "Th ese", + "SE C", + "S EC", + "▁boy friend", + "Di agnostics", + "Hi nt", + "H int", + "mu l", + "m ul", + "▁in ode", + "▁i node", + "▁ inode", + "x A", + "ef t", + "e ft", + "OP TION", + "OPT ION", + "un ct", + "unc t", + "an non", + "ann on", + "anno n", + "EN S", + "E NS", + "st rip", + "str ip", + "stri p", + "▁enthus i", + "▁W hit", + "▁Wh it", + "▁Ф и", + "au de", + "aud e", + "a ude", + "▁disag ree", + "▁sn apped", + "▁snap ped", + "Ph ys", + "▁S yn", + "▁Sy n", + "▁s our", + "▁so ur", + "▁sou r", + "▁L ux", + "▁Lu x", + "ug ar", + "uga r", + "u gar", + "til e", + "ti le", + "t ile", + "▁in fection", + "▁inf ection", + "▁infect ion", + "▁F eb", + "▁Fe b", + "▁C hem", + "▁Ch em", + "▁Che m", + "data set", + "dat aset", + "ch ts", + "cht s", + "D ynamic", + "▁с ред", + "▁qu een", + "▁que en", + "work er", + "wor ker", + "sw ap", + "▁tim estamp", + "▁ timestamp", + "▁In tegr", + "▁Int egr", + "▁ Integr", + "▁inter views", + "▁interview s", + "su ch", + "s uch", + "▁l aughter", + "▁laugh ter", + "pro f", + "pr of", + "▁B ird", + "▁Bi rd", + "▁Bir d", + "( |", + "â n", + "▁g ra", + "▁gr a", + "▁ gra", + "& =", + "ze ns", + "zen s", + "z ens", + "get Message", + "▁O st", + "▁Os t", + "▁g ab", + "▁ga b", + "▁mort gage", + "mult icol", + "multi col", + "LE VEL", + "part ition", + "se en", + "see n", + "s een", + "▁dec lar", + "▁decl ar", + "A U", + "▁o x", + "▁ ox", + "▁l igger", + "▁lig ger", + "▁C arm", + "▁Car m", + "▁Ca rm", + "ge me", + "gem e", + "g eme", + "▁Ve gas", + "▁Veg as", + "▁E ug", + "▁Eu g", + "or us", + "o rus", + "▁b rick", + "▁br ick", + "▁as í", + "▁Mag azine", + "HasColumn Type", + "V R", + "lic her", + "li cher", + "lich er", + "liche r", + "l icher", + "▁F uture", + "▁Fut ure", + "▁ Future", + "▁J ug", + "▁Ju g", + "at tan", + "att an", + "atta n", + "con structor", + "construct or", + "V P", + "▁т ур", + "▁ту р", + "▁ тур", + "чи на", + "чин а", + "Comp arator", + "Compar ator", + "▁aut hentic", + "▁mon ster", + "▁trans formed", + "▁transform ed", + "▁firm s", + "▁fir ms", + "F W", + "▁c atalog", + "▁catal og", + "▁ catalog", + "bo ards", + "board s", + "▁dise ases", + "▁disease s", + "▁Benj amin", + "▁hor izon", + "▁Av ailable", + "▁ Available", + "M vc", + "St ud", + "▁l ord", + "▁lo rd", + "▁ lord", + "gen eral", + "gener al", + "па р", + "п ар", + "▁cab inet", + "▁cabin et", + "▁Bas ic", + "▁ Basic", + "Test Case", + "an sk", + "ans k", + "▁S now", + "▁Sn ow", + "ier ten", + "iert en", + "ierte n", + "i erten", + "▁v ocal", + "▁vo cal", + "▁voc al", + "Pad ding", + "P adding", + "ha lt", + "hal t", + "h alt", + "▁Alex and", + "▁Col omb", + "iv amente", + "iva mente", + "▁art ificial", + "▁Atl anta", + "▁m entre", + "▁men tre", + "▁ment re", + "▁est aba", + "▁estab a", + "▁esta ba", + "je kt", + "jek t", + "j ekt", + "▁sle pt", + "▁end less", + "▁endl ess", + "ér o", + "é ro", + "at tery", + "att ery", + "atter y", + "atte ry", + "uu r", + "u ur", + "▁weak ness", + "▁attempt ing", + "BY TE", + "▁found er", + "▁fo under", + "▁fou nder", + "▁sa lv", + "▁sal v", + "▁Medic ine", + "ti d", + "t id", + "▁Sch we", + "▁Schw e", + "ra ction", + "ract ion", + "r action", + "▁ ¿", + "cr ate", + "c rate", + "SER VER", + "▁comp ound", + "▁con ve", + "▁conv e", + "▁c af", + "▁ca f", + "▁hand ful", + "on ne", + "úblic a", + "▁def ensive", + "▁defens ive", + "Al ignment", + "Align ment", + "▁pr éc", + "▁pré c", + "▁signific ance", + "él é", + "é lé", + "ar ta", + "art a", + "Da m", + "D am", + "▁per pet", + "▁c aller", + "▁call er", + "▁cal ler", + "ic ients", + "ici ents", + "icient s", + "ce p", + "c ep", + "▁Mult i", + "▁Mul ti", + "▁ Multi", + "▁st olen", + "▁sto len", + "▁stole n", + "▁focus ing", + "em bed", + "emb ed", + "▁b ree", + "▁br ee", + "▁bre e", + "▁A B", + "▁ AB", + "▁occasion s", + "▁occas ions", + "se a", + "s ea", + "Pro v", + "Pr ov", + "P rov", + "че ние", + "▁C ategory", + "▁ Category", + "▁s q", + "▁ sq", + "▁Ф е", + "V A", + "Di ff", + "D iff", + "Tr i", + "T ri", + "iss ement", + "isse ment", + "▁act ress", + "▁П е", + "▁j ej", + "▁je j", + "▁tw isted", + "▁twist ed", + "▁N icol", + "▁Nic ol", + "▁Ni col", + "▁jun ior", + "▁junio r", + "▁juni or", + "So und", + "S ound", + "▁Bra sil", + "▁Bras il", + "▁ju ice", + "▁> >>", + "▁>> >", + "▁ >>>", + "▁A lb", + "▁Al b", + "▁soft ly", + "▁Mc K", + "▁G ren", + "▁Gr en", + "▁Gre n", + "▁ital iano", + "▁cre atures", + "▁creat ures", + "▁creature s", + "▁res idential", + "▁resident ial", + "▁resid ential", + "▁Inst agram", + "uck s", + "uc ks", + "u cks", + "▁k iller", + "▁kill er", + "▁kil ler", + "▁John ny", + "▁enter prise", + "D to", + "ch estra", + "che stra", + "ches tra", + "chestr a", + "▁T el", + "▁Te l", + "▁Act iv", + "▁ Activ", + "fa ctor", + "fac tor", + "fact or", + "f actor", + "ou st", + "ous t", + "o ust", + "▁vac uum", + "ра л", + "р ал", + "') ->", + "' )->", + "▁L eft", + "▁Le ft", + "▁ Left", + "▁de fect", + "▁def ect", + "▁defe ct", + "▁nine te", + "▁nin ete", + "fa re", + "far e", + "f are", + "▁reg ret", + "▁s har", + "▁sh ar", + "▁sha r", + "ctr ine", + "me sh", + "mes h", + "m esh", + "ci ty", + "cit y", + "c ity", + "ic it", + "ici t", + "i cit", + "▁F em", + "▁Fe m", + "lim ited", + "limit ed", + "ok a", + "o ka", + "!\\ !\\", + "Don ald", + "з но", + "▁pro vision", + "▁prov ision", + "▁discuss ions", + "▁discussion s", + "Dr ag", + "D rag", + "▁In cl", + "▁Inc l", + "Ex it", + "E xit", + "▁A bd", + "▁Ab d", + "st ory", + "sto ry", + "ie ve", + "iev e", + "i eve", + "▁by ł", + "ol ving", + "olv ing", + "woh ner", + "▁gu idelines", + "▁guide lines", + "▁guid elines", + "▁st raw", + "▁str aw", + "▁stra w", + "ü ss", + "▁бу ло", + "▁bur den", + "▁spat ial", + "▁stret ched", + "▁stretch ed", + "▁I nf", + "▁In f", + "▁ Inf", + "▁type def", + "▁typed ef", + "▁ro bot", + "▁rob ot", + "▁D oc", + "▁Do c", + "▁ Doc", + "pl iers", + "plier s", + "wa l", + "w al", + "ca mp", + "cam p", + "c amp", + "▁dif fé", + "▁diff é", + "▁Mc G", + "▁t el", + "▁te l", + "ar ette", + "aret te", + "▁sub sequently", + "▁subsequ ently", + "▁subsequent ly", + "▁h oney", + "▁hon ey", + "▁ho ney", + "FUN C", + "▁establish ment", + "te sy", + "tes y", + "▁któ ry", + "▁се ль", + "▁F O", + "▁ FO", + "▁Is lands", + "▁Island s", + "▁m p", + "▁ mp", + "Scal ar", + "▁Y an", + "▁Ya n", + "ck en", + "cke n", + "c ken", + "▁var iation", + "▁vari ation", + "i ą", + "op tim", + "opt im", + "az or", + "tu ple", + "t uple", + "▁gr avity", + "▁grav ity", + "▁con clude", + "▁concl ude", + "▁col lections", + "▁collection s", + "▁collect ions", + "▁colle ctions", + "és z", + "é sz", + "▁L iver", + "▁Li ver", + "▁Live r", + "▁Liv er", + "▁eth nic", + "comp ile", + "▁p arl", + "▁par l", + "▁pa rl", + "Sur face", + "{ '", + "▁par agraph", + "▁para graph", + "▁ paragraph", + "pos ite", + "po site", + "ít ulo", + "ob a", + "o ba", + "bin ary", + "b inary", + "ro b", + "r ob", + "▁Pe dro", + "▁Ped ro", + "▁f is", + "▁fi s", + "▁Gr ande", + "▁Grand e", + "▁Gran de", + "▁Gra nde", + "od ox", + "odo x", + "▁pos ting", + "▁post ing", + "< !--", + "▁rac ial", + "▁ra cial", + "CO M", + "C OM", + "ё м", + "▁A UT", + "▁AU T", + "▁ AUT", + "▁d ishes", + "▁dis hes", + "▁dish es", + "assert True", + "▁G row", + "▁Gr ow", + "▁Gro w", + "▁sl id", + "▁ju illet", + "сс о", + "с со", + "Run ner", + "Sa l", + "S al", + "Sa me", + "Sam e", + "S ame", + "▁Stud y", + "▁Col onel", + "▁J oin", + "▁Jo in", + "▁ Join", + "ar ms", + "arm s", + "▁l y", + "▁ ly", + "▁co oper", + "▁cur ves", + "▁curve s", + "▁curv es", + "He alth", + "▁M OD", + "▁MO D", + "▁ MOD", + "▁pr imo", + "▁prim o", + "▁pri mo", + "ock ets", + "ocket s", + "multi column", + "multicol umn", + "▁С ан", + "▁Са н", + "▁H unter", + "▁Hun ter", + "▁Hunt er", + "Custom er", + "ot hy", + "oth y", + "o thy", + "Des ign", + "De sign", + "ma ss", + "mas s", + "m ass", + "▁fam ille", + "▁famil le", + "▁fue ron", + "▁fu eron", + "▁fuer on", + "ä m", + "▁head quarters", + "▁d ign", + "▁di gn", + "▁dig n", + "▁Ro bin", + "▁Rob in", + "▁me ets", + "▁meet s", + "▁so it", + "па да", + "пад а", + ")\" );", + ") \");", + "▁w rapper", + "▁wrap per", + "▁ wrapper", + "▁theoret ical", + "▁u d", + "▁ ud", + "pl icity", + "plic ity", + "plicit y", + "▁w p", + "▁ wp", + "▁испо ль", + "▁c amps", + "▁camp s", + "▁cam ps", + "▁A gency", + "▁Ag ency", + "g c", + "hu m", + "h um", + "AT T", + "A TT", + "B tn", + "C ent", + "▁H elen", + "▁He len", + "▁Hel en", + "▁am plit", + "▁ampl it", + "▁Mem orial", + "und ial", + "SH IFT", + "wi k", + "w ik", + "▁Lie utenant", + "VAL ID", + "▁B ath", + "▁Ba th", + "▁Bat h", + "▁Jeff erson", + "▁C ut", + "▁Cu t", + "▁ Cut", + "▁ser vers", + "▁serv ers", + "▁server s", + "▁serve rs", + "▁ servers", + "ly ph", + "▁CO PY", + "▁COP Y", + "▁comput ers", + "▁computer s", + "▁compute rs", + "const ruction", + "construct ion", + "▁P DF", + "▁PD F", + "▁ PDF", + "▁pro tagon", + "▁prot agon", + "▁fore head", + "custom er", + "Un is", + "U nis", + "▁sign ing", + "▁sig ning", + ". ’", + "F etch", + "▁S core", + "▁Sc ore", + "▁ Score", + "hu man", + "hum an", + "h uman", + "▁down town", + "▁downt own", + "In tern", + "Int ern", + "Inter n", + "▁bes ides", + "▁beside s", + "▁д во", + "▁пра ви", + "▁ прави", + "▁c c", + "▁ cc", + "▁D ebug", + "▁De bug", + "▁Deb ug", + "▁ Debug", + "▁Cl ose", + "▁ Close", + "el ihood", + "eli hood", + "▁al gorithms", + "▁algorithm s", + "▁H amb", + "▁Ham b", + "▁Ha mb", + "ч на", + "▁c ust", + "▁cu st", + "▁mo unted", + "▁mount ed", + "par en", + "pa ren", + "pare n", + "p aren", + "▁isol ated", + "▁A gr", + "▁Ag r", + "▁or bit", + "▁orb it", + "print k", + "▁t urb", + "▁tu rb", + "▁tur b", + "▁gru po", + "ми и", + "\"\" \"", + "\" \"\"", + "▁h ills", + "▁hill s", + "ря д", + "▁B od", + "▁Bo d", + "▁об ще", + "est one", + "esto ne", + "eston e", + "e stone", + "▁satisf ying", + "▁satisfy ing", + "▁I van", + "▁Iv an", + "▁associ ate", + "name d", + "na med", + "nam ed", + "n amed", + "oc cup", + "occ up", + "GP IO", + "G PIO", + "hi t", + "h it", + "▁dis tract", + "▁di stract", + "▁dist ract", + "▁bar rel", + "▁barr el", + "▁in variant", + "di d", + "d id", + "▁l ieu", + "▁li eu", + "▁lie u", + "sc ene", + "UN K", + "▁Ont ario", + "▁M ission", + "▁Miss ion", + "zi al", + "z ial", + "▁comp ete", + "▁compet e", + "▁cou ples", + "▁couple s", + "▁coup les", + "SH A", + "S HA", + "▁s ei", + "▁se i", + "▁m igration", + "▁migr ation", + "ac ked", + "ack ed", + "▁b arn", + "▁bar n", + "▁ba rn", + "hal f", + "h alf", + "▁neigh bour", + "▁neighb our", + "ft e", + "f te", + "▁od ds", + "▁odd s", + "▁optim ization", + "▁I C", + "▁ IC", + "▁H end", + "▁He nd", + "▁Hen d", + "pay ment", + "M r", + "') :", + "' ):", + "vo ir", + "v oir", + "▁R ange", + "▁Rang e", + "▁Ran ge", + "▁ Range", + "▁polit icians", + "▁politician s", + "▁K han", + "▁Kh an", + "▁shel ter", + "▁tim ing", + "▁ti ming", + "Create d", + "Creat ed", + "C reated", + "▁sept embre", + "li t", + "l it", + "▁S hel", + "▁She l", + "▁Sh el", + "▁c ouch", + "▁co uch", + "▁cou ch", + "▁d är", + "ult ur", + "▁G iov", + "▁Gi ov", + "ô le", + "RE AM", + "▁O cean", + "▁M B", + "▁ MB", + "▁lie gt", + "▁o v", + "▁ ov", + "▁car pet", + "та р", + "т ар", + "▁го дина", + "▁годи на", + "▁S ão", + "▁о тно", + "▁от но", + "ab ling", + "abl ing", + "a bling", + "in th", + "int h", + "▁purs ue", + "▁Const itution", + "an j", + "▁F BI", + "▁ar row", + "▁arr ow", + "▁ arrow", + "ph ones", + "phone s", + "▁kn ocked", + "▁knock ed", + "▁de com", + "▁dec om", + "ie k", + "i ek", + "ь е", + "St rip", + "Str ip", + "▁V enez", + "▁Ven ez", + "▁Ve nez", + "▁p upp", + "▁pu pp", + "▁pup p", + "bi an", + "bia n", + "b ian", + "▁cot ton", + "h p", + "▁the atre", + "▁accept able", + "cuss ion", + "▁r ounds", + "▁round s", + "▁act ively", + "▁activ ely", + "▁active ly", + "▁among st", + "▁a bc", + "▁ab c", + "▁ abc", + "F M", + "Pop up", + "▁divers ity", + "us z", + "u sz", + "▁employ er", + "spec ially", + "special ly", + "▁sus pected", + "▁suspect ed", + "▁c rypt", + "▁cry pt", + "▁O scar", + "▁Os car", + "no r", + "n or", + "▁bab ies", + "во м", + "▁m undo", + "▁li bert", + "▁lib ert", + "▁liber t", + "S G", + "ah ren", + "ahr en", + "a hren", + "▁magn itude", + "T M", + "' +", + "▁об ъ", + "▁G ust", + "▁Gu st", + "▁gr ain", + "▁gra in", + "мен т", + "м ент", + "to Equal", + "▁m os", + "▁mo s", + "▁ mos", + "▁consist ently", + "▁consistent ly", + "х у", + "▁domin ant", + "Con verter", + "Convert er", + "at able", + "ata ble", + "a table", + "▁J ag", + "▁Ja g", + "scri ptions", + "script ions", + "scription s", + "s criptions", + "x B", + "▁ ©", + "fol der", + "fold er", + "f older", + "▁sub stance", + "▁subst ance", + "▁по с", + "L o", + "BU S", + "B US", + "bas ic", + "us sen", + "uss en", + "▁co ins", + "▁coin s", + ": -", + "▁N elson", + "▁Nel son", + "In ner", + "ograf ía", + "▁ex empl", + "▁exem pl", + "ch g", + "▁sy nd", + "▁syn d", + "dyn amic", + "d ynamic", + "ver ted", + "vert ed", + "▁EV ENT", + "▁ EVENT", + "se ek", + "see k", + "av ier", + "avi er", + "a vier", + "▁p rot", + "▁pro t", + "▁pr ot", + "▁ prot", + "-- ----", + "---- --", + "--- ---", + "----- -", + "- -----", + "▁con vention", + "▁conv ention", + "▁convent ion", + "▁станов ника", + "gl ing", + "g ling", + "hor a", + "ho ra", + "h ora", + "ши й", + "▁wh ilst", + "ser ialize", + "serial ize", + "s erialize", + "▁R ing", + "([ '", + "( ['", + "▁c her", + "▁ch er", + "▁che r", + "▁ cher", + "сь кі", + "▁D anny", + "▁Dan ny", + "▁re aches", + "▁reach es", + "▁el igible", + "▁P arent", + "▁Par ent", + "▁Pa rent", + "▁ Parent", + "▁came ras", + "▁cam eras", + "▁camera s", + "▁discipl ine", + "▁s illy", + "▁sil ly", + "re ts", + "ret s", + "r ets", + "yt ics", + "▁Reg ional", + "▁Region al", + "▁B aby", + "▁Ba by", + "▁Bab y", + "te le", + "t ele", + "WAR NING", + "WARN ING", + "su pp", + "sup p", + "s upp", + "▁refer ring", + "▁mer ch", + "▁merc h", + "ol ves", + "olve s", + "olv es", + "em et", + "eme t", + "e met", + "ck e", + "c ke", + "▁M unicip", + "▁Mun icip", + "Wh ite", + "▁ Ś", + "ri os", + "rio s", + "r ios", + "log ging", + "▁d x", + "▁ dx", + "▁su sp", + "▁sus p", + "ex ternal", + "▁Liber al", + "▁Lib eral", + "▁Init ialize", + "▁Initial ize", + "▁ Initialize", + "▁exhib ition", + "▁exhibit ion", + "▁ext ensions", + "▁extension s", + "▁extens ions", + "▁ extensions", + "ke eper", + "keep er", + "kee per", + "SY S", + "▁J ake", + "▁Ja ke", + "▁Jak e", + "fo oter", + "foot er", + "foo ter", + "▁ph ones", + "▁phone s", + "▁ phones", + "▁real m", + "▁contribut ed", + "▁contribute d", + "ME SS", + "▁For mat", + "▁Form at", + "▁ Format", + "Per iod", + "▁h id", + "▁hi d", + "▁ hid", + "▁me tres", + "▁met res", + "▁D im", + "▁Di m", + "▁ Dim", + "ache lor", + "achel or", + "▁T ak", + "▁Ta k", + "▁ве ли", + "▁g ram", + "▁gr am", + "▁gra m", + "▁ gram", + "▁M Y", + "▁ MY", + "on ders", + "ond ers", + "onder s", + "onde rs", + "'; \r", + "' ;\r", + "▁F ro", + "▁Fr o", + "▁advant ages", + "▁advantage s", + "io v", + "i ov", + "▁she ets", + "▁sheet s", + "ce mbre", + "c embre", + "ž e", + "] \r", + "▁D J", + "subset eq", + "UP DATE", + "▁b locked", + "▁bl ocked", + "▁block ed", + "▁pan els", + "▁pa nels", + "▁panel s", + "E A", + "nd e", + "n de", + "ê t", + "Bu l", + "B ul", + "▁m eters", + "▁me ters", + "▁met ers", + "▁meter s", + "jo ur", + "j our", + "▁rap port", + "▁rapp ort", + "▁J ak", + "▁Ja k", + "▁V AL", + "▁VA L", + "▁ VAL", + "▁p up", + "▁pu p", + "▁k a", + "▁ ka", + "for ced", + "force d", + "▁ав гу", + "ener gy", + "e nergy", + "▁V a", + "not es", + "no tes", + "note s", + "n otes", + "▁relax ed", + "C r", + "id ding", + "idd ing", + "▁def ines", + "▁define s", + "▁defin es", + "▁kiss ed", + "▁inv asion", + "▁invas ion", + "▁sc reens", + "▁screen s", + "C trl", + "▁pass engers", + "▁passenger s", + "▁Х о", + "ation ship", + "ations hip", + "per cent", + "\\ }", + "▁be ating", + "▁beat ing", + "life ray", + "lifer ay", + "▁V M", + "▁ VM", + "▁Gab riel", + "▁g allery", + "▁gall ery", + "▁Л о", + "iv ot", + "ivo t", + "▁r ental", + "▁ren tal", + "▁rent al", + "▁sh ocked", + "▁shock ed", + "▁Ste in", + "▁B h", + "▁ ло", + "Un e", + "U ne", + "ге н", + "г ен", + "▁kom mun", + "an ka", + "ank a", + "▁C ape", + "▁Cap e", + "▁Ca pe", + "Re ady", + "Read y", + "▁к ри", + "▁ кри", + "tr ag", + "tra g", + "t rag", + "Al ign", + "Ali gn", + "▁host ed", + "▁ho sted", + "▁\\ (", + "▁S ession", + "▁ Session", + "ys k", + "y sk", + "Pen ding", + "P ending", + "ellig ence", + "elli gence", + "▁Never theless", + "bit ro", + "bitr o", + "ho lm", + "hol m", + "quir y", + "▁mechan ical", + "▁D é", + "an eous", + "ane ous", + "▁psych ological", + "▁a broad", + "▁ab road", + "▁a voir", + "▁av oir", + "▁separ ation", + "▁sep aration", + "▁Haw ai", + "iej sc", + "▁N ether", + "▁Ne ther", + "▁Net her", + "▁sub tle", + "bi rd", + "b ird", + "▁mark er", + "▁mar ker", + "▁ marker", + "▁со зда", + "ва ла", + "вал а", + "▁Work ing", + "▁Wor king", + "▁h over", + "▁ho ver", + "▁ hover", + "%%%% %%%%", + "▁м ат", + "▁ма т", + "▁ мат", + "▁s oup", + "▁so up", + "▁sou p", + "Al ert", + "ch r", + "c hr", + "▁P CI", + "▁PC I", + "▁ PCI", + "▁m ús", + "ient ras", + "ien tras", + "▁St orage", + "▁Sto rage", + "▁ Storage", + "▁av ailability", + "▁op era", + "▁oper a", + "▁P roduction", + "▁Produ ction", + "▁Product ion", + "ia ne", + "ian e", + "i ane", + "▁Bet ter", + "▁B utton", + "▁But ton", + "▁ Button", + "▁Pe ace", + "▁Mor ris", + "▁s ib", + "▁si b", + "▁f iber", + "▁fi ber", + "▁fib er", + "Int ent", + "▁D esc", + "▁De sc", + "▁Des c", + "▁ Desc", + "ning en", + "n ingen", + "ze j", + "z ej", + "av an", + "ava n", + "a van", + "cover ed", + "cov ered", + "▁s yst", + "▁sy st", + "▁sys t", + "_ +", + "▁орга ни", + "▁Re lig", + "▁Rel ig", + "ци аль", + "▁s pite", + "▁sp ite", + "▁re prés", + "▁~ ~", + "▁ ~~", + "▁to xic", + "▁a pro", + "▁ap ro", + "▁apr o", + "X Y", + "▁tr ips", + "▁tri ps", + "▁trip s", + "▁pl aats", + "▁con vey", + "▁conv ey", + "▁conve y", + "Pr im", + "P rim", + "▁о ста", + "▁ос та", + "▁ост а", + "ok o", + "o ko", + "▁l obby", + "▁lob by", + "▁recommend ations", + "▁recommendation s", + "SP ACE", + "▁overwhel ming", + "ennes see", + "▁ac quire", + "▁acqu ire", + "w m", + "LOB AL", + "▁D EF", + "▁DE F", + "▁ DEF", + "je r", + "j er", + "▁re cur", + "▁rec ur", + "om men", + "omm en", + "▁j og", + "▁jo g", + "▁n ast", + "▁na st", + "▁nas t", + "▁L P", + "▁ LP", + "jo n", + "j on", + "▁w ishes", + "▁wish es", + "▁wis hes", + "▁N ancy", + "▁support ers", + "▁supp orters", + "^{ -\\", + "^{- \\", + "▁T rib", + "▁Tr ib", + "▁Tri b", + "▁ Ä", + "▁disappoint ed", + "▁у ни", + "x D", + "li nt", + "lin t", + "l int", + "I p", + "▁Islam ic", + "än de", + "änd e", + "ä nde", + "end ment", + "dt ype", + "d type", + "▁di gest", + "▁dig est", + "▁Set tings", + "▁Setting s", + "▁ Settings", + "ér a", + "é ra", + "▁aggress ive", + "▁intellig ent", + "eder börd", + "ster dam", + "pc i", + "p ci", + "▁over flow", + "▁ overflow", + "im b", + "i mb", + "re ach", + "rea ch", + "r each", + "cept or", + "cep tor", + "▁yield s", + "▁Se bast", + "▁ut ility", + "▁util ity", + "▁р и", + "▁ ри", + "▁fac ulty", + "▁In ternal", + "▁Intern al", + "▁Inter nal", + "▁ Internal", + "▁attract ed", + "▁attra cted", + "рі в", + "р ів", + "▁mix ing", + "▁R uth", + "▁Ru th", + "▁esc aped", + "▁escape d", + "▁E asy", + "▁dr ain", + "▁r ings", + "▁ring s", + "▁ rings", + "qu ire", + "quir e", + "Av ailable", + "▁ц и", + "▁ ци", + "▁conv ince", + "▁convin ce", + "or sch", + "ors ch", + "ут бо", + "CP P", + "C PP", + "ra ge", + "rag e", + "r age", + "ч і", + "▁p rod", + "▁pro d", + "▁pr od", + "▁ prod", + "▁p ig", + "▁pi g", + "▁C atal", + "▁Cat al", + "▁Ca tal", + "▁al ias", + "▁ali as", + "▁ alias", + "▁че мпи", + "▁чем пи", + "Pl ace", + "P lace", + "▁g orge", + "▁depend ence", + "▁cr uel", + "▁cru el", + "▁ther mal", + "▁therm al", + "ut down", + "ref resh", + "▁re sort", + "▁res ort", + "▁S HA", + "▁SH A", + "▁ SHA", + "ти й", + "fo od", + "foo d", + "f ood", + "▁N ad", + "▁Na d", + "▁pregn ancy", + "▁pro jection", + "▁project ion", + "▁pa ís", + "▁полу чи", + "▁the mes", + "▁them es", + "▁theme s", + "▁fun eral", + "▁cas o", + "▁ca so", + "ле кт", + "лек т", + "Ex tra", + "Ext ra", + "▁t issue", + "▁dr agon", + "▁drag on", + "▁l ig", + "▁li g", + "▁ lig", + "▁n ei", + "▁ne i", + "▁com edy", + "▁come dy", + "▁comed y", + "те м", + "т ем", + "сла в", + "с лав", + "▁pass enger", + "Cl one", + "i ção", + "yg on", + "y gon", + "▁H alf", + "▁Hal f", + "▁la bour", + "▁lab our", + "▁vill ages", + "▁village s", + "▁ві й", + "▁О т", + "▁L isa", + "▁Li sa", + "▁Lis a", + "_ [", + "ba g", + "b ag", + "▁d iver", + "▁di ver", + "▁div er", + "▁dive r", + "▁M L", + "▁ ML", + "▁transl ated", + "▁translate d", + "▁per ò", + "ab ama", + "aba ma", + "▁cas tle", + "▁cast le", + "▁ castle", + "* \\", + "▁reg ia", + "!! !!", + "!!! !", + "! !!!", + "*> (", + "* >(", + "▁Work s", + "▁Wor ks", + "▁N ature", + "▁Nat ure", + "▁Natur e", + "NE L", + "N EL", + "▁P om", + "▁Po m", + "tt a", + "t ta", + "▁Jam ie", + "▁p unch", + "▁pun ch", + "tain ment", + "▁K rieg", + "▁Kr ieg", + "▁restr icted", + "▁restrict ed", + "mob ile", + "m obile", + "▁grand mother", + "Arg uments", + "Argument s", + "▁s inc", + "▁si nc", + "▁sin c", + "▁Mon th", + "▁Mont h", + "▁ Month", + "esc ape", + "e scape", + "▁opt ical", + "▁L ane", + "▁La ne", + "▁Lan e", + "▁Deutsch land", + "▁S aison", + "▁Sa ison", + "▁V irtual", + "▁ Virtual", + "pe z", + "p ez", + "In line", + "ow any", + "owa ny", + "rad io", + "r adio", + "ö ß", + "▁O thers", + "▁Other s", + "MA IN", + "M AIN", + "sc al", + "s cal", + "▁D allas", + "▁Dal las", + "▁an chor", + "▁anc hor", + "▁anch or", + "▁ anchor", + "en cias", + "enc ias", + "encia s", + "enci as", + "▁re porter", + "▁rep orter", + "▁report er", + "▁veget ables", + "▁enforce ment", + "▁Wis consin", + "▁con dem", + "▁cond em", + "▁e b", + "▁ eb", + "▁s its", + "▁sit s", + "▁si ts", + "▁calcul ations", + "▁calculation s", + "▁calc ulations", + "▁\" --", + "▁\"- -", + "ue lle", + "uel le", + "u elle", + "▁tip o", + "▁ti po", + "▁P AR", + "▁PA R", + "▁ PAR", + "co rd", + "cor d", + "c ord", + "▁ро ків", + "ph an", + "pha n", + "p han", + "▁kon nte", + "▁z ap", + "▁za p", + "wr iting", + "writ ing", + "en gu", + "eng u", + "▁pert urb", + "Fac e", + "F ace", + "ag og", + "ago g", + "▁De cl", + "▁Dec l", + "▁ Decl", + "est ly", + "▁War ren", + "▁H ills", + "▁Hill s", + "▁Hil ls", + "▁ref resh", + "▁refr esh", + "▁refres h", + "▁ refresh", + "▁fl ip", + "io p", + "i op", + "▁key board", + "is to", + "ist o", + "i sto", + "▁prom oted", + "▁promote d", + "▁promot ed", + "back s", + "ba cks", + "b acks", + "Enc oding", + "▁ ال", + "▁g min", + "ро б", + "р об", + "▁follow ers", + "▁p epper", + "um ble", + "umb le", + "▁sp ray", + "▁spr ay", + "▁dr ives", + "▁dri ves", + "▁driv es", + "▁drive s", + "P ush", + "cook ie", + "c ookie", + "▁gel dig", + "▁geld ig", + "ig ung", + "igu ng", + "vis it", + "▁at omic", + "▁atom ic", + "▁ atomic", + "▁A thlet", + "▁Ath let", + "▁Or igin", + "▁Ori gin", + "▁ Origin", + "▁H appy", + "▁G ra", + "▁Gr a", + "▁att ribut", + "▁п ов", + "▁по в", + "▁ пов", + "▁n ost", + "▁no st", + "▁nos t", + "▁ nost", + "ur u", + "u ru", + "▁Ne ither", + "▁ma ar", + "ject ions", + "je ctions", + "jection s", + "▁re nov", + "▁ren ov", + "fin ity", + "f inity", + "gener ic", + "init ialize", + "initial ize", + "pgf set", + "▁hyp othes", + "▁ma cro", + "▁mac ro", + "ma ps", + "map s", + "m aps", + "▁f are", + "▁far e", + "▁fa re", + "▁ fare", + "Be st", + "B est", + "uch t", + "uc ht", + "u cht", + "co d", + "c od", + "▁h orm", + "▁hor m", + "▁ho rm", + "▁P oll", + "▁Pol l", + "▁Po ll", + "▁host ing", + "▁Re ading", + "▁Read ing", + "Cert ificate", + "▁и ма", + "▁им а", + "▁C ov", + "▁Co v", + "▁P red", + "▁Pr ed", + "▁Pre d", + "▁ Pred", + "re direct", + "red irect", + "▁l attice", + "▁port folio", + "▁o ven", + "▁ov en", + "▁ oven", + "ie len", + "iel en", + "iele n", + "i elen", + "sub scribe", + "foot note", + "но ю", + "▁mom ento", + "▁moment o", + "▁d ich", + "▁di ch", + "▁dic h", + "▁ent ert", + "▁enter t", + "▁g é", + "▁connect ing", + "▁n acional", + "▁o tt", + "▁ot t", + "▁ ott", + "ні в", + "н ів", + "▁rac ist", + "▁penal ty", + "ül t", + "ü lt", + "▁Israel i", + "▁( †", + "▁desc end", + "▁ос іб", + "▁b elly", + "▁bel ly", + "▁bell y", + "ні сть", + "▁encounter ed", + "T ip", + "▁gu ilt", + "▁d amp", + "▁da mp", + "▁dam p", + "ze ug", + "▁Mem ory", + "▁ Memory", + "Check ed", + "▁Sh akespeare", + "hi ll", + "h ill", + "▁w oke", + "▁wo ke", + "▁sal ary", + "eth eless", + "ethe less", + "e theless", + "▁Т и", + "er de", + "erd e", + "▁He in", + "▁g it", + "▁gi t", + "▁ git", + "=\" \"", + "= \"\"", + "ül l", + "ü ll", + "ge ben", + "geb en", + "g eben", + "Pr es", + "Pre s", + "P res", + "ie val", + "iev al", + "i eval", + "mark er", + "mar ker", + "▁д ан", + "▁да н", + "▁ дан", + "▁oct obre", + "RO L", + "R OL", + "▁jan u", + "▁ja nu", + "▁) :", + "▁ ):", + "br anch", + "▁J erry", + "▁Jer ry", + "ke hr", + "▁contr acts", + "▁contract s", + "▁aff air", + "▁Росси и", + "ja ck", + "j ack", + "AN G", + "A NG", + "▁dro pping", + "▁drop ping", + "▁d ic", + "▁di c", + "sch ool", + "▁Fin land", + "▁d ort", + "▁do rt", + "▁K ings", + "▁King s", + "▁Kin gs", + "▁Arg ument", + "▁ Argument", + "▁Sim ilarly", + "▁Similar ly", + "▁V erm", + "▁Ver m", + "▁Ve rm", + "▁pret end", + "! _", + "łu g", + "ł ug", + "же ння", + "жен ня", + "da ting", + "dat ing", + "d ating", + "cs v", + "c sv", + "▁dialog ue", + "▁dial ogue", + "STR U", + "▁public ly", + "wed ge", + "w edge", + "▁H och", + "▁Ho ch", + "▁spe aks", + "▁speak s", + "▁compens ation", + "an ca", + "anc a", + "text tt", + "▁Fil ter", + "▁ Filter", + "▁part ly", + "▁us eless", + "▁use less", + "▁г у", + "▁ гу", + "▁d eter", + "▁de ter", + "▁det er", + "IE W", + "▁con secut", + "▁cons ecut", + "▁conse cut", + "▁h oly", + "▁hol y", + "▁ho ly", + "▁grad uated", + "▁gradu ated", + "▁graduate d", + "an dal", + "and al", + "anda l", + "ți e", + "ț ie", + "▁W ant", + "▁Wa nt", + "▁Aust ria", + "or den", + "ord en", + "fr ag", + "f rag", + "▁f oo", + "▁fo o", + "▁ foo", + "cl aimed", + "claim ed", + "во е", + "▁not able", + "▁no table", + "▁journal ist", + "▁M ail", + "▁Ma il", + "▁Mai l", + "▁ Mail", + "!( \"", + "! (\"", + "ps e", + "p se", + "▁C lay", + "▁Cl ay", + "iv i", + "i vi", + "▁sc ales", + "▁scale s", + "▁scal es", + "▁er ste", + "▁erst e", + "▁ers te", + "Data Type", + "▁D iam", + "▁Di am", + "í r", + "loc ale", + "local e", + "▁rel uct", + "ien st", + "iens t", + "ast ro", + "astr o", + "act ly", + "я х", + "▁Vill age", + "▁Villa ge", + "▁Vil lage", + "▁d aughters", + "▁daughter s", + "▁manufact urers", + "▁manufacturer s", + "▁print ing", + "▁prin ting", + "ч ка", + "Nd Ex", + "Ch anges", + "Change s", + "▁/ ******/", + "ver tex", + "vert ex", + "▁b rows", + "▁br ows", + "▁bro ws", + "▁brow s", + "▁K ö", + "not ations", + "notation s", + "▁i ls", + "▁il s", + "▁ ils", + "at el", + "ate l", + "C ir", + "▁meaning ful", + "q a", + "▁C old", + "▁Col d", + "▁Co ld", + "ue to", + "u eto", + "you r", + "yo ur", + "y our", + "m f", + "мо в", + "м ов", + "▁Ü ber", + "▁fam ilia", + "▁famil ia", + "▁ste ep", + "▁pres idential", + "▁president ial", + "▁presid ential", + "▁z á", + "▁ zá", + "▁w ars", + "▁war s", + "▁wa rs", + "▁C re", + "▁Cr e", + "▁after wards", + "▁afterward s", + "ha lb", + "hal b", + "▁strugg led", + "▁struggle d", + "Ch art", + "Char t", + "User Id", + "ac ular", + "a cular", + "iv ia", + "ivi a", + "i via", + "▁u gly", + "▁K unst", + "E s", + "▁Q String", + "▁C ow", + "▁Co w", + "Rad ius", + "▁Gr iff", + "▁V as", + "▁Va s", + "HA L", + "H AL", + "Mod ified", + "ra le", + "ral e", + "r ale", + "mem cpy", + "▁в клю", + "▁r s", + "▁ rs", + "▁h alt", + "▁ha lt", + "▁hal t", + "▁ halt", + "▁Miss iss", + "▁h uvud", + "ec a", + "e ca", + "▁Jahrhund ert", + "E urope", + "Sign ature", + "▁grand father", + "▁O regon", + "gu e", + "g ue", + "xy gen", + "fr ames", + "frame s", + "▁hab its", + "▁ha bits", + "▁habit s", + "Support ed", + "Supp orted", + "▁low ered", + "▁lower ed", + "▁rad iation", + "▁radi ation", + "ab en", + "abe n", + "a ben", + "▁Pro gress", + "▁ Progress", + "▁C osta", + "▁Co sta", + "▁Cost a", + "▁Cos ta", + "▁dev oted", + "▁gest ure", + "▁Dez ember", + "▁qu oted", + "▁quote d", + "▁quot ed", + "▁difficult ies", + "т ре", + "▁sustain able", + "▁d ense", + "▁den se", + "▁dens e", + "▁ih rer", + "▁ihr er", + "▁ihre r", + "▁firm ly", + "â t", + "om ent", + "ome nt", + "omen t", + "o ment", + "▁c out", + "▁co ut", + "▁cou t", + "▁ cout", + "▁p oi", + "▁po i", + "d jango", + "▁pro found", + "▁prof ound", + "▁Wil helm", + "▁fl ush", + "▁flu sh", + "▁ flush", + "▁av ril", + "LA B", + "L AB", + "▁B row", + "▁Br ow", + "▁Bro w", + "▁pro pose", + "▁prop ose", + "▁propos e", + "▁r anks", + "▁ran ks", + "▁rank s", + "WI D", + "W ID", + "▁mut ual", + "▁text s", + "▁tex ts", + "▁S ale", + "▁Sal e", + "▁Sa le", + "▁qu asi", + "▁n og", + "▁no g", + "▁ nog", + "▁nouve au", + "▁c v", + "▁ cv", + "▁no ble", + "▁nob le", + "▁dé cembre", + "▁déc embre", + "▁cl ever", + "▁cle ver", + "▁P ir", + "▁Pi r", + "▁graph ics", + "▁graphic s", + "▁ graphics", + "▁G R", + "▁ GR", + "че ской", + "▁s ag", + "▁sa g", + "ict ions", + "iction s", + "i ctions", + "na nt", + "nan t", + "n ant", + "▁th é", + "C G", + "▁Jac ques", + "W M", + "▁F inn", + "▁Fin n", + "▁Fi nn", + "▁dev ast", + "зо м", + "хо в", + "х ов", + "▁En tre", + "▁Ent re", + ". ;", + "▁fl uct", + "▁flu ct", + "▁Sc iences", + "▁Sci ences", + "▁Science s", + "▁т у", + "▁ ту", + "path s", + "pat hs", + "▁sh orter", + "▁short er", + "▁suggest ion", + "ER Y", + "▁D ire", + "▁Di re", + "▁Dir e", + "at eurs", + "ate urs", + "ateur s", + "▁round ed", + "▁t art", + "▁tar t", + "▁ta rt", + "ю ще", + "up er", + "u per", + "▁secret s", + "▁sec rets", + "▁secre ts", + "▁compan ion", + "▁K EY", + "▁ KEY", + "T ile", + "▁B ibli", + "x s", + "▁ang ular", + "▁ angular", + "pa g", + "p ag", + "er ness", + "ern ess", + "erne ss", + "▁S orry", + "▁Sor ry", + "▁ Sorry", + "▁pre diction", + "▁predict ion", + "▁pred iction", + "▁M aking", + "▁Ma king", + "▁Mak ing", + "на род", + "ol are", + "ola re", + "olar e", + "rp c", + "r pc", + "▁t ens", + "▁te ns", + "▁ten s", + "en as", + "ena s", + "e nas", + "▁Re ally", + "▁Real ly", + "H I", + "port al", + "por tal", + "▁for me", + "▁form e", + "gan g", + "ga ng", + "g ang", + "▁l ane", + "▁la ne", + "▁lan e", + "▁ lane", + "▁s tag", + "▁st ag", + "▁sta g", + "▁Mar x", + "▁Ma rx", + "▁L LC", + "▁LL C", + "▁d are", + "▁da re", + "▁dar e", + "▁Olymp ic", + "▁p ant", + "▁pan t", + "▁pa nt", + "build ing", + "; ;", + "▁c ops", + "▁co ps", + "▁cop s", + "▁r ushed", + "▁rush ed", + "▁rus hed", + "▁L ot", + "▁Lo t", + "▁init iative", + "▁initi ative", + "▁inv ite", + "▁Saf ety", + "▁Safe ty", + "FA ILED", + "FAIL ED", + "▁habit ants", + "en sen", + "ens en", + "ense n", + "▁l ég", + "▁W elcome", + "▁Wel come", + "Valid ate", + "▁qu atre", + "▁G ray", + "▁Gr ay", + "▁Gra y", + "▁E ve", + "▁Ev e", + "▁C omb", + "▁Com b", + "▁Co mb", + "▁ Comb", + "▁p endant", + "a qu", + "con figure", + "config ure", + "▁A dm", + "▁Ad m", + "▁rif le", + "▁Exper ience", + "Decl aration", + "▁å r", + "▁ år", + "ill ery", + "ille ry", + "iller y", + "os pel", + "osp el", + "▁A rena", + "▁Ar ena", + "▁Are na", + "▁bo ards", + "▁board s", + "▁ boards", + "▁pur ple", + "▁p ills", + "▁pil ls", + "▁pill s", + "ueto oth", + "li que", + "l ique", + "▁pop ulations", + "▁population s", + "▁popul ations", + "▁acc ent", + "▁ac cent", + "▁r anges", + "▁range s", + "▁ran ges", + "▁rang es", + "▁Anal ysis", + "▁ Analysis", + "▁d ictionary", + "▁Dr agon", + "▁Drag on", + "re ction", + "rect ion", + "r ection", + "▁vis itor", + "▁visit or", + "seg ment", + "▁д р", + "▁F uck", + "▁Fu ck", + "д ж", + "▁ident ification", + "Class Name", + "boot strap", + "▁sur faces", + "▁surface s", + "▁surf aces", + "▁scream ing", + "кт у", + "к ту", + "pl ain", + "sh adow", + "incl udes", + "include s", + "▁j azz", + "▁ja zz", + "▁á l", + "▁ ál", + "ri ka", + "rik a", + "r ika", + "ho p", + "h op", + "▁i on", + "▁io n", + "▁ ion", + "vr e", + "v re", + "▁newsp apers", + "▁newspaper s", + "▁i hn", + "▁ih n", + "▁P arse", + "▁Par se", + "▁Pars e", + "▁ Parse", + "П о", + "▁strict ly", + "▁re covered", + "▁recover ed", + "▁U na", + "▁Un a", + "▁err e", + "▁er re", + "▁ erre", + "iss ues", + "issue s", + "▁exp ense", + "че ния", + "▁do nc", + "▁don c", + "Bi n", + "B in", + "▁Com ment", + "▁Comm ent", + "▁ Comment", + "▁sac rifice", + "▁sacrific e", + "T uple", + "() [", + "( )[", + "▁tra vers", + "▁trav ers", + "Im p", + "I mp", + "J e", + "▁Lin ux", + "▁е ё", + "▁P i", + "▁ Pi", + "▁cur ios", + "▁cu rios", + "▁r age", + "▁rag e", + "▁ra ge", + "▁ rage", + "▁e scal", + "▁es cal", + "▁esc al", + "▁al ignment", + "▁align ment", + "▁pent ru", + "▁cur r", + "▁cu rr", + "▁ curr", + "▁b este", + "▁be ste", + "▁best e", + "▁bes te", + "[] ,", + "[ ],", + "▁// !", + "H ub", + "Vis ibility", + "▁A sk", + "▁As k", + "ab ul", + "a bul", + "co lon", + "col on", + "colo n", + "▁D ays", + "▁Day s", + "▁Da ys", + "Aut hentication", + "ві т", + "▁l od", + "▁lo d", + "xF C", + "x FC", + "Look up", + "js ce", + "Al pha", + "▁harm ony", + "▁harmon y", + "▁W ard", + "▁War d", + "▁Wa rd", + "trans fer", + "▁H orn", + "▁Hor n", + "▁Ho rn", + "▁s d", + "▁ sd", + "so ap", + "▁z ich", + "▁Con sole", + "▁Cons ole", + "▁ Console", + "▁ко ли", + "▁Ph one", + "▁ Phone", + "pa per", + "p aper", + "й н", + "▁z m", + "▁ zm", + "Do ne", + "Don e", + "D one", + "ph ase", + "pha se", + "phas e", + "▁Jul ia", + "▁Ju lia", + "▁Juli a", + "▁ed ited", + "▁edit ed", + "af fe", + "aff e", + "Sy ntax", + "yl l", + "y ll", + "▁Lu cas", + "▁Luc as", + "▁and eren", + "▁andere n", + "▁ander en", + "[ <", + "▁Data base", + "▁Dat abase", + "▁ Database", + "▁spect ral", + "▁spectra l", + "ass ador", + "ска та", + "с ката", + "▁import ante", + "▁important e", + "▁х а", + "▁ ха", + "t z", + "▁s tere", + "▁st ere", + "▁ste re", + "▁ster e", + "▁m elt", + "▁me lt", + "▁mel t", + "▁C row", + "▁Cr ow", + "▁Cro w", + "ш ка", + "it utes", + "itut es", + "itute s", + "itu tes", + "▁satisf ies", + "▁L iga", + "▁Li ga", + "▁t omb", + "▁to mb", + "▁tom b", + "▁f ühr", + "▁ führ", + "▁sol ely", + "▁sole ly", + "▁E ither", + "▁t ennis", + "▁ten nis", + "▁s igh", + "▁si gh", + "▁sig h", + "ser de", + "s erde", + "ub a", + "u ba", + "ę d", + "le z", + "l ez", + "Fac t", + "F act", + "▁sque ez", + "▁Thom pson", + "▁N L", + "▁ NL", + "▁P ara", + "▁Par a", + "▁Pa ra", + "▁? ?", + "▁ ??", + "▁fin ishing", + "▁finish ing", + "She et", + "S heet", + "LIN K", + "L INK", + "▁б ро", + "▁ бро", + "▁l over", + "▁lo ver", + "▁love r", + "▁lov er", + "m achine", + "▁L esser", + "▁Les ser", + "▁Less er", + "pon d", + "po nd", + "p ond", + "▁pain tings", + "▁paint ings", + "▁painting s", + "▁assum ptions", + "▁assumption s", + "▁mod ification", + "fr e", + "f re", + "▁U lt", + "▁Ul t", + "▁A F", + "▁ AF", + "R V", + "bin ding", + "bind ing", + "b inding", + "▁toile t", + "ra r", + "r ar", + "▁an ge", + "▁ang e", + "▁ ange", + "▁she ep", + "PRO TO", + "act ic", + "a ctic", + "▁S peed", + "▁Sp eed", + "▁Spe ed", + "▁ Speed", + "▁I ce", + "gn u", + "g nu", + "ow ned", + "own ed", + "Sub scription", + "yr ics", + "y rics", + "▁back ward", + ">\" .", + "> \".", + "pi t", + "p it", + "▁real istic", + "öff ent", + "az i", + "a zi", + "DE R", + "D ER", + "b ucket", + "én y", + "é ny", + "xF E", + "x FE", + "▁f ancy", + "▁fan cy", + "ex cept", + "▁S ul", + "▁Su l", + "▁l aser", + "▁la ser", + "▁las er", + "Mon itor", + "▁c omic", + "▁com ic", + "▁co mic", + "▁Arch itect", + "▁ex pr", + "▁exp r", + "▁ expr", + "ount ers", + "oun ters", + "ounter s", + "▁Mel bourne", + "com plex", + "comp lex", + "'. $", + "' .$", + "om ot", + "omo t", + "o mot", + "▁M enu", + "▁Me nu", + "▁Men u", + "▁ Menu", + "astic search", + "▁ed iting", + "▁edit ing", + "Pre sent", + "Pres ent", + "P resent", + "op les", + "ople s", + "opl es", + "o ples", + "è ncia", + "▁в то", + "gl ise", + "she et", + "s heet", + "▁he lic", + "▁hel ic", + "▁str anger", + "▁strange r", + "▁strang er", + "▁ex ec", + "▁ exec", + "FE R", + "F ER", + "in ian", + "ini an", + "SET TING", + "▁M ix", + "▁Mi x", + "▁ Mix", + "▁com plain", + "▁compl ain", + "▁in crement", + "▁incre ment", + "CS S", + "C SS", + "mm a", + "m ma", + "sl ide", + "▁про тив", + "▁проти в", + "▁Lim ited", + "Con sole", + "Cons ole", + "▁eng aging", + "ul er", + "ule r", + "u ler", + "▁O ptions", + "▁Option s", + "▁Opt ions", + "▁ Options", + "▁l ens", + "▁le ns", + "▁len s", + "Ma il", + "M ail", + "▁bar rier", + "▁barr ier", + "trans port", + "▁c ups", + "▁cu ps", + "▁cup s", + "it err", + "ite rr", + "iter r", + "▁const ants", + "▁constant s", + "▁ constants", + "▁T ech", + "▁Te ch", + "iz io", + "izi o", + "сту па", + "ступ а", + "▁Sw eden", + "at hon", + "ath on", + "a thon", + "▁M agn", + "▁Mag n", + "▁Ma gn", + "trans ition", + "де ла", + "es k", + "e sk", + "So ft", + "S oft", + "fun ctions", + "function s", + "ne a", + "n ea", + "Im plement", + "Impl ement", + "Imp lement", + "ev ery", + "ever y", + "eve ry", + "e very", + "▁Man ufact", + "▁improve ments", + "▁improvement s", + "▁Ind iana", + "▁India na", + "▁Indian a", + "▁host s", + "▁ho sts", + "C V", + "We st", + "W est", + "to wn", + "t own", + "can vas", + "▁ш ко", + "▁Col umn", + "▁ Column", + "▁Par ker", + "▁Park er", + "▁es pa", + "▁esp a", + "▁Pub lish", + "▁которы й", + "av is", + "avi s", + "a vis", + "▁Z w", + "▁emphas is", + "ol v", + "o lv", + "▁re curs", + "▁rec urs", + "▁recur s", + "it aire", + "ita ire", + "▁B ishop", + "▁Bi shop", + "▁Bis hop", + "ne ro", + "ner o", + "n ero", + "▁d eny", + "▁de ny", + "▁den y", + "▁do ub", + "▁dou b", + "peon ato", + "▁C ourse", + "▁Cour se", + "▁Que ens", + "▁Queen s", + "▁bl ur", + "el ed", + "ele d", + "e led", + "iz o", + "i zo", + "▁dé but", + "▁Mod ule", + "▁Mo dule", + "▁ Module", + "▁anx ious", + "▁st are", + "▁star e", + "▁sta re", + "▁Pro position", + "▁K u", + "▁i c", + "▁ ic", + "Per cent", + "Qu ant", + "▁И сто", + "▁h ex", + "▁he x", + "▁ hex", + "ass oci", + "asso ci", + "▁arrang ement", + "▁arrange ment", + "▁bo ats", + "▁boat s", + "Un d", + "U nd", + "▁sl ots", + "▁slot s", + "се н", + "с ен", + "necess ary", + "▁app earing", + "▁appe aring", + "▁appear ing", + "▁R ule", + "▁Ru le", + "▁ Rule", + "▁G T", + "▁ GT", + "For ce", + "et to", + "ett o", + "e tto", + "ze nia", + "zen ia", + "▁o uts", + "▁out s", + "▁ou ts", + "▁ outs", + "▁vari ations", + "▁variation s", + "▁wh ites", + "▁white s", + "▁g lo", + "▁gl o", + "▁B R", + "▁ BR", + "ic ky", + "ick y", + "▁j ury", + "▁ju ry", + "▁jur y", + "▁treat ments", + "▁treatment s", + "▁The ater", + "kn ow", + "k now", + "▁pro files", + "▁prof iles", + "▁profile s", + "▁con spir", + "▁class room", + "▁B ass", + "▁Bas s", + "▁Ba ss", + "▁law yers", + "▁lawyer s", + "v ue", + "▁A rc", + "▁Ar c", + "▁ Arc", + "▁s la", + "▁sl a", + "▁att ending", + "▁attend ing", + "n x", + "m x", + "TO P", + "T OP", + "▁b ored", + "▁bo red", + "▁bore d", + "▁bor ed", + "pre vious", + "prev ious", + "r w", + "pt ic", + "љ у", + "▁app ar", + "▁ap par", + "▁P ont", + "▁Po nt", + ": _", + "ii i", + "i ii", + "▁j erk", + "▁jer k", + "hed ral", + "сс а", + "с са", + "▁Pr ize", + "▁Pri ze", + "▁Р и", + "б ре", + "▁hand les", + "▁handle s", + "▁j ak", + "▁ja k", + "▁Afghan istan", + "▁b oring", + "▁bo ring", + "▁bor ing", + "if ik", + "ifi k", + "▁sh ade", + "▁sha de", + "air o", + "ai ro", + "a iro", + "od ay", + "oda y", + "o day", + "▁pl ates", + "▁plate s", + "▁plat es", + "▁Championship s", + "▁Champion ships", + "▁che eks", + "▁cheek s", + "ri ke", + "rik e", + "r ike", + "▁kön nen", + "▁app le", + "▁ap ple", + "▁appl e", + "▁ apple", + "▁Ed die", + "▁Edd ie", + "▁s od", + "▁so d", + "▁tr ains", + "▁tra ins", + "▁train s", + "pan ic", + "pa nic", + "▁Ad vent", + "▁Adv ent", + "ub re", + "u bre", + "▁d å", + "▁S ymbol", + "▁Sym bol", + "▁ Symbol", + "▁с те", + "▁ст е", + "▁ сте", + "Sa m", + "S am", + "inher it", + "cam era", + "▁c ours", + "▁co urs", + "▁cour s", + "▁cou rs", + "▁make up", + "re gex", + "reg ex", + "▁U E", + "▁ UE", + "▁Det roit", + "▁W eight", + "▁We ight", + "▁ Weight", + "▁P iet", + "▁Pi et", + "▁a ria", + "▁ar ia", + "▁ aria", + "DI RECT", + "DIR ECT", + "ace ae", + "▁In fo", + "▁Inf o", + "▁ Info", + "an ya", + "any a", + "back end", + "▁T ennessee", + "pi cker", + "pic ker", + "pick er", + "p icker", + "▁Le o", + "▁P oss", + "▁Po ss", + "▁Pos s", + "pr ises", + "prise s", + "▁m ature", + "▁mat ure", + "сь ких", + "▁F ant", + "▁Fa nt", + "Re ason", + "▁m oy", + "▁mo y", + "▁B aker", + "▁Ba ker", + "▁Bak er", + "▁sub set", + "▁subs et", + "▁ subset", + "▁Stan ley", + "▁el even", + "▁ele ven", + "▁elev en", + "ol ate", + "ola te", + "o late", + "▁fort une", + "Status Code", + "▁ent ities", + "▁ entities", + "▁Ok ay", + "▁ Okay", + "ц о", + "an os", + "ano s", + "a nos", + "rel ative", + "▁order ing", + "▁ord ering", + "▁No body", + "▁Nob ody", + "▁str len", + "▁ strlen", + "▁r ope", + "▁ro pe", + "▁cig arette", + "hol ds", + "hold s", + "h olds", + "ir able", + "ira ble", + "value Of", + "St ub", + "▁phot ography", + "▁photograph y", + "es tra", + "est ra", + "estr a", + "e stra", + "▁cult ures", + "▁culture s", + "▁decl aration", + "▁declar ation", + "mer cial", + "LI ED", + "au te", + "aut e", + "a ute", + "al ter", + "alt er", + "Sub mit", + "▁Mag ic", + "▁r hythm", + "Pay ment", + "ni h", + "n ih", + "▁inter section", + "l é", + "EN TRY", + "/ )", + "▁m og", + "▁mo g", + "ru st", + "rus t", + "r ust", + "▁threat s", + "▁Mil itary", + "ap or", + "a por", + "▁s igu", + "▁si gu", + "▁sig u", + "set minus", + "▁I ng", + "▁In g", + "st ation", + "stat ion", + "T ake", + "▁s hed", + "▁sh ed", + "▁she d", + "▁Fr ancia", + "▁Franc ia", + "▁Fra ncia", + "▁Fran cia", + "pos ts", + "po sts", + "post s", + "Mar ker", + "Mark er", + "Lower Case", + "▁be find", + "▁bef ind", + "▁C zech", + "▁Cz ech", + "ícul a", + "▁Per formance", + "▁W es", + "▁We s", + "▁L arry", + "▁Lar ry", + "▁o st", + "▁os t", + "▁ ost", + "▁em ails", + "▁email s", + "▁Re lease", + "▁ Release", + "▁ad apter", + "▁adapt er", + "▁ adapter", + "▁pad re", + "ac io", + "aci o", + "a cio", + "▁з ем", + "▁gen etic", + "▁ge netic", + "▁U nd", + "▁Un d", + "▁ Und", + "▁accept ance", + "да н", + "д ан", + "▁Girl s", + "▁Gir ls", + "comp iler", + "compile r", + "su n", + "s un", + "▁whe els", + "▁wheel s", + "▁thorough ly", + "gr und", + "gru nd", + "g rund", + "un ction", + "unct ion", + "▁e lla", + "▁el la", + "▁ell a", + "▁ ella", + "X FF", + "ug s", + "u gs", + "ient os", + "ien tos", + "iento s", + "▁D M", + "▁ DM", + "▁polit ique", + "▁campaign s", + "▁Tok yo", + "▁album s", + "KERN EL", + "pd ata", + "p data", + "▁lap top", + "▁lapt op", + "▁v ál", + "▁vá l", + "▁f ou", + "▁fo u", + "or b", + "o rb", + "▁T ower", + "▁To wer", + "▁Tow er", + "▁Get ting", + "▁cor ners", + "▁corner s", + "▁corn ers", + "pl ess", + "ple ss", + "ples s", + "p less", + "▁special ist", + "▁i v", + "▁ iv", + "Ui nt", + "U int", + "▁name ly", + "▁nam ely", + "▁sc aling", + "▁scal ing", + "Ext ensions", + "Extension s", + "▁cent ro", + "omorph ism", + "▁dé f", + "), \\", + ") ,\\", + "▁contr ary", + "▁contra ry", + "▁str iking", + "▁stri king", + "▁B ere", + "▁Be re", + "▁Ber e", + "▁fore cast", + "▁z ones", + "▁zone s", + "▁zo nes", + "sm art", + "s mart", + "as hi", + "ash i", + "ri n", + "r in", + "NE W", + "▁sim ulations", + "▁simulation s", + "▁R ather", + "▁Ra ther", + "▁Rat her", + "▁Writ ing", + "▁Wr iting", + "▁$ [", + "▁as sh", + "▁ass h", + "▁f ailing", + "▁fa iling", + "▁fail ing", + "▁man if", + "▁B og", + "▁Bo g", + "▁D ir", + "▁Di r", + "▁ Dir", + "▁influ enced", + "▁influence d", + "conf irm", + "▁we igh", + "▁in ventory", + "▁invent ory", + "▁a pare", + "▁ap are", + "▁e u", + "▁ eu", + "char acter", + "io m", + "i om", + "▁o rb", + "▁or b", + "▁ orb", + "dev ices", + "device s", + "▁L ED", + "▁LE D", + "▁ LED", + "▁prop ortion", + "▁proport ion", + "▁Hon or", + "▁Ho nor", + "▁appro aching", + "▁approach ing", + "de leg", + "del eg", + "▁B B", + "▁ BB", + "hel pers", + "help ers", + "helper s", + "re pository", + "rep ository", + "▁б ере", + "▁бе ре", + "▁inhab it", + "▁s ão", + "▁travel ed", + "▁trav eled", + "ne x", + "n ex", + "▁C lin", + "▁Cl in", + "CE PT", + "▁off ense", + "▁in cent", + "▁inc ent", + "ID S", + "I DS", + "▁coeff icients", + "▁coefficient s", + "▁l p", + "▁ lp", + "чно го", + "ч ного", + "▁c d", + "▁ cd", + "mu st", + "mus t", + "m ust", + "▁soon er", + "ez e", + "e ze", + "C at", + "ma ker", + "make r", + "m aker", + "▁r anked", + "▁ran ked", + "▁rank ed", + "ful ness", + "▁part ially", + "▁partial ly", + "▁parti ally", + "Pro m", + "Pr om", + "P rom", + "▁ф он", + "▁фо н", + "▁Pro bably", + "▁c ached", + "▁cache d", + "▁ca ched", + "▁ cached", + "▁bal anced", + "▁balance d", + "ah oma", + "aho ma", + "▁Mur ray", + "▁a li", + "▁al i", + "▁ ali", + "iv os", + "ivo s", + "▁b ark", + "▁bar k", + "IT EM", + "ITE M", + "▁Kir che", + "▁alloc ated", + "▁allocate d", + "Al t", + "A lt", + "▁am éric", + "íl ia", + "í lia", + "▁c ens", + "▁ce ns", + "▁lic enses", + "▁license s", + "▁ licenses", + "ac z", + "a cz", + "▁G ate", + "▁Ga te", + "▁ Gate", + "▁B L", + "▁ BL", + "▁re public", + "▁rep ublic", + "RO W", + "▁состав ля", + "▁соста вля", + "▁Fil ip", + "▁Ind ivid", + "▁tr ials", + "▁tri als", + "▁trial s", + "/* !", + "▁G P", + "▁ GP", + "ni ka", + "nik a", + "n ika", + "▁ex em", + "▁ad vers", + "▁adv ers", + "um ped", + "ump ed", + "▁Dev ice", + "▁ Device", + "wa ke", + "w ake", + "Ex ec", + "ar ding", + "ard ing", + "ardi ng", + "▁pobl ación", + "▁k een", + "▁ke en", + "▁b itch", + "▁bit ch", + "▁embed ded", + "▁B ond", + "▁Bo nd", + "▁Bon d", + "ri des", + "ride s", + "rid es", + "r ides", + "▁W oman", + "▁Wo man", + ". [", + "ér é", + "é ré", + "▁Hash Map", + "▁ HashMap", + "▁co unting", + "▁coun ting", + "▁count ing", + "▁Init ial", + "▁ Initial", + "▁ver se", + "▁vers e", + "▁ verse", + "▁Vere in", + ">\" ,", + "> \",", + "▁an th", + "▁ant h", + "▁ anth", + "ci d", + "c id", + "▁h unt", + "▁hun t", + "на л", + "н ал", + "ci es", + "cie s", + "c ies", + "Pi n", + "P in", + "▁# !", + "ва я", + "sn d", + "s nd", + "▁u k", + "▁ uk", + "▁sw ift", + "▁tempor ada", + "▁environment s", + "▁environ ments", + "claim er", + "eme tery", + "emet ery", + "j är", + "▁ча ст", + "▁час т", + "Trans port", + "▁A rr", + "▁Ar r", + "▁ Arr", + "▁P aper", + "▁Pa per", + "▁Pap er", + "▁b ew", + "▁be w", + "▁ bew", + "▁har vest", + "▁- ----", + "▁-- ---", + "▁--- --", + "▁ -----", + "product s", + "ле т", + "л ет", + "ident ifier", + "RO OT", + "▁M ak", + "▁Ma k", + "▁App ro", + "▁Ap pro", + "▁ Appro", + "ie ri", + "ier i", + "i eri", + "▁F ly", + "▁Fl y", + "▁is set", + "▁iss et", + "▁ isset", + "▁determ ination", + "▁determin ation", + "Ge ometry", + "▁emer ging", + "sub scription", + "ol y", + "o ly", + "▁R ace", + "▁Ra ce", + "▁B ah", + "▁Ba h", + "▁Config uration", + "▁ Configuration", + "▁Inter est", + "ско в", + "ск ов", + "с ков", + "ist rz", + "istr z", + "▁S han", + "▁Sh an", + "▁Sha n", + "▁P ain", + "▁Pa in", + "CON NE", + "ma jor", + "m ajor", + "▁St ay", + "▁Sta y", + "▁bron ze", + "▁f itting", + "▁fit ting", + "▁J ar", + "▁Ja r", + "mg r", + "m gr", + "▁S har", + "▁Sh ar", + "▁Sha r", + "FL O", + "F LO", + "ut er", + "ute r", + "u ter", + "с ы", + "▁cont acts", + "▁contact s", + "▁f iring", + "▁fi ring", + "▁fir ing", + "на н", + "н ан", + "▁prof es", + "sk é", + "s ké", + "▁rule d", + "▁ru led", + "▁rul ed", + "=\" /", + "an dro", + "and ro", + "▁ens uring", + "iz en", + "ize n", + "i zen", + "▁че рез", + "ise cond", + "i second", + "ob il", + "obi l", + "o bil", + "▁re ck", + "▁rec k", + "▁ reck", + ")} (", + ") }(", + "bit map", + "▁B run", + "▁Br un", + "▁Bru n", + "▁Jer usalem", + "▁W o", + "▁Republic ans", + "▁Republican s", + "mat ic", + "m atic", + "▁E arl", + "▁d ock", + "▁do ck", + "▁doc k", + "▁M all", + "▁Mal l", + "▁Ma ll", + "k k", + "▁ Й", + "▁C OL", + "▁CO L", + "▁ COL", + "▁lat ach", + "UI nt", + "U Int", + "ци ональ", + "цион аль", + "циона ль", + "▁seg ments", + "▁segment s", + "▁re fund", + "▁ref und", + "fa c", + "f ac", + "▁Art icle", + "▁B orn", + "▁Bo rn", + "▁Bor n", + "² .", + "br and", + "bra nd", + "b rand", + "{$ \\", + "{ $\\", + "▁s s", + "▁ ss", + "▁Re sources", + "▁Res ources", + "▁Resource s", + "▁ Resources", + "▁re cycl", + "▁rec ycl", + "▁$ $\\", + "▁$$ \\", + "▁Conne ction", + "▁Connect ion", + "▁ Connection", + "▁imp erial", + "▁imper ial", + "▁pract ically", + "▁practical ly", + "▁– ,", + "▁Dis play", + "▁ Display", + "ier no", + "mo uth", + "m outh", + "ed es", + "ede s", + "e des", + "ba hn", + "b ahn", + "▁C atherine", + "▁high way", + "un ting", + "unt ing", + "▁Any way", + "Sp ell", + "Spe ll", + "▁L iste", + "▁List e", + "▁Li ste", + "▁Lis te", + "▁ret rieve", + "▁retr ieve", + "▁retriev e", + "▁z d", + "▁ zd", + "stra ße", + "▁dom inated", + "▁domin ated", + "to uch", + "t ouch", + "▁m b", + "▁ mb", + "LO NG", + "L ONG", + "as ures", + "asure s", + "TL S", + "T LS", + "▁accompl ished", + "▁accomp lished", + "▁accomplish ed", + "▁f ears", + "▁fe ars", + "▁fear s", + "▁seem ingly", + "▁d ag", + "▁da g", + "▁ dag", + "▁b ureau", + "▁bur eau", + "▁Gro ß", + "▁accord ance", + ". ]", + "ou x", + "o ux", + "▁col onial", + "▁colon ial", + "▁compass ion", + "th umb", + "▁s wo", + "▁sw o", + "on line", + "▁J i", + "▁work shop", + "▁works hop", + "▁l ub", + "▁lu b", + "év rier", + "ш і", + ">\" ;", + "> \";", + "▁gener ous", + "▁gene rous", + "ro us", + "rou s", + "r ous", + "av id", + "avi d", + "a vid", + "igen ous", + "▁R aw", + "▁Ra w", + "▁ Raw", + "▁sw ap", + "▁ swap", + "h c", + "java script", + "jav ascript", + "Fact or", + "Fac tor", + "F actor", + "▁gar bage", + "▁M icro", + "▁Mic ro", + "▁Mi cro", + "co u", + "c ou", + "ü ber", + "▁f atal", + "▁fa tal", + "▁fat al", + "▁trans parent", + "▁b earing", + "▁be aring", + "▁bear ing", + "▁celebr ated", + "▁celebrate d", + "VI S", + "V IS", + "▁B M", + "▁ BM", + "▁pr ince", + "▁prin ce", + "to l", + "t ol", + "▁' ", + "\\ \">", + "▁du rant", + "▁dur ant", + "▁vent ure", + "▁F itz", + "▁Fi tz", + "▁C BD", + "▁CB D", + "▁b acking", + "▁back ing", + "▁w are", + "▁war e", + "▁wa re", + "▁ ware", + "ev e", + "e ve", + "O G", + "ed ish", + "edi sh", + "▁Giov anni", + "▁Sh are", + "▁Shar e", + "▁Sha re", + "▁ Share", + "▁rec ipes", + "▁recipe s", + "▁recip es", + "big g", + "bi gg", + "b igg", + "▁minor ity", + "▁n ar", + "▁na r", + "▁ nar", + "oll ary", + "ollar y", + "▁F E", + "▁ FE", + "sh irt", + "▁redu ces", + "▁reduce s", + "Ch e", + "C he", + "▁NOT E", + "▁NO TE", + "j query", + "▁F low", + "▁Fl ow", + "▁Flo w", + "▁ Flow", + "task s", + "pr event", + "pre vent", + "prev ent", + "▁со вет", + "▁сов ет", + "it as", + "ita s", + "▁exam ined", + "▁examine d", + "ho n", + "h on", + "▁M ine", + "▁Min e", + "▁Mi ne", + "▁grad ient", + "▁V ien", + "▁Vi en", + "▁b eds", + "▁be ds", + "▁bed s", + "ET H", + "E TH", + "fl at", + "f lat", + "an son", + "ans on", + "▁in tu", + "▁int u", + "▁fl ows", + "▁flo ws", + "▁flow s", + "но к", + "▁E ine", + "▁Ein e", + "ро ди", + "род и", + "▁ко р", + "▁к ор", + "▁ кор", + "▁aff ection", + "▁af fection", + "▁affect ion", + "▁p orts", + "▁por ts", + "▁port s", + "▁ ports", + "__ .", + "_ _.", + "re po", + "rep o", + "ail and", + "ai land", + "▁по да", + "▁под а", + "int age", + "inta ge", + "▁Prote ction", + "î t", + "▁[ {", + "▁l amp", + "▁la mp", + "▁benef icial", + "ка де", + "▁Станов ништво", + "▁l ined", + "▁li ned", + "▁line d", + "▁lin ed", + "▁ lined", + "▁Ex change", + "▁f itted", + "▁fit ted", + "▁v erk", + "▁ver k", + "▁focus es", + "vo d", + "v od", + "▁Car lo", + "▁Carl o", + "▁ра спо", + "▁рас по", + "ain ted", + "aint ed", + "ainte d", + "a inted", + "▁r ape", + "▁rap e", + "▁ra pe", + "▁t ogg", + "▁to gg", + "ac ker", + "ack er", + "a cker", + "T w", + "ra h", + "r ah", + "trans l", + "▁je alous", + "▁re pository", + "▁rep ository", + "▁ repository", + "re marks", + "rem arks", + "remark s", + "▁i e", + "▁ ie", + "í d", + "▁sk ull", + "ra c", + "r ac", + "() ]", + "( )]", + "ri en", + "rie n", + "r ien", + "? (", + "▁K ids", + "▁Ki ds", + "▁Kid s", + "▁sw itched", + "▁switch ed", + "▁G ew", + "▁Ge w", + "▁be ef", + "▁appear ances", + "▁appearance s", + "▁Coll ins", + "▁V illa", + "▁Vill a", + "▁Vi lla", + "▁Vil la", + "▁z ona", + "▁zo na", + "▁n eu", + "▁ne u", + "те льно", + "тель но", + "▁х удо", + "▁oper ational", + "▁operation al", + "ON LY", + "▁h ockey", + "▁ś wi", + "ö k", + "Sl ice", + "Ref resh", + "▁n uts", + "▁nu ts", + "▁nut s", + "sa y", + "s ay", + "▁ста нови", + "▁станов и", + "х е", + "▁le aning", + "▁lean ing", + "▁H aus", + "▁Ha us", + "▁o ral", + "▁or al", + "▁ oral", + "▁ Ž", + "▁Sup pose", + "▁Supp ose", + "▁ess ence", + "EN TER", + "ENT ER", + "B ucket", + "▁C ant", + "▁Can t", + "▁Ca nt", + "▁N azi", + "▁Na zi", + "▁Naz i", + "ш ти", + "▁Vol ume", + "▁ Volume", + "▁wor thy", + "▁worth y", + "▁ worthy", + "B u", + "Ent ries", + "on ie", + "oni e", + "o nie", + "▁h ood", + "▁ho od", + "▁ hood", + "▁emp ire", + "▁dé velop", + "▁p robe", + "▁pro be", + "▁pr obe", + "▁prob e", + "▁ probe", + "▁K night", + "▁Kn ight", + "▁peace ful", + "hu b", + "h ub", + "▁ál bum", + "su it", + "s uit", + "▁sil k", + "+ =", + "▁p ione", + "▁pi one", + "' \"", + "ка ми", + "▁N ull", + "▁Nu ll", + "▁ Null", + "Label s", + "au tres", + "aut res", + "autre s", + "to LowerCase", + "▁b uzz", + "▁bu zz", + "▁w ashed", + "▁was hed", + "▁wash ed", + "' *", + "itzer land", + "▁r amp", + "▁ra mp", + "▁ram p", + "▁к ни", + "▁k un", + "col ors", + "color s", + "colo rs", + "▁vacc ine", + "an imation", + "anim ation", + "▁Just in", + "mem set", + "▁c ensus", + "▁cens us", + "in fl", + "inf l", + "▁statist ical", + "▁trop ical", + "Dis abled", + "Disable d", + "\r \r", + "▁Cra ig", + "Page s", + "Pag es", + "P ages", + "▁mag az", + "▁comput ing", + "▁flo ors", + "▁floor s", + "oin e", + "oi ne", + "o ine", + "▁tit olo", + "▁an ci", + "▁anc i", + "▁Indust ry", + "▁г лав", + "▁гла в", + "Bo ot", + "B oot", + "Cl ip", + "▁d v", + "▁ dv", + "▁met all", + "▁metal l", + "▁meta ll", + "▁Is abel", + "▁Isa bel", + "▁look up", + "▁ lookup", + "▁ц ер", + "▁це р", + "▁ цер", + "▁car ries", + "f u", + "tp l", + "t pl", + "pe rp", + "per p", + "▁St orm", + "▁Sto rm", + "eh icle", + "▁S even", + "▁Se ven", + "▁Sev en", + "љ а", + "▁l ut", + "▁lu t", + "th reshold", + "▁d ull", + "▁du ll", + "▁E ND", + "▁EN D", + "▁ END", + "▁O tto", + "▁Ot to", + "▁Ott o", + "▁there by", + "TE MP", + "T EMP", + "▁S cal", + "▁Sc al", + "▁ Scal", + "Com put", + "Comp ut", + "ip v", + "i pv", + "▁ins ane", + "▁myster ious", + "▁M is", + "▁Mi s", + "uch ar", + "uc har", + "u char", + "as ma", + "asm a", + "au ch", + "auc h", + "a uch", + "ne tt", + "net t", + "n ett", + "El em", + "E lem", + "de rive", + "der ive", + "▁murder ed", + "ak ten", + "akt en", + "akte n", + "ро ван", + "ров ан", + "рова н", + "▁a nos", + "▁an os", + "▁ano s", + "▁ anos", + "}} ^", + "} }^", + "▁F uß", + "▁Fu ß", + "▁S ister", + "▁Si ster", + "▁volunte er", + ":: _", + ": :_", + "er ta", + "ert a", + "▁бо лее", + "og rá", + "▁Im Gui", + "sa me", + "sam e", + "s ame", + "Sh adow", + "▁re actions", + "▁reaction s", + "▁react ions", + "▁purch asing", + "PRE FIX", + "▁emb od", + "со м", + "▁alt ogether", + "▁prom oting", + "▁promot ing", + "U V", + "▁ind uced", + "▁indu ced", + "▁eer ste", + "▁eerst e", + "Li fe", + "Lif e", + "L ife", + "hd d", + "h dd", + "ní ch", + "▁c hill", + "▁ch ill", + "▁chi ll", + "RG B", + "R GB", + "red uce", + "redu ce", + "FR OM", + "F ROM", + "dir name", + "▁t une", + "▁tu ne", + "▁tun e", + "▁r ay", + "▁ra y", + "▁ ray", + "T D", + "▁к ъ", + "▁Febru ar", + "▁suspend ed", + "▁susp ended", + "▁u pp", + "▁up p", + "▁ upp", + "er i", + "e ri", + "pr eter", + "pre ter", + "pret er", + "▁E R", + "▁ ER", + "то н", + "т он", + "▁c atal", + "▁cat al", + "▁ca tal", + "▁h iring", + "▁hi ring", + "▁п ів", + "▁пі в", + "▁Olymp ics", + "▁Olympic s", + "da le", + "dal e", + "d ale", + ":: {", + ": :{", + "▁expl oring", + "▁explo ring", + "▁с тал", + "▁ста л", + "▁ст ал", + "▁univers ities", + "Class es", + "▁ча с", + "▁C ool", + "▁Co ol", + "▁S ony", + "▁So ny", + "▁Son y", + "th al", + "tha l", + "t hal", + "▁es crit", + "▁esc rit", + "▁cor ruption", + "▁corrupt ion", + "az ar", + "aza r", + "▁N eb", + "▁Ne b", + "▁Py thon", + "▁c him", + "▁ch im", + "▁chi m", + "▁cap ability", + "cy cl", + "c ycl", + "▁re try", + "▁r etry", + "▁ret ry", + "▁retr y", + "▁ retry", + "++ ]", + "▁t oy", + "▁to y", + "▁T erry", + "▁Ter ry", + "▁Terr y", + "View ById", + "▁v ine", + "▁vi ne", + "▁vin e", + "▁Kit chen", + "▁B iden", + "▁Bi den", + "Back end", + "gl ich", + "g lich", + "re lation", + "rel ation", + "▁rat ings", + "▁ra tings", + "▁rating s", + "Execut or", + "ibr ation", + ">( )", + "> ()", + "▁he al", + "if iable", + "ifi able", + "par k", + "p ark", + "▁P ete", + "▁Pe te", + "▁Pet e", + "▁tr aged", + "▁tra ged", + "▁trag ed", + "▁ch uck", + "▁wire less", + "▁wir eless", + "Re place", + "Rep lace", + "IR Q", + "▁се зо", + "i ß", + "▁j unto", + "▁jun to", + "Lo w", + "L ow", + "▁s id", + "▁si d", + "▁ sid", + "Tag Helpers", + "TagHelper s", + "▁comp aring", + "▁compar ing", + "▁c elle", + "▁cell e", + "▁ce lle", + "▁cel le", + "▁obt aining", + "▁obtain ing", + "▁qu ar", + "▁q uar", + "Br o", + "B ro", + "▁E C", + "▁ EC", + "in ea", + "ine a", + "i nea", + "▁F ue", + "▁Fu e", + "▁Prince ss", + "▁Prin cess", + "ij o", + "i jo", + "ge ns", + "gen s", + "g ens", + "PO L", + "P OL", + "è tres", + "▁h ind", + "▁hi nd", + "▁ hind", + "Var iant", + "Vari ant", + "▁rece ives", + "▁receive s", + "go d", + "g od", + "ik en", + "ike n", + "i ken", + "na il", + "n ail", + "▁amer ican", + "▁ american", + "br as", + "bra s", + "b ras", + "(' \\", + "( '\\", + "ie ce", + "if ference", + "iffer ence", + "iffe rence", + "▁b ubble", + "▁bub ble", + "▁B ear", + "▁Be ar", + "un ivers", + "uni vers", + "▁demand ing", + "sa ved", + "save d", + "s aved", + "▁cred entials", + "MS M", + "M SM", + "▁struct ural", + "Con s", + "Co ns", + "C ons", + "▁Way ne", + "▁blank et", + "▁re pet", + "▁rep et", + "▁repe t", + "Ne g", + "N eg", + "▁exclusive ly", + "▁exclus ively", + "IF I", + "I FI", + "бур г", + "▁arg uing", + "▁Re pub", + "▁Rep ub", + "▁f rowned", + "▁fr owned", + "Met ric", + "M etric", + "sk im", + "ski m", + "s kim", + "▁П ет", + "▁Пе т", + "▁rele ases", + "▁release s", + "▁t ast", + "▁ta st", + "▁p reference", + "▁pre ference", + "▁prefer ence", + "▁S üd", + "▁Sü d", + "oc c", + "o cc", + "▁r x", + "▁ rx", + "activ ate", + "cl am", + "c lam", + "▁фи ль", + "▁Sud denly", + "▁cr ushing", + "▁crush ing", + "▁L ower", + "▁Lo wer", + "▁Low er", + "▁ Lower", + "ei ng", + "e ing", + "wa lt", + "wal t", + "w alt", + "▁Г ер", + "▁Ге р", + "▁m ö", + "ри сто", + "la gen", + "lag en", + "lage n", + "l agen", + "▁co aching", + "▁coach ing", + "ight ers", + "igh ters", + "ighter s", + "▁bas ement", + "▁base ment", + "▁F IX", + "▁FI X", + "▁ FIX", + "Te le", + "T ele", + "With out", + "▁Com mons", + "▁Comm ons", + "▁Common s", + "ul ly", + "ull y", + "h box", + "fl ash", + "▁por tal", + "▁port al", + "▁ portal", + "ot ype", + "o type", + "▁S or", + "▁So r", + "▁trou bles", + "▁trouble s", + "ar si", + "ars i", + "▁с тан", + "▁ста н", + "▁ст ан", + "▁ стан", + "CA M", + "C AM", + "▁de notes", + "▁den otes", + "▁denote s", + "LA NG", + "LAN G", + "L ANG", + "▁Be yond", + "▁Bey ond", + "▁Bo wl", + "▁Bow l", + "▁import antly", + "▁important ly", + "▁W R", + "▁ WR", + "▁rel ating", + "▁a nder", + "▁and er", + "▁an der", + "▁ ander", + "▁gr inned", + "▁grin ned", + "▁D ak", + "▁Da k", + "▁Brook lyn", + "▁d p", + "▁ dp", + "▁P oly", + "▁Pol y", + "▁Po ly", + "▁ Poly", + "▁Sch ul", + "▁B uffer", + "▁Buff er", + "▁ Buffer", + "▁h older", + "▁hold er", + "▁hol der", + "▁ holder", + "IC AL", + "I CAL", + "▁tra iler", + "▁trail er", + "er ek", + "ere k", + "e rek", + "▁n ě", + "▁ ně", + "sh aped", + "shape d", + "sha ped", + ": `", + "▁de code", + "▁dec ode", + "▁ decode", + "▁co unted", + "▁coun ted", + "▁count ed", + "▁v amp", + "▁va mp", + "▁re late", + "▁rel ate", + "▁M ason", + "▁Ma son", + "▁Mas on", + "▁t itled", + "▁title d", + "▁tit led", + "▁Kent ucky", + "▁particip ated", + "▁participate d", + "▁Jenn ifer", + "▁mat rices", + "Cal endar", + "st s", + "s ts", + "Ass oci", + "▁f orum", + "▁for um", + "▁fo rum", + "▁s phere", + "▁sp here", + "▁spher e", + "▁S EO", + "▁SE O", + "pop up", + "▁Current ly", + "CL E", + "C LE", + "▁vol unt", + "▁stell ar", + "for all", + "Is s", + "I ss", + "im et", + "ime t", + "i met", + "q p", + "la test", + "lat est", + "late st", + "▁config ured", + "▁configure d", + "ab ol", + "a bol", + "ig ent", + "igen t", + "ige nt", + "i gent", + "▁delay ed", + "ff ic", + "f fic", + "▁g ing", + "▁gi ng", + "▁ ging", + "▁s cent", + "▁sc ent", + "▁scen t", + "▁disg ust", + "▁disgu st", + "he sis", + "hes is", + "h esis", + "im en", + "ime n", + "i men", + "▁re ign", + "▁П и", + "ul as", + "ula s", + "u las", + "um ing", + "umin g", + "umi ng", + "u ming", + "in nings", + "inn ings", + "Re nd", + "R end", + "id ity", + "idi ty", + "▁do zens", + "▁dozen s", + "wa rf", + "war f", + "▁Del hi", + "▁bi ological", + "▁corrid or", + "Vis ual", + "▁I z", + "▁s uits", + "▁su its", + "▁suit s", + "Py Object", + "ia go", + "i ago", + "▁div ide", + "▁divid e", + "pe nt", + "pen t", + "p ent", + "hel lo", + "hell o", + "h ello", + "▁b eta", + "▁be ta", + "▁bet a", + "▁ beta", + "▁ex terior", + "▁fin est", + "▁fine st", + "▁B ir", + "▁Bi r", + "▁f reed", + "▁fr eed", + "▁free d", + "▁fre ed", + "▁K el", + "▁Ke l", + "Se m", + "S em", + "▁fr uits", + "▁fruit s", + "▁fru its", + "▁serv ants", + "▁servant s", + "▁pub lisher", + "▁publish er", + "▁cop per", + "ol ation", + "o lation", + "se p", + "s ep", + "▁chair man", + "ti k", + "t ik", + "▁m others", + "▁mother s", + "▁mo thers", + "A ug", + "▁je ans", + "[] )", + "[ ])", + "▁D ATA", + "▁DA TA", + "▁ DATA", + "▁reve als", + "▁reveal s", + "▁un conscious", + "▁h acer", + "▁ha cer", + "▁hace r", + "ric ulum", + "▁T ogether", + "▁ш та", + "▁ шта", + "or sz", + "ors z", + "▁c anal", + "▁can al", + "▁ca nal", + "ös t", + "ö st", + "▁equ als", + "▁equal s", + "▁eq uals", + "▁ equals", + "▁по мо", + "▁al location", + "▁all ocation", + "▁alloc ation", + "st änd", + "▁ч ер", + "▁че р", + "ac king", + "ack ing", + "▁motiv ation", + "со н", + "с он", + "▁R ole", + "▁Ro le", + "▁Rol e", + "▁ Role", + "App ly", + "Ap ply", + "ig es", + "ige s", + "i ges", + "* {", + "▁f ires", + "▁fire s", + "▁fi res", + "▁fir es", + "Us ed", + "Use d", + "U sed", + "▁he ute", + "sk iej", + "ski ej", + "▁Or leans", + "yl an", + "y lan", + "▁warm th", + "▁w elfare", + "▁wel fare", + "je m", + "j em", + "▁си сте", + "be z", + "b ez", + "ř e", + "ke e", + "k ee", + "▁segu ito", + "un ge", + "ung e", + "▁y oga", + "▁yo ga", + "▁d ug", + "▁du g", + "▁rest ored", + "▁restore d", + "Dr oid", + "D roid", + "▁P ent", + "▁Pe nt", + "▁Pen t", + "▁ran king", + "▁rank ing", + "mo r", + "m or", + ".~ (\\", + "ograph ical", + "ographic al", + "▁p ian", + "▁pi an", + "▁g ates", + "▁gate s", + "▁ga tes", + "▁с ти", + "▁ст и", + "▁ сти", + "s quare", + "▁im plicit", + "▁impl icit", + "▁G ram", + "▁Gr am", + "▁Gra m", + "▁Apr ès", + "▁Ap rès", + "▁Ass istant", + "▁p ac", + "▁pa c", + "▁P ope", + "▁Po pe", + "▁Pop e", + "г ре", + "▁sc attering", + "▁scatter ing", + "стра тив", + "▁all ocate", + "▁alloc ate", + "▁Man hattan", + "▁а нг", + "▁ан г", + "▁ анг", + "▁inter rupted", + "▁interrupt ed", + "ér ieur", + "éri eur", + "érie ur", + "数 据", + "Sign al", + "Sig nal", + "▁Con tract", + "▁Cont ract", + "▁ Contract", + "ór ia", + "ó ria", + "WI TH", + "W ITH", + "хо дя", + "ход я", + "Ag greg", + "A ggreg", + "cul es", + "cu les", + "cule s", + "c ules", + "J an", + "▁s to", + "▁st o", + "▁ sto", + "▁G PIO", + "▁GP IO", + "▁ GPIO", + "▁ident ifying", + "▁identify ing", + "▁p id", + "▁pi d", + "▁ pid", + "ę p", + "▁di git", + "▁dig it", + "el ia", + "eli a", + "e lia", + "inv oke", + "▁Fl oren", + "▁Flor en", + "▁Flo ren", + "▁sh allow", + "▁shall ow", + "get Class", + "getC lass", + "▁advert is", + "ем ы", + "е мы", + "▁H R", + "▁ HR", + "ym an", + "y man", + "▁C E", + "▁ CE", + "▁sec ured", + "▁secure d", + "▁secur ed", + "▁rel atives", + "▁relative s", + "▁relativ es", + "▁s ob", + "▁so b", + "▁s tab", + "▁st ab", + "▁sta b", + "Trans ition", + "▁w en", + "▁we n", + "▁ wen", + "sh ops", + "shop s", + "▁k ont", + "▁kon t", + "▁ko nt", + "▁h acia", + "▁ha cia", + "H y", + "в ри", + "sh ell", + "she ll", + "s hell", + "▁ant ib", + "▁anti b", + "env ironment", + "environ ment", + "um bs", + "umb s", + "Tr acker", + "Track er", + "Tra cker", + "en tr", + "ent r", + "▁Polit ical", + "ex tract", + "ext ract", + "extra ct", + "extr act", + "=\" {{", + "▁m erc", + "▁me rc", + "▁mer c", + "▁p oc", + "▁po c", + "▁Re set", + "▁Res et", + "▁ Reset", + "▁pur ely", + "▁pure ly", + "▁M ul", + "▁Mu l", + "▁gorge ous", + "▁Î n", + "ri ven", + "riv en", + "rive n", + "r iven", + "▁rom ance", + "▁roman ce", + "▁d av", + "▁da v", + "че ского", + "ér ica", + "éri ca", + "éric a", + "▁tra ject", + "▁a rise", + "▁ar ise", + "▁sw ung", + "▁p ockets", + "▁pocket s", + "▁trad itions", + "▁tradition s", + "▁re ver", + "▁r ever", + "▁rev er", + "▁reve r", + ">> >", + "> >>", + "▁n d", + "▁ nd", + "▁di vis", + "▁div is", + "▁bel oved", + "▁quant ities", + "▁é d", + "▁ éd", + "ien do", + "i endo", + "▁tal ented", + "▁talent ed", + "▁C ad", + "▁Ca d", + "▁В ла", + "▁imm igration", + "▁immigr ation", + "▁ju ris", + "▁jur is", + "▁a er", + "▁e aten", + "▁eat en", + "▁m iejsc", + "▁sum mon", + "pe ople", + "▁g ains", + "▁gain s", + "▁ga ins", + "▁пра во", + "▁restr iction", + "▁restrict ion", + "st ub", + "▁b out", + "▁bo ut", + "▁bou t", + "▁slave ry", + "▁sla very", + "▁comput ation", + "▁ar mor", + "▁arm or", + "▁e k", + "▁ ek", + "▁Muslim s", + "▁co operation", + "▁cooper ation", + "▁enh anced", + "▁enhance d", + "os lav", + "▁ab rupt", + "▁pod cast", + "▁hospital s", + "▁hosp itals", + "нь о", + "▁hot els", + "▁hotel s", + "▁Wik ipedia", + "▁ж ен", + "▁же н", + "▁ жен", + "G LOBAL", + "▁Commun ist", + "an gles", + "ang les", + "angle s", + "▁t high", + "▁th igh", + "▁K irk", + "▁Kir k", + "▁t ends", + "▁ten ds", + "▁tend s", + "▁M ode", + "▁Mod e", + "▁Mo de", + "▁ Mode", + "▁N atur", + "▁Nat ur", + "▁de let", + "▁del et", + "▁po pul", + "▁pop ul", + "▁Ch amber", + "▁Cha mber", + "▁Conserv ative", + "kr ieg", + "k rieg", + "▁Class ic", + "▁die sem", + "▁dies em", + "▁diese m", + "▁em power", + "▁emp ower", + "▁M es", + "▁Me s", + "▁de alt", + "▁deal t", + "▁e stad", + "▁est ad", + "▁esta d", + "▁Se it", + "▁cred its", + "▁credit s", + "sub subsection", + "Inv oke", + "▁phys ician", + "це в", + "ц ев", + "ás a", + "á sa", + "▁g ob", + "▁go b", + "▁R ug", + "▁Ru g", + "▁м іс", + "▁мі с", + "sh aller", + "shal ler", + "shall er", + "▁k ol", + "▁ko l", + "▁ kol", + "▁c ared", + "▁car ed", + "▁care d", + "▁ca red", + "▁of icial", + "no s", + "n os", + "▁j el", + "▁je l", + "▁ jel", + "null able", + "GU I", + "G UI", + "▁r app", + "▁rap p", + "▁ra pp", + "▁An nie", + "▁Ann ie", + "▁st ocks", + "▁stock s", + "▁sto cks", + "▁develop er", + "▁pl acement", + "▁place ment", + "▁plac ement", + "▁ placement", + "(\" <", + "▁l avor", + "▁la vor", + "▁lav or", + "▁acc us", + "Mar t", + "Ma rt", + "M art", + "amer ikan", + "▁sk etch", + "▁sent iment", + "▁а мерикан", + "An chor", + "Mer ge", + "Pe ople", + "▁rend ered", + "▁render ed", + "▁la und", + "▁n ons", + "▁no ns", + "▁non s", + "▁bl ew", + "▁ble w", + "k b", + "ate gor", + "ateg or", + "▁franç aise", + "▁français e", + "KE N", + "K EN", + "method s", + "▁Part icip", + "nost i", + "nos ti", + "n osti", + "▁com merce", + "▁commer ce", + "▁ commerce", + "▁до ма", + "▁d re", + "▁dr e", + "▁t win", + "▁tw in", + "▁ded ic", + "▁U TC", + "▁ UTC", + "We ek", + "▁differ ential", + "▁different ial", + "л ё", + "▁Ch oose", + "▁Cho ose", + "▁\" (", + "▁то м", + "▁ том", + "▁про фе", + "em ark", + "e mark", + "▁fe ared", + "▁fear ed", + "sk o", + "s ko", + "Br anch", + "▁in vention", + "▁inv ention", + "▁invent ion", + "er mine", + "erm ine", + "▁car act", + "▁ca ract", + "ро го", + "р ого", + "lo yd", + "▁ку ль", + "▁ куль", + "▁del icate", + "Or gan", + "▁Im pro", + "▁Imp ro", + "▁r ip", + "▁ri p", + "▁ rip", + "Up dated", + "Update d", + "ul ent", + "ule nt", + "▁o bra", + "▁ob ra", + "s uspend", + "Line s", + "Lin es", + "Li nes", + "L ines", + "▁b anda", + "▁band a", + "▁ban da", + "ot ta", + "ott a", + "o tta", + "▁k ole", + "▁ko le", + "▁kol e", + "il io", + "ili o", + "i lio", + "▁output s", + "▁ outputs", + "est ro", + "estr o", + "AAAA AAAA", + "R UN", + "ne nt", + "nen t", + "n ent", + "▁d ated", + "▁da ted", + "▁dat ed", + "▁date d", + "▁ dated", + "▁s py", + "▁sp y", + "▁c rap", + "▁cr ap", + "▁in coming", + "▁inc oming", + "▁ф ев", + "▁фе в", + "PH Y", + "P HY", + "▁O range", + "▁Or ange", + "▁ob server", + "▁observ er", + "▁observe r", + "▁up stairs", + "ion ed", + "io ned", + "ione d", + "i oned", + "▁a tr", + "▁at r", + "▁ atr", + "igh bor", + "▁expect ation", + "Hi s", + "H is", + "im edia", + "i media", + "com put", + "comp ut", + "▁arg v", + "▁ argv", + "▁ear liest", + "та ли", + "тал и", + "т али", + "мо н", + "м он", + "ol len", + "oll en", + "ra ke", + "r ake", + "▁pat ience", + "ходи т", + "ход ит", + "▁де ка", + "▁bu yers", + "▁buy ers", + "▁buyer s", + "▁Conne ct", + "▁ Connect", + "▁Univers al", + "▁adjust ed", + "▁adj usted", + "im eq", + "ime q", + "el lers", + "ell ers", + "elle rs", + "eller s", + "▁ru in", + "▁Cr usher", + "▁Freder ick", + "ott age", + "otta ge", + "▁com prom", + "▁comp rom", + "▁compr om", + "ia sm", + "ias m", + "i asm", + "wa ve", + "w ave", + "▁encour aging", + "▁be ans", + "▁bean s", + "▁ beans", + "▁per ceived", + "… ]", + "▁gl obe", + "▁glob e", + "▁glo be", + "▁S F", + "▁ SF", + "he rent", + "her ent", + "here nt", + "▁a like", + "▁al ike", + "▁ali ke", + "▁hur ried", + "qu el", + "que l", + "q uel", + "▁mus icians", + "▁music ians", + "▁musician s", + "ar z", + "a rz", + "по в", + "п ов", + "drop down", + "ac l", + "a cl", + "pre view", + "prev iew", + "p review", + "▁under neath", + "ze ś", + "▁fem ales", + "▁female s", + "list ener", + "listen er", + "▁C AN", + "▁CA N", + "▁ CAN", + "▁T ow", + "▁To w", + "▁pe ers", + "▁peer s", + "tl s", + "t ls", + "at ra", + "atr a", + "a tra", + "se nder", + "send er", + "sen der", + "s ender", + "TIME OUT", + "fu rt", + "fur t", + "f urt", + "▁Gu erra", + "{} )", + "{ })", + "▁D urch", + "▁Dur ch", + "▁s ki", + "▁sk i", + "▁ ski", + "il las", + "ill as", + "illa s", + "▁S of", + "▁So f", + "▁Organ ization", + "▁C leveland", + "▁b utt", + "▁but t", + "▁bu tt", + "▁sim ilarly", + "▁similar ly", + "▁assert True", + "▁ assertTrue", + "▁inev itable", + "ne ll", + "nel l", + "n ell", + "▁R af", + "▁Ra f", + "DIS ABLE", + "am ine", + "ami ne", + "amin e", + "a mine", + "▁Com plete", + "▁Comp lete", + "▁ Complete", + "▁be iden", + "▁bei den", + "▁Chall enge", + "Rad io", + "R adio", + "▁Not ice", + "He x", + "H ex", + "▁C uba", + "▁Cub a", + "▁Cu ba", + "▁aug ust", + "▁Philipp ines", + "Mar gin", + "M argin", + "ja l", + "j al", + "gener ator", + "▁t atto", + "▁ta tto", + "▁H em", + "▁He m", + "▁S alt", + "▁Sal t", + "▁Sa lt", + "un ately", + "unate ly", + "▁terr ain", + "▁terra in", + ",\\ ,", + ", \\,", + "гра д", + "▁c rop", + "▁cr op", + "▁cro p", + "Name d", + "Na med", + "N amed", + "▁W onder", + "▁Wo nder", + "▁Won der", + "es sen", + "ess en", + "esse n", + "▁f ist", + "▁fi st", + "▁fis t", + "▁z oom", + "▁zo om", + "▁ zoom", + "пе н", + "п ен", + "▁ru ling", + "▁rul ing", + "un likely", + "as sy", + "ass y", + "or ent", + "ore nt", + "oren t", + "o rent", + "▁g ibt", + "▁gi bt", + "▁A w", + "sim eq", + "s imeq", + "▁r aid", + "▁ra id", + "▁ raid", + "▁Com par", + "▁Comp ar", + "▁ Compar", + "▁free ly", + "▁fre ely", + "▁esp añ", + "▁espa ñ", + "▁py thon", + "▁ python", + "▁diagn osis", + "▁ch ips", + "▁chip s", + "▁chi ps", + "R azor", + "▁V ert", + "▁Ver t", + "▁Ve rt", + "▁ Vert", + "For ward", + "▁P é", + "▁compar able", + "▁anal ys", + "▁analy s", + "St d", + "S td", + "▁Franç ois", + "▁c ó", + "jo s", + "j os", + "▁p eg", + "▁pe g", + "▁ peg", + "CON ST", + "cl usive", + "▁voy age", + "▁Sch l", + "▁Sc hl", + "Group Layout", + "oi se", + "ois e", + "o ise", + "сс е", + "с се", + "▁cr ush", + "▁cru sh", + "▁Die se", + "▁Di ese", + "▁Dies e", + "▁be kan", + "▁bek an", + "ci t", + "c it", + "▁Ein wohner", + "▁L an", + "▁La n", + "▁dress ing", + "▁s olved", + "▁sol ved", + "▁solve d", + "М а", + "▁C hel", + "▁Ch el", + "▁Che l", + "par ed", + "pa red", + "pare d", + "p ared", + "▁se aled", + "▁sea led", + "▁seal ed", + "}) )", + "} ))", + "anc ouver", + "se h", + "s eh", + "ta bles", + "table s", + "tab les", + "t ables", + "▁red dit", + "▁redd it", + "▁ reddit", + "▁m our", + "▁mo ur", + "▁mou r", + "▁clean up", + "▁ cleanup", + "ov ić", + "ovi ć", + "▁Ur ban", + "oc t", + "o ct", + "то ра", + "тор а", + "▁Le gal", + "▁Leg al", + "▁J ur", + "▁Ju r", + "▁N as", + "▁Na s", + "C ity", + "▁un fortunately", + "▁unfortunate ly", + "▁P ER", + "▁PE R", + "▁ PER", + "ma kers", + "make rs", + "maker s", + "m akers", + "▁sig lo", + "▁k in", + "▁ki n", + "▁ kin", + "co des", + "code s", + "cod es", + "c odes", + "ля р", + "NI NG", + "N ING", + "▁C ec", + "▁Ce c", + "▁C T", + "▁ CT", + "▁R acing", + "▁Ra cing", + "da n", + "d an", + "▁He rz", + "▁Her z", + "▁gen ius", + "▁e urop", + "▁eu rop", + "serv let", + "ow ego", + "owe go", + "▁Im agine", + "▁Imp erial", + "▁Imper ial", + "Re gex", + "Reg ex", + "c é", + "HE D", + "H ED", + "det ect", + "з ни", + "io c", + "i oc", + "Anal ysis", + "Analy sis", + "▁* =", + "▁f ever", + "▁fe ver", + "▁Ob viously", + "F oot", + "Line ar", + "Lin ear", + "▁p ró", + "▁pr ó", + "▁satell ite", + "▁B eng", + "▁Be ng", + "▁Ben g", + "bound s", + "b ounds", + "▁J azz", + "▁Ja zz", + "▁C urt", + "▁Cur t", + "▁Cu rt", + "▁поли ти", + "▁b ild", + "▁bi ld", + "▁bil d", + "▁ bild", + "▁\" \");", + "▁\"\" );", + "▁\"\") ;", + "▁document ary", + "▁gr asp", + "▁gra sp", + "▁gras p", + "▁d la", + "▁dl a", + "TR A", + "T RA", + "▁read ily", + "To r", + "T or", + "C ACHE", + "▁Const ruction", + "▁Construct ion", + "▁d ía", + "да т", + "д ат", + "▁G rey", + "▁Gr ey", + "▁Gre y", + "run ner", + "le ading", + "▁co oked", + "▁cook ed", + "ro log", + "rol og", + "r olog", + "▁annoy ing", + "DE LETE", + "amer ican", + "▁Niger ia", + "▁d ai", + "▁da i", + "▁ dai", + "▁sac rific", + "▁serv ant", + "▁s kb", + "▁sk b", + "▁ skb", + "▁b arg", + "▁bar g", + "▁ba rg", + "pix el", + "p ixel", + "In ject", + "ca ched", + "cache d", + "c ached", + "▁cou pled", + "▁couple d", + "▁coup led", + "un gle", + "ung le", + "pro b", + "pr ob", + "p rob", + ">{ @", + "ла го", + "default s", + "▁por trait", + "▁port rait", + "▁d ental", + "▁den tal", + "▁dent al", + "▁d estro", + "▁dest ro", + "▁r ue", + "▁ru e", + "▁hy brid", + "▁ й", + "▁CO MP", + "▁COM P", + "▁ COMP", + "▁B ent", + "▁Be nt", + "▁Ben t", + "Com pare", + "Comp are", + "Compar e", + "bo th", + "bot h", + "b oth", + "kl ahoma", + "ais er", + "ai ser", + "aise r", + "a iser", + "Su re", + "Sur e", + "S ure", + "▁s olving", + "▁sol ving", + "▁l ista", + "▁li sta", + "▁list a", + "▁ lista", + "▁у чи", + "▁Ev ans", + "▁Eva ns", + "▁f usion", + "▁fus ion", + "▁compl aint", + "▁complain t", + "H P", + "He ap", + "al ways", + "M gr", + "▁appro x", + "▁ approx", + "display style", + "lo rd", + "lor d", + "l ord", + "in sn", + "ins n", + "▁Fe ature", + "▁ Feature", + "RP C", + "R PC", + "▁v et", + "▁ve t", + "▁ vet", + "К а", + "▁kil omet", + "▁kilom et", + "▁deliver ing", + "▁const itution", + "sh ine", + "ле к", + "▁го род", + "▁горо д", + "▁prob able", + "▁run ner", + "▁ runner", + "hr en", + "hre n", + "h ren", + "▁N ep", + "▁Ne p", + "▁over night", + "pr ead", + "pre ad", + "p read", + "л та", + "фор ма", + "CL O", + "C LO", + "ie sa", + "ies a", + "i esa", + "▁object ives", + "▁objective s", + "con tract", + "cont ract", + "contr act", + "EX P", + "▁col ours", + "▁colour s", + "xi co", + "xic o", + "x ico", + "C lean", + "▁light ly", + "▁scen arios", + "▁scenario s", + "▁qu arters", + "▁quarter s", + "▁quart ers", + "▁quar ters", + "▁ quarters", + "▁D ear", + "▁De ar", + "▁l uc", + "▁lu c", + "▁app et", + "▁ap pet", + "▁appe t", + "▁de port", + "▁dep ort", + "Sa fe", + "▁me nos", + "▁men os", + "▁Paul o", + "▁Pa ulo", + "CI AL", + "C IAL", + "ці в", + "ц ів", + "▁R oc", + "▁Ro c", + "▁c aring", + "▁car ing", + "▁ca ring", + "▁elect ro", + "▁de cember", + "▁dec ember", + "▁dece mber", + "▁Phil osoph", + "▁col ored", + "▁color ed", + "▁ colored", + "it sch", + "its ch", + "ropol itan", + "os ti", + "ost i", + "▁N ut", + "▁Nu t", + "▁consecut ive", + "Pe er", + "ar ness", + "arn ess", + "▁ż e", + "▁ że", + "▁A round", + "▁Ar ound", + "af ka", + "▁d io", + "▁di o", + "ci p", + "c ip", + "▁to ys", + "▁toy s", + "cr o", + "c ro", + "▁m iser", + "▁mis er", + "▁mi ser", + "▁mise r", + "check box", + "▁F isher", + "▁Fish er", + "▁gover ned", + "▁govern ed", + "▁h á", + "▁En able", + "▁ Enable", + "▁t rivial", + "▁occup ation", + "ro rs", + "ror s", + "r ors", + "▁l av", + "▁la v", + "▁ lav", + "▁m ou", + "▁mo u", + "▁b ord", + "▁bo rd", + "▁bor d", + "ли ч", + "Ro om", + "R oom", + "') \r", + "' )\r", + "▁art ic", + "▁m ientras", + "ch air", + "cha ir", + "uation s", + "u ations", + "▁comm ented", + "▁comment ed", + "▁trigger ed", + "Can not", + "C annot", + "▁Marc us", + "▁p unct", + "▁pun ct", + "▁achie vement", + "▁achieve ment", + "е ди", + "ext ensions", + "extension s", + "ad ers", + "ade rs", + "ader s", + "a ders", + "jo urs", + "jour s", + "j ours", + "ir lines", + "irl ines", + "▁со стоя", + "V IEW", + "▁Nap ole", + "Conf irm", + "▁por que", + "........ ........", + "▁LI ABILITY", + "Wall et", + "W allet", + "Sub ject", + "al gorithm", + "▁tr iple", + "▁tri ple", + "▁trip le", + "ru b", + "r ub", + "▁se cur", + "▁sec ur", + "▁hand some", + "▁hands ome", + "▁d od", + "▁do d", + "r ès", + "ac ja", + "ch od", + "cho d", + "н ва", + "es ar", + "esa r", + "an chor", + "anc hor", + "anch or", + "▁Soph ie", + "▁Украї ни", + "Up per", + "am ous", + "amo us", + "Fe atures", + "Feature s", + "▁б ли", + "▁ бли", + "Supp ress", + "Sup press", + "▁kil om", + "▁Z u", + "▁belong ed", + "▁Red dit", + "▁pro ces", + "▁proc es", + "▁с тар", + "▁ста р", + "▁ст ар", + "▁F est", + "▁Fe st", + "/ %", + "▁P am", + "▁Pa m", + "st orm", + "sto rm", + "W W", + "P aul", + "▁t ales", + "▁tal es", + "▁ta les", + "▁tale s", + "▁рай она", + "▁райо на", + "▁район а", + "▁spread ing", + "▁s ched", + "▁sc hed", + "▁sch ed", + "▁sche d", + "▁ sched", + "le ased", + "lease d", + "Non Null", + "▁High way", + "▁Re serve", + "▁Res erve", + "▁c ater", + "▁cat er", + "▁ca ter", + "▁t ire", + "▁ti re", + "▁tir e", + "▁por ch", + "qu ier", + "US A", + "U SA", + "▁Sw iss", + "▁ È", + "▁br ave", + "▁bra ve", + "▁explos ion", + "l r", + "▁class ified", + "Ab out", + "▁P ict", + "▁Pic t", + "▁Pi ct", + "▁Dub lin", + "▁separ ately", + "▁separate ly", + "▁bank ing", + "▁ban king", + "▁Christian ity", + "mi gr", + "m igr", + "Ro b", + "R ob", + "се р", + "с ер", + "▁el f", + "▁ elf", + "▁employ ers", + "▁employer s", + "▁S low", + "▁Sl ow", + "▁j uli", + "▁ju li", + "▁jul i", + "west ern", + "w estern", + "▁anal yst", + "▁analy st", + "▁analys t", + "ob serv", + "obs erv", + "▁N ice", + "▁Nic e", + "▁Ni ce", + "▁G C", + "▁ GC", + "▁Let ter", + "▁ha rass", + "▁har ass", + "User name", + "▁A unt", + "▁Au nt", + "▁с ент", + "Su p", + "S up", + "IC ES", + "ICE S", + "RE NT", + "R ENT", + "rat io", + "r atio", + "▁Мо ск", + "▁an gles", + "▁ang les", + "▁angle s", + "▁angl es", + "▁ angles", + "▁l lev", + "▁ll ev", + "_ *", + "▁n it", + "▁ni t", + "▁ nit", + "▁w reck", + "▁pat rol", + "▁loyal ty", + "▁n ationale", + "▁nat ionale", + "▁national e", + "▁nation ale", + "go m", + "g om", + "}$ -", + "} $-", + "▁dis pute", + "▁disput e", + "▁disp ute", + "▁r us", + "▁ru s", + "▁ rus", + "▁П рез", + "▁Пре з", + "▁Indust rial", + "▁dem ocratic", + "▁democr atic", + "b w", + "li mp", + "lim p", + "l imp", + "ur bed", + "urb ed", + "▁mie jsce", + "▁miejsc e", + "ру д", + "▁t ex", + "▁te x", + "▁ tex", + "▁develop ments", + "▁development s", + "▁B right", + "▁Br ight", + "▁Brig ht", + "▁var ying", + "▁va rying", + "▁vary ing", + "fa ct", + "fac t", + "f act", + "▁Port al", + "▁Por tal", + "as is", + "asi s", + "a sis", + "▁горо да", + "▁город а", + "▁cre ativity", + "▁creat ivity", + ")) ))", + "))) )", + ") )))", + ".\" ;", + ". \";", + "ie ux", + "ieu x", + "▁prov isions", + "▁provision s", + "uv e", + "u ve", + "La ng", + "L ang", + "miss ing", + "ра т", + "р ат", + "ph ony", + "▁out line", + "pa s", + "p as", + "el m", + "e lm", + "mon itor", + "TC P", + "T CP", + "ka t", + "k at", + "uc ed", + "uce d", + "u ced", + "\\\" ,", + "\\ \",", + "yn a", + "y na", + "ра бо", + "раб о", + "oc ate", + "oca te", + "▁c ares", + "▁car es", + "▁care s", + "▁ca res", + "▁f ins", + "▁fin s", + "▁fi ns", + "▁he ap", + "▁ heap", + "▁small est", + "äch st", + "▁I X", + "▁ IX", + "re cv", + "rec v", + "key word", + "▁at tra", + "▁att ra", + "▁attr a", + "▁sel bst", + "Un expected", + "Une xpected", + "Sm all", + "▁насе ље", + "▁H us", + "▁Hu s", + "Enc oder", + "Encode r", + "▁un set", + "▁uns et", + "▁home less", + "▁hom eless", + "▁Johann es", + "▁U RI", + "▁ URI", + "ant age", + "anta ge", + "▁in hib", + "▁appreci ated", + "▁appreciate d", + "ie lte", + "iel te", + "ielt e", + "i elte", + "▁st ays", + "▁stay s", + "▁sta ys", + "▁alle ged", + "▁alleg ed", + "▁c oding", + "▁co ding", + "▁cod ing", + "▁tv å", + "pipe line", + "p ipeline", + "▁W or", + "▁Wo r", + "File Path", + "▁accept ing", + "▁Ex cell", + "▁L uther", + "▁Lu ther", + "▁Friend s", + "▁c urt", + "▁cur t", + "▁cu rt", + "▁' $", + "▁ '$", + "▁tight ly", + "▁cz ę", + "▁un necessary", + "▁F ed", + "▁Fe d", + "▁А нд", + "▁Ан д", + "▁H P", + "▁ HP", + "▁String Builder", + "en burg", + "' (", + "vm a", + "v ma", + "▁Ab raham", + "W L", + "▁Re ference", + "▁Refer ence", + "▁ Reference", + "J o", + "Bl ob", + "Blo b", + "▁H ugh", + "▁Hug h", + "▁Hu gh", + "▁Bul gar", + "MESS AGE", + "з во", + "▁avoid ed", + "▁po ems", + "▁poem s", + "▁с ы", + "▁ сы", + "▁O pp", + "▁Op p", + "av irus", + "avi rus", + "Pre view", + "Prev iew", + "P review", + "▁k er", + "▁ke r", + "▁ ker", + "ue va", + "u eva", + "fl ix", + "▁char ging", + "▁charg ing", + "▁motiv ated", + "▁O rd", + "▁Or d", + "▁ Ord", + "▁av eva", + "▁ave va", + "x l", + "▁flex ibility", + "ag na", + "agn a", + "▁rac ism", + "d h", + "▁b aking", + "▁ba king", + "F riend", + "ble r", + "bl er", + "b ler", + "▁Log ger", + "▁ Logger", + "Te n", + "T en", + "nav igation", + "▁att achment", + "▁attach ment", + "▁ attachment", + "▁b ajo", + "▁ba jo", + "▁pr icing", + "▁pri cing", + "▁T ip", + "▁Ti p", + "▁ Tip", + "da r", + "d ar", + "G G", + "To ols", + "Tool s", + "Too ls", + "T ools", + "vol ution", + "v olution", + "am as", + "ama s", + "a mas", + "▁b ibli", + "▁adapt ed", + "ox y", + "o xy", + "▁F reedom", + "▁Free dom", + "ri co", + "ric o", + "r ico", + "▁coll apsed", + "▁collapse d", + "z m", + "pl o", + "p lo", + "▁c ô", + "▁r t", + "▁ rt", + "än ger", + "äng er", + "änge r", + "▁D R", + "▁ DR", + "▁Bit coin", + "go w", + "g ow", + "▁ch ez", + "▁che z", + "▁ chez", + "▁ot ro", + "▁te il", + "▁ teil", + "ла га", + "▁St ars", + "▁Star s", + "▁Sta rs", + "▁invest ing", + "▁a board", + "▁ab oard", + "▁f lights", + "▁fl ights", + "▁flight s", + "▁genu inely", + "▁genuine ly", + "▁prom ising", + "Rot ation", + "O cc", + "▁su oi", + "▁suo i", + "string ify", + "ac ies", + "aci es", + "a cies", + "▁G round", + "▁Gr ound", + "▁Gro und", + "▁sequ ences", + "▁sequence s", + "▁c ure", + "▁cur e", + "▁cu re", + "out ine", + "▁! !", + "▁ !!", + "▁G ay", + "▁Ga y", + "▁garden s", + "▁gard ens", + "▁G las", + "▁Gl as", + "▁Tai wan", + "reg istry", + "▁# {", + "▁ #{", + "▁ins pection", + "▁insp ection", + "▁inspect ion", + "Te ll", + "T ell", + "▁` ${", + "p matrix", + "▁reg ulation", + "▁regul ation", + "fin ish", + "▁Ed ge", + "▁ Edge", + "Sp rite", + "S prite", + "▁Conf eder", + "▁immigr ants", + "▁elder ly", + "um ed", + "ume d", + "u med", + "▁Quest ion", + "▁ Question", + "Gate way", + "fo ny", + "fon y", + "f ony", + "ît re", + "î tre", + "▁co sm", + "▁cos m", + "Ro und", + "R ound", + "▁ign oring", + "▁ignor ing", + "▁K i", + "▁sens itivity", + "âte au", + "ât eau", + "▁engine ers", + "▁engineer s", + "▁cor rel", + "▁corre l", + "ir teen", + "irt een", + "▁Sw itzerland", + "▁inher it", + "▁ inherit", + "wo r", + "w or", + "▁mid night", + "▁P un", + "▁Pu n", + "ak te", + "akt e", + "a kte", + "Dis able", + "▁es per", + "▁esp er", + "▁not ation", + "▁ notation", + "▁Univers idad", + "so l", + "s ol", + "de rn", + "der n", + "d ern", + "in ge", + "ing e", + "▁inv itation", + ")} }", + ") }}", + "▁ â", + "▁ess ays", + "▁essay s", + "ar med", + "arm ed", + "ch sel", + "chs el", + "▁не го", + "▁ него", + "▁confirm ation", + "un ity", + "unit y", + "uni ty", + "▁Br other", + "▁Bro ther", + "▁ Є", + "ni ce", + "nic e", + "n ice", + "▁S ue", + "▁Su e", + "▁t ray", + "▁tr ay", + "▁tra y", + "ро и", + "C ookie", + "▁Feder ation", + "IC T", + "I CT", + "▁p éri", + "stud ent", + "▁V ent", + "▁Ven t", + "▁Ve nt", + "K K", + "ST EM", + "aw k", + "▁re un", + "▁pe oples", + "▁people s", + "io res", + "ior es", + "iore s", + "i ores", + "ou bt", + "▁St age", + "▁Sta ge", + "▁ Stage", + "▁c harm", + "▁ch arm", + "▁char m", + "▁cha rm", + "ie ur", + "ieu r", + "i eur", + "▁util ize", + "▁utiliz e", + "▁d istribute", + "▁dist ribute", + "▁distribut e", + "▁g otta", + "▁go tta", + "▁got ta", + "▁block ing", + "H ot", + "br ew", + "bre w", + "b rew", + "▁b onds", + "▁bon ds", + "▁bond s", + "le af", + "Pro te", + "Pr ote", + "P rote", + "▁d ice", + "▁di ce", + "▁dic e", + "▁Nor man", + "▁Norm an", + "▁о кт", + "▁ок т", + "▁in spir", + "▁insp ir", + "Pr iv", + "P riv", + "▁P uerto", + "▁то ва", + "RS T", + "R ST", + "▁s f", + "▁ sf", + "▁qu ale", + "▁qual e", + "ni ck", + "nic k", + "n ick", + "▁sup press", + "▁supp ress", + "ча т", + "ч ат", + "▁H ello", + "▁Hel lo", + "▁Hell o", + "▁ Hello", + "▁crow ded", + "▁crowd ed", + "hba r", + "h bar", + "▁lo ads", + "▁load s", + "▁ loads", + "▁cor rection", + "▁correct ion", + "▁corre ction", + "ad just", + "adj ust", + "▁E state", + "▁Est ate", + "▁Esta te", + "text sc", + "▁cool ing", + "iv eau", + "ive au", + "▁bet ting", + "==== ========", + "======== ====", + "re mark", + "rem ark", + "r emark", + "▁im plications", + "▁impl ications", + "▁p oz", + "▁po z", + "ün g", + "ü ng", + "▁reg ards", + "▁regard s", + "▁a mid", + "▁am id", + "▁habit antes", + "G I", + "▁F ou", + "▁Fo u", + "▁j ar", + "▁ja r", + "▁ jar", + "▁requ iring", + "▁D rupal", + "▁Dru pal", + "▁li ability", + "cz as", + "c zas", + "▁l yrics", + "▁ly rics", + "▁N ort", + "▁No rt", + "▁Nor t", + "si l", + "s il", + "▁M ey", + "▁Me y", + "UN IT", + "ва ния", + "f uture", + "hi r", + "h ir", + "CA L", + "C AL", + "LAB EL", + "▁S weet", + "▁stat ue", + "bor ne", + "born e", + "b orne", + "Not ify", + "▁her itage", + "▁d orm", + "▁do rm", + "▁l ever", + "▁le ver", + "▁lev er", + "▁mut tered", + "} &", + "▁inter mediate", + "▁Wat son", + "▁view ing", + "▁vie wing", + "kt or", + "k tor", + "enti eth", + "xx x", + "x xx", + "at u", + "a tu", + "▁Inst all", + "▁ Install", + "Cont in", + "▁t oute", + "▁to ute", + "▁tou te", + "▁tout e", + "▁P T", + "▁ PT", + "▁u ri", + "▁ur i", + "▁ uri", + "Call ed", + "Cal led", + "C alled", + "▁O FF", + "▁OF F", + "▁ OFF", + "ig lia", + "ic hi", + "ich i", + "i chi", + "с ни", + "V o", + "▁exhib it", + "▁asym pt", + "▁G ulf", + "л ли", + "do min", + "dom in", + "d omin", + "▁départ ement", + "mi l", + "m il", + "▁B ez", + "▁Be z", + "▁l ately", + "▁late ly", + "▁lat ely", + "▁def ining", + "▁defin ing", + "▁E L", + "▁ EL", + "omorph ic", + "▁f ebru", + "▁fe bru", + "▁febr u", + "IS TER", + "IST ER", + "I STER", + "res olved", + "resolve d", + "те й", + "т ей", + "▁S pect", + "▁Sp ect", + "▁Spec t", + "▁Spe ct", + "▁sem pre", + "▁Se pt", + "▁Sep t", + "▁cl earing", + "▁cle aring", + "▁clear ing", + "▁diam eter", + "in do", + "ind o", + "▁soc cer", + "▁D CHECK", + "▁DC HECK", + "vo te", + "v ote", + "▁n omin", + "▁no min", + "▁nom in", + "Type d", + "Ty ped", + "Typ ed", + "Miss ing", + "W as", + "▁Cent ury", + "▁direct ors", + "▁dire ctors", + "▁director s", + "▁mode rate", + "▁moder ate", + "▁Ill uminate", + "▁ Illuminate", + "▁челове к", + "▁B apt", + "▁Ba pt", + "▁Qu ant", + "▁ Quant", + "▁tre ating", + "▁treat ing", + "ag i", + "a gi", + "Si l", + "S il", + "ring e", + "rin ge", + "r inge", + "ł ą", + "el lan", + "ell an", + "ella n", + "▁f ino", + "▁fin o", + "▁fi no", + "Capt ure", + "C apture", + "▁S ic", + "▁Si c", + "▁st amp", + "▁sta mp", + "▁stam p", + "▁B uen", + "▁Bu en", + "▁seg undo", + "▁in verse", + "▁d up", + "▁du p", + "▁ dup", + "▁br oker", + "▁bro ker", + "▁broke r", + "▁search ed", + "▁sear ched", + "be ans", + "bean s", + "▁A BC", + "▁AB C", + "is ha", + "ish a", + "i sha", + "▁Lin ked", + "▁Link ed", + "▁ Linked", + "▁Nich olas", + "▁Sw edish", + "he mal", + "hem al", + "▁E M", + "▁ EM", + "▁j ego", + "▁je go", + "че ский", + "чески й", + "lo t", + "l ot", + "▁dis cret", + "▁disc ret", + "▁discre t", + "▁E g", + "pi ck", + "pic k", + "p ick", + "am on", + "amo n", + "a mon", + "▁Rail way", + "ка р", + "к ар", + "▁nav igate", + "▁navig ate", + "▁Comm ander", + "▁Command er", + "▁disappe ar", + "▁con gress", + "▁congr ess", + "▁graph ic", + "sp r", + "s pr", + "FLO AT", + "▁S erial", + "▁Se rial", + "▁Ser ial", + "▁ Serial", + "▁я нва", + "so cial", + "soc ial", + "s ocial", + "bu ch", + "b uch", + "▁se al", + "▁sea l", + "▁c ement", + "▁ce ment", + "▁Y e", + "ot ti", + "ott i", + "o tti", + "▁The od", + "remove Class", + "▁Jul ie", + "▁Ju lie", + "▁Juli e", + "▁gr öß", + "ST REAM", + "▁G B", + "▁ GB", + "▁Ben ef", + "▁Mat rix", + "▁ Matrix", + "▁ke ine", + "▁cont inent", + "▁contin ent", + "▁ja ar", + "DA I", + "D AI", + "▁S equ", + "▁Se qu", + "▁ Sequ", + "kre is", + "▁c rown", + "▁cr own", + "▁crow n", + "▁cro wn", + "Init ialize", + "Initial ize", + "ax y", + "a xy", + "▁C IA", + "▁int end", + "▁inte nd", + "▁b ub", + "▁bu b", + "▁mask s", + "▁mas ks", + "▁sit uated", + "▁situ ated", + "▁E du", + "▁Ed u", + "▁particip ating", + "ше й", + "ш ей", + "_{ -", + "_ {-", + "▁Tele vision", + "▁pre ferences", + "▁prefer ences", + "▁preference s", + "▁D rop", + "▁Dr op", + "▁ Drop", + "re view", + "rev iew", + "▁vi olation", + "▁viol ation", + "▁ch rist", + "▁chr ist", + "q q", + "▁M yst", + "▁My st", + "comm ands", + "command s", + "▁prim itive", + "ill ance", + "▁r anging", + "▁ran ging", + "▁rang ing", + "▁Adv anced", + ") &", + "▁О б", + "▁sub str", + "▁subst r", + "▁subs tr", + "▁ substr", + "▁clos ure", + "▁clo sure", + "▁ closure", + "tw itter", + "ne z", + "n ez", + "▁pr zed", + "▁prz ed", + "▁prze d", + "▁mer ged", + "▁merge d", + "ur os", + "uro s", + "u ros", + "▁j er", + "▁je r", + "▁ jer", + "▁_ (", + "▁ _(", + "ar an", + "ara n", + "a ran", + "▁P atri", + "▁Pat ri", + "▁Pa tri", + "▁T un", + "▁Tu n", + "U K", + "il iation", + "ili ation", + "▁Ke ith", + "Own Property", + "op sis", + "ops is", + "Ma d", + "M ad", + "▁def ence", + "A ir", + "=$ {", + "= ${", + "cript ors", + "criptor s", + "So m", + "S om", + "▁ ±", + "▁HA VE", + "~~~~ ~~~~", + "▁be aten", + "▁beat en", + "▁int imate", + "▁intim ate", + "op ic", + "o pic", + "▁p řed", + "▁př ed", + "Sh op", + "S hop", + "Table s", + "Tab les", + "T ables", + "▁S I", + "▁ SI", + "re name", + "ren ame", + "rena me", + "r ename", + "▁product ive", + "rib ly", + "r ibly", + "▁L uck", + "▁Lu ck", + "▁Luc k", + "▁kl ub", + "}} ^{", + "}}^ {", + "} }^{", + "▁F ish", + "▁Fi sh", + "PR I", + "P RI", + "en ario", + "ena rio", + "▁pse ud", + "Or d", + "O rd", + "▁quel ques", + "▁D od", + "▁Do d", + "▁p unto", + "▁pun to", + "▁punt o", + "se nal", + "sen al", + "▁Br others", + "▁Bro thers", + "▁Brother s", + "▁diab etes", + "P aint", + "▁person as", + "▁persona s", + "в ър", + "▁n ep", + "▁ne p", + "▁El len", + "▁Ell en", + "▁Elle n", + "▁h ä", + "cr tc", + "c rtc", + "▁frustr ation", + ". ^{[", + "▁s printf", + "▁sprint f", + "▁ sprintf", + "+ -", + "En code", + "Enc ode", + "▁насе лення", + "Draw able", + "▁b ore", + "▁bo re", + "▁bor e", + "▁E ld", + "▁El d", + "те т", + "т ет", + "T ick", + "ar ator", + "ara tor", + "▁Fin ance", + "▁agric ultural", + ")^ {-", + ")^{ -", + ") ^{-", + "may be", + "Sche dule", + "▁[ …]", + "et ection", + "ete ction", + "ль ного", + "льно го", + "▁he els", + "▁En joy", + "Sy s", + "S ys", + "orsz ág", + "CONT ROL", + "cc cc", + "▁D ictionary", + "▁ Dictionary", + "Ne ed", + "N eed", + "▁He aven", + "▁vess els", + "▁vessel s", + "ec ycle", + "e cycle", + "ti es", + "t ies", + "▁e nde", + "▁en de", + "▁end e", + "▁ ende", + "SI NG", + "S ING", + "De scribe", + "Desc ribe", + "▁Pub lished", + "▁Publish ed", + "▁win ds", + "▁wind s", + "neh men", + "▁D ES", + "▁DE S", + "Hor izontal", + "▁L ost", + "▁Los t", + "▁Lo st", + "-- -----------", + "---- ---------", + "-------- -----", + "--- ----------", + "------------ -", + "----- --------", + "---------- ---", + "------ -------", + "--------- ----", + "------- ------", + "----------- --", + "- ------------", + "▁p x", + "▁ px", + "}( {\\", + "} ({\\", + "▁Hein rich", + "oms nitt", + "ho s", + "h os", + "Ro ll", + "R oll", + "tor ch", + "▁equ ity", + "▁eq uity", + "▁collect ing", + "▁l ifting", + "▁lif ting", + "▁lift ing", + "sub figure", + "Ne ver", + "N ever", + "▁L ength", + "▁Le ngth", + "▁ Length", + "▁w inners", + "▁win ners", + "▁winner s", + "▁U SD", + "▁US D", + "▁st esso", + "▁а бо", + "▁al tri", + "▁alt ri", + "▁produ cers", + "▁produce rs", + "▁producer s", + "mon s", + "mo ns", + "m ons", + "▁Pop ular", + "Com b", + "Co mb", + "C omb", + "ab lo", + "abl o", + "a blo", + "RE SET", + "RES ET", + "т ва", + "Over lay", + "▁id iot", + "▁idi ot", + "ex ist", + "Be havior", + "UB LE", + "ier re", + "i erre", + "mine craft", + "▁f os", + "▁fo s", + "▁encuent ra", + "▁scream ed", + "▁polynom ial", + "▁c one", + "▁con e", + "▁co ne", + "▁c ited", + "▁cit ed", + "▁ci ted", + "▁president e", + "▁presid ente", + "▁re sign", + "▁res ign", + "▁y elled", + "▁i k", + "▁ ik", + "Pl us", + "▁Ми ха", + "▁The me", + "▁Th eme", + "▁ Theme", + "▁re li", + "▁r eli", + "▁rel i", + "ne m", + "n em", + "▁a men", + "▁am en", + "▁ amen", + "▁ Ј", + "Th anks", + "Thank s", + "Than ks", + "▁al umin", + "▁sh elf", + "▁shel f", + "!\" );", + "! \");", + "append Child", + "▁l ogs", + "▁lo gs", + "▁log s", + "▁ logs", + "▁re gex", + "▁reg ex", + "▁ regex", + "▁p unk", + "▁pun k", + "CO RE", + "▁b orders", + "▁border s", + "▁bord ers", + "▁bor ders", + "▁Requ ired", + "▁ Required", + "▁f law", + "▁fl aw", + "▁cin ema", + "▁v í", + "▁ ví", + "▁ab ortion", + "▁abort ion", + "jour nal", + "j ournal", + "in itions", + "init ions", + "inition s", + "state ment", + "stat ement", + "▁o urs", + "▁our s", + "▁ou rs", + "▁ ours", + "ó t", + "▁Tur ner", + "▁Turn er", + "in us", + "ev es", + "eve s", + "e ves", + "▁magazine s", + "▁magaz ines", + "… …", + "la ce", + "l ace", + "sl ider", + "slide r", + "▁l ocate", + "▁loc ate", + "▁des arroll", + "P an", + "To m", + "T om", + "▁Land es", + "▁Lan des", + "ol ia", + "oli a", + "o lia", + "▁u nm", + "▁un m", + "▁Sen ator", + "▁ad minister", + "▁admin ister", + "▁ко ји", + "▁' {", + "▁) {", + "▁ ){", + "▁G olf", + "▁Gol f", + "▁g ele", + "▁ge le", + "▁gel e", + "▁d rank", + "▁dr ank", + "pos ing", + "po sing", + "p osing", + "▁en semble", + "he ap", + "sign ature", + "то й", + "ци й", + "scri ber", + "scr iber", + "scribe r", + "scrib er", + "▁ch amp", + "▁cha mp", + "ni o", + "n io", + "la yers", + "lay ers", + "layer s", + "▁tr ump", + "▁mod al", + "▁mo dal", + "▁ modal", + "on ces", + "once s", + "че ння", + "чен ня", + "▁C ort", + "▁Co rt", + "▁Cor t", + "▁sun light", + "▁M use", + "▁Mus e", + "▁Mu se", + "ém ent", + "é ment", + "▁curios ity", + "▁v r", + "▁ vr", + "O ct", + "yl on", + "y lon", + "▁rel ativ", + "st y", + "s ty", + "] /", + "az u", + "a zu", + "▁U SS", + "▁US S", + "▁person a", + "▁pers ona", + "Me n", + "M en", + "▁w ides", + "▁wide s", + "▁wid es", + "▁K as", + "▁Ka s", + "ic ies", + "ici es", + "i cies", + "▁C off", + "▁Co ff", + "▁con solid", + "▁cons olid", + "▁inter active", + "▁interact ive", + "op ing", + "o ping", + "La nd", + "L and", + "▁energ ies", + "▁independ ently", + "▁independent ly", + "inner HTML", + "Requ ire", + "Re quire", + "▁abs urd", + "▁IN FO", + "▁ INFO", + "▁b und", + "▁bu nd", + "▁ bund", + "anz ös", + "▁G ent", + "▁Ge nt", + "▁Gen t", + "▁scholar s", + "▁schol ars", + "▁C reated", + "▁Create d", + "▁Creat ed", + "▁Cre ated", + "▁ Created", + "▁mar ine", + "▁mari ne", + ".. .'", + "... '", + "EN V", + "E NV", + "ach te", + "acht e", + "a chte", + "am ents", + "ament s", + "amen ts", + "a ments", + "▁tr ucks", + "▁truck s", + "▁re wards", + "▁reward s", + "og s", + "o gs", + "Gr een", + "Gre en", + "G reen", + "▁n ä", + "▁inher ited", + "▁inherit ed", + "im ated", + "imate d", + "ima ted", + "imat ed", + "▁F REE", + "▁FR EE", + "▁ FREE", + "▁ext ens", + "da g", + "d ag", + "▁g low", + "▁gl ow", + "▁glo w", + "ar di", + "ard i", + "N F", + "▁evalu ated", + "▁evaluate d", + "▁eval uated", + "▁o ps", + "▁op s", + "▁ ops", + "▁cle aned", + "▁clean ed", + "▁Prov ince", + "▁Provinc e", + "ha bil", + "hab il", + "h abil", + "гра фі", + "▁T CP", + "▁ TCP", + "▁я кі", + "▁як і", + "▁de ce", + "▁dec e", + "▁cont empl", + "▁acquis ition", + "}) $.", + "})$ .", + "} )$.", + "=\" -", + "▁se ctors", + "▁sector s", + "▁sect ors", + ":: <", + "u ß", + "▁trab aj", + "th an", + "tha n", + "t han", + "▁S ta", + "▁St a", + "Mem bers", + "Member s", + "▁r v", + "▁ rv", + ")^ {\\", + ")^{ \\", + ") ^{\\", + "mit t", + "mi tt", + "m itt", + "▁W ang", + "▁Wa ng", + "▁W end", + "▁We nd", + "▁G lass", + "▁Gl ass", + "▁Glas s", + "▁t xt", + "▁tx t", + "▁ txt", + "▁Cam eron", + "ie ls", + "iel s", + "i els", + "▁im mer", + "▁imm er", + "▁ immer", + "▁насе ления", + ".. . /", + "▁ро ди", + "▁ роди", + "▁sophistic ated", + "▁R he", + "▁Rh e", + "us sy", + "uss y", + "▁Sy ria", + "▁Car oline", + "▁Carol ine", + "riter ion", + "ér c", + "é rc", + "Lo ve", + "L ove", + "▁cy cles", + "▁cycle s", + "▁cycl es", + "▁Ter ms", + "▁Term s", + "▁med ieval", + "▁medi eval", + "ь я", + "▁m issions", + "▁miss ions", + "▁mission s", + "Har d", + "Ha rd", + "H ard", + "▁rég ion", + "▁Ph oenix", + "De ep", + "▁sam pling", + "▁dismiss ed", + "prop ri", + "p ropri", + "▁jud ges", + "▁judge s", + "▁judg es", + "ał a", + "a ła", + "ul os", + "ulo s", + "u los", + "▁L ion", + "▁Li on", + "▁loc als", + "▁local s", + "neg ative", + "ogen eous", + "ogene ous", + "▁A pi", + "▁Ap i", + "▁ Api", + "▁d ici", + "▁di ci", + "▁dic i", + "▁а пре", + "▁author ized", + "▁ authorized", + "ze rw", + "zer w", + "▁p g", + "▁ pg", + "▁A WS", + "▁key word", + "▁ keyword", + "▁entrepre neur", + "▁п рое", + "▁про е", + "▁V ancouver", + "it ating", + "ita ting", + "itat ing", + "F ast", + "▁acknowled ged", + "▁acknowledge d", + "▁tour ist", + "▁tou rist", + "▁G rid", + "▁Gr id", + "▁ Grid", + "▁En try", + "▁Ent ry", + "▁ Entry", + "▁g ebru", + "▁ge bru", + "▁geb ru", + "sa t", + "s at", + "ber ger", + "berg er", + "▁T F", + "▁ TF", + "▁m t", + "▁ mt", + "▁Mar cel", + "▁Marc el", + "▁Tw enty", + "▁ ”", + "{} {", + "{ }{", + "hi nt", + "hin t", + "h int", + "▁an onymous", + "Cam p", + "C amp", + "▁** _", + "By Comparator", + "U C", + "▁t ö", + "Event Handler", + "▁t ours", + "▁to urs", + "▁tour s", + "▁tou rs", + "▁lon ely", + "▁Sum mary", + "▁ Summary", + "st ick", + "s tick", + "All owed", + "Allow ed", + "лі в", + "л ів", + "▁B rew", + "▁Br ew", + "▁Bre w", + "AME TER", + "▁review ed", + "ir at", + "ira t", + "i rat", + "▁n erve", + "▁nerv e", + "▁ner ve", + "▁L inda", + "▁Lin da", + "▁Lind a", + "▁dec is", + "▁sp okes", + "▁spoke s", + "▁spo kes", + "▁qu ed", + "▁que d", + "▁q ued", + "▁F T", + "▁ FT", + "▁в ін", + "▁ві н", + "ou sing", + "ous ing", + "o using", + "▁L arge", + "▁Lar ge", + "▁ Large", + "▁op ponents", + "▁oppon ents", + "▁opponent s", + "▁D isc", + "▁Dis c", + "▁Di sc", + "Found ation", + "EQ UAL", + "og g", + "o gg", + "Re try", + "Ret ry", + "R etry", + "CHAN NEL", + "▁Е вро", + "▁% .", + "▁ %.", + "▁i i", + "▁ ii", + "de ad", + "d ead", + "▁M ale", + "▁Mal e", + "▁Ma le", + "Com pleted", + "Comp leted", + "Complete d", + "ty p", + "t yp", + "▁Ty ler", + "Dis k", + "Di sk", + "D isk", + "Hi de", + "H ide", + "iju ana", + "▁public ations", + "▁publication s", + "fo x", + "f ox", + "vis ed", + "vi sed", + "v ised", + "Fore ign", + "Write Line", + "де ра", + "дер а", + "▁remain der", + "Pi cker", + "P icker", + "we alth", + "▁G or", + "▁Go r", + "sequ ently", + "▁coll ision", + "▁Harr ison", + "▁Harris on", + "▁work place", + "▁N ormal", + "▁Nor mal", + "▁Norm al", + "▁ Normal", + "▁B irth", + "▁Bir th", + "▁cons ume", + "▁consum e", + "Sh ift", + "▁avoid ing", + "▁C ha", + "▁Ch a", + "▁An ti", + "▁Ant i", + "▁ch arts", + "▁char ts", + "▁chart s", + "▁P av", + "▁Pa v", + "ст вом", + "ство м", + "ual mente", + "an ed", + "ane d", + "a ned", + "▁A uch", + "▁Au ch", + "rd ev", + "r dev", + "▁she er", + "▁an gl", + "▁ang l", + "sub str", + "Gener ate", + "> =", + "▁B ev", + "▁Be v", + "▁ч ем", + "▁че м", + "▁camp o", + "▁cam po", + "▁lect ure", + "hy per", + "▁Balt imore", + "mi x", + "m ix", + "ke iten", + "keit en", + "▁ра ди", + "▁l asted", + "▁la sted", + "▁last ed", + "▁las ted", + "▁discrim ination", + "ig te", + "igt e", + "ok al", + "oka l", + "o kal", + "Ph ase", + "▁T itel", + "▁Tit el", + "▁Fif th", + "▁di agnostic", + "su ng", + "sun g", + "s ung", + "▁giorn ata", + "os ta", + "ost a", + "o sta", + "is co", + "isc o", + "▁S ara", + "▁Sa ra", + "▁Sar a", + "m v", + "▁el ő", + "▁R osen", + "▁Ro sen", + "▁Ros en", + "▁Rose n", + "▁E SP", + "▁ES P", + "ph er", + "p her", + "▁a j", + "▁ aj", + "Path s", + "Pat hs", + "▁R alph", + "▁ž e", + "▁ že", + "ре в", + "р ев", + "▁о коло", + "▁ок оло", + "▁Ag reement", + "▁Word Press", + "an try", + "ant ry", + "▁p icks", + "▁pick s", + "▁pi cks", + "▁pic ks", + "▁N ur", + "▁Nu r", + "chedul ed", + "ki e", + "k ie", + "▁represent ations", + "▁representation s", + "++ ){", + "++) {", + "ess ment", + "▁count less", + "Block s", + "Bl ocks", + "Blo cks", + "ym e", + "y me", + "▁c lo", + "▁cl o", + "▁B ened", + "▁Be ned", + "▁Ben ed", + "ch ars", + "char s", + "cha rs", + "▁A gent", + "▁Ag ent", + "▁Age nt", + "▁ Agent", + "▁hist oria", + "▁histor ia", + "▁F loor", + "▁Fl oor", + "▁Flo or", + "▁ten ía", + "▁long est", + "▁lon gest", + "fr ica", + "▁b ef", + "▁be f", + "▁mechan isms", + "▁mechanism s", + "ла зи", + "▁h eter", + "▁he ter", + "▁het er", + "▁athlet es", + "▁period ic", + "▁V otes", + "▁Vo tes", + "ри сти", + "▁n á", + "▁ ná", + "▁m aid", + "▁ma id", + "▁mai d", + "▁s wear", + "▁sw ear", + "▁swe ar", + "▁wip ed", + "▁graph s", + "▁grap hs", + "▁t hesis", + "▁the sis", + "▁th esis", + "▁sens ation", + "pers istence", + "▁V il", + "▁Vi l", + "ac s", + "a cs", + "▁de el", + "sc rib", + "scri b", + "scr ib", + "ie ro", + "ier o", + "i ero", + "▁dis cre", + "▁disc re", + "air y", + "ai ry", + "Data Source", + "q t", + "ic iones", + "ici ones", + "icio nes", + "icion es", + "▁res pected", + "▁respect ed", + "▁f ram", + "▁fr am", + "▁fra m", + "▁spec ialized", + "▁special ized", + "▁prés ent", + "▁pré sent", + "Tur n", + "T urn", + "▁compl aints", + "▁complain ts", + "▁complaint s", + "(\" ,", + "( \",", + "▁Rel ated", + "▁Set ting", + "▁ Setting", + "р ю", + "▁s ą", + "▁P le", + "▁Pl e", + "▁d isse", + "▁dis se", + "▁diss e", + "ca ps", + "cap s", + "c aps", + "▁C ash", + "▁Cas h", + "▁Ca sh", + "▁cons umed", + "▁consum ed", + "▁consume d", + "▁l b", + "▁ lb", + "Ad just", + "Ser ialize", + "Serial ize", + "S erialize", + "is y", + "i sy", + "▁pat ent", + "▁vis ibility", + "▁S ach", + "▁Sa ch", + "▁Sac h", + "ün st", + "▁cy ber", + "▁Bl ake", + "▁Bl oom", + "▁Blo om", + "▁Sh ah", + "▁Sha h", + "PO WER", + "▁in clusion", + "▁incl usion", + "se rie", + "ser ie", + "s erie", + "▁man era", + "sec onds", + "second s", + "is ches", + "isch es", + "ische s", + "isc hes", + "▁C andidate", + "W D", + "op ath", + "o path", + "▁про гра", + "▁efficient ly", + "ap ps", + "app s", + "tool bar", + "we nd", + "wen d", + "w end", + "▁Ne il", + "▁form ats", + "▁format s", + "▁forma ts", + "▁T emplate", + "▁Temp late", + "▁ Template", + "▁min istry", + "▁minist ry", + "▁Char acter", + "▁ Character", + "Un iform", + "▁fon ction", + "не м", + "н ем", + "Wh ile", + "к ва", + "рі я", + "▁D L", + "▁ DL", + "▁L ayout", + "▁La yout", + "▁Lay out", + "▁ Layout", + "не ние", + "▁c aval", + "▁ca val", + "▁cav al", + "▁H ob", + "▁Ho b", + "SP I", + "S PI", + "▁h ely", + "▁he ly", + "▁hel y", + "Dest ination", + "), \r", + ") ,\r", + "▁i OS", + "▁ad mission", + "▁adm ission", + "▁c ss", + "▁cs s", + "▁ css", + "user Id", + "um bling", + "umb ling", + "▁bo oking", + "▁book ing", + "▁COPY RIGHT", + "▁b land", + "▁bl and", + "output s", + "▁sub mission", + "▁subm ission", + "ti t", + "t it", + "fe ctions", + "fect ions", + "fection s", + "fr agment", + "frag ment", + "▁fa ç", + "▁Through out", + "▁distingu ished", + "▁distinguish ed", + "▁ar range", + "▁arr ange", + "▁arrang e", + "ume ric", + "umer ic", + "xf e", + "x fe", + "ip age", + "ipa ge", + "i page", + "ер жа", + "▁C ars", + "▁Car s", + "▁Ca rs", + "▁P AGE", + "▁PA GE", + "▁ PAGE", + "▁a unque", + "▁insert ed", + "smith y", + "AL LOC", + "ALL OC", + "RE C", + "R EC", + "▁B ak", + "▁Ba k", + "▁Str ong", + "ac hen", + "ach en", + "ache n", + "a chen", + "▁Spec ific", + "w q", + "▁Д у", + "MO VE", + "▁mús ica", + "▁C ris", + "▁Cr is", + "ea u", + "e au", + "▁F orum", + "▁For um", + "▁Fo rum", + "li sted", + "list ed", + "l isted", + ")\\ \\", + ") \\\\", + "▁X VI", + "▁XV I", + "▁м оло", + "▁мо ло", + "/ $", + "Be r", + "B er", + "▁tact ics", + "Form atter", + "Format ter", + "op ens", + "ope ns", + "open s", + "▁r h", + "▁ rh", + "▁t ram", + "▁tr am", + "▁tra m", + "V L", + "▁Pro file", + "▁Prof ile", + "▁ Profile", + "▁par ish", + "▁Ray mond", + "▁cont empor", + "▁Pl anning", + "▁Plan ning", + "▁Ч е", + "▁A RM", + "▁AR M", + "▁ ARM", + "▁des ires", + "▁desire s", + "k v", + "O s", + "▁m iner", + "▁min er", + "▁mi ner", + "▁mine r", + "▁qual ify", + "ik u", + "i ku", + "▁der ni", + "ol óg", + "▁K id", + "▁Ki d", + "ane an", + "▁Hol land", + "▁Holl and", + "Aut om", + "Auto m", + "▁Hamilton ian", + "St ation", + "Stat ion", + "js p", + "j sp", + "▁YO UR", + "▁YOU R", + "▁Th ailand", + "effect ive", + "п ло", + "▁relie ved", + "▁O klahoma", + "▁Jul ian", + "▁Juli an", + "▁Julia n", + "▁ind ent", + "▁inde nt", + "▁ indent", + "if r", + "i fr", + "пре де", + "▁fl ame", + "on io", + "oni o", + "o nio", + "As sign", + "Ass ign", + "▁sh ifts", + "▁shift s", + "▁car acter", + "▁caract er", + "if icates", + "ific ates", + "ificate s", + "ifica tes", + "X R", + "▁G FP", + "▁GF P", + "FE ATURE", + "▁M aine", + "▁Ma ine", + "▁Main e", + "▁Mai ne", + "▁f rank", + "▁fr ank", + "▁al igned", + "▁align ed", + "▁ aligned", + "▁p ří", + "▁př í", + "Code Attribute", + "▁M AC", + "▁MA C", + "▁ MAC", + "▁R oot", + "▁Ro ot", + "▁ Root", + "▁F M", + "▁ FM", + "erv ation", + "с лі", + "▁s hy", + "▁sh y", + "▁partic ul", + "▁parti cul", + "pl atz", + "▁hypothes is", + "at hol", + "ath ol", + "s With", + "J s", + "$ ^{-", + "▁#! /", + "▁l emon", + "▁le mon", + "▁a bol", + "▁ab ol", + "▁ abol", + "▁Mil an", + "▁Mi lan", + "an ten", + "ant en", + "ante n", + "a nten", + "▁s ia", + "▁si a", + "ri as", + "ria s", + "r ias", + "▁con sid", + "▁cons id", + "as so", + "ass o", + "ain ers", + "ai ners", + "ainer s", + "aine rs", + "▁cir ca", + "▁circ a", + "re try", + "ret ry", + "r etry", + "▁nue vo", + "const ants", + "constant s", + "▁Med iterr", + "▁Turk ish", + "ion en", + "io nen", + "ione n", + "i onen", + "c rypto", + "▁ev olved", + "▁\" ?", + "▁p úblic", + "▁comp rend", + "▁compre nd", + "▁compr end", + "al lo", + "all o", + "zo om", + "z oom", + "▁dat etime", + "▁date time", + "▁ datetime", + "▁mond iale", + "ма т", + "м ат", + "▁M ask", + "▁Ma sk", + "▁Mas k", + "▁ Mask", + "▁p row", + "▁pro w", + "▁pr ow", + "▁belong ing", + "+ '", + "OUT PUT", + "▁G rab", + "▁Gr ab", + "▁Gra b", + "M ir", + "▁accommod ate", + "▁$ ('#", + "▁ $('#", + "▁Lou ise", + "▁Louis e", + "▁da mit", + "▁dam it", + "}' ,", + "} ',", + "scri pts", + "script s", + "sn apshot", + "snap shot", + "▁sh itty", + "▁shit ty", + "▁y o", + "▁ yo", + "▁belie ving", + "▁inhabit ants", + "W P", + "▁Colomb ia", + "li sts", + "list s", + "l ists", + "▁Mur phy", + "Data set", + "Dat aset", + "▁(! $", + "▁tremend ous", + "▁se ñ", + "▁S ed", + "▁Se d", + "▁sw allowed", + "▁swallow ed", + "om p", + "o mp", + "▁L ate", + "▁La te", + "▁Lat e", + "▁an ys", + "▁any s", + "▁dead ly", + "fol low", + "f ollow", + "▁A nc", + "▁An c", + "▁h w", + "▁ hw", + "wik ipedia", + "ic ts", + "ict s", + "▁Al aska", + "▁sc ary", + "▁scar y", + "▁second o", + "▁sec ondo", + "▁her oes", + "▁hero es", + "▁veter an", + "▁behav iors", + "▁behavior s", + "▁behavi ors", + "- %", + "▁E z", + "▁с і", + "▁ сі", + "tik z", + "▁spect acular", + "▁Ch ron", + "▁( @", + "▁ (@", + "▁de mo", + "▁dem o", + "▁ demo", + "▁ser ialized", + "▁serial ized", + "▁In depend", + "▁Indep end", + "BU ILD", + "fail ure", + "▁P ORT", + "▁PO RT", + "▁ PORT", + "ю чи", + "▁med itation", + "sample s", + "sam ples", + "s amples", + "i ão", + "▁Ни кола", + "▁я зы", + "▁Tr uth", + "▁Tru th", + "▁co efficient", + "▁coeff icient", + "sl ug", + "▁XV III", + "▁XVI II", + "▁XVII I", + "ia o", + "i ao", + "de ck", + "dec k", + "▁раз ви", + "▁ad oles", + "ar ius", + "ari us", + "▁H az", + "▁Ha z", + "▁Pro test", + "▁Prote st", + "ra de", + "rad e", + "r ade", + "не ния", + "▁cl ause", + "conne ctor", + "connect or", + "conn ector", + "RA TE", + "R ATE", + "ц ю", + "▁Conne cticut", + "V S", + "abul ary", + "HO W", + "▁d elen", + "▁de len", + "▁del en", + "▁su ited", + "▁suit ed", + "▁suite d", + "▁Sur vey", + "ze c", + "z ec", + "ți i", + "ț ii", + "▁b acks", + "▁back s", + "▁ba cks", + "▁ backs", + "com merce", + "▁And rea", + "▁Andre a", + "▁Andr ea", + "▁propag anda", + "iz ioni", + "izi oni", + "izio ni", + "▁B il", + "▁Bi l", + "▁In nov", + "▁Inn ov", + "▁forg ive", + "▁oper ates", + "▁operate s", + "▁opera tes", + "ч ний", + "▁l ingu", + "▁lin gu", + "▁ling u", + "▁c ollar", + "▁col lar", + "▁coll ar", + "до л", + "сі й", + "zt en", + "zte n", + "z ten", + "im at", + "ima t", + "i mat", + "▁sh oe", + "ge nder", + "gen der", + "g ender", + "▁leg ally", + "▁legal ly", + "RO P", + "R OP", + "▁S leep", + "deleg ate", + "ID s", + "▁build s", + "▁qu er", + "▁que r", + "▁q uer", + "▁ quer", + "uls ion", + ". “", + "к ло", + "ri se", + "ris e", + "r ise", + "th ink", + "К о", + "▁bacter ia", + "▁magn ific", + "▁prison er", + "Cl ock", + "C lock", + "R B", + "ú t", + "▁L iz", + "▁Li z", + "gr a", + "g ra", + "▁And ré", + "▁Andr é", + "▁D ennis", + "▁Den nis", + "▁sur ge", + "▁surg e", + "ex isting", + "exist ing", + "▁W ald", + "▁Wal d", + "▁Wa ld", + "▁S chema", + "▁Sch ema", + "▁Sche ma", + "▁ Schema", + "▁war nings", + "▁warn ings", + "▁warning s", + "▁qu adr", + "▁quad r", + "at te", + "att e", + "▁E ins", + "▁Ein s", + "▁ad option", + "▁adopt ion", + "▁w anna", + "▁de rive", + "▁der ive", + "▁deriv e", + "▁ derive", + "▁a rena", + "▁are na", + "▁ar ena", + "▁aren a", + "▁Den ver", + "▁F i", + "▁ Fi", + "▁Jess ica", + "acy j", + "R atio", + "▁которы е", + "▁Act ivity", + "▁Activ ity", + "▁ Activity", + "em u", + "e mu", + "▁St alin", + "▁Sta lin", + "ag gi", + "agg i", + "a ggi", + "▁f ün", + "▁f ils", + "▁fil s", + "▁fi ls", + "aj u", + "a ju", + "card s", + "car ds", + "c ards", + "▁att raction", + "▁attract ion", + "▁attr action", + "▁attra ction", + "od ot", + "odo t", + "o dot", + "F at", + "▁H aven", + "▁Ha ven", + "▁Have n", + "▁Hav en", + "▁nine teenth", + "▁ninete enth", + "▁* *\"", + "▁** \"", + "▁m aggio", + "▁mag gio", + "ma ny", + "man y", + "m any", + "win ning", + "▁G A", + "▁ GA", + "▁d ummy", + "▁ dummy", + "Un able", + "en ci", + "enc i", + "ère nt", + "è rent", + "Im g", + "I mg", + "▁t ob", + "▁to b", + "DI P", + "D IP", + "S ince", + "▁Sa fe", + "▁Saf e", + "▁ Safe", + "Gu ard", + "is ure", + "i sure", + "port e", + "por te", + "p orte", + "▁stad ium", + "in di", + "ind i", + "▁App arently", + "ug no", + "▁w olf", + "▁ne ces", + "▁overse as", + "of s", + "o fs", + "ar el", + "are l", + "a rel", + "▁F ine", + "▁Fin e", + "▁Fi ne", + "▁cor rupt", + "▁n ovember", + "▁nov ember", + "▁nove mber", + "▁interpret ed", + "ib ile", + "ibil e", + "▁w ages", + "▁wa ges", + "▁wage s", + "▁Pre tty", + "▁Her bert", + "▁reg istr", + "вы м", + "an swer", + "ans wer", + "▁m orte", + "▁mor te", + "▁mort e", + "▁com posite", + "▁compos ite", + "Tool bar", + "▁iter ator", + "▁ iterator", + "ant ine", + "anti ne", + "▁init ialized", + "▁initial ized", + "▁initialize d", + "▁ initialized", + "▁poor ly", + "Access or", + "▁Han nah", + "▁Hann ah", + "▁то лько", + "ol an", + "ola n", + "o lan", + "▁o tto", + "▁ot to", + "▁ott o", + "▁ otto", + "▁str ikes", + "▁stri kes", + "▁strike s", + "▁conflict s", + "▁conflic ts", + "▁s urg", + "▁su rg", + "▁sur g", + "▁histor ian", + "▁historia n", + "wo man", + "w oman", + "▁l ibraries", + "be w", + "b ew", + ")- -(", + ")-- (", + "ga ther", + "g ather", + "▁L ip", + "▁Li p", + "▁f ict", + "▁fi ct", + "FIL TER", + "@ {", + "▁bl essed", + "▁bless ed", + "et ics", + "etic s", + "eti cs", + "▁f ork", + "▁for k", + "▁Me tal", + "▁Met al", + "▁Meta l", + "po lation", + "pol ation", + "p olation", + "▁negoti ations", + "▁gen us", + "▁genu s", + "▁cont rolling", + "▁control ling", + "VER T", + "VE RT", + "V ERT", + "▁P erry", + "▁Per ry", + "▁S PD", + "▁SP D", + "CA SE", + "C ASE", + "т вер", + "▁C rown", + "▁Cr own", + "▁Cro wn", + "▁Crow n", + "▁ind ul", + "▁indu l", + "▁e hemal", + "▁ampl itude", + "▁amplit ude", + "▁B ach", + "▁Ba ch", + "▁phot ographer", + "▁photograph er", + "n ý", + "▁inv ested", + "▁invest ed", + "▁P arte", + "▁Par te", + "▁Part e", + "▁pro long", + "C U", + "icht et", + "ichte t", + "res ume", + "▁c arb", + "▁car b", + "▁ca rb", + "ur st", + "urs t", + "▁N ixon", + "▁n eur", + "▁ne ur", + "▁neu r", + "▁ neur", + "▁corpor ations", + "▁corporation s", + "Op s", + "O ps", + "u u", + "l m", + "ap ple", + "app le", + "ch te", + "cht e", + "▁deliber ately", + "ber e", + "be re", + "b ere", + "▁fe br", + "▁provinc ia", + "▁provin cia", + "Over flow", + "▁E ight", + "▁ind ication", + "▁indic ation", + "▁pist ol", + "▁к ре", + "▁ кре", + "oc ial", + "oci al", + "o cial", + "▁r und", + "▁run d", + "▁ru nd", + "▁ rund", + "▁se hr", + "ok at", + "oka t", + "o kat", + "ül et", + "ü let", + "▁He at", + "Н а", + "▁о дин", + "▁од ин", + "IC S", + "I CS", + "ay e", + "a ye", + "▁eight een", + "▁t ug", + "▁tu g", + "LO T", + "L OT", + "▁L ar", + "▁La r", + "ning s", + "n ings", + "▁T odd", + "▁To dd", + "▁Tod d", + "▁organis ations", + "▁organisation s", + "▁g enes", + "▁gen es", + "▁ge nes", + "▁gene s", + "B ag", + "Ke ep", + "^{ +", + "Base d", + "Bas ed", + "B ased", + "sk in", + "ski n", + "s kin", + "▁to das", + "▁tod as", + "▁toda s", + "▁illustr ated", + "▁c f", + "▁ cf", + "▁ar riving", + "▁arriv ing", + "▁arr iving", + "▁excess ive", + "▁tra its", + "▁trait s", + "▁s ank", + "▁san k", + "▁Att ribute", + "▁ Attribute", + "▁G D", + "▁ GD", + "com par", + "comp ar", + "▁dent ro", + "br is", + "b ris", + "▁at oms", + "▁atom s", + "fr ed", + "fre d", + "f red", + "▁E val", + "▁Ev al", + "▁Eva l", + "▁ Eval", + "▁di stances", + "▁dist ances", + "▁distance s", + "st aw", + "sta w", + "краї н", + "vari ables", + "variable s", + "l c", + "на ли", + "нал и", + "н али", + "▁чемпи она", + "wi j", + "w ij", + "▁Sim ilar", + "je k", + "j ek", + "Pe t", + "P et", + "=\" $", + "ко то", + "▁R ang", + "▁Ra ng", + "▁Ran g", + "ion ato", + "iona to", + "▁bek annt", + "▁bekan nt", + "! *", + "Li m", + "L im", + "▁concl usions", + "▁conclusion s", + "ain te", + "ai nte", + "aint e", + "a inte", + "- ,", + "▁g ł", + "▁pass ive", + "▁Ga ussian", + "▁stag ione", + "ME DI", + "MED I", + "it ol", + "ito l", + "i tol", + "▁Jer emy", + "View s", + "class List", + "▁desper ately", + "▁desperate ly", + "▁ver l", + "▁ve rl", + "br ace", + "bra ce", + "N P", + "▁c ob", + "▁co b", + "▁A rist", + "▁Ar ist", + "▁Ari st", + "da p", + "d ap", + "Fil ters", + "Filter s", + "'=> '", + "ul tan", + "ult an", + "▁F actory", + "▁ Factory", + "è le", + "▁l asting", + "▁last ing", + "▁las ting", + "▁element ary", + "▁C M", + "▁ CM", + "▁Louis iana", + "▁p ov", + "▁po v", + "PC I", + "P CI", + "è de", + "▁P ink", + "▁Pin k", + "▁Br uno", + "▁Bru no", + "▁Brun o", + "▁Y ellow", + "▁ev angel", + "▁lik elihood", + "WID TH", + "▁$ -", + "▁ $-", + "ni co", + "nic o", + "n ico", + "hu i", + "h ui", + "ak ter", + "akt er", + "akte r", + "ne urs", + "neur s", + "n eurs", + "▁bre eze", + "▁bree ze", + "▁со ста", + "▁He ader", + "▁Head er", + "▁ Header", + "om rå", + "▁D ylan", + "▁Dy lan", + "▁Bi ographie", + "▁Univers ität", + "on so", + "ons o", + "HAND LE", + "J ournal", + "ea st", + "e ast", + "▁sup pliers", + "▁supplier s", + "▁table t", + "▁tab let", + "LI C", + "L IC", + "PER TY", + "ї в", + "▁z aw", + "▁za w", + "▁su bm", + "▁sub m", + "▁Fern ando", + "▁nou velle", + "▁nouve lle", + "▁Point s", + "▁ Points", + "▁str angers", + "▁strange rs", + "▁stranger s", + "▁strang ers", + "Component Model", + "ist ro", + "istr o", + "au rus", + "aur us", + "▁san ct", + "▁о дна", + "▁од на", + "▁В ы", + "▁о на", + "▁он а", + "▁ она", + "vert ical", + "Sp ring", + "▁Har old", + "▁Back ground", + "▁ Background", + "Bal ance", + "Key word", + "~$ \\", + "~ $\\", + "mal loc", + "m alloc", + "ORM AL", + "Sk ip", + "▁Mu ham", + "▁back wards", + "▁backward s", + "c ów", + "по зи", + "▁back end", + "▁ backend", + "▁de emed", + "▁accur ately", + "▁accurate ly", + "▁trans c", + "▁Broad way", + "▁g rud", + "▁gr ud", + "▁gru d", + "▁N amen", + "▁Name n", + "▁Na men", + "▁Nam en", + "▁sh ifting", + "▁shift ing", + "▁ment ally", + "▁mental ly", + "▁cal ories", + "▁cons ensus", + "Perm issions", + "Permission s", + "▁ob jet", + "▁obj et", + "▁elabor ate", + "at ts", + "att s", + "▁sn ake", + "▁ref res", + "▁refr es", + "ar u", + "a ru", + "▁reflect s", + "oun ge", + "o unge", + "R ank", + "▁K urt", + "▁Kur t", + "▁Ku rt", + "▁p ied", + "▁pie d", + "▁pi ed", + "▁exped ition", + "V el", + "▁O wen", + "Le ad", + "L ead", + "▁utter ly", + "▁Ar be", + "▁bre asts", + "▁breast s", + "IP S", + "I PS", + "▁hung er", + "▁hun ger", + "at em", + "ate m", + "a tem", + "▁vers chied", + "▁versch ied", + "▁Cam era", + "▁ Camera", + "▁Mün chen", + "iv als", + "ival s", + "iva ls", + "i vals", + "▁sp raw", + "▁spr aw", + "▁S ü", + "▁Was ser", + "▁mechan ics", + "Load ed", + "Lo aded", + "db c", + "d bc", + "▁re marks", + "▁rem arks", + "▁remark s", + "▁ remarks", + "▁} ).", + "▁}) .", + "▁ }).", + "▁pain ter", + "▁pa inter", + "▁paint er", + "▁h aut", + "▁ha ut", + "Mar shal", + "IS D", + "I SD", + "▁ve loc", + "▁vel oc", + "▁In cre", + "▁Inc re", + "W ar", + "▁ру с", + "▁com pte", + "▁comp te", + "▁compt e", + "ü g", + "▁Def inition", + "▁ Definition", + "▁G am", + "▁Ga m", + "▁H ir", + "▁Hi r", + "▁witness ed", + "▁g ren", + "▁gr en", + "▁gre n", + "▁ gren", + "▁hur ry", + "ch et", + "che t", + "c het", + "re verse", + "G F", + "▁Qu arter", + "п ла", + "▁s ar", + "▁sa r", + "sb urg", + "sbur g", + "s burg", + "▁D it", + "▁Di t", + "▁ Dit", + "▁Arn old", + "j k", + "▁l ambda", + "▁ lambda", + "è ge", + "▁o z", + "▁ oz", + "▁h ans", + "▁ha ns", + "▁han s", + "▁answ ering", + "▁answer ing", + "▁o live", + "▁ol ive", + "▁sp ont", + "▁spo nt", + "▁inter vals", + "▁interval s", + "> @", + "▁т ран", + "▁тра н", + "▁F ocus", + "▁ Focus", + "ч них", + "▁д ви", + "▁tri angle", + "▁r ally", + "▁P unk", + "▁Pun k", + "▁G and", + "▁Ga nd", + "se ctions", + "section s", + "sect ions", + "сси й", + "AC CESS", + "A CCESS", + "ha rm", + "har m", + "h arm", + "▁Sk ip", + "▁ Skip", + "▁D river", + "▁Dr iver", + "▁Drive r", + "▁ Driver", + "▁Sant iago", + "it ung", + "itu ng", + "▁B arr", + "▁Bar r", + "▁Ba rr", + "process or", + "▁real ised", + "▁realise d", + "ą z", + "le ave", + "▁C omo", + "▁Com o", + "▁Co mo", + "▁Re views", + "▁Review s", + "▁и зда", + "▁из да", + "▁earn ings", + "▁ear nings", + "▁earning s", + "▁S creen", + "▁Sc reen", + "▁Scre en", + "▁ Screen", + "gr and", + "gra nd", + "g rand", + "▁ap ril", + "▁apr il", + "▁sil ently", + "▁silent ly", + "ed o", + "e do", + "ue st", + "ues t", + "u est", + "oo oo", + "▁Исто рия", + "ра з", + "MAGE S", + "MAG ES", + "▁Sing h", + "▁Sin gh", + "▁Per fect", + "▁revolution ary", + "▁н і", + "▁ ні", + "▁Sch ools", + "▁School s", + "R ich", + "▁ch rom", + "▁chr om", + "▁an terior", + "▁ante rior", + "▁Indones ia", + "Con straints", + "Constraint s", + "▁\" __", + "▁\"_ _", + "▁six teen", + "▁sixt een", + "ér e", + "é re", + "мен та", + "мент а", + "N il", + "je l", + "j el", + "че ские", + "чески е", + "▁thr one", + "▁thro ne", + "▁aud iences", + "▁audience s", + "▁i hren", + "▁ih ren", + "▁ihr en", + "▁ihre n", + "ра б", + "Qu ick", + "in burgh", + "fi co", + "fic o", + "f ico", + "▁kid n", + "▁ki dn", + "irm ingham", + "is le", + "isl e", + "iz ación", + "iza ción", + "▁Ch ampions", + "▁Champion s", + "▁вы со", + "ol er", + "ole r", + "o ler", + "▁z ak", + "▁za k", + "▁p lat", + "▁pl at", + "▁V III", + "▁VI II", + "▁VII I", + "at ique", + "ati que", + "li ter", + "lit er", + "l iter", + "▁P rest", + "▁Pr est", + "▁Pres t", + "▁Pre st", + "in is", + "ini s", + "i nis", + "▁scient ist", + "▁m ån", + "▁må n", + "ke ley", + "kel ey", + "▁h yd", + "▁hy d", + "grad uate", + "of t", + "o ft", + "▁N GC", + "on gs", + "ong s", + "▁t ier", + "▁tie r", + "▁ti er", + "▁Sh aw", + "▁Sha w", + "un ächst", + "▁establish ing", + "▁ind icator", + "▁indic ator", + "▁Par ad", + "▁Pa rad", + "▁Para d", + "▁Tr ail", + "▁Tra il", + "UM N", + "▁sp ine", + "▁spin e", + "▁Vis ual", + "▁ Visual", + ":: $", + "▁t eles", + "▁te les", + "▁tele s", + "▁tel es", + "OP ER", + "O PER", + "▁pack aging", + "to ire", + "t oire", + "▁не ско", + "▁product ivity", + "A f", + "ні ї", + "▁de gener", + "▁deg ener", + "br it", + "b rit", + "U i", + "▁Y am", + "▁Ya m", + "▁d ough", + "▁do ugh", + "▁dou gh", + "os ph", + "osp h", + "▁cl ue", + "▁ре ги", + "▁me ille", + "▁tend ency", + "▁re lay", + "▁rel ay", + "▁design ers", + "▁designer s", + "▁Т у", + "Sh are", + "▁b icy", + "▁bi cy", + "▁M asters", + "▁Ma sters", + "▁Mas ters", + "▁Master s", + "▁м но", + "▁altern atives", + "▁alternative s", + "ет о", + "е то", + "▁coun tr", + "▁count r", + "▁W ow", + "▁Wo w", + "LO CAL", + "LOC AL", + "en ue", + "enu e", + "▁s lim", + "▁sl im", + "к ви", + "▁t ir", + "▁ti r", + "▁do it", + "lic a", + "li ca", + "l ica", + "ci pe", + "cip e", + "c ipe", + "iz ia", + "izi a", + "▁A ires", + "▁Air es", + "▁F alls", + "▁Fall s", + "▁Fal ls", + "▁concent rate", + "▁concentr ate", + "▁ne gl", + "▁neg l", + "▁Re in", + "? ,", + "▁G ott", + "▁Go tt", + "▁Got t", + "▁Ver ify", + "▁ Verify", + "▁Stud ios", + "▁Studio s", + "$ ('#", + "ow ym", + "owy m", + "я в", + "Prim itive", + "▁tax i", + "▁ta xi", + "▁Com mercial", + "▁Ч ер", + "▁Че р", + "place holder", + "se au", + "sea u", + "s eau", + "cor rect", + "he imer", + "heim er", + "▁H of", + "▁Ho f", + "▁d ia", + "▁di a", + "▁i rr", + "▁ir r", + "▁ur ged", + "▁urg ed", + "▁urge d", + "▁a nom", + "▁an om", + "▁ano m", + "▁t arde", + "▁tar de", + "▁tard e", + "ur m", + "u rm", + "▁se ized", + "▁sei zed", + "▁seiz ed", + "DO T", + "D OT", + "op acity", + "St rings", + "String s", + "Str ings", + "▁dec iding", + "▁decid ing", + "▁listen ers", + "▁listener s", + "ár a", + "á ra", + "▁pl anted", + "▁plan ted", + "▁plant ed", + "▁é taient", + "▁ét aient", + "Z oom", + "st ví", + "ng th", + "ä ude", + "▁C av", + "▁Ca v", + "▁v endor", + "▁vend or", + "▁ vendor", + "▁ ż", + "▁meas uring", + "▁necess ity", + "▁r ivers", + "▁ri vers", + "▁river s", + "▁riv ers", + "▁labor atory", + "▁E ff", + "▁reprodu ce", + "▁S ak", + "▁Sa k", + "▁not ebook", + "▁note book", + "▁reason ably", + "isecond s", + "i seconds", + "▁Part ial", + "▁ Partial", + "GUI D", + "GU ID", + "G UID", + "▁Per iod", + "▁ Period", + "▁reve aling", + "▁reveal ing", + "▁conv iction", + "▁ н", + "▁бу ли", + "▁altern ate", + "▁alter nate", + "cc iones", + "▁N AT", + "▁NA T", + "▁can onical", + "▁canon ical", + "mo z", + "m oz", + "▁Mé xico", + "M o", + "▁ш а", + "▁ ша", + "lim inary", + "f é", + "чно й", + "ч ной", + "▁Ham burg", + "▁Hamb urg", + "▁influ ential", + "▁b olt", + "▁bo lt", + "▁bol t", + "az zo", + "azz o", + "PH P", + "P HP", + "▁Sa udi", + "▁Saud i", + "▁Sau di", + "▁r m", + "▁ rm", + "▁cer ca", + "▁decor ated", + "▁st aat", + "▁sta at", + "Lo u", + "L ou", + "▁compet itors", + "во ї", + "▁diam ond", + "▁dia mond", + "▁m obil", + "▁mo bil", + "▁mob il", + "Click Listener", + "set State", + "▁s üd", + "; \"", + "œ ur", + "▁Lud wig", + "▁clin ic", + "▁e go", + "▁eg o", + "▁ ego", + "Thread ing", + "▁f ract", + "▁fr act", + "▁fra ct", + "Ref lection", + "oss ip", + "\"] [\"", + "▁L ov", + "▁Lo v", + "Ex press", + "Exp ress", + "Expr ess", + "д ри", + "if acts", + "ifact s", + "▁O ften", + "▁Of ten", + "▁ лу", + "▁p ets", + "▁pe ts", + "▁pet s", + "▁address ing", + "▁m ens", + "▁me ns", + "▁men s", + "▁ED IT", + "▁ EDIT", + "ud der", + "udd er", + "Vert ical", + "ка та", + "Cap t", + "C apt", + "verb ose", + "▁вой ны", + "UNK NOWN", + "un its", + "unit s", + "uni ts", + "per mission", + "perm ission", + "[ _", + "▁er sch", + "▁ers ch", + "▁comm unes", + "▁commun es", + "▁commune s", + "Un ityEngine", + "▁com mut", + "▁comm ut", + "kl ass", + "k lass", + "▁volt age", + "▁volta ge", + "re zent", + "rez ent", + "pe rf", + "per f", + "DR V", + "D RV", + "▁f ame", + "▁fam e", + "▁fa me", + "▁S pot", + "▁Sp ot", + "▁Л ю", + "▁c asting", + "▁cas ting", + "▁cast ing", + "hi m", + "h im", + "▁en gl", + "▁eng l", + "▁int ro", + "▁intr o", + "▁Г у", + "Comp any", + "some thing", + "som ething", + "▁cl icking", + "▁click ing", + "жи ва", + "▁fl ames", + "▁flame s", + "▁random ly", + "ex tr", + "ext r", + "Equal To", + "an ners", + "ann ers", + "anner s", + "anne rs", + "▁p arks", + "▁par ks", + "▁park s", + "▁murm ured", + "ми я", + "▁reason ing", + "сле д", + "▁n er", + "▁ne r", + "▁ ner", + "▁é c", + "▁ éc", + "ow ners", + "own ers", + "owner s", + "▁Д же", + "▁Дж е", + "▁me er", + "▁typ ing", + "▁ty ping", + "▁happ ily", + ".. ...", + "... ..", + ".... .", + ". ....", + "▁Ч а", + "be cca", + "bec ca", + "▁P apers", + "▁Pa pers", + "▁Pap ers", + "▁Paper s", + "▁Or acle", + "▁equ ilibrium", + "man agement", + "Li te", + "L ite", + "▁des ktop", + "▁desk top", + "ă r", + "▁G ill", + "▁Gi ll", + "▁Gil l", + "do rf", + "d orf", + "ig g", + "i gg", + "▁qu esta", + "▁que sta", + "▁quest a", + "▁ questa", + "Warning s", + "Warn ings", + "War nings", + "over flow", + "▁V T", + "▁ VT", + "▁cons isted", + "▁consist ed", + "▁A bu", + "▁Ab u", + "v scale", + "J O", + "ah o", + "a ho", + "▁T ensor", + "▁Ten sor", + "▁ Tensor", + "▁hes itated", + "▁w enn", + "▁we nn", + "▁wen n", + "map sto", + "maps to", + "▁controvers ial", + "M F", + "▁l ac", + "▁la c", + "▁an ch", + "▁anc h", + "▁ anch", + "▁A A", + "▁ AA", + "it ta", + "itt a", + "i tta", + "ul in", + "uli n", + "u lin", + "▁c ler", + "▁cl er", + "▁cle r", + "▁D iana", + "▁Di ana", + "▁Fre ud", + "▁challeng ed", + "▁challenge d", + "лё н", + "л ён", + "▁se ated", + "▁sea ted", + "▁seat ed", + "▁sm iles", + "▁smile s", + "▁cr acked", + "▁crack ed", + "▁а ктив", + "ско ј", + "dict ion", + "di ction", + "d iction", + "ex press", + "exp ress", + "expr ess", + "▁im posed", + "▁imp osed", + "▁pro tests", + "▁prote sts", + "▁protest s", + "▁prot ests", + "▁w ounds", + "▁wound s", + "C ulture", + "N Y", + "prevent Default", + "ad io", + "adi o", + "▁NE W", + "▁ NEW", + "B attle", + "▁se colo", + "▁sec olo", + "▁A x", + "▁found ing", + "(\" -", + "▁ret ro", + "▁retr o", + "▁pot atoes", + "import ant", + "ie me", + "iem e", + "i eme", + "ys ide", + "y side", + "d ummy", + "▁t ilt", + "▁til t", + "▁ti lt", + "▁R ules", + "▁Ru les", + "▁Rule s", + "▁ Rules", + "▁un ters", + "▁unt ers", + "▁unter s", + "A ud", + "V ENDOR", + "ud ge", + "un al", + "una l", + "u nal", + "▁Ad ult", + "▁im pat", + "▁imp at", + "▁rep airs", + "▁repair s", + "▁F erd", + "▁Fe rd", + "▁Fer d", + "▁Az ure", + "▁ Azure", + ")) :", + ") ):", + "▁pag ina", + "▁E pisode", + "File name", + "Fil ename", + "▁j á", + "▁oblig ation", + "ig hed", + "igh ed", + "▁pers istent", + "Mus ic", + "▁C ele", + "▁Ce le", + "▁Cel e", + "▁r y", + "▁ ry", + "▁cert ification", + "ul d", + "u ld", + "▁T L", + "▁ TL", + "▁sk irt", + "▁ski rt", + "▁M ini", + "▁Min i", + "▁Mi ni", + "▁B ring", + "▁Br ing", + ">< ?", + "> %", + "▁P and", + "▁Pan d", + "▁Pa nd", + "▁S UB", + "▁SU B", + "▁ SUB", + "▁compan ions", + "▁companion s", + "▁RE AD", + "▁ READ", + "▁S olutions", + "▁Solution s", + "▁acc essed", + "▁access ed", + "▁p osto", + "▁pos to", + "▁po sto", + "▁post o", + "▁pur suit", + "▁purs uit", + "ow i", + "o wi", + "▁gro cery", + "Sp e", + "S pe", + "haus en", + "▁normal ized", + "▁tra uma", + "gg i", + "g gi", + "ie nia", + "ien ia", + "▁aut umn", + "▁so vere", + "▁sov ere", + "▁Men schen", + "▁Mens chen", + "▁D AG", + "▁DA G", + "▁S ort", + "▁So rt", + "▁Sor t", + "▁ Sort", + "| ---", + "▁l iver", + "▁li ver", + "▁live r", + "▁liv er", + "▁ liver", + "env iron", + "DE CL", + "DEC L", + "▁ма й", + "▁N ak", + "▁Na k", + "bet ween", + "▁gentle man", + "in ging", + "ing ing", + "▁su bur", + "▁sub ur", + "ST O", + "S TO", + "ace ut", + "\\ !", + "▁Fuß ball", + "na r", + "n ar", + "▁b og", + "▁bo g", + "Token s", + "Tok ens", + "▁cer emon", + "▁cere mon", + "DA Y", + "D AY", + "▁out fit", + "▁agric ulture", + "ди и", + "▁N in", + "▁Ni n", + "▁Sp rings", + "▁Spring s", + "▁Spr ings", + "▁Co ach", + "▁d jango", + "▁ django", + "▁C rim", + "▁Cr im", + "▁te cn", + "Th ree", + "em os", + "e mos", + "▁be an", + "▁ bean", + "pi eler", + "pie ler", + "p ieler", + "ri tz", + "rit z", + "r itz", + "ta bs", + "tab s", + "t abs", + "▁Pro blem", + "in and", + "ina nd", + "oc on", + "oco n", + "o con", + "њ и", + "▁bu yer", + "▁buy er", + "us ement", + "use ment", + "▁b or", + "▁bo r", + "▁ bor", + "▁sett embre", + "pp e", + "p pe", + "▁D eg", + "▁De g", + "▁W a", + "▁w ives", + "▁fr anzös", + "▁mar ca", + "▁des cent", + "▁desc ent", + "▁S ha", + "▁Sh a", + "ver ts", + "vert s", + "v erts", + "▁Sh adow", + "▁ Shadow", + "▁Hug o", + "▁Hu go", + "▁A ppe", + "▁App e", + "▁Ap pe", + "▁ Appe", + "▁L ac", + "▁La c", + "al len", + "all en", + "alle n", + "os ity", + "osi ty", + "▁consult ation", + "▁T i", + "▁er ano", + "▁era no", + "▁eran o", + "▁lo vers", + "▁love rs", + "▁lov ers", + "▁lover s", + "▁уни версите", + "▁virt ue", + "▁view ers", + "M u", + "c ategories", + "▁о пера", + "▁over look", + "▁overl ook", + "▁тер рито", + "▁Oper ations", + "▁Operation s", + "▁ Operations", + "è ve", + "- (", + "▁ Ż", + "je v", + "j ev", + "▁c rist", + "▁cr ist", + "▁cris t", + "▁cri st", + "▁мар та", + "▁pro vin", + "▁prov in", + "product ion", + "produ ction", + "prod uction", + "p roduction", + "▁T all", + "▁Tal l", + "▁Ta ll", + "Requ ests", + "Request s", + "▁t iles", + "▁til es", + "▁tile s", + "▁ti les", + "ref lect", + "▁ar gc", + "▁arg c", + "▁ argc", + "▁t emplates", + "▁templ ates", + "▁template s", + "▁ templates", + "AR B", + "A RB", + "▁weiter e", + "▁weit ere", + ")? ;", + ") ?;", + "▁t oll", + "▁to ll", + "▁correspond ence", + "$ ;", + "L T", + "▁t am", + "▁ta m", + "de cess", + "dec ess", + "built in", + "da sh", + "das h", + "d ash", + "ze nie", + "zen ie", + "▁mole cular", + "▁chem icals", + "▁chemical s", + "▁rend ering", + "▁render ing", + "▁Sing les", + "▁Sin gles", + "▁Single s", + "Init ialized", + "Initial ized", + "Initialize d", + "▁Mar tha", + "▁Mart ha", + "ri ere", + "rie re", + "rier e", + "r iere", + "par agraph", + "para graph", + "as ters", + "ast ers", + "aster s", + "aste rs", + "a sters", + "▁dec ides", + "▁decide s", + "▁decid es", + "▁Flor ence", + "▁Flo rence", + "▁Floren ce", + "▁And ers", + "▁An ders", + "мо й", + "▁a pt", + "▁ap t", + "▁ apt", + "▁affili ate", + "ch el", + "che l", + "c hel", + "▁re vision", + "▁rev ision", + "Pat ch", + "P atch", + "▁fi scal", + "▁fis cal", + "wi ę", + "w ię", + "N ational", + "▁depend encies", + "TRAN S", + "TRA NS", + "▁r ack", + "▁rac k", + "▁ra ck", + "sel ling", + "s elling", + "na issance", + "c atalog", + "Sh ip", + "S hip", + "IM AGE", + "I MAGE", + "'] [", + "' ][", + "▁p rv", + "▁pr v", + "▁F en", + "▁Fe n", + "▁rad ar", + "▁ra dar", + "cond itions", + "condition s", + "▁Quest ions", + "▁Question s", + "▁v ivid", + "▁vi vid", + "▁viv id", + "op f", + "o pf", + "FA CE", + "F ACE", + "ry s", + "r ys", + "Ex tract", + "Ext ract", + "Extra ct", + "il ians", + "ili ans", + "ilia ns", + "pl ug", + "▁a té", + "▁at é", + "и л", + "▁like wise", + "▁L il", + "▁Li l", + "▁Cam peonato", + "AUT O", + "AU TO", + "▁M eta", + "▁Me ta", + "▁Met a", + "▁ Meta", + "re no", + "ren o", + "r eno", + "▁Trans fer", + "▁ Transfer", + "▁Mich elle", + "▁Michel le", + "▁Miche lle", + "bi s", + "b is", + "ń st", + "зо н", + "з он", + "▁C ultural", + "com pass", + "comp ass", + "▁my sql", + "▁ mysql", + "▁cancel led", + "▁cancell ed", + "▁ ’", + "to o", + "t oo", + "▁re bell", + "▁reb ell", + "▁rebel l", + "ég e", + "é ge", + "os z", + "o sz", + "▁com poser", + "▁comp oser", + "▁compos er", + "}\" )", + "} \")", + "▁des erves", + "▁deserve s", + "▁oh ne", + "▁J ed", + "▁Je d", + "K ernel", + "▁pract ition", + "▁in door", + "▁ind oor", + "▁config urations", + "▁configuration s", + "▁m eth", + "▁me th", + "▁met h", + "+ (", + "Quest ion", + "▁bl own", + "▁blo wn", + "▁blow n", + ") '", + "▁Ar gs", + "▁Arg s", + "▁ Args", + "F ake", + "▁d even", + "▁de ven", + "▁dev en", + "istrz ost", + "na io", + "▁\" {", + "▁L it", + "▁Li t", + "com ed", + "co med", + "come d", + "c omed", + "▁st am", + "▁sta m", + "▁pl ugins", + "▁plugin s", + "▁plug ins", + "▁ plugins", + "▁travel ling", + "▁trav elling", + "na ire", + "n aire", + "▁aut onom", + "▁auto nom", + "STRU CT", + "n h", + "né es", + "née s", + "n ées", + "▁consider ably", + "ко р", + "к ор", + "B G", + "▁lad der", + "▁h ast", + "▁has t", + "▁ha st", + "iz ado", + "iza do", + "▁s ele", + "▁se le", + "▁sel e", + "▁W ere", + "▁We re", + "▁Wer e", + "ar don", + "ard on", + "ardo n", + "B ank", + "bund le", + "b undle", + "▁anticip ated", + "▁C ot", + "▁Co t", + "▁else if", + "▁ elseif", + "▁Bl ues", + "▁Blue s", + "▁fil tered", + "▁filter ed", + "▁a uction", + "▁au ction", + "ed uc", + "edu c", + "e duc", + "▁Ex pression", + "▁Express ion", + "▁Exp ression", + "▁ Expression", + "in x", + "i nx", + "▁s ucks", + "▁su cks", + "▁suc ks", + "▁suck s", + "▁ма я", + "EL L", + "E LL", + "ющи й", + "▁Hud son", + "it ä", + "на ми", + "▁fem me", + "in ho", + "▁e vt", + "▁ev t", + "▁ evt", + "istribut ions", + "istribution s", + "▁r uss", + "▁ru ss", + "▁rus s", + "▁pet ition", + "▁petit ion", + "▁г ла", + "▁ гла", + "Si g", + "S ig", + "▁T ut", + "▁Tu t", + "Part ial", + "Ent ities", + "▁b ears", + "▁be ars", + "▁bear s", + "▁h ollow", + "▁hol low", + "__ [\"", + "▁R is", + "ț ă", + "dim s", + "di ms", + "d ims", + "▁compl ained", + "▁complain ed", + "▁m apped", + "▁map ped", + "▁ma pped", + "▁авгу ста", + "▁initi atives", + "▁initiative s", + "▁own s", + "ch ez", + "che z", + "▁dis pon", + "▁disp on", + "▁m ush", + "▁mus h", + "▁mu sh", + "q s", + "▁er folg", + "▁Nor weg", + "▁c et", + "▁ce t", + "im ag", + "ima g", + "i mag", + "▁исто ри", + "▁ни х", + "▁ них", + "Un til", + "U ntil", + "▁s talk", + "▁st alk", + "▁П ра", + "uv o", + "u vo", + "ie rz", + "ier z", + "ri eben", + "rie ben", + "rieb en", + "X T", + "ic als", + "ical s", + "ica ls", + "std out", + "▁extra cted", + "▁extract ed", + "▁Im ages", + "▁Image s", + "▁ Images", + "un def", + "und ef", + "unde f", + "u ndef", + "▁L é", + "▁accommod ation", + "▁T ouch", + "▁To uch", + "▁ Touch", + "▁intent ions", + "▁intention s", + "▁concent rated", + "▁concentr ated", + "▁concentrate d", + "▁Насе ление", + "▁ut ilis", + "▁util is", + "▁сле д", + "▁ след", + "li f", + "l if", + "▁comp ris", + "▁compr is", + "▁с бор", + "med ium", + "medi um", + "St ates", + "State s", + "Stat es", + "▁Би ография", + "▁Fa ith", + "U A", + "ADD RESS", + "▁r ated", + "▁rate d", + "▁rat ed", + "▁ra ted", + "▁ rated", + "▁R ena", + "▁Re na", + "▁Ren a", + "▁C ache", + "▁Ca che", + "▁ Cache", + "▁pe que", + "▁un used", + "▁unus ed", + "▁ unused", + "ni m", + "n im", + "ol ding", + "old ing", + "▁N r", + "R ay", + "ur ls", + "url s", + "▁em issions", + "▁emission s", + "I r", + "▁m å", + "be ar", + "b ear", + "▁L ub", + "▁Lu b", + "▁Out side", + "min ded", + "mind ed", + "▁PRO VID", + "▁s ó", + "▁civil ian", + "Find er", + "Fin der", + "Fi nder", + "F inder", + "▁achie ving", + "mod ified", + "la ne", + "lan e", + "l ane", + "Se nder", + "Send er", + "S ender", + "▁Cr ime", + "▁Crim e", + "REQ UI", + "▁open ly", + "▁Belg ium", + "ic ity", + "ici ty", + "icit y", + "i city", + "▁M az", + "▁Ma z", + "▁st agger", + "▁stag ger", + "}} $,", + "}}$ ,", + "} }$,", + "na te", + "nat e", + "n ate", + "'' '", + "' ''", + "▁Ge off", + "ll i", + "l li", + "Su ite", + "▁D istribution", + "▁я кий", + "Com bo", + "Comb o", + "ho oks", + "hook s", + "▁F ight", + "▁Fig ht", + "▁Fi ght", + "Set s", + "Se ts", + "S ets", + "▁m k", + "▁ mk", + "▁gu ides", + "▁guide s", + "▁guid es", + "▁princip ale", + "▁principal e", + "Pre ferences", + "ti ny", + "t iny", + "ap pen", + "app en", + "appe n", + "a ppen", + "▁ru ined", + "▁ruin ed", + "▁sl iding", + "▁slid ing", + "▁Z en", + "▁Ze n", + "▁oct ubre", + "pos er", + "po ser", + "pose r", + "p oser", + "▁F lag", + "▁Fl ag", + "▁ Flag", + "▁b oom", + "▁bo om", + "▁Det ect", + "▁activ ation", + "▁обра зова", + "▁entertain ing", + "▁entert aining", + "▁protect ive", + "ál l", + "á ll", + "▁Fl ash", + "▁mid st", + "▁mi dst", + "ствен ной", + "▁Ph D", + "ij ing", + "iji ng", + "cl ub", + "get C", + "▁tro uve", + "▁trou ve", + "am bers", + "amb ers", + "amber s", + "▁g reed", + "▁gr eed", + "▁gre ed", + "am arin", + "ama rin", + "amar in", + "▁suspic ious", + "▁susp icious", + "▁dep uty", + "▁deput y", + "as per", + "asp er", + "▁fun ded", + "▁fund ed", + "al one", + "alo ne", + "▁t ract", + "▁tr act", + "▁tra ct", + "▁ tract", + "▁R ating", + "▁Ra ting", + "▁Rat ing", + "ad ays", + "ada ys", + "a days", + "▁st att", + "▁stat t", + "▁sta tt", + "▁Priv acy", + "▁_ _(", + "▁__ (", + "▁ __(", + "▁f ights", + "▁fight s", + "á j", + "\\ ]", + "ag h", + "a gh", + "or na", + "orn a", + "▁Diam ond", + "▁pro totype", + "▁proto type", + "▁prot otype", + "▁ prototype", + "▁Str ateg", + "ha do", + "had o", + "h ado", + "▁l ungs", + "▁lung s", + "▁lun gs", + "Pro totype", + "Proto type", + "ließ lich", + "▁d ive", + "▁di ve", + "▁div e", + "co v", + "c ov", + "▁M ist", + "▁Mi st", + "▁Mis t", + "▁T ypes", + "▁Type s", + "▁Ty pes", + "▁Typ es", + "▁ Types", + "▁di agonal", + "▁p review", + "▁pre view", + "▁prev iew", + "▁ preview", + "▁Cont ainer", + "▁ Container", + "DESC RIP", + "▁brit ann", + "▁C ord", + "▁Co rd", + "▁Cor d", + "ak ov", + "ako v", + "a kov", + "▁far ming", + "▁farm ing", + "▁p ère", + "▁k ills", + "▁kill s", + "▁kil ls", + "▁Car ib", + "▁Ca rib", + "ћ и", + "▁А л", + "? ;", + "▁пи са", + "▁ писа", + "▁En sure", + "par sed", + "parse d", + "pars ed", + "än ge", + "äng e", + "▁D elta", + "▁Del ta", + "▁ Delta", + "▁g aining", + "▁gain ing", + "▁ga ining", + "▁n oting", + "▁not ing", + "▁no ting", + "▁B arb", + "▁Bar b", + "▁Ba rb", + "▁фев ра", + "▁фе вра", + "Em p", + "E mp", + "▁{ })", + "▁{} )", + "▁ {})", + "▁sy ntax", + "▁syn tax", + "▁synt ax", + "W alk", + "▁P ere", + "▁Per e", + "▁Pe re", + "Is Null", + "▁U V", + "▁ UV", + "▁ret val", + "▁ retval", + "▁sim plicity", + "▁simpl icity", + "▁rein force", + "Lin q", + "▁diff usion", + "▁dis orders", + "▁disorder s", + "ât re", + "â tre", + "ui ty", + "uit y", + "u ity", + "▁hel pless", + "▁help less", + "Me asure", + "▁com pression", + "▁comp ression", + "▁compr ession", + "▁compress ion", + "▁Co al", + "olut ely", + "olute ly", + "og ue", + "o gue", + "▁up ward", + "▁Block ly", + "▁b ride", + "▁br ide", + "parse Int", + "▁is olation", + "▁isol ation", + "▁regul atory", + "ș ti", + "ric ane", + "м б", + "▁с ло", + "▁ сло", + "▁sa lad", + "▁sal ad", + "we i", + "w ei", + "▁B asket", + "▁Bas ket", + "▁M ON", + "▁MO N", + "▁ MON", + "\"> &", + "\" >&", + "do ors", + "door s", + "▁K ill", + "▁Kil l", + "▁Ki ll", + "▁conspir acy", + "▁M iles", + "▁Mil es", + "▁Mi les", + "wa nt", + "wan t", + "w ant", + "Mod ifier", + "▁batter ies", + "▁batt eries", + "iv as", + "iva s", + "i vas", + "▁att endance", + "▁attend ance", + "▁AUT H", + "▁AU TH", + "▁ AUTH", + "▁с ві", + ".. .,", + "... ,", + "▁aggreg ate", + "▁de struct", + "▁dest ruct", + "▁four teen", + "▁м ет", + "▁ме т", + "▁ мет", + "▁both ered", + "▁bother ed", + "el te", + "elt e", + "e lte", + "▁m ism", + "▁mis m", + "▁mi sm", + "▁res ting", + "▁rest ing", + "▁P ars", + "▁Par s", + "▁Pa rs", + "▁ Pars", + "▁id le", + "▁ idle", + "▁d eren", + "▁de ren", + "▁der en", + "▁dere n", + "▁di ary", + "▁dia ry", + "▁v ague", + "▁va gue", + "▁vag ue", + "▁margin al", + "▁marg inal", + "Wr it", + "W rit", + "Bo t", + "B ot", + "▁Met ro", + "▁e arning", + "▁earn ing", + "▁ear ning", + "hist oire", + "his toire", + "▁end orse", + "▁be ard", + "▁bear d", + "▁Chair man", + "ie b", + "i eb", + "▁neut r", + "▁neu tr", + "▁am bit", + "▁amb it", + "▁Leon ard", + "ban ds", + "band s", + "b ands", + "▁D ale", + "▁Da le", + "▁Dal e", + "▁ver ified", + "Al gorithm", + "Enumer able", + "op code", + "cast le", + "cas tle", + "š e", + "▁Venez uela", + "▁de scriptions", + "▁des criptions", + "▁description s", + "▁value d", + "▁val ued", + "▁chapter s", + "▁chap ters", + "▁I ls", + "▁Il s", + "▁cl arity", + "▁clar ity", + "▁tour ists", + "▁tourist s", + "Da n", + "D an", + "▁t ribe", + "▁tr ibe", + "▁tri be", + "▁trib e", + "▁г и", + "▁ ги", + "fol k", + "f olk", + "ac cur", + "acc ur", + "▁St ack", + "▁Sta ck", + "▁ Stack", + "▁adv ocate", + "▁advoc ate", + "▁G ene", + "▁Ge ne", + "▁Gen e", + "Im ages", + "Image s", + "▁rig id", + "▁con greg", + "▁congr eg", + "▁start up", + "▁dead line", + "co uld", + "cou ld", + "c ould", + "▁beg ann", + "▁began n", + "▁cal ci", + "▁calc i", + "▁Cir cle", + "▁Circ le", + "▁in cons", + "▁inc ons", + "▁incon s", + "aaaa aaaa", + "▁rub bed", + "ape ut", + "ua rio", + "uar io", + "u ario", + "worth y", + "wor thy", + "wort hy", + "▁уча сти", + "▁участ и", + "▁fam ília", + "▁synchron ized", + "▁unf air", + "rs p", + "r sp", + "▁soc ieties", + "▁societ ies", + "bo at", + "gr o", + "g ro", + "▁k at", + "▁ka t", + "▁ kat", + "▁p oker", + "▁po ker", + "▁pok er", + "▁l ocks", + "▁loc ks", + "▁lo cks", + "▁lock s", + "▁G F", + "▁ GF", + "▁re conc", + "▁recon c", + "▁Maur ice", + "▁Mau rice", + "__( /*!", + "▁ble eding", + "äs ident", + "▁по след", + "▁после д", + "▁deriv ative", + "ша я", + "cc ió", + "c ció", + "▁cr ushed", + "▁crush ed", + "▁tempor arily", + "▁co aches", + "▁coach es", + "▁Mo vement", + "▁Move ment", + "▁Mov ement", + "}} $.", + "}}$ .", + "} }$.", + "▁K yle", + "▁Ky le", + "▁S ohn", + "▁So hn", + "▁cre ator", + "▁creat or", + "ind ust", + "▁E rik", + "▁Er ik", + "▁se iz", + "▁sei z", + "▁dim ensional", + "▁dimension al", + "▁ dimensional", + "▁I st", + "▁Is t", + "▁pre val", + "▁pr eval", + "▁prev al", + "he ads", + "head s", + "▁про ти", + "▁determ ines", + "▁determine s", + "▁determin es", + "eg y", + "e gy", + "▁U INT", + "▁UI NT", + "▁ UINT", + "▁V olk", + "▁Vol k", + "pa wn", + "p awn", + "Ph oto", + "▁C olin", + "▁Col in", + "▁Co lin", + "ap propri", + "app ropri", + "ort ion", + "st eller", + "stell er", + "É tat", + "▁im ply", + "▁imp ly", + "▁impl y", + "▁t outes", + "▁to utes", + "▁tou tes", + "▁tout es", + "▁toute s", + "VO L", + "V OL", + "an ing", + "ani ng", + "a ning", + "Tool tip", + "ig ious", + "igi ous", + "▁e ternal", + "▁etern al", + "▁P oz", + "▁Po z", + "▁bank rupt", + "▁fail ures", + "▁failure s", + "uer te", + "▁вре ме", + "zu ng", + "z ung", + "▁t cp", + "▁tc p", + "▁ tcp", + "▁cont ainers", + "▁contain ers", + "▁container s", + "ou sel", + "ous el", + "ouse l", + "▁H IV", + "▁con ced", + "▁conc ed", + "▁conce d", + "▁sept iembre", + "gi rl", + "g irl", + "▁C ho", + "▁Ch o", + "▁f az", + "▁fa z", + "▁Up per", + "▁ Upper", + "▁For ces", + "▁Force s", + "äh lt", + "in ject", + "Re ceived", + "MA T", + "M AT", + "ag lia", + "ów nie", + "ówn ie", + "/ '", + "▁p ip", + "▁pi p", + "▁G est", + "▁Ge st", + "▁Ges t", + "▁l ado", + "▁la do", + "▁lad o", + "▁compat ibility", + "▁m are", + "▁mar e", + "▁ma re", + "▁ mare", + "▁Cle arly", + "▁Clear ly", + "vers ation", + "Ver s", + "V ers", + "▁ch ick", + "▁chi ck", + "▁organ ize", + "▁organiz e", + "▁econom ics", + "▁economic s", + "▁ancest ors", + "ME D", + "M ED", + "▁sc rub", + "▁scr ub", + "▁label ed", + "▁lab eled", + "▁п р", + "▁S uz", + "▁Su z", + "▁A str", + "▁As tr", + "▁Ast r", + "allow een", + "allo ween", + "rh s", + "r hs", + "as ci", + "asc i", + "▁C ancer", + "▁Can cer", + "▁H unt", + "▁Hun t", + "▁Hu nt", + "▁switch ing", + "▁R idge", + "Se q", + "S eq", + "▁gi ugno", + "bus iness", + "▁char ming", + "▁charm ing", + "▁I o", + "▁ Io", + "▁prés ident", + "ek ing", + "e king", + "í l", + "en h", + "e nh", + "pr it", + "p rit", + "erc ise", + "án ak", + "á nak", + "▁х ра", + "▁ хра", + "▁b ugs", + "▁bu gs", + "▁bug s", + "▁жи во", + "▁light ning", + "▁never theless", + "▁length s", + "G U", + "H idden", + "Act or", + "Ac tor", + "A ctor", + "To pic", + "Top ic", + "T opic", + "▁H orse", + "▁Hor se", + "ћ е", + "el ines", + "eline s", + "eli nes", + "elin es", + "e lines", + "▁trag edy", + "▁traged y", + "int endo", + "▁abund ance", + "▁ev ac", + "it ably", + "+\\ _\\", + "▁rec ib", + "ua ted", + "uate d", + "u ated", + "рі ї", + "▁fool ish", + "▁foo lish", + "▁t m", + "▁ tm", + "▁des pair", + "▁desp air", + "TO KEN", + "▁comp romise", + "▁comprom ise", + "▁Person en", + "▁Pers onen", + "▁investig ated", + "▁investigate d", + "▁ex clude", + "▁excl ude", + "▁telev is", + "▁tele vis", + "▁pull s", + "▁pul ls", + "▁according ly", + "▁accord ingly", + "▁f ő", + "▁Le ave", + "▁ Leave", + "oper ations", + "operation s", + "cri m", + "cr im", + "c rim", + "▁r hs", + "▁rh s", + "▁ rhs", + "▁form ally", + "▁formal ly", + "▁L ily", + "▁Li ly", + "▁Lil y", + "▁Com ments", + "▁Comm ents", + "▁Comment s", + "▁se ptember", + "▁sept ember", + "ie fs", + "ief s", + "▁tre asure", + "Http Servlet", + "ді в", + "д ів", + "▁dis claimer", + "lu ss", + "l uss", + "▁ка о", + "ro gen", + "rog en", + "r ogen", + "▁Start ing", + "▁Star ting", + "▁d ém", + "▁dé m", + "▁select ing", + "▁ ↘", + "▁О н", + "▁Pract ice", + "▁p orte", + "▁por te", + "▁port e", + "▁ porte", + "▁as sure", + "▁ass ure", + "▁frustr ated", + "S ink", + "▁A ri", + "▁Ar i", + "▁esc ort", + "ais es", + "ai ses", + "aise s", + "a ises", + "▁b ush", + "▁bu sh", + "▁bus h", + "▁Se ine", + "▁F ill", + "▁Fil l", + "▁Fi ll", + "▁ Fill", + "▁S ull", + "▁Su ll", + "▁Sul l", + "Do t", + "D ot", + "vi l", + "v il", + "un ing", + "uni ng", + "u ning", + "Render ing", + "Rend ering", + "sh ake", + "sha ke", + "пи си", + "пис и", + "pt e", + "p te", + "▁b end", + "▁be nd", + "▁ben d", + "▁jewel ry", + "▁Stock holm", + "▁Hon estly", + "! [", + "▁array s", + "▁arr ays", + "▁War ner", + "▁sh aft", + "▁sha ft", + "▁C ann", + "▁Can n", + "▁Ca nn", + "▁Pitt sburgh", + "ir ical", + "iri cal", + "i rical", + "au tre", + "aut re", + "▁R ück", + "▁gen naio", + "▁Ш а", + "an nte", + "ann te", + "annt e", + "ps hire", + "p shire", + "но логи", + "н ологи", + "ét a", + "é ta", + "▁pr inter", + "▁print er", + "▁prin ter", + "▁dam ages", + "▁damage s", + "▁Isa ac", + "▁Famil ie", + "Code s", + "Co des", + "C odes", + "th rift", + "no b", + "n ob", + "▁c av", + "▁ca v", + "▁techn ically", + "▁technical ly", + "▁I mm", + "▁Im m", + "▁tr icks", + "▁tri cks", + "▁trick s", + "EA R", + "E AR", + "▁Sub ject", + "▁ Subject", + "▁ne eding", + "▁need ing", + "▁G ir", + "▁Gi r", + "Bo ard", + "B oard", + "▁re he", + "▁rem inder", + "▁remind er", + "▁sh iver", + "K it", + "▁strugg les", + "▁struggle s", + "▁gen om", + "▁ge nom", + "im il", + "imi l", + "i mil", + "Reg istration", + "▁gl oves", + "▁glo ves", + "▁Z ur", + "▁Zu r", + "▁B eg", + "▁Be g", + "▁in clusive", + "▁incl usive", + "/ ,", + "og an", + "oga n", + "o gan", + "po que", + "cont rib", + "contr ib", + "ши н", + "ш ин", + "▁M ama", + "▁Ma ma", + "▁Mam a", + "print s", + "▁re named", + "▁ren amed", + "ють ся", + "ю ться", + "net dev", + "▁comp ile", + "▁ compile", + "▁ §", + "M UL", + "▁dr aws", + "▁draw s", + "co ck", + "c ock", + "▁сво и", + "▁M um", + "▁Mu m", + "sp ieler", + "spi eler", + "s pieler", + "▁n ail", + "▁na il", + "▁ nail", + "▁trans it", + "▁S aw", + "▁Sa w", + "▁com press", + "▁comp ress", + "▁compre ss", + "▁compr ess", + "▁ compress", + "▁purch ases", + "▁purchase s", + "▁per forms", + "▁perform s", + "▁dem ol", + "▁demo l", + "▁comm ence", + "▁C B", + "▁ CB", + "▁A ber", + "▁Ab er", + "▁c ush", + "▁cu sh", + "▁ком п", + "▁ру ко", + "▁Muham mad", + "▁Net flix", + "▁Environment al", + "No rm", + "N orm", + "▁w ir", + "null ptr", + "▁refuge es", + "до н", + "д он", + "▁B irmingham", + "New s", + "Ne ws", + "▁В се", + "Or ient", + "O rient", + "As sembly", + "▁introdu cing", + "fin der", + "find er", + "fi nder", + "f inder", + "▁scholar ship", + "▁scholars hip", + "▁ос нова", + "▁основ а", + "if a", + "i fa", + "Si ng", + "S ing", + "ib lic", + "ibli c", + "i blic", + "istribut ed", + "istribute d", + "▁depart ments", + "▁department s", + "CR EF", + "CRE F", + "C REF", + "▁Malays ia", + "CO NF", + "CON F", + "▁Cl aud", + "▁Bu ilt", + "▁ Built", + "RAN GE", + "Re direct", + "Red irect", + "LE ASE", + "-- -------", + "---- -----", + "-------- -", + "--- ------", + "----- ----", + "------ ---", + "------- --", + "- --------", + "▁П у", + "▁n umpy", + "▁num py", + "▁project ed", + "▁remind s", + "▁- *-", + "ib ling", + "ibli ng", + "i bling", + "▁s lower", + "▁sl ower", + "▁slow er", + "op p", + "o pp", + "ro pic", + "rop ic", + "r opic", + "▁Mont real", + "▁detect ive", + "TH READ", + "▁qu é", + "▁R osa", + "▁Ro sa", + "▁Ros a", + "▁seven th", + "▁sevent h", + "Col ors", + "Color s", + "de mo", + "dem o", + "▁E sta", + "▁Est a", + "▁Es ta", + "ff f", + "f ff", + "ick ets", + "icket s", + "Gr e", + "G re", + "á b", + "bo ost", + "▁Go ing", + "▁Su ite", + "▁ Suite", + "▁adapt ation", + "▁j ours", + "▁jour s", + "▁jo urs", + "▁jou rs", + "▁ jours", + "▁Or th", + "▁Ort h", + "х і", + "Fig ure", + "▁su pers", + "▁sup ers", + "▁super s", + "▁access ories", + "we ak", + "▁dist ress", + "fr ied", + "f ried", + "▁go og", + "ка з", + "▁far mer", + "▁farm er", + "it ational", + "itation al", + "itat ional", + "Go ld", + "G old", + "▁ass hole", + "▁assh ole", + "▁Cont roller", + "▁Control ler", + "▁ Controller", + "▁ар хи", + "To o", + "T oo", + "▁mol to", + "▁p ropri", + "▁prop ri", + "▁ propri", + "▁al go", + "▁alg o", + "Af f", + "A ff", + "re sc", + "res c", + "r esc", + "▁D y", + "▁con gr", + "▁T es", + "▁Te s", + "▁W IN", + "▁ WIN", + "de serialize", + "des erialize", + "sy n", + "s yn", + "▁chem istry", + "m iddle", + "▁an imated", + "▁anim ated", + "▁K um", + "▁Ku m", + "file Name", + "Amer ica", + "▁dr ums", + "▁dru ms", + "▁drum s", + "▁program a", + "▁n ej", + "▁ne j", + "▁ nej", + "Read Only", + "▁Б ра", + "-- -----", + "---- ---", + "--- ----", + "----- --", + "------ -", + "- ------", + "Mut ex", + "Mu tex", + "un ned", + "unn ed", + "ynam ics", + "ynamic s", + "co system", + "cos ystem", + "▁R ect", + "▁Re ct", + "▁Rec t", + "▁ Rect", + "▁an ime", + "▁anim e", + "▁I BM", + "▁need le", + "es ser", + "ess er", + "esse r", + "▁incl u", + "▁inc lu", + "Le an", + "tr aining", + "tra ining", + "train ing", + "▁b our", + "▁bo ur", + "▁bou r", + "▁ bour", + "ab ases", + "abase s", + "aba ses", + "▁tak że", + "wa rz", + "war z", + "w arz", + "▁ste pping", + "▁step ping", + "▁T IME", + "▁ TIME", + "▁Ein stein", + "▁Log in", + "▁Lo gin", + "▁ Login", + "pon ential", + "ponent ial", + "De ad", + "D ead", + "in str", + "ins tr", + "inst r", + "▁ne ural", + "▁neu ral", + "▁neur al", + "▁ub ic", + "▁Init ialized", + "▁Initialize d", + "▁Initial ized", + "▁ Initialized", + "▁facil itate", + "G D", + "}{ (", + "} {(", + "D ark", + "▁n ag", + "▁na g", + "min ipage", + "Size s", + "Si zes", + "S izes", + "▁w orm", + "▁wor m", + "▁wo rm", + "bi as", + "bia s", + "b ias", + "Su ch", + "S uch", + "wick lung", + "▁sp ouse", + "▁spo use", + "▁surviv ors", + "er st", + "ers t", + "at ype", + "aty pe", + "a type", + "}) $,", + "})$ ,", + "} )$,", + "▁n l", + "▁ nl", + "▁cogn itive", + "▁o nde", + "▁on de", + "▁ onde", + "▁en abling", + "▁soc iet", + "▁soci et", + "▁c lan", + "▁cl an", + "▁ex cluded", + "▁excl uded", + "▁exclude d", + "▁th under", + "▁ent ropy", + "▁entr opy", + "▁fast est", + "RE EN", + "REE N", + "▁Vien na", + "▁fl owing", + "▁flo wing", + "▁flow ing", + "▁aff irm", + "al om", + "alo m", + "▁h ips", + "▁hi ps", + "▁hip s", + "▁can nab", + "▁st icks", + "▁stick s", + "▁cur riculum", + "▁ret ained", + "▁retain ed", + "▁ext ending", + "▁extend ing", + "ó z", + "he aded", + "head ed", + "ex c", + "e xc", + "▁je ho", + "▁for ests", + "▁fore sts", + "▁forest s", + "ma nia", + "man ia", + "m ania", + "▁C anal", + "▁Can al", + "▁Ca nal", + "▁S out", + "▁So ut", + "▁Sou t", + "▁B ahn", + "▁Ba hn", + "▁Bah n", + "▁T EXT", + "▁TE XT", + "▁ TEXT", + "▁др жа", + "▁User s", + "▁Us ers", + "▁Use rs", + "▁ Users", + "▁G EN", + "▁ GEN", + "sl ash", + "ben falls", + "Text Field", + "▁r av", + "▁ra v", + "▁ rav", + "▁continu ously", + "▁continuous ly", + "IT ER", + "ITE R", + "I TER", + "▁Jen ny", + "▁Jenn y", + "ch os", + "cho s", + "c hos", + "▁am big", + "▁amb ig", + "▁ж ур", + "Aut ow", + "Auto w", + "▁V eter", + "▁Ve ter", + "▁dest in", + "H om", + "au ge", + "aug e", + "a uge", + "▁com mod", + "▁comm od", + "▁gar lic", + "< =", + "▁dram atically", + "▁dramatic ally", + "CA N", + "C AN", + "an cers", + "ance rs", + "anc ers", + "ancer s", + "() }", + "( )}", + "gh ai", + "▁tw ee", + "▁twe e", + "▁сент ября", + "GP U", + "G PU", + "▁B omb", + "▁Bo mb", + "▁young est", + "▁c age", + "▁ca ge", + "ok s", + "o ks", + "ic hes", + "ich es", + "iche s", + "i ches", + "▁T ests", + "▁Te sts", + "▁Test s", + "▁Tes ts", + "▁ Tests", + "sk ý", + "cur y", + "cu ry", + "c ury", + "na ls", + "nal s", + "n als", + "ț a", + "▁V oice", + "▁Vo ice", + "Depend ency", + "v f", + "e ous", + "▁Z a", + "▁am ateur", + "▁G host", + "▁Gh ost", + "▁dis ability", + "▁Вла ди", + "▁rev enge", + "▁reven ge", + "Trans lation", + "▁cour tesy", + "ски я", + "▁bl ob", + "▁blo b", + "▁ blob", + "ä ß", + "ó j", + "▁print s", + "▁prin ts", + "▁ prints", + "▁pro ves", + "▁pr oves", + "▁prov es", + "▁prove s", + ">? [<", + "▁ut ils", + "▁util s", + "▁ utils", + "ty pen", + "type n", + "typ en", + "▁t erra", + "▁ter ra", + "▁terr a", + "▁ terra", + "▁min eral", + "▁mine ral", + "▁miner al", + "▁war rior", + "▁ме ст", + "▁D S", + "▁ DS", + "Em b", + "E mb", + "get Data", + "ли чи", + "лич и", + "▁sa fer", + "▁saf er", + "▁safe r", + "▁com une", + "▁comun e", + "▁hier archy", + "Cred entials", + "res se", + "ress e", + "r esse", + "gr av", + "gra v", + "g rav", + "lo gs", + "log s", + "l ogs", + "br os", + "bro s", + "b ros", + "BUT TON", + "lit eral", + "liter al", + "l iteral", + "▁S r", + "an tal", + "ant al", + "anta l", + "▁mer cy", + "▁merc y", + "DA P", + "D AP", + "▁Mag gie", + "▁sust ained", + "▁sustain ed", + "N M", + "Re view", + "Rev iew", + "▁Buen os", + "▁de aler", + "▁deal er", + "en es", + "ene s", + "e nes", + "▁file Name", + "▁ fileName", + "bb ra", + "b bra", + "ро ма", + "ром а", + "Inst all", + "▁Mor ning", + "LE T", + "L ET", + "ip a", + "i pa", + "G a", + "го в", + "г ов", + "▁Sche dule", + "▁ Schedule", + "▁rep orters", + "▁report ers", + "▁reporter s", + "▁pecul iar", + "▁sup plier", + ")$ -", + ") $-", + "ë l", + "▁roll s", + "▁né cess", + "▁p reg", + "▁pre g", + "▁pr eg", + "▁Re yn", + "▁sur render", + "▁contribut ing", + ")+ \\", + ") +\\", + "PRO P", + "PR OP", + "P ROP", + "▁dec imal", + "▁Town ship", + "gr p", + "g rp", + "▁terror ist", + "pt o", + "p to", + "on en", + "one n", + "o nen", + "▁Polit ics", + "▁Pe arl", + "▁Pear l", + "▁pil low", + "▁pill ow", + "▁gr ades", + "▁grad es", + "▁grade s", + "▁gra des", + "▁ grades", + "TH E", + "T HE", + "▁num ero", + "▁numer o", + "▁nu mero", + "i NdEx", + "M igration", + "PE ND", + "P END", + "ph oto", + "▁cent ered", + "▁center ed", + "▁r het", + "▁rh et", + "egr ünd", + "▁laund ry", + "get Node", + "▁est imation", + "▁estim ation", + "▁I v", + "▁wh oles", + "▁who les", + "▁whole s", + "ше ния", + "▁const itutional", + "▁constitution al", + "am ination", + "amin ation", + "▁Municip al", + "ad t", + "a dt", + "th y", + "t hy", + "▁pub li", + "▁di cembre", + "▁dic embre", + "▁dice mbre", + "` )", + "▁Ch rome", + "ef e", + "e fe", + "con g", + "co ng", + "c ong", + "bre aking", + "break ing", + "at ched", + "atch ed", + "es tr", + "est r", + "e str", + "▁i di", + "▁id i", + "▁ idi", + "VER Y", + "V ERY", + "▁app el", + "▁ap pel", + "▁appe l", + "▁Techn ical", + "tc x", + "t cx", + "DO UBLE", + "se k", + "s ek", + "hu ng", + "h ung", + "▁A ur", + "▁Au r", + "coll apse", + "▁adv ise", + "▁advis e", + "▁Pr imary", + "▁Pri mary", + "▁Prim ary", + "▁ Primary", + "ia z", + "i az", + "▁a nten", + "▁an ten", + "▁ant en", + "▁ante n", + "▁ anten", + "▁bro ader", + "▁broad er", + "▁ju nio", + "▁jun io", + "▁juni o", + "▁w ool", + "▁wo ol", + "▁hat red", + "▁ex agger", + "Con v", + "Co nv", + "kt ur", + "▁em peror", + "▁Pack age", + "▁ Package", + "TD M", + "T DM", + "\\{ \\", + "\\ {\\", + "whe el", + "▁fe as", + "▁js ou", + "", + "< ?>", + "INST ANCE", + "▁ch ant", + "▁cha nt", + "▁ chant", + "▁Re fer", + "▁Ref er", + "▁S hir", + "▁Sh ir", + "▁ве ка", + "▁Me eting", + "▁Meet ing", + "▁n v", + "▁ nv", + "▁associ ations", + "▁association s", + "it ations", + "itation s", + "itat ions", + "or um", + "o rum", + "▁t ires", + "▁ti res", + "▁tire s", + "▁tir es", + "▁d ash", + "▁da sh", + "▁das h", + "▁ dash", + "▁} ));", + "▁}) );", + "ar to", + "art o", + "▁Ed inburgh", + "W T", + "▁inv ented", + "▁invent ed", + "ve h", + "v eh", + "▁Hind u", + "▁Насе лення", + "▁ur gent", + "▁urg ent", + "▁urge nt", + "text color", + "we rp", + "wer p", + "▁det ector", + "▁detect or", + "▁al tered", + "▁alt ered", + "▁alter ed", + "▁t b", + "▁ tb", + "▁N aval", + "▁Na val", + "▁Nav al", + "▁mem br", + "style sheet", + "styles heet", + "un ts", + "unt s", + "▁nut rition", + "▁S ylv", + "▁Sy lv", + "▁e numer", + "▁en umer", + "▁enum er", + "▁m ines", + "▁min es", + "▁mi nes", + "▁mine s", + "▁l itter", + "▁lit ter", + "▁litt er", + "ž í", + "con current", + "▁sw allow", + "Si r", + "S ir", + "tal k", + "t alk", + "▁de utschen", + "▁deutsch en", + "re peat", + "▁dom ains", + "▁domain s", + "▁Mc Donald", + "▁cand le", + "▁pl ural", + "▁sharp ly", + "▁shar ply", + "orig ine", + "origin e", + "▁c andy", + "▁can dy", + "▁cand y", + "▁kilomet res", + "▁power ed", + "▁pow ered", + "▁ powered", + "▁s ep", + "▁se p", + "▁ sep", + "▁S oci", + "▁So ci", + "▁Soc i", + "▁Ber nie", + "▁Bern ie", + "GE NER", + "GEN ER", + "Ex per", + "Exp er", + "▁Al low", + "▁All ow", + "▁ Allow", + "▁Ern st", + "▁Re becca", + "▁Cont ribut", + "ro utes", + "rou tes", + "route s", + "r outes", + "▁s uffix", + "▁suff ix", + "▁ju lio", + "▁jul io", + "▁juli o", + "▁provinc ial", + "▁provincia l", + "▁provin cial", + "▁appreci ation", + "Us ing", + "U sing", + "abs olute", + "▁cr icket", + "W ould", + "▁Equip ment", + "▁tort ure", + "на х", + "ut ton", + "utt on", + "че ство", + "▁out break", + "▁prevent ing", + "▁mad re", + "▁ret ire", + "end region", + "▁f ais", + "▁fa is", + "▁remember ing", + "▁Al ban", + "▁Alb an", + "▁a rist", + "▁ar ist", + "▁work out", + "▁u z", + "▁ uz", + "as to", + "ast o", + "a sto", + "fort unate", + "fortun ate", + "▁p aste", + "▁past e", + "▁pas te", + "▁pa ste", + "▁M R", + "▁ MR", + "▁o tra", + "▁ot ra", + "S v", + "an gen", + "ang en", + "ange n", + "▁S ierra", + "▁Si erra", + "▁n au", + "▁na u", + "▁s era", + "▁se ra", + "▁ser a", + "$ ~", + "▁cos ì", + ")( (", + ") ((", + "▁propos als", + "▁proposal s", + "it te", + "itt e", + "▁P ero", + "▁Per o", + "▁Pe ro", + "▁te nant", + "▁ten ant", + "▁ tenant", + "Y P", + "▁Param eter", + "▁ Parameter", + "sp ell", + "spe ll", + "▁e merge", + "▁emer ge", + "▁g ek", + "▁ge k", + "ol ence", + "olen ce", + "ot os", + "oto s", + "o tos", + "▁witness es", + "▁watch es", + "▁wat ches", + "▁A ch", + "▁Ac h", + "Cr oss", + "C ross", + "▁янва ря", + "; }", + "▁O NE", + "▁ON E", + "▁ ONE", + "▁care ers", + "▁career s", + "▁faith ful", + "▁J our", + "▁Jo ur", + "▁Gener ate", + "▁Gene rate", + "▁ Generate", + "▁ию ля", + "▁recommend ation", + "w b", + "sk ich", + "ski ch", + "bold math", + "▁orig ins", + "▁origin s", + "▁spin ning", + "▁// \r", + "▁bomb s", + "▁bom bs", + "min ister", + "I o", + "öl ker", + "Autow ired", + "um per", + "ump er", + "ich ael", + "▁contribut ors", + "▁contributor s", + "▁n asty", + "▁na sty", + "▁nas ty", + "▁nast y", + "▁d rap", + "▁dr ap", + "▁Bud apest", + "ur ious", + "uri ous", + "hi d", + "h id", + "▁wel comed", + "▁welcome d", + "▁w agon", + "▁wa gon", + "▁Ва си", + "▁embarrass ed", + "▁Har vey", + "Lo s", + "L os", + "▁S ter", + "▁St er", + "▁Ste r", + "▁enjoy able", + "ör t", + "ö rt", + "Mill is", + "-- )", + "- -)", + "▁d ashed", + "▁das hed", + "▁dash ed", + "\"> < ?", + "\" >' ,", + "> ',", + "▁all iance", + "ic ism", + "ici sm", + "▁NAS A", + "▁NA SA", + "▁p ode", + "▁po de", + "▁pod e", + "č ní", + "▁respon ding", + "▁respond ing", + "▁bl owing", + "▁blo wing", + "▁blow ing", + "ic ké", + "ick é", + "ва но", + "ван о", + "▁H off", + "▁Ho ff", + "▁Hof f", + "MB ER", + "M BER", + "▁civil ization", + "ar ía", + "a ría", + "Un lock", + "ge ts", + "get s", + "g ets", + "no d", + "n od", + "▁S TE", + "▁ST E", + "▁con science", + "PE G", + "ch anging", + "chan ging", + "▁Rich mond", + "ling ton", + "l ington", + "ocr atic", + "▁trav és", + "▁ф ран", + "▁up dating", + "process ing", + "Al ex", + "A lex", + "▁mil itar", + "▁milit ar", + "▁pse udo", + "▁pseud o", + "str len", + "▁be have", + "▁beh ave", + "▁behav e", + "▁distinct ive", + "▁E c", + "▁c x", + "▁ cx", + "▁journal ists", + "▁journalist s", + "vo lt", + "vol t", + "v olt", + "▁sp un", + "▁d urable", + "▁dur able", + "▁pro position", + "▁propos ition", + "▁ proposition", + "thread s", + "▁tw entieth", + "▁ф і", + "▁ фі", + "en son", + "ens on", + "enso n", + "▁self ish", + "▁sel fish", + "ar ium", + "ari um", + "a rium", + "▁de cid", + "▁dec id", + "▁ха рак", + "▁psy chiat", + "▁psych iat", + "g d", + "Z Z", + "ug u", + "u gu", + "▁i ds", + "▁id s", + "▁ ids", + "Man aged", + "▁Leg isl", + "ancell ationToken", + "▁gr ants", + "▁gran ts", + "▁grant s", + "▁lie utenant", + "▁lieu tenant", + "▁Fle et", + "** /", + "* */", + "▁T ig", + "▁Ti g", + "▁accept s", + "▁system atic", + ", {\\", + "▁У кра", + "▁aus ge", + "▁dial ect", + "▁dia lect", + "st ri", + "str i", + "s tri", + "er me", + "erm e", + "▁B esch", + "▁Be sch", + "▁Bes ch", + "lo ve", + "lov e", + "l ove", + "S ensor", + "▁B IT", + "▁ BIT", + "▁т ру", + "▁mist aken", + "▁mistake n", + "p v", + "▁u tf", + "▁ut f", + "▁ utf", + "▁[ \\", + "▁ [\\", + "▁Geb iet", + "▁Mann schaft", + "PAR AMETER", + "▁u rb", + "▁ur b", + "▁ urb", + "▁R eed", + "▁Re ed", + "▁c ough", + "▁co ugh", + "▁cou gh", + "wa ld", + "wal d", + "w ald", + "▁L amb", + "▁La mb", + "▁Lam b", + "▁surv iving", + "▁surviv ing", + "▁s way", + "▁sw ay", + "▁с ве", + "WI SE", + "ä ger", + "f y", + "sk e", + "s ke", + "▁s og", + "▁so g", + "▁Im plement", + "▁Imp lement", + "▁ Implement", + "获 取", + "▁T ools", + "▁To ols", + "▁Tool s", + "▁Too ls", + "▁ Tools", + "▁ne wer", + "▁new er", + "▁exempl e", + "▁exem ple", + "▁l itt", + "▁li tt", + "▁lit t", + "▁вы пу", + "▁у прав", + "Em itter", + "Emit ter", + "IS ING", + "I SING", + "▁органи за", + "▁М і", + "▁Ex amples", + "▁Example s", + "▁I con", + "▁ Icon", + "Get ter", + "▁L ay", + "▁La y", + "▁Col lect", + "▁Coll ect", + "▁ Collect", + "Sa int", + "S aint", + "or able", + "ora ble", + "▁f ick", + "▁fi ck", + "ik h", + "i kh", + "sl ave", + "▁c lay", + "▁cl ay", + "▁W A", + "▁ WA", + "Re po", + "Rep o", + "▁Java Script", + "it r", + "i tr", + "pa id", + "p aid", + "▁home work", + "M iddleware", + "▁r éal", + "▁ré al", + "▁при зна", + "ê m", + "ès e", + "è se", + "▁W ells", + "▁Well s", + "▁Wel ls", + "▁e nero", + "▁en ero", + "▁ener o", + "emperature n", + "▁N aj", + "▁Na j", + "▁Re agan", + "▁comp elling", + "▁tri bes", + "▁trib es", + "▁tribe s", + "▁to String", + "▁ toString", + "pace s", + "pa ces", + "p aces", + "▁harm ful", + "▁Con se", + "▁Cons e", + "od io", + "odi o", + "▁m im", + "▁mi m", + "get Item", + "▁script s", + "▁ scripts", + "ra is", + "rai s", + "r ais", + "▁Ph ase", + "▁ Phase", + "▁An swer", + "▁$ |\\", + "▁$| \\", + "▁as sembled", + "el in", + "eli n", + "e lin", + "ph abet", + "pha bet", + "▁to ast", + "▁tut ti", + "▁tu tti", + "▁be zeichnet", + "Gre at", + "G reat", + "et tes", + "ett es", + "ette s", + "e ttes", + "▁дека бря", + "F ULL", + "▁re gener", + "▁reg ener", + "▁któ re", + "го р", + "г ор", + "is ce", + "isc e", + "▁t oda", + "▁to da", + "▁tod a", + "▁eth ical", + "i q", + "P t", + "ar in", + "ari n", + "a rin", + "ig os", + "igo s", + "i gos", + "▁work shops", + "▁workshop s", + "▁R oche", + "▁Ro che", + "▁Roc he", + "Get String", + "мини стратив", + "m ême", + "▁D aw", + "▁Da w", + "ar ians", + "ari ans", + "aria ns", + "arian s", + "▁imp acts", + "▁impact s", + "▁por table", + "▁port able", + ")- \\", + ") -\\", + "sh ots", + "shot s", + "▁re lev", + "▁rel ev", + "▁rele v", + "PR IV", + "PRI V", + "▁бу ла", + "ard less", + "ul ously", + "ulous ly", + "-- >", + "- ->", + "ol ent", + "ole nt", + "olen t", + "▁э того", + "▁это го", + "▁Gener ic", + "▁Gene ric", + "▁ Generic", + "▁* /,", + "▁*/ ,", + "▁comb inations", + "▁combination s", + "▁re jo", + "с публи", + "cap acity", + "▁tr aces", + "▁tra ces", + "▁trace s", + "▁op acity", + "▁ opacity", + "▁Off icial", + "ic ion", + "ici on", + "icio n", + "▁emotional ly", + "▁emotion ally", + "▁Jo el", + "▁Joe l", + "сько му", + "▁legend ary", + "▁p am", + "▁pa m", + "▁Tamb ién", + ". <", + "ib a", + "i ba", + "mi dt", + "mid t", + "бо м", + "▁en suite", + "Author ization", + "P ag", + "▁hel met", + "▁ter rito", + "▁terr ito", + "second ary", + "▁seg unda", + "▁W ire", + "▁Wi re", + "rec ated", + "▁inv oked", + "▁invoke d", + "▁Value Error", + "▁ф о", + "▁ фо", + "AL IGN", + "CUR RENT", + "\\ +\\_\\", + "▁comp ilation", + "æ r", + "▁Pal mar", + "▁Palm ar", + "▁influ ences", + "▁influence s", + "/ :", + "M ix", + "NO P", + "N OP", + "ec onom", + "e conom", + "▁t ucked", + "▁} );\r", + "▁}); \r", + "▁}) ;\r", + "▁ });\r", + "AN K", + "re ject", + "▁p ension", + "▁pens ion", + "▁gener ates", + "▁generate s", + "ч ё", + "▁in cap", + "▁inc ap", + "▁cl icked", + "▁click ed", + "▁f us", + "▁fu s", + "our ses", + "ours es", + "ourse s", + "▁E aster", + "▁East er", + "% ;", + "zi n", + "z in", + "▁oblig ations", + "▁obligation s", + "▁T ips", + "▁Tip s", + "▁Ti ps", + "}; \r", + "} ;\r", + ".\" _", + "▁B SD", + "▁BS D", + "át ica", + "▁ex pose", + "▁exp ose", + "▁expos e", + "Par s", + "P ars", + "▁Am anda", + "ку п", + "▁gu essed", + "▁guess ed", + "ds i", + "d si", + "▁Le ip", + "Br oad", + "Bro ad", + "B road", + "▁Hug hes", + "▁Hugh es", + "i é", + "▁W ahl", + "▁Wa hl", + "▁former ly", + "Rel ative", + "▁Y u", + "▁Mount ains", + "▁Mountain s", + "▁E num", + "▁En um", + "▁ Enum", + "▁str ang", + "▁stra ng", + "_ -", + "re cht", + "rec ht", + "vi v", + "v iv", + "pa use", + "p ause", + "▁Lond res", + "▁el bow", + "▁Hawai i", + "▁Cas ino", + "Th reshold", + "Un its", + "Unit s", + "In clude", + "ит о", + "и то", + "as ury", + "▁ste ht", + "▁dam ned", + "▁damn ed", + "▁pack ets", + "▁packet s", + "▁W erk", + "▁Wer k", + "▁elev ator", + "ied ad", + "go vern", + "gov ern", + "g overn", + "▁CONTR ACT", + "ma ls", + "mal s", + "m als", + "▁re mem", + "▁rem em", + "▁ent onces", + "▁v as", + "▁va s", + "▁ vas", + "▁sym pathy", + "▁befind et", + "in cing", + "inc ing", + "Data Set", + "▁add itionally", + "▁addition ally", + "▁additional ly", + "▁mus ician", + "▁music ian", + "ше го", + "▁li stop", + "▁list op", + ">\" )", + "> \")", + "Print f", + "▁Fel ix", + "▁car ved", + "▁nice ly", + "▁nic ely", + "го м", + "ch ap", + "cha p", + "▁N ieder", + "▁Ni eder", + "▁Nie der", + "▁L av", + "▁La v", + "▁mod ifications", + "▁modification s", + "mo ment", + "m oment", + "▁bal con", + "▁depend ency", + "CK ET", + "▁van ished", + "▁f ighters", + "▁fight ers", + "▁fighter s", + "▁z unächst", + "io ctl", + "ioc tl", + "▁def ens", + "▁defe ns", + "▁N em", + "▁Ne m", + "Util ity", + "Ut ility", + "▁cur v", + "▁cu rv", + "▁DA MAGES", + "▁Ro gers", + "▁Rog ers", + "▁Roger s", + "▁grat itude", + "▁Den mark", + "ра я", + "gr pc", + "grp c", + "g rpc", + "▁j uni", + "▁ju ni", + "▁jun i", + "▁окт ября", + "▁imm ense", + "▁prevent ed", + "▁prev ented", + "▁fo am", + "▁Ex tra", + "▁Ext ra", + "▁ Extra", + "ai med", + "aim ed", + "▁C riteria", + "▁Crit eria", + "▁ Criteria", + "▁Sim ply", + "box es", + "▁Leg end", + "▁P layers", + "▁Play ers", + "▁Player s", + "▁Mer cedes", + "▁Merc edes", + "▁Br anch", + "▁ Branch", + "TER N", + "T ERN", + "om ena", + "ome na", + "omen a", + "▁incorpor ate", + "con de", + "co nde", + "cond e", + "c onde", + "▁Est ado", + "▁Esta do", + "▁w asted", + "▁was ted", + "▁wa sted", + "▁waste d", + "▁compl aining", + "▁complain ing", + "▁war riors", + "▁warrior s", + "ot er", + "ote r", + "o ter", + "▁э том", + "▁это м", + "▁con ten", + "▁cont en", + "▁co nten", + "▁machine ry", + "▁mach inery", + "▁techn ological", + "▁T D", + "▁ TD", + "▁g ras", + "▁gr as", + "▁gra s", + "▁minim ize", + "▁D oor", + "▁Do or", + "▁b zw", + "▁p rac", + "▁pr ac", + "▁pra c", + "TR EE", + "T REE", + "▁W ing", + "▁Win g", + "▁Wi ng", + "▁Trans action", + "▁ Transaction", + "▁M VT", + "▁Kle in", + "com mons", + "comm ons", + "common s", + "▁} {", + "▁ }{", + "▁Her itage", + "▁f ade", + "▁fa de", + "ро к", + "set Value", + "▁Wal lace", + "▁Wall ace", + "M X", + "▁A CT", + "▁AC T", + "▁ ACT", + "▁foot age", + "▁ent stand", + "ar ga", + "arg a", + "▁n ails", + "▁na ils", + "▁nail s", + "▁capital ism", + "▁G arc", + "▁Gar c", + "▁Ga rc", + "▁susp ension", + "il is", + "ili s", + "▁M ov", + "▁Mo v", + "uff led", + "uffle d", + "Ar c", + "A rc", + "▁Beaut iful", + "WA Y", + "W AY", + "Par allel", + "XX XX", + "di ag", + "▁D T", + "▁ DT", + "m q", + "Text View", + "ML E", + "M LE", + "en nen", + "enn en", + "enne n", + "▁infect ed", + "▁therap ist", + "IN GS", + "ING S", + "▁c idade", + "ъ н", + "▁p df", + "▁pd f", + "▁ pdf", + "▁b ump", + "▁bu mp", + "CT X", + "C TX", + "▁IN CLUDING", + "▁ INCLUDING", + "▁G ef", + "▁Ge f", + "ENT IAL", + "▁h andy", + "▁hand y", + "▁han dy", + "▁tempor al", + "▁temp oral", + "▁tempo ral", + "At A", + "IS H", + "I SH", + "▁Pat tern", + "▁ Pattern", + "▁l an", + "▁la n", + "▁ lan", + "ep endant", + "▁sh ining", + "id y", + "i dy", + "▁N T", + "▁ NT", + "▁F ran", + "▁Fr an", + "▁Fra n", + "▁nur ses", + "▁nurs es", + "▁nurse s", + "▁bet ray", + "▁sens ible", + "▁апре ля", + "▁' [", + "▁th irteen", + ")} _{", + ") }_{", + "▁No ah", + "INS ERT", + "ist ically", + "istic ally", + "▁Append ix", + "▁re cher", + "▁rec her", + "Re ceiver", + "▁der nier", + "▁derni er", + "л ла", + "ли за", + "▁Part ido", + "▁max imal", + "▁maxim al", + "sn ap", + "▁ча сть", + "▁част ь", + "▁час ть", + "ST OP", + "STO P", + "S TOP", + "▁ult ra", + "▁ul tra", + "▁dévelop p", + "▁t egen", + "▁te gen", + "▁Ч и", + "LI B", + "L IB", + "▁bas eline", + "▁base line", + "re load", + "rel oad", + "▁Ar bitro", + "▁k all", + "▁ka ll", + "c apture", + "Ar m", + "A rm", + "qu in", + "im pse", + "imp se", + "za s", + "z as", + "▁C and", + "▁Can d", + "▁Ca nd", + "▁br ains", + "▁brain s", + "▁bra ins", + "▁host ile", + "▁mar ble", + "oo ns", + "oon s", + "o ons", + "▁L oss", + "▁Los s", + "▁Lo ss", + "Meta Data", + "▁Rep ública", + "▁and ra", + "▁ andra", + "od en", + "ode n", + "o den", + "▁document ed", + "▁M oses", + "▁Mo ses", + "▁Mos es", + "od d", + "o dd", + "▁w ax", + "▁wa x", + "us ch", + "usc h", + "u sch", + "▁diagn osed", + "in kle", + "ink le", + "▁X box", + "▁seven ty", + "▁sevent y", + "ci as", + "cia s", + "c ias", + "▁nov iembre", + "Com pute", + "Comp ute", + "Comput e", + "}) ;\r", + "}); \r", + "} );\r", + "▁Philip pe", + "▁Philipp e", + "▁F ör", + "Le ave", + "▁s age", + "▁sa ge", + "▁sag e", + "▁un pre", + "▁Fort unately", + "▁a post", + "▁ap ost", + "ent ities", + "enti ties", + "▁el los", + "▁ell os", + "author ized", + "GB T", + "G BT", + "▁ins ist", + "▁insp ire", + "▁inspir e", + "Ma ss", + "M ass", + "▁r ôle", + "fe e", + "f ee", + "ip art", + "ipa rt", + "i part", + "це р", + "ц ер", + "un ate", + "una te", + "u nate", + "▁C NN", + ": }", + "▁unh appy", + "▁import ed", + "▁imp orted", + "H IGH", + "ring s", + "rin gs", + "r ings", + "▁In stance", + "▁Inst ance", + "▁ Instance", + "B ay", + "ag les", + "agle s", + "a gles", + "me e", + "m ee", + "ber y", + "be ry", + "b ery", + "▁St ories", + "▁Sto ries", + "▁Ch ase", + "▁Cha se", + "▁car riage", + "▁mis under", + "▁imag in", + "p w", + "▁M eter", + "▁Me ter", + "▁Met er", + "▁crow ds", + "▁crowd s", + "▁F ame", + "▁Fa me", + "sk ill", + "ski ll", + "s kill", + "▁c omed", + "▁com ed", + "▁co med", + "▁come d", + "▁ comed", + "▁r anch", + "▁ran ch", + "▁l acking", + "▁lack ing", + "▁lac king", + "▁sub mar", + "▁subm ar", + "ia nte", + "ian te", + "iant e", + "i ante", + "▁l anz", + "▁lan z", + "▁слу ж", + "-- ---------", + "---- -------", + "-------- ---", + "--- --------", + "----- ------", + "---------- -", + "------ -----", + "--------- --", + "------- ----", + "- ----------", + "▁ob ten", + "▁obt en", + "▁down stairs", + "Y N", + "rot ation", + "▁J esse", + "▁Jes se", + "▁Jess e", + "$ (\"#", + "▁p uls", + "▁pu ls", + "▁pul s", + "ir ling", + "irl ing", + "▁Sch aus", + "▁Sc haus", + "▁de ployed", + "▁deploy ed", + "▁{ }\",", + "▁{} \",", + "▁Mar vel", + "EN UM", + "E NUM", + "▁Mat hemat", + "▁Math emat", + "▁n n", + "▁ nn", + "com pet", + "comp et", + "k ów", + "bi l", + "b il", + "Wh ich", + "is ine", + "isi ne", + "▁r ude", + "▁ru de", + "▁n iveau", + "▁á rea", + "▁p rès", + "▁pr ès", + "at is", + "ati s", + "▁[... ]", + "fu r", + "f ur", + "om m", + "o mm", + "pack ed", + "p acked", + "ме не", + "мен е", + "м ене", + "script style", + "▁A th", + "▁At h", + "▁d esp", + "▁de sp", + "▁des p", + "elt emperaturen", + "▁tal ents", + "▁talent s", + "oc y", + "o cy", + "▁r aises", + "▁rais es", + "▁raise s", + "▁ra ises", + "LI MIT", + "L IMIT", + "▁editor ial", + "▁edit orial", + "▁An imal", + "▁Anim al", + "dr ive", + "d rive", + "▁рабо та", + "bs s", + "b ss", + "▁S ev", + "▁Se v", + "ep och", + "e poch", + "▁R C", + "▁ RC", + "UN USED", + "▁mand atory", + "( ?:", + "▁B in", + "▁Bi n", + "▁ Bin", + "▁synt hetic", + "▁g own", + "▁go wn", + "▁D ob", + "▁Do b", + "ka p", + "k ap", + "▁har mon", + "▁harm on", + "▁liber ty", + "▁libert y", + "▁R ice", + "▁Ric e", + "▁pray ers", + "▁pra yers", + "▁prayer s", + "▁m ise", + "▁mis e", + "▁mi se", + "▁conf using", + "▁le ap", + "▁arriv es", + "▁arr ives", + "▁arrive s", + "ka mp", + "k amp", + "▁th ats", + "▁that s", + "AC C", + "A CC", + "▁Param eters", + "▁Parameter s", + "▁ Parameters", + "▁о дно", + "▁од но", + "▁B io", + "▁Bi o", + "d ensity", + "▁gl impse", + "FO RE", + "FOR E", + "▁L isten", + "▁List en", + "▁Li sten", + "▁Liste n", + "▁Lis ten", + "▁ Listen", + "Pr ev", + "Pre v", + "P rev", + "}\\ ,\\", + "}\\, \\", + "} \\,\\", + "ку ль", + "▁S EC", + "▁SE C", + "▁ SEC", + "▁expl ored", + "▁explore d", + "▁explo red", + "▁mean time", + "▁meant ime", + "AI L", + "A IL", + "▁W P", + "▁ WP", + "▁r aison", + "▁rais on", + "▁ra ison", + "▁ex iste", + "▁exist e", + "▁l esser", + "▁les ser", + "▁less er", + "▁Valid ate", + "▁ Validate", + "▁ca ution", + "▁caut ion", + "us ta", + "ust a", + "u sta", + "he ading", + "head ing", + "EF F", + "E FF", + ".' \"", + ". '\"", + "▁Gil bert", + "▁lim itation", + "▁limit ation", + "▁ret our", + "▁Common wealth", + "▁gew ann", + "▁miser able", + "▁net working", + "▁network ing", + "▁ott obre", + "▁otto bre", + "▁D ise", + "▁Dis e", + "▁Di se", + "ed ges", + "edge s", + "▁s ede", + "▁se de", + "▁sed e", + "ви ча", + "вич а", + "un iform", + "uni form", + "▁дея тель", + "ir os", + "iro s", + "i ros", + "▁d esen", + "▁de sen", + "▁des en", + "▁p arc", + "▁par c", + "▁pa rc", + "▁R ico", + "▁Ric o", + "N s", + "gu id", + "gui d", + "g uid", + "or io", + "ori o", + "o rio", + "ave length", + "avel ength", + "▁G le", + "▁Gl e", + "ince ton", + "inc eton", + "Am az", + "A maz", + "Con struct", + "Const ruct", + "▁m x", + "▁ mx", + "▁V ern", + "▁Ver n", + "▁Ve rn", + "▁Gener ation", + "▁ Generation", + "J ack", + "ro mag", + "rom ag", + "▁vi agra", + "▁via gra", + "▁P eg", + "▁Pe g", + "▁Up dated", + "▁Update d", + "▁ Updated", + "▁over lap", + "▁overl ap", + "Event Args", + "к ро", + "▁* «", + "▁quest ioned", + "▁question ed", + "So uth", + "S outh", + "not ice", + "▁perman ently", + "▁permanent ly", + "ls t", + "l st", + "fi cie", + "fic ie", + "▁qu ella", + "▁que lla", + "▁quel la", + "▁college s", + "▁colle ges", + "▁colleg es", + "▁disappoint ment", + "▁Lu ft", + "img ur", + "▁trans itions", + "▁transition s", + "▁transit ions", + "▁s eller", + "▁sell er", + "▁sel ler", + "▁ию ня", + "▁O g", + "▁A DD", + "▁AD D", + "▁ ADD", + "▁P ays", + "▁Pa ys", + "▁Pay s", + "COMM AND", + "gr ades", + "grad es", + "grade s", + "gra des", + "▁fe bbra", + "▁C yr", + "▁Cy r", + "▁febbra io", + "et i", + "e ti", + "▁a rom", + "▁ar om", + "▁Cl aude", + "▁Claud e", + "▁UE FA", + "▁жи ве", + "▁Victor ian", + "▁Victoria n", + "ke eping", + "keep ing", + "kee ping", + "ê n", + "▁FIX ME", + "it ime", + "iti me", + "i time", + "ch estr", + "che str", + "ches tr", + "▁Sam sung", + "▁do ctrine", + "▁p ear", + "▁pe ar", + "▁Mediterr anean", + "▁Y a", + "▁v ault", + "▁va ult", + "▁Hist oric", + "▁Histor ic", + "▁se dan", + "▁sed an", + "▁he ated", + "▁heat ed", + "▁polít ica", + "Pro of", + ": {", + "fe m", + "f em", + "▁Frank furt", + "pect ives", + "pective s", + "M G", + "▁E ye", + "da i", + "d ai", + "▁res erves", + "▁reserv es", + "▁reserve s", + "NE R", + "N ER", + "▁tob acco", + "▁frag ments", + "▁fragment s", + "ic c", + "i cc", + "▁b ooth", + "▁bo oth", + "▁boot h", + "▁cru ise", + "▁Test ament", + "co la", + "col a", + "c ola", + "▁Le op", + "▁Leo p", + "▁n oon", + "▁no on", + "▁ noon", + "▁terr ified", + "v b", + "int el", + "inte l", + "al ie", + "ali e", + "a lie", + "▁ver ification", + "yst er", + "ys ter", + "y ster", + "AD ER", + "A DER", + "ch ied", + "chie d", + "chi ed", + "▁data sets", + "▁dat asets", + "▁dataset s", + "▁з і", + "▁ зі", + "▁m iem", + "▁mi em", + "▁mie m", + "ul ates", + "ula tes", + "ulate s", + "▁u uid", + "▁ uuid", + "▁Pict ures", + "▁Picture s", + "▁B rend", + "▁Br end", + "▁Bre nd", + "▁Bren d", + "Bill board", + "▁s tern", + "▁st ern", + "▁ste rn", + "▁ster n", + "▁de nom", + "▁den om", + "▁acc idents", + "▁accident s", + "с ня", + "▁p acking", + "▁pack ing", + "▁pac king", + "ци ја", + "ibli cal", + "iblic al", + "▁Та к", + "▁wh isk", + "▁whis k", + "▁l uego", + "▁lu ego", + "▁rect angle", + "▁ho oks", + "▁hook s", + "▁ hooks", + "▁neg lect", + "▁negl ect", + "▁s ober", + "▁so ber", + "▁sob er", + "pro position", + "Mult iple", + "Multi ple", + ":\" ,", + ": \",", + "▁b apt", + "▁ba pt", + "Par ts", + "Part s", + "P arts", + "▁S election", + "▁Se lection", + "▁Sel ection", + "▁Select ion", + "▁ Selection", + "▁Al pha", + "▁ Alpha", + "we ights", + "weight s", + "ha ll", + "hal l", + "h all", + "со б", + "с об", + "▁l ur", + "▁lu r", + "▁ép oca", + "▁re sted", + "▁r ested", + "▁res ted", + "▁rest ed", + "▁reste d", + "amb igu", + "▁taste s", + "▁tast es", + "amazon aws", + "▁conf ess", + "▁dic iembre", + "▁dici embre", + "im plement", + "impl ement", + "imp lement", + "▁absor ption", + "Ha l", + "H al", + "LE AN", + "▁Z ach", + "▁Za ch", + "▁free ze", + "▁fre eze", + "L BL", + "ST M", + "S TM", + "▁cal c", + "▁ca lc", + "▁ calc", + "={ ()", + "= */", + "▁b t", + "▁ bt", + "Re b", + "R eb", + "▁W ien", + "▁Wi en", + "an ska", + "ans ka", + "ansk a", + "▁s urn", + "▁su rn", + "▁sur n", + "iat ive", + "i ative", + "▁inv ån", + "C Y", + "▁l à", + "am ba", + "amb a", + "le en", + "lee n", + "l een", + "wa hl", + "w ahl", + "▁function ing", + "ți a", + "ț ia", + "get Context", + "ga rt", + "gar t", + "g art", + "▁о бе", + "▁об е", + "Pe n", + "P en", + "vi k", + "v ik", + "Sl ider", + "▁Ac cept", + "▁ Accept", + "Ga p", + "G ap", + "▁J orge", + "SI G", + "S IG", + "▁во с", + "▁го ло", + "▁г оло", + "▁period o", + "ш та", + "▁pat ches", + "▁patch es", + "ко ї", + "är e", + "ä re", + "eng ono", + "li sta", + "list a", + "l ista", + "hor n", + "ho rn", + "h orn", + "▁Com plex", + "▁Comp lex", + "▁ Complex", + "Se nt", + "S ent", + "tr fs", + "▁conv ex", + "▁conve x", + "Gener ation", + "▁міс це", + "com press", + "comp ress", + "▁S ax", + "▁Sa x", + "▁u id", + "▁ui d", + "▁ uid", + "▁Leb ens", + "▁Leben s", + "Com pletion", + "\\| _{", + "\\ |_{", + "in sky", + "ins ky", + "▁sc hon", + "▁sch on", + "▁m asters", + "▁ma sters", + "▁master s", + "▁mas ters", + "▁mast ers", + "in depend", + "inde pend", + "ne ys", + "ney s", + "▁l ied", + "▁li ed", + "▁lie d", + "▁a spir", + "▁asp ir", + "ч ні", + "▁break down", + "▁H arm", + "▁Har m", + "▁Ha rm", + "▁design ing", + "h f", + "▁Ang ela", + "▁Angel a", + "▁con fer", + "▁conf er", + "▁part ido", + "▁parti do", + "▁inter ference", + "ma o", + "m ao", + "▁absor bed", + "▁absorb ed", + "▁V all", + "▁Val l", + "▁Va ll", + "Error Code", + "▁Publish ing", + "va no", + "van o", + "v ano", + "BIT S", + "BI TS", + "B ITS", + "▁de er", + "▁Camp aign", + "▁g raz", + "▁gr az", + "▁gra z", + "CHAN GE", + "▁f eder", + "▁fe der", + "▁fed er", + "if fe", + "iff e", + "hand ed", + "han ded", + "h anded", + "c q", + "um bing", + "umb ing", + "▁un re", + "▁s iendo", + "▁si endo", + "▁sim pler", + "▁simple r", + "▁simpl er", + "wh y", + "w hy", + "ar ettes", + "are ttes", + "aret tes", + "arette s", + "an st", + "ans t", + "▁h ass", + "▁has s", + "▁ha ss", + "▁Enter prise", + "▁m ois", + "▁mo is", + "▁F o", + "▁уча ст", + "ff en", + "f fen", + "▁MOD ULE", + "▁ MODULE", + "▁activ ated", + "▁activate d", + "▁intern acional", + "▁M ittel", + "deg ree", + "▁от кры", + "▁& (", + "get Property", + "is z", + "i sz", + "ced ure", + "▁en ters", + "▁ent ers", + "▁enter s", + "▁S ally", + "▁Sal ly", + "▁Tr ain", + "▁Tra in", + "▁lo gged", + "▁log ged", + "▁R av", + "▁Ra v", + "▁A void", + "▁Av oid", + "▁K aiser", + "▁Ka iser", + "▁ex pend", + "▁exp end", + "ap hor", + "aph or", + "▁b rass", + "▁br ass", + "▁bra ss", + "▁bras s", + "▁mel od", + "▁att itudes", + "▁attitude s", + "* \"", + "W all", + "▁o we", + "▁ owe", + "▁b amb", + "▁ba mb", + "sh ader", + "sha der", + "ce ster", + "ces ter", + "c ester", + "▁P P", + "▁ PP", + "▁migr ations", + "▁migration s", + "ent ric", + "entr ic", + "▁Set up", + "▁ Setup", + "▁Art ist", + "hr e", + "h re", + "▁pol ite", + "▁polit e", + "ah an", + "aha n", + "a han", + "▁lug lio", + "▁pre decess", + "▁S IG", + "▁SI G", + "▁ SIG", + "ті в", + "т ів", + "▁R F", + "▁ RF", + "▁D ry", + "▁Dr y", + "▁m aker", + "▁make r", + "▁ma ker", + "▁ maker", + "ши м", + "ш им", + "▁S ounds", + "▁Sound s", + "▁implement ing", + "▁a h", + "▁ ah", + "▁g ev", + "▁ge v", + "▁du plicate", + "▁L ogan", + "▁Log an", + "▁Lo gan", + "▁G rade", + "▁Gr ade", + "▁Grad e", + "▁Gra de", + "DU CT", + "ís es", + "í ses", + "ér t", + "é rt", + "▁nons ense", + "back up", + "Att achment", + "▁e cc", + "▁ec c", + "▁Squad ron", + "le arn", + "lear n", + "de precated", + "dep recated", + "▁A ub", + "▁Au b", + "▁G ol", + "▁Go l", + "▁over l", + "SER VICE", + "▁beautiful ly", + "RE L", + "R EL", + "▁G ian", + "▁Gi an", + "▁P apa", + "▁Pa pa", + "▁Pap a", + "res pond", + "respon d", + "resp ond", + "▁Carib bean", + "r n", + "▁худо ж", + "C fg", + "ra i", + "r ai", + "▁sn iff", + "tt o", + "t to", + "оло ги", + "о логи", + "▁r b", + "▁ rb", + "▁inc idents", + "▁incident s", + "▁d uck", + "▁du ck", + "▁PROVID ED", + "Source s", + "S ources", + "▁Chel sea", + "▁t ek", + "▁te k", + "▁ tek", + "▁на лази", + "▁pil ots", + "▁pilot s", + "т ки", + "▁tr aded", + "▁trad ed", + "▁tra ded", + "▁trade d", + "▁Be ijing", + "▁Greg ory", + "scal ar", + "▁incl ined", + "▁inc lined", + "▁K amp", + "▁Kam p", + "▁Ka mp", + "▁M arian", + "▁Mar ian", + "▁Ma rian", + "▁Maria n", + "▁fier ce", + "▁the ft", + "▁th eft", + "ющи х", + "▁In to", + "▁Int o", + "▁ Into", + "con straint", + "parent Node", + "id ental", + "ident al", + "iden tal", + "▁gouver nement", + "▁S ND", + "▁SN D", + "▁Rub y", + "▁Ru by", + "▁mon aster", + "Rec ords", + "Record s", + "▁K ab", + "▁Ka b", + "▁Un iverse", + "▁Univers e", + "▁approxim ate", + "▁approx imate", + "W ater", + "▁Phys ical", + "ap pers", + "app ers", + "appe rs", + "oubt edly", + "ло жен", + "ложе н", + "▁tow el", + "▁sib lings", + "ep h", + "e ph", + "ic ios", + "ici os", + "icio s", + "ра ми", + "▁out rage", + "▁tamb é", + "SR C", + "S RC", + "те лем", + "тел ем", + "V i", + ".' );", + ". ');", + "L M", + "▁m itt", + "▁mit t", + "▁mi tt", + "▁ mitt", + "▁w eed", + "▁we ed", + "▁cr ops", + "▁cro ps", + "▁crop s", + "im an", + "ima n", + "i man", + "Cl aim", + "ins ula", + "▁( “", + "▁Ch anges", + "▁Change s", + "▁ Changes", + "▁invån are", + "ag ain", + "aga in", + "a gain", + "▁c nt", + "▁ cnt", + "▁G az", + "▁Ga z", + "▁a ustral", + "over lay", + "▁Me chan", + "▁sl ammed", + "▁tr ailing", + "▁tra iling", + "▁trail ing", + "▁Bi ography", + "▁appe aling", + "▁appeal ing", + "IV ER", + "IVE R", + "I VER", + "▁A ve", + "▁Av e", + "▁P lot", + "▁Pl ot", + "vo j", + "v oj", + "▁s ung", + "▁su ng", + "▁sun g", + "▁ sung", + "▁u nos", + "▁un os", + "▁uno s", + "Effect s", + "v v", + "co ok", + "c ook", + "But tons", + "Button s", + "▁trans m", + "ier to", + "iert o", + "CON TEXT", + "CONT EXT", + "▁dign ity", + "air ed", + "ai red", + "aire d", + "a ired", + "java x", + "jav ax", + "j avax", + "▁Albert o", + "▁Alber to", + "▁Rec ently", + "▁Recent ly", + "▁fac ial", + "▁fa cial", + "math op", + "mat hop", + "ał o", + "a ło", + "ви д", + "co tt", + "c ott", + "Vari ables", + "Variable s", + "▁R an", + "▁Ra n", + "▁b unk", + "am iliar", + "amil iar", + "CA ST", + "C AST", + "▁fr ü", + "VE D", + "V ED", + "▁NOT ICE", + "▁turn o", + "▁tur no", + "valid ator", + "▁Portug uese", + "▁question ing", + "}} )", + "} })", + "▁l ear", + "▁le ar", + "▁ lear", + "X amarin", + "▁dis adv", + "enc oded", + "encode d", + "▁K ot", + "▁Ko t", + "ra ted", + "rat ed", + "rate d", + "r ated", + "▁The ory", + "ci us", + "c ius", + "▁Dar win", + "ђ е", + "▁dé cl", + "▁déc l", + "▁обла сть", + "ро вич", + "▁mob ility", + "▁mobil ity", + "V F", + "▁х и", + "▁ хи", + "un til", + "unt il", + "u ntil", + "▁bar riers", + "▁barrier s", + "▁barr iers", + "gi f", + "g if", + "▁R oh", + "▁Ro h", + "▁a ging", + "▁ag ing", + "▁ aging", + "▁W idget", + "▁ Widget", + "ol k", + "▁f arms", + "▁far ms", + "▁farm s", + "Check er", + "Che cker", + "Int roduction", + "с мо", + "▁Russ ians", + "▁Russian s", + "▁Russia ns", + "na ments", + "nam ents", + "nament s", + "n aments", + "▁In sert", + "▁Ins ert", + "▁ Insert", + "▁When ever", + "▁Whe never", + "er set", + "ers et", + "it ori", + "itor i", + "ito ri", + "▁D ort", + "▁Do rt", + "▁Dor t", + "▁cost ume", + "▁mathemat ical", + "▁B ast", + "▁Bas t", + "▁Ba st", + "▁nom inated", + "▁nomin ated", + "▁rest oration", + "pos al", + "po sal", + "▁un fortunate", + "P s", + "LI N", + "L IN", + "▁int act", + "▁prov oc", + "▁situ ée", + "▁но ября", + "er mo", + "erm o", + "▁f isher", + "▁fish er", + "▁fis her", + "г ля", + "▁con ting", + "▁cont ing", + "▁contin g", + "▁Do ug", + "▁Dou g", + "\" ?", + "▁E va", + "▁Ev a", + "▁t ops", + "▁to ps", + "▁top s", + "▁Rem ote", + "▁ Remote", + "▁art work", + "▁art illery", + "qu ick", + "▁Arab ia", + "▁SD Value", + "▁Dak ota", + "ia ted", + "iat ed", + "iate d", + "i ated", + "▁Op tim", + "▁Opt im", + "but tons", + "button s", + "▁c ottage", + "▁where in", + "▁tut orial", + "▁S cre", + "▁Sc re", + "▁swe ep", + "▁Coff ee", + "}) }", + "} )}", + "▁му зы", + "host name", + "▁T emp", + "▁Te mp", + "▁Tem p", + "▁ Temp", + "▁F ut", + "▁Fu t", + "re spect", + "res pect", + "resp ect", + "oc z", + "o cz", + "▁pre domin", + "▁pred omin", + "Ind icator", + "en cial", + "enc ial", + "encia l", + "enci al", + "UM ENT", + "U MENT", + "▁SH ALL", + "▁SHA LL", + "▁comm anded", + "▁command ed", + "▁withdraw al", + "io ur", + "i our", + "REG ION", + "s printf", + "▁в ме", + "▁Pay ment", + "▁ Payment", + "▁A nim", + "▁An im", + "▁ Anim", + "pub lish", + "▁se eks", + "▁see ks", + "▁seek s", + "ou w", + "o uw", + "▁G M", + "▁ GM", + "ru gu", + "rug u", + "r ugu", + "us tain", + "ust ain", + "usta in", + "▁) )", + "▁ ))", + "▁consult ing", + "▁D ialog", + "▁ Dialog", + "▁L ars", + "▁La rs", + "▁Lar s", + "▁crit ique", + "▁circ ulation", + "▁circul ation", + "▁land sc", + "▁lands c", + "man aged", + "▁C raft", + "▁Cr aft", + "▁Cra ft", + "▁h erman", + "▁her man", + "af i", + "a fi", + "am y", + "a my", + "▁disc our", + "▁disco ur", + "<> (", + "< >(", + "▁St eph", + "▁Ste ph", + "▁Step h", + "▁toler ance", + "type name", + "typ ename", + "typen ame", + "vent ions", + "vention s", + "zi ał", + "z iał", + "ст ов", + "сто в", + "с тов", + "▁st icking", + "▁stick ing", + "AS C", + "A SC", + "IS O", + "I SO", + "▁Sp encer", + "▁Di dn", + "▁Did n", + "gom ery", + "im iter", + "imit er", + "imi ter", + "dr u", + "d ru", + "Cl ause", + "▁sl ides", + "▁slide s", + "▁slid es", + "## #", + "# ##", + "▁S ugar", + "▁Su gar", + "H Y", + "▁э ти", + "▁Ed wards", + "▁Edward s", + "▁c ents", + "▁cent s", + "oy a", + "o ya", + "ser ts", + "sert s", + "s erts", + "▁H ass", + "▁Ha ss", + "▁Has s", + "▁in gen", + "▁ing en", + "▁ ingen", + "ст ри", + "с три", + "▁s addle", + "sol id", + "s olid", + "▁ch ampions", + "▁champion s", + "▁champ ions", + "- )", + "▁S lov", + "▁Sl ov", + "▁sh iny", + "▁* )&", + "▁*) &", + "▁Def ine", + "č e", + "▁scr ut", + "on den", + "ond en", + "onde n", + "'\" ,", + "' \",", + "uf fs", + "uff s", + "▁o lymp", + "id ential", + "ident ial", + "wa nd", + "wan d", + "w and", + "▁ann ually", + "▁annual ly", + "▁Ark ansas", + "▁s aint", + "▁sa int", + "▁gle ich", + "▁per fection", + "▁perfect ion", + "▁perf ection", + ") >", + "▁sh orts", + "▁short s", + "▁just ified", + "pe ated", + "peat ed", + "pack ages", + "package s", + "dr iven", + "drive n", + "d riven", + "▁Liber ty", + "▁str ipped", + "▁stri pped", + "▁strip ped", + "ше ние", + "▁fün f", + "▁e cosystem", + "ix a", + "i xa", + "▁F resh", + "▁Fr esh", + "▁Fre sh", + "var t", + "va rt", + "v art", + "▁tre ats", + "▁treat s", + "▁st ance", + "▁stan ce", + "▁ stance", + "чё т", + "ч ёт", + "▁p ity", + "▁pi ty", + "▁pit y", + "ad ém", + "▁о кон", + "▁ок он", + "▁C hand", + "▁Ch and", + "▁Cha nd", + "ra b", + "r ab", + "вши й", + "в ший", + "in ski", + "ins ki", + "▁contin ually", + "▁continu ally", + "▁D addy", + "▁Dad dy", + "▁night mare", + "ic ional", + "ici onal", + "icio nal", + "icion al", + "▁e fect", + "ue blo", + "▁l anç", + "▁lan ç", + "▁Col lections", + "▁Collection s", + "▁Collect ions", + "▁ Collections", + "du e", + "d ue", + "am pton", + "amp ton", + "▁mem cpy", + "▁ memcpy", + "▁* *(", + "▁** (", + "is sent", + "iss ent", + "isse nt", + "issen t", + "▁In sp", + "▁Ins p", + "▁Glas gow", + "▁fur ono", + "▁kind ness", + "B i", + "▁comp eted", + "▁compet ed", + "▁compete d", + "▁o ak", + "L arge", + "▁dis gu", + "▁disg u", + "▁k ings", + "▁king s", + "▁kin gs", + "та ми", + "▁st uffed", + "▁stuff ed", + "▁h ilar", + "▁hi lar", + "pub lished", + "publish ed", + "▁st ressed", + "▁str essed", + "▁stress ed", + "▁Pe ak", + "▁lo ader", + "▁load er", + "▁ loader", + "Key board", + "▁re construction", + "▁v od", + "▁vo d", + "▁ vod", + "▁d un", + "▁du n", + "▁understand s", + "te nant", + "ten ant", + "▁ch aque", + "▁cha que", + "▁pre jud", + "ut at", + "uta t", + "u tat", + "▁u so", + "▁us o", + "▁ uso", + "▁He avy", + "▁cu atro", + "▁side walk", + "▁B ug", + "▁Bu g", + "▁mån aden", + "ge o", + "▁un ited", + "▁unit ed", + "▁F iles", + "▁Fil es", + "▁File s", + "▁Fi les", + "▁ Files", + "▁А ль", + "▁Ал ь", + "▁rug by", + "▁fin ancing", + "▁financ ing", + "▁com ply", + "▁comp ly", + "▁compl y", + "& #", + "▁r ushing", + "▁rush ing", + "▁rus hing", + "▁f en", + "▁fe n", + "▁ fen", + "mon g", + "mo ng", + "m ong", + "▁sp é", + "▁present ing", + "IN CLUDING", + "ě l", + "zeich nung", + "Back up", + "▁pe tit", + "▁pet it", + "▁all erg", + "▁alle rg", + "▁aller g", + "ну т", + "н ут", + "▁wor rying", + "▁worry ing", + "▁m amm", + "▁ma mm", + "▁oper and", + "▁opera nd", + ":%.* ]]", + "▁real ise", + "Comm ands", + "Command s", + "▁B ew", + "▁Be w", + "▁ass umes", + "▁assum es", + "▁assume s", + "▁Co vid", + "▁Cov id", + "▁qu and", + "ty ard", + "t yard", + "▁M ono", + "▁Mon o", + "▁Mo no", + "lin ked", + "link ed", + "M ARK", + "Es p", + "E sp", + "▁bless ing", + "▁eyeb rows", + "▁N V", + "▁ NV", + "▁ст ру", + "▁ стру", + "▁mod eling", + "▁model ing", + "▁mode ling", + "▁gre eted", + "Work space", + "▁pe dest", + "▁ped est", + "▁не за", + "lem agne", + "Stat istics", + "▁a ument", + "▁au ment", + "▁spe eds", + "▁speed s", + "▁synd rome", + "CONNE CT", + "za hl", + "z ahl", + "ver so", + "vers o", + "érc ito", + "▁astr onom", + "▁ap rile", + "▁apr ile", + "▁april e", + "že n", + "ž en", + "ве ро", + "вер о", + "dr aft", + "d raft", + "▁g ioc", + "▁gi oc", + "▁com port", + "▁comp ort", + "▁var iance", + "▁vari ance", + "▁real izing", + "▁realiz ing", + "ED IT", + "оло ві", + "▁e star", + "▁est ar", + "▁es tar", + "▁esta r", + "▁s ost", + "▁so st", + "N ORMAL", + "▁ ó", + "▁And r", + "▁An dr", + "ATTR IB", + "▁re de", + "▁r ede", + "▁red e", + "▁t oes", + "▁to es", + "▁toe s", + "▁adv ances", + "▁advance s", + "▁Again st", + "TO M", + "T OM", + "rs s", + "r ss", + "MM MM", + "▁ne west", + "▁new est", + "▁V ER", + "▁ VER", + "▁phrase s", + "▁phr ases", + "an ter", + "ant er", + "ante r", + "La unch", + "▁c hr", + "▁ch r", + "▁ chr", + "▁manufact ured", + "$) ,", + "$ ),", + "roll ment", + "es ton", + "est on", + "esto n", + "e ston", + "▁pe int", + "” )", + "en det", + "end et", + "ende t", + "▁H air", + "▁Ha ir", + "ival ent", + "▁up right", + "gr en", + "gre n", + "g ren", + "an ked", + "ank ed", + "wr ight", + "w right", + "▁m ast", + "▁ma st", + "▁mas t", + "▁on Change", + "▁de bris", + "▁deb ris", + "▁g rap", + "▁gr ap", + "▁gra p", + "et ry", + "etr y", + "e try", + "▁( __", + "▁(_ _", + "▁ (__", + "▁Com merce", + "BO X", + "T ax", + "▁о три", + "▁от ри", + "▁pre vention", + "▁prevent ion", + "▁prev ention", + "▁Fe el", + "▁ex otic", + "▁B ark", + "▁Bar k", + "▁S team", + "▁Ste am", + "fo n", + "f on", + "ol in", + "oli n", + "o lin", + "▁elim inated", + "▁eliminate d", + "▁b c", + "▁ bc", + "▁C ycl", + "▁Cy cl", + "▁$ (\"#", + "▁ $(\"#", + "▁P arl", + "▁Par l", + "▁Pa rl", + "man uel", + "os pher", + "osp her", + "osph er", + "W F", + "An aly", + "Anal y", + "▁nav ig", + "▁re nown", + "▁ren own", + "R x", + "▁W alt", + "▁Wal t", + "▁Wa lt", + "uf fed", + "uff ed", + "▁f oster", + "▁fo ster", + "▁fost er", + "▁fos ter", + "$ :", + "sh ore", + "Conne ctor", + "Conn ector", + "Connect or", + "фи ка", + "▁real ization", + "▁realiz ation", + "L i", + "ct xt", + "ctx t", + "c txt", + "ah oo", + "aho o", + "▁mir acle", + "▁E T", + "▁ ET", + "▁G PS", + "▁GP S", + "▁Observ able", + "▁h f", + "▁ hf", + "▁magnific ent", + "не го", + "BI N", + "B IN", + "▁D orf", + "▁Do rf", + "▁Dor f", + "ie ck", + "ve e", + "v ee", + "▁C raw", + "▁Cr aw", + "▁Cra w", + "/ #", + "▁p ci", + "▁pc i", + "▁ pci", + "ip pet", + "ipp et", + "▁Hill ary", + "▁g ir", + "▁gi r", + "▁r and", + "▁ran d", + "▁ra nd", + "▁ rand", + "▁la ying", + "▁lay ing", + "▁D ifferent", + "bo ys", + "boy s", + "vi rt", + "vir t", + "v irt", + "▁enc ryption", + "ás z", + "á sz", + "по р", + "п ор", + "▁sm elled", + "▁smell ed", + "▁sus cept", + "cl uded", + "clude d", + "▁C arn", + "▁Car n", + "▁Ca rn", + "ig ten", + "igt en", + "igte n", + "▁Ch uck", + "▁Prov inc", + "▁per í", + "▁Mar shal", + "▁Mars hal", + "▁ Marshal", + "мо ж", + "g fx", + "os hi", + "osh i", + "▁W HE", + "▁WH E", + "▁relax ation", + ", .", + "we re", + "wer e", + "w ere", + "▁var ieties", + "▁W on", + "▁Wo n", + "▁g aps", + "▁gap s", + "▁ga ps", + "▁st ole", + "▁sto le", + "ig ua", + "igu a", + "ющи е", + "▁Ham pshire", + "ph rase", + "▁pel ícula", + "Process ing", + "▁initial ization", + "oust ic", + "▁Jose f", + "▁Jos ef", + "ic ating", + "ica ting", + "▁good ness", + "TE S", + "T ES", + "▁c ope", + "▁co pe", + "▁cop e", + "▁ cope", + "▁ignor ance", + "▁B rist", + "▁Br ist", + "▁par as", + "▁para s", + "▁pa ras", + "▁accident ally", + "▁t and", + "▁tan d", + "▁ta nd", + "it test", + "itt est", + "itte st", + "▁у ли", + "▁sh ipped", + "▁ship ped", + "▁о ст", + "▁ос т", + "else if", + "▁u size", + "▁us ize", + "hor izontal", + "▁C arr", + "▁Car r", + "▁Ca rr", + "▁pre cip", + "▁prec ip", + "ro z", + "r oz", + "path etic", + "pat hetic", + "ri ved", + "riv ed", + "rive d", + "r ived", + "ro k", + "r ok", + "▁dig ging", + "мо м", + "▁M ull", + "▁Mu ll", + "▁Mul l", + "▁X III", + "▁XII I", + "▁XI II", + "▁pe as", + "▁f oul", + "▁fo ul", + "▁fou l", + "▁travel s", + "▁trav els", + "▁N g", + "▁состав е", + "▁соста ве", + "Mon t", + "Mo nt", + "M ont", + "ar de", + "ard e", + "▁Ste fan", + "^^ ^^", + "▁K iss", + "▁Ki ss", + "▁E k", + "▁ok tober", + "▁mem orable", + "▁memor able", + "') ).", + "')) .", + "' )).", + "▁V ision", + "▁Vis ion", + "▁N ina", + "▁Ni na", + "▁Nin a", + "▁S olar", + "▁So lar", + "▁Sol ar", + "▁highlight ed", + "▁me mo", + "▁mem o", + "me isterschaft", + "side bar", + "SE E", + "S EE", + "▁Nev ada", + "D a", + "▁draw er", + "ast ically", + "astic ally", + "el de", + "eld e", + "sc ribed", + "scri bed", + "scribe d", + "scrib ed", + "▁pri ests", + "▁priest s", + "▁hom mes", + "▁homme s", + "▁in structor", + "▁instruct or", + "кла д", + "▁sp ett", + "▁spe tt", + "\\ -", + "▁ми ра", + "▁ мира", + "▁Look s", + "▁Lo oks", + "▁sle eve", + "▁strong est", + "▁t ête", + "▁Nic ole", + "▁Ni cole", + "▁Nicol e", + "im per", + "imp er", + "на ча", + "ip per", + "ipp er", + "▁in won", + "il ers", + "ile rs", + "iler s", + "i lers", + "▁Dep uty", + "og e", + "o ge", + "▁de pressed", + "▁dep ressed", + "▁depress ed", + "▁ar te", + "▁art e", + "▁ arte", + "▁comb ining", + "LA ST", + "L AST", + "in ted", + "int ed", + "inte d", + "▁A verage", + "▁Ave rage", + "▁poll ution", + "▁Phill ips", + "▁W M", + "▁ WM", + "}} }\\", + "}}} \\", + "} }}\\", + "Add ed", + "Ad ded", + "▁per ipher", + "Creat ion", + "C reation", + "▁ital ien", + "▁Ch oice", + "▁Cho ice", + "▁ Choice", + "▁EX PRESS", + "▁St ruct", + "▁Str uct", + "▁ Struct", + "ys z", + "y sz", + "Res ize", + "Re size", + "AR GS", + "ARG S", + "▁re po", + "▁rep o", + "▁ repo", + "▁что бы", + "▁p ref", + "▁pre f", + "▁pr ef", + "▁ pref", + "▁earth qu", + "▁Ме кси", + "▁F inale", + "▁Fin ale", + "▁Final e", + "▁h echo", + "▁he cho", + "requ ests", + "request s", + "C ut", + "▁des erved", + "▁deserve d", + "го во", + "гов о", + "▁Re cent", + "▁Rec ent", + "▁ди визи", + "▁support ive", + "пра ви", + "прав и", + "▁irre levant", + "' \r", + "▁c trl", + "▁ ctrl", + "▁De al", + "iz ada", + "iza da", + "u o", + "▁n ort", + "▁no rt", + "▁nor t", + "ge ometry", + "geo metry", + "▁Individ ual", + "er eg", + "ere g", + "e reg", + "▁при ня", + "cre f", + "cr ef", + "c ref", + "═ ═", + "▁com erc", + "▁come rc", + "= _", + "bu nd", + "b und", + "та х", + "il en", + "ile n", + "i len", + "чи та", + "▁corpor ation", + "es z", + "e sz", + "▁= =>", + "▁== >", + "ab lish", + "abl ish", + "Ap r", + "A pr", + "▁r ipped", + "▁ri pped", + "▁rip ped", + "Var s", + "V ars", + "st ret", + "str et", + "stre t", + "▁Frances co", + "Na N", + "▁any time", + "▁autom ated", + "ost ream", + "o stream", + "▁draw ings", + "▁drawing s", + "▁enhance ment", + "ok rat", + "▁Iss ue", + "в ра", + "Cur rency", + "▁w yn", + "▁wy n", + "izar re", + "ét ico", + "mult iple", + "multi ple", + "multip le", + "▁R ate", + "▁Ra te", + "▁Rat e", + "▁ Rate", + "▁I ch", + "▁A uss", + "▁Aus s", + "▁Au ss", + "▁For mer", + "▁Form er", + "Cur ve", + "▁mar vel", + "att ro", + "attr o", + "▁с п", + "BO OL", + "си я", + "go ld", + "g old", + "▁N intendo", + "▁Salv ador", + "▁S olution", + "▁Sol ution", + "AD C", + "A DC", + "бо ра", + "бор а", + "▁Ben nett", + "▁F R", + "▁ FR", + "▁pu eden", + "▁pued en", + "▁puede n", + "pat ient", + "▁P G", + "▁ PG", + "▁J in", + "▁Ji n", + "▁cr ashed", + "▁crash ed", + "▁d enen", + "▁de nen", + "▁den en", + "▁S ample", + "▁Sam ple", + "▁ Sample", + "▁Que bec", + "it ories", + "itor ies", + "ito ries", + "itori es", + "▁b linked", + "▁blink ed", + "▁l ion", + "▁li on", + "▁vo ce", + "▁voc e", + "▁Imp act", + "▁M au", + "▁Ma u", + "▁N ie", + "▁Ni e", + "▁l ob", + "▁lo b", + "▁д ве", + "or neys", + "orney s", + "orne ys", + "▁coast al", + "▁s ensors", + "▁sens ors", + "▁sensor s", + "▁X II", + "▁XI I", + "▁ill usion", + "oj i", + "o ji", + "▁I NC", + "▁IN C", + "▁Dun can", + "y k", + "▁affect ing", + "pu l", + "p ul", + "▁Napole on", + "▁а каде", + "▁com pt", + "▁comp t", + "▁prof itable", + "▁profit able", + "lo e", + "l oe", + "▁deux ième", + "▁W C", + "▁ WC", + "▁v iable", + "▁vi able", + "▁via ble", + "▁D rug", + "▁Dr ug", + "▁Dru g", + "Text Box", + "▁lum inos", + "au té", + "aut é", + "y c", + "št ě", + "▁affili ates", + "▁affiliate s", + "il da", + "ild a", + "con duct", + "cond uct", + "▁e benfalls", + "▁A MD", + "▁AM D", + "▁Mon itor", + "▁ Monitor", + "▁Compan ies", + "▁correct ed", + "▁corre cted", + "ä ck", + "SY STEM", + "other apy", + "▁п еред", + "▁пере д", + "▁пе ред", + "▁bl ues", + "▁blue s", + "at isf", + "ati sf", + "atis f", + "al though", + "alth ough", + "ro st", + "ros t", + "r ost", + "SC AN", + "S CAN", + "▁R AM", + "ці ональ", + "▁vend ors", + "▁vendor s", + "▁custom s", + "▁cust oms", + "▁activ ate", + "▁ activate", + "▁b logs", + "▁bl ogs", + "▁blo gs", + "▁blog s", + "▁br ace", + "▁bra ce", + "▁ brace", + "▁st rat", + "▁str at", + "▁stra t", + "an je", + "anj e", + "щ ё", + "▁t ide", + "▁tid e", + "▁ti de", + "▁Brig ade", + "get Operand", + "▁al iment", + "▁ali ment", + "▁achieve ments", + "▁achievement s", + "▁suspic ion", + "▁susp icion", + "▁touch down", + "br oad", + "bro ad", + "b road", + "io re", + "ior e", + "i ore", + "Compar ison", + "▁m um", + "▁mu m", + "Eng lish", + "▁P icture", + "▁Pict ure", + "▁M ouse", + "▁Mo use", + "▁ Mouse", + "am d", + "a md", + "▁[ `", + "▁den omin", + "▁denom in", + "▁Al eks", + "▁Ale ks", + "▁pr events", + "▁prevent s", + "▁prev ents", + "ó b", + "fe d", + "f ed", + "▁P ray", + "▁Pr ay", + "▁Pra y", + "▁sh ine", + "▁ shine", + "▁cl utch", + "mu x", + "m ux", + "App ro", + "Ap pro", + "▁not ably", + "ch io", + "chi o", + "na ge", + "n age", + "HA S", + "H AS", + "▁' )", + "▁ ')", + "▁M iche", + "▁Mich e", + "▁Mic he", + "▁Mi che", + "t g", + ":: ~", + "▁am ely", + "▁ro dz", + "▁rod z", + "z s", + "tr ait", + "tra it", + "t rait", + "▁k lass", + "▁kl ass", + "▁ klass", + "f ö", + "▁dest ac", + "▁Cl ara", + "▁Clar a", + "f requency", + "▁G it", + "▁Gi t", + "▁по ль", + "▁пол ь", + "▁frequ encies", + "▁febr ero", + "▁st umbled", + "ко ю", + "▁N ames", + "▁Name s", + "▁Na mes", + "▁Nam es", + "▁ Names", + "▁F light", + "▁Fl ight", + "▁p rey", + "▁pre y", + "▁pr ey", + "▁med io", + "▁medi o", + "▁V AR", + "▁VA R", + "▁ VAR", + "▁F loat", + "▁Flo at", + "▁ Float", + "▁Ern est", + "▁Marc atori", + "op ort", + "o port", + "▁cancel lation", + "▁cancell ation", + "▁Br yan", + "▁Bry an", + "—— ——", + "Lu c", + "L uc", + "▁li bre", + "▁lib re", + "▁t ítulo", + "* >", + "▁S andy", + "▁San dy", + "▁Sand y", + "▁Mar ina", + "Be en", + "B een", + "▁w al", + "▁wa l", + "▁ wal", + "▁K ultur", + "▁expl ode", + "▁explo de", + "▁lim iting", + "▁limit ing", + "▁presum ably", + "▁p b", + "▁ pb", + "▁M erc", + "▁Me rc", + "▁Mer c", + "▁ре ки", + "le arning", + "lear ning", + "learn ing", + "C atalog", + "▁C ensus", + "lt e", + "l te", + "▁N ET", + "▁NE T", + "▁ NET", + "ra ising", + "rais ing", + "rai sing", + "сь ке", + "st aff", + "sta ff", + "▁Qu inn", + "▁mem orial", + "▁memor ial", + "▁memo rial", + "п ня", + "▁cu enta", + "▁X I", + "lb l", + "l bl", + "▁v aries", + "▁var ies", + "▁vari es", + "▁va ries", + "▁fluct uations", + "▁дол ж", + "▁осо би", + "▁ware house", + "How ever", + "▁correct ions", + "▁corre ctions", + "▁correction s", + "dh d", + "d hd", + "▁f als", + "▁fa ls", + "▁fal s", + "▁controvers y", + "▁cur se", + "▁t élé", + "▁té lé", + "ře d", + "ř ed", + "▁A U", + "▁ AU", + "▁т ор", + "▁то р", + "▁ тор", + "▁cr ít", + "id an", + "ida n", + "i dan", + "ili ary", + "iliar y", + "ilia ry", + "▁P anel", + "▁Pan el", + "▁Pa nel", + "▁ Panel", + "cul e", + "cu le", + "c ule", + "▁P oor", + "▁Po or", + "▁B A", + "▁ BA", + "▁ignor ant", + "ème s", + "è mes", + "▁aest hetic", + "Link ed", + "Lin ked", + "get Int", + "Un icode", + "[ @", + "▁Z ent", + "▁Ze nt", + "▁Zen t", + "Man ifest", + "▁v ars", + "▁var s", + "▁va rs", + "▁ vars", + "P B", + "▁в у", + "▁ ву", + "▁De scribe", + "▁Desc ribe", + "▁ Describe", + "▁Any thing", + "oi rs", + "oir s", + "o irs", + "▁s ocks", + "▁so cks", + "▁soc ks", + "▁sock s", + "▁im ped", + "▁imp ed", + "▁ne ue", + "▁neu e", + "▁dis pers", + "▁disp ers", + "Col lect", + "Coll ect", + "file r", + "fil er", + "fi ler", + "f iler", + "▁Fr au", + "▁Fra u", + "▁H ockey", + "▁te ens", + "▁teen s", + "▁Rober to", + "▁Robert o", + "la uf", + "l auf", + "ва ть", + "ват ь", + "▁с ко", + "▁ ско", + "is Array", + "▁teen ager", + "Bu ilt", + "▁loud ly", + "Cap acity", + "▁advent ures", + "▁adventure s", + "▁M olly", + "▁Mol ly", + "rec ogn", + "bar s", + "ba rs", + "b ars", + "▁L or", + "▁Lo r", + "▁pu ò", + "▁m ong", + "▁mon g", + "▁mo ng", + "▁ mong", + "in ement", + "ine ment", + "i nement", + "Ass ignment", + "Assign ment", + "▁d iz", + "▁di z", + "less ness", + "▁H alloween", + "▁bit map", + "▁ bitmap", + "Ro m", + "R om", + "на р", + "н ар", + "▁re bel", + "▁reb el", + "▁rad ial", + "▁radi al", + "me asure", + "ni t", + "n it", + "▁Ass ume", + "▁assign ments", + "▁assignment s", + "▁I sn", + "▁Is n", + "▁al tre", + "▁alt re", + "ße r", + "ß er", + "на ль", + "нал ь", + "н аль", + "▁fl ies", + "▁d roit", + "▁dro it", + "▁thick ness", + "▁en jo", + "▁d well", + "▁dw ell", + "▁hom osexual", + "▁e val", + "▁ev al", + "▁ eval", + "$_ {", + "$ _{", + "as ia", + "asi a", + "▁phil os", + "get Current", + "▁veter ans", + "▁veteran s", + "▁Ber keley", + "▁wild life", + "Co p", + "C op", + "ve rn", + "ver n", + "v ern", + "▁ Ú", + "to s", + "t os", + "▁L ed", + "▁Le d", + "▁key words", + "▁keyword s", + "▁med ications", + "▁medic ations", + "▁medication s", + "ne um", + "▁jam ais", + "▁B uc", + "▁Bu c", + "▁P D", + "▁ PD", + "▁State ment", + "▁Stat ement", + "▁ Statement", + "▁P I", + "▁ PI", + "▁Jack ie", + "▁Jac kie", + "▁ord in", + "▁k ör", + "▁kö r", + "en ze", + "enz e", + "▁util ized", + "▁utiliz ed", + "▁utilize d", + "á ct", + "az ed", + "aze d", + "a zed", + "▁sever ely", + "▁severe ly", + "▁ä ven", + "▁li bro", + "▁lib ro", + "▁E u", + "äs t", + "ä st", + "PAR T", + "PA RT", + "P ART", + "▁But ler", + "▁puzz le", + "F all", + "Count ry", + "C ountry", + "pf n", + "p fn", + "▁у країн", + "▁Or chestra", + "▁al to", + "▁alt o", + "▁anc ora", + "▁decom position", + "▁ م", + "▁appet ite", + "ad u", + "a du", + "▁TH AT", + "▁com enz", + "min a", + "mi na", + "m ina", + "▁init iated", + "▁initi ated", + "▁T at", + "▁Ta t", + "▁some time", + "▁som etime", + "▁somet ime", + "re k", + "r ek", + "br ead", + "bre ad", + "b read", + "▁Stat istics", + "▁ Statistics", + "▁C ob", + "▁Co b", + "F ollow", + "▁ge ometric", + "ш ла", + "▁proceed ings", + "D lg", + "se ven", + "s even", + "▁[ -", + "▁ [-", + "▁Buff alo", + "▁bl acks", + "▁black s", + "▁s ov", + "▁so v", + "▁cust ody", + "▁r as", + "▁ra s", + "▁ ras", + "▁tatto o", + "öffent licht", + "Bl o", + "B lo", + "A ustral", + "▁rec uper", + "ле в", + "л ев", + "▁b em", + "▁be m", + "▁t hou", + "▁th ou", + "ori ented", + "orient ed", + "vi r", + "v ir", + "▁col ony", + "▁colon y", + "▁Stan ford", + "Abs olute", + "ad rat", + "adr at", + "▁S itu", + "▁Si tu", + "▁sou vent", + "EX EC", + "▁m ű", + "▁apart ments", + "▁apartment s", + "▁слу ча", + "▁a no", + "▁an o", + "▁ ano", + "WIN DO", + "ac ci", + "acc i", + "▁L au", + "▁La u", + "co urt", + "cou rt", + "c ourt", + "▁manif old", + "▁coal ition", + "▁X IV", + "▁XI V", + "Att rib", + "Attr ib", + "asc ade", + "▁whe at", + "▁strength s", + "FR EE", + "F REE", + "EMP TY", + "▁h ey", + "▁he y", + "as cular", + "asc ular", + "▁pl asma", + "▁b ob", + "▁bo b", + "Sep arator", + "=\" ${", + "=\"$ {", + "▁Z ag", + "▁Za g", + "▁pro jet", + "▁smooth ly", + "SE QU", + "an aly", + "ana ly", + "anal y", + "att achment", + "attach ment", + "▁E S", + "▁ ES", + "▁po pped", + "▁pop ped", + "ő s", + "to m", + "t om", + "▁s ón", + "▁só n", + "▁r ott", + "▁ro tt", + "▁rot t", + "▁ rott", + "Util ities", + "Ut ilities", + "had oop", + "hado op", + "▁s otto", + "▁so tto", + "au tor", + "aut or", + "auto r", + "▁George s", + "▁Georg es", + "▁kter ý", + "▁gru ppo", + "▁ко гда", + "▁ме да", + "▁instrument al", + "▁W riter", + "▁Write r", + "▁Writ er", + "▁Wr iter", + "▁ Writer", + "▁set Timeout", + "ik k", + "i kk", + "▁Do po", + "▁Dop o", + "]) ;\r", + "]); \r", + "] );\r", + "▁pract icing", + "▁Ron ald", + "▁у би", + "▁ag rees", + "▁agree s", + "▁agre es", + "▁den oted", + "▁denote d", + "is miss", + "ism iss", + "▁interview ed", + "template s", + "t emplates", + "ř i", + "ad ministr", + "admin istr", + "▁B utter", + "▁But ter", + "▁XV II", + "▁XVI I", + "▁position ed", + "▁posit ioned", + "▁Four th", + "▁overwhel med", + "▁Reg ular", + "▁rep rezent", + "коно ми", + "▁expect s", + "Ind ices", + "▁mar ijuana", + "▁z aj", + "▁za j", + "▁B ren", + "▁Br en", + "▁Bre n", + "▁be gg", + "▁beg g", + "▁na hm", + "▁nah m", + "▁inter rog", + "ти е", + "▁B un", + "▁Bu n", + "▁с еред", + "▁се ред", + "▁shel ves", + "▁которы х", + "▁Fra uen", + "▁Frau en", + "▁Serge ant", + "▁у спе", + "mat ched", + "match ed", + "m atched", + "▁d onne", + "▁don ne", + "▁touch es", + "▁tou ches", + "ab ort", + "abor t", + "▁v ale", + "▁val e", + "▁va le", + "▁inst itutional", + "▁institut ional", + "▁institution al", + "▁M ons", + "▁Mon s", + "▁Mo ns", + "▁ambit ious", + "▁non etheless", + "▁none theless", + "j d", + "пе й", + "п ей", + "▁back pack", + "da o", + "d ao", + "ви я", + "▁surround ings", + "▁surrounding s", + "| _{", + "▁g egründ", + "dis p", + "di sp", + "d isp", + "▁moist ure", + "▁w yd", + "▁wy d", + "▁tr aders", + "▁trad ers", + "▁tra ders", + "▁trade rs", + "▁Er st", + "▁Gal axy", + "▁в оло", + "▁во ло", + "▁Per u", + "▁Pe ru", + "▁prior ities", + "▁pron ounced", + "▁C BS", + "▁CB S", + "▁Pal m", + "▁Pa lm", + "▁exp ans", + "▁ener get", + "▁energ et", + "▁Cond ition", + "▁ Condition", + "▁S ver", + "▁Sv er", + "ne sted", + "nes ted", + "n ested", + "▁февра ля", + "he ro", + "her o", + "h ero", + "▁ко ло", + "▁к оло", + "▁ коло", + "▁Fil ms", + "▁Film s", + "Bo n", + "B on", + "é al", + "ploy ed", + "tr ained", + "tra ined", + "train ed", + "▁els ő", + "▁l ust", + "▁lu st", + "ati num", + "atin um", + "oy le", + "o yle", + "▁J et", + "▁Je t", + "жде ния", + "▁survey s", + "▁surve ys", + "be e", + "b ee", + "work ers", + "worker s", + "wor kers", + "rec ords", + "record s", + "cal endar", + "bb ing", + "b bing", + "reg ation", + "dash board", + "d ashboard", + "K ing", + "▁v ista", + "▁vis ta", + "▁vi sta", + "▁dep icted", + "▁occur ring", + "▁о фи", + "▁sand wich", + "rc u", + "r cu", + "ke rn", + "ker n", + "k ern", + "▁min ut", + "▁mi nut", + "▁с мер", + "▁t d", + "▁ td", + "so lete", + "sole te", + "sol ete", + "Com plex", + "Comp lex", + "▁t unn", + "▁tu nn", + "▁tun n", + "▁sc arc", + "▁scar c", + "st ead", + "ste ad", + "▁F ail", + "▁Fa il", + "▁ Fail", + "▁R s", + "▁tr ails", + "▁tra ils", + "▁trail s", + "ke m", + "k em", + "▁Rom ans", + "▁Ro mans", + "▁Roman s", + "▁Roma ns", + "at ivity", + "ativ ity", + "Pre vious", + "Prev ious", + "▁de press", + "▁dep ress", + "▁re signed", + "▁res igned", + "▁resign ed", + "get Default", + "▁Tib et", + "▁Ti bet", + "▁Fr anco", + "▁Franc o", + "▁Fran co", + "\") ));", + "\")) );", + "\" )));", + "▁in jection", + "▁inj ection", + "▁inject ion", + "rem oved", + "remove d", + "▁pra ised", + "▁praise d", + "▁A sc", + "▁As c", + "er ase", + "era se", + "eras e", + "e rase", + "▁commission ed", + "MA IL", + "M AIL", + "▁B oh", + "▁Bo h", + "Pol y", + "Po ly", + "P oly", + "▁cin q", + "▁Ab ove", + "▁Josh ua", + "ZE RO", + "Z ERO", + "▁sum mit", + "▁U rs", + "▁Ur s", + "▁c url", + "▁cur l", + "▁cu rl", + "▁v isa", + "▁vis a", + "▁vi sa", + "▁re sur", + "▁res ur", + "={ '", + "= {'", + "fe at", + "▁abs orb", + "▁absor b", + "▁plan ets", + "▁plane ts", + "▁planet s", + "▁prin cess", + "▁prince ss", + "▁Jahrhund erts", + "▁Jahrhundert s", + "x p", + "▁N BC", + "▁ко ми", + "▁ком и", + "▁F UN", + "▁ FUN", + "▁ne uen", + "▁neu en", + "▁neue n", + "▁dé jà", + "▁O z", + "bb en", + "b ben", + "VID EO", + "▁ej empl", + "▁cons iders", + "▁consider s", + "▁consid ers", + "at ri", + "atr i", + "a tri", + "▁ar rog", + "▁arr og", + "io so", + "ios o", + "i oso", + "▁h ace", + "▁ha ce", + "▁contact ed", + "▁un ple", + "▁spons ored", + "▁tr ainer", + "▁tra iner", + "▁train er", + "sb i", + "s bi", + "▁за нима", + "C riterion", + "но то", + "sch eme", + "sche me", + "enn ial", + "per form", + "perf orm", + "▁fix ing", + "▁по стро", + "▁пос тро", + "ar b", + "a rb", + "EX IT", + "▁ca fé", + "▁caf é", + "itut ed", + "itute d", + "itu ted", + "ri ages", + "ria ges", + "riage s", + "T ur", + "▁hab er", + "▁ha ber", + "el asticsearch", + "▁а л", + "▁ ал", + "r h", + "▁v oll", + "▁vo ll", + "▁vol l", + "CL U", + "M il", + "▁mem bres", + "▁membr es", + "▁membre s", + "▁remark ed", + "ва на", + "ван а", + "в ана", + "=\" _", + "Le ss", + "Les s", + "L ess", + "(\" \");", + "▁Y ale", + "▁Ya le", + "ber ries", + "▁rele asing", + "▁im ports", + "▁import s", + "▁imp orts", + "id ea", + "ide a", + "▁( +", + "▁ar qu", + "ific ación", + "ifica ción", + "▁па ра", + "▁пар а", + "▁R angers", + "▁Range rs", + "▁Rang ers", + "▁Ran gers", + "M ic", + "▁n ederbörd", + "▁imag inary", + "▁imagin ary", + "▁special ists", + "▁specialist s", + "▁ho of", + "Mod ules", + "Module s", + "▁sad ly", + "ce il", + "Tab Index", + "at ionale", + "ation ale", + "ational e", + "▁Part ner", + "tb ody", + "t body", + "▁le verage", + "▁lever age", + "D N", + "▁P rec", + "▁Pr ec", + "▁Pre c", + "▁S é", + "▁M am", + "▁Ma m", + "▁a fin", + "▁af in", + "is Valid", + "Ps e", + "P se", + "▁сто ро", + "▁cho pped", + "▁chop ped", + "▁Min or", + "▁Mi nor", + "▁d abei", + "Da vid", + "D avid", + "uss ia", + "▁дере вня", + "▁Id entity", + "▁Ident ity", + "▁ Identity", + "▁L GBT", + "ци је", + "▁Or ts", + "▁Ort s", + "▁part i", + "▁par ti", + "▁B achelor", + "ug a", + "u ga", + "▁O PT", + "▁OP T", + "▁ OPT", + "▁S eth", + "▁Se th", + "▁Set h", + "▁LI ABLE", + "▁inaug ur", + "▁Shan ghai", + "▁relax ing", + "ци она", + "цион а", + "\" %", + "▁o bey", + "▁ob ey", + "▁A irlines", + "▁Air lines", + "Link s", + "Lin ks", + "L inks", + "▁C elt", + "▁Ce lt", + "▁Cel t", + "▁Ad min", + "▁Adm in", + "▁ Admin", + "ag ation", + "▁wor ries", + "IN TE", + "INT E", + "ar ith", + "ari th", + "Fat alf", + "]] )", + "] ])", + "co lm", + "col m", + "▁arch ae", + "▁br ushed", + "▁brush ed", + "▁t ät", + "▁struct ured", + "▁structure d", + "ти и", + "▁home m", + "▁hom em", + "▁ho mem", + "[: ,", + "▁n avy", + "▁na vy", + "▁nav y", + "get Key", + "power ed", + "pow ered", + "▁s ucked", + "▁suc ked", + "▁suck ed", + "▁z omb", + "▁zo mb", + "iss ant", + "issa nt", + "▁M ight", + "▁Mi ght", + "▁Mig ht", + "▁P ull", + "▁Pu ll", + "▁Pul l", + "ri r", + "r ir", + "▁п і", + "▁ пі", + "▁se as", + "▁sea s", + "▁W rest", + "▁Wr est", + "▁t ense", + "▁ten se", + "▁tens e", + "▁a tm", + "▁at m", + "▁have t", + "▁ha vet", + "▁hav et", + "▁pier ws", + "▁trag ic", + "▁D iff", + "▁Di ff", + "▁ Diff", + "▁conf idential", + "▁confident ial", + "success ful", + "ę ż", + "▁Ch ain", + "▁Cha in", + "▁ Chain", + "▁Ken ya", + "Ch oice", + "oc ur", + "o cur", + "an iu", + "ani u", + "▁consult ant", + "▁Ad vis", + "▁Adv is", + "Li f", + "L if", + "▁L ors", + "▁Lo rs", + "▁Lor s", + "avor ite", + "avo rite", + "▁util izing", + "▁utiliz ing", + "▁v intage", + "Mat cher", + "Match er", + "▁m embre", + "▁me mbre", + "▁mem bre", + "▁membr e", + "▁Ex pect", + "▁Exp ect", + "▁ Expect", + "▁tr acing", + "▁tra cing", + "no g", + "n og", + "▁d ej", + "▁de j", + "▁у че", + "▁lo ops", + "▁loop s", + "▁on click", + "▁G PU", + "▁GP U", + "▁ GPU", + "▁Album s", + "▁Alb ums", + "▁Arch ives", + "ва та", + "ват а", + "▁st ove", + "▁sto ve", + "ш ли", + "an cies", + "anc ies", + "▁geme ente", + "mo b", + "m ob", + "PD F", + "P DF", + "es o", + "e so", + "▁v ég", + "▁vé g", + "Res olve", + "▁te aches", + "▁teach es", + "▁tea ches", + "ло же", + "▁с тво", + "▁ст во", + "▁ ство", + "▁О дна", + "▁f id", + "▁fi d", + "Some thing", + "Som ething", + "▁ne bo", + "▁Valent ine", + "row ning", + "rown ing", + "▁а ле", + "▁ал е", + "aw i", + "a wi", + "is hi", + "ish i", + "▁S PI", + "▁SP I", + "▁ SPI", + "▁s pel", + "▁sp el", + "▁spe l", + "▁б іль", + "▁бі ль", + "▁particip ant", + "▁N ed", + "▁Ne d", + "▁G ast", + "▁Ga st", + "▁Gas t", + "▁bl ond", + "▁blo nd", + "▁s aves", + "▁sa ves", + "▁save s", + "▁sav es", + "col ored", + "color ed", + "colo red", + "▁A CTION", + "▁AC TION", + "▁ACT ION", + "▁ ACTION", + "▁Polit iker", + "}$ )", + "} $)", + "▁D um", + "▁Du m", + "den try", + "d entry", + "Stud ent", + "▁~ =", + "lo ads", + "load s", + "▁F oster", + "▁Fo ster", + "一 个", + "▁P K", + "▁ PK", + "▁S B", + "▁ SB", + "▁H ern", + "▁He rn", + "▁Her n", + "▁Ex hib", + "Listener s", + "Listen ers", + "Su n", + "S un", + "pl ac", + "▁B ever", + "▁Be ver", + "▁Bev er", + "▁incl uy", + "▁inclu y", + "▁d c", + "▁ dc", + "ar gc", + "arg c", + "▁g ed", + "▁ge d", + "▁ ged", + "с па", + "▁Form ula", + "▁с ем", + "▁се м", + "▁em pt", + "▁emp t", + "▁ empt", + "un register", + "▁Queens land", + "ánd ez", + "ot ive", + "oti ve", + "▁al ley", + "▁all ey", + "▁alle y", + "▁Democr at", + "▁trav ail", + "▁$ ,", + "▁ $,", + "R P", + "ро е", + "pers onal", + "person al", + "▁péri ode", + "HO ME", + "om es", + "ome s", + "o mes", + "▁recogn ised", + "he ng", + "hen g", + "h eng", + "▁J ung", + "▁Jun g", + "▁Ju ng", + "▁Ro land", + "▁Rol and", + "▁conv icted", + "Loc ked", + "Lock ed", + "L ocked", + "▁m ari", + "▁mar i", + "▁ma ri", + "▁Lux em", + "refer to", + "De leted", + "Dele ted", + "Delete d", + "Del eted", + "int ent", + "inte nt", + "▁St aats", + "▁Sta ats", + "▁обла сті", + "и т", + "▁са ве", + "▁Pro tocol", + "▁ Protocol", + "ają c", + "ch k", + "Type Info", + "▁p kt", + "▁ pkt", + "▁sc andal", + "▁scan dal", + "▁individ ually", + "▁individual ly", + "FM T", + "F MT", + "▁n j", + "ab ile", + "abil e", + "abi le", + "▁R ivers", + "▁River s", + "PRO PERTY", + "V B", + "wo rt", + "wor t", + "w ort", + "▁split ting", + "▁spl itting", + "ach ten", + "acht en", + "achte n", + "a chten", + "▁AR ISING", + "▁s ip", + "▁si p", + "▁f res", + "▁fr es", + "▁fre s", + "▁g room", + "▁gr oom", + "▁gro om", + "H ol", + "▁c anon", + "▁can on", + "▁ca non", + "▁abrupt ly", + "▁after ward", + "▁R unning", + "▁Run ning", + "▁ Running", + "▁j i", + "▁ ji", + "▁% ,", + "▁ %,", + "▁Palest inian", + "R W", + "pgf scope", + "▁country side", + "▁countr yside", + "▁fort unate", + "▁ fortunate", + "▁c él", + "▁Po inter", + "▁Point er", + "▁ Pointer", + "ens ors", + "ensor s", + "enso rs", + "ra ting", + "rat ing", + "r ating", + "▁buff ers", + "▁buffer s", + "▁buf fers", + "▁re mot", + "▁rem ot", + "▁Prop Types", + "▁N ah", + "▁Na h", + "al tern", + "alt ern", + "alter n", + "▁eas iest", + "▁in vas", + "▁inv as", + "▁cl k", + "▁ clk", + "copy right", + "c opyright", + "▁bl anc", + "SA MP", + "S AMP", + "▁Co hen", + "▁S hell", + "▁She ll", + "▁Sh ell", + "▁Shel l", + "▁ Shell", + "▁destroy ing", + "▁destro ying", + "▁Z el", + "▁Ze l", + "date r", + "da ter", + "dat er", + "d ater", + "če n", + "č en", + "▁f iling", + "▁fil ing", + "▁fi ling", + "▁integr ate", + "xi t", + "x it", + "▁R ET", + "▁RE T", + "▁ RET", + "le ne", + "len e", + "l ene", + "cal ls", + "call s", + "c alls", + "▁sl aughter", + "init ialized", + "initial ized", + "initialize d", + "un ches", + "unch es", + "unc hes", + "▁Tr ace", + "▁Tra ce", + "▁ Trace", + "eff icient", + "▁Wood s", + "▁long itud", + "G N", + "▁K ont", + "▁Kon t", + "▁Ko nt", + "▁chunk s", + "á ch", + "▁unem ployment", + "ac om", + "aco m", + "a com", + "▁sl owed", + "▁slow ed", + "▁out lined", + "▁outline d", + "xff ff", + "xf fff", + "x ffff", + "▁ik ke", + "▁work space", + "▁works pace", + "M c", + "▁k icking", + "▁kick ing", + "▁embed ding", + "ch nitt", + "chn itt", + "er ten", + "ert en", + "▁In terior", + "▁Inter ior", + "▁S ongs", + "▁Son gs", + "▁Song s", + "mm c", + "m mc", + "▁analy zed", + "▁analyze d", + "▁Cou pe", + "▁favor ites", + "▁favorite s", + "▁t t", + "▁ tt", + "▁то й", + "▁ той", + "R outing", + "▁Sil va", + "▁andere m", + "▁ander em", + "▁h onom", + "▁hon om", + "▁ho nom", + "▁исполь зова", + ".\" ]", + ". \"]", + "▁W u", + "le gt", + "leg t", + "▁s poon", + "▁sp oon", + "▁spo on", + "▁j ap", + "▁ja p", + "▁Ext ension", + "▁ Extension", + "er ne", + "ern e", + "▁v agy", + "▁va gy", + "▁vag y", + "▁се ла", + "▁ф унк", + "▁anal ytics", + "▁analyt ics", + "▁s ug", + "▁su g", + "▁A sync", + "▁As ync", + "▁ Async", + "▁pe aks", + "▁peak s", + "▁G ym", + "▁Gy m", + "▁law suit", + "▁laws uit", + "< >", + "ial is", + "i alis", + "et ric", + "etr ic", + "face d", + "fa ced", + "fac ed", + "f aced", + "▁dis rupt", + "▁f å", + "Input s", + "`) ;", + "` );", + "▁M end", + "▁Me nd", + "▁Men d", + "go n", + "g on", + "▁\" ,\"", + "▁\", \"", + "▁ \",\"", + "▁n erves", + "▁nerv es", + "▁nerve s", + "▁ner ves", + "▁doubt s", + "▁doub ts", + "sa p", + "s ap", + "▁s ow", + "▁so w", + ",\\ ,\\", + ",\\, \\", + ", \\,\\", + "▁B S", + "▁ BS", + "▁G lad", + "▁Gl ad", + "▁a ster", + "▁as ter", + "▁ast er", + "▁ aster", + "œuv re", + "▁Bang l", + "▁Ban gl", + "▁i Pad", + "use ppe", + "▁conduct ing", + "▁( {\\", + "▁({ \\", + "▁ ({\\", + "▁Har bor", + "ps z", + "p sz", + "▁FI FA", + "_* *", + "_ **", + "em or", + "e mor", + "▁ ▁", + "▁▁ ▁▁", + "▁▁▁ ▁", + "▁ ▁▁▁", + "▁▁ ▁▁▁▁▁▁", + "▁▁▁▁ ▁▁▁▁", + "▁▁▁▁▁ ▁▁▁", + "▁▁▁▁▁▁ ▁▁", + "▁▁▁ ▁▁▁▁▁", + "▁▁▁▁▁▁▁ ▁", + "▁ ▁▁▁▁▁▁▁", + "▁▁ ▁▁▁", + "▁▁▁▁ ▁", + "▁▁▁ ▁▁", + "▁ ▁▁▁▁", + "▁▁ ▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁ ▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁ ▁▁▁▁▁▁▁▁", + "▁▁▁▁▁ ▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁ ▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁ ▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁ ▁▁▁", + "▁▁▁▁▁▁▁▁▁▁ ▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▁▁", + "▁▁▁ ▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁ ▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁ ▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁ ▁▁▁▁▁", + "▁▁ ▁▁▁▁", + "▁▁▁▁ ▁▁", + "▁▁▁▁▁ ▁", + "▁▁▁ ▁▁▁", + "▁ ▁▁▁▁▁", + "▁▁ ▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁ ▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁ ▁▁▁▁", + "▁▁▁▁▁ ▁▁▁▁▁▁▁", + "▁▁▁▁▁▁ ▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁ ▁▁", + "▁▁▁ ▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁ ▁▁▁", + "▁▁▁▁▁▁▁ ▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁ ▁", + "▁ ▁▁▁▁▁▁▁▁▁▁▁", + "▁▁ ▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁ ▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁ ▁▁▁▁▁", + "▁▁▁▁▁ ▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁ ▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁ ▁", + "▁▁▁▁▁▁▁▁▁▁ ▁▁▁", + "▁▁▁ ▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁ ▁▁▁▁", + "▁▁▁▁▁▁▁ ▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁ ▁▁", + "▁ ▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁ ▁▁▁▁▁▁▁▁", + "▁▁▁▁ ▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁ ▁▁", + "▁▁▁▁▁ ▁▁▁▁▁", + "▁▁▁▁▁▁ ▁▁▁▁", + "▁▁▁ ▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁ ▁", + "▁▁▁▁▁▁▁ ▁▁▁", + "▁ ▁▁▁▁▁▁▁▁▁", + "▁▁ ▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁ ▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁ ▁▁▁▁▁▁", + "▁▁▁▁▁ ▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁ ▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁ ▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁ ▁", + "▁▁▁▁▁▁▁▁▁▁ ▁▁▁▁", + "▁▁▁ ▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁ ▁▁▁▁▁", + "▁▁▁▁▁▁▁ ▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁ ▁▁▁", + "▁ ▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁ ▁", + "▁ ▁▁", + "▁▁ ▁▁▁▁▁▁▁", + "▁▁▁▁ ▁▁▁▁▁", + "▁▁▁▁▁▁▁▁ ▁", + "▁▁▁▁▁ ▁▁▁▁", + "▁▁▁▁▁▁ ▁▁▁", + "▁▁▁ ▁▁▁▁▁▁", + "▁▁▁▁▁▁▁ ▁▁", + "▁ ▁▁▁▁▁▁▁▁", + "▁▁ ▁▁▁▁▁", + "▁▁▁▁ ▁▁▁", + "▁▁▁▁▁ ▁▁", + "▁▁▁▁▁▁ ▁", + "▁▁▁ ▁▁▁▁", + "▁ ▁▁▁▁▁▁", + "▁▁ ▁▁▁▁▁▁▁▁▁", + "▁▁▁▁ ▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁ ▁▁▁", + "▁▁▁▁▁ ▁▁▁▁▁▁", + "▁▁▁▁▁▁ ▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁ ▁", + "▁▁▁ ▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁ ▁▁", + "▁▁▁▁▁▁▁ ▁▁▁▁", + "▁ ▁▁▁▁▁▁▁▁▁▁" + ] + } +} \ No newline at end of file diff --git a/code/assets/tokenizer/mistral-7b-v0.3/tokenizer_config.json b/code/assets/tokenizer/mistral-7b-v0.3/tokenizer_config.json new file mode 100644 index 0000000000000000000000000000000000000000..07992b5eb9617dbdf13bb69b825c45e0da5fddb2 --- /dev/null +++ b/code/assets/tokenizer/mistral-7b-v0.3/tokenizer_config.json @@ -0,0 +1,6186 @@ +{ + "add_bos_token": true, + "add_eos_token": false, + "add_prefix_space": true, + "added_tokens_decoder": { + "0": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "1": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "2": { + "content": "", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "3": { + "content": "[INST]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "4": { + "content": "[/INST]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "5": { + "content": "[TOOL_CALLS]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "6": { + "content": "[AVAILABLE_TOOLS]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "7": { + "content": "[/AVAILABLE_TOOLS]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "8": { + "content": "[TOOL_RESULTS]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "9": { + "content": "[/TOOL_RESULTS]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "10": { + "content": "[control_8]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "11": { + "content": "[control_9]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "12": { + "content": "[control_10]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "13": { + "content": "[control_11]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "14": { + "content": "[control_12]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "15": { + "content": "[control_13]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "16": { + "content": "[control_14]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "17": { + "content": "[control_15]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "18": { + "content": "[control_16]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "19": { + "content": "[control_17]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "20": { + "content": "[control_18]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "21": { + "content": "[control_19]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "22": { + "content": "[control_20]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "23": { + "content": "[control_21]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "24": { + "content": "[control_22]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "25": { + "content": "[control_23]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "26": { + "content": "[control_24]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "27": { + "content": "[control_25]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "28": { + "content": "[control_26]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "29": { + "content": "[control_27]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "30": { + "content": "[control_28]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "31": { + "content": "[control_29]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "32": { + "content": "[control_30]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "33": { + "content": "[control_31]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "34": { + "content": "[control_32]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "35": { + "content": "[control_33]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "36": { + "content": "[control_34]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "37": { + "content": "[control_35]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "38": { + "content": "[control_36]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "39": { + "content": "[control_37]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "40": { + "content": "[control_38]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "41": { + "content": "[control_39]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "42": { + "content": "[control_40]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "43": { + "content": "[control_41]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "44": { + "content": "[control_42]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "45": { + "content": "[control_43]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "46": { + "content": "[control_44]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "47": { + "content": "[control_45]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "48": { + "content": "[control_46]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "49": { + "content": "[control_47]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "50": { + "content": "[control_48]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "51": { + "content": "[control_49]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "52": { + "content": "[control_50]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "53": { + "content": "[control_51]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "54": { + "content": "[control_52]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "55": { + "content": "[control_53]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "56": { + "content": "[control_54]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "57": { + "content": "[control_55]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "58": { + "content": "[control_56]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "59": { + "content": "[control_57]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "60": { + "content": "[control_58]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "61": { + "content": "[control_59]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "62": { + "content": "[control_60]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "63": { + "content": "[control_61]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "64": { + "content": "[control_62]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "65": { + "content": "[control_63]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "66": { + "content": "[control_64]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "67": { + "content": "[control_65]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "68": { + "content": "[control_66]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "69": { + "content": "[control_67]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "70": { + "content": "[control_68]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "71": { + "content": "[control_69]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "72": { + "content": "[control_70]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "73": { + "content": "[control_71]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "74": { + "content": "[control_72]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "75": { + "content": "[control_73]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "76": { + "content": "[control_74]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "77": { + "content": "[control_75]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "78": { + "content": "[control_76]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "79": { + "content": "[control_77]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "80": { + "content": "[control_78]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "81": { + "content": "[control_79]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "82": { + "content": "[control_80]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "83": { + "content": "[control_81]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "84": { + "content": "[control_82]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "85": { + "content": "[control_83]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "86": { + "content": "[control_84]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "87": { + "content": "[control_85]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "88": { + "content": "[control_86]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "89": { + "content": "[control_87]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "90": { + "content": "[control_88]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "91": { + "content": "[control_89]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "92": { + "content": "[control_90]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "93": { + "content": "[control_91]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "94": { + "content": "[control_92]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "95": { + "content": "[control_93]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "96": { + "content": "[control_94]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "97": { + "content": "[control_95]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "98": { + "content": "[control_96]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "99": { + "content": "[control_97]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "100": { + "content": "[control_98]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "101": { + "content": "[control_99]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "102": { + "content": "[control_100]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "103": { + "content": "[control_101]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "104": { + "content": "[control_102]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "105": { + "content": "[control_103]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "106": { + "content": "[control_104]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "107": { + "content": "[control_105]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "108": { + "content": "[control_106]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "109": { + "content": "[control_107]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "110": { + "content": "[control_108]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "111": { + "content": "[control_109]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "112": { + "content": "[control_110]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "113": { + "content": "[control_111]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "114": { + "content": "[control_112]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "115": { + "content": "[control_113]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "116": { + "content": "[control_114]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "117": { + "content": "[control_115]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "118": { + "content": "[control_116]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "119": { + "content": "[control_117]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "120": { + "content": "[control_118]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "121": { + "content": "[control_119]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "122": { + "content": "[control_120]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "123": { + "content": "[control_121]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "124": { + "content": "[control_122]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "125": { + "content": "[control_123]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "126": { + "content": "[control_124]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "127": { + "content": "[control_125]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "128": { + "content": "[control_126]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "129": { + "content": "[control_127]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "130": { + "content": "[control_128]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "131": { + "content": "[control_129]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "132": { + "content": "[control_130]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "133": { + "content": "[control_131]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "134": { + "content": "[control_132]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "135": { + "content": "[control_133]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "136": { + "content": "[control_134]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "137": { + "content": "[control_135]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "138": { + "content": "[control_136]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "139": { + "content": "[control_137]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "140": { + "content": "[control_138]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "141": { + "content": "[control_139]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "142": { + "content": "[control_140]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "143": { + "content": "[control_141]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "144": { + "content": "[control_142]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "145": { + "content": "[control_143]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "146": { + "content": "[control_144]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "147": { + "content": "[control_145]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "148": { + "content": "[control_146]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "149": { + "content": "[control_147]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "150": { + "content": "[control_148]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "151": { + "content": "[control_149]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "152": { + "content": "[control_150]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "153": { + "content": "[control_151]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "154": { + "content": "[control_152]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "155": { + "content": "[control_153]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "156": { + "content": "[control_154]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "157": { + "content": "[control_155]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "158": { + "content": "[control_156]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "159": { + "content": "[control_157]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "160": { + "content": "[control_158]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "161": { + "content": "[control_159]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "162": { + "content": "[control_160]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "163": { + "content": "[control_161]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "164": { + "content": "[control_162]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "165": { + "content": "[control_163]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "166": { + "content": "[control_164]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "167": { + "content": "[control_165]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "168": { + "content": "[control_166]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "169": { + "content": "[control_167]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "170": { + "content": "[control_168]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "171": { + "content": "[control_169]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "172": { + "content": "[control_170]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "173": { + "content": "[control_171]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "174": { + "content": "[control_172]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "175": { + "content": "[control_173]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "176": { + "content": "[control_174]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "177": { + "content": "[control_175]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "178": { + "content": "[control_176]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "179": { + "content": "[control_177]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "180": { + "content": "[control_178]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "181": { + "content": "[control_179]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "182": { + "content": "[control_180]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "183": { + "content": "[control_181]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "184": { + "content": "[control_182]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "185": { + "content": "[control_183]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "186": { + "content": "[control_184]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "187": { + "content": "[control_185]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "188": { + "content": "[control_186]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "189": { + "content": "[control_187]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "190": { + "content": "[control_188]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "191": { + "content": "[control_189]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "192": { + "content": "[control_190]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "193": { + "content": "[control_191]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "194": { + "content": "[control_192]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "195": { + "content": "[control_193]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "196": { + "content": "[control_194]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "197": { + "content": "[control_195]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "198": { + "content": "[control_196]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "199": { + "content": "[control_197]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "200": { + "content": "[control_198]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "201": { + "content": "[control_199]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "202": { + "content": "[control_200]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "203": { + "content": "[control_201]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "204": { + "content": "[control_202]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "205": { + "content": "[control_203]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "206": { + "content": "[control_204]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "207": { + "content": "[control_205]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "208": { + "content": "[control_206]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "209": { + "content": "[control_207]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "210": { + "content": "[control_208]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "211": { + "content": "[control_209]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "212": { + "content": "[control_210]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "213": { + "content": "[control_211]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "214": { + "content": "[control_212]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "215": { + "content": "[control_213]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "216": { + "content": "[control_214]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "217": { + "content": "[control_215]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "218": { + "content": "[control_216]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "219": { + "content": "[control_217]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "220": { + "content": "[control_218]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "221": { + "content": "[control_219]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "222": { + "content": "[control_220]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "223": { + "content": "[control_221]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "224": { + "content": "[control_222]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "225": { + "content": "[control_223]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "226": { + "content": "[control_224]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "227": { + "content": "[control_225]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "228": { + "content": "[control_226]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "229": { + "content": "[control_227]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "230": { + "content": "[control_228]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "231": { + "content": "[control_229]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "232": { + "content": "[control_230]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "233": { + "content": "[control_231]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "234": { + "content": "[control_232]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "235": { + "content": "[control_233]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "236": { + "content": "[control_234]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "237": { + "content": "[control_235]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "238": { + "content": "[control_236]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "239": { + "content": "[control_237]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "240": { + "content": "[control_238]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "241": { + "content": "[control_239]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "242": { + "content": "[control_240]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "243": { + "content": "[control_241]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "244": { + "content": "[control_242]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "245": { + "content": "[control_243]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "246": { + "content": "[control_244]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "247": { + "content": "[control_245]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "248": { + "content": "[control_246]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "249": { + "content": "[control_247]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "250": { + "content": "[control_248]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "251": { + "content": "[control_249]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "252": { + "content": "[control_250]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "253": { + "content": "[control_251]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "254": { + "content": "[control_252]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "255": { + "content": "[control_253]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "256": { + "content": "[control_254]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "257": { + "content": "[control_255]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "258": { + "content": "[control_256]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "259": { + "content": "[control_257]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "260": { + "content": "[control_258]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "261": { + "content": "[control_259]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "262": { + "content": "[control_260]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "263": { + "content": "[control_261]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "264": { + "content": "[control_262]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "265": { + "content": "[control_263]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "266": { + "content": "[control_264]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "267": { + "content": "[control_265]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "268": { + "content": "[control_266]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "269": { + "content": "[control_267]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "270": { + "content": "[control_268]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "271": { + "content": "[control_269]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "272": { + "content": "[control_270]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "273": { + "content": "[control_271]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "274": { + "content": "[control_272]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "275": { + "content": "[control_273]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "276": { + "content": "[control_274]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "277": { + "content": "[control_275]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "278": { + "content": "[control_276]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "279": { + "content": "[control_277]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "280": { + "content": "[control_278]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "281": { + "content": "[control_279]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "282": { + "content": "[control_280]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "283": { + "content": "[control_281]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "284": { + "content": "[control_282]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "285": { + "content": "[control_283]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "286": { + "content": "[control_284]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "287": { + "content": "[control_285]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "288": { + "content": "[control_286]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "289": { + "content": "[control_287]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "290": { + "content": "[control_288]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "291": { + "content": "[control_289]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "292": { + "content": "[control_290]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "293": { + "content": "[control_291]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "294": { + "content": "[control_292]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "295": { + "content": "[control_293]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "296": { + "content": "[control_294]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "297": { + "content": "[control_295]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "298": { + "content": "[control_296]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "299": { + "content": "[control_297]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "300": { + "content": "[control_298]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "301": { + "content": "[control_299]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "302": { + "content": "[control_300]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "303": { + "content": "[control_301]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "304": { + "content": "[control_302]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "305": { + "content": "[control_303]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "306": { + "content": "[control_304]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "307": { + "content": "[control_305]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "308": { + "content": "[control_306]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "309": { + "content": "[control_307]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "310": { + "content": "[control_308]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "311": { + "content": "[control_309]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "312": { + "content": "[control_310]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "313": { + "content": "[control_311]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "314": { + "content": "[control_312]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "315": { + "content": "[control_313]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "316": { + "content": "[control_314]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "317": { + "content": "[control_315]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "318": { + "content": "[control_316]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "319": { + "content": "[control_317]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "320": { + "content": "[control_318]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "321": { + "content": "[control_319]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "322": { + "content": "[control_320]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "323": { + "content": "[control_321]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "324": { + "content": "[control_322]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "325": { + "content": "[control_323]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "326": { + "content": "[control_324]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "327": { + "content": "[control_325]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "328": { + "content": "[control_326]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "329": { + "content": "[control_327]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "330": { + "content": "[control_328]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "331": { + "content": "[control_329]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "332": { + "content": "[control_330]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "333": { + "content": "[control_331]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "334": { + "content": "[control_332]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "335": { + "content": "[control_333]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "336": { + "content": "[control_334]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "337": { + "content": "[control_335]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "338": { + "content": "[control_336]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "339": { + "content": "[control_337]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "340": { + "content": "[control_338]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "341": { + "content": "[control_339]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "342": { + "content": "[control_340]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "343": { + "content": "[control_341]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "344": { + "content": "[control_342]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "345": { + "content": "[control_343]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "346": { + "content": "[control_344]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "347": { + "content": "[control_345]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "348": { + "content": "[control_346]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "349": { + "content": "[control_347]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "350": { + "content": "[control_348]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "351": { + "content": "[control_349]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "352": { + "content": "[control_350]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "353": { + "content": "[control_351]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "354": { + "content": "[control_352]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "355": { + "content": "[control_353]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "356": { + "content": "[control_354]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "357": { + "content": "[control_355]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "358": { + "content": "[control_356]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "359": { + "content": "[control_357]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "360": { + "content": "[control_358]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "361": { + "content": "[control_359]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "362": { + "content": "[control_360]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "363": { + "content": "[control_361]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "364": { + "content": "[control_362]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "365": { + "content": "[control_363]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "366": { + "content": "[control_364]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "367": { + "content": "[control_365]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "368": { + "content": "[control_366]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "369": { + "content": "[control_367]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "370": { + "content": "[control_368]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "371": { + "content": "[control_369]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "372": { + "content": "[control_370]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "373": { + "content": "[control_371]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "374": { + "content": "[control_372]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "375": { + "content": "[control_373]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "376": { + "content": "[control_374]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "377": { + "content": "[control_375]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "378": { + "content": "[control_376]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "379": { + "content": "[control_377]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "380": { + "content": "[control_378]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "381": { + "content": "[control_379]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "382": { + "content": "[control_380]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "383": { + "content": "[control_381]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "384": { + "content": "[control_382]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "385": { + "content": "[control_383]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "386": { + "content": "[control_384]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "387": { + "content": "[control_385]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "388": { + "content": "[control_386]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "389": { + "content": "[control_387]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "390": { + "content": "[control_388]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "391": { + "content": "[control_389]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "392": { + "content": "[control_390]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "393": { + "content": "[control_391]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "394": { + "content": "[control_392]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "395": { + "content": "[control_393]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "396": { + "content": "[control_394]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "397": { + "content": "[control_395]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "398": { + "content": "[control_396]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "399": { + "content": "[control_397]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "400": { + "content": "[control_398]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "401": { + "content": "[control_399]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "402": { + "content": "[control_400]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "403": { + "content": "[control_401]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "404": { + "content": "[control_402]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "405": { + "content": "[control_403]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "406": { + "content": "[control_404]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "407": { + "content": "[control_405]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "408": { + "content": "[control_406]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "409": { + "content": "[control_407]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "410": { + "content": "[control_408]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "411": { + "content": "[control_409]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "412": { + "content": "[control_410]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "413": { + "content": "[control_411]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "414": { + "content": "[control_412]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "415": { + "content": "[control_413]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "416": { + "content": "[control_414]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "417": { + "content": "[control_415]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "418": { + "content": "[control_416]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "419": { + "content": "[control_417]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "420": { + "content": "[control_418]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "421": { + "content": "[control_419]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "422": { + "content": "[control_420]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "423": { + "content": "[control_421]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "424": { + "content": "[control_422]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "425": { + "content": "[control_423]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "426": { + "content": "[control_424]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "427": { + "content": "[control_425]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "428": { + "content": "[control_426]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "429": { + "content": "[control_427]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "430": { + "content": "[control_428]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "431": { + "content": "[control_429]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "432": { + "content": "[control_430]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "433": { + "content": "[control_431]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "434": { + "content": "[control_432]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "435": { + "content": "[control_433]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "436": { + "content": "[control_434]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "437": { + "content": "[control_435]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "438": { + "content": "[control_436]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "439": { + "content": "[control_437]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "440": { + "content": "[control_438]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "441": { + "content": "[control_439]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "442": { + "content": "[control_440]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "443": { + "content": "[control_441]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "444": { + "content": "[control_442]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "445": { + "content": "[control_443]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "446": { + "content": "[control_444]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "447": { + "content": "[control_445]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "448": { + "content": "[control_446]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "449": { + "content": "[control_447]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "450": { + "content": "[control_448]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "451": { + "content": "[control_449]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "452": { + "content": "[control_450]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "453": { + "content": "[control_451]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "454": { + "content": "[control_452]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "455": { + "content": "[control_453]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "456": { + "content": "[control_454]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "457": { + "content": "[control_455]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "458": { + "content": "[control_456]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "459": { + "content": "[control_457]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "460": { + "content": "[control_458]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "461": { + "content": "[control_459]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "462": { + "content": "[control_460]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "463": { + "content": "[control_461]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "464": { + "content": "[control_462]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "465": { + "content": "[control_463]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "466": { + "content": "[control_464]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "467": { + "content": "[control_465]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "468": { + "content": "[control_466]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "469": { + "content": "[control_467]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "470": { + "content": "[control_468]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "471": { + "content": "[control_469]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "472": { + "content": "[control_470]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "473": { + "content": "[control_471]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "474": { + "content": "[control_472]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "475": { + "content": "[control_473]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "476": { + "content": "[control_474]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "477": { + "content": "[control_475]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "478": { + "content": "[control_476]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "479": { + "content": "[control_477]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "480": { + "content": "[control_478]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "481": { + "content": "[control_479]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "482": { + "content": "[control_480]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "483": { + "content": "[control_481]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "484": { + "content": "[control_482]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "485": { + "content": "[control_483]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "486": { + "content": "[control_484]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "487": { + "content": "[control_485]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "488": { + "content": "[control_486]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "489": { + "content": "[control_487]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "490": { + "content": "[control_488]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "491": { + "content": "[control_489]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "492": { + "content": "[control_490]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "493": { + "content": "[control_491]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "494": { + "content": "[control_492]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "495": { + "content": "[control_493]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "496": { + "content": "[control_494]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "497": { + "content": "[control_495]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "498": { + "content": "[control_496]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "499": { + "content": "[control_497]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "500": { + "content": "[control_498]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "501": { + "content": "[control_499]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "502": { + "content": "[control_500]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "503": { + "content": "[control_501]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "504": { + "content": "[control_502]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "505": { + "content": "[control_503]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "506": { + "content": "[control_504]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "507": { + "content": "[control_505]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "508": { + "content": "[control_506]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "509": { + "content": "[control_507]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "510": { + "content": "[control_508]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "511": { + "content": "[control_509]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "512": { + "content": "[control_510]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "513": { + "content": "[control_511]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "514": { + "content": "[control_512]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "515": { + "content": "[control_513]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "516": { + "content": "[control_514]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "517": { + "content": "[control_515]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "518": { + "content": "[control_516]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "519": { + "content": "[control_517]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "520": { + "content": "[control_518]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "521": { + "content": "[control_519]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "522": { + "content": "[control_520]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "523": { + "content": "[control_521]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "524": { + "content": "[control_522]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "525": { + "content": "[control_523]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "526": { + "content": "[control_524]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "527": { + "content": "[control_525]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "528": { + "content": "[control_526]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "529": { + "content": "[control_527]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "530": { + "content": "[control_528]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "531": { + "content": "[control_529]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "532": { + "content": "[control_530]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "533": { + "content": "[control_531]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "534": { + "content": "[control_532]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "535": { + "content": "[control_533]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "536": { + "content": "[control_534]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "537": { + "content": "[control_535]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "538": { + "content": "[control_536]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "539": { + "content": "[control_537]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "540": { + "content": "[control_538]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "541": { + "content": "[control_539]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "542": { + "content": "[control_540]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "543": { + "content": "[control_541]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "544": { + "content": "[control_542]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "545": { + "content": "[control_543]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "546": { + "content": "[control_544]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "547": { + "content": "[control_545]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "548": { + "content": "[control_546]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "549": { + "content": "[control_547]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "550": { + "content": "[control_548]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "551": { + "content": "[control_549]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "552": { + "content": "[control_550]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "553": { + "content": "[control_551]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "554": { + "content": "[control_552]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "555": { + "content": "[control_553]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "556": { + "content": "[control_554]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "557": { + "content": "[control_555]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "558": { + "content": "[control_556]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "559": { + "content": "[control_557]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "560": { + "content": "[control_558]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "561": { + "content": "[control_559]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "562": { + "content": "[control_560]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "563": { + "content": "[control_561]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "564": { + "content": "[control_562]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "565": { + "content": "[control_563]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "566": { + "content": "[control_564]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "567": { + "content": "[control_565]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "568": { + "content": "[control_566]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "569": { + "content": "[control_567]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "570": { + "content": "[control_568]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "571": { + "content": "[control_569]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "572": { + "content": "[control_570]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "573": { + "content": "[control_571]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "574": { + "content": "[control_572]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "575": { + "content": "[control_573]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "576": { + "content": "[control_574]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "577": { + "content": "[control_575]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "578": { + "content": "[control_576]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "579": { + "content": "[control_577]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "580": { + "content": "[control_578]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "581": { + "content": "[control_579]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "582": { + "content": "[control_580]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "583": { + "content": "[control_581]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "584": { + "content": "[control_582]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "585": { + "content": "[control_583]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "586": { + "content": "[control_584]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "587": { + "content": "[control_585]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "588": { + "content": "[control_586]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "589": { + "content": "[control_587]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "590": { + "content": "[control_588]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "591": { + "content": "[control_589]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "592": { + "content": "[control_590]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "593": { + "content": "[control_591]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "594": { + "content": "[control_592]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "595": { + "content": "[control_593]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "596": { + "content": "[control_594]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "597": { + "content": "[control_595]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "598": { + "content": "[control_596]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "599": { + "content": "[control_597]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "600": { + "content": "[control_598]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "601": { + "content": "[control_599]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "602": { + "content": "[control_600]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "603": { + "content": "[control_601]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "604": { + "content": "[control_602]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "605": { + "content": "[control_603]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "606": { + "content": "[control_604]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "607": { + "content": "[control_605]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "608": { + "content": "[control_606]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "609": { + "content": "[control_607]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "610": { + "content": "[control_608]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "611": { + "content": "[control_609]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "612": { + "content": "[control_610]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "613": { + "content": "[control_611]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "614": { + "content": "[control_612]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "615": { + "content": "[control_613]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "616": { + "content": "[control_614]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "617": { + "content": "[control_615]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "618": { + "content": "[control_616]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "619": { + "content": "[control_617]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "620": { + "content": "[control_618]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "621": { + "content": "[control_619]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "622": { + "content": "[control_620]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "623": { + "content": "[control_621]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "624": { + "content": "[control_622]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "625": { + "content": "[control_623]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "626": { + "content": "[control_624]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "627": { + "content": "[control_625]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "628": { + "content": "[control_626]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "629": { + "content": "[control_627]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "630": { + "content": "[control_628]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "631": { + "content": "[control_629]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "632": { + "content": "[control_630]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "633": { + "content": "[control_631]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "634": { + "content": "[control_632]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "635": { + "content": "[control_633]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "636": { + "content": "[control_634]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "637": { + "content": "[control_635]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "638": { + "content": "[control_636]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "639": { + "content": "[control_637]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "640": { + "content": "[control_638]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "641": { + "content": "[control_639]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "642": { + "content": "[control_640]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "643": { + "content": "[control_641]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "644": { + "content": "[control_642]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "645": { + "content": "[control_643]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "646": { + "content": "[control_644]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "647": { + "content": "[control_645]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "648": { + "content": "[control_646]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "649": { + "content": "[control_647]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "650": { + "content": "[control_648]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "651": { + "content": "[control_649]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "652": { + "content": "[control_650]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "653": { + "content": "[control_651]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "654": { + "content": "[control_652]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "655": { + "content": "[control_653]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "656": { + "content": "[control_654]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "657": { + "content": "[control_655]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "658": { + "content": "[control_656]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "659": { + "content": "[control_657]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "660": { + "content": "[control_658]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "661": { + "content": "[control_659]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "662": { + "content": "[control_660]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "663": { + "content": "[control_661]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "664": { + "content": "[control_662]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "665": { + "content": "[control_663]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "666": { + "content": "[control_664]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "667": { + "content": "[control_665]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "668": { + "content": "[control_666]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "669": { + "content": "[control_667]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "670": { + "content": "[control_668]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "671": { + "content": "[control_669]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "672": { + "content": "[control_670]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "673": { + "content": "[control_671]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "674": { + "content": "[control_672]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "675": { + "content": "[control_673]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "676": { + "content": "[control_674]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "677": { + "content": "[control_675]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "678": { + "content": "[control_676]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "679": { + "content": "[control_677]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "680": { + "content": "[control_678]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "681": { + "content": "[control_679]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "682": { + "content": "[control_680]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "683": { + "content": "[control_681]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "684": { + "content": "[control_682]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "685": { + "content": "[control_683]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "686": { + "content": "[control_684]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "687": { + "content": "[control_685]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "688": { + "content": "[control_686]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "689": { + "content": "[control_687]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "690": { + "content": "[control_688]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "691": { + "content": "[control_689]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "692": { + "content": "[control_690]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "693": { + "content": "[control_691]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "694": { + "content": "[control_692]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "695": { + "content": "[control_693]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "696": { + "content": "[control_694]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "697": { + "content": "[control_695]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "698": { + "content": "[control_696]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "699": { + "content": "[control_697]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "700": { + "content": "[control_698]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "701": { + "content": "[control_699]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "702": { + "content": "[control_700]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "703": { + "content": "[control_701]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "704": { + "content": "[control_702]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "705": { + "content": "[control_703]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "706": { + "content": "[control_704]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "707": { + "content": "[control_705]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "708": { + "content": "[control_706]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "709": { + "content": "[control_707]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "710": { + "content": "[control_708]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "711": { + "content": "[control_709]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "712": { + "content": "[control_710]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "713": { + "content": "[control_711]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "714": { + "content": "[control_712]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "715": { + "content": "[control_713]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "716": { + "content": "[control_714]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "717": { + "content": "[control_715]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "718": { + "content": "[control_716]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "719": { + "content": "[control_717]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "720": { + "content": "[control_718]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "721": { + "content": "[control_719]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "722": { + "content": "[control_720]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "723": { + "content": "[control_721]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "724": { + "content": "[control_722]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "725": { + "content": "[control_723]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "726": { + "content": "[control_724]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "727": { + "content": "[control_725]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "728": { + "content": "[control_726]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "729": { + "content": "[control_727]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "730": { + "content": "[control_728]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "731": { + "content": "[control_729]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "732": { + "content": "[control_730]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "733": { + "content": "[control_731]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "734": { + "content": "[control_732]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "735": { + "content": "[control_733]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "736": { + "content": "[control_734]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "737": { + "content": "[control_735]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "738": { + "content": "[control_736]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "739": { + "content": "[control_737]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "740": { + "content": "[control_738]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "741": { + "content": "[control_739]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "742": { + "content": "[control_740]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "743": { + "content": "[control_741]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "744": { + "content": "[control_742]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "745": { + "content": "[control_743]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "746": { + "content": "[control_744]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "747": { + "content": "[control_745]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "748": { + "content": "[control_746]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "749": { + "content": "[control_747]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "750": { + "content": "[control_748]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "751": { + "content": "[control_749]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "752": { + "content": "[control_750]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "753": { + "content": "[control_751]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "754": { + "content": "[control_752]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "755": { + "content": "[control_753]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "756": { + "content": "[control_754]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "757": { + "content": "[control_755]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "758": { + "content": "[control_756]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "759": { + "content": "[control_757]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "760": { + "content": "[control_758]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "761": { + "content": "[control_759]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "762": { + "content": "[control_760]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "763": { + "content": "[control_761]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "764": { + "content": "[control_762]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "765": { + "content": "[control_763]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "766": { + "content": "[control_764]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "767": { + "content": "[control_765]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "768": { + "content": "[control_766]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "769": { + "content": "[control_767]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + }, + "770": { + "content": "[control_768]", + "lstrip": false, + "normalized": false, + "rstrip": false, + "single_word": false, + "special": true + } + }, + "bos_token": "", + "clean_up_tokenization_spaces": false, + "eos_token": "", + "legacy": false, + "model_max_length": 1000000000000000019884624838656, + "pad_token": null, + "sp_model_kwargs": {}, + "spaces_between_special_tokens": false, + "tokenizer_class": "LlamaTokenizer", + "unk_token": "", + "use_default_system_prompt": false +} diff --git a/code/bugfind/baselines/README.md b/code/bugfind/baselines/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f569caea18dcf8e13de10d1b4882fab384a81976 --- /dev/null +++ b/code/bugfind/baselines/README.md @@ -0,0 +1,22 @@ +# Bounded-checker baselines (Phase 5, Part A arms) + +Arms: Kani (bounded model checking), proptest (property-based testing), cargo-fuzz (libFuzzer). +All three consume ONE shared property bank (`bank/*.json`, same format the prover / reviewer arms use), so recall +differences cannot come from different properties. + +Equal-CPU protocol: each (item, arm) gets the same `--cpu-seconds` budget of CPU time on one core +(`RLIMIT_CPU` on the whole process group plus a wall-clock backstop of 3x). Compilation time is reported separately +and is NOT charged to the budget (the prover arm's Lean elaboration is likewise reported separately); the budget +covers search only. Set `--cpu-seconds` identically across arms in the pre-registration. + +Layout +- `property_bank.py` bank schema + validation + the always-on "no panic / no overflow" implicit property. +- `gen_harness.py` emits a Kani / proptest / cargo-fuzz project for one item from the bank. +- `run_baselines.py` runs the arms under the budget, emits one JSON result line per (item, arm). +- `bank/smoke.json` properties for the smoke crate (`../smoke/tiny`) and an example for the mutant corpus. + +Status: all three arms run end to end through `run_baselines.py` (proptest + cargo-fuzz on the 23 kernel banks / smoke, Kani on the smoke crate; Kani handles +scalar-argument properties only, vec/option-argument properties are skipped for Kani). `--revision post` runs the same bank against the fixed +revision (negative control / spec gate). `bank/.json` are the 23 kernel banks (blind authored; see `bank/README_PROVENANCE.md`); +`bench/ledger/baseline_sweep_proptest.jsonl` is the proptest sweep (4 CPU-s per property) on pre and post. +Harness calls use the fully qualified `lib::fn(...)` so argument names cannot shadow the function. diff --git a/code/bugfind/baselines/bank/README_PROVENANCE.md b/code/bugfind/baselines/bank/README_PROVENANCE.md new file mode 100644 index 0000000000000000000000000000000000000000..8b6ef2dce9d751f26b17689d4e116554a5c5f530 --- /dev/null +++ b/code/bugfind/baselines/bank/README_PROVENANCE.md @@ -0,0 +1,16 @@ +# Property bank provenance + +Bank files `bank/.json` (one per extracted kernel, `bench/kernels//`) carry a `provenance` block and a per-property +`basis` (the sentence of the doc string the property encodes). + +Protocol (SOTA plan v3.1, "written blind to the known bugs"): +1. The extractor writes `spec_doc` (a documentation-style contract) and the signature into `bench/kernels//meta.json`. + Honest limit: the extractor had read the diff, so `spec_doc` is not blind. It is written to state the intended contract + (what the docs/changelog of the crate promise), not the fix. +2. Properties are authored by a *separate* agent invocation that is given ONLY `{kernel, signature, doc}` (no source, no diff, no advisory + text, no repo access) and records `saw_source/saw_diff/saw_advisory = false`. +3. Properties are frozen before any arm runs. A property that is wrong on the FIXED revision (fails on `post`) is a spec-gate rejection: + it is counted (not silently dropped) via `run_baselines.py --revision post` (negative control) and reported. +4. Properties that pass on `pre` are not evidence of a bug-free `pre`; true bugs they miss count against recall. +Stronger option for the final benchmark: authors who also did not write `spec_doc` (human or a different model), plus doc strings taken +verbatim from the crate's rustdoc at the PRE revision. The format and harness support that unchanged. diff --git a/code/bugfind/baselines/bank/bcrypt_split.json b/code/bugfind/baselines/bank/bcrypt_split.json new file mode 100644 index 0000000000000000000000000000000000000000..99795257bc8c12761cbfa5fbd55d81be9ae75283 --- /dev/null +++ b/code/bugfind/baselines/bank/bcrypt_split.json @@ -0,0 +1,7 @@ +{"item_id": "ker-bcrypt_split", "crate_dir": "../../bench/kernels/bcrypt_split/pre", "lib_name": "k_bcrypt_split_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "split_hash_salt_len", "args": [["hash", "bytes"]], "pre": "true", "post": "hash.len() == 60 || r.is_err()", "ret": "Result", "basis": "A valid hash is exactly 60 ASCII bytes; every other input must give Err"}, + {"id": "p2", "fn": "split_hash_salt_len", "args": [["hash", "bytes"]], "pre": "true", "post": "match &r { Ok(n) => *n == 22 && hash.len() == 60 && hash.iter().all(|b| b.is_ascii()), Err(_) => true }", "ret": "Result", "basis": "returns the salt length (22) only for a valid 60-byte ASCII hash"}, + {"id": "p3", "fn": "split_hash_salt_len", "args": [["hash", "bytes"]], "pre": "true", "post": "!(hash.len() == 60 && hash.iter().any(|b| !b.is_ascii())) || r.is_err()", "ret": "Result", "basis": "non-ASCII bytes make a 60-byte input invalid, so Err"}, + {"id": "p4", "fn": "split_hash_salt_len", "args": [["hash", "bytes"]], "pre": "true", "post": "!(hash.len() == 60 && hash.iter().all(|&b| b.is_ascii_alphanumeric())) || r == Ok(22)", "ret": "Result", "basis": "a 60-byte all-ASCII input is a valid hash and yields salt length 22"} + ]} diff --git a/code/bugfind/baselines/bank/bytes_reserve.json b/code/bugfind/baselines/bank/bytes_reserve.json new file mode 100644 index 0000000000000000000000000000000000000000..d4db053ac1aef25f3b85d4dc364974a289426f3f --- /dev/null +++ b/code/bugfind/baselines/bank/bytes_reserve.json @@ -0,0 +1,7 @@ +{"item_id": "ker-bytes_reserve", "crate_dir": "../../bench/kernels/bytes_reserve/pre", "lib_name": "k_bytes_reserve_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "reserve_fits", "args": [["v_capacity", "usize"], ["new_cap", "usize"], ["offset", "usize"]], "pre": "true", "post": "r == ((v_capacity as u128) >= (new_cap as u128) + (offset as u128))", "ret": "bool", "basis": "true iff v_capacity >= new_cap + offset in exact arithmetic"}, + {"id": "p2", "fn": "reserve_fits", "args": [["v_capacity", "usize"], ["new_cap", "usize"], ["offset", "usize"]], "pre": "true", "post": "new_cap.checked_add(offset).is_some() || !r", "ret": "bool", "basis": "exact arithmetic: if new_cap + offset overflows usize it exceeds any capacity, so false"}, + {"id": "p3", "fn": "reserve_fits", "args": [["v_capacity", "usize"], ["new_cap", "usize"], ["offset", "usize"]], "pre": "true", "post": "offset != 0 || r == (v_capacity >= new_cap)", "ret": "bool", "basis": "with offset 0 the condition reduces to v_capacity >= new_cap"}, + {"id": "p4", "fn": "reserve_fits", "args": [["v_capacity", "usize"], ["new_cap", "usize"], ["offset", "usize"]], "pre": "true", "post": "!(v_capacity == new_cap && offset > 0) || !r", "ret": "bool", "basis": "capacity exactly new_cap with a positive offset is insufficient"} + ]} diff --git a/code/bugfind/baselines/bank/claxon_rice.json b/code/bugfind/baselines/bank/claxon_rice.json new file mode 100644 index 0000000000000000000000000000000000000000..4717d1539c6c4a4ce5e69e2d944d9cd0914af1f7 --- /dev/null +++ b/code/bugfind/baselines/bank/claxon_rice.json @@ -0,0 +1,7 @@ +{"item_id": "ker-claxon_rice", "crate_dir": "../../bench/kernels/claxon_rice/pre", "lib_name": "k_claxon_rice_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "rice_layout", "args": [["block_size", "u16"], ["order", "u32"], ["n_warm_up", "u16"]], "pre": "true", "post": "match &r { Ok(n) => *n == block_size as u32, Err(_) => true }", "ret": "Result", "basis": "On Ok(n), n must equal block_size"}, + {"id": "p2", "fn": "rice_layout", "args": [["block_size", "u16"], ["order", "u32"], ["n_warm_up", "u16"]], "pre": "true", "post": "!(order >= 16 && block_size > 0) || r.is_err()", "ret": "Result", "basis": "2^order partitions (order>=16) cannot each hold a sample of a block smaller than 2^16, so they cannot fill the block; otherwise Err"}, + {"id": "p3", "fn": "rice_layout", "args": [["block_size", "u16"], ["order", "u32"], ["n_warm_up", "u16"]], "pre": "true", "post": "!(order < 16 && (block_size as u32) % (1u32 << order) != 0) || r.is_err()", "ret": "Result", "basis": "if block_size is not divisible by the 2^order partitions they do not fill the block, so Err"}, + {"id": "p4", "fn": "rice_layout", "args": [["block_size", "u16"], ["order", "u32"], ["n_warm_up", "u16"]], "pre": "true", "post": "!(order < 16 && n_warm_up == 0 && (block_size as u32) % (1u32 << order) == 0) || r == Ok(block_size as u32)", "ret": "Result", "basis": "the partitions fill the block when evenly divisible and there is no warm-up, so Ok(block_size)"} + ]} diff --git a/code/bugfind/baselines/bank/ecdh_scalar.json b/code/bugfind/baselines/bank/ecdh_scalar.json new file mode 100644 index 0000000000000000000000000000000000000000..30e7df14dd5886b8fc6df1e861f3b8f89832c935 --- /dev/null +++ b/code/bugfind/baselines/bank/ecdh_scalar.json @@ -0,0 +1,7 @@ +{"item_id": "ker-ecdh_scalar", "crate_dir": "../../bench/kernels/ecdh_scalar/pre", "lib_name": "k_ecdh_scalar_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "validate_x25519_scalar", "args": [["s", "bytes"]], "pre": "true", "post": "r == (s.len() == 32 && s.iter().any(|&b| b != 0) && (s[0] & 7) == 0 && (s[31] & 0x80) == 0 && (s[31] & 0x40) != 0)", "ret": "bool", "basis": "exactly 32 bytes, not all zero, clamped (low 3 bits of byte 0 clear, top bit of byte 31 clear, second-highest bit of byte 31 set)"}, + {"id": "p2", "fn": "validate_x25519_scalar", "args": [["s", "bytes"]], "pre": "true", "post": "s.len() == 32 || !r", "ret": "bool", "basis": "must be exactly 32 bytes"}, + {"id": "p3", "fn": "validate_x25519_scalar", "args": [["s", "bytes"]], "pre": "true", "post": "!(s.len() == 32 && (s[0] & 7) != 0) || !r", "ret": "bool", "basis": "low 3 bits of byte 0 must be clear"}, + {"id": "p4", "fn": "validate_x25519_scalar", "args": [["s", "bytes"]], "pre": "true", "post": "!(s.len() == 32 && ((s[31] & 0x80) != 0 || (s[31] & 0x40) == 0)) || !r", "ret": "bool", "basis": "top bit of byte 31 must be clear and second-highest bit must be set"} + ]} diff --git a/code/bugfind/baselines/bank/evm_memset.json b/code/bugfind/baselines/bank/evm_memset.json new file mode 100644 index 0000000000000000000000000000000000000000..3d689919d79b36589405a2029db5cdda3f9f4400 --- /dev/null +++ b/code/bugfind/baselines/bank/evm_memset.json @@ -0,0 +1,7 @@ +{"item_id": "ker-evm_memset", "crate_dir": "../../bench/kernels/evm_memset/pre", "lib_name": "k_evm_memset_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "memory_set_len", "args": [["cur_len", "usize"], ["offset", "usize"], ["value_len", "usize"], ["target_size", "opt_usize"], ["limit", "usize"]], "pre": "true", "post": "{ let size = target_size.unwrap_or(value_len); !((offset as u128) + (size as u128) > limit as u128) || r.is_err() }", "ret": "Result", "basis": "Err if offset+target_size exceeds limit (target_size defaults to value_len), in exact arithmetic"}, + {"id": "p2", "fn": "memory_set_len", "args": [["cur_len", "usize"], ["offset", "usize"], ["value_len", "usize"], ["target_size", "opt_usize"], ["limit", "usize"]], "pre": "true", "post": "!(value_len == 0 && target_size.is_none() && offset <= limit) || r == Ok(cur_len)", "ret": "Result", "basis": "Writing an empty value must not grow memory"}, + {"id": "p3", "fn": "memory_set_len", "args": [["cur_len", "usize"], ["offset", "usize"], ["value_len", "usize"], ["target_size", "opt_usize"], ["limit", "usize"]], "pre": "true", "post": "{ let size = target_size.unwrap_or(value_len); match &r { Ok(n) => *n >= cur_len && (size == 0 || (*n as u128) >= (offset as u128) + (size as u128)) && (offset as u128) + (size as u128) <= limit as u128, Err(_) => true } }", "ret": "Result", "basis": "New length after writing size bytes at offset covers the written range, never shrinks, and Ok implies within limit"}, + {"id": "p4", "fn": "memory_set_len", "args": [["cur_len", "usize"], ["offset", "usize"], ["value_len", "usize"], ["target_size", "opt_usize"], ["limit", "usize"]], "pre": "true", "post": "{ let size = target_size.unwrap_or(value_len); !(size > 0 && (offset as u128) + (size as u128) <= limit as u128) || r.is_ok() }", "ret": "Result", "basis": "a non-empty write that fits within limit succeeds (Err only when exceeding limit)"} + ]} diff --git a/code/bugfind/baselines/bank/exif_discard.json b/code/bugfind/baselines/bank/exif_discard.json new file mode 100644 index 0000000000000000000000000000000000000000..fb97f7210b23d3f12cf6fafad8973f5811c17572 --- /dev/null +++ b/code/bugfind/baselines/bank/exif_discard.json @@ -0,0 +1,6 @@ +{"item_id": "ker-exif_discard", "crate_dir": "../../bench/kernels/exif_discard/pre", "lib_name": "k_exif_discard_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "discard_exact", "args": [["avail", "usize"], ["len", "usize"]], "pre": "true", "post": "len <= avail || r.is_err()", "ret": "Result", "basis": "Err when the reader hits EOF early (len > avail)"}, + {"id": "p2", "fn": "discard_exact", "args": [["avail", "usize"], ["len", "usize"]], "pre": "true", "post": "len > avail || r.is_ok()", "ret": "Result", "basis": "returns Ok when the reader had enough data"}, + {"id": "p3", "fn": "discard_exact", "args": [["avail", "usize"], ["len", "usize"]], "pre": "true", "post": "match &r { Ok(n) => *n <= len && (len == 0 || *n >= 1), Err(_) => true }", "ret": "Result", "basis": "number of read rounds: each round consumes at least one byte, so at most len rounds, at least one when len>0"} + ]} diff --git a/code/bugfind/baselines/bank/matrix_power.json b/code/bugfind/baselines/bank/matrix_power.json new file mode 100644 index 0000000000000000000000000000000000000000..05588263b8a37faa3fb64b8dff9b1328d25a2e7b --- /dev/null +++ b/code/bugfind/baselines/bank/matrix_power.json @@ -0,0 +1,7 @@ +{"item_id": "ker-matrix_power", "crate_dir": "../../bench/kernels/matrix_power/pre", "lib_name": "k_matrix_power_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "normalize_power_level", "args": [["power_level", "i64"], ["max_power_level", "i64"]], "pre": "power_level > -(1i64 << 53) && power_level < (1i64 << 53) && max_power_level > 0", "post": "r >= 0 && r <= 100", "ret": "i64", "basis": "Scales to the range 0..=100"}, + {"id": "p2", "fn": "normalize_power_level", "args": [["power_level", "i64"], ["max_power_level", "i64"]], "pre": "power_level > -(1i64 << 53) && power_level < (1i64 << 53) && max_power_level > 0", "post": "power_level < max_power_level || r == 100", "ret": "i64", "basis": "a level at or above max_power_level maps to the top of the range, 100"}, + {"id": "p3", "fn": "normalize_power_level", "args": [["power_level", "i64"], ["max_power_level", "i64"]], "pre": "power_level > -(1i64 << 53) && power_level < (1i64 << 53) && max_power_level > 0", "post": "power_level > 0 || r == 0", "ret": "i64", "basis": "a non-positive level maps to the bottom of the range, 0"}, + {"id": "p4", "fn": "normalize_power_level", "args": [["power_level", "i64"], ["max_power_level", "i64"]], "pre": "power_level > -(1i64 << 53) && power_level < (1i64 << 53) && max_power_level > 0", "post": "!(power_level > 0 && power_level < max_power_level) || (((r as i128) * (max_power_level as i128) - (power_level as i128) * 100).abs() < max_power_level as i128)", "ret": "i64", "basis": "scaling relative to max_power_level: r is within 1 of power_level*100/max_power_level (any rounding)"} + ]} diff --git a/code/bugfind/baselines/bank/mldsa_hint.json b/code/bugfind/baselines/bank/mldsa_hint.json new file mode 100644 index 0000000000000000000000000000000000000000..e0d70a4cc55618025eaf75edba8265e32b800128 --- /dev/null +++ b/code/bugfind/baselines/bank/mldsa_hint.json @@ -0,0 +1,7 @@ +{"item_id": "ker-mldsa_hint", "crate_dir": "../../bench/kernels/mldsa_hint/pre", "lib_name": "k_mldsa_hint_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "hint_weight", "args": [["hint", "bytes"], ["max_ones", "usize"], ["rows", "usize"]], "pre": "(hint.len() as u128) >= (max_ones as u128) + (rows as u128)", "post": "!(1..rows).any(|i| hint[max_ones + i] < hint[max_ones + i - 1]) || r.is_none()", "ret": "Option", "basis": "cumulative counts must be non-decreasing, else malformed (None)"}, + {"id": "p2", "fn": "hint_weight", "args": [["hint", "bytes"], ["max_ones", "usize"], ["rows", "usize"]], "pre": "(hint.len() as u128) >= (max_ones as u128) + (rows as u128)", "post": "!hint[max_ones..max_ones + rows].iter().any(|&c| (c as usize) > max_ones) || r.is_none()", "ret": "Option", "basis": "cumulative counts must be at most max_ones, else malformed (None)"}, + {"id": "p3", "fn": "hint_weight", "args": [["hint", "bytes"], ["max_ones", "usize"], ["rows", "usize"]], "pre": "(hint.len() as u128) >= (max_ones as u128) + (rows as u128)", "post": "{ let c = &hint[max_ones..max_ones + rows]; let ok = c.iter().all(|&x| (x as usize) <= max_ones) && c.windows(2).all(|w| w[0] <= w[1]); !ok || { let k = c.last().map(|&x| x as usize).unwrap_or(0); r == Some(hint[..k].iter().map(|&b| b as usize).sum::()) } }", "ret": "Option", "basis": "Returns the sum of the hint bytes it consumed (the first K position bytes, K = final cumulative count) for a well-formed encoding"}, + {"id": "p4", "fn": "hint_weight", "args": [["hint", "bytes"], ["max_ones", "usize"], ["rows", "usize"]], "pre": "(hint.len() as u128) >= (max_ones as u128) + (rows as u128)", "post": "match r { Some(w) => (w as u128) <= 255u128 * (max_ones as u128), None => true }", "ret": "Option", "basis": "the sum covers at most max_ones consumed bytes, each at most 255"} + ]} diff --git a/code/bugfind/baselines/bank/mldsa_norm.json b/code/bugfind/baselines/bank/mldsa_norm.json new file mode 100644 index 0000000000000000000000000000000000000000..40ff0cb4658b1872264757c1c5c0483c37dbc9dd --- /dev/null +++ b/code/bugfind/baselines/bank/mldsa_norm.json @@ -0,0 +1,7 @@ +{"item_id": "ker-mldsa_norm", "crate_dir": "../../bench/kernels/mldsa_norm/pre", "lib_name": "k_mldsa_norm_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "response_bound", "args": [["gamma1_exponent", "u32"], ["beta", "i32"]], "pre": "gamma1_exponent <= 30 && (1i64 << gamma1_exponent) - (beta as i64) <= i32::MAX as i64 && (1i64 << gamma1_exponent) - (beta as i64) >= i32::MIN as i64", "post": "(r as i64) == (1i64 << gamma1_exponent) - (beta as i64)", "ret": "i32", "basis": "gamma1 - beta where gamma1 = 2^gamma1_exponent (result representable in i32)"}, + {"id": "p2", "fn": "response_bound", "args": [["gamma1_exponent", "u32"], ["beta", "i32"]], "pre": "gamma1_exponent <= 30 && (1i64 << gamma1_exponent) - (beta as i64) <= i32::MAX as i64 && (1i64 << gamma1_exponent) - (beta as i64) >= i32::MIN as i64", "post": "gamma1_exponent != 19 || (r as i64) == 524288 - (beta as i64)", "ret": "i32", "basis": "gamma1 = 2^19 = 524288 for exponent 19"}, + {"id": "p3", "fn": "response_bound", "args": [["gamma1_exponent", "u32"], ["beta", "i32"]], "pre": "gamma1_exponent <= 30 && (1i64 << gamma1_exponent) - (beta as i64) <= i32::MAX as i64 && (1i64 << gamma1_exponent) - (beta as i64) >= i32::MIN as i64", "post": "gamma1_exponent != 17 || (r as i64) == 131072 - (beta as i64)", "ret": "i32", "basis": "gamma1 = 2^17 = 131072 for exponent 17"}, + {"id": "p4", "fn": "response_bound", "args": [["gamma1_exponent", "u32"], ["beta", "i32"]], "pre": "gamma1_exponent <= 30 && (1i64 << gamma1_exponent) - (beta as i64) <= i32::MAX as i64 && (1i64 << gamma1_exponent) - (beta as i64) >= i32::MIN as i64", "post": "beta != 0 || (r as i64) == (1i64 << gamma1_exponent)", "ret": "i32", "basis": "with beta 0 the bound is gamma1 = 2^gamma1_exponent itself"} + ]} diff --git a/code/bugfind/baselines/bank/nanoid_mask.json b/code/bugfind/baselines/bank/nanoid_mask.json new file mode 100644 index 0000000000000000000000000000000000000000..b66ab64fef61a95fea89fe82904622b8cb05d242 --- /dev/null +++ b/code/bugfind/baselines/bank/nanoid_mask.json @@ -0,0 +1,7 @@ +{"item_id": "ker-nanoid_mask", "crate_dir": "../../bench/kernels/nanoid_mask/pre", "lib_name": "k_nanoid_mask_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "alphabet_mask", "args": [["len", "usize"]], "pre": "len >= 2", "post": "match len.checked_next_power_of_two() { Some(p) => r == p - 1, None => true }", "ret": "usize", "basis": "next_power_of_two(len) - 1"}, + {"id": "p2", "fn": "alphabet_mask", "args": [["len", "usize"]], "pre": "len >= 2", "post": "(r.wrapping_add(1) & r) == 0", "ret": "usize", "basis": "the mask is all-ones (2^k - 1)"}, + {"id": "p3", "fn": "alphabet_mask", "args": [["len", "usize"]], "pre": "len >= 2", "post": "r >= len - 1", "ret": "usize", "basis": "m >= len - 1"}, + {"id": "p4", "fn": "alphabet_mask", "args": [["len", "usize"]], "pre": "len >= 2", "post": "(r >> 1) < len - 1", "ret": "usize", "basis": "smallest all-ones value m with m >= len - 1 (the next smaller all-ones value is too small)"} + ]} diff --git a/code/bugfind/baselines/bank/nostr_iv.json b/code/bugfind/baselines/bank/nostr_iv.json new file mode 100644 index 0000000000000000000000000000000000000000..947ef39a5bbc73b2c5a0793ce2ff3e2532f39d7c --- /dev/null +++ b/code/bugfind/baselines/bank/nostr_iv.json @@ -0,0 +1,6 @@ +{"item_id": "ker-nostr_iv", "crate_dir": "../../bench/kernels/nostr_iv/pre", "lib_name": "k_nostr_iv_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "load_iv", "args": [["iv", "bytes"]], "pre": "true", "post": "iv.len() == 16 || r.is_err()", "ret": "Result<[u8; 16], u8>", "basis": "must return Err unless the input is exactly 16 bytes"}, + {"id": "p2", "fn": "load_iv", "args": [["iv", "bytes"]], "pre": "true", "post": "iv.len() != 16 || r.as_ref().map(|a| a[..] == iv[..]).unwrap_or(false)", "ret": "Result<[u8; 16], u8>", "basis": "an exactly-16-byte input is loaded as Ok with the same bytes"}, + {"id": "p3", "fn": "load_iv", "args": [["iv", "bytes"]], "pre": "true", "post": "!(iv.len() == 15 || iv.len() == 17 || iv.len() == 0 || iv.len() == 32) || r.is_err()", "ret": "Result<[u8; 16], u8>", "basis": "off-by-one and boundary lengths (0, 15, 17, 32) are rejected"} + ]} diff --git a/code/bugfind/baselines/bank/odoh_split.json b/code/bugfind/baselines/bank/odoh_split.json new file mode 100644 index 0000000000000000000000000000000000000000..6011b0f08e3830515cb84d7b52e6c7172cbefd67 --- /dev/null +++ b/code/bugfind/baselines/bank/odoh_split.json @@ -0,0 +1,6 @@ +{"item_id": "ker-odoh_split", "crate_dir": "../../bench/kernels/odoh_split/pre", "lib_name": "k_odoh_split_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "encrypted_payload_len", "args": [["msg", "bytes"], ["key_size", "usize"]], "pre": "true", "post": "msg.len() >= key_size || r.is_err()", "ret": "Result", "basis": "Err if the message is shorter than key_size"}, + {"id": "p2", "fn": "encrypted_payload_len", "args": [["msg", "bytes"], ["key_size", "usize"]], "pre": "true", "post": "msg.len() < key_size || r == Ok(msg.len() - key_size)", "ret": "Result", "basis": "ciphertext is the rest after the first key_size bytes, so its length is len - key_size (Ok(0) when len == key_size)"}, + {"id": "p3", "fn": "encrypted_payload_len", "args": [["msg", "bytes"], ["key_size", "usize"]], "pre": "true", "post": "key_size != 0 || r == Ok(msg.len())", "ret": "Result", "basis": "with an empty key the whole message is ciphertext"} + ]} diff --git a/code/bugfind/baselines/bank/phone_ctx.json b/code/bugfind/baselines/bank/phone_ctx.json new file mode 100644 index 0000000000000000000000000000000000000000..f16d573177382195fbd8dad739ac6f21bdcdc016 --- /dev/null +++ b/code/bugfind/baselines/bank/phone_ctx.json @@ -0,0 +1,6 @@ +{"item_id": "ker-phone_ctx", "crate_dir": "../../bench/kernels/phone_ctx/pre", "lib_name": "k_phone_ctx_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "context_prefix_skip", "args": [["s", "bytes"]], "pre": "true", "post": "s.first() != Some(&b'+') || r == 1", "ret": "usize", "basis": "1 if it starts with '+'"}, + {"id": "p2", "fn": "context_prefix_skip", "args": [["s", "bytes"]], "pre": "true", "post": "s.first() == Some(&b'+') || r == 0", "ret": "usize", "basis": "otherwise 0 (including empty input, which must not panic)"}, + {"id": "p3", "fn": "context_prefix_skip", "args": [["s", "bytes"]], "pre": "true", "post": "r <= s.len() && r <= 1", "ret": "usize", "basis": "skip is 0 or 1 and never exceeds the input length"} + ]} diff --git a/code/bugfind/baselines/bank/poly1305_key.json b/code/bugfind/baselines/bank/poly1305_key.json new file mode 100644 index 0000000000000000000000000000000000000000..51028a45d33e173c67e72ada221faa446d76efcc --- /dev/null +++ b/code/bugfind/baselines/bank/poly1305_key.json @@ -0,0 +1,6 @@ +{"item_id": "ker-poly1305_key", "crate_dir": "../../bench/kernels/poly1305_key/pre", "lib_name": "k_poly1305_key_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "key_len_ok", "args": [["key", "bytes"]], "pre": "true", "post": "r == (key.len() == 32)", "ret": "bool", "basis": "a key is acceptable iff it is exactly 32 bytes"}, + {"id": "p2", "fn": "key_len_ok", "args": [["key", "bytes"]], "pre": "true", "post": "key.len() != 32 || r", "ret": "bool", "basis": "a 32-byte key (r then s) is acceptable"}, + {"id": "p3", "fn": "key_len_ok", "args": [["key", "bytes"]], "pre": "true", "post": "!(key.len() == 0 || key.len() == 16 || key.len() == 31 || key.len() == 33 || key.len() == 64) || !r", "ret": "bool", "basis": "lengths other than 32 (empty, r only, off-by-one, double) are rejected"} + ]} diff --git a/code/bugfind/baselines/bank/ring_ctr.json b/code/bugfind/baselines/bank/ring_ctr.json new file mode 100644 index 0000000000000000000000000000000000000000..345bfe75db54a0c1cfebb8e959b967811a1e00a6 --- /dev/null +++ b/code/bugfind/baselines/bank/ring_ctr.json @@ -0,0 +1,6 @@ +{"item_id": "ker-ring_ctr", "crate_dir": "../../bench/kernels/ring_ctr/pre", "lib_name": "k_ring_ctr_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "increment_by", "args": [["old_value", "u32"], ["increment_by", "u32"]], "pre": "true", "post": "r == (((old_value as u64) + (increment_by as u64)) % (1u64 << 32)) as u32", "ret": "u32", "basis": "increments the 32-bit counter, wrapping modulo 2^32"}, + {"id": "p2", "fn": "increment_by", "args": [["old_value", "u32"], ["increment_by", "u32"]], "pre": "true", "post": "increment_by != 0 || r == old_value", "ret": "u32", "basis": "incrementing by zero leaves the counter unchanged"}, + {"id": "p3", "fn": "increment_by", "args": [["old_value", "u32"], ["increment_by", "u32"]], "pre": "true", "post": "(((old_value as u64) + (increment_by as u64)) >= (1u64 << 32)) == (r < old_value)", "ret": "u32", "basis": "wraps modulo 2^32: result is below old_value exactly when the sum overflowed 32 bits"} + ]} diff --git a/code/bugfind/baselines/bank/smoke.json b/code/bugfind/baselines/bank/smoke.json new file mode 100644 index 0000000000000000000000000000000000000000..308ecf618d6e1e507f31b3074f1b99c19df8cd7a --- /dev/null +++ b/code/bugfind/baselines/bank/smoke.json @@ -0,0 +1,13 @@ +{ + "item_id": "smoke-tiny", + "crate_dir": "../../smoke/tiny", + "lib_name": "tiny", + "properties": [ + {"id": "avg_buggy_floor_mean", "fn": "avg_buggy", "args": [["a","u32"],["b","u32"]], "pre": "true", + "post": "r as u64 == (a as u64 + b as u64) / 2", "ret": "u32"}, + {"id": "abs_diff_sym", "fn": "abs_diff", "args": [["a","u32"],["b","u32"]], "pre": "true", + "post": "r as i64 == (a as i64 - b as i64).abs()", "ret": "u32"}, + {"id": "gcd_divides", "fn": "gcd", "args": [["a","u32"],["b","u32"]], "pre": "a != 0 && b != 0", + "post": "r != 0 && a % r == 0 && b % r == 0", "ret": "u32"} + ] +} diff --git a/code/bugfind/baselines/bank/stack_insert.json b/code/bugfind/baselines/bank/stack_insert.json new file mode 100644 index 0000000000000000000000000000000000000000..12a5b8c3747daf7e8cdaa0feaf1c3cbdac29a3a3 --- /dev/null +++ b/code/bugfind/baselines/bank/stack_insert.json @@ -0,0 +1,6 @@ +{"item_id": "ker-stack_insert", "crate_dir": "../../bench/kernels/stack_insert/pre", "lib_name": "k_stack_insert_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "insert_shift_len", "args": [["len", "usize"], ["index", "usize"]], "pre": "true", "post": "index <= len || r.is_err()", "ret": "Result", "basis": "Err if index > len"}, + {"id": "p2", "fn": "insert_shift_len", "args": [["len", "usize"], ["index", "usize"]], "pre": "true", "post": "index > len || r == Ok(len - index)", "ret": "Result", "basis": "elements to shift when inserting at index are those at positions index..len, i.e. len - index"}, + {"id": "p3", "fn": "insert_shift_len", "args": [["len", "usize"], ["index", "usize"]], "pre": "true", "post": "index != len || r == Ok(0)", "ret": "Result", "basis": "inserting at the end (index == len) shifts nothing and is not an error"} + ]} diff --git a/code/bugfind/baselines/bank/tar_pax.json b/code/bugfind/baselines/bank/tar_pax.json new file mode 100644 index 0000000000000000000000000000000000000000..09b7b8f59febcd8784add25b2fd01227a67207a7 --- /dev/null +++ b/code/bugfind/baselines/bank/tar_pax.json @@ -0,0 +1,7 @@ +{"item_id": "ker-tar_pax", "crate_dir": "../../bench/kernels/tar_pax/pre", "lib_name": "k_tar_pax_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "apply_pax", "args": [["entry_type", "u8"], ["has_pax", "bool"]], "pre": "true", "post": "!(entry_type == b'L' || entry_type == b'K') || !r", "ret": "bool", "basis": "never for GNU long-name 'L' or long-link 'K' headers"}, + {"id": "p2", "fn": "apply_pax", "args": [["entry_type", "u8"], ["has_pax", "bool"]], "pre": "true", "post": "!(entry_type == b'x' || entry_type == b'g') || !r", "ret": "bool", "basis": "never for PAX local 'x' or global 'g' headers (even when pending PAX data exists)"}, + {"id": "p3", "fn": "apply_pax", "args": [["entry_type", "u8"], ["has_pax", "bool"]], "pre": "true", "post": "has_pax || !r", "ret": "bool", "basis": "PAX data is applied only if there is pending PAX data"}, + {"id": "p4", "fn": "apply_pax", "args": [["entry_type", "u8"], ["has_pax", "bool"]], "pre": "true", "post": "!(has_pax && (entry_type == b'0' || entry_type == b'5')) || r", "ret": "bool", "basis": "pending PAX data must be applied to real entries (regular file '0', directory '5')"} + ]} diff --git a/code/bugfind/baselines/bank/tinyhttp_hdr.json b/code/bugfind/baselines/bank/tinyhttp_hdr.json new file mode 100644 index 0000000000000000000000000000000000000000..3fe10f2a838cf0b91e0c46bf0db0599772f372bb --- /dev/null +++ b/code/bugfind/baselines/bank/tinyhttp_hdr.json @@ -0,0 +1,7 @@ +{"item_id": "ker-tinyhttp_hdr", "crate_dir": "../../bench/kernels/tinyhttp_hdr/pre", "lib_name": "k_tinyhttp_hdr_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "header_field_ok", "args": [["s", "bytes"]], "pre": "true", "post": "!s.iter().any(|&b| b == b' ' || b == b'\\t' || b == b'\\r' || b == b'\\n') || !r", "ret": "bool", "basis": "contains no whitespace"}, + {"id": "p2", "fn": "header_field_ok", "args": [["s", "bytes"]], "pre": "true", "post": "!(s.first() == Some(&b' ') || s.last() == Some(&b' ')) || !r", "ret": "bool", "basis": "no trimming: ' Transfer-Encoding' and 'Transfer-Encoding ' are invalid"}, + {"id": "p3", "fn": "header_field_ok", "args": [["s", "bytes"]], "pre": "true", "post": "s.iter().all(|b| b.is_ascii()) || !r", "ret": "bool", "basis": "must be ASCII"}, + {"id": "p4", "fn": "header_field_ok", "args": [["s", "bytes"]], "pre": "true", "post": "!(!s.is_empty() && s.iter().all(|&b| b.is_ascii_alphanumeric() || b == b'-')) || r", "ret": "bool", "basis": "a non-empty ASCII name without whitespace (e.g. Transfer-Encoding) is valid"} + ]} diff --git a/code/bugfind/baselines/bank/toodee_drain.json b/code/bugfind/baselines/bank/toodee_drain.json new file mode 100644 index 0000000000000000000000000000000000000000..1256c484107d21e0ccb932d298d93daaf409a5ee --- /dev/null +++ b/code/bugfind/baselines/bank/toodee_drain.json @@ -0,0 +1,6 @@ +{"item_id": "ker-toodee_drain", "crate_dir": "../../bench/kernels/toodee_drain/pre", "lib_name": "k_toodee_drain_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "drain_col_copy_len", "args": [["orig_cols", "usize"], ["col", "usize"]], "pre": "col < orig_cols", "post": "r == orig_cols - col - 1", "ret": "usize", "basis": "cells strictly after col: orig_cols - col - 1"}, + {"id": "p2", "fn": "drain_col_copy_len", "args": [["orig_cols", "usize"], ["col", "usize"]], "pre": "col < orig_cols", "post": "col != orig_cols - 1 || r == 0", "ret": "usize", "basis": "removing the last column shifts nothing"}, + {"id": "p3", "fn": "drain_col_copy_len", "args": [["orig_cols", "usize"], ["col", "usize"]], "pre": "col < orig_cols", "post": "col != 0 || r == orig_cols - 1", "ret": "usize", "basis": "removing the first column shifts all other cells"} + ]} diff --git a/code/bugfind/baselines/bank/tract_len.json b/code/bugfind/baselines/bank/tract_len.json new file mode 100644 index 0000000000000000000000000000000000000000..0dde9c8acd1724d1f50120f005d65d0154742c0c --- /dev/null +++ b/code/bugfind/baselines/bank/tract_len.json @@ -0,0 +1,7 @@ +{"item_id": "ker-tract_len", "crate_dir": "../../bench/kernels/tract_len/pre", "lib_name": "k_tract_len_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "tensor_len_ok", "args": [["dims", "usizes"], ["bits_per_item", "usize"], ["data_size_bytes", "usize"]], "pre": "bits_per_item >= 8", "post": "{ let b = (bits_per_item / 8) as u128; let p = if dims.contains(&0) { Some(0u128) } else { dims.iter().try_fold(1u128, |a, &d| a.checked_mul(d as u128)) }; match p { Some(p) => match p.checked_mul(b) { Some(t) => r == (t == data_size_bytes as u128), None => !r }, None => !r } }", "ret": "bool", "basis": "true iff prod(dims) * (bits_per_item / 8) == data_size_bytes in exact arithmetic"}, + {"id": "p2", "fn": "tensor_len_ok", "args": [["dims", "usizes"], ["bits_per_item", "usize"], ["data_size_bytes", "usize"]], "pre": "true", "post": "!dims.is_empty() || r == (data_size_bytes == bits_per_item / 8)", "ret": "bool", "basis": "empty dims have product 1, so size must equal bits_per_item / 8"}, + {"id": "p3", "fn": "tensor_len_ok", "args": [["dims", "usizes"], ["bits_per_item", "usize"], ["data_size_bytes", "usize"]], "pre": "true", "post": "!dims.contains(&0) || r == (data_size_bytes == 0)", "ret": "bool", "basis": "a zero dimension gives product 0 (fits usize), so true iff data_size_bytes == 0"}, + {"id": "p4", "fn": "tensor_len_ok", "args": [["dims", "usizes"], ["bits_per_item", "usize"], ["data_size_bytes", "usize"]], "pre": "true", "post": "{ let p = dims.iter().try_fold(1usize, |a, &d| a.checked_mul(d)); !(p.is_none() && !dims.contains(&0)) || !r }", "ret": "bool", "basis": "false if the product does not fit usize"} + ]} diff --git a/code/bugfind/baselines/bank/transpose_dims.json b/code/bugfind/baselines/bank/transpose_dims.json new file mode 100644 index 0000000000000000000000000000000000000000..cc4dd74a61d94c87a43df66024f24ee34e16b8a9 --- /dev/null +++ b/code/bugfind/baselines/bank/transpose_dims.json @@ -0,0 +1,7 @@ +{"item_id": "ker-transpose_dims", "crate_dir": "../../bench/kernels/transpose_dims/pre", "lib_name": "k_transpose_dims_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "dims_match", "args": [["width", "usize"], ["height", "usize"], ["len", "usize"]], "pre": "true", "post": "r == ((width as u128) * (height as u128) == len as u128)", "ret": "bool", "basis": "true iff width * height == len in exact arithmetic"}, + {"id": "p2", "fn": "dims_match", "args": [["width", "usize"], ["height", "usize"], ["len", "usize"]], "pre": "true", "post": "width.checked_mul(height).is_some() || !r", "ret": "bool", "basis": "false when the product does not fit usize"}, + {"id": "p3", "fn": "dims_match", "args": [["width", "usize"], ["height", "usize"], ["len", "usize"]], "pre": "true", "post": "!(width == 0 || height == 0) || r == (len == 0)", "ret": "bool", "basis": "a zero dimension gives product 0, so true iff len == 0"}, + {"id": "p4", "fn": "dims_match", "args": [["width", "usize"], ["height", "usize"], ["len", "usize"]], "pre": "true", "post": "width != 1 || r == (len == height)", "ret": "bool", "basis": "width 1 gives product height"} + ]} diff --git a/code/bugfind/baselines/bank/trustdns_ptr.json b/code/bugfind/baselines/bank/trustdns_ptr.json new file mode 100644 index 0000000000000000000000000000000000000000..9092ce8e5cfd61d592b07adae7efef249c766ab5 --- /dev/null +++ b/code/bugfind/baselines/bank/trustdns_ptr.json @@ -0,0 +1,6 @@ +{"item_id": "ker-trustdns_ptr", "crate_dir": "../../bench/kernels/trustdns_ptr/pre", "lib_name": "k_trustdns_ptr_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "pointer_ok", "args": [["location", "usize"], ["pointer_location", "usize"], ["name_start", "usize"]], "pre": "true", "post": "location < name_start || !r", "ret": "bool", "basis": "pointer target (location) at or after the start of the current name is rejected (chains could loop)"}, + {"id": "p2", "fn": "pointer_ok", "args": [["location", "usize"], ["pointer_location", "usize"], ["name_start", "usize"]], "pre": "true", "post": "location >= name_start || r", "ret": "bool", "basis": "target strictly before name start is acceptable"}, + {"id": "p3", "fn": "pointer_ok", "args": [["location", "usize"], ["pointer_location", "usize"], ["name_start", "usize"]], "pre": "true", "post": "location != name_start || !r", "ret": "bool", "basis": "strictly before: a target equal to name_start is rejected"} + ]} diff --git a/code/bugfind/baselines/bank/versionize_fam.json b/code/bugfind/baselines/bank/versionize_fam.json new file mode 100644 index 0000000000000000000000000000000000000000..ec6e57fd7cf40d5d39799e0e14a4532480226361 --- /dev/null +++ b/code/bugfind/baselines/bank/versionize_fam.json @@ -0,0 +1,6 @@ +{"item_id": "ker-versionize_fam", "crate_dir": "../../bench/kernels/versionize_fam/pre", "lib_name": "k_versionize_fam_pre", "provenance": {"author": "claude-sonnet subagent, blind", "written_from": "signature + doc string only", "saw_source": false, "saw_diff": false, "saw_advisory": false}, + "properties": [ + {"id": "p1", "fn": "fam_entry", "args": [["entries", "u32s"], ["header_len", "usize"], ["i", "usize"]], "pre": "i < header_len", "post": "header_len == entries.len() || r.is_err()", "ret": "Result", "basis": "Err if the header length disagrees with the actual number of entries"}, + {"id": "p2", "fn": "fam_entry", "args": [["entries", "u32s"], ["header_len", "usize"], ["i", "usize"]], "pre": "i < header_len", "post": "header_len != entries.len() || r == Ok(entries[i])", "ret": "Result", "basis": "reads entry i when the header length matches the entries"}, + {"id": "p3", "fn": "fam_entry", "args": [["entries", "u32s"], ["header_len", "usize"], ["i", "usize"]], "pre": "i < header_len", "post": "header_len <= entries.len() || r.is_err()", "ret": "Result", "basis": "a header declaring more entries than exist must be Err and never read out of bounds"} + ]} diff --git a/code/bugfind/baselines/gen_harness.py b/code/bugfind/baselines/gen_harness.py new file mode 100644 index 0000000000000000000000000000000000000000..640153fb903bc8b2d9d480dd1cef5a22686627db --- /dev/null +++ b/code/bugfind/baselines/gen_harness.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 -I +"""Emit a Kani / proptest / cargo-fuzz project for one bank. Usage: gen_harness.py BANK ARM OUTDIR [pre|post]""" +import json, os, shutil, sys +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import property_bank as pb + + +def kani(bank, out): + lib = bank["lib_name"] + body = ["use %s::*;" % lib] + for p in bank["properties"]: + if any(t not in pb.SCALARS for _, t in p["args"]): + continue # Kani arm: scalar-argument properties only + decl = "\n ".join(f"let {n}: {t} = kani::any();" for n, t in p["args"]) + call = ", ".join(n for n, _ in p["args"]) + body.append(f"#[kani::proof]\nfn proof_{p['id']}() {{\n {decl}\n kani::assume({p['pre']});\n" + f" let r: {p['ret']} = {lib}::{p['fn']}({call});\n assert!({p['post']});\n}}") + os.makedirs(out + "/tests", exist_ok=True) + open(out + "/tests/kani_props.rs", "w").write("\n\n".join(body) + "\n") + open(out + "/Cargo.toml", "w").write(_cargo(bank, "kani", "")) + + +def proptest(bank, out): + lib = bank["lib_name"] + body = ["use proptest::prelude::*;", "use %s::*;" % lib, "proptest! {", "#![proptest_config(ProptestConfig { cases: u32::MAX, max_shrink_iters: 0, failure_persistence: None, .. ProptestConfig::default() })]"] + for p in bank["properties"]: + sig = ", ".join(f"{n} in any::<{pb.rust_type(t)}>()" for n, t in p["args"]) + call = ", ".join(pb.call_arg(n, t) for n, t in p["args"]) + body.append(f"#[test]\nfn prop_{p['id']}({sig}) {{\n prop_assume!({p['pre']});\n let r: {p['ret']} = {lib}::{p['fn']}({call});\n let ok: bool = {{ {p['post']} }};\n prop_assert!(ok, \"property {p['id']} violated\");\n}}") + body.append("}") + os.makedirs(out + "/tests", exist_ok=True) + open(out + "/tests/pt_props.rs", "w").write("\n".join(body) + "\n") + open(out + "/Cargo.toml", "w").write(_cargo(bank, "proptest", 'proptest = "1"\n')) + + +def fuzz(bank, out): + lib = bank["lib_name"] + os.makedirs(out + "/fuzz/fuzz_targets", exist_ok=True) + names = [] + open(out + "/Cargo.toml", "w").write('[package]\nname = "fuzz-root"\nversion = "0.0.0"\nedition = "2021"\n\n[lib]\npath = "empty.rs"\n\n[workspace]\n') + for p in bank["properties"]: + fields = "\n".join(f" {n}: {pb.rust_type(t)}," for n, t in p["args"]) + call = ", ".join(pb.call_arg(n, t) for n, t in p["args"]) + binds = "\n ".join(f"let {n} = i.{n};" for n, _ in p["args"]) + src = (f"#![no_main]\nuse libfuzzer_sys::fuzz_target;\nuse arbitrary::Arbitrary;\nuse {lib}::*;\n" + f"#[derive(Arbitrary, Debug)]\nstruct In {{\n{fields}\n}}\n" + f"fuzz_target!(|i: In| {{\n {binds}\n if !({p['pre']}) {{ return; }}\n" + f" let r: {p['ret']} = {lib}::{p['fn']}({call});\n let ok: bool = {{ {p['post']} }};\n assert!(ok);\n}});\n") + open(f"{out}/fuzz/fuzz_targets/{p['id']}.rs", "w").write(src); names.append(p["id"]) + bins = "".join(f'\n[[bin]]\nname = "{n}"\npath = "fuzz_targets/{n}.rs"\ntest = false\ndoc = false\nbench = false\n' for n in names) + open(out + "/fuzz/Cargo.toml", "w").write( + f'[package]\nname = "fuzz-harness"\nversion = "0.0.0"\nedition = "2021"\npublish = false\n\n[package.metadata]\ncargo-fuzz = true\n\n' + f'[dependencies]\nlibfuzzer-sys = "0.4"\narbitrary = {{ version = "1", features = ["derive"] }}\n{lib} = {{ path = "{os.path.abspath(bank["crate_dir"])}" }}\n{bins}\n[workspace]\n') + + +def _cargo(bank, name, deps): + return (f'[package]\nname = "{name}-harness"\nversion = "0.0.0"\nedition = "2021"\n\n[lib]\npath = "empty.rs"\n\n[dependencies]\n{deps}' + f'{bank["lib_name"]} = {{ path = "{os.path.abspath(bank["crate_dir"])}" }}\n\n[workspace]\n') + + +def main(): + bank_path, arm, out = sys.argv[1:4] + bank = pb.load(bank_path) + rev = sys.argv[4] if len(sys.argv) > 4 else "pre" + bank["crate_dir"] = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(bank_path)), bank["crate_dir"])) + bank = pb.revision(bank, rev) + os.makedirs(out, exist_ok=True) + open(out + "/empty.rs", "w").write("") + {"kani": kani, "proptest": proptest, "fuzz": fuzz}[arm](bank, out) + print("generated", arm, "->", out) + +if __name__ == "__main__": + main() diff --git a/code/bugfind/baselines/property_bank.py b/code/bugfind/baselines/property_bank.py new file mode 100644 index 0000000000000000000000000000000000000000..3e534c63459b38530546292670483cb7a5845a16 --- /dev/null +++ b/code/bugfind/baselines/property_bank.py @@ -0,0 +1,49 @@ +"""Shared property bank. One JSON file per item: +{ + "item_id": "...", "crate_dir": "path with Cargo.toml (lib name `target_crate`)", "lib_name": "tiny", + "properties": [ + {"id": "p1", "fn": "avg_buggy", "args": [["a","u32"],["b","u32"]], + "pre": "true", "post": "r == ((a as u64 + b as u64) / 2) as u32", "ret": "u32"} + ] +} +`pre` and `post` are Rust boolean expressions over the arg names and `r` (the return value). Every property also +carries the implicit check "the call does not panic / overflow", which each tool detects natively. +""" +import json + +SCALARS = {"u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "isize", "bool"} +# v1 adds owned-collection arg types, passed to the function by reference (`&a`): `bytes`=Vec, `u32s`=Vec, `usizes`=Vec, +# and `opt_usize`=Option (passed by value). Kani handles scalars only (vec/option properties are reported `unsupported` for Kani). +RUST_TYPE = {"bytes": "Vec", "u32s": "Vec", "usizes": "Vec", "opt_usize": "Option"} +BY_REF = {"bytes", "u32s", "usizes"} +SUPPORTED = SCALARS | set(RUST_TYPE) + + +def rust_type(t): return RUST_TYPE.get(t, t) + + +def call_arg(n, t): return ("&" + n) if t in BY_REF else n + + +def revision(bank, rev): + """Return a copy of the bank pointed at the `pre` or `post` revision of a kernel (crate_dir .../pre -> .../post, lib k_x_pre -> k_x_post).""" + b = dict(bank) + if rev == "post": + b["crate_dir"] = bank["crate_dir"].rstrip("/").rsplit("/pre", 1)[0] + "/post" + b["lib_name"] = bank["lib_name"].rsplit("_pre", 1)[0] + "_post" + return b + + +def load(path): + b = json.load(open(path)) + for k in ("item_id", "crate_dir", "lib_name", "properties"): + if k not in b: raise ValueError(f"bank missing {k}") + ids = set() + for p in b["properties"]: + for k in ("id", "fn", "args", "pre", "post", "ret"): + if k not in p: raise ValueError(f"property missing {k}: {p}") + if p["id"] in ids: raise ValueError("duplicate property id " + p["id"]) + ids.add(p["id"]) + for _, t in p["args"]: + if t not in SUPPORTED: raise ValueError(f"unsupported arg type {t} ") + return b diff --git a/code/bugfind/baselines/run_baselines.py b/code/bugfind/baselines/run_baselines.py new file mode 100644 index 0000000000000000000000000000000000000000..5a58d411733567020c179901f1249e90c6ffa7dd --- /dev/null +++ b/code/bugfind/baselines/run_baselines.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 -I +"""Run Kani / proptest / cargo-fuzz on one property bank under an EQUAL CPU budget. +Usage: run_baselines.py BANK --cpu-seconds 60 [--arms kani,proptest,fuzz] [--workdir /apps/...] +Emits one JSON line per (property, arm): {item_id, property, arm, flagged, cpu_seconds, status}. +Budget is per (property, arm). `flagged` = tool reported a violation / panic. Build time is reported +as build_seconds and not charged to the budget. +""" +import argparse, json, os, resource, subprocess, sys, time +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +import property_bank as pb + + +def limited(cmd, cwd, cpu, env=None): + def pre(): + os.setsid(); resource.setrlimit(resource.RLIMIT_CPU, (cpu, cpu + 5)) + t0 = time.time(); r0 = resource.getrusage(resource.RUSAGE_CHILDREN) + try: + p = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, timeout=cpu * 3 + 10, preexec_fn=pre, env=env) + rc, out = p.returncode, p.stdout + p.stderr + except subprocess.TimeoutExpired as e: + rc, out = -9, "wall timeout" + r1 = resource.getrusage(resource.RUSAGE_CHILDREN) + return rc, out, (r1.ru_utime + r1.ru_stime) - (r0.ru_utime + r0.ru_stime), time.time() - t0 + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("bank"); ap.add_argument("--cpu-seconds", type=int, default=60) + ap.add_argument("--arms", default="kani,proptest,fuzz"); ap.add_argument("--revision", default="pre", choices=["pre", "post"], help="post = negative control (the fixed revision)") + ap.add_argument("--fuzz-toolchain", default="nightly-2026-09-17"); ap.add_argument("--workdir", default="/apps/development/rlhf/bugfind_data/work/baselines") + a = ap.parse_args() + if not a.workdir.startswith("/apps/"): sys.exit("workdir must be under /apps") + bank = pb.load(a.bank) + for arm in a.arms.split(","): + out = os.path.join(a.workdir, bank["item_id"] + "." + a.revision, arm) + subprocess.run([sys.executable, "-I", os.path.join(HERE, "gen_harness.py"), a.bank, arm, out, a.revision], check=True, capture_output=True) + env = dict(os.environ, CARGO_TARGET_DIR=os.path.join(out, "target")) + for p in bank["properties"]: + res = dict(item_id=bank["item_id"], revision=a.revision, property=p["id"], arm=arm, cpu_budget=a.cpu_seconds) + if arm == "proptest": + b = limited(["cargo", "test", "--no-run", "--test", "pt_props", "-j4"], out, 900, env) + res["build_seconds"] = round(b[3], 1) + if b[0] != 0: res.update(status="build_fail", flagged=None, log=b[1][-400:]) + else: + rc, o, cpu, wall = limited(["cargo", "test", "--test", "pt_props", f"prop_{p['id']}"], out, a.cpu_seconds, env) + res.update(flagged=(rc != 0 and "test result: FAILED" in o), status="ok" if rc in (0, 101) else f"rc{rc}", cpu_seconds=round(cpu, 1)) + elif arm == "fuzz": + fdir = os.path.join(out, "fuzz") + fenv = dict(env, RUSTUP_TOOLCHAIN=a.fuzz_toolchain) # libFuzzer sanitizer flags need a nightly + b = limited(["cargo", "fuzz", "build", p["id"]], out, 900, fenv) # build is reported, not charged to the budget + res["build_seconds"] = round(b[3], 1) + if b[0] != 0: + res.update(status="build_fail", flagged=None, log=b[1][-400:]); print(json.dumps(res), flush=True); continue + rc, o, cpu, wall = limited(["cargo", "fuzz", "run", p["id"], "--", f"-max_total_time={a.cpu_seconds}", "-rss_limit_mb=2048"], out, a.cpu_seconds + 20, fenv) + res.update(flagged=("panicked" in o or "SUMMARY: libFuzzer" in o or "AddressSanitizer" in o), status="ok" if rc in (0, 77) else f"rc{rc}", cpu_seconds=round(cpu, 1)) + elif arm == "kani": + rc, o, cpu, wall = limited(["cargo", "kani", "--tests", "--harness", f"proof_{p['id']}"], out, a.cpu_seconds, env) + res.update(flagged=("VERIFICATION:- FAILED" in o or "VERIFICATION FAILED" in o), status="ok" if rc in (0, 1) else f"rc{rc}", cpu_seconds=round(cpu, 1)) + print(json.dumps(res), flush=True) + +if __name__ == "__main__": + main() diff --git a/code/bugfind/baselines/sweep.sh b/code/bugfind/baselines/sweep.sh new file mode 100644 index 0000000000000000000000000000000000000000..36ec52ba2b9bf4d271ec667e3354147fa154eca3 --- /dev/null +++ b/code/bugfind/baselines/sweep.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# Serial sweep of the proptest arm over every kernel bank, pre (positive) and post (negative control). +# Usage (ONE hostguard job, never parallel): hostguard.py run --cores 4 --mem-gb 16 --label sweep --wait -- bash baselines/sweep.sh CPU_SECONDS ARMS OUT.jsonl +set -u +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"; source "$HERE/../env.sh"; export KANI_HOME=$TC/kani +CPU=${1:-5}; ARMS=${2:-proptest}; OUT=${3:-$HERE/../bench/ledger/baseline_sweep.jsonl} +: > "$OUT" +for b in "$HERE"/bank/*.json; do + case "$b" in *smoke*) continue;; esac + for rev in pre post; do + timeout 900 python3 -I "$HERE/run_baselines.py" "$b" --cpu-seconds "$CPU" --arms "$ARMS" --revision $rev >> "$OUT" 2>>"$OUT.err" + done +done diff --git a/code/bugfind/bench/build_items.py b/code/bugfind/bench/build_items.py new file mode 100644 index 0000000000000000000000000000000000000000..85048f03b3d05181319b0102f1844228a452a9af --- /dev/null +++ b/code/bugfind/bench/build_items.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 -I +"""Merge selection + translation outputs into the committed item records and an honest funnel summary. +Inputs (under /apps data dir): advisory_candidates.jsonl, advisory_translate.jsonl, mutants.jsonl, mutant_translate.jsonl +Outputs (committed, under bugfind/bench/items/): advisory_items.jsonl (kept), advisory_attempts.jsonl (all translation attempts), +mutant_items.jsonl (kept), SUMMARY.json. +Item semantics: every item is a (buggy, reference) pair. Advisory: pre-fix crate version (positive) vs first patched version +(negative control). Mutant: mutated function (positive, with a differential-execution witness) vs the original (negative control). +""" +import json, os, sys, collections +HERE = os.path.dirname(os.path.abspath(__file__)) +DATA = "/apps/development/rlhf/bugfind_data/out" +OUT = os.path.join(HERE, "items"); os.makedirs(OUT, exist_ok=True) + + +def jl(p): + return [json.loads(l) for l in open(p)] if os.path.exists(p) else [] + +adv = {r["adv_id"]: r for r in jl(f"{DATA}/advisory_candidates.jsonl")} +tr = {r["item"]: r for r in jl(f"{DATA}/advisory_translate.jsonl")} +funnel = json.load(open(f"{DATA}/advisory_funnel.json")) +pre = json.load(open(f"{DATA}/advisory_translate.jsonl.prefilter.json")) if os.path.exists(f"{DATA}/advisory_translate.jsonl.prefilter.json") else {} +keep_fields = ["adv_id", "crate", "date", "url", "title", "categories", "affected_functions", "bug_class", "pre_version", "post_version", "stage", "changed_files", "changed_lines", "unsafe_in_changed_files"] +kept, attempts = [], [] +for k, t in tr.items(): + a = adv[k] + rec = {f: a.get(f) for f in keep_fields} + rec.update({f: t.get(f) for f in ["changed_functions", "charon_ok", "aeneas_ok", "fn_present", "lean_ok", "translated", "error", "lean_lines", "seconds"]}) + rec["item_id"] = f"adv-{k}"; rec["kind"] = "advisory" + rec["labels"] = {"buggy": f"{a['crate']}@{a['pre_version']}", "reference": f"{a['crate']}@{a['post_version']}"} + attempts.append(rec) + if t.get("translated"): kept.append(rec) +with open(f"{OUT}/advisory_items.jsonl", "w") as f: + for r in sorted(kept, key=lambda r: r["item_id"]): f.write(json.dumps(r) + "\n") +with open(f"{OUT}/advisory_attempts.jsonl", "w") as f: + for r in sorted(attempts, key=lambda r: r["item_id"]): f.write(json.dumps(r) + "\n") + +mut = jl(f"{DATA}/mutants.jsonl"); mtr = {r["item"]: r for r in jl(f"{DATA}/mutant_translate.jsonl")} +mk = [] +for m in mut: + if m["status"] != "kept_nonequivalent": continue + t = mtr.get(m["item_id"]) + m = dict(m); m["translated"] = bool(t and t["translated"]); m["translate_error"] = (t or {}).get("error") + if m["translated"]: mk.append(m) +with open(f"{OUT}/mutant_items.jsonl", "w") as f: + for m in mk: f.write(json.dumps(m) + "\n") + +fail = collections.Counter((r.get("error") or "ok").split(":")[0] + ":" + (r.get("error") or "").split(":")[-1].strip()[:50] for r in attempts if not r["translated"]) +mstat = collections.Counter(m["status"] for m in mut) +# --- kernels (minimal-extraction pairs from RustSec fixes) --- +ker_tr = {r["item"]: r for r in jl(f"{DATA}/kernel_translate.jsonl")} +ker_fail = jl(f"{DATA}/kernel_translate.jsonl.failed_attempts") +wit = {r["item_id"]: r for r in jl(os.path.join(HERE, "ledger", "witness_ledger.jsonl"))} +kdir = os.path.join(HERE, "kernels"); kk, katt = [], [] +for kid in sorted(os.listdir(kdir)): + m = json.load(open(f"{kdir}/{kid}/meta.json")); a, b = ker_tr.get(kid + ".pre"), ker_tr.get(kid + ".post"); w = wit.get(m["item_id"], {}) + rec = dict(m, kind="kernel", pre_translated=bool(a and a["translated"]), post_translated=bool(b and b["translated"]), + pre_lean_sha256=(a or {}).get("lean_sha256"), post_lean_sha256=(b or {}).get("lean_sha256"), + witness_pre=w.get("pre", {}).get("outcome"), witness_post=w.get("post", {}).get("outcome"), discriminating=bool(w.get("discriminating"))) + rec["kept"] = rec["pre_translated"] and rec["post_translated"] and rec["discriminating"] + katt.append(rec) + if rec["kept"]: kk.append(rec) +with open(f"{OUT}/kernel_items.jsonl", "w") as f: + for r in kk: f.write(json.dumps(r) + "\n") +with open(f"{OUT}/kernel_attempts.jsonl", "w") as f: + for r in katt: f.write(json.dumps(r) + "\n") + +S = { + "advisories": {**{k: v for k, v in funnel.items()}, "prefilter": pre, + "translation_attempted": len(attempts), "translated_and_lean_compiles": len(kept), + "distinct_crates_kept": len({r["crate"] for r in kept}), "kept_by_bug_class": dict(collections.Counter(c for r in kept for c in r["bug_class"])), + "translation_failure_reasons_top": fail.most_common(12)}, + "mutants": {"generated": len(mut), "by_status": dict(mstat), "translation_attempted": len(mtr), + "kept_nonequivalent_and_translated": len(mk), "distinct_functions": len({m["function"] for m in mk}), + "by_operator": dict(collections.Counter(m["operator"] for m in mk))}, + "kernels": {"attempted_pairs": len(katt), "pre_and_post_lean_compile": sum(r["pre_translated"] and r["post_translated"] for r in katt), + "witness_discriminating_on_original_rust": sum(r["discriminating"] for r in katt), "kept_pairs": len(kk), + "distinct_crates": len({r["crate"] for r in kk}), "by_bug_class": dict(collections.Counter(r["bug_class"] for r in kk)), + "by_fidelity": dict(collections.Counter(r["fidelity"] for r in kk)), + "translation_failures_before_rewrite": [{"item": r["item"], "error": (r.get("error") or "")[:160]} for r in ker_fail], + "note": "Aeneas (6c2788d) emitted ill-typed Lean for `!b` / `a || b` chains bound to a bool (Prop vs Bool, `failed to synthesize Decidable`); the post kernel of tar_pax was rewritten with explicit if/else (same semantics) and then translates."}, + "total_items_kept_now": len(kept) + len(mk) + len(kk), + "total_real_bug_pairs": len(kept) + len(kk), + "notes": "Mutants are clustered by source function (21 functions) and are not independent samples; the crate-clustered bootstrap treats the function as the cluster. Advisory items are clustered by crate.", +} +json.dump(S, open(f"{OUT}/SUMMARY.json", "w"), indent=1) +print(json.dumps(S, indent=1)) diff --git a/code/bugfind/bench/corpus/functions.json b/code/bugfind/bench/corpus/functions.json new file mode 100644 index 0000000000000000000000000000000000000000..9ee673d7831e489c14ab4183cc7201807e1980ec --- /dev/null +++ b/code/bugfind/bench/corpus/functions.json @@ -0,0 +1,44 @@ +[ + {"name":"avg_floor","args":["u32","u32"],"ret":"u32","doc":"floor((a+b)/2) without overflow", + "src":"pub fn avg_floor(a: u32, b: u32) -> u32 {\n (a & b) + ((a ^ b) >> 1)\n}"}, + {"name":"abs_diff_u32","args":["u32","u32"],"ret":"u32","doc":"|a-b|", + "src":"pub fn abs_diff_u32(a: u32, b: u32) -> u32 {\n if a >= b { a - b } else { b - a }\n}"}, + {"name":"gcd","args":["u32","u32"],"ret":"u32","doc":"Euclid gcd, gcd(0,0)=0", + "src":"pub fn gcd(a: u32, b: u32) -> u32 {\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n x\n}"}, + {"name":"isqrt","args":["u32"],"ret":"u32","doc":"floor(sqrt(n))", + "src":"pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}"}, + {"name":"clamp_add","args":["u8","u8","u8"],"ret":"u8","doc":"min(a+b, cap) without overflow", + "src":"pub fn clamp_add(a: u8, b: u8, cap: u8) -> u8 {\n let s = (a as u16) + (b as u16);\n if s > cap as u16 { cap } else { s as u8 }\n}"}, + {"name":"round_up_div","args":["u32","u32"],"ret":"Option","doc":"ceil(a/b), None if b==0", + "src":"pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b != 0 { 1 } else { 0 })\n }\n}"}, + {"name":"next_multiple","args":["u32","u32"],"ret":"Option","doc":"smallest multiple of m that is >= a; None on m==0 or overflow", + "src":"pub fn next_multiple(a: u32, m: u32) -> Option {\n if m == 0 {\n return None;\n }\n let r = a % m;\n if r == 0 {\n Some(a)\n } else {\n a.checked_add(m - r)\n }\n}"}, + {"name":"digit_sum","args":["u32"],"ret":"u32","doc":"sum of decimal digits", + "src":"pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 10;\n x /= 10;\n }\n s\n}"}, + {"name":"is_pow2","args":["u32"],"ret":"bool","doc":"n is a positive power of two", + "src":"pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n & (n - 1)) == 0\n}"}, + {"name":"popcount","args":["u32"],"ret":"u32","doc":"number of set bits", + "src":"pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c += x & 1;\n x >>= 1;\n }\n c\n}"}, + {"name":"ilog2_floor","args":["u32"],"ret":"Option","doc":"floor(log2 n), None for 0", + "src":"pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}"}, + {"name":"triangular","args":["u32"],"ret":"u64","doc":"n(n+1)/2 in u64", + "src":"pub fn triangular(n: u32) -> u64 {\n let m = n as u64;\n m * (m + 1) / 2\n}"}, + {"name":"collatz_steps","args":["u16"],"ret":"u32","doc":"steps to reach 1 (0 for n<=1)", + "src":"pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}"}, + {"name":"sat_sub_i32","args":["i32","i32"],"ret":"i32","doc":"saturating subtraction", + "src":"pub fn sat_sub_i32(a: i32, b: i32) -> i32 {\n let d = (a as i64) - (b as i64);\n if d > i32::MAX as i64 {\n i32::MAX\n } else if d < i32::MIN as i64 {\n i32::MIN\n } else {\n d as i32\n }\n}"}, + {"name":"sign3","args":["i32"],"ret":"i32","doc":"-1,0,1", + "src":"pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}"}, + {"name":"pow_mod","args":["u32","u32","u32"],"ret":"u32","doc":"b^e mod m, m>0 (m==0 -> 0)", + "src":"pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}"}, + {"name":"varint_len","args":["u64"],"ret":"u32","doc":"LEB128 byte length of n", + "src":"pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}"}, + {"name":"zigzag_enc","args":["i32"],"ret":"u32","doc":"protobuf zigzag encode", + "src":"pub fn zigzag_enc(n: i32) -> u32 {\n ((n << 1) ^ (n >> 31)) as u32\n}"}, + {"name":"bit_reverse8","args":["u8"],"ret":"u8","doc":"reverse bits of a byte", + "src":"pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}"}, + {"name":"lcm_checked","args":["u32","u32"],"ret":"Option","doc":"lcm, None on overflow, lcm(_,0)=Some(0)", + "src":"pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}"}, + {"name":"midpoint_idx","args":["usize","usize"],"ret":"usize","doc":"lo + (hi-lo)/2 for lo<=hi, else lo", + "src":"pub fn midpoint_idx(lo: usize, hi: usize) -> usize {\n if hi <= lo { lo } else { lo + (hi - lo) / 2 }\n}"} +] diff --git a/code/bugfind/bench/difffuncs.py b/code/bugfind/bench/difffuncs.py new file mode 100644 index 0000000000000000000000000000000000000000..74c54003c3191f82ad6962d9cc00f2390f7a6893 --- /dev/null +++ b/code/bugfind/bench/difffuncs.py @@ -0,0 +1,39 @@ +"""Find the functions whose bodies changed between two unpacked crate versions (pre-side names), by line-range +overlap of difflib opcodes with a regex-located enclosing `fn`. Heuristic (no parser), documented as such.""" +import difflib, os, re + +FN = re.compile(r"^\s*(?:pub(?:\([^)]*\))?\s+)?(?:const\s+)?(?:unsafe\s+)?(?:async\s+)?(?:extern\s+\"[^\"]*\"\s+)?fn\s+([A-Za-z_]\w*)") + + +def modpath(rel): + p = rel[len("src/"):-3].split("/") + if p[-1] in ("mod", "lib"): p = p[:-1] + return p + + +def changed_functions(pre, post): + out = [] + for dp, _, fs in os.walk(os.path.join(pre, "src")): + for f in fs: + if not f.endswith(".rs"): continue + rel = os.path.relpath(os.path.join(dp, f), pre) + if rel.endswith("main.rs") and rel == "src/main.rs": continue + a = open(os.path.join(pre, rel), encoding="utf8", errors="replace").read().splitlines() + pp = os.path.join(post, rel) + b = open(pp, encoding="utf8", errors="replace").read().splitlines() if os.path.exists(pp) else [] + if a == b: continue + # skip test code: everything from a `#[cfg(test)]` line on, and fns directly under `#[test]` + cut = next((i for i, l in enumerate(a) if re.match(r"\s*#\[cfg\(test\)\]", l)), len(a)) + starts = [(i, FN.match(l).group(1)) for i, l in enumerate(a[:cut]) if FN.match(l) and not any("#[test]" in a[k] for k in range(max(0, i - 3), i))] + if cut < len(a): + a, b = a[:cut], b[: next((i for i, l in enumerate(b) if re.match(r"\s*#\[cfg\(test\)\]", l)), len(b))] + for tag, i1, i2, j1, j2 in difflib.SequenceMatcher(None, a, b, autojunk=False).get_opcodes(): + if tag == "equal": continue + for ln in sorted({i1, max(i2 - 1, i1)}): + cands = [s for s in starts if s[0] <= ln] + if cands: + name = cands[-1][1] + # a `fn` header preceding the changed line only counts if the change is within a plausible body (<= 400 lines) + if ln - cands[-1][0] <= 400: + out.append((rel, ".".join(modpath(rel)).replace(".", "::"), name)) + return sorted(set(out)) diff --git a/code/bugfind/bench/items/SUMMARY.json b/code/bugfind/bench/items/SUMMARY.json new file mode 100644 index 0000000000000000000000000000000000000000..3dc36dfac790c2ef42ff637f4528b77fddc9ae9e --- /dev/null +++ b/code/bugfind/bench/items/SUMMARY.json @@ -0,0 +1,129 @@ +{ + "advisories": { + "parsed": 1294, + "has_patch": 633, + "resolved": 566, + "downloaded": 481, + "small_diff": 278, + "diff_safe": 152, + "strict_safe": 87, + "reject_reasons": { + "diff_touches_unsafe_io_async": 126, + "diff_too_large": 165, + "no_published_vulnerable_version": 64, + "download": 85, + "no_published_patched_version": 3, + "no_rs_diff": 38 + }, + "prefilter": { + "skipped_not_targeted_or_no_fn": 58, + "to_attempt": 94 + }, + "translation_attempted": 94, + "translated_and_lean_compiles": 4, + "distinct_crates_kept": 4, + "kept_by_bug_class": { + "other": 1, + "panic": 2, + "logic": 1, + "dos_loop_or_recursion": 1 + }, + "translation_failure_reasons_top": [ + [ + "start function not in generated Lean:start function not in generated Lean", + 15 + ], + [ + "aeneas:[Error] Unimplemented", + 8 + ], + [ + "aeneas/lean timeout:aeneas/lean timeout", + 6 + ], + [ + "aeneas:[Error] Dynamic trait types are not supported yet", + 5 + ], + [ + "aeneas:[Error] Early returns inside of loops are not supp", + 5 + ], + [ + "charon timeout:charon timeout", + 4 + ], + [ + "lean:Type class instance resolution failures can be ins", + 4 + ], + [ + "aeneas:[Error] Returns inside of nested loops are not sup", + 3 + ], + [ + "lean:declaration uses `sorry`", + 2 + ], + [ + "charon:unknown feature `stdsimd`", + 2 + ], + [ + "aeneas:new value doesn't have the same type as its destin", + 2 + ], + [ + "aeneas:", + 2 + ] + ] + }, + "mutants": { + "generated": 228, + "by_status": { + "kept_nonequivalent": 207, + "no_witness": 8, + "timeout": 13 + }, + "translation_attempted": 207, + "kept_nonequivalent_and_translated": 199, + "distinct_functions": 21, + "by_operator": { + "op": 93, + "const": 104, + "checked": 2 + } + }, + "kernels": { + "attempted_pairs": 23, + "pre_and_post_lean_compile": 23, + "witness_discriminating_on_original_rust": 23, + "kept_pairs": 23, + "distinct_crates": 22, + "by_bug_class": { + "panic": 8, + "overflow": 5, + "logic": 7, + "dos_loop_or_recursion": 3 + }, + "by_fidelity": { + "model_of_std": 5, + "verbatim_logic": 18 + }, + "translation_failures_before_rewrite": [ + { + "item": "tar_pax.post", + "error": "lean: /apps/development/rlhf/bugfind_data/work/kernels/tar_pax.post/Crate.lean:37:10: error: Application type mismatch: The argument\n \u00acis_extension_header\nhas " + }, + { + "item": "tar_pax.post", + "error": "lean: /apps/development/rlhf/bugfind_data/work/kernels/tar_pax.post/Crate.lean:26:70: error: failed to synthesize\n Decidable is_extension_header\n\nHint: Additio" + } + ], + "note": "Aeneas (6c2788d) emitted ill-typed Lean for `!b` / `a || b` chains bound to a bool (Prop vs Bool, `failed to synthesize Decidable`); the post kernel of tar_pax was rewritten with explicit if/else (same semantics) and then translates." + }, + "total_items_kept_now": 226, + "total_real_bug_pairs": 27, + "notes": "Mutants are clustered by source function (21 functions) and are not independent samples; the crate-clustered bootstrap treats the function as the cluster. Advisory items are clustered by crate." +} \ No newline at end of file diff --git a/code/bugfind/bench/items/advisory_attempts.jsonl b/code/bugfind/bench/items/advisory_attempts.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..5a2a5a6b2a5ec488512a6602b0980d627023e81d --- /dev/null +++ b/code/bugfind/bench/items/advisory_attempts.jsonl @@ -0,0 +1,94 @@ +{"adv_id": "RUSTSEC-2017-0004", "crate": "base64", "date": "2017-05-03", "url": "https://github.com/alicemaz/rust-base64/commit/24ead980daf11ba563e4fb2516187a56a71ad319", "title": "Integer overflow leads to heap-based buffer overflow in encode_config_buf", "categories": [], "affected_functions": [], "bug_class": ["overflow"], "pre_version": "0.5.1", "post_version": "0.5.2", "stage": "diff_safe", "changed_files": ["src/lib.rs"], "changed_lines": 180, "unsafe_in_changed_files": 10, "changed_functions": ["encode_config", "encode_config_buf", "encoded_size"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Nested borrows are not supported yet", "lean_lines": null, "seconds": 2.3, "item_id": "adv-RUSTSEC-2017-0004", "kind": "advisory", "labels": {"buggy": "base64@0.5.1", "reference": "base64@0.5.2"}} +{"adv_id": "RUSTSEC-2018-0004", "crate": "claxon", "date": "2018-08-25", "url": "https://github.com/ruuda/claxon/commit/8f28ec275e412dd3af4f3cda460605512faf332c", "title": "Malicious input could cause uninitialized memory to be exposed", "categories": [], "affected_functions": [], "bug_class": ["logic"], "pre_version": "0.3.1", "post_version": "0.3.2", "stage": "strict_safe", "changed_files": ["src/subframe.rs"], "changed_lines": 25, "unsafe_in_changed_files": 0, "changed_functions": ["subframe::decode_residual"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Early returns inside of loops are not supported yet", "lean_lines": null, "seconds": 3.6, "item_id": "adv-RUSTSEC-2018-0004", "kind": "advisory", "labels": {"buggy": "claxon@0.3.1", "reference": "claxon@0.3.2"}} +{"adv_id": "RUSTSEC-2018-0007", "crate": "trust-dns-proto", "date": "2018-10-09", "url": null, "title": "Stack overflow when parsing malicious DNS packet", "categories": [], "affected_functions": [], "bug_class": ["overflow", "dos_loop_or_recursion", "logic"], "pre_version": "0.4.2", "post_version": "0.4.3", "stage": "strict_safe", "changed_files": ["src/rr/domain/name.rs"], "changed_lines": 11, "unsafe_in_changed_files": 0, "changed_functions": ["rr::domain::name::read"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error: failed to select a version for the requirement `ring = \"^0.12\"`", "lean_lines": null, "seconds": 1.2, "item_id": "adv-RUSTSEC-2018-0007", "kind": "advisory", "labels": {"buggy": "trust-dns-proto@0.4.2", "reference": "trust-dns-proto@0.4.3"}} +{"adv_id": "RUSTSEC-2019-0004", "crate": "libp2p-core", "date": "2019-05-15", "url": null, "title": "Failure to properly verify ed25519 signatures makes any signature valid", "categories": [], "affected_functions": [], "bug_class": ["other"], "pre_version": "0.7.0", "post_version": "0.7.1", "stage": "strict_safe", "changed_files": ["src/identity/ed25519.rs"], "changed_lines": 22, "unsafe_in_changed_files": 0, "changed_functions": ["identity::ed25519::verify"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error: failed to select a version for the requirement `zeroize = \"^0.5\"`", "lean_lines": null, "seconds": 1.2, "item_id": "adv-RUSTSEC-2019-0004", "kind": "advisory", "labels": {"buggy": "libp2p-core@0.7.0", "reference": "libp2p-core@0.7.1"}} +{"adv_id": "RUSTSEC-2019-0007", "crate": "asn1_der", "date": "2019-06-13", "url": "https://github.com/KizzyCode/asn1_der/issues/1", "title": "Processing of maliciously crafted length fields causes memory allocation SIGABRTs", "categories": [], "affected_functions": [], "bug_class": ["other"], "pre_version": "0.6.1", "post_version": "0.6.2", "stage": "strict_safe", "changed_files": ["src/der/value.rs"], "changed_lines": 11, "unsafe_in_changed_files": 0, "changed_functions": ["der::value::deserialize"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": true, "translated": true, "error": null, "lean_lines": 132, "seconds": 7.7, "item_id": "adv-RUSTSEC-2019-0007", "kind": "advisory", "labels": {"buggy": "asn1_der@0.6.1", "reference": "asn1_der@0.6.2"}} +{"adv_id": "RUSTSEC-2020-0001", "crate": "trust-dns-server", "date": "2020-01-06", "url": "https://github.com/bluejekyll/trust-dns/issues/980", "title": "Stack overflow when resolving additional records from MX or SRV null targets", "categories": ["denial-of-service"], "affected_functions": [], "bug_class": ["overflow", "dos_loop_or_recursion"], "pre_version": "0.18.0", "post_version": "0.18.1", "stage": "strict_safe", "changed_files": ["src/store/file/authority.rs", "src/store/in_memory/authority.rs"], "changed_lines": 4, "unsafe_in_changed_files": 0, "changed_functions": ["store::file::authority::try_from_config", "store::in_memory::authority::inner_lookup_wildcard"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Returns inside of nested loops are not supported yet", "lean_lines": null, "seconds": 41.6, "item_id": "adv-RUSTSEC-2020-0001", "kind": "advisory", "labels": {"buggy": "trust-dns-server@0.18.0", "reference": "trust-dns-server@0.18.1"}} +{"adv_id": "RUSTSEC-2020-0008", "crate": "hyper", "date": "2020-03-19", "url": "https://github.com/hyperium/hyper/issues/1925", "title": "Flaw in hyper allows request smuggling by sending a body in GET requests", "categories": ["format-injection"], "affected_functions": [], "bug_class": ["logic"], "pre_version": "0.12.33", "post_version": "0.12.34", "stage": "diff_safe", "changed_files": ["src/lib.rs", "src/proto/h1/role.rs"], "changed_lines": 101, "unsafe_in_changed_files": 14, "changed_functions": ["proto::h1::role::set_length"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Unimplemented", "lean_lines": null, "seconds": 13.9, "item_id": "adv-RUSTSEC-2020-0008", "kind": "advisory", "labels": {"buggy": "hyper@0.12.33", "reference": "hyper@0.12.34"}} +{"adv_id": "RUSTSEC-2020-0019", "crate": "tokio-rustls", "date": "2020-05-19", "url": "https://github.com/tokio-rs/tls/pull/14", "title": "tokio-rustls reads may cause excessive memory usage", "categories": ["denial-of-service"], "affected_functions": [], "bug_class": ["other"], "pre_version": "0.12.2", "post_version": "0.12.3", "stage": "strict_safe", "changed_files": ["src/common/mod.rs"], "changed_lines": 11, "unsafe_in_changed_files": 0, "changed_functions": ["common::handshake", "common::poll_read"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Breaks to outer loops are not supported yet", "lean_lines": null, "seconds": 13.3, "item_id": "adv-RUSTSEC-2020-0019", "kind": "advisory", "labels": {"buggy": "tokio-rustls@0.12.2", "reference": "tokio-rustls@0.12.3"}} +{"adv_id": "RUSTSEC-2020-0024", "crate": "tough", "date": "2020-07-09", "url": "https://github.com/awslabs/tough/commit/c1c950682d765ebc661f70381f947bc28b8b058c", "title": "Improper uniqueness verification of signature threshold", "categories": [], "affected_functions": [], "bug_class": ["other"], "pre_version": "0.7.0", "post_version": "0.7.1", "stage": "strict_safe", "changed_files": ["src/schema/verify.rs"], "changed_lines": 31, "unsafe_in_changed_files": 0, "changed_functions": ["schema::verify::verify_role"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "start function not in generated Lean", "lean_lines": 23, "seconds": 92.9, "item_id": "adv-RUSTSEC-2020-0024", "kind": "advisory", "labels": {"buggy": "tough@0.7.0", "reference": "tough@0.7.1"}} +{"adv_id": "RUSTSEC-2020-0031", "crate": "tiny_http", "date": "2020-06-16", "url": "https://github.com/tiny-http/tiny-http/issues/173", "title": "HTTP Request smuggling through malformed Transfer Encoding headers", "categories": [], "affected_functions": [], "bug_class": ["logic"], "pre_version": "0.6.2", "post_version": "0.6.3", "stage": "strict_safe", "changed_files": ["src/common.rs"], "changed_lines": 23, "unsafe_in_changed_files": 0, "changed_functions": ["common::from_str"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "start function not in generated Lean", "lean_lines": 23, "seconds": 19.9, "item_id": "adv-RUSTSEC-2020-0031", "kind": "advisory", "labels": {"buggy": "tiny_http@0.6.2", "reference": "tiny_http@0.6.3"}} +{"adv_id": "RUSTSEC-2020-0042", "crate": "stack", "date": "2020-09-24", "url": "https://github.com/arcnmx/stack-rs/issues/4", "title": "Missing check in ArrayVec leads to out-of-bounds write.", "categories": [], "affected_functions": [], "bug_class": ["panic"], "pre_version": "0.3.0", "post_version": "0.3.1", "stage": "diff_safe", "changed_files": ["src/vector.rs"], "changed_lines": 3, "unsafe_in_changed_files": 22, "changed_functions": ["vector::insert"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Raw ptr casts are only supported between pointers to literal types; found: cast<*mut Clause0_Item, *const Clause0_Item>", "lean_lines": null, "seconds": 4.3, "item_id": "adv-RUSTSEC-2020-0042", "kind": "advisory", "labels": {"buggy": "stack@0.3.0", "reference": "stack@0.3.1"}} +{"adv_id": "RUSTSEC-2020-0060", "crate": "futures-task", "date": "2020-09-04", "url": "https://github.com/rust-lang/futures-rs/pull/2206", "title": "futures_task::waker may cause a use-after-free if used on a type that isn't 'static", "categories": ["code-execution", "memory-corruption"], "affected_functions": ["futures_task::waker"], "bug_class": ["other"], "pre_version": "0.3.5", "post_version": "0.3.6", "stage": "diff_safe", "changed_files": ["src/lib.rs", "src/waker.rs"], "changed_lines": 9, "unsafe_in_changed_files": 12, "changed_functions": ["waker::waker"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Detected groups of mixed mutually recursive definitions (such as a type mutually recursive with a function, or a function mutually recursive with a trait implementation):", "lean_lines": null, "seconds": 1.4, "item_id": "adv-RUSTSEC-2020-0060", "kind": "advisory", "labels": {"buggy": "futures-task@0.3.5", "reference": "futures-task@0.3.6"}} +{"adv_id": "RUSTSEC-2020-0069", "crate": "lettre", "date": "2020-11-11", "url": "https://github.com/lettre/lettre/pull/508/commits/bbe7cc5381c5380b54fb8bbb4f77a3725917ff0b", "title": "Argument injection in sendmail transport", "categories": ["code-execution", "file-disclosure"], "affected_functions": ["lettre::sendmail::SendmailTransport::send", "lettre::transport::sendmail::SendmailTransport::send", "lettre::transport::sendmail::SendmailTransport::send_raw"], "bug_class": ["logic"], "pre_version": "0.7.0", "post_version": "0.7.1", "stage": "strict_safe", "changed_files": ["src/sendmail/mod.rs"], "changed_lines": 1, "unsafe_in_changed_files": 0, "changed_functions": ["sendmail::send"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error: failed to select a version for the requirement `security-framework = \"^0.1.9\"`", "lean_lines": null, "seconds": 2.4, "item_id": "adv-RUSTSEC-2020-0069", "kind": "advisory", "labels": {"buggy": "lettre@0.7.0", "reference": "lettre@0.7.1"}} +{"adv_id": "RUSTSEC-2020-0103", "crate": "autorand", "date": "2020-12-31", "url": "https://github.com/mersinvald/autorand-rs/issues/5", "title": "`impl Random` on arrays can lead to dropping uninitialized memory", "categories": ["memory-corruption"], "affected_functions": [], "bug_class": ["panic"], "pre_version": "0.1.1", "post_version": "0.2.3", "stage": "diff_safe", "changed_files": ["src/lib.rs"], "changed_lines": 170, "unsafe_in_changed_files": 2, "changed_functions": ["rand_iter", "rand_length_iter", "random"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": false, "translated": false, "error": "lean: 03/Crate.lean:2070:4: warning: declaration uses `sorry`\n/apps/development/rlhf/bugfind_data/work/translate/RUSTSEC-2020-0103/Crate.lean:2085:4: warning: declaration uses `sorry`\n/apps/development/rlhf/bugfind_data/work/translate/RUSTSEC-2020-0103/Crate.lean:2100:4: warning: declaration uses `sorry`\n", "lean_lines": 2407, "seconds": 14.8, "item_id": "adv-RUSTSEC-2020-0103", "kind": "advisory", "labels": {"buggy": "autorand@0.1.1", "reference": "autorand@0.2.3"}} +{"adv_id": "RUSTSEC-2021-0056", "crate": "openssl-src", "date": "2021-05-01", "url": "https://www.openssl.org/news/secadv/20210325.txt", "title": "CA certificate check bypass with X509_V_FLAG_X509_STRICT", "categories": ["crypto-failure"], "affected_functions": [], "bug_class": ["logic"], "pre_version": "111.14.0+1.1.1j", "post_version": "111.15.0+1.1.1k", "stage": "strict_safe", "changed_files": ["src/lib.rs"], "changed_lines": 62, "unsafe_in_changed_files": 0, "changed_functions": ["build", "cmd_make"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Unimplemented", "lean_lines": null, "seconds": 20.4, "item_id": "adv-RUSTSEC-2021-0056", "kind": "advisory", "labels": {"buggy": "openssl-src@111.14.0+1.1.1j", "reference": "openssl-src@111.15.0+1.1.1k"}} +{"adv_id": "RUSTSEC-2021-0066", "crate": "evm-core", "date": "2021-05-11", "url": "https://github.com/rust-blockchain/evm", "title": "Denial of service on EVM execution due to memory over-allocation", "categories": ["denial-of-service"], "affected_functions": [], "bug_class": ["other"], "pre_version": "0.21.0", "post_version": "0.21.1", "stage": "strict_safe", "changed_files": ["src/memory.rs"], "changed_lines": 4, "unsafe_in_changed_files": 0, "changed_functions": ["memory::set"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error: use of deprecated associated function `core::num::::max_value`: replaced by the `MAX` associated constant on this type", "lean_lines": null, "seconds": 20.6, "item_id": "adv-RUSTSEC-2021-0066", "kind": "advisory", "labels": {"buggy": "evm-core@0.21.0", "reference": "evm-core@0.21.1"}} +{"adv_id": "RUSTSEC-2021-0069", "crate": "lettre", "date": "2021-05-22", "url": "https://github.com/lettre/lettre/pull/627/commits/93458d01fed0ec81c0e7b4e98e6f35961356fae2", "title": "SMTP command injection in body", "categories": ["format-injection"], "affected_functions": ["lettre::smtp::SmtpTransport::send", "lettre::transport::smtp::SmtpTransport::send", "lettre::transport::smtp::SmtpTransport::send_raw"], "bug_class": ["other"], "pre_version": "0.9.5", "post_version": "0.9.6", "stage": "strict_safe", "changed_files": ["src/lib.rs", "src/smtp/client/mod.rs"], "changed_lines": 15, "unsafe_in_changed_files": 0, "changed_functions": ["smtp::client::encode"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error: failed to run custom build command for `openssl-sys v0.9.58`", "lean_lines": null, "seconds": 1.6, "item_id": "adv-RUSTSEC-2021-0069", "kind": "advisory", "labels": {"buggy": "lettre@0.9.5", "reference": "lettre@0.9.6"}} +{"adv_id": "RUSTSEC-2021-0073", "crate": "prost-types", "date": "2021-07-08", "url": "https://github.com/tokio-rs/prost/issues/438", "title": "Conversion from `prost_types::Timestamp` to `SystemTime` can cause an overflow and panic ", "categories": ["denial-of-service"], "affected_functions": ["prost_types::Timestamp::Into"], "bug_class": ["overflow", "panic"], "pre_version": "0.7.0", "post_version": "0.8.0", "stage": "strict_safe", "changed_files": ["src/lib.rs"], "changed_lines": 284, "unsafe_in_changed_files": 0, "changed_functions": ["from", "normalize"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": false, "translated": false, "error": "lean: USTSEC-2021-0073/Crate.lean:12427:4: error: `prost_types.P.Insts.CoreOpsFunctionFnOnceTupleTT.call_once` has already been declared\n/apps/development/rlhf/bugfind_data/work/translate/RUSTSEC-2021-0073/Crate.lean:12434:4: error: maximum number of errors (100; from option `maxErrors`) reached, exiting\n", "lean_lines": 29361, "seconds": 88.3, "item_id": "adv-RUSTSEC-2021-0073", "kind": "advisory", "labels": {"buggy": "prost-types@0.7.0", "reference": "prost-types@0.8.0"}} +{"adv_id": "RUSTSEC-2021-0103", "crate": "molecule", "date": "2021-07-30", "url": "https://github.com/nervosnetwork/molecule/pull/49", "title": "Partial read is incorrect in molecule", "categories": [], "affected_functions": [], "bug_class": ["logic"], "pre_version": "0.7.1", "post_version": "0.7.2", "stage": "strict_safe", "changed_files": ["src/prelude.rs"], "changed_lines": 1, "unsafe_in_changed_files": 0, "changed_functions": ["prelude::as_builder"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Unexpected", "lean_lines": null, "seconds": 1.3, "item_id": "adv-RUSTSEC-2021-0103", "kind": "advisory", "labels": {"buggy": "molecule@0.7.1", "reference": "molecule@0.7.2"}} +{"adv_id": "RUSTSEC-2021-0119", "crate": "nix", "date": "2021-09-27", "url": "https://github.com/nix-rust/nix/issues/1541", "title": "Out-of-bounds write in nix::unistd::getgrouplist", "categories": ["memory-corruption"], "affected_functions": ["nix::unistd::getgrouplist"], "bug_class": ["panic"], "pre_version": "0.20.1", "post_version": "0.20.2", "stage": "diff_safe", "changed_files": ["src/unistd.rs"], "changed_lines": 4, "unsafe_in_changed_files": 188, "changed_functions": ["unistd::getgrouplist"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error: rule #6 of macro `libc_enum` is never used", "lean_lines": null, "seconds": 4.8, "item_id": "adv-RUSTSEC-2021-0119", "kind": "advisory", "labels": {"buggy": "nix@0.20.1", "reference": "nix@0.20.2"}} +{"adv_id": "RUSTSEC-2021-0129", "crate": "openssl-src", "date": "2021-12-14", "url": "https://www.openssl.org/news/secadv/20211214.txt", "title": "Invalid handling of `X509_verify_cert()` internal errors in libssl", "categories": ["denial-of-service"], "affected_functions": [], "bug_class": ["dos_loop_or_recursion", "logic"], "pre_version": "300.0.3+3.0.0", "post_version": "300.0.4+3.0.1", "stage": "strict_safe", "changed_files": ["src/lib.rs"], "changed_lines": 1, "unsafe_in_changed_files": 0, "changed_functions": ["build"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Unimplemented", "lean_lines": null, "seconds": 23.2, "item_id": "adv-RUSTSEC-2021-0129", "kind": "advisory", "labels": {"buggy": "openssl-src@300.0.3+3.0.0", "reference": "openssl-src@300.0.4+3.0.1"}} +{"adv_id": "RUSTSEC-2021-0143", "crate": "kamadak-exif", "date": "2021-01-04", "url": "https://github.com/kamadak/exif-rs/commit/1b05eab57e484cd7d576d4357b9cda7fdc57df8c", "title": "kamadak-exif DoS with untrusted PNG data", "categories": ["denial-of-service"], "affected_functions": ["kamadak_exif::Reader::read_from_container"], "bug_class": ["dos_loop_or_recursion"], "pre_version": "0.5.2", "post_version": "0.5.3", "stage": "strict_safe", "changed_files": ["src/png.rs", "src/util.rs"], "changed_lines": 40, "unsafe_in_changed_files": 0, "changed_functions": ["png::get_exif_attr_sub", "util::discard_exact"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Dynamic trait types are not supported yet", "lean_lines": null, "seconds": 5.0, "item_id": "adv-RUSTSEC-2021-0143", "kind": "advisory", "labels": {"buggy": "kamadak-exif@0.5.2", "reference": "kamadak-exif@0.5.3"}} +{"adv_id": "RUSTSEC-2021-0158", "crate": "ammonia", "date": "2021-10-10", "url": "https://github.com/rust-ammonia/ammonia/pull/261", "title": "XSS in ammonia via SVG `animateMotion`, `animateTransform`, and/or `animateColor` tags", "categories": ["format-injection"], "affected_functions": [], "bug_class": ["other"], "pre_version": "4.1.6", "post_version": "4.1.7", "stage": "strict_safe", "changed_files": ["src/style.rs"], "changed_lines": 9, "unsafe_in_changed_files": 0, "changed_functions": ["style::parse_value"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "start function not in generated Lean", "lean_lines": 23, "seconds": 53.5, "item_id": "adv-RUSTSEC-2021-0158", "kind": "advisory", "labels": {"buggy": "ammonia@4.1.6", "reference": "ammonia@4.1.7"}} +{"adv_id": "RUSTSEC-2022-0006", "crate": "thread_local", "date": "2022-01-23", "url": "https://github.com/Amanieu/thread_local-rs/issues/33", "title": "Data race in `Iter` and `IterMut`", "categories": ["memory-corruption"], "affected_functions": [], "bug_class": ["other"], "pre_version": "1.1.3", "post_version": "1.1.4", "stage": "diff_safe", "changed_files": ["src/lib.rs"], "changed_lines": 2, "unsafe_in_changed_files": 38, "changed_functions": ["next"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Returns inside of nested loops are not supported yet", "lean_lines": null, "seconds": 3.6, "item_id": "adv-RUSTSEC-2022-0006", "kind": "advisory", "labels": {"buggy": "thread_local@1.1.3", "reference": "thread_local@1.1.4"}} +{"adv_id": "RUSTSEC-2022-0018", "crate": "totp-rs", "date": "2022-05-09", "url": "https://github.com/constantoine/totp-rs/issues/13", "title": "Timing attack", "categories": ["crypto-failure"], "affected_functions": ["totp_rs::TOTP::check"], "bug_class": ["other"], "pre_version": "1.0.0", "post_version": "1.1.0", "stage": "strict_safe", "changed_files": ["src/lib.rs"], "changed_lines": 67, "unsafe_in_changed_files": 0, "changed_functions": ["check", "sign"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon timeout", "lean_lines": null, "seconds": 300.1, "item_id": "adv-RUSTSEC-2022-0018", "kind": "advisory", "labels": {"buggy": "totp-rs@1.0.0", "reference": "totp-rs@1.1.0"}} +{"adv_id": "RUSTSEC-2022-0025", "crate": "openssl-src", "date": "2022-05-03", "url": "https://www.openssl.org/news/secadv/20220503.txt", "title": "Resource leakage when decoding certificates and keys", "categories": ["denial-of-service"], "affected_functions": [], "bug_class": ["logic"], "pre_version": "300.0.5+3.0.2", "post_version": "300.0.6+3.0.3", "stage": "strict_safe", "changed_files": ["src/lib.rs"], "changed_lines": 5, "unsafe_in_changed_files": 0, "changed_functions": ["build"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Unimplemented", "lean_lines": null, "seconds": 24.2, "item_id": "adv-RUSTSEC-2022-0025", "kind": "advisory", "labels": {"buggy": "openssl-src@300.0.5+3.0.2", "reference": "openssl-src@300.0.6+3.0.3"}} +{"adv_id": "RUSTSEC-2022-0028", "crate": "neon", "date": "2022-05-22", "url": "https://github.com/neon-bindings/neon/issues/896", "title": "Use after free in Neon external buffers", "categories": ["memory-corruption", "memory-exposure"], "affected_functions": ["neon::types::JsArrayBuffer::external", "neon::types::JsBuffer::external"], "bug_class": ["panic", "logic"], "pre_version": "0.10.0", "post_version": "0.10.1", "stage": "diff_safe", "changed_files": ["src/types/buffer/types.rs"], "changed_lines": 4, "unsafe_in_changed_files": 48, "changed_functions": ["types::buffer::types::external"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "start function not in generated Lean", "lean_lines": 23, "seconds": 73.3, "item_id": "adv-RUSTSEC-2022-0028", "kind": "advisory", "labels": {"buggy": "neon@0.10.0", "reference": "neon@0.10.1"}} +{"adv_id": "RUSTSEC-2022-0059", "crate": "openssl-src", "date": "2022-10-11", "url": "https://www.openssl.org/news/secadv/20221011.txt", "title": "Using a Custom Cipher with `NID_undef` may lead to NULL encryption", "categories": ["crypto-failure"], "affected_functions": [], "bug_class": ["logic"], "pre_version": "300.0.9+3.0.5", "post_version": "300.0.11+3.0.7", "stage": "strict_safe", "changed_files": ["src/lib.rs"], "changed_lines": 7, "unsafe_in_changed_files": 0, "changed_functions": ["build"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Unimplemented", "lean_lines": null, "seconds": 25.0, "item_id": "adv-RUSTSEC-2022-0059", "kind": "advisory", "labels": {"buggy": "openssl-src@300.0.9+3.0.5", "reference": "openssl-src@300.0.11+3.0.7"}} +{"adv_id": "RUSTSEC-2022-0062", "crate": "matrix-sdk", "date": "2022-10-24", "url": "https://github.com/matrix-org/matrix-rust-sdk/issues/1110", "title": "matrix-sdk 0.6.0 logs access tokens", "categories": [], "affected_functions": [], "bug_class": ["other"], "pre_version": "0.6.1", "post_version": "0.6.2", "stage": "strict_safe", "changed_files": ["src/config/sync.rs"], "changed_lines": 1, "unsafe_in_changed_files": 0, "changed_functions": ["config::sync::fmt"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "start function not in generated Lean", "lean_lines": 23, "seconds": 278.1, "item_id": "adv-RUSTSEC-2022-0062", "kind": "advisory", "labels": {"buggy": "matrix-sdk@0.6.1", "reference": "matrix-sdk@0.6.2"}} +{"adv_id": "RUSTSEC-2022-0088", "crate": "tauri", "date": "2022-08-07", "url": "https://github.com/tauri-apps/tauri/issues/4882", "title": "`tauri`'s `readDir` endpoint allows possible enumeration outside of filesystem scope", "categories": ["privilege-escalation"], "affected_functions": [], "bug_class": ["logic"], "pre_version": "1.0.5", "post_version": "1.0.6", "stage": "diff_safe", "changed_files": ["src/api/dir.rs", "src/api/file.rs", "src/endpoints/file_system.rs"], "changed_lines": 58, "unsafe_in_changed_files": 4, "changed_functions": ["api::dir::is_dir", "api::dir::read_dir", "endpoints::file_system::read_dir"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error: failed to run custom build command for `gdk-sys v0.15.1`", "lean_lines": null, "seconds": 23.7, "item_id": "adv-RUSTSEC-2022-0088", "kind": "advisory", "labels": {"buggy": "tauri@1.0.5", "reference": "tauri@1.0.6"}} +{"adv_id": "RUSTSEC-2023-0001", "crate": "tokio", "date": "2023-01-04", "url": "https://github.com/tokio-rs/tokio/pull/5336", "title": "reject_remote_clients Configuration corruption", "categories": [], "affected_functions": [], "bug_class": ["other"], "pre_version": "1.18.3", "post_version": "1.18.4", "stage": "diff_safe", "changed_files": ["src/net/windows/named_pipe.rs"], "changed_lines": 54, "unsafe_in_changed_files": 34, "changed_functions": ["net::windows::named_pipe::named_pipe_info", "net::windows::named_pipe::pipe_mode"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "start function not in generated Lean", "lean_lines": 4316, "seconds": 9.6, "item_id": "adv-RUSTSEC-2023-0001", "kind": "advisory", "labels": {"buggy": "tokio@1.18.3", "reference": "tokio@1.18.4"}} +{"adv_id": "RUSTSEC-2023-0004", "crate": "bzip2", "date": "2023-01-09", "url": "https://github.com/alexcrichton/bzip2-rs/pull/86", "title": "bzip2 Denial of Service (DoS)", "categories": ["denial-of-service"], "affected_functions": [], "bug_class": ["dos_loop_or_recursion"], "pre_version": "0.4.3", "post_version": "0.4.4", "stage": "diff_safe", "changed_files": ["src/mem.rs"], "changed_lines": 8, "unsafe_in_changed_files": 24, "changed_functions": ["mem::compress", "mem::decompress"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Arrow types are not supported yet", "lean_lines": null, "seconds": 4.9, "item_id": "adv-RUSTSEC-2023-0004", "kind": "advisory", "labels": {"buggy": "bzip2@0.4.3", "reference": "bzip2@0.4.4"}} +{"adv_id": "RUSTSEC-2023-0006", "crate": "openssl-src", "date": "2023-02-07", "url": "https://www.openssl.org/news/secadv/20230207.txt", "title": "X.400 address type confusion in X.509 `GeneralName`", "categories": ["denial-of-service", "memory-exposure"], "affected_functions": [], "bug_class": ["logic"], "pre_version": "111.24.0+1.1.1s", "post_version": "111.25.0+1.1.1t", "stage": "strict_safe", "changed_files": ["src/lib.rs"], "changed_lines": 1, "unsafe_in_changed_files": 0, "changed_functions": ["build"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Unimplemented", "lean_lines": null, "seconds": 22.2, "item_id": "adv-RUSTSEC-2023-0006", "kind": "advisory", "labels": {"buggy": "openssl-src@111.24.0+1.1.1s", "reference": "openssl-src@111.25.0+1.1.1t"}} +{"adv_id": "RUSTSEC-2023-0030", "crate": "versionize", "date": "2023-03-24", "url": "https://github.com/firecracker-microvm/versionize/pull/53", "title": "`Versionize::deserialize` implementation for `FamStructWrapper` is lacking bound checks, potentially leading to out of bounds memory accesses ", "categories": ["memory-exposure"], "affected_functions": [], "bug_class": ["overflow", "panic"], "pre_version": "0.1.9", "post_version": "0.1.10", "stage": "diff_safe", "changed_files": ["src/primitives.rs"], "changed_lines": 14, "unsafe_in_changed_files": 2, "changed_functions": ["primitives::deserialize"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "start function not in generated Lean", "lean_lines": 23, "seconds": 28.4, "item_id": "adv-RUSTSEC-2023-0030", "kind": "advisory", "labels": {"buggy": "versionize@0.1.9", "reference": "versionize@0.1.10"}} +{"adv_id": "RUSTSEC-2023-0038", "crate": "sequoia-openpgp", "date": "2023-05-16", "url": "https://lists.sequoia-pgp.org/hyperkitty/list/announce@lists.sequoia-pgp.org/thread/SN2E3QRT4DMQ5JNEK6VIN6DJ5SH766DI/", "title": "Out-of-bounds array access leads to panic", "categories": ["denial-of-service"], "affected_functions": [], "bug_class": ["panic"], "pre_version": "1.1.0", "post_version": "1.1.1", "stage": "diff_safe", "changed_files": ["src/armor.rs", "src/parse.rs", "src/parse/hashed_reader.rs", "src/parse/map.rs", "src/parse/stream.rs"], "changed_lines": 130, "unsafe_in_changed_files": 4, "changed_functions": ["parse::hashed_reader::hash_update_csf", "parse::map::new", "parse::stream::push_signature"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error: failed to run custom build command for `clang-sys v1.1.1`", "lean_lines": null, "seconds": 10.3, "item_id": "adv-RUSTSEC-2023-0038", "kind": "advisory", "labels": {"buggy": "sequoia-openpgp@1.1.0", "reference": "sequoia-openpgp@1.1.1"}} +{"adv_id": "RUSTSEC-2023-0039", "crate": "buffered-reader", "date": "2023-05-16", "url": "https://lists.sequoia-pgp.org/hyperkitty/list/announce@lists.sequoia-pgp.org/thread/SN2E3QRT4DMQ5JNEK6VIN6DJ5SH766DI/", "title": "Out-of-bounds array access leads to panic", "categories": ["denial-of-service"], "affected_functions": [], "bug_class": ["panic"], "pre_version": "1.0.1", "post_version": "1.0.2", "stage": "strict_safe", "changed_files": ["src/generic.rs"], "changed_lines": 37, "unsafe_in_changed_files": 0, "changed_functions": ["generic::data_helper"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Dynamic trait types are not supported yet", "lean_lines": null, "seconds": 12.6, "item_id": "adv-RUSTSEC-2023-0039", "kind": "advisory", "labels": {"buggy": "buffered-reader@1.0.1", "reference": "buffered-reader@1.0.2"}} +{"adv_id": "RUSTSEC-2023-0041", "crate": "trust-dns-server", "date": "2023-06-01", "url": "https://github.com/bluejekyll/trust-dns/pull/1952", "title": "Remote Attackers can cause Denial-of-Service (packet loops) with crafted DNS packets", "categories": ["denial-of-service"], "affected_functions": [], "bug_class": ["other"], "pre_version": "0.22.0", "post_version": "0.22.1", "stage": "diff_safe", "changed_files": ["src/server/server_future.rs"], "changed_lines": 7, "unsafe_in_changed_files": 2, "changed_functions": ["server::server_future::handle_request"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Found type error in the output of charon", "lean_lines": null, "seconds": 43.7, "item_id": "adv-RUSTSEC-2023-0041", "kind": "advisory", "labels": {"buggy": "trust-dns-server@0.22.0", "reference": "trust-dns-server@0.22.1"}} +{"adv_id": "RUSTSEC-2023-0065", "crate": "tungstenite", "date": "2023-09-25", "url": "https://github.com/snapview/tungstenite-rs/issues/376", "title": "Tungstenite allows remote attackers to cause a denial of service", "categories": ["denial-of-service"], "affected_functions": [], "bug_class": ["logic"], "pre_version": "0.20.0", "post_version": "0.20.1", "stage": "strict_safe", "changed_files": ["src/error.rs", "src/handshake/machine.rs"], "changed_lines": 88, "unsafe_in_changed_files": 0, "changed_functions": ["handshake::machine::single_round", "handshake::machine::start_read", "handshake::machine::try_parse"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] The input arguments don't have the proper type", "lean_lines": null, "seconds": 13.2, "item_id": "adv-RUSTSEC-2023-0065", "kind": "advisory", "labels": {"buggy": "tungstenite@0.20.0", "reference": "tungstenite@0.20.1"}} +{"adv_id": "RUSTSEC-2023-0073", "crate": "candid", "date": "2023-12-08", "url": "https://github.com/dfinity/candid/pull/478", "title": "Infinite decoding loop through specially crafted payload", "categories": ["denial-of-service"], "affected_functions": ["candid::Decode"], "bug_class": ["logic"], "pre_version": "0.9.9", "post_version": "0.9.10", "stage": "diff_safe", "changed_files": ["src/de.rs", "src/types/value.rs"], "changed_lines": 9, "unsafe_in_changed_files": 2, "changed_functions": ["de::deserialize_empty", "types::value::visit_byte_buf"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "start function not in generated Lean", "lean_lines": 377, "seconds": 144.1, "item_id": "adv-RUSTSEC-2023-0073", "kind": "advisory", "labels": {"buggy": "candid@0.9.9", "reference": "candid@0.9.10"}} +{"adv_id": "RUSTSEC-2023-0080", "crate": "transpose", "date": "2023-12-18", "url": "https://github.com/ejmahler/transpose/issues/11", "title": "Buffer overflow due to integer overflow in `transpose`", "categories": ["memory-corruption"], "affected_functions": ["transpose::transpose"], "bug_class": ["overflow", "panic"], "pre_version": "0.2.2", "post_version": "0.2.3", "stage": "diff_safe", "changed_files": ["src/in_place.rs", "src/out_of_place.rs"], "changed_lines": 16, "unsafe_in_changed_files": 24, "changed_functions": ["in_place::multiplicative_inverse", "in_place::transpose_inplace", "out_of_place::transpose"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Unimplemented", "lean_lines": null, "seconds": 20.0, "item_id": "adv-RUSTSEC-2023-0080", "kind": "advisory", "labels": {"buggy": "transpose@0.2.2", "reference": "transpose@0.2.3"}} +{"adv_id": "RUSTSEC-2023-0082", "crate": "phonenumber", "date": "2023-09-19", "url": "https://github.com/whisperfish/rust-phonenumber/commit/2dd44be94539c051b4dee55d1d9d349bd7bedde6", "title": "phonenumber: panic on parsing crafted RF3966 phonenumber inputs ", "categories": ["denial-of-service"], "affected_functions": ["phonenumber::parse"], "bug_class": ["panic", "logic"], "pre_version": "0.2.4+8.11.3", "post_version": "0.2.5+8.11.3", "stage": "strict_safe", "changed_files": ["src/parser/mod.rs", "src/parser/rfc3966.rs"], "changed_lines": 13, "unsafe_in_changed_files": 0, "changed_functions": ["parser::rfc3966::phone_number"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error[E0308]: mismatched types", "lean_lines": null, "seconds": 15.4, "item_id": "adv-RUSTSEC-2023-0082", "kind": "advisory", "labels": {"buggy": "phonenumber@0.2.4+8.11.3", "reference": "phonenumber@0.2.5+8.11.3"}} +{"adv_id": "RUSTSEC-2023-0095", "crate": "odoh-rs", "date": "2023-08-03", "url": "https://github.com/cloudflare/odoh-rs/pull/28", "title": "Invalid Slice Split Results in Server Panic", "categories": ["denial-of-service"], "affected_functions": [], "bug_class": ["panic", "logic"], "pre_version": "1.0.1", "post_version": "1.0.2", "stage": "strict_safe", "changed_files": ["src/protocol.rs"], "changed_lines": 22, "unsafe_in_changed_files": 0, "changed_functions": ["protocol::decrypt_query"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error[E0635]: unknown feature `proc_macro_span_shrink`", "lean_lines": null, "seconds": 2.2, "item_id": "adv-RUSTSEC-2023-0095", "kind": "advisory", "labels": {"buggy": "odoh-rs@1.0.1", "reference": "odoh-rs@1.0.2"}} +{"adv_id": "RUSTSEC-2023-0096", "crate": "aes-gcm", "date": "2023-11-22", "url": "https://github.com/RustCrypto/AEADs/pull/551", "title": "Plaintext exposed in decrypt_in_place_detached even on tag verification failure", "categories": ["crypto-failure"], "affected_functions": ["aes_gcm::AeadInPlace::decrypt_in_place_detached", "aes_gcm::AesGcm::decrypt_in_place_detached"], "bug_class": ["other"], "pre_version": "0.10.2", "post_version": "0.10.3", "stage": "strict_safe", "changed_files": ["src/lib.rs"], "changed_lines": 2, "unsafe_in_changed_files": 0, "changed_functions": ["decrypt_in_place_detached"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": false, "translated": false, "error": "lean: 96/Crate.lean:4743:4: warning: declaration uses `sorry`\n/apps/development/rlhf/bugfind_data/work/translate/RUSTSEC-2023-0096/Crate.lean:4795:2: warning: declaration uses `sorry`\n/apps/development/rlhf/bugfind_data/work/translate/RUSTSEC-2023-0096/Crate.lean:4826:2: warning: declaration uses `sorry`\n", "lean_lines": 4894, "seconds": 39.2, "item_id": "adv-RUSTSEC-2023-0096", "kind": "advisory", "labels": {"buggy": "aes-gcm@0.10.2", "reference": "aes-gcm@0.10.3"}} +{"adv_id": "RUSTSEC-2024-0008", "crate": "trillium-client", "date": "2024-01-23", "url": "https://github.com/trillium-rs/trillium/commit/16a42b3f8378a3fa4e61ece3e3e37e6a530df51d", "title": "Improper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Request/Response Splitting')", "categories": [], "affected_functions": [], "bug_class": ["logic"], "pre_version": "0.5.3", "post_version": "0.5.4", "stage": "strict_safe", "changed_files": ["src/conn.rs"], "changed_lines": 17, "unsafe_in_changed_files": 0, "changed_functions": ["conn::build_head"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error: unnecessary qualification", "lean_lines": null, "seconds": 13.3, "item_id": "adv-RUSTSEC-2024-0008", "kind": "advisory", "labels": {"buggy": "trillium-client@0.5.3", "reference": "trillium-client@0.5.4"}} +{"adv_id": "RUSTSEC-2024-0011", "crate": "snow", "date": "2024-01-23", "url": "https://github.com/mcginty/snow/commit/12e8ae55547ae297d5f70599e5c884ea891303eb", "title": "Unauthenticated Nonce Increment in snow", "categories": ["crypto-failure", "denial-of-service"], "affected_functions": [], "bug_class": ["other"], "pre_version": "0.9.4", "post_version": "0.9.5", "stage": "strict_safe", "changed_files": ["src/cipherstate.rs", "src/resolvers/default.rs"], "changed_lines": 11, "unsafe_in_changed_files": 0, "changed_functions": ["cipherstate::decrypt_ad"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error[E0635]: unknown feature `stdsimd`", "lean_lines": null, "seconds": 7.9, "item_id": "adv-RUSTSEC-2024-0011", "kind": "advisory", "labels": {"buggy": "snow@0.9.4", "reference": "snow@0.9.5"}} +{"adv_id": "RUSTSEC-2024-0021", "crate": "eyre", "date": "2024-03-05", "url": "https://github.com/eyre-rs/eyre/issues/141", "title": "Parts of Report are dropped as the wrong type during downcast", "categories": ["memory-corruption"], "affected_functions": ["eyre::Report::downcast"], "bug_class": ["overflow", "logic"], "pre_version": "0.6.11", "post_version": "0.6.12", "stage": "diff_safe", "changed_files": ["src/error.rs", "src/lib.rs", "src/option.rs"], "changed_lines": 13, "unsafe_in_changed_files": 116, "changed_functions": ["error::context_drop_rest", "option::ok_or_eyre"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Early returns inside of loops are not supported yet", "lean_lines": null, "seconds": 3.7, "item_id": "adv-RUSTSEC-2024-0021", "kind": "advisory", "labels": {"buggy": "eyre@0.6.11", "reference": "eyre@0.6.12"}} +{"adv_id": "RUSTSEC-2024-0335", "crate": "gix-transport", "date": "2024-04-13", "url": "https://github.com/Byron/gitoxide/pull/1032", "title": "gix-transport indirect code execution via malicious username", "categories": ["code-execution"], "affected_functions": [], "bug_class": ["other"], "pre_version": "0.41.2", "post_version": "0.42.0", "stage": "strict_safe", "changed_files": ["src/client/blocking_io/file.rs", "src/client/blocking_io/ssh/mod.rs", "src/client/blocking_io/ssh/program_kind.rs", "src/client/blocking_io/ssh/tests.rs"], "changed_lines": 130, "unsafe_in_changed_files": 0, "changed_functions": ["client::blocking_io::file::configure", "client::blocking_io::ssh::connect", "client::blocking_io::ssh::program_kind::prepare_invocation"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "start function not in generated Lean", "lean_lines": 3110, "seconds": 23.5, "item_id": "adv-RUSTSEC-2024-0335", "kind": "advisory", "labels": {"buggy": "gix-transport@0.41.2", "reference": "gix-transport@0.42.0"}} +{"adv_id": "RUSTSEC-2024-0357", "crate": "openssl", "date": "2024-07-21", "url": "https://github.com/sfackler/rust-openssl/pull/2266", "title": "`MemBio::get_buf` has undefined behavior with empty buffers", "categories": [], "affected_functions": ["openssl::bio::MemBio::get_buf"], "bug_class": ["panic"], "pre_version": "0.10.65", "post_version": "0.10.66", "stage": "diff_safe", "changed_files": ["src/bio.rs"], "changed_lines": 17, "unsafe_in_changed_files": 14, "changed_functions": ["bio::BIO_new_mem_buf", "bio::get_buf"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Unsupported operation: &raw mut (*_6)", "lean_lines": null, "seconds": 9.8, "item_id": "adv-RUSTSEC-2024-0357", "kind": "advisory", "labels": {"buggy": "openssl@0.10.65", "reference": "openssl@0.10.66"}} +{"adv_id": "RUSTSEC-2024-0366", "crate": "cosmwasm-vm", "date": "2024-08-27", "url": "https://github.com/CosmWasm/advisories/blob/main/CWAs/CWA-2023-004.md", "title": "CWA-2023-004: Excessive number of function parameters in compiled Wasm", "categories": ["denial-of-service"], "affected_functions": [], "bug_class": ["other"], "pre_version": "1.2.7", "post_version": "1.2.8", "stage": "diff_safe", "changed_files": ["src/compatibility.rs", "src/modules/file_system_cache.rs"], "changed_lines": 66, "unsafe_in_changed_files": 12, "changed_functions": ["compatibility::check_wasm", "compatibility::check_wasm_capabilities", "modules::file_system_cache::store"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error[E0635]: unknown feature `stdsimd`", "lean_lines": null, "seconds": 10.7, "item_id": "adv-RUSTSEC-2024-0366", "kind": "advisory", "labels": {"buggy": "cosmwasm-vm@1.2.7", "reference": "cosmwasm-vm@1.2.8"}} +{"adv_id": "RUSTSEC-2024-0369", "crate": "phonenumber", "date": "2024-07-07", "url": "https://github.com/whisperfish/rust-phonenumber/issues/69", "title": "phonenumber: panic on parsing crafted phonenumber inputs", "categories": ["denial-of-service"], "affected_functions": ["phonenumber::parse"], "bug_class": ["panic", "logic"], "pre_version": "0.3.5+8.13.36", "post_version": "0.3.6+8.13.36", "stage": "strict_safe", "changed_files": ["src/national_number.rs", "src/parser/mod.rs", "src/phone_number.rs"], "changed_lines": 46, "unsafe_in_changed_files": 0, "changed_functions": ["national_number::new", "parser::phone_number"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Unimplemented: found an occurrence of a lifetime constraint relating", "lean_lines": null, "seconds": 29.5, "item_id": "adv-RUSTSEC-2024-0369", "kind": "advisory", "labels": {"buggy": "phonenumber@0.3.5+8.13.36", "reference": "phonenumber@0.3.6+8.13.36"}} +{"adv_id": "RUSTSEC-2024-0405", "crate": "rustyscript", "date": "2024-07-18", "url": "https://github.com/rscarson/rustyscript/issues/174", "title": "op_panic in the base runtime can force a panic in the runtime's containing thread", "categories": ["denial-of-service"], "affected_functions": [], "bug_class": ["panic"], "pre_version": "0.6.0", "post_version": "0.6.1", "stage": "strict_safe", "changed_files": ["src/error.rs", "src/inner_runtime.rs"], "changed_lines": 6, "unsafe_in_changed_files": 0, "changed_functions": ["inner_runtime::eval"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] unions are not supported", "lean_lines": null, "seconds": 125.5, "item_id": "adv-RUSTSEC-2024-0405", "kind": "advisory", "labels": {"buggy": "rustyscript@0.6.0", "reference": "rustyscript@0.6.1"}} +{"adv_id": "RUSTSEC-2024-0437", "crate": "protobuf", "date": "2024-12-12", "url": "https://github.com/stepancheg/rust-protobuf/issues/749", "title": "Crash due to uncontrolled recursion in protobuf crate", "categories": ["denial-of-service"], "affected_functions": ["protobuf::coded_input_stream::CodedInputStream::skip_group"], "bug_class": ["overflow", "panic", "dos_loop_or_recursion", "logic"], "pre_version": "3.7.1", "post_version": "3.7.2", "stage": "diff_safe", "changed_files": ["src/coded_input_stream/mod.rs"], "changed_lines": 73, "unsafe_in_changed_files": 4, "changed_functions": ["coded_input_stream::drop", "coded_input_stream::merge_message", "coded_input_stream::skip_group"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Dynamic trait types are not supported yet", "lean_lines": null, "seconds": 16.6, "item_id": "adv-RUSTSEC-2024-0437", "kind": "advisory", "labels": {"buggy": "protobuf@3.7.1", "reference": "protobuf@3.7.2"}} +{"adv_id": "RUSTSEC-2024-0445", "crate": "cap-primitives", "date": "2024-11-05", "url": "https://github.com/bytecodealliance/cap-std/pull/371", "title": "cap-primitives doesn't fully sandbox all the Windows device filenames", "categories": [], "affected_functions": [], "bug_class": ["logic"], "pre_version": "3.4.0", "post_version": "3.4.1", "stage": "strict_safe", "changed_files": ["src/windows/fs/open_impl.rs"], "changed_lines": 6, "unsafe_in_changed_files": 0, "changed_functions": ["windows::fs::open_impl::open_impl"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": false, "translated": false, "error": "lean: /work/translate/RUSTSEC-2024-0445/Crate.lean:12958:2: error: `find` is not a field of structure `core.iter.traits.iterator.Iterator`\n/apps/development/rlhf/bugfind_data/work/translate/RUSTSEC-2024-0445/Crate.lean:12965:2: error: `rev` is not a field of structure `core.iter.traits.iterator.Iterator`\n", "lean_lines": 13560, "seconds": 48.8, "item_id": "adv-RUSTSEC-2024-0445", "kind": "advisory", "labels": {"buggy": "cap-primitives@3.4.0", "reference": "cap-primitives@3.4.1"}} +{"adv_id": "RUSTSEC-2025-0008", "crate": "openh264-sys2", "date": "2025-02-24", "url": null, "title": "Openh264 Decoding Functions Heap Overflow Vulnerability", "categories": ["memory-corruption"], "affected_functions": [], "bug_class": ["overflow", "logic"], "pre_version": "0.7.1", "post_version": "0.8.0", "stage": "diff_safe", "changed_files": ["src/generated/types.rs"], "changed_lines": 18, "unsafe_in_changed_files": 74, "changed_functions": ["generated::types::default"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "start function not in generated Lean", "lean_lines": 23, "seconds": 154.0, "item_id": "adv-RUSTSEC-2025-0008", "kind": "advisory", "labels": {"buggy": "openh264-sys2@0.7.1", "reference": "openh264-sys2@0.8.0"}} +{"adv_id": "RUSTSEC-2025-0009", "crate": "ring", "date": "2025-03-06", "url": "https://github.com/briansmith/ring/blob/main/RELEASES.md#version-01712-2025-03-05", "title": "Some AES functions may panic when overflow checking is enabled.", "categories": ["denial-of-service"], "affected_functions": [], "bug_class": ["overflow", "panic"], "pre_version": "0.17.11", "post_version": "0.17.12", "stage": "strict_safe", "changed_files": ["src/aead/aes.rs"], "changed_lines": 2, "unsafe_in_changed_files": 0, "changed_functions": ["aead::aes::increment_by_less_safe"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "start function not in generated Lean", "lean_lines": 23, "seconds": 52.5, "item_id": "adv-RUSTSEC-2025-0009", "kind": "advisory", "labels": {"buggy": "ring@0.17.11", "reference": "ring@0.17.12"}} +{"adv_id": "RUSTSEC-2025-0062", "crate": "toodee", "date": "2025-05-22", "url": "https://github.com/antonmarsden/toodee/issues/26", "title": "Heap Buffer Overflow in the DrainCol Destructor", "categories": ["memory-corruption", "memory-exposure"], "affected_functions": ["toodee::DrainCol::drop"], "bug_class": ["overflow"], "pre_version": "0.5.0", "post_version": "0.6.0", "stage": "diff_safe", "changed_files": ["src/tests.rs", "src/toodee.rs"], "changed_lines": 10, "unsafe_in_changed_files": 54, "changed_functions": ["toodee::drop", "toodee::from_box"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "start function not in generated Lean", "lean_lines": 74, "seconds": 22.1, "item_id": "adv-RUSTSEC-2025-0062", "kind": "advisory", "labels": {"buggy": "toodee@0.5.0", "reference": "toodee@0.6.0"}} +{"adv_id": "RUSTSEC-2025-0065", "crate": "matrix-sdk-base", "date": "2025-09-11", "url": "https://github.com/matrix-org/matrix-rust-sdk/pull/5635", "title": "matrix-sdk-base: Panic in the `RoomMember::normalized_power_level()` method", "categories": [], "affected_functions": ["matrix_sdk_base::RoomMember::normalized_power_level"], "bug_class": ["panic"], "pre_version": "0.14.0", "post_version": "0.14.1", "stage": "strict_safe", "changed_files": ["src/room/members.rs"], "changed_lines": 79, "unsafe_in_changed_files": 0, "changed_functions": ["room::members::as_vec", "room::members::normalized_power_level"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Assertion failed: new value doesn't have the same type as its destination", "lean_lines": null, "seconds": 73.7, "item_id": "adv-RUSTSEC-2025-0065", "kind": "advisory", "labels": {"buggy": "matrix-sdk-base@0.14.0", "reference": "matrix-sdk-base@0.14.1"}} +{"adv_id": "RUSTSEC-2025-0071", "crate": "ammonia", "date": "2025-09-21", "url": null, "title": "Incorrect handling of embedded SVG and MathML leads to mutation XSS after removal", "categories": ["format-injection"], "affected_functions": [], "bug_class": ["logic"], "pre_version": "3.3.0", "post_version": "3.3.1", "stage": "strict_safe", "changed_files": ["src/lib.rs"], "changed_lines": 54, "unsafe_in_changed_files": 0, "changed_functions": ["check_expected_namespace", "clean_dom", "is_url_attr"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error[E0422]: cannot find struct, variant or union type `LineColumn` in crate `proc_macro`", "lean_lines": null, "seconds": 3.6, "item_id": "adv-RUSTSEC-2025-0071", "kind": "advisory", "labels": {"buggy": "ammonia@3.3.0", "reference": "ammonia@3.3.1"}} +{"adv_id": "RUSTSEC-2025-0073", "crate": "alloy-dyn-abi", "date": "2025-10-15", "url": "https://github.com/alloy-rs/core/commit/7823e9af8c20e9fcfb5360f5eafd891c457ebccf", "title": "DoS vulnerability on `alloy_dyn_abi::TypedData` hashing", "categories": ["denial-of-service"], "affected_functions": ["alloy_dyn_abi::eip712::Resolver::encode_type"], "bug_class": ["panic"], "pre_version": "0.8.25", "post_version": "0.8.26", "stage": "diff_safe", "changed_files": ["src/arbitrary.rs", "src/eip712/parser.rs", "src/eip712/resolver.rs", "src/eip712/typed_data.rs"], "changed_lines": 87, "unsafe_in_changed_files": 2, "changed_functions": ["arbitrary::new", "eip712::parser::parse", "eip712::resolver::encode_type"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "start function not in generated Lean", "lean_lines": 23, "seconds": 153.7, "item_id": "adv-RUSTSEC-2025-0073", "kind": "advisory", "labels": {"buggy": "alloy-dyn-abi@0.8.25", "reference": "alloy-dyn-abi@0.8.26"}} +{"adv_id": "RUSTSEC-2026-0007", "crate": "bytes", "date": "2026-02-03", "url": "https://github.com/tokio-rs/bytes/commit/d0293b0e35838123c51ca5dfdf468ecafee4398f", "title": "Integer overflow in `BytesMut::reserve`", "categories": ["memory-corruption"], "affected_functions": [], "bug_class": ["overflow", "panic", "logic"], "pre_version": "1.11.0", "post_version": "1.11.1", "stage": "diff_safe", "changed_files": ["src/bytes_mut.rs"], "changed_lines": 20, "unsafe_in_changed_files": 100, "changed_functions": ["bytes_mut::reserve_inner"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Aeneas does not yet support dereferencing raw pointers.", "lean_lines": null, "seconds": 2.9, "item_id": "adv-RUSTSEC-2026-0007", "kind": "advisory", "labels": {"buggy": "bytes@1.11.0", "reference": "bytes@1.11.1"}} +{"adv_id": "RUSTSEC-2026-0023", "crate": "libcrux-ecdh", "date": "2026-01-26", "url": "https://github.com/cryspen/libcrux/pull/1301", "title": "X25519 secret validation did not check buffer length or clamping", "categories": [], "affected_functions": ["libcrux_ecdh::validate_scalar"], "bug_class": ["dos_loop_or_recursion", "logic"], "pre_version": "0.0.5", "post_version": "0.0.6", "stage": "strict_safe", "changed_files": ["src/ecdh.rs"], "changed_lines": 7, "unsafe_in_changed_files": 0, "changed_functions": ["ecdh::validate_scalar"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": false, "translated": false, "error": "lean: STSEC-2026-0023/Crate.lean:2793:4: error: `libcrux_ecdh.hacl.Error.Insts.CoreConvertFromError.from` has already been declared\n/apps/development/rlhf/bugfind_data/work/translate/RUSTSEC-2026-0023/Crate.lean:2800:4: error: `libcrux_ecdh.hacl.Error.Insts.CoreConvertFromError` has already been declared\n", "lean_lines": 3294, "seconds": 22.7, "item_id": "adv-RUSTSEC-2026-0023", "kind": "advisory", "labels": {"buggy": "libcrux-ecdh@0.0.5", "reference": "libcrux-ecdh@0.0.6"}} +{"adv_id": "RUSTSEC-2026-0026", "crate": "libcrux-ed25519", "date": "2026-02-05", "url": "https://github.com/cryspen/libcrux/pull/1320", "title": "Unnecessary clamping of seed reduces seed entropy to 251 bits", "categories": [], "affected_functions": ["libcrux_ed25519::generate_key_pair"], "bug_class": ["other"], "pre_version": "0.0.5", "post_version": "0.0.6", "stage": "strict_safe", "changed_files": ["src/impl_hacl.rs"], "changed_lines": 5, "unsafe_in_changed_files": 0, "changed_functions": ["impl_hacl::generate_key_pair"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas/lean timeout", "lean_lines": 23, "seconds": 343.8, "item_id": "adv-RUSTSEC-2026-0026", "kind": "advisory", "labels": {"buggy": "libcrux-ed25519@0.0.5", "reference": "libcrux-ed25519@0.0.6"}} +{"adv_id": "RUSTSEC-2026-0035", "crate": "pingora-cache", "date": "2026-03-04", "url": "https://blog.cloudflare.com/pingora-oss-smuggling-vulnerabilities/", "title": "Cache poisoning via insecure-by-default cache key", "categories": [], "affected_functions": [], "bug_class": ["other"], "pre_version": "0.7.0", "post_version": "0.8.0", "stage": "strict_safe", "changed_files": ["src/key.rs"], "changed_lines": 14, "unsafe_in_changed_files": 0, "changed_functions": ["key::default", "key::primary_hasher"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Unexpected error", "lean_lines": null, "seconds": 106.4, "item_id": "adv-RUSTSEC-2026-0035", "kind": "advisory", "labels": {"buggy": "pingora-cache@0.7.0", "reference": "pingora-cache@0.8.0"}} +{"adv_id": "RUSTSEC-2026-0049", "crate": "rustls-webpki", "date": "2026-03-20", "url": null, "title": "CRLs not considered authoritative by Distribution Point due to faulty matching logic", "categories": ["privilege-escalation"], "affected_functions": [], "bug_class": ["logic"], "pre_version": "0.103.9", "post_version": "0.103.10", "stage": "strict_safe", "changed_files": ["src/alg_tests.rs", "src/cert.rs", "src/crl/types.rs", "src/der.rs", "src/end_entity.rs", "src/verify_cert.rs"], "changed_lines": 94, "unsafe_in_changed_files": 0, "changed_functions": ["crl::types::authoritative_for", "crl::types::uri_name_in_common", "verify_cert::next"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Early returns inside of loops are not supported yet", "lean_lines": null, "seconds": 7.8, "item_id": "adv-RUSTSEC-2026-0049", "kind": "advisory", "labels": {"buggy": "rustls-webpki@0.103.9", "reference": "rustls-webpki@0.103.10"}} +{"adv_id": "RUSTSEC-2026-0075", "crate": "libcrux-ed25519", "date": "2026-03-04", "url": "https://github.com/cryspen/libcrux/pull/1349", "title": "All-Zero Key Generation on Catastrophic RNG Failure", "categories": [], "affected_functions": ["libcrux_ed25519::generate_key_pair"], "bug_class": ["other"], "pre_version": "0.0.6", "post_version": "0.0.7", "stage": "strict_safe", "changed_files": ["src/impl_hacl.rs"], "changed_lines": 6, "unsafe_in_changed_files": 0, "changed_functions": ["impl_hacl::generate_key_pair"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas/lean timeout", "lean_lines": 23, "seconds": 344.3, "item_id": "adv-RUSTSEC-2026-0075", "kind": "advisory", "labels": {"buggy": "libcrux-ed25519@0.0.6", "reference": "libcrux-ed25519@0.0.7"}} +{"adv_id": "RUSTSEC-2026-0076", "crate": "libcrux-ml-dsa", "date": "2026-03-04", "url": "https://github.com/cryspen/libcrux/pull/1348", "title": "Panic in Signature Hint Decoding During Verification", "categories": [], "affected_functions": ["libcrux_ml_dsa::ml_dsa_44::verify", "libcrux_ml_dsa::ml_dsa_65::verify", "libcrux_ml_dsa::ml_dsa_87::verify"], "bug_class": ["panic", "logic"], "pre_version": "0.0.7", "post_version": "0.0.8", "stage": "strict_safe", "changed_files": ["src/encoding/signature.rs", "src/ml_dsa_generic.rs"], "changed_lines": 7, "unsafe_in_changed_files": 0, "changed_functions": ["encoding::signature::deserialize", "ml_dsa_generic::verify_internal"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Unreachable", "lean_lines": null, "seconds": 18.8, "item_id": "adv-RUSTSEC-2026-0076", "kind": "advisory", "labels": {"buggy": "libcrux-ml-dsa@0.0.7", "reference": "libcrux-ml-dsa@0.0.8"}} +{"adv_id": "RUSTSEC-2026-0086", "crate": "wasmtime", "date": "2026-04-09", "url": "https://github.com/bytecodealliance/wasmtime/pull/13009", "title": "Host data leakage with 64-bit tables and Winch", "categories": [], "affected_functions": [], "bug_class": ["other"], "pre_version": "36.0.6", "post_version": "36.0.7", "stage": "diff_safe", "changed_files": ["src/runtime/component/values.rs", "src/runtime/vm/cow.rs"], "changed_lines": 4, "unsafe_in_changed_files": 100, "changed_functions": ["runtime::component::values::push_flags", "runtime::vm::cow::instantiate"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": false, "translated": false, "error": "lean: f/bugfind_data/work/translate/RUSTSEC-2026-0086/Crate.lean:1664:4: error(lean.synthInstanceFailed): failed to synthesize instance of type class\n Decidable (base = right_val)\n\nHint: Type class instance resolution failures can be inspected with the `set_option trace.Meta.synthInstance true` command.\n", "lean_lines": 3561, "seconds": 139.2, "item_id": "adv-RUSTSEC-2026-0086", "kind": "advisory", "labels": {"buggy": "wasmtime@36.0.6", "reference": "wasmtime@36.0.7"}} +{"adv_id": "RUSTSEC-2026-0090", "crate": "wasmtime", "date": "2026-04-09", "url": "https://github.com/bytecodealliance/wasmtime/issues/12069", "title": "Use-after-free bug after cloning `wasmtime::Linker`", "categories": [], "affected_functions": [], "bug_class": ["other"], "pre_version": "43.0.0", "post_version": "43.0.1", "stage": "diff_safe", "changed_files": ["src/runtime/component/values.rs", "src/runtime/vm/cow.rs"], "changed_lines": 4, "unsafe_in_changed_files": 88, "changed_functions": ["runtime::component::values::push_flags", "runtime::vm::cow::instantiate"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Dynamic trait types are not supported yet", "lean_lines": null, "seconds": 127.3, "item_id": "adv-RUSTSEC-2026-0090", "kind": "advisory", "labels": {"buggy": "wasmtime@43.0.0", "reference": "wasmtime@43.0.1"}} +{"adv_id": "RUSTSEC-2026-0091", "crate": "wasmtime", "date": "2026-04-09", "url": "https://github.com/bytecodealliance/wasmtime/pull/13026", "title": "Out-of-bounds write or crash when transcoding component model strings", "categories": [], "affected_functions": [], "bug_class": ["panic"], "pre_version": "24.0.6", "post_version": "24.0.7", "stage": "diff_safe", "changed_files": ["src/runtime/component/values.rs"], "changed_lines": 2, "unsafe_in_changed_files": 2, "changed_functions": ["runtime::component::values::push_flags"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error: implicit autoref creates a reference to the dereference of a raw pointer", "lean_lines": null, "seconds": 86.2, "item_id": "adv-RUSTSEC-2026-0091", "kind": "advisory", "labels": {"buggy": "wasmtime@24.0.6", "reference": "wasmtime@24.0.7"}} +{"adv_id": "RUSTSEC-2026-0093", "crate": "wasmtime", "date": "2026-04-09", "url": "https://github.com/bytecodealliance/wasmtime/pull/13016", "title": "Heap OOB read in component model UTF-16 to latin1+utf16 string transcoding", "categories": [], "affected_functions": [], "bug_class": ["other"], "pre_version": "24.0.6", "post_version": "24.0.7", "stage": "diff_safe", "changed_files": ["src/runtime/component/values.rs"], "changed_lines": 2, "unsafe_in_changed_files": 2, "changed_functions": ["runtime::component::values::push_flags"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon: error: implicit autoref creates a reference to the dereference of a raw pointer", "lean_lines": null, "seconds": 84.6, "item_id": "adv-RUSTSEC-2026-0093", "kind": "advisory", "labels": {"buggy": "wasmtime@24.0.6", "reference": "wasmtime@24.0.7"}} +{"adv_id": "RUSTSEC-2026-0094", "crate": "wasmtime", "date": "2026-04-09", "url": "https://github.com/bytecodealliance/wasmtime/pull/13014", "title": "Improperly masked return value from `table.grow` with Winch compiler backend", "categories": [], "affected_functions": [], "bug_class": ["other"], "pre_version": "36.0.6", "post_version": "36.0.7", "stage": "diff_safe", "changed_files": ["src/runtime/component/values.rs", "src/runtime/vm/cow.rs"], "changed_lines": 4, "unsafe_in_changed_files": 100, "changed_functions": ["runtime::component::values::push_flags", "runtime::vm::cow::instantiate"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": false, "translated": false, "error": "lean: f/bugfind_data/work/translate/RUSTSEC-2026-0094/Crate.lean:1664:4: error(lean.synthInstanceFailed): failed to synthesize instance of type class\n Decidable (base = right_val)\n\nHint: Type class instance resolution failures can be inspected with the `set_option trace.Meta.synthInstance true` command.\n", "lean_lines": 3561, "seconds": 135.5, "item_id": "adv-RUSTSEC-2026-0094", "kind": "advisory", "labels": {"buggy": "wasmtime@36.0.6", "reference": "wasmtime@36.0.7"}} +{"adv_id": "RUSTSEC-2026-0095", "crate": "wasmtime", "date": "2026-04-09", "url": "https://github.com/bytecodealliance/wasmtime/pull/13014", "title": "Wasmtime with Winch compiler backend may allow a sandbox-escaping memory access", "categories": [], "affected_functions": [], "bug_class": ["other"], "pre_version": "36.0.6", "post_version": "36.0.7", "stage": "diff_safe", "changed_files": ["src/runtime/component/values.rs", "src/runtime/vm/cow.rs"], "changed_lines": 4, "unsafe_in_changed_files": 100, "changed_functions": ["runtime::component::values::push_flags", "runtime::vm::cow::instantiate"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": false, "translated": false, "error": "lean: f/bugfind_data/work/translate/RUSTSEC-2026-0095/Crate.lean:1664:4: error(lean.synthInstanceFailed): failed to synthesize instance of type class\n Decidable (base = right_val)\n\nHint: Type class instance resolution failures can be inspected with the `set_option trace.Meta.synthInstance true` command.\n", "lean_lines": 3561, "seconds": 136.4, "item_id": "adv-RUSTSEC-2026-0095", "kind": "advisory", "labels": {"buggy": "wasmtime@36.0.6", "reference": "wasmtime@36.0.7"}} +{"adv_id": "RUSTSEC-2026-0096", "crate": "wasmtime", "date": "2026-04-09", "url": "https://github.com/bytecodealliance/wasmtime/pull/13013", "title": "Miscompiled guest heap access enables sandbox escape on aarch64 Cranelift", "categories": [], "affected_functions": [], "bug_class": ["other"], "pre_version": "36.0.6", "post_version": "36.0.7", "stage": "diff_safe", "changed_files": ["src/runtime/component/values.rs", "src/runtime/vm/cow.rs"], "changed_lines": 4, "unsafe_in_changed_files": 100, "changed_functions": ["runtime::component::values::push_flags", "runtime::vm::cow::instantiate"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": false, "translated": false, "error": "lean: f/bugfind_data/work/translate/RUSTSEC-2026-0096/Crate.lean:1664:4: error(lean.synthInstanceFailed): failed to synthesize instance of type class\n Decidable (base = right_val)\n\nHint: Type class instance resolution failures can be inspected with the `set_option trace.Meta.synthInstance true` command.\n", "lean_lines": 3561, "seconds": 142.7, "item_id": "adv-RUSTSEC-2026-0096", "kind": "advisory", "labels": {"buggy": "wasmtime@36.0.6", "reference": "wasmtime@36.0.7"}} +{"adv_id": "RUSTSEC-2026-0114", "crate": "wasmtime", "date": "2026-04-30", "url": "https://github.com/bytecodealliance/wasmtime/pull/13245", "title": "Panic when allocating a table exceeding the size of the host's address space", "categories": [], "affected_functions": [], "bug_class": ["panic"], "pre_version": "36.0.7", "post_version": "36.0.8", "stage": "diff_safe", "changed_files": ["src/runtime/vm/table.rs"], "changed_lines": 14, "unsafe_in_changed_files": 54, "changed_functions": ["runtime::vm::table::alloc_dynamic_table_elements", "runtime::vm::table::default", "runtime::vm::table::grow"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Early returns inside of loops are not supported yet", "lean_lines": null, "seconds": 161.6, "item_id": "adv-RUSTSEC-2026-0114", "kind": "advisory", "labels": {"buggy": "wasmtime@36.0.7", "reference": "wasmtime@36.0.8"}} +{"adv_id": "RUSTSEC-2026-0124", "crate": "libcrux-chacha20poly1305", "date": "2026-03-29", "url": "https://github.com/cryspen/libcrux/pull/1386", "title": "Potential Panic on Overlong Ciphertext Buffer", "categories": [], "affected_functions": ["libcrux_chacha20poly1305::encrypt", "libcrux_chacha20poly1305::xchacha20_poly1305::encrypt"], "bug_class": ["panic"], "pre_version": "0.0.7", "post_version": "0.0.8", "stage": "strict_safe", "changed_files": ["src/impl_hacl.rs"], "changed_lines": 5, "unsafe_in_changed_files": 0, "changed_functions": ["impl_hacl::encrypt"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": true, "translated": true, "error": null, "lean_lines": 2737, "seconds": 88.7, "item_id": "adv-RUSTSEC-2026-0124", "kind": "advisory", "labels": {"buggy": "libcrux-chacha20poly1305@0.0.7", "reference": "libcrux-chacha20poly1305@0.0.8"}} +{"adv_id": "RUSTSEC-2026-0140", "crate": "dynoxide-rs", "date": "2026-05-12", "url": "https://github.com/nubo-db/dynoxide/commit/10292083fd16fe7116e9089ffa189f4f4f071e0f", "title": "DNS rebinding and cross-origin CSRF in dynoxide's MCP HTTP transport", "categories": [], "affected_functions": [], "bug_class": ["other"], "pre_version": "0.9.12", "post_version": "0.9.13", "stage": "diff_safe", "changed_files": ["src/mcp/mod.rs", "src/mcp/server.rs"], "changed_lines": 18, "unsafe_in_changed_files": 2, "changed_functions": ["mcp::serve_http_with_shutdown", "mcp::server::default", "mcp::server::with_config"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon timeout", "lean_lines": null, "seconds": 300.4, "item_id": "adv-RUSTSEC-2026-0140", "kind": "advisory", "labels": {"buggy": "dynoxide-rs@0.9.12", "reference": "dynoxide-rs@0.9.13"}} +{"adv_id": "RUSTSEC-2026-0145", "crate": "astral-tokio-tar", "date": "2026-05-18", "url": "https://github.com/astral-sh/tokio-tar/pull/82", "title": "PAX Header Desynchronization in astral-tokio-tar", "categories": ["file-disclosure"], "affected_functions": [], "bug_class": ["other"], "pre_version": "0.6.1", "post_version": "0.6.2", "stage": "strict_safe", "changed_files": ["src/archive.rs"], "changed_lines": 14, "unsafe_in_changed_files": 0, "changed_functions": ["archive::poll_next_raw"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Returns inside of nested loops are not supported yet", "lean_lines": null, "seconds": 14.8, "item_id": "adv-RUSTSEC-2026-0145", "kind": "advisory", "labels": {"buggy": "astral-tokio-tar@0.6.1", "reference": "astral-tokio-tar@0.6.2"}} +{"adv_id": "RUSTSEC-2026-0149", "crate": "wasmtime-wasi", "date": "2026-05-21", "url": "https://github.com/bytecodealliance/wasmtime/pull/13429", "title": "WASI path_open(TRUNCATE) bypasses `FilePerms::WRITE` host restriction", "categories": [], "affected_functions": [], "bug_class": ["logic"], "pre_version": "24.0.8", "post_version": "24.0.9", "stage": "strict_safe", "changed_files": ["src/host/filesystem.rs"], "changed_lines": 1, "unsafe_in_changed_files": 0, "changed_functions": ["host::filesystem::open_at"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas/lean timeout", "lean_lines": 23, "seconds": 366.3, "item_id": "adv-RUSTSEC-2026-0149", "kind": "advisory", "labels": {"buggy": "wasmtime-wasi@24.0.8", "reference": "wasmtime-wasi@24.0.9"}} +{"adv_id": "RUSTSEC-2026-0152", "crate": "oneringbuf", "date": "2026-05-27", "url": "https://github.com/skilvingr/rust-oneringbuf/commit/643a24b30914068416dff9021a069c12c865a316", "title": "Use-after-free", "categories": ["memory-corruption"], "affected_functions": [], "bug_class": ["other"], "pre_version": "0.7.1", "post_version": "0.8.0", "stage": "diff_safe", "changed_files": ["src/ring_buffer/impls.rs", "src/ring_buffer/wrappers/refs/droppable.rs", "src/ring_buffer/wrappers/refs/mod.rs", "src/ring_buffer/wrappers/refs/non_droppable.rs"], "changed_lines": 24, "unsafe_in_changed_files": 10, "changed_functions": ["ring_buffer::impls::into_ref", "ring_buffer::impls::split_mut", "ring_buffer::wrappers::refs::into_ref"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "start function not in generated Lean", "lean_lines": 38, "seconds": 15.5, "item_id": "adv-RUSTSEC-2026-0152", "kind": "advisory", "labels": {"buggy": "oneringbuf@0.7.1", "reference": "oneringbuf@0.8.0"}} +{"adv_id": "RUSTSEC-2026-0158", "crate": "matrix-sdk-ui", "date": "2026-06-03", "url": "https://github.com/matrix-org/matrix-rust-sdk/pull/6454", "title": "Incomplete message edit validation in matrix-sdk-ui", "categories": [], "affected_functions": [], "bug_class": ["logic"], "pre_version": "0.16.0", "post_version": "0.16.1", "stage": "strict_safe", "changed_files": ["src/timeline/controller/aggregations.rs"], "changed_lines": 69, "unsafe_in_changed_files": 0, "changed_functions": ["timeline::controller::aggregations::edit_item", "timeline::controller::aggregations::resolve_edits"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Detected groups of mixed mutually recursive definitions (such as a type mutually recursive with a function, or a function mutually recursive with a trait implementation):", "lean_lines": null, "seconds": 176.0, "item_id": "adv-RUSTSEC-2026-0158", "kind": "advisory", "labels": {"buggy": "matrix-sdk-ui@0.16.0", "reference": "matrix-sdk-ui@0.16.1"}} +{"adv_id": "RUSTSEC-2026-0179", "crate": "postgres-protocol", "date": "2026-06-12", "url": "https://github.com/rust-postgres/rust-postgres/commit/d40097a36a85068ea50a3afbf0ce154ba439e7f0", "title": "Unbounded SCRAM iteration count allows a malicious server to cause CPU-exhaustion denial of service", "categories": ["denial-of-service"], "affected_functions": ["postgres_protocol::authentication::sasl::ScramSha256::update"], "bug_class": ["dos_loop_or_recursion"], "pre_version": "0.6.11", "post_version": "0.6.12", "stage": "strict_safe", "changed_files": ["src/authentication/sasl.rs", "src/types/mod.rs", "src/types/test.rs"], "changed_lines": 75, "unsafe_in_changed_files": 0, "changed_functions": ["authentication::sasl::update", "authentication::sasl::value"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon timeout", "lean_lines": null, "seconds": 300.1, "item_id": "adv-RUSTSEC-2026-0179", "kind": "advisory", "labels": {"buggy": "postgres-protocol@0.6.11", "reference": "postgres-protocol@0.6.12"}} +{"adv_id": "RUSTSEC-2026-0180", "crate": "postgres-protocol", "date": "2026-06-12", "url": "https://github.com/rust-postgres/rust-postgres/commit/a7cf84b5c46431cbca9d8ff50508c23f446efa7d", "title": "Panic decoding a malformed `hstore` value allows denial of service", "categories": ["denial-of-service"], "affected_functions": ["postgres_protocol::types::hstore_from_sql"], "bug_class": ["panic", "logic"], "pre_version": "0.6.11", "post_version": "0.6.12", "stage": "strict_safe", "changed_files": ["src/authentication/sasl.rs", "src/types/mod.rs", "src/types/test.rs"], "changed_lines": 75, "unsafe_in_changed_files": 0, "changed_functions": ["authentication::sasl::update", "authentication::sasl::value"], "charon_ok": false, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "charon timeout", "lean_lines": null, "seconds": 300.1, "item_id": "adv-RUSTSEC-2026-0180", "kind": "advisory", "labels": {"buggy": "postgres-protocol@0.6.11", "reference": "postgres-protocol@0.6.12"}} +{"adv_id": "RUSTSEC-2026-0188", "crate": "wasmtime-wasi", "date": "2026-06-24", "url": "https://github.com/bytecodealliance/wasmtime/pull/13725", "title": "WASI hard links and renames bypass wasmtime-wasi's FilePerms for destination", "categories": [], "affected_functions": [], "bug_class": ["logic"], "pre_version": "24.0.10", "post_version": "24.0.11", "stage": "strict_safe", "changed_files": ["src/host/filesystem.rs"], "changed_lines": 6, "unsafe_in_changed_files": 0, "changed_functions": ["host::filesystem::link_at", "host::filesystem::rename_at"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas/lean timeout", "lean_lines": 23, "seconds": 364.6, "item_id": "adv-RUSTSEC-2026-0188", "kind": "advisory", "labels": {"buggy": "wasmtime-wasi@24.0.10", "reference": "wasmtime-wasi@24.0.11"}} +{"adv_id": "RUSTSEC-2026-0199", "crate": "bcrypt", "date": "2026-06-20", "url": "https://github.com/Keats/rust-bcrypt/pull/103", "title": "Panic in `bcrypt::verify` on non-ASCII hash input", "categories": ["denial-of-service"], "affected_functions": [], "bug_class": ["panic", "logic"], "pre_version": "0.19.1", "post_version": "0.19.2", "stage": "strict_safe", "changed_files": ["src/lib.rs"], "changed_lines": 33, "unsafe_in_changed_files": 0, "changed_functions": ["doesnt_verify_different_passwords", "split_hash"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] There should be no bottoms in the value", "lean_lines": null, "seconds": 5.8, "item_id": "adv-RUSTSEC-2026-0199", "kind": "advisory", "labels": {"buggy": "bcrypt@0.19.1", "reference": "bcrypt@0.19.2"}} +{"adv_id": "RUSTSEC-2026-0213", "crate": "ammonia", "date": "2026-07-21", "url": null, "title": "XSS in ammonia via SVG `animate` and `set` animation tags", "categories": ["format-injection"], "affected_functions": [], "bug_class": ["other"], "pre_version": "3.3.2", "post_version": "3.3.3", "stage": "strict_safe", "changed_files": ["src/lib.rs"], "changed_lines": 20, "unsafe_in_changed_files": 0, "changed_functions": ["clean_dom", "is_url_attr"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Dynamic trait types are not supported yet", "lean_lines": null, "seconds": 36.0, "item_id": "adv-RUSTSEC-2026-0213", "kind": "advisory", "labels": {"buggy": "ammonia@3.3.2", "reference": "ammonia@3.3.3"}} +{"adv_id": "RUSTSEC-2026-0217", "crate": "tract-nnef", "date": "2026-06-18", "url": "https://github.com/sonos/tract/commit/34c7df2c9bd2a36583e09b52f3e6319bf23102e8", "title": "Integer overflow in tract-nnef NNEF tensor parser leads to out-of-bounds read on model load", "categories": ["memory-exposure", "denial-of-service"], "affected_functions": ["tract_nnef::tensors::read_tensor"], "bug_class": ["overflow", "panic", "logic"], "pre_version": "0.21.15", "post_version": "0.21.16", "stage": "diff_safe", "changed_files": ["src/tensors.rs"], "changed_lines": 19, "unsafe_in_changed_files": 14, "changed_functions": ["tensors::read_block_quant_value", "tensors::read_tensor"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Early returns inside of loops are not supported yet", "lean_lines": null, "seconds": 141.0, "item_id": "adv-RUSTSEC-2026-0217", "kind": "advisory", "labels": {"buggy": "tract-nnef@0.21.15", "reference": "tract-nnef@0.21.16"}} +{"adv_id": "RUSTSEC-2026-0219", "crate": "nostr", "date": "2026-07-26", "url": "https://github.com/nostrdevkit/nostr/commit/b24619346f666d08ef7fefe27f033b8bc871697f", "title": "Remote Denial of Service via malformed NIP-04 IV", "categories": ["denial-of-service"], "affected_functions": ["nostr::nips::nip04::decrypt", "nostr::nips::nip04::decrypt_to_bytes"], "bug_class": ["panic", "logic"], "pre_version": "0.44.5", "post_version": "0.44.6", "stage": "strict_safe", "changed_files": ["src/nips/nip04.rs"], "changed_lines": 33, "unsafe_in_changed_files": 0, "changed_functions": ["nips::nip04::decrypt_to_bytes", "nips::nip04::encrypt_with_rng", "nips::nip04::fmt"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "start function not in generated Lean", "lean_lines": 23, "seconds": 222.1, "item_id": "adv-RUSTSEC-2026-0219", "kind": "advisory", "labels": {"buggy": "nostr@0.44.5", "reference": "nostr@0.44.6"}} +{"adv_id": "RUSTSEC-2026-0274", "crate": "rtrb", "date": "2026-08-04", "url": "https://github.com/mgeier/rtrb/issues/185", "title": "Double free / use-after-free in `ReadChunk::commit` when an element's `Drop` panics", "categories": ["memory-corruption"], "affected_functions": ["rtrb::chunks::ReadChunk::commit", "rtrb::chunks::ReadChunk::commit_all"], "bug_class": ["panic", "dos_loop_or_recursion"], "pre_version": "0.3.4", "post_version": "0.3.5", "stage": "diff_safe", "changed_files": ["src/chunks.rs"], "changed_lines": 31, "unsafe_in_changed_files": 98, "changed_functions": ["chunks::commit_unchecked"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": true, "translated": true, "error": null, "lean_lines": 299, "seconds": 4.7, "item_id": "adv-RUSTSEC-2026-0274", "kind": "advisory", "labels": {"buggy": "rtrb@0.3.4", "reference": "rtrb@0.3.5"}} +{"adv_id": "RUSTSEC-2026-0278", "crate": "zbus_polkit", "date": "2026-08-31", "url": "https://github.com/z-galaxy/zbus_polkit/pull/101", "title": "`zbus_polkit`: authorization bypass via PID reuse", "categories": ["privilege-escalation"], "affected_functions": ["zbus_polkit::Subject::new_for_owner"], "bug_class": ["logic"], "pre_version": "5.0.0", "post_version": "5.1.0", "stage": "diff_safe", "changed_files": ["src/policykit1.rs"], "changed_lines": 4, "unsafe_in_changed_files": 2, "changed_functions": ["policykit1::new_for_owner", "policykit1::try_from"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Unimplemented", "lean_lines": null, "seconds": 42.0, "item_id": "adv-RUSTSEC-2026-0278", "kind": "advisory", "labels": {"buggy": "zbus_polkit@5.0.0", "reference": "zbus_polkit@5.1.0"}} +{"adv_id": "RUSTSEC-2026-0307", "crate": "uncbv", "date": "2026-09-23", "url": "https://github.com/antoyo/uncbv", "title": "`uncbv`: archive extraction is vulnerable to path traversal (zip-slip)", "categories": ["code-execution"], "affected_functions": [], "bug_class": ["other"], "pre_version": "0.3.0", "post_version": "0.3.1", "stage": "diff_safe", "changed_files": ["src/archive.rs"], "changed_lines": 17, "unsafe_in_changed_files": 4, "changed_functions": ["archive::extract", "archive::init_output"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Breaks to outer loops are not supported yet", "lean_lines": null, "seconds": 19.4, "item_id": "adv-RUSTSEC-2026-0307", "kind": "advisory", "labels": {"buggy": "uncbv@0.3.0", "reference": "uncbv@0.3.1"}} +{"adv_id": "RUSTSEC-2026-0312", "crate": "x509-validator", "date": "2026-09-24", "url": "https://github.com/namecare/x509-validator/commit/da661f8ecee820e05d089a76ecb654ff52a2c987", "title": "Excluded iPAddress name constraints with an all-zero mask are not applied", "categories": ["crypto-failure"], "affected_functions": [], "bug_class": ["logic"], "pre_version": "0.3.0", "post_version": "0.3.1", "stage": "strict_safe", "changed_files": ["src/rfc5280/ip_constraints.rs"], "changed_lines": 34, "unsafe_in_changed_files": 0, "changed_functions": ["rfc5280::ip_constraints::is_valid_cidr_mask"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": true, "translated": true, "error": null, "lean_lines": 221, "seconds": 19.4, "item_id": "adv-RUSTSEC-2026-0312", "kind": "advisory", "labels": {"buggy": "x509-validator@0.3.0", "reference": "x509-validator@0.3.1"}} +{"adv_id": "RUSTSEC-2026-0313", "crate": "wasmtime-wasi-http", "date": "2026-09-24", "url": "https://github.com/bytecodealliance/wasmtime/pull/14408", "title": "Outgoing HTTP body write allows guest-driven host memory exhaustion", "categories": [], "affected_functions": [], "bug_class": ["dos_loop_or_recursion"], "pre_version": "36.0.15", "post_version": "36.0.16", "stage": "strict_safe", "changed_files": ["src/body.rs"], "changed_lines": 3, "unsafe_in_changed_files": 0, "changed_functions": ["body::write"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas/lean timeout", "lean_lines": 23, "seconds": 388.0, "item_id": "adv-RUSTSEC-2026-0313", "kind": "advisory", "labels": {"buggy": "wasmtime-wasi-http@36.0.15", "reference": "wasmtime-wasi-http@36.0.16"}} +{"adv_id": "RUSTSEC-2026-0314", "crate": "wasmtime-wasi", "date": "2026-09-24", "url": "https://github.com/bytecodealliance/wasmtime/pull/14403", "title": "Guest can panic host through filesystem datetime overflow", "categories": [], "affected_functions": [], "bug_class": ["overflow", "panic"], "pre_version": "36.0.15", "post_version": "36.0.16", "stage": "diff_safe", "changed_files": ["src/p2/host/filesystem.rs"], "changed_lines": 10, "unsafe_in_changed_files": 2, "changed_functions": ["p2::host::filesystem::systemtime_from"], "charon_ok": true, "aeneas_ok": false, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas: [Error] Assertion failed: new value doesn't have the same type as its destination", "lean_lines": null, "seconds": 83.5, "item_id": "adv-RUSTSEC-2026-0314", "kind": "advisory", "labels": {"buggy": "wasmtime-wasi@36.0.15", "reference": "wasmtime-wasi@36.0.16"}} +{"adv_id": "RUSTSEC-2026-0320", "crate": "wasmtime-wasi-http", "date": "2026-10-02", "url": "https://github.com/bytecodealliance/wasmtime/pull/14483", "title": "Wasmtime wasi:http implementation panics with a zero timeout supplied", "categories": [], "affected_functions": [], "bug_class": ["panic"], "pre_version": "48.0.3", "post_version": "48.0.4", "stage": "strict_safe", "changed_files": ["src/default_send_request.rs"], "changed_lines": 7, "unsafe_in_changed_files": 0, "changed_functions": ["default_send_request::size_hint"], "charon_ok": true, "aeneas_ok": true, "fn_present": false, "lean_ok": false, "translated": false, "error": "aeneas/lean timeout", "lean_lines": 23, "seconds": 392.5, "item_id": "adv-RUSTSEC-2026-0320", "kind": "advisory", "labels": {"buggy": "wasmtime-wasi-http@48.0.3", "reference": "wasmtime-wasi-http@48.0.4"}} diff --git a/code/bugfind/bench/items/advisory_items.jsonl b/code/bugfind/bench/items/advisory_items.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..cd11ff60079fe833bb839c02e982209a6cc88672 --- /dev/null +++ b/code/bugfind/bench/items/advisory_items.jsonl @@ -0,0 +1,4 @@ +{"adv_id": "RUSTSEC-2019-0007", "crate": "asn1_der", "date": "2019-06-13", "url": "https://github.com/KizzyCode/asn1_der/issues/1", "title": "Processing of maliciously crafted length fields causes memory allocation SIGABRTs", "categories": [], "affected_functions": [], "bug_class": ["other"], "pre_version": "0.6.1", "post_version": "0.6.2", "stage": "strict_safe", "changed_files": ["src/der/value.rs"], "changed_lines": 11, "unsafe_in_changed_files": 0, "changed_functions": ["der::value::deserialize"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": true, "translated": true, "error": null, "lean_lines": 132, "seconds": 7.7, "item_id": "adv-RUSTSEC-2019-0007", "kind": "advisory", "labels": {"buggy": "asn1_der@0.6.1", "reference": "asn1_der@0.6.2"}} +{"adv_id": "RUSTSEC-2026-0124", "crate": "libcrux-chacha20poly1305", "date": "2026-03-29", "url": "https://github.com/cryspen/libcrux/pull/1386", "title": "Potential Panic on Overlong Ciphertext Buffer", "categories": [], "affected_functions": ["libcrux_chacha20poly1305::encrypt", "libcrux_chacha20poly1305::xchacha20_poly1305::encrypt"], "bug_class": ["panic"], "pre_version": "0.0.7", "post_version": "0.0.8", "stage": "strict_safe", "changed_files": ["src/impl_hacl.rs"], "changed_lines": 5, "unsafe_in_changed_files": 0, "changed_functions": ["impl_hacl::encrypt"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": true, "translated": true, "error": null, "lean_lines": 2737, "seconds": 88.7, "item_id": "adv-RUSTSEC-2026-0124", "kind": "advisory", "labels": {"buggy": "libcrux-chacha20poly1305@0.0.7", "reference": "libcrux-chacha20poly1305@0.0.8"}} +{"adv_id": "RUSTSEC-2026-0274", "crate": "rtrb", "date": "2026-08-04", "url": "https://github.com/mgeier/rtrb/issues/185", "title": "Double free / use-after-free in `ReadChunk::commit` when an element's `Drop` panics", "categories": ["memory-corruption"], "affected_functions": ["rtrb::chunks::ReadChunk::commit", "rtrb::chunks::ReadChunk::commit_all"], "bug_class": ["panic", "dos_loop_or_recursion"], "pre_version": "0.3.4", "post_version": "0.3.5", "stage": "diff_safe", "changed_files": ["src/chunks.rs"], "changed_lines": 31, "unsafe_in_changed_files": 98, "changed_functions": ["chunks::commit_unchecked"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": true, "translated": true, "error": null, "lean_lines": 299, "seconds": 4.7, "item_id": "adv-RUSTSEC-2026-0274", "kind": "advisory", "labels": {"buggy": "rtrb@0.3.4", "reference": "rtrb@0.3.5"}} +{"adv_id": "RUSTSEC-2026-0312", "crate": "x509-validator", "date": "2026-09-24", "url": "https://github.com/namecare/x509-validator/commit/da661f8ecee820e05d089a76ecb654ff52a2c987", "title": "Excluded iPAddress name constraints with an all-zero mask are not applied", "categories": ["crypto-failure"], "affected_functions": [], "bug_class": ["logic"], "pre_version": "0.3.0", "post_version": "0.3.1", "stage": "strict_safe", "changed_files": ["src/rfc5280/ip_constraints.rs"], "changed_lines": 34, "unsafe_in_changed_files": 0, "changed_functions": ["rfc5280::ip_constraints::is_valid_cidr_mask"], "charon_ok": true, "aeneas_ok": true, "fn_present": true, "lean_ok": true, "translated": true, "error": null, "lean_lines": 221, "seconds": 19.4, "item_id": "adv-RUSTSEC-2026-0312", "kind": "advisory", "labels": {"buggy": "x509-validator@0.3.0", "reference": "x509-validator@0.3.1"}} diff --git a/code/bugfind/bench/items/kernel_attempts.jsonl b/code/bugfind/bench/items/kernel_attempts.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..1eb9a144203b0c483afd6070b6fc52761f19f06e --- /dev/null +++ b/code/bugfind/bench/items/kernel_attempts.jsonl @@ -0,0 +1,23 @@ +{"item_id": "ker-bcrypt_split", "kernel": "bcrypt_split", "advisory": "RUSTSEC-2026-0199", "crate": "bcrypt", "pre_version": "0.19.1", "post_version": "0.19.2", "advisory_url": "https://github.com/Keats/rust-bcrypt/pull/103", "title": "Panic in `bcrypt::verify` on non-ASCII hash input", "source_file": "src/lib.rs", "function": "split_hash_salt_len", "signature": "pub fn split_hash_salt_len(hash: &[u8]) -> Result", "spec_doc": "Validates a bcrypt hash string and returns the salt length (22). A valid hash is exactly 60 ASCII bytes; every other input must give Err, never panic.", "bug_class": "panic", "fidelity": "model_of_std", "extraction_note": "src/lib.rs split_hash: &str slicing at a non-char-boundary on non-ASCII 60-byte input", "witness_args": "&[b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', 0xA3, b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a']", "labels": {"buggy": "bcrypt@0.19.1", "reference": "bcrypt@0.19.2"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "7d53f927725503b07907dc448e7c98313079394b1cd3febf577d94019e94ac69", "post_lean_sha256": "a9dae044f2c50150b97d1f91c9d02d9fd3c36c9a050b08f825c490bc066643d0", "witness_pre": "PANIC", "witness_post": "Err(2)", "discriminating": true, "kept": true} +{"item_id": "ker-bytes_reserve", "kernel": "bytes_reserve", "advisory": "RUSTSEC-2026-0007", "crate": "bytes", "pre_version": "1.11.0", "post_version": "1.11.1", "advisory_url": "https://github.com/tokio-rs/bytes/commit/d0293b0e35838123c51ca5dfdf468ecafee4398f", "title": "Integer overflow in `BytesMut::reserve`", "source_file": "src/bytes_mut.rs", "function": "reserve_fits", "signature": "pub fn reserve_fits(v_capacity: usize, new_cap: usize, offset: usize) -> bool", "spec_doc": "Decides whether a Vec-backed buffer with capacity v_capacity can serve a reserve request of new_cap bytes when the live window starts at offset; must be true iff v_capacity >= new_cap + offset in exact arithmetic.", "bug_class": "overflow", "fidelity": "verbatim_logic", "extraction_note": "src/bytes_mut.rs reserve_inner: new_cap + offset overflow", "witness_args": "10usize, usize::MAX, 1usize", "labels": {"buggy": "bytes@1.11.0", "reference": "bytes@1.11.1"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "7e96b2fcef4037173d24e1a5c00af53f14e932464e0e989d8ad824499cf6b4b1", "post_lean_sha256": "f0ffe2dc35ef8cfdedb1dd161c6c58dfc016c5f122fd204845b4ff02dfaccd26", "witness_pre": "PANIC", "witness_post": "false", "discriminating": true, "kept": true} +{"item_id": "ker-claxon_rice", "kernel": "claxon_rice", "advisory": "RUSTSEC-2018-0004", "crate": "claxon", "pre_version": "0.3.1", "post_version": "0.3.2", "advisory_url": "https://github.com/ruuda/claxon/commit/8f28ec275e412dd3af4f3cda460605512faf332c", "title": "Malicious input could cause uninitialized memory to be exposed", "source_file": "src/subframe.rs", "function": "rice_layout", "signature": "pub fn rice_layout(block_size: u16, order: u32, n_warm_up: u16) -> Result", "spec_doc": "Computes how many residual samples a FLAC Rice-coded subframe's 2^order partitions cover (order is a 4-bit field, so order > 15 is rejected with Err). On Ok(n), n must equal block_size (the partitions fill the block); otherwise return Err.", "bug_class": "logic", "fidelity": "verbatim_logic", "extraction_note": "src/subframe.rs decode_residual: block size not a multiple of 2^order left buffer tail uninitialised", "witness_args": "10u16, 2u32, 0u16", "labels": {"buggy": "claxon@0.3.1", "reference": "claxon@0.3.2"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "cdaba15895178577f58dd2225e2a1cb69a2d97026a1e048f89d8214e0712dfef", "post_lean_sha256": "1f7189a114350b6cc5d051c07bc9635e432a9acdfe4fc9261f6d8474a7e411f7", "witness_pre": "Ok(8)", "witness_post": "Err(2)", "discriminating": true, "kept": true} +{"item_id": "ker-ecdh_scalar", "kernel": "ecdh_scalar", "advisory": "RUSTSEC-2026-0023", "crate": "libcrux-ecdh", "pre_version": "0.0.5", "post_version": "0.0.6", "advisory_url": "https://github.com/cryspen/libcrux/pull/1301", "title": "X25519 secret validation did not check buffer length or clamping", "source_file": "src/ecdh.rs", "function": "validate_x25519_scalar", "signature": "pub fn validate_x25519_scalar(s: &[u8]) -> bool", "spec_doc": "Validates an X25519 secret scalar: must be exactly 32 bytes, not all zero, and clamped (low 3 bits of byte 0 clear, top bit of byte 31 clear, second-highest bit of byte 31 set).", "bug_class": "logic", "fidelity": "verbatim_logic", "extraction_note": "src/ecdh.rs validate_scalar: only checked all-zero", "witness_args": "&[1u8, 2, 3]", "labels": {"buggy": "libcrux-ecdh@0.0.5", "reference": "libcrux-ecdh@0.0.6"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "b722ec6b0e7c0cf6e0019198cff7de3ebe78a6013913cce2e51d7c74ba9f4048", "post_lean_sha256": "d1a6b256dc6cce87bca1afc47c15ab10724e4b5a676dba3774703b0f4b326fd1", "witness_pre": "true", "witness_post": "false", "discriminating": true, "kept": true} +{"item_id": "ker-evm_memset", "kernel": "evm_memset", "advisory": "RUSTSEC-2021-0066", "crate": "evm-core", "pre_version": "0.21.0", "post_version": "0.21.1", "advisory_url": "https://github.com/rust-blockchain/evm", "title": "Denial of service on EVM execution due to memory over-allocation", "source_file": "src/memory.rs", "function": "memory_set_len", "signature": "pub fn memory_set_len(cur_len: usize, offset: usize, value_len: usize, target_size: Option, limit: usize) -> Result", "spec_doc": "New length of EVM memory after writing value (value_len bytes) at offset, zero-padded to target_size (default value_len). Err if offset+target_size exceeds limit. Writing an empty value must not grow memory.", "bug_class": "dos_loop_or_recursion", "fidelity": "verbatim_logic", "extraction_note": "src/memory.rs Memory::set: empty value with large target_size over-allocates", "witness_args": "0usize, 0usize, 0usize, Some(1000usize), 1048576usize", "labels": {"buggy": "evm-core@0.21.0", "reference": "evm-core@0.21.1"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "d853c43e6b0bf2aa130f9144b9d98e3023723b905a77edc81058f14e23028cbd", "post_lean_sha256": "6cd5f64bfcceeaf8268969610d802f26a9dcfac33bd25388b0a94929773204ee", "witness_pre": "Ok(1000)", "witness_post": "Ok(0)", "discriminating": true, "kept": true} +{"item_id": "ker-exif_discard", "kernel": "exif_discard", "advisory": "RUSTSEC-2021-0143", "crate": "kamadak-exif", "pre_version": "0.5.2", "post_version": "0.5.3", "advisory_url": "https://github.com/kamadak/exif-rs/commit/1b05eab57e484cd7d576d4357b9cda7fdc57df8c", "title": "kamadak-exif DoS with untrusted PNG data", "source_file": "src/util.rs", "function": "discard_exact", "signature": "pub fn discard_exact(avail: usize, len: usize) -> Result", "spec_doc": "Models skipping len bytes of a reader that has only avail bytes: returns Ok(number of read rounds) when the reader had enough data, Err when it hits EOF early. Must terminate on every input.", "bug_class": "dos_loop_or_recursion", "fidelity": "verbatim_logic", "extraction_note": "src/util.rs discard_exact: spins forever at EOF (consume_len == 0)", "witness_args": "3usize, 10usize", "labels": {"buggy": "kamadak-exif@0.5.2", "reference": "kamadak-exif@0.5.3"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "c96464a9a2cc0fb97e16ab7b265fc0e661459f2abc94eec2e8701d1459ba8c67", "post_lean_sha256": "529e5e3afdf5ff1b27f120a50df8e6d6d63744b50d7145d2662ad59d56562854", "witness_pre": "HANG", "witness_post": "Err(1)", "discriminating": true, "kept": true} +{"item_id": "ker-matrix_power", "kernel": "matrix_power", "advisory": "RUSTSEC-2025-0065", "crate": "matrix-sdk-base", "pre_version": "0.14.0", "post_version": "0.14.1", "advisory_url": "https://github.com/matrix-org/matrix-rust-sdk/pull/5635", "title": "matrix-sdk-base: Panic in the `RoomMember::normalized_power_level()` method", "source_file": "src/room/members.rs", "function": "normalize_power_level", "signature": "pub fn normalize_power_level(power_level: i64, max_power_level: i64) -> i64", "spec_doc": "Scales a Matrix user power level (|power_level| < 2^53) to the range 0..=100 relative to max_power_level > 0.", "bug_class": "panic", "fidelity": "verbatim_logic", "extraction_note": "src/room/members.rs normalized_power_level: expect() on out-of-range Int when max_power_level is small", "witness_args": "9007199254740991i64, 1i64", "labels": {"buggy": "matrix-sdk-base@0.14.0", "reference": "matrix-sdk-base@0.14.1"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "5d5368f9f867a54b16589188c6adddbd82a663b7239985d2edc3845dded3a6e0", "post_lean_sha256": "5e5444c8e2f6e675cdd33a7aceee308866a3eaa40bfe6537a7b889f02239d125", "witness_pre": "PANIC", "witness_post": "100", "discriminating": true, "kept": true} +{"item_id": "ker-mldsa_hint", "kernel": "mldsa_hint", "advisory": "RUSTSEC-2026-0076", "crate": "libcrux-ml-dsa", "pre_version": "0.0.7", "post_version": "0.0.8", "advisory_url": "https://github.com/cryspen/libcrux/pull/1348", "title": "Panic in Signature Hint Decoding During Verification", "source_file": "src/encoding/signature.rs", "function": "hint_weight", "signature": "pub fn hint_weight(hint: &[u8], max_ones: usize, rows: usize) -> Option", "spec_doc": "Decodes the ML-DSA signature hint encoding: hint[..max_ones] are positions, hint[max_ones..max_ones+rows] are cumulative counts that must be non-decreasing and at most max_ones. Returns the sum of the hint bytes it consumed, or None for a malformed encoding. Must never panic on any input of length >= max_ones+rows.", "bug_class": "panic", "fidelity": "verbatim_logic", "extraction_note": "src/ml_dsa_generic.rs / encoding/signature.rs deserialize hint: checked previous instead of current against max_ones", "witness_args": "&[0u8, 0, 200], 2usize, 1usize", "labels": {"buggy": "libcrux-ml-dsa@0.0.7", "reference": "libcrux-ml-dsa@0.0.8"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "369de5ded1473ad360569f6bab10c6c0be5ee8f8015dcd8b06efa823e49f1539", "post_lean_sha256": "f6bcf49adef14b0ce4fd2e1751cd3294ea2749d0d1e7c96066fdc2fea6f33d14", "witness_pre": "PANIC", "witness_post": "None", "discriminating": true, "kept": true} +{"item_id": "ker-mldsa_norm", "kernel": "mldsa_norm", "advisory": "RUSTSEC-2026-0076", "crate": "libcrux-ml-dsa", "pre_version": "0.0.7", "post_version": "0.0.8", "advisory_url": "https://github.com/cryspen/libcrux/pull/1348", "title": "Panic in Signature Hint Decoding During Verification", "source_file": "src/ml_dsa_generic.rs", "function": "response_bound", "signature": "pub fn response_bound(gamma1_exponent: u32, beta: i32) -> i32", "spec_doc": "ML-DSA verification bound for the signer response: gamma1 - beta where gamma1 = 2^gamma1_exponent.", "bug_class": "logic", "fidelity": "verbatim_logic", "extraction_note": "src/ml_dsa_generic.rs verify: (2 << GAMMA1_EXPONENT) - BETA instead of (1 << ...) - BETA", "witness_args": "17u32, 78i32", "labels": {"buggy": "libcrux-ml-dsa@0.0.7", "reference": "libcrux-ml-dsa@0.0.8"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "b3aee20eb8775621568ec83f0b152929c78119ff61b7cc3154c4eb473c6c36cf", "post_lean_sha256": "43c47039869cf45f1f80300523602ae4633d7f8c8c1e0b9eebc4a237b47a1f61", "witness_pre": "262066", "witness_post": "130994", "discriminating": true, "kept": true} +{"item_id": "ker-nanoid_mask", "kernel": "nanoid_mask", "advisory": "RUSTSEC-2024-0343", "crate": "nano-id", "pre_version": "0.3.3", "post_version": "0.4.0", "advisory_url": null, "title": "Reduced entropy due to inadequate character set usage", "source_file": "src/lib.rs", "function": "alphabet_mask", "signature": "pub fn alphabet_mask(len: usize) -> usize", "spec_doc": "Bit mask used to index an alphabet of len symbols (len >= 2) from a random byte: the smallest all-ones value m with m >= len - 1, i.e. next_power_of_two(len) - 1.", "bug_class": "logic", "fidelity": "verbatim_logic", "extraction_note": "src/lib.rs MASK = $len - 1 is not a bit mask for non-power-of-two alphabets (biased/short alphabet)", "witness_args": "62usize", "labels": {"buggy": "nano-id@0.3.3", "reference": "nano-id@0.4.0"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "77f18cc6dec2889cb0be86e91faded65fb3020c33ddb75cad2695aa6a4d3e139", "post_lean_sha256": "87d440ff0746922e2532a2f00e718d79c58adec9f02783f532eede1096fdb740", "witness_pre": "61", "witness_post": "63", "discriminating": true, "kept": true} +{"item_id": "ker-nostr_iv", "kernel": "nostr_iv", "advisory": "RUSTSEC-2026-0219", "crate": "nostr", "pre_version": "0.44.5", "post_version": "0.44.6", "advisory_url": "https://github.com/nostrdevkit/nostr/commit/b24619346f666d08ef7fefe27f033b8bc871697f", "title": "Remote Denial of Service via malformed NIP-04 IV", "source_file": "src/nips/nip04.rs", "function": "load_iv", "signature": "pub fn load_iv(iv: &[u8]) -> Result<[u8; 16], u8>", "spec_doc": "Loads a NIP-04 AES-CBC initialisation vector from untrusted bytes; must return Err unless the input is exactly 16 bytes, and must never panic.", "bug_class": "panic", "fidelity": "model_of_std", "extraction_note": "src/nips/nip04.rs decrypt: iv.as_slice().into() panics on wrong length", "witness_args": "&[1u8, 2, 3]", "labels": {"buggy": "nostr@0.44.5", "reference": "nostr@0.44.6"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "d2a795acc975354b04b5e30e15a356353bda1fc461f2b814cf3b730780a9675d", "post_lean_sha256": "72b7f8d389dcab073d3ac0be3fd1b18dd366ce160083f09643bd79b1437278a1", "witness_pre": "PANIC", "witness_post": "Err(1)", "discriminating": true, "kept": true} +{"item_id": "ker-odoh_split", "kernel": "odoh_split", "advisory": "RUSTSEC-2023-0095", "crate": "odoh-rs", "pre_version": "1.0.1", "post_version": "1.0.2", "advisory_url": "https://github.com/cloudflare/odoh-rs/pull/28", "title": "Invalid Slice Split Results in Server Panic", "source_file": "src/protocol.rs", "function": "encrypted_payload_len", "signature": "pub fn encrypted_payload_len(msg: &[u8], key_size: usize) -> Result", "spec_doc": "Splits an encrypted ODoH query into an encapsulated key (first key_size bytes) and ciphertext (the rest); returns the ciphertext length, or Err if the message is shorter than key_size. Must not panic on any input.", "bug_class": "panic", "fidelity": "model_of_std", "extraction_note": "src/protocol.rs decrypt_query: split_at(key_size) without length check", "witness_args": "&[1u8, 2, 3], 32usize", "labels": {"buggy": "odoh-rs@1.0.1", "reference": "odoh-rs@1.0.2"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "ac94ea295289c87699352a11aa6bc83ee4a8b231ba8bc39842bd38fb69fe1a38", "post_lean_sha256": "4de24b5c9da44807587a71885ea633e86de8b62af2afa54441231eeb4f01676e", "witness_pre": "PANIC", "witness_post": "Err(1)", "discriminating": true, "kept": true} +{"item_id": "ker-phone_ctx", "kernel": "phone_ctx", "advisory": "RUSTSEC-2023-0082", "crate": "phonenumber", "pre_version": "0.2.4+8.11.3", "post_version": "0.2.5+8.11.3", "advisory_url": "https://github.com/whisperfish/rust-phonenumber/commit/2dd44be94539c051b4dee55d1d9d349bd7bedde6", "title": "phonenumber: panic on parsing crafted RF3966 phonenumber inputs ", "source_file": "src/parser/rfc3966.rs", "function": "context_prefix_skip", "signature": "pub fn context_prefix_skip(s: &[u8]) -> usize", "spec_doc": "Returns how many leading bytes of an RFC3966 phone-context value to skip: 1 if it starts with '+', otherwise 0. Must not panic on empty input.", "bug_class": "panic", "fidelity": "verbatim_logic", "extraction_note": "src/parser/rfc3966.rs: s.as_bytes()[0] on empty phone-context", "witness_args": "&[]", "labels": {"buggy": "phonenumber@0.2.4+8.11.3", "reference": "phonenumber@0.2.5+8.11.3"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "60b03cf485ff638f22e2345cc07a9c4fd7c95b89cdc485300af2a821dcb567bd", "post_lean_sha256": "14a0680b2a1b983868ebfd1b490faeab2f9f4bf091bdbc3b01176d7be1fb4ae1", "witness_pre": "PANIC", "witness_post": "0", "discriminating": true, "kept": true} +{"item_id": "ker-poly1305_key", "kernel": "poly1305_key", "advisory": "RUSTSEC-2026-0073", "crate": "libcrux-poly1305", "pre_version": "0.0.4", "post_version": "0.0.5", "advisory_url": "https://github.com/cryspen/libcrux/pull/1351", "title": "Panic in Standalone MAC Operations", "source_file": "src/lib.rs", "function": "key_len_ok", "signature": "pub fn key_len_ok(key: &[u8]) -> bool", "spec_doc": "Poly1305 one-time keys are r (16 bytes) followed by s (16 bytes): a key is acceptable iff it is exactly 32 bytes.", "bug_class": "logic", "fidelity": "verbatim_logic", "extraction_note": "src/lib.rs KEY_LEN = 16 (standalone mac rejected/panicked on real 32-byte keys)", "witness_args": "&[0u8; 32]", "labels": {"buggy": "libcrux-poly1305@0.0.4", "reference": "libcrux-poly1305@0.0.5"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "ba6fdb350c0200f1b43cced2a87f6f4ad6352c7a646c6587373950fdcb35c94c", "post_lean_sha256": "0b0a4c77ac465168c2da89b6a933d83773deeb3d9f358ef0c5ae5fbb2f41ebde", "witness_pre": "false", "witness_post": "true", "discriminating": true, "kept": true} +{"item_id": "ker-ring_ctr", "kernel": "ring_ctr", "advisory": "RUSTSEC-2025-0009", "crate": "ring", "pre_version": "0.17.11", "post_version": "0.17.12", "advisory_url": "https://github.com/briansmith/ring/blob/main/RELEASES.md#version-01712-2025-03-05", "title": "Some AES functions may panic when overflow checking is enabled.", "source_file": "src/aead/aes.rs", "function": "increment_by", "signature": "pub fn increment_by(old_value: u32, increment_by: u32) -> u32", "spec_doc": "Increments a 32-bit big-endian AES-GCM block counter, wrapping modulo 2^32.", "bug_class": "overflow", "fidelity": "verbatim_logic", "extraction_note": "src/aead/aes.rs increment_by_less_safe: + panics with overflow checks", "witness_args": "4294967295u32, 1u32", "labels": {"buggy": "ring@0.17.11", "reference": "ring@0.17.12"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "b554eb737dc075edf7b2082cfeea1e6b753e88f6b7efce128f68ac7abab266e8", "post_lean_sha256": "d2b224067bcf3c02a0e85c12ea97a00d53388eb99b58ecd88a330617f40d8711", "witness_pre": "PANIC", "witness_post": "0", "discriminating": true, "kept": true} +{"item_id": "ker-stack_insert", "kernel": "stack_insert", "advisory": "RUSTSEC-2020-0042", "crate": "stack", "pre_version": "0.3.0", "post_version": "0.3.1", "advisory_url": "https://github.com/arcnmx/stack-rs/issues/4", "title": "Missing check in ArrayVec leads to out-of-bounds write.", "source_file": "src/vector.rs", "function": "insert_shift_len", "signature": "pub fn insert_shift_len(len: usize, index: usize) -> Result", "spec_doc": "Number of elements to shift when inserting at index into a vector of length len; Err if index > len.", "bug_class": "panic", "fidelity": "model_of_std", "extraction_note": "src/vector.rs insert: missing index <= len assert; copy length len - index wrapped (release) -> OOB write", "witness_args": "3usize, 5usize", "labels": {"buggy": "stack@0.3.0", "reference": "stack@0.3.1"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "f49c341180a895e92e930e5a5fe2717f3d24acd62cf82b97cb738e3230f14e2f", "post_lean_sha256": "1b16c2fa9bbc4eea6282a0886308917418820adfb93839468c85d5f67e2b1aa7", "witness_pre": "Ok(18446744073709551614)", "witness_post": "Err(1)", "discriminating": true, "kept": true} +{"item_id": "ker-tar_pax", "kernel": "tar_pax", "advisory": "RUSTSEC-2026-0145", "crate": "astral-tokio-tar", "pre_version": "0.6.1", "post_version": "0.6.2", "advisory_url": "https://github.com/astral-sh/tokio-tar/pull/82", "title": "PAX Header Desynchronization in astral-tokio-tar", "source_file": "src/archive.rs", "function": "apply_pax", "signature": "pub fn apply_pax(entry_type: u8, has_pax: bool) -> bool", "spec_doc": "PAX extended-header data describes the next file entry. Returns whether pending PAX data must be applied to a header of the given type byte: only for real entries, never for GNU long-name 'L', long-link 'K', PAX local 'x' or global 'g' headers.", "bug_class": "logic", "fidelity": "verbatim_logic", "extraction_note": "src/archive.rs: PAX data applied to extension headers (desynchronisation)", "witness_args": "b'L', true", "labels": {"buggy": "astral-tokio-tar@0.6.1", "reference": "astral-tokio-tar@0.6.2"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "82e7ef8d01c7e3f93ef8f93102d323947a0abe2dc49e5d053d2bf885ca7bb8c9", "post_lean_sha256": "301bca5019525ab0aa07d847b9523d4302b32aaea5a0784678691452db6386fd", "witness_pre": "true", "witness_post": "false", "discriminating": true, "kept": true} +{"item_id": "ker-tinyhttp_hdr", "kernel": "tinyhttp_hdr", "advisory": "RUSTSEC-2020-0031", "crate": "tiny_http", "pre_version": "0.6.2", "post_version": "0.6.3", "advisory_url": "https://github.com/tiny-http/tiny-http/issues/173", "title": "HTTP Request smuggling through malformed Transfer Encoding headers", "source_file": "src/common.rs", "function": "header_field_ok", "signature": "pub fn header_field_ok(s: &[u8]) -> bool", "spec_doc": "A header field name is valid iff it is ASCII and contains no whitespace (no trimming: ' Transfer-Encoding' and 'Transfer-Encoding ' are invalid).", "bug_class": "logic", "fidelity": "verbatim_logic", "extraction_note": "src/common.rs HeaderField::from_str: trimmed whitespace (request smuggling)", "witness_args": "b\"Transfer-Encoding \"", "labels": {"buggy": "tiny_http@0.6.2", "reference": "tiny_http@0.6.3"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "cf98ac9dd721cc7955340dc00ca57e1a680d875dd70e958be2592c635a52531e", "post_lean_sha256": "d5790424f20d4118c7484ff00d33c36b395c29a780889dbaaa3736cf5a276ce3", "witness_pre": "true", "witness_post": "false", "discriminating": true, "kept": true} +{"item_id": "ker-toodee_drain", "kernel": "toodee_drain", "advisory": "RUSTSEC-2025-0062", "crate": "toodee", "pre_version": "0.5.0", "post_version": "0.6.0", "advisory_url": "https://github.com/antonmarsden/toodee/issues/26", "title": "Heap Buffer Overflow in the DrainCol Destructor", "source_file": "src/toodee.rs", "function": "drain_col_copy_len", "signature": "pub fn drain_col_copy_len(orig_cols: usize, col: usize) -> usize", "spec_doc": "When removing column col from a row of orig_cols cells, the number of cells to shift left: those strictly after col (orig_cols - col - 1).", "bug_class": "overflow", "fidelity": "verbatim_logic", "extraction_note": "src/toodee.rs DrainCol::drop: ptr::copy length off by one (heap overflow)", "witness_args": "5usize, 2usize", "labels": {"buggy": "toodee@0.5.0", "reference": "toodee@0.6.0"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "177f2dd0ea0c671940d625ad9a1b50cb362afa3394dd21c8388fb6fb53f1fe89", "post_lean_sha256": "37c476e752dccb574108426345b76c7fafd33920bc8a4021d9ccab72c334076b", "witness_pre": "3", "witness_post": "2", "discriminating": true, "kept": true} +{"item_id": "ker-tract_len", "kernel": "tract_len", "advisory": "RUSTSEC-2026-0217", "crate": "tract-nnef", "pre_version": "0.21.15", "post_version": "0.21.16", "advisory_url": "https://github.com/sonos/tract/commit/34c7df2c9bd2a36583e09b52f3e6319bf23102e8", "title": "Integer overflow in tract-nnef NNEF tensor parser leads to out-of-bounds read on model load", "source_file": "src/tensors.rs", "function": "tensor_len_ok", "signature": "pub fn tensor_len_ok(dims: &[usize], bits_per_item: usize, data_size_bytes: usize) -> bool", "spec_doc": "NNEF tensor header consistency: true iff prod(dims) * (bits_per_item / 8) == data_size_bytes in exact arithmetic (false if the product does not fit usize).", "bug_class": "overflow", "fidelity": "verbatim_logic", "extraction_note": "src/tensors.rs read_tensor: unchecked shape product", "witness_args": "&[4294967296usize, 4294967296], 8usize, 0usize", "labels": {"buggy": "tract-nnef@0.21.15", "reference": "tract-nnef@0.21.16"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "63477f85f9b3b7df5b1a724968985b2502a33e7c6fbd3737cba4e348bec40059", "post_lean_sha256": "37591104ba05a5128d5dde81dcafe9a12a3882a409f9aab0d7d52b6be4b4a0c0", "witness_pre": "PANIC", "witness_post": "false", "discriminating": true, "kept": true} +{"item_id": "ker-transpose_dims", "kernel": "transpose_dims", "advisory": "RUSTSEC-2023-0080", "crate": "transpose", "pre_version": "0.2.2", "post_version": "0.2.3", "advisory_url": "https://github.com/ejmahler/transpose/issues/11", "title": "Buffer overflow due to integer overflow in `transpose`", "source_file": "src/lib.rs", "function": "dims_match", "signature": "pub fn dims_match(width: usize, height: usize, len: usize) -> bool", "spec_doc": "True iff width * height == len in exact arithmetic (false when the product does not fit usize).", "bug_class": "overflow", "fidelity": "verbatim_logic", "extraction_note": "src/lib.rs transpose: assert_eq!(w*h, len) wraps in release -> buffer overflow", "witness_args": "4294967296usize, 4294967296usize, 0usize", "labels": {"buggy": "transpose@0.2.2", "reference": "transpose@0.2.3"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "17e06c374eed67fb6362fb4cf7fe66ee4f61912bba8afdb4119cd68e89757588", "post_lean_sha256": "f407c338d6bccc7635d18bedd7de51595dd214296a9fc30866ac897ecd8aa49f", "witness_pre": "PANIC", "witness_post": "false", "discriminating": true, "kept": true} +{"item_id": "ker-trustdns_ptr", "kernel": "trustdns_ptr", "advisory": "RUSTSEC-2018-0007", "crate": "trust-dns-proto", "pre_version": "0.4.2", "post_version": "0.4.3", "advisory_url": null, "title": "Stack overflow when parsing malicious DNS packet", "source_file": "src/rr/domain/name.rs", "function": "pointer_ok", "signature": "pub fn pointer_ok(location: usize, pointer_location: usize, name_start: usize) -> bool", "spec_doc": "A DNS name-compression pointer is acceptable iff its target lies strictly before the start of the name currently being parsed (so pointer chains cannot loop).", "bug_class": "dos_loop_or_recursion", "fidelity": "verbatim_logic", "extraction_note": "src/rr/domain/name.rs Name::read: pointer compared with current label instead of name start (self-referential name)", "witness_args": "0usize, 2usize, 0usize", "labels": {"buggy": "trust-dns-proto@0.4.2", "reference": "trust-dns-proto@0.4.3"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "d796b9b7a74e878ea4a98203892f1631ba8a7ca948b2df03fe1a2d6193d954c9", "post_lean_sha256": "dab0b1a20e96463fd38383d69b684d5cf07699fe2988d8ed0f32300ce5eafdf9", "witness_pre": "true", "witness_post": "false", "discriminating": true, "kept": true} +{"item_id": "ker-versionize_fam", "kernel": "versionize_fam", "advisory": "RUSTSEC-2023-0030", "crate": "versionize", "pre_version": "0.1.9", "post_version": "0.1.10", "advisory_url": "https://github.com/firecracker-microvm/versionize/pull/53", "title": "`Versionize::deserialize` implementation for `FamStructWrapper` is lacking bound checks, potentially leading to out of bounds memory accesses ", "source_file": "src/primitives.rs", "function": "fam_entry", "signature": "pub fn fam_entry(entries: &[u32], header_len: usize, i: usize) -> Result", "spec_doc": "Reads entry i (< header_len) of a deserialised flexible-array struct whose header declares header_len entries; Err if the header length disagrees with the actual number of entries, never panic.", "bug_class": "panic", "fidelity": "model_of_std", "extraction_note": "src/primitives.rs FamStructWrapper::deserialize: header length not checked against entries", "witness_args": "&[7u32, 8], 5usize, 3usize", "labels": {"buggy": "versionize@0.1.9", "reference": "versionize@0.1.10"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "3cff1a14db289fd5fe269b7cc9f226c934e0a288f303afcee251f6906eb577e7", "post_lean_sha256": "9b567f5bdf7efdc3b4b87d5db97c5f32560530074b9d8fe09b17bd4569d8cfda", "witness_pre": "PANIC", "witness_post": "Err(1)", "discriminating": true, "kept": true} diff --git a/code/bugfind/bench/items/kernel_items.jsonl b/code/bugfind/bench/items/kernel_items.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..1eb9a144203b0c483afd6070b6fc52761f19f06e --- /dev/null +++ b/code/bugfind/bench/items/kernel_items.jsonl @@ -0,0 +1,23 @@ +{"item_id": "ker-bcrypt_split", "kernel": "bcrypt_split", "advisory": "RUSTSEC-2026-0199", "crate": "bcrypt", "pre_version": "0.19.1", "post_version": "0.19.2", "advisory_url": "https://github.com/Keats/rust-bcrypt/pull/103", "title": "Panic in `bcrypt::verify` on non-ASCII hash input", "source_file": "src/lib.rs", "function": "split_hash_salt_len", "signature": "pub fn split_hash_salt_len(hash: &[u8]) -> Result", "spec_doc": "Validates a bcrypt hash string and returns the salt length (22). A valid hash is exactly 60 ASCII bytes; every other input must give Err, never panic.", "bug_class": "panic", "fidelity": "model_of_std", "extraction_note": "src/lib.rs split_hash: &str slicing at a non-char-boundary on non-ASCII 60-byte input", "witness_args": "&[b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', 0xA3, b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a']", "labels": {"buggy": "bcrypt@0.19.1", "reference": "bcrypt@0.19.2"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "7d53f927725503b07907dc448e7c98313079394b1cd3febf577d94019e94ac69", "post_lean_sha256": "a9dae044f2c50150b97d1f91c9d02d9fd3c36c9a050b08f825c490bc066643d0", "witness_pre": "PANIC", "witness_post": "Err(2)", "discriminating": true, "kept": true} +{"item_id": "ker-bytes_reserve", "kernel": "bytes_reserve", "advisory": "RUSTSEC-2026-0007", "crate": "bytes", "pre_version": "1.11.0", "post_version": "1.11.1", "advisory_url": "https://github.com/tokio-rs/bytes/commit/d0293b0e35838123c51ca5dfdf468ecafee4398f", "title": "Integer overflow in `BytesMut::reserve`", "source_file": "src/bytes_mut.rs", "function": "reserve_fits", "signature": "pub fn reserve_fits(v_capacity: usize, new_cap: usize, offset: usize) -> bool", "spec_doc": "Decides whether a Vec-backed buffer with capacity v_capacity can serve a reserve request of new_cap bytes when the live window starts at offset; must be true iff v_capacity >= new_cap + offset in exact arithmetic.", "bug_class": "overflow", "fidelity": "verbatim_logic", "extraction_note": "src/bytes_mut.rs reserve_inner: new_cap + offset overflow", "witness_args": "10usize, usize::MAX, 1usize", "labels": {"buggy": "bytes@1.11.0", "reference": "bytes@1.11.1"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "7e96b2fcef4037173d24e1a5c00af53f14e932464e0e989d8ad824499cf6b4b1", "post_lean_sha256": "f0ffe2dc35ef8cfdedb1dd161c6c58dfc016c5f122fd204845b4ff02dfaccd26", "witness_pre": "PANIC", "witness_post": "false", "discriminating": true, "kept": true} +{"item_id": "ker-claxon_rice", "kernel": "claxon_rice", "advisory": "RUSTSEC-2018-0004", "crate": "claxon", "pre_version": "0.3.1", "post_version": "0.3.2", "advisory_url": "https://github.com/ruuda/claxon/commit/8f28ec275e412dd3af4f3cda460605512faf332c", "title": "Malicious input could cause uninitialized memory to be exposed", "source_file": "src/subframe.rs", "function": "rice_layout", "signature": "pub fn rice_layout(block_size: u16, order: u32, n_warm_up: u16) -> Result", "spec_doc": "Computes how many residual samples a FLAC Rice-coded subframe's 2^order partitions cover (order is a 4-bit field, so order > 15 is rejected with Err). On Ok(n), n must equal block_size (the partitions fill the block); otherwise return Err.", "bug_class": "logic", "fidelity": "verbatim_logic", "extraction_note": "src/subframe.rs decode_residual: block size not a multiple of 2^order left buffer tail uninitialised", "witness_args": "10u16, 2u32, 0u16", "labels": {"buggy": "claxon@0.3.1", "reference": "claxon@0.3.2"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "cdaba15895178577f58dd2225e2a1cb69a2d97026a1e048f89d8214e0712dfef", "post_lean_sha256": "1f7189a114350b6cc5d051c07bc9635e432a9acdfe4fc9261f6d8474a7e411f7", "witness_pre": "Ok(8)", "witness_post": "Err(2)", "discriminating": true, "kept": true} +{"item_id": "ker-ecdh_scalar", "kernel": "ecdh_scalar", "advisory": "RUSTSEC-2026-0023", "crate": "libcrux-ecdh", "pre_version": "0.0.5", "post_version": "0.0.6", "advisory_url": "https://github.com/cryspen/libcrux/pull/1301", "title": "X25519 secret validation did not check buffer length or clamping", "source_file": "src/ecdh.rs", "function": "validate_x25519_scalar", "signature": "pub fn validate_x25519_scalar(s: &[u8]) -> bool", "spec_doc": "Validates an X25519 secret scalar: must be exactly 32 bytes, not all zero, and clamped (low 3 bits of byte 0 clear, top bit of byte 31 clear, second-highest bit of byte 31 set).", "bug_class": "logic", "fidelity": "verbatim_logic", "extraction_note": "src/ecdh.rs validate_scalar: only checked all-zero", "witness_args": "&[1u8, 2, 3]", "labels": {"buggy": "libcrux-ecdh@0.0.5", "reference": "libcrux-ecdh@0.0.6"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "b722ec6b0e7c0cf6e0019198cff7de3ebe78a6013913cce2e51d7c74ba9f4048", "post_lean_sha256": "d1a6b256dc6cce87bca1afc47c15ab10724e4b5a676dba3774703b0f4b326fd1", "witness_pre": "true", "witness_post": "false", "discriminating": true, "kept": true} +{"item_id": "ker-evm_memset", "kernel": "evm_memset", "advisory": "RUSTSEC-2021-0066", "crate": "evm-core", "pre_version": "0.21.0", "post_version": "0.21.1", "advisory_url": "https://github.com/rust-blockchain/evm", "title": "Denial of service on EVM execution due to memory over-allocation", "source_file": "src/memory.rs", "function": "memory_set_len", "signature": "pub fn memory_set_len(cur_len: usize, offset: usize, value_len: usize, target_size: Option, limit: usize) -> Result", "spec_doc": "New length of EVM memory after writing value (value_len bytes) at offset, zero-padded to target_size (default value_len). Err if offset+target_size exceeds limit. Writing an empty value must not grow memory.", "bug_class": "dos_loop_or_recursion", "fidelity": "verbatim_logic", "extraction_note": "src/memory.rs Memory::set: empty value with large target_size over-allocates", "witness_args": "0usize, 0usize, 0usize, Some(1000usize), 1048576usize", "labels": {"buggy": "evm-core@0.21.0", "reference": "evm-core@0.21.1"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "d853c43e6b0bf2aa130f9144b9d98e3023723b905a77edc81058f14e23028cbd", "post_lean_sha256": "6cd5f64bfcceeaf8268969610d802f26a9dcfac33bd25388b0a94929773204ee", "witness_pre": "Ok(1000)", "witness_post": "Ok(0)", "discriminating": true, "kept": true} +{"item_id": "ker-exif_discard", "kernel": "exif_discard", "advisory": "RUSTSEC-2021-0143", "crate": "kamadak-exif", "pre_version": "0.5.2", "post_version": "0.5.3", "advisory_url": "https://github.com/kamadak/exif-rs/commit/1b05eab57e484cd7d576d4357b9cda7fdc57df8c", "title": "kamadak-exif DoS with untrusted PNG data", "source_file": "src/util.rs", "function": "discard_exact", "signature": "pub fn discard_exact(avail: usize, len: usize) -> Result", "spec_doc": "Models skipping len bytes of a reader that has only avail bytes: returns Ok(number of read rounds) when the reader had enough data, Err when it hits EOF early. Must terminate on every input.", "bug_class": "dos_loop_or_recursion", "fidelity": "verbatim_logic", "extraction_note": "src/util.rs discard_exact: spins forever at EOF (consume_len == 0)", "witness_args": "3usize, 10usize", "labels": {"buggy": "kamadak-exif@0.5.2", "reference": "kamadak-exif@0.5.3"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "c96464a9a2cc0fb97e16ab7b265fc0e661459f2abc94eec2e8701d1459ba8c67", "post_lean_sha256": "529e5e3afdf5ff1b27f120a50df8e6d6d63744b50d7145d2662ad59d56562854", "witness_pre": "HANG", "witness_post": "Err(1)", "discriminating": true, "kept": true} +{"item_id": "ker-matrix_power", "kernel": "matrix_power", "advisory": "RUSTSEC-2025-0065", "crate": "matrix-sdk-base", "pre_version": "0.14.0", "post_version": "0.14.1", "advisory_url": "https://github.com/matrix-org/matrix-rust-sdk/pull/5635", "title": "matrix-sdk-base: Panic in the `RoomMember::normalized_power_level()` method", "source_file": "src/room/members.rs", "function": "normalize_power_level", "signature": "pub fn normalize_power_level(power_level: i64, max_power_level: i64) -> i64", "spec_doc": "Scales a Matrix user power level (|power_level| < 2^53) to the range 0..=100 relative to max_power_level > 0.", "bug_class": "panic", "fidelity": "verbatim_logic", "extraction_note": "src/room/members.rs normalized_power_level: expect() on out-of-range Int when max_power_level is small", "witness_args": "9007199254740991i64, 1i64", "labels": {"buggy": "matrix-sdk-base@0.14.0", "reference": "matrix-sdk-base@0.14.1"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "5d5368f9f867a54b16589188c6adddbd82a663b7239985d2edc3845dded3a6e0", "post_lean_sha256": "5e5444c8e2f6e675cdd33a7aceee308866a3eaa40bfe6537a7b889f02239d125", "witness_pre": "PANIC", "witness_post": "100", "discriminating": true, "kept": true} +{"item_id": "ker-mldsa_hint", "kernel": "mldsa_hint", "advisory": "RUSTSEC-2026-0076", "crate": "libcrux-ml-dsa", "pre_version": "0.0.7", "post_version": "0.0.8", "advisory_url": "https://github.com/cryspen/libcrux/pull/1348", "title": "Panic in Signature Hint Decoding During Verification", "source_file": "src/encoding/signature.rs", "function": "hint_weight", "signature": "pub fn hint_weight(hint: &[u8], max_ones: usize, rows: usize) -> Option", "spec_doc": "Decodes the ML-DSA signature hint encoding: hint[..max_ones] are positions, hint[max_ones..max_ones+rows] are cumulative counts that must be non-decreasing and at most max_ones. Returns the sum of the hint bytes it consumed, or None for a malformed encoding. Must never panic on any input of length >= max_ones+rows.", "bug_class": "panic", "fidelity": "verbatim_logic", "extraction_note": "src/ml_dsa_generic.rs / encoding/signature.rs deserialize hint: checked previous instead of current against max_ones", "witness_args": "&[0u8, 0, 200], 2usize, 1usize", "labels": {"buggy": "libcrux-ml-dsa@0.0.7", "reference": "libcrux-ml-dsa@0.0.8"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "369de5ded1473ad360569f6bab10c6c0be5ee8f8015dcd8b06efa823e49f1539", "post_lean_sha256": "f6bcf49adef14b0ce4fd2e1751cd3294ea2749d0d1e7c96066fdc2fea6f33d14", "witness_pre": "PANIC", "witness_post": "None", "discriminating": true, "kept": true} +{"item_id": "ker-mldsa_norm", "kernel": "mldsa_norm", "advisory": "RUSTSEC-2026-0076", "crate": "libcrux-ml-dsa", "pre_version": "0.0.7", "post_version": "0.0.8", "advisory_url": "https://github.com/cryspen/libcrux/pull/1348", "title": "Panic in Signature Hint Decoding During Verification", "source_file": "src/ml_dsa_generic.rs", "function": "response_bound", "signature": "pub fn response_bound(gamma1_exponent: u32, beta: i32) -> i32", "spec_doc": "ML-DSA verification bound for the signer response: gamma1 - beta where gamma1 = 2^gamma1_exponent.", "bug_class": "logic", "fidelity": "verbatim_logic", "extraction_note": "src/ml_dsa_generic.rs verify: (2 << GAMMA1_EXPONENT) - BETA instead of (1 << ...) - BETA", "witness_args": "17u32, 78i32", "labels": {"buggy": "libcrux-ml-dsa@0.0.7", "reference": "libcrux-ml-dsa@0.0.8"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "b3aee20eb8775621568ec83f0b152929c78119ff61b7cc3154c4eb473c6c36cf", "post_lean_sha256": "43c47039869cf45f1f80300523602ae4633d7f8c8c1e0b9eebc4a237b47a1f61", "witness_pre": "262066", "witness_post": "130994", "discriminating": true, "kept": true} +{"item_id": "ker-nanoid_mask", "kernel": "nanoid_mask", "advisory": "RUSTSEC-2024-0343", "crate": "nano-id", "pre_version": "0.3.3", "post_version": "0.4.0", "advisory_url": null, "title": "Reduced entropy due to inadequate character set usage", "source_file": "src/lib.rs", "function": "alphabet_mask", "signature": "pub fn alphabet_mask(len: usize) -> usize", "spec_doc": "Bit mask used to index an alphabet of len symbols (len >= 2) from a random byte: the smallest all-ones value m with m >= len - 1, i.e. next_power_of_two(len) - 1.", "bug_class": "logic", "fidelity": "verbatim_logic", "extraction_note": "src/lib.rs MASK = $len - 1 is not a bit mask for non-power-of-two alphabets (biased/short alphabet)", "witness_args": "62usize", "labels": {"buggy": "nano-id@0.3.3", "reference": "nano-id@0.4.0"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "77f18cc6dec2889cb0be86e91faded65fb3020c33ddb75cad2695aa6a4d3e139", "post_lean_sha256": "87d440ff0746922e2532a2f00e718d79c58adec9f02783f532eede1096fdb740", "witness_pre": "61", "witness_post": "63", "discriminating": true, "kept": true} +{"item_id": "ker-nostr_iv", "kernel": "nostr_iv", "advisory": "RUSTSEC-2026-0219", "crate": "nostr", "pre_version": "0.44.5", "post_version": "0.44.6", "advisory_url": "https://github.com/nostrdevkit/nostr/commit/b24619346f666d08ef7fefe27f033b8bc871697f", "title": "Remote Denial of Service via malformed NIP-04 IV", "source_file": "src/nips/nip04.rs", "function": "load_iv", "signature": "pub fn load_iv(iv: &[u8]) -> Result<[u8; 16], u8>", "spec_doc": "Loads a NIP-04 AES-CBC initialisation vector from untrusted bytes; must return Err unless the input is exactly 16 bytes, and must never panic.", "bug_class": "panic", "fidelity": "model_of_std", "extraction_note": "src/nips/nip04.rs decrypt: iv.as_slice().into() panics on wrong length", "witness_args": "&[1u8, 2, 3]", "labels": {"buggy": "nostr@0.44.5", "reference": "nostr@0.44.6"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "d2a795acc975354b04b5e30e15a356353bda1fc461f2b814cf3b730780a9675d", "post_lean_sha256": "72b7f8d389dcab073d3ac0be3fd1b18dd366ce160083f09643bd79b1437278a1", "witness_pre": "PANIC", "witness_post": "Err(1)", "discriminating": true, "kept": true} +{"item_id": "ker-odoh_split", "kernel": "odoh_split", "advisory": "RUSTSEC-2023-0095", "crate": "odoh-rs", "pre_version": "1.0.1", "post_version": "1.0.2", "advisory_url": "https://github.com/cloudflare/odoh-rs/pull/28", "title": "Invalid Slice Split Results in Server Panic", "source_file": "src/protocol.rs", "function": "encrypted_payload_len", "signature": "pub fn encrypted_payload_len(msg: &[u8], key_size: usize) -> Result", "spec_doc": "Splits an encrypted ODoH query into an encapsulated key (first key_size bytes) and ciphertext (the rest); returns the ciphertext length, or Err if the message is shorter than key_size. Must not panic on any input.", "bug_class": "panic", "fidelity": "model_of_std", "extraction_note": "src/protocol.rs decrypt_query: split_at(key_size) without length check", "witness_args": "&[1u8, 2, 3], 32usize", "labels": {"buggy": "odoh-rs@1.0.1", "reference": "odoh-rs@1.0.2"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "ac94ea295289c87699352a11aa6bc83ee4a8b231ba8bc39842bd38fb69fe1a38", "post_lean_sha256": "4de24b5c9da44807587a71885ea633e86de8b62af2afa54441231eeb4f01676e", "witness_pre": "PANIC", "witness_post": "Err(1)", "discriminating": true, "kept": true} +{"item_id": "ker-phone_ctx", "kernel": "phone_ctx", "advisory": "RUSTSEC-2023-0082", "crate": "phonenumber", "pre_version": "0.2.4+8.11.3", "post_version": "0.2.5+8.11.3", "advisory_url": "https://github.com/whisperfish/rust-phonenumber/commit/2dd44be94539c051b4dee55d1d9d349bd7bedde6", "title": "phonenumber: panic on parsing crafted RF3966 phonenumber inputs ", "source_file": "src/parser/rfc3966.rs", "function": "context_prefix_skip", "signature": "pub fn context_prefix_skip(s: &[u8]) -> usize", "spec_doc": "Returns how many leading bytes of an RFC3966 phone-context value to skip: 1 if it starts with '+', otherwise 0. Must not panic on empty input.", "bug_class": "panic", "fidelity": "verbatim_logic", "extraction_note": "src/parser/rfc3966.rs: s.as_bytes()[0] on empty phone-context", "witness_args": "&[]", "labels": {"buggy": "phonenumber@0.2.4+8.11.3", "reference": "phonenumber@0.2.5+8.11.3"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "60b03cf485ff638f22e2345cc07a9c4fd7c95b89cdc485300af2a821dcb567bd", "post_lean_sha256": "14a0680b2a1b983868ebfd1b490faeab2f9f4bf091bdbc3b01176d7be1fb4ae1", "witness_pre": "PANIC", "witness_post": "0", "discriminating": true, "kept": true} +{"item_id": "ker-poly1305_key", "kernel": "poly1305_key", "advisory": "RUSTSEC-2026-0073", "crate": "libcrux-poly1305", "pre_version": "0.0.4", "post_version": "0.0.5", "advisory_url": "https://github.com/cryspen/libcrux/pull/1351", "title": "Panic in Standalone MAC Operations", "source_file": "src/lib.rs", "function": "key_len_ok", "signature": "pub fn key_len_ok(key: &[u8]) -> bool", "spec_doc": "Poly1305 one-time keys are r (16 bytes) followed by s (16 bytes): a key is acceptable iff it is exactly 32 bytes.", "bug_class": "logic", "fidelity": "verbatim_logic", "extraction_note": "src/lib.rs KEY_LEN = 16 (standalone mac rejected/panicked on real 32-byte keys)", "witness_args": "&[0u8; 32]", "labels": {"buggy": "libcrux-poly1305@0.0.4", "reference": "libcrux-poly1305@0.0.5"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "ba6fdb350c0200f1b43cced2a87f6f4ad6352c7a646c6587373950fdcb35c94c", "post_lean_sha256": "0b0a4c77ac465168c2da89b6a933d83773deeb3d9f358ef0c5ae5fbb2f41ebde", "witness_pre": "false", "witness_post": "true", "discriminating": true, "kept": true} +{"item_id": "ker-ring_ctr", "kernel": "ring_ctr", "advisory": "RUSTSEC-2025-0009", "crate": "ring", "pre_version": "0.17.11", "post_version": "0.17.12", "advisory_url": "https://github.com/briansmith/ring/blob/main/RELEASES.md#version-01712-2025-03-05", "title": "Some AES functions may panic when overflow checking is enabled.", "source_file": "src/aead/aes.rs", "function": "increment_by", "signature": "pub fn increment_by(old_value: u32, increment_by: u32) -> u32", "spec_doc": "Increments a 32-bit big-endian AES-GCM block counter, wrapping modulo 2^32.", "bug_class": "overflow", "fidelity": "verbatim_logic", "extraction_note": "src/aead/aes.rs increment_by_less_safe: + panics with overflow checks", "witness_args": "4294967295u32, 1u32", "labels": {"buggy": "ring@0.17.11", "reference": "ring@0.17.12"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "b554eb737dc075edf7b2082cfeea1e6b753e88f6b7efce128f68ac7abab266e8", "post_lean_sha256": "d2b224067bcf3c02a0e85c12ea97a00d53388eb99b58ecd88a330617f40d8711", "witness_pre": "PANIC", "witness_post": "0", "discriminating": true, "kept": true} +{"item_id": "ker-stack_insert", "kernel": "stack_insert", "advisory": "RUSTSEC-2020-0042", "crate": "stack", "pre_version": "0.3.0", "post_version": "0.3.1", "advisory_url": "https://github.com/arcnmx/stack-rs/issues/4", "title": "Missing check in ArrayVec leads to out-of-bounds write.", "source_file": "src/vector.rs", "function": "insert_shift_len", "signature": "pub fn insert_shift_len(len: usize, index: usize) -> Result", "spec_doc": "Number of elements to shift when inserting at index into a vector of length len; Err if index > len.", "bug_class": "panic", "fidelity": "model_of_std", "extraction_note": "src/vector.rs insert: missing index <= len assert; copy length len - index wrapped (release) -> OOB write", "witness_args": "3usize, 5usize", "labels": {"buggy": "stack@0.3.0", "reference": "stack@0.3.1"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "f49c341180a895e92e930e5a5fe2717f3d24acd62cf82b97cb738e3230f14e2f", "post_lean_sha256": "1b16c2fa9bbc4eea6282a0886308917418820adfb93839468c85d5f67e2b1aa7", "witness_pre": "Ok(18446744073709551614)", "witness_post": "Err(1)", "discriminating": true, "kept": true} +{"item_id": "ker-tar_pax", "kernel": "tar_pax", "advisory": "RUSTSEC-2026-0145", "crate": "astral-tokio-tar", "pre_version": "0.6.1", "post_version": "0.6.2", "advisory_url": "https://github.com/astral-sh/tokio-tar/pull/82", "title": "PAX Header Desynchronization in astral-tokio-tar", "source_file": "src/archive.rs", "function": "apply_pax", "signature": "pub fn apply_pax(entry_type: u8, has_pax: bool) -> bool", "spec_doc": "PAX extended-header data describes the next file entry. Returns whether pending PAX data must be applied to a header of the given type byte: only for real entries, never for GNU long-name 'L', long-link 'K', PAX local 'x' or global 'g' headers.", "bug_class": "logic", "fidelity": "verbatim_logic", "extraction_note": "src/archive.rs: PAX data applied to extension headers (desynchronisation)", "witness_args": "b'L', true", "labels": {"buggy": "astral-tokio-tar@0.6.1", "reference": "astral-tokio-tar@0.6.2"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "82e7ef8d01c7e3f93ef8f93102d323947a0abe2dc49e5d053d2bf885ca7bb8c9", "post_lean_sha256": "301bca5019525ab0aa07d847b9523d4302b32aaea5a0784678691452db6386fd", "witness_pre": "true", "witness_post": "false", "discriminating": true, "kept": true} +{"item_id": "ker-tinyhttp_hdr", "kernel": "tinyhttp_hdr", "advisory": "RUSTSEC-2020-0031", "crate": "tiny_http", "pre_version": "0.6.2", "post_version": "0.6.3", "advisory_url": "https://github.com/tiny-http/tiny-http/issues/173", "title": "HTTP Request smuggling through malformed Transfer Encoding headers", "source_file": "src/common.rs", "function": "header_field_ok", "signature": "pub fn header_field_ok(s: &[u8]) -> bool", "spec_doc": "A header field name is valid iff it is ASCII and contains no whitespace (no trimming: ' Transfer-Encoding' and 'Transfer-Encoding ' are invalid).", "bug_class": "logic", "fidelity": "verbatim_logic", "extraction_note": "src/common.rs HeaderField::from_str: trimmed whitespace (request smuggling)", "witness_args": "b\"Transfer-Encoding \"", "labels": {"buggy": "tiny_http@0.6.2", "reference": "tiny_http@0.6.3"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "cf98ac9dd721cc7955340dc00ca57e1a680d875dd70e958be2592c635a52531e", "post_lean_sha256": "d5790424f20d4118c7484ff00d33c36b395c29a780889dbaaa3736cf5a276ce3", "witness_pre": "true", "witness_post": "false", "discriminating": true, "kept": true} +{"item_id": "ker-toodee_drain", "kernel": "toodee_drain", "advisory": "RUSTSEC-2025-0062", "crate": "toodee", "pre_version": "0.5.0", "post_version": "0.6.0", "advisory_url": "https://github.com/antonmarsden/toodee/issues/26", "title": "Heap Buffer Overflow in the DrainCol Destructor", "source_file": "src/toodee.rs", "function": "drain_col_copy_len", "signature": "pub fn drain_col_copy_len(orig_cols: usize, col: usize) -> usize", "spec_doc": "When removing column col from a row of orig_cols cells, the number of cells to shift left: those strictly after col (orig_cols - col - 1).", "bug_class": "overflow", "fidelity": "verbatim_logic", "extraction_note": "src/toodee.rs DrainCol::drop: ptr::copy length off by one (heap overflow)", "witness_args": "5usize, 2usize", "labels": {"buggy": "toodee@0.5.0", "reference": "toodee@0.6.0"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "177f2dd0ea0c671940d625ad9a1b50cb362afa3394dd21c8388fb6fb53f1fe89", "post_lean_sha256": "37c476e752dccb574108426345b76c7fafd33920bc8a4021d9ccab72c334076b", "witness_pre": "3", "witness_post": "2", "discriminating": true, "kept": true} +{"item_id": "ker-tract_len", "kernel": "tract_len", "advisory": "RUSTSEC-2026-0217", "crate": "tract-nnef", "pre_version": "0.21.15", "post_version": "0.21.16", "advisory_url": "https://github.com/sonos/tract/commit/34c7df2c9bd2a36583e09b52f3e6319bf23102e8", "title": "Integer overflow in tract-nnef NNEF tensor parser leads to out-of-bounds read on model load", "source_file": "src/tensors.rs", "function": "tensor_len_ok", "signature": "pub fn tensor_len_ok(dims: &[usize], bits_per_item: usize, data_size_bytes: usize) -> bool", "spec_doc": "NNEF tensor header consistency: true iff prod(dims) * (bits_per_item / 8) == data_size_bytes in exact arithmetic (false if the product does not fit usize).", "bug_class": "overflow", "fidelity": "verbatim_logic", "extraction_note": "src/tensors.rs read_tensor: unchecked shape product", "witness_args": "&[4294967296usize, 4294967296], 8usize, 0usize", "labels": {"buggy": "tract-nnef@0.21.15", "reference": "tract-nnef@0.21.16"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "63477f85f9b3b7df5b1a724968985b2502a33e7c6fbd3737cba4e348bec40059", "post_lean_sha256": "37591104ba05a5128d5dde81dcafe9a12a3882a409f9aab0d7d52b6be4b4a0c0", "witness_pre": "PANIC", "witness_post": "false", "discriminating": true, "kept": true} +{"item_id": "ker-transpose_dims", "kernel": "transpose_dims", "advisory": "RUSTSEC-2023-0080", "crate": "transpose", "pre_version": "0.2.2", "post_version": "0.2.3", "advisory_url": "https://github.com/ejmahler/transpose/issues/11", "title": "Buffer overflow due to integer overflow in `transpose`", "source_file": "src/lib.rs", "function": "dims_match", "signature": "pub fn dims_match(width: usize, height: usize, len: usize) -> bool", "spec_doc": "True iff width * height == len in exact arithmetic (false when the product does not fit usize).", "bug_class": "overflow", "fidelity": "verbatim_logic", "extraction_note": "src/lib.rs transpose: assert_eq!(w*h, len) wraps in release -> buffer overflow", "witness_args": "4294967296usize, 4294967296usize, 0usize", "labels": {"buggy": "transpose@0.2.2", "reference": "transpose@0.2.3"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "17e06c374eed67fb6362fb4cf7fe66ee4f61912bba8afdb4119cd68e89757588", "post_lean_sha256": "f407c338d6bccc7635d18bedd7de51595dd214296a9fc30866ac897ecd8aa49f", "witness_pre": "PANIC", "witness_post": "false", "discriminating": true, "kept": true} +{"item_id": "ker-trustdns_ptr", "kernel": "trustdns_ptr", "advisory": "RUSTSEC-2018-0007", "crate": "trust-dns-proto", "pre_version": "0.4.2", "post_version": "0.4.3", "advisory_url": null, "title": "Stack overflow when parsing malicious DNS packet", "source_file": "src/rr/domain/name.rs", "function": "pointer_ok", "signature": "pub fn pointer_ok(location: usize, pointer_location: usize, name_start: usize) -> bool", "spec_doc": "A DNS name-compression pointer is acceptable iff its target lies strictly before the start of the name currently being parsed (so pointer chains cannot loop).", "bug_class": "dos_loop_or_recursion", "fidelity": "verbatim_logic", "extraction_note": "src/rr/domain/name.rs Name::read: pointer compared with current label instead of name start (self-referential name)", "witness_args": "0usize, 2usize, 0usize", "labels": {"buggy": "trust-dns-proto@0.4.2", "reference": "trust-dns-proto@0.4.3"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "d796b9b7a74e878ea4a98203892f1631ba8a7ca948b2df03fe1a2d6193d954c9", "post_lean_sha256": "dab0b1a20e96463fd38383d69b684d5cf07699fe2988d8ed0f32300ce5eafdf9", "witness_pre": "true", "witness_post": "false", "discriminating": true, "kept": true} +{"item_id": "ker-versionize_fam", "kernel": "versionize_fam", "advisory": "RUSTSEC-2023-0030", "crate": "versionize", "pre_version": "0.1.9", "post_version": "0.1.10", "advisory_url": "https://github.com/firecracker-microvm/versionize/pull/53", "title": "`Versionize::deserialize` implementation for `FamStructWrapper` is lacking bound checks, potentially leading to out of bounds memory accesses ", "source_file": "src/primitives.rs", "function": "fam_entry", "signature": "pub fn fam_entry(entries: &[u32], header_len: usize, i: usize) -> Result", "spec_doc": "Reads entry i (< header_len) of a deserialised flexible-array struct whose header declares header_len entries; Err if the header length disagrees with the actual number of entries, never panic.", "bug_class": "panic", "fidelity": "model_of_std", "extraction_note": "src/primitives.rs FamStructWrapper::deserialize: header length not checked against entries", "witness_args": "&[7u32, 8], 5usize, 3usize", "labels": {"buggy": "versionize@0.1.9", "reference": "versionize@0.1.10"}, "kind": "kernel", "pre_translated": true, "post_translated": true, "pre_lean_sha256": "3cff1a14db289fd5fe269b7cc9f226c934e0a288f303afcee251f6906eb577e7", "post_lean_sha256": "9b567f5bdf7efdc3b4b87d5db97c5f32560530074b9d8fe09b17bd4569d8cfda", "witness_pre": "PANIC", "witness_post": "Err(1)", "discriminating": true, "kept": true} diff --git a/code/bugfind/bench/items/mutant_items.jsonl b/code/bugfind/bench/items/mutant_items.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..82c04d3da9f0a9f575678051c44cd2e3d1c04577 --- /dev/null +++ b/code/bugfind/bench/items/mutant_items.jsonl @@ -0,0 +1,199 @@ +{"item_id": "mut-avg_floor-000", "kind": "mutant", "function": "avg_floor", "operator": "op", "orig_token": "&", "new_token": "|", "token_index": 5, "original_source": "pub fn avg_floor(a: u32, b: u32) -> u32 {\n (a & b) + ((a ^ b) >> 1)\n}", "mutant_source": "pub fn avg_floor(a: u32, b: u32) -> u32 {\n (a | b) + ((a ^ b) >> 1)\n}", "spec_doc": "floor((a+b)/2) without overflow", "status": "kept_nonequivalent", "witness": "DIFF [(1, 0)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-avg_floor-001", "kind": "mutant", "function": "avg_floor", "operator": "op", "orig_token": "+", "new_token": "-", "token_index": 10, "original_source": "pub fn avg_floor(a: u32, b: u32) -> u32 {\n (a & b) + ((a ^ b) >> 1)\n}", "mutant_source": "pub fn avg_floor(a: u32, b: u32) -> u32 {\n (a & b) - ((a ^ b) >> 1)\n}", "spec_doc": "floor((a+b)/2) without overflow", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295, 0)] orig=2147483647 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-avg_floor-002", "kind": "mutant", "function": "avg_floor", "operator": "op", "orig_token": "^", "new_token": "|", "token_index": 16, "original_source": "pub fn avg_floor(a: u32, b: u32) -> u32 {\n (a & b) + ((a ^ b) >> 1)\n}", "mutant_source": "pub fn avg_floor(a: u32, b: u32) -> u32 {\n (a & b) + ((a | b) >> 1)\n}", "spec_doc": "floor((a+b)/2) without overflow", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295, 4294967295)] orig=4294967295 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-avg_floor-003", "kind": "mutant", "function": "avg_floor", "operator": "op", "orig_token": ">>", "new_token": "<<", "token_index": 21, "original_source": "pub fn avg_floor(a: u32, b: u32) -> u32 {\n (a & b) + ((a ^ b) >> 1)\n}", "mutant_source": "pub fn avg_floor(a: u32, b: u32) -> u32 {\n (a & b) + ((a ^ b) << 1)\n}", "spec_doc": "floor((a+b)/2) without overflow", "status": "kept_nonequivalent", "witness": "DIFF [(1, 0)] orig=0 mutant=2", "translated": true, "translate_error": null} +{"item_id": "mut-avg_floor-004", "kind": "mutant", "function": "avg_floor", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 23, "original_source": "pub fn avg_floor(a: u32, b: u32) -> u32 {\n (a & b) + ((a ^ b) >> 1)\n}", "mutant_source": "pub fn avg_floor(a: u32, b: u32) -> u32 {\n (a & b) + ((a ^ b) >> 0)\n}", "spec_doc": "floor((a+b)/2) without overflow", "status": "kept_nonequivalent", "witness": "DIFF [(1, 0)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-avg_floor-005", "kind": "mutant", "function": "avg_floor", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 23, "original_source": "pub fn avg_floor(a: u32, b: u32) -> u32 {\n (a & b) + ((a ^ b) >> 1)\n}", "mutant_source": "pub fn avg_floor(a: u32, b: u32) -> u32 {\n (a & b) + ((a ^ b) >> 2)\n}", "spec_doc": "floor((a+b)/2) without overflow", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295, 0)] orig=2147483647 mutant=1073741823", "translated": true, "translate_error": null} +{"item_id": "mut-abs_diff_u32-001", "kind": "mutant", "function": "abs_diff_u32", "operator": "op", "orig_token": ">=", "new_token": "<=", "token_index": 6, "original_source": "pub fn abs_diff_u32(a: u32, b: u32) -> u32 {\n if a >= b { a - b } else { b - a }\n}", "mutant_source": "pub fn abs_diff_u32(a: u32, b: u32) -> u32 {\n if a <= b { a - b } else { b - a }\n}", "spec_doc": "|a-b|", "status": "kept_nonequivalent", "witness": "DIFF [(1, 0)] orig=1 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-abs_diff_u32-002", "kind": "mutant", "function": "abs_diff_u32", "operator": "op", "orig_token": "-", "new_token": "+", "token_index": 14, "original_source": "pub fn abs_diff_u32(a: u32, b: u32) -> u32 {\n if a >= b { a - b } else { b - a }\n}", "mutant_source": "pub fn abs_diff_u32(a: u32, b: u32) -> u32 {\n if a >= b { a + b } else { b - a }\n}", "spec_doc": "|a-b|", "status": "kept_nonequivalent", "witness": "DIFF [(1, 1)] orig=0 mutant=2", "translated": true, "translate_error": null} +{"item_id": "mut-abs_diff_u32-003", "kind": "mutant", "function": "abs_diff_u32", "operator": "op", "orig_token": "-", "new_token": "+", "token_index": 26, "original_source": "pub fn abs_diff_u32(a: u32, b: u32) -> u32 {\n if a >= b { a - b } else { b - a }\n}", "mutant_source": "pub fn abs_diff_u32(a: u32, b: u32) -> u32 {\n if a >= b { a - b } else { b + a }\n}", "spec_doc": "|a-b|", "status": "kept_nonequivalent", "witness": "DIFF [(1, 4294967295)] orig=4294967294 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-gcd-000", "kind": "mutant", "function": "gcd", "operator": "op", "orig_token": "!=", "new_token": "==", "token_index": 28, "original_source": "pub fn gcd(a: u32, b: u32) -> u32 {\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n x\n}", "mutant_source": "pub fn gcd(a: u32, b: u32) -> u32 {\n let mut x = a;\n let mut y = b;\n while y == 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n x\n}", "spec_doc": "Euclid gcd, gcd(0,0)=0", "status": "kept_nonequivalent", "witness": "DIFF [(0, 0)] orig=0 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-gcd-001", "kind": "mutant", "function": "gcd", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 30, "original_source": "pub fn gcd(a: u32, b: u32) -> u32 {\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n x\n}", "mutant_source": "pub fn gcd(a: u32, b: u32) -> u32 {\n let mut x = a;\n let mut y = b;\n while y != 1 {\n let t = x % y;\n x = y;\n y = t;\n }\n x\n}", "spec_doc": "Euclid gcd, gcd(0,0)=0", "status": "kept_nonequivalent", "witness": "DIFF [(0, 0)] orig=0 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-isqrt-000", "kind": "mutant", "function": "isqrt", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 13, "original_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "mutant_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 1;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "spec_doc": "floor(sqrt(n))", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-isqrt-001", "kind": "mutant", "function": "isqrt", "operator": "const", "orig_token": "65536", "new_token": "0", "token_index": 27, "original_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "mutant_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 0;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "spec_doc": "floor(sqrt(n))", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-isqrt-002", "kind": "mutant", "function": "isqrt", "operator": "const", "orig_token": "65536", "new_token": "65535", "token_index": 27, "original_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "mutant_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65535;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "spec_doc": "floor(sqrt(n))", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=65535 mutant=65534", "translated": true, "translate_error": null} +{"item_id": "mut-isqrt-006", "kind": "mutant", "function": "isqrt", "operator": "op", "orig_token": ">", "new_token": "<", "token_index": 51, "original_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "mutant_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo < 1 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "spec_doc": "floor(sqrt(n))", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-isqrt-008", "kind": "mutant", "function": "isqrt", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 53, "original_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "mutant_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 2 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "spec_doc": "floor(sqrt(n))", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-isqrt-009", "kind": "mutant", "function": "isqrt", "operator": "op", "orig_token": "+", "new_token": "-", "token_index": 66, "original_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "mutant_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo - hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "spec_doc": "floor(sqrt(n))", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=0 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-isqrt-010", "kind": "mutant", "function": "isqrt", "operator": "op", "orig_token": "/", "new_token": "*", "token_index": 71, "original_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "mutant_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) * 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "spec_doc": "floor(sqrt(n))", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=0 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-isqrt-014", "kind": "mutant", "function": "isqrt", "operator": "op", "orig_token": "*", "new_token": "+", "token_index": 80, "original_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "mutant_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid + mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "spec_doc": "floor(sqrt(n))", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-isqrt-015", "kind": "mutant", "function": "isqrt", "operator": "op", "orig_token": "<=", "new_token": "<", "token_index": 84, "original_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "mutant_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid < n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "spec_doc": "floor(sqrt(n))", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-isqrt-016", "kind": "mutant", "function": "isqrt", "operator": "op", "orig_token": "<=", "new_token": ">=", "token_index": 84, "original_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid <= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "mutant_source": "pub fn isqrt(n: u32) -> u32 {\n let mut lo: u64 = 0;\n let mut hi: u64 = 65536;\n let n64 = n as u64;\n while hi - lo > 1 {\n let mid = (lo + hi) / 2;\n if mid * mid >= n64 { lo = mid; } else { hi = mid; }\n }\n lo as u32\n}", "spec_doc": "floor(sqrt(n))", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=0 mutant=65535", "translated": true, "translate_error": null} +{"item_id": "mut-clamp_add-000", "kind": "mutant", "function": "clamp_add", "operator": "op", "orig_token": "+", "new_token": "-", "token_index": 16, "original_source": "pub fn clamp_add(a: u8, b: u8, cap: u8) -> u8 {\n let s = (a as u16) + (b as u16);\n if s > cap as u16 { cap } else { s as u8 }\n}", "mutant_source": "pub fn clamp_add(a: u8, b: u8, cap: u8) -> u8 {\n let s = (a as u16) - (b as u16);\n if s > cap as u16 { cap } else { s as u8 }\n}", "spec_doc": "min(a+b, cap) without overflow", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1, 223)] orig=1 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-clamp_add-002", "kind": "mutant", "function": "clamp_add", "operator": "op", "orig_token": ">", "new_token": "<", "token_index": 31, "original_source": "pub fn clamp_add(a: u8, b: u8, cap: u8) -> u8 {\n let s = (a as u16) + (b as u16);\n if s > cap as u16 { cap } else { s as u8 }\n}", "mutant_source": "pub fn clamp_add(a: u8, b: u8, cap: u8) -> u8 {\n let s = (a as u16) + (b as u16);\n if s < cap as u16 { cap } else { s as u8 }\n}", "spec_doc": "min(a+b, cap) without overflow", "status": "kept_nonequivalent", "witness": "DIFF [(192, 0, 49)] orig=49 mutant=192", "translated": true, "translate_error": null} +{"item_id": "mut-round_up_div-000", "kind": "mutant", "function": "round_up_div", "operator": "op", "orig_token": "==", "new_token": "!=", "token_index": 6, "original_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b != 0 { 1 } else { 0 })\n }\n}", "mutant_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b != 0 {\n None\n } else {\n Some(a / b + if a % b != 0 { 1 } else { 0 })\n }\n}", "spec_doc": "ceil(a/b), None if b==0", "status": "kept_nonequivalent", "witness": "DIFF [(0, 0)] orig=None mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-round_up_div-001", "kind": "mutant", "function": "round_up_div", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 8, "original_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b != 0 { 1 } else { 0 })\n }\n}", "mutant_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 1 {\n None\n } else {\n Some(a / b + if a % b != 0 { 1 } else { 0 })\n }\n}", "spec_doc": "ceil(a/b), None if b==0", "status": "kept_nonequivalent", "witness": "DIFF [(0, 0)] orig=None mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-round_up_div-002", "kind": "mutant", "function": "round_up_div", "operator": "op", "orig_token": "/", "new_token": "*", "token_index": 24, "original_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b != 0 { 1 } else { 0 })\n }\n}", "mutant_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a * b + if a % b != 0 { 1 } else { 0 })\n }\n}", "spec_doc": "ceil(a/b), None if b==0", "status": "kept_nonequivalent", "witness": "DIFF [(1, 4294967295)] orig=Some(1) mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-round_up_div-003", "kind": "mutant", "function": "round_up_div", "operator": "op", "orig_token": "+", "new_token": "-", "token_index": 28, "original_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b != 0 { 1 } else { 0 })\n }\n}", "mutant_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b - if a % b != 0 { 1 } else { 0 })\n }\n}", "spec_doc": "ceil(a/b), None if b==0", "status": "kept_nonequivalent", "witness": "DIFF [(1, 4294967295)] orig=Some(1) mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-round_up_div-004", "kind": "mutant", "function": "round_up_div", "operator": "op", "orig_token": "%", "new_token": "/", "token_index": 34, "original_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b != 0 { 1 } else { 0 })\n }\n}", "mutant_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a / b != 0 { 1 } else { 0 })\n }\n}", "spec_doc": "ceil(a/b), None if b==0", "status": "kept_nonequivalent", "witness": "DIFF [(1, 1)] orig=Some(1) mutant=Some(2)", "translated": true, "translate_error": null} +{"item_id": "mut-round_up_div-005", "kind": "mutant", "function": "round_up_div", "operator": "op", "orig_token": "!=", "new_token": "==", "token_index": 38, "original_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b != 0 { 1 } else { 0 })\n }\n}", "mutant_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b == 0 { 1 } else { 0 })\n }\n}", "spec_doc": "ceil(a/b), None if b==0", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1)] orig=Some(0) mutant=Some(1)", "translated": true, "translate_error": null} +{"item_id": "mut-round_up_div-006", "kind": "mutant", "function": "round_up_div", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 40, "original_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b != 0 { 1 } else { 0 })\n }\n}", "mutant_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b != 1 { 1 } else { 0 })\n }\n}", "spec_doc": "ceil(a/b), None if b==0", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1)] orig=Some(0) mutant=Some(1)", "translated": true, "translate_error": null} +{"item_id": "mut-round_up_div-007", "kind": "mutant", "function": "round_up_div", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 44, "original_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b != 0 { 1 } else { 0 })\n }\n}", "mutant_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b != 0 { 0 } else { 0 })\n }\n}", "spec_doc": "ceil(a/b), None if b==0", "status": "kept_nonequivalent", "witness": "DIFF [(1, 4294967295)] orig=Some(1) mutant=Some(0)", "translated": true, "translate_error": null} +{"item_id": "mut-round_up_div-008", "kind": "mutant", "function": "round_up_div", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 44, "original_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b != 0 { 1 } else { 0 })\n }\n}", "mutant_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b != 0 { 2 } else { 0 })\n }\n}", "spec_doc": "ceil(a/b), None if b==0", "status": "kept_nonequivalent", "witness": "DIFF [(1, 4294967295)] orig=Some(1) mutant=Some(2)", "translated": true, "translate_error": null} +{"item_id": "mut-round_up_div-009", "kind": "mutant", "function": "round_up_div", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 52, "original_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b != 0 { 1 } else { 0 })\n }\n}", "mutant_source": "pub fn round_up_div(a: u32, b: u32) -> Option {\n if b == 0 {\n None\n } else {\n Some(a / b + if a % b != 0 { 1 } else { 1 })\n }\n}", "spec_doc": "ceil(a/b), None if b==0", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1)] orig=Some(0) mutant=Some(1)", "translated": true, "translate_error": null} +{"item_id": "mut-next_multiple-000", "kind": "mutant", "function": "next_multiple", "operator": "op", "orig_token": "==", "new_token": "!=", "token_index": 6, "original_source": "pub fn next_multiple(a: u32, m: u32) -> Option {\n if m == 0 {\n return None;\n }\n let r = a % m;\n if r == 0 {\n Some(a)\n } else {\n a.checked_add(m - r)\n }\n}", "mutant_source": "pub fn next_multiple(a: u32, m: u32) -> Option {\n if m != 0 {\n return None;\n }\n let r = a % m;\n if r == 0 {\n Some(a)\n } else {\n a.checked_add(m - r)\n }\n}", "spec_doc": "smallest multiple of m that is >= a; None on m==0 or overflow", "status": "kept_nonequivalent", "witness": "DIFF [(0, 0)] orig=None mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-next_multiple-001", "kind": "mutant", "function": "next_multiple", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 8, "original_source": "pub fn next_multiple(a: u32, m: u32) -> Option {\n if m == 0 {\n return None;\n }\n let r = a % m;\n if r == 0 {\n Some(a)\n } else {\n a.checked_add(m - r)\n }\n}", "mutant_source": "pub fn next_multiple(a: u32, m: u32) -> Option {\n if m == 1 {\n return None;\n }\n let r = a % m;\n if r == 0 {\n Some(a)\n } else {\n a.checked_add(m - r)\n }\n}", "spec_doc": "smallest multiple of m that is >= a; None on m==0 or overflow", "status": "kept_nonequivalent", "witness": "DIFF [(0, 0)] orig=None mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-next_multiple-002", "kind": "mutant", "function": "next_multiple", "operator": "op", "orig_token": "%", "new_token": "/", "token_index": 27, "original_source": "pub fn next_multiple(a: u32, m: u32) -> Option {\n if m == 0 {\n return None;\n }\n let r = a % m;\n if r == 0 {\n Some(a)\n } else {\n a.checked_add(m - r)\n }\n}", "mutant_source": "pub fn next_multiple(a: u32, m: u32) -> Option {\n if m == 0 {\n return None;\n }\n let r = a / m;\n if r == 0 {\n Some(a)\n } else {\n a.checked_add(m - r)\n }\n}", "spec_doc": "smallest multiple of m that is >= a; None on m==0 or overflow", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295, 1)] orig=Some(4294967295) mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-next_multiple-003", "kind": "mutant", "function": "next_multiple", "operator": "op", "orig_token": "==", "new_token": "!=", "token_index": 36, "original_source": "pub fn next_multiple(a: u32, m: u32) -> Option {\n if m == 0 {\n return None;\n }\n let r = a % m;\n if r == 0 {\n Some(a)\n } else {\n a.checked_add(m - r)\n }\n}", "mutant_source": "pub fn next_multiple(a: u32, m: u32) -> Option {\n if m == 0 {\n return None;\n }\n let r = a % m;\n if r != 0 {\n Some(a)\n } else {\n a.checked_add(m - r)\n }\n}", "spec_doc": "smallest multiple of m that is >= a; None on m==0 or overflow", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1)] orig=Some(0) mutant=Some(1)", "translated": true, "translate_error": null} +{"item_id": "mut-next_multiple-004", "kind": "mutant", "function": "next_multiple", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 38, "original_source": "pub fn next_multiple(a: u32, m: u32) -> Option {\n if m == 0 {\n return None;\n }\n let r = a % m;\n if r == 0 {\n Some(a)\n } else {\n a.checked_add(m - r)\n }\n}", "mutant_source": "pub fn next_multiple(a: u32, m: u32) -> Option {\n if m == 0 {\n return None;\n }\n let r = a % m;\n if r == 1 {\n Some(a)\n } else {\n a.checked_add(m - r)\n }\n}", "spec_doc": "smallest multiple of m that is >= a; None on m==0 or overflow", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1)] orig=Some(0) mutant=Some(1)", "translated": true, "translate_error": null} +{"item_id": "mut-next_multiple-005", "kind": "mutant", "function": "next_multiple", "operator": "checked", "orig_token": "checked_add", "new_token": "checked_sub", "token_index": 55, "original_source": "pub fn next_multiple(a: u32, m: u32) -> Option {\n if m == 0 {\n return None;\n }\n let r = a % m;\n if r == 0 {\n Some(a)\n } else {\n a.checked_add(m - r)\n }\n}", "mutant_source": "pub fn next_multiple(a: u32, m: u32) -> Option {\n if m == 0 {\n return None;\n }\n let r = a % m;\n if r == 0 {\n Some(a)\n } else {\n a.checked_sub(m - r)\n }\n}", "spec_doc": "smallest multiple of m that is >= a; None on m==0 or overflow", "status": "kept_nonequivalent", "witness": "DIFF [(1, 4294967295)] orig=Some(4294967295) mutant=None", "translated": true, "translate_error": null} +{"item_id": "mut-next_multiple-006", "kind": "mutant", "function": "next_multiple", "operator": "op", "orig_token": "-", "new_token": "+", "token_index": 59, "original_source": "pub fn next_multiple(a: u32, m: u32) -> Option {\n if m == 0 {\n return None;\n }\n let r = a % m;\n if r == 0 {\n Some(a)\n } else {\n a.checked_add(m - r)\n }\n}", "mutant_source": "pub fn next_multiple(a: u32, m: u32) -> Option {\n if m == 0 {\n return None;\n }\n let r = a % m;\n if r == 0 {\n Some(a)\n } else {\n a.checked_add(m + r)\n }\n}", "spec_doc": "smallest multiple of m that is >= a; None on m==0 or overflow", "status": "kept_nonequivalent", "witness": "DIFF [(1, 4294967295)] orig=Some(4294967295) mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-digit_sum-000", "kind": "mutant", "function": "digit_sum", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 10, "original_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 10;\n x /= 10;\n }\n s\n}", "mutant_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 1;\n let mut x = n;\n while x > 0 {\n s += x % 10;\n x /= 10;\n }\n s\n}", "spec_doc": "sum of decimal digits", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-digit_sum-002", "kind": "mutant", "function": "digit_sum", "operator": "op", "orig_token": ">", "new_token": "<", "token_index": 28, "original_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 10;\n x /= 10;\n }\n s\n}", "mutant_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x < 0 {\n s += x % 10;\n x /= 10;\n }\n s\n}", "spec_doc": "sum of decimal digits", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-digit_sum-003", "kind": "mutant", "function": "digit_sum", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 30, "original_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 10;\n x /= 10;\n }\n s\n}", "mutant_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 1 {\n s += x % 10;\n x /= 10;\n }\n s\n}", "spec_doc": "sum of decimal digits", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-digit_sum-004", "kind": "mutant", "function": "digit_sum", "operator": "op", "orig_token": "+=", "new_token": "-=", "token_index": 36, "original_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 10;\n x /= 10;\n }\n s\n}", "mutant_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s -= x % 10;\n x /= 10;\n }\n s\n}", "spec_doc": "sum of decimal digits", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-digit_sum-005", "kind": "mutant", "function": "digit_sum", "operator": "op", "orig_token": "%", "new_token": "/", "token_index": 40, "original_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 10;\n x /= 10;\n }\n s\n}", "mutant_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x / 10;\n x /= 10;\n }\n s\n}", "spec_doc": "sum of decimal digits", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-digit_sum-007", "kind": "mutant", "function": "digit_sum", "operator": "const", "orig_token": "10", "new_token": "9", "token_index": 42, "original_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 10;\n x /= 10;\n }\n s\n}", "mutant_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 9;\n x /= 10;\n }\n s\n}", "spec_doc": "sum of decimal digits", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=57 mutant=47", "translated": true, "translate_error": null} +{"item_id": "mut-digit_sum-008", "kind": "mutant", "function": "digit_sum", "operator": "const", "orig_token": "10", "new_token": "11", "token_index": 42, "original_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 10;\n x /= 10;\n }\n s\n}", "mutant_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 11;\n x /= 10;\n }\n s\n}", "spec_doc": "sum of decimal digits", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=57 mutant=41", "translated": true, "translate_error": null} +{"item_id": "mut-digit_sum-009", "kind": "mutant", "function": "digit_sum", "operator": "op", "orig_token": "/=", "new_token": "*=", "token_index": 47, "original_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 10;\n x /= 10;\n }\n s\n}", "mutant_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 10;\n x *= 10;\n }\n s\n}", "spec_doc": "sum of decimal digits", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-digit_sum-011", "kind": "mutant", "function": "digit_sum", "operator": "const", "orig_token": "10", "new_token": "9", "token_index": 49, "original_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 10;\n x /= 10;\n }\n s\n}", "mutant_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 10;\n x /= 9;\n }\n s\n}", "spec_doc": "sum of decimal digits", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=57 mutant=51", "translated": true, "translate_error": null} +{"item_id": "mut-digit_sum-012", "kind": "mutant", "function": "digit_sum", "operator": "const", "orig_token": "10", "new_token": "11", "token_index": 49, "original_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 10;\n x /= 10;\n }\n s\n}", "mutant_source": "pub fn digit_sum(n: u32) -> u32 {\n let mut s = 0;\n let mut x = n;\n while x > 0 {\n s += x % 10;\n x /= 11;\n }\n s\n}", "spec_doc": "sum of decimal digits", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=57 mutant=31", "translated": true, "translate_error": null} +{"item_id": "mut-is_pow2-000", "kind": "mutant", "function": "is_pow2", "operator": "op", "orig_token": "!=", "new_token": "==", "token_index": 4, "original_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n & (n - 1)) == 0\n}", "mutant_source": "pub fn is_pow2(n: u32) -> bool {\n n == 0 && (n & (n - 1)) == 0\n}", "spec_doc": "n is a positive power of two", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=false mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-is_pow2-001", "kind": "mutant", "function": "is_pow2", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 6, "original_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n & (n - 1)) == 0\n}", "mutant_source": "pub fn is_pow2(n: u32) -> bool {\n n != 1 && (n & (n - 1)) == 0\n}", "spec_doc": "n is a positive power of two", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=false mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-is_pow2-002", "kind": "mutant", "function": "is_pow2", "operator": "op", "orig_token": "&&", "new_token": "||", "token_index": 8, "original_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n & (n - 1)) == 0\n}", "mutant_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 || (n & (n - 1)) == 0\n}", "spec_doc": "n is a positive power of two", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=false mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-is_pow2-003", "kind": "mutant", "function": "is_pow2", "operator": "op", "orig_token": "&", "new_token": "|", "token_index": 13, "original_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n & (n - 1)) == 0\n}", "mutant_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n | (n - 1)) == 0\n}", "spec_doc": "n is a positive power of two", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=true mutant=false", "translated": true, "translate_error": null} +{"item_id": "mut-is_pow2-004", "kind": "mutant", "function": "is_pow2", "operator": "op", "orig_token": "-", "new_token": "+", "token_index": 18, "original_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n & (n - 1)) == 0\n}", "mutant_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n & (n + 1)) == 0\n}", "spec_doc": "n is a positive power of two", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=false mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-is_pow2-005", "kind": "mutant", "function": "is_pow2", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 20, "original_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n & (n - 1)) == 0\n}", "mutant_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n & (n - 0)) == 0\n}", "spec_doc": "n is a positive power of two", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=true mutant=false", "translated": true, "translate_error": null} +{"item_id": "mut-is_pow2-006", "kind": "mutant", "function": "is_pow2", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 20, "original_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n & (n - 1)) == 0\n}", "mutant_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n & (n - 2)) == 0\n}", "spec_doc": "n is a positive power of two", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=true mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-is_pow2-007", "kind": "mutant", "function": "is_pow2", "operator": "op", "orig_token": "==", "new_token": "!=", "token_index": 24, "original_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n & (n - 1)) == 0\n}", "mutant_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n & (n - 1)) != 0\n}", "spec_doc": "n is a positive power of two", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=true mutant=false", "translated": true, "translate_error": null} +{"item_id": "mut-is_pow2-008", "kind": "mutant", "function": "is_pow2", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 26, "original_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n & (n - 1)) == 0\n}", "mutant_source": "pub fn is_pow2(n: u32) -> bool {\n n != 0 && (n & (n - 1)) == 1\n}", "spec_doc": "n is a positive power of two", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=true mutant=false", "translated": true, "translate_error": null} +{"item_id": "mut-popcount-000", "kind": "mutant", "function": "popcount", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 10, "original_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c += x & 1;\n x >>= 1;\n }\n c\n}", "mutant_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 1;\n let mut x = n;\n while x != 0 {\n c += x & 1;\n x >>= 1;\n }\n c\n}", "spec_doc": "number of set bits", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-popcount-003", "kind": "mutant", "function": "popcount", "operator": "op", "orig_token": "+=", "new_token": "-=", "token_index": 36, "original_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c += x & 1;\n x >>= 1;\n }\n c\n}", "mutant_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c -= x & 1;\n x >>= 1;\n }\n c\n}", "spec_doc": "number of set bits", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-popcount-004", "kind": "mutant", "function": "popcount", "operator": "op", "orig_token": "&", "new_token": "|", "token_index": 40, "original_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c += x & 1;\n x >>= 1;\n }\n c\n}", "mutant_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c += x | 1;\n x >>= 1;\n }\n c\n}", "spec_doc": "number of set bits", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=32 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-popcount-005", "kind": "mutant", "function": "popcount", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 42, "original_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c += x & 1;\n x >>= 1;\n }\n c\n}", "mutant_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c += x & 0;\n x >>= 1;\n }\n c\n}", "spec_doc": "number of set bits", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-popcount-006", "kind": "mutant", "function": "popcount", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 42, "original_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c += x & 1;\n x >>= 1;\n }\n c\n}", "mutant_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c += x & 2;\n x >>= 1;\n }\n c\n}", "spec_doc": "number of set bits", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-popcount-007", "kind": "mutant", "function": "popcount", "operator": "op", "orig_token": ">>=", "new_token": "<<=", "token_index": 47, "original_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c += x & 1;\n x >>= 1;\n }\n c\n}", "mutant_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c += x & 1;\n x <<= 1;\n }\n c\n}", "spec_doc": "number of set bits", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=32 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-popcount-008", "kind": "mutant", "function": "popcount", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 49, "original_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c += x & 1;\n x >>= 1;\n }\n c\n}", "mutant_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c += x & 1;\n x >>= 0;\n }\n c\n}", "spec_doc": "number of set bits", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-popcount-009", "kind": "mutant", "function": "popcount", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 49, "original_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c += x & 1;\n x >>= 1;\n }\n c\n}", "mutant_source": "pub fn popcount(n: u32) -> u32 {\n let mut c = 0;\n let mut x = n;\n while x != 0 {\n c += x & 1;\n x >>= 2;\n }\n c\n}", "spec_doc": "number of set bits", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=32 mutant=16", "translated": true, "translate_error": null} +{"item_id": "mut-ilog2_floor-000", "kind": "mutant", "function": "ilog2_floor", "operator": "op", "orig_token": "==", "new_token": "!=", "token_index": 6, "original_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "mutant_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n != 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "spec_doc": "floor(log2 n), None for 0", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=None mutant=Some(0)", "translated": true, "translate_error": null} +{"item_id": "mut-ilog2_floor-001", "kind": "mutant", "function": "ilog2_floor", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 8, "original_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "mutant_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 1 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "spec_doc": "floor(log2 n), None for 0", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=None mutant=Some(0)", "translated": true, "translate_error": null} +{"item_id": "mut-ilog2_floor-002", "kind": "mutant", "function": "ilog2_floor", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 27, "original_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "mutant_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 1;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "spec_doc": "floor(log2 n), None for 0", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=Some(0) mutant=Some(1)", "translated": true, "translate_error": null} +{"item_id": "mut-ilog2_floor-003", "kind": "mutant", "function": "ilog2_floor", "operator": "op", "orig_token": ">", "new_token": ">=", "token_index": 45, "original_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "mutant_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x >= 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "spec_doc": "floor(log2 n), None for 0", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=Some(0) mutant=Some(1)", "translated": true, "translate_error": null} +{"item_id": "mut-ilog2_floor-004", "kind": "mutant", "function": "ilog2_floor", "operator": "op", "orig_token": ">", "new_token": "<", "token_index": 45, "original_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "mutant_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x < 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "spec_doc": "floor(log2 n), None for 0", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=Some(31) mutant=Some(0)", "translated": true, "translate_error": null} +{"item_id": "mut-ilog2_floor-005", "kind": "mutant", "function": "ilog2_floor", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 47, "original_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "mutant_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 0 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "spec_doc": "floor(log2 n), None for 0", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=Some(0) mutant=Some(1)", "translated": true, "translate_error": null} +{"item_id": "mut-ilog2_floor-006", "kind": "mutant", "function": "ilog2_floor", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 47, "original_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "mutant_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 2 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "spec_doc": "floor(log2 n), None for 0", "status": "kept_nonequivalent", "witness": "DIFF [(2,)] orig=Some(1) mutant=Some(0)", "translated": true, "translate_error": null} +{"item_id": "mut-ilog2_floor-007", "kind": "mutant", "function": "ilog2_floor", "operator": "op", "orig_token": ">>=", "new_token": "<<=", "token_index": 53, "original_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "mutant_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x <<= 1;\n k += 1;\n }\n Some(k)\n}", "spec_doc": "floor(log2 n), None for 0", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=Some(31) mutant=Some(32)", "translated": true, "translate_error": null} +{"item_id": "mut-ilog2_floor-008", "kind": "mutant", "function": "ilog2_floor", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 55, "original_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "mutant_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 0;\n k += 1;\n }\n Some(k)\n}", "spec_doc": "floor(log2 n), None for 0", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=Some(31) mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-ilog2_floor-009", "kind": "mutant", "function": "ilog2_floor", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 55, "original_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "mutant_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 2;\n k += 1;\n }\n Some(k)\n}", "spec_doc": "floor(log2 n), None for 0", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=Some(31) mutant=Some(16)", "translated": true, "translate_error": null} +{"item_id": "mut-ilog2_floor-010", "kind": "mutant", "function": "ilog2_floor", "operator": "op", "orig_token": "+=", "new_token": "-=", "token_index": 60, "original_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "mutant_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k -= 1;\n }\n Some(k)\n}", "spec_doc": "floor(log2 n), None for 0", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=Some(31) mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-ilog2_floor-011", "kind": "mutant", "function": "ilog2_floor", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 62, "original_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "mutant_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 0;\n }\n Some(k)\n}", "spec_doc": "floor(log2 n), None for 0", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=Some(31) mutant=Some(0)", "translated": true, "translate_error": null} +{"item_id": "mut-ilog2_floor-012", "kind": "mutant", "function": "ilog2_floor", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 62, "original_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 1;\n }\n Some(k)\n}", "mutant_source": "pub fn ilog2_floor(n: u32) -> Option {\n if n == 0 {\n return None;\n }\n let mut k = 0;\n let mut x = n;\n while x > 1 {\n x >>= 1;\n k += 2;\n }\n Some(k)\n}", "spec_doc": "floor(log2 n), None for 0", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=Some(31) mutant=Some(62)", "translated": true, "translate_error": null} +{"item_id": "mut-triangular-000", "kind": "mutant", "function": "triangular", "operator": "op", "orig_token": "*", "new_token": "+", "token_index": 17, "original_source": "pub fn triangular(n: u32) -> u64 {\n let m = n as u64;\n m * (m + 1) / 2\n}", "mutant_source": "pub fn triangular(n: u32) -> u64 {\n let m = n as u64;\n m + (m + 1) / 2\n}", "spec_doc": "n(n+1)/2 in u64", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=2", "translated": true, "translate_error": null} +{"item_id": "mut-triangular-001", "kind": "mutant", "function": "triangular", "operator": "op", "orig_token": "+", "new_token": "-", "token_index": 22, "original_source": "pub fn triangular(n: u32) -> u64 {\n let m = n as u64;\n m * (m + 1) / 2\n}", "mutant_source": "pub fn triangular(n: u32) -> u64 {\n let m = n as u64;\n m * (m - 1) / 2\n}", "spec_doc": "n(n+1)/2 in u64", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=0 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-triangular-002", "kind": "mutant", "function": "triangular", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 24, "original_source": "pub fn triangular(n: u32) -> u64 {\n let m = n as u64;\n m * (m + 1) / 2\n}", "mutant_source": "pub fn triangular(n: u32) -> u64 {\n let m = n as u64;\n m * (m + 0) / 2\n}", "spec_doc": "n(n+1)/2 in u64", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-triangular-003", "kind": "mutant", "function": "triangular", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 24, "original_source": "pub fn triangular(n: u32) -> u64 {\n let m = n as u64;\n m * (m + 1) / 2\n}", "mutant_source": "pub fn triangular(n: u32) -> u64 {\n let m = n as u64;\n m * (m + 2) / 2\n}", "spec_doc": "n(n+1)/2 in u64", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295,)] orig=9223372034707292160 mutant=9223372036854775807", "translated": true, "translate_error": null} +{"item_id": "mut-triangular-004", "kind": "mutant", "function": "triangular", "operator": "op", "orig_token": "/", "new_token": "*", "token_index": 27, "original_source": "pub fn triangular(n: u32) -> u64 {\n let m = n as u64;\n m * (m + 1) / 2\n}", "mutant_source": "pub fn triangular(n: u32) -> u64 {\n let m = n as u64;\n m * (m + 1) * 2\n}", "spec_doc": "n(n+1)/2 in u64", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=4", "translated": true, "translate_error": null} +{"item_id": "mut-triangular-006", "kind": "mutant", "function": "triangular", "operator": "const", "orig_token": "2", "new_token": "1", "token_index": 29, "original_source": "pub fn triangular(n: u32) -> u64 {\n let m = n as u64;\n m * (m + 1) / 2\n}", "mutant_source": "pub fn triangular(n: u32) -> u64 {\n let m = n as u64;\n m * (m + 1) / 1\n}", "spec_doc": "n(n+1)/2 in u64", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=2", "translated": true, "translate_error": null} +{"item_id": "mut-triangular-007", "kind": "mutant", "function": "triangular", "operator": "const", "orig_token": "2", "new_token": "3", "token_index": 29, "original_source": "pub fn triangular(n: u32) -> u64 {\n let m = n as u64;\n m * (m + 1) / 2\n}", "mutant_source": "pub fn triangular(n: u32) -> u64 {\n let m = n as u64;\n m * (m + 1) / 3\n}", "spec_doc": "n(n+1)/2 in u64", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-000", "kind": "mutant", "function": "collatz_steps", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 25, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 1;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-001", "kind": "mutant", "function": "collatz_steps", "operator": "op", "orig_token": ">", "new_token": ">=", "token_index": 32, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x >= 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=0 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-002", "kind": "mutant", "function": "collatz_steps", "operator": "op", "orig_token": ">", "new_token": "<", "token_index": 32, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x < 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=0 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-003", "kind": "mutant", "function": "collatz_steps", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 34, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 0 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=0 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-004", "kind": "mutant", "function": "collatz_steps", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 34, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 2 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=129", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-005", "kind": "mutant", "function": "collatz_steps", "operator": "op", "orig_token": "%", "new_token": "/", "token_index": 46, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x / 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-007", "kind": "mutant", "function": "collatz_steps", "operator": "const", "orig_token": "2", "new_token": "1", "token_index": 48, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 1 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=15", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-008", "kind": "mutant", "function": "collatz_steps", "operator": "const", "orig_token": "2", "new_token": "3", "token_index": 48, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 3 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-009", "kind": "mutant", "function": "collatz_steps", "operator": "op", "orig_token": "==", "new_token": "!=", "token_index": 50, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 != 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=15", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-010", "kind": "mutant", "function": "collatz_steps", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 52, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 1 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=15", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-011", "kind": "mutant", "function": "collatz_steps", "operator": "op", "orig_token": "/", "new_token": "*", "token_index": 58, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x * 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-013", "kind": "mutant", "function": "collatz_steps", "operator": "const", "orig_token": "2", "new_token": "1", "token_index": 60, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 1 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-014", "kind": "mutant", "function": "collatz_steps", "operator": "const", "orig_token": "2", "new_token": "3", "token_index": 60, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 3 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-015", "kind": "mutant", "function": "collatz_steps", "operator": "const", "orig_token": "3", "new_token": "0", "token_index": 68, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 0 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-016", "kind": "mutant", "function": "collatz_steps", "operator": "const", "orig_token": "3", "new_token": "2", "token_index": 68, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 2 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-017", "kind": "mutant", "function": "collatz_steps", "operator": "const", "orig_token": "3", "new_token": "4", "token_index": 68, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 4 * x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-018", "kind": "mutant", "function": "collatz_steps", "operator": "op", "orig_token": "*", "new_token": "+", "token_index": 70, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 + x + 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-019", "kind": "mutant", "function": "collatz_steps", "operator": "op", "orig_token": "+", "new_token": "-", "token_index": 74, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x - 1 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=47", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-020", "kind": "mutant", "function": "collatz_steps", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 76, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 0 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-021", "kind": "mutant", "function": "collatz_steps", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 76, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 2 };\n s += 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-022", "kind": "mutant", "function": "collatz_steps", "operator": "op", "orig_token": "+=", "new_token": "-=", "token_index": 83, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s -= 1;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-023", "kind": "mutant", "function": "collatz_steps", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 85, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 0;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-collatz_steps-024", "kind": "mutant", "function": "collatz_steps", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 85, "original_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 1;\n }\n s\n}", "mutant_source": "pub fn collatz_steps(n: u16) -> u32 {\n let mut x = n as u64;\n let mut s = 0;\n while x > 1 {\n x = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };\n s += 2;\n }\n s\n}", "spec_doc": "steps to reach 1 (0 for n<=1)", "status": "kept_nonequivalent", "witness": "DIFF [(65535,)] orig=130 mutant=260", "translated": true, "translate_error": null} +{"item_id": "mut-sat_sub_i32-000", "kind": "mutant", "function": "sat_sub_i32", "operator": "op", "orig_token": "-", "new_token": "+", "token_index": 16, "original_source": "pub fn sat_sub_i32(a: i32, b: i32) -> i32 {\n let d = (a as i64) - (b as i64);\n if d > i32::MAX as i64 {\n i32::MAX\n } else if d < i32::MIN as i64 {\n i32::MIN\n } else {\n d as i32\n }\n}", "mutant_source": "pub fn sat_sub_i32(a: i32, b: i32) -> i32 {\n let d = (a as i64) + (b as i64);\n if d > i32::MAX as i64 {\n i32::MAX\n } else if d < i32::MIN as i64 {\n i32::MIN\n } else {\n d as i32\n }\n}", "spec_doc": "saturating subtraction", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1)] orig=-1 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-sat_sub_i32-002", "kind": "mutant", "function": "sat_sub_i32", "operator": "op", "orig_token": ">", "new_token": "<", "token_index": 31, "original_source": "pub fn sat_sub_i32(a: i32, b: i32) -> i32 {\n let d = (a as i64) - (b as i64);\n if d > i32::MAX as i64 {\n i32::MAX\n } else if d < i32::MIN as i64 {\n i32::MIN\n } else {\n d as i32\n }\n}", "mutant_source": "pub fn sat_sub_i32(a: i32, b: i32) -> i32 {\n let d = (a as i64) - (b as i64);\n if d < i32::MAX as i64 {\n i32::MAX\n } else if d < i32::MIN as i64 {\n i32::MIN\n } else {\n d as i32\n }\n}", "spec_doc": "saturating subtraction", "status": "kept_nonequivalent", "witness": "DIFF [(0, 0)] orig=0 mutant=2147483647", "translated": true, "translate_error": null} +{"item_id": "mut-sat_sub_i32-004", "kind": "mutant", "function": "sat_sub_i32", "operator": "op", "orig_token": "<", "new_token": ">", "token_index": 55, "original_source": "pub fn sat_sub_i32(a: i32, b: i32) -> i32 {\n let d = (a as i64) - (b as i64);\n if d > i32::MAX as i64 {\n i32::MAX\n } else if d < i32::MIN as i64 {\n i32::MIN\n } else {\n d as i32\n }\n}", "mutant_source": "pub fn sat_sub_i32(a: i32, b: i32) -> i32 {\n let d = (a as i64) - (b as i64);\n if d > i32::MAX as i64 {\n i32::MAX\n } else if d > i32::MIN as i64 {\n i32::MIN\n } else {\n d as i32\n }\n}", "spec_doc": "saturating subtraction", "status": "kept_nonequivalent", "witness": "DIFF [(0, 0)] orig=0 mutant=-2147483648", "translated": true, "translate_error": null} +{"item_id": "mut-sign3-000", "kind": "mutant", "function": "sign3", "operator": "op", "orig_token": ">", "new_token": ">=", "token_index": 6, "original_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "mutant_source": "pub fn sign3(x: i32) -> i32 {\n if x >= 0 {\n 1\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "spec_doc": "-1,0,1", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-sign3-001", "kind": "mutant", "function": "sign3", "operator": "op", "orig_token": ">", "new_token": "<", "token_index": 6, "original_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "mutant_source": "pub fn sign3(x: i32) -> i32 {\n if x < 0 {\n 1\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "spec_doc": "-1,0,1", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-sign3-002", "kind": "mutant", "function": "sign3", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 8, "original_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "mutant_source": "pub fn sign3(x: i32) -> i32 {\n if x > 1 {\n 1\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "spec_doc": "-1,0,1", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-sign3-003", "kind": "mutant", "function": "sign3", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 12, "original_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "mutant_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 0\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "spec_doc": "-1,0,1", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-sign3-004", "kind": "mutant", "function": "sign3", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 12, "original_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "mutant_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 2\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "spec_doc": "-1,0,1", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=1 mutant=2", "translated": true, "translate_error": null} +{"item_id": "mut-sign3-005", "kind": "mutant", "function": "sign3", "operator": "op", "orig_token": "<", "new_token": "<=", "token_index": 22, "original_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "mutant_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x <= 0 {\n -1\n } else {\n 0\n }\n}", "spec_doc": "-1,0,1", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=0 mutant=-1", "translated": true, "translate_error": null} +{"item_id": "mut-sign3-006", "kind": "mutant", "function": "sign3", "operator": "op", "orig_token": "<", "new_token": ">", "token_index": 22, "original_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "mutant_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x > 0 {\n -1\n } else {\n 0\n }\n}", "spec_doc": "-1,0,1", "status": "kept_nonequivalent", "witness": "DIFF [(-1,)] orig=-1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-sign3-007", "kind": "mutant", "function": "sign3", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 24, "original_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "mutant_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 1 {\n -1\n } else {\n 0\n }\n}", "spec_doc": "-1,0,1", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=0 mutant=-1", "translated": true, "translate_error": null} +{"item_id": "mut-sign3-008", "kind": "mutant", "function": "sign3", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 29, "original_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "mutant_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 0 {\n -0\n } else {\n 0\n }\n}", "spec_doc": "-1,0,1", "status": "kept_nonequivalent", "witness": "DIFF [(-1,)] orig=-1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-sign3-009", "kind": "mutant", "function": "sign3", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 29, "original_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "mutant_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 0 {\n -2\n } else {\n 0\n }\n}", "spec_doc": "-1,0,1", "status": "kept_nonequivalent", "witness": "DIFF [(-1,)] orig=-1 mutant=-2", "translated": true, "translate_error": null} +{"item_id": "mut-sign3-010", "kind": "mutant", "function": "sign3", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 37, "original_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 0 {\n -1\n } else {\n 0\n }\n}", "mutant_source": "pub fn sign3(x: i32) -> i32 {\n if x > 0 {\n 1\n } else if x < 0 {\n -1\n } else {\n 1\n }\n}", "spec_doc": "-1,0,1", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-000", "kind": "mutant", "function": "pow_mod", "operator": "op", "orig_token": "==", "new_token": "!=", "token_index": 6, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m != 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(0, 0, 0)] orig=0 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-001", "kind": "mutant", "function": "pow_mod", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 8, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 1 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(0, 0, 0)] orig=0 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-002", "kind": "mutant", "function": "pow_mod", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 14, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 1;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(0, 0, 0)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-003", "kind": "mutant", "function": "pow_mod", "operator": "op", "orig_token": "%", "new_token": "/", "token_index": 48, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) / mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(1, 1, 3096764529)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-004", "kind": "mutant", "function": "pow_mod", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 75, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 0 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295, 0, 4294967295)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-005", "kind": "mutant", "function": "pow_mod", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 75, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 2 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295, 0, 4294967295)] orig=1 mutant=2", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-006", "kind": "mutant", "function": "pow_mod", "operator": "op", "orig_token": "%", "new_token": "/", "token_index": 77, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 / mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(1, 0, 1)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-008", "kind": "mutant", "function": "pow_mod", "operator": "op", "orig_token": ">", "new_token": "<", "token_index": 86, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp < 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1, 1175895263)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-009", "kind": "mutant", "function": "pow_mod", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 88, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 1 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1, 1175895263)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-010", "kind": "mutant", "function": "pow_mod", "operator": "op", "orig_token": "&", "new_token": "|", "token_index": 96, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp | 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295, 4294967295, 2917660787)] orig=574928797 mutant=1123820376", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-011", "kind": "mutant", "function": "pow_mod", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 98, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 0 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1, 1175895263)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-012", "kind": "mutant", "function": "pow_mod", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 98, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 2 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1, 1175895263)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-013", "kind": "mutant", "function": "pow_mod", "operator": "op", "orig_token": "==", "new_token": "!=", "token_index": 100, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 != 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1, 1175895263)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-014", "kind": "mutant", "function": "pow_mod", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 102, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 0 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1, 1175895263)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-015", "kind": "mutant", "function": "pow_mod", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 102, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 2 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1, 1175895263)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-016", "kind": "mutant", "function": "pow_mod", "operator": "op", "orig_token": "*", "new_token": "+", "token_index": 113, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc + base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1, 1175895263)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-017", "kind": "mutant", "function": "pow_mod", "operator": "op", "orig_token": "%", "new_token": "/", "token_index": 118, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) / mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(1, 1, 3096764529)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-018", "kind": "mutant", "function": "pow_mod", "operator": "op", "orig_token": "*", "new_token": "+", "token_index": 132, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base + base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(1, 4294967295, 4221459743)] orig=1 mutant=1464657872", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-019", "kind": "mutant", "function": "pow_mod", "operator": "op", "orig_token": "%", "new_token": "/", "token_index": 137, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) / mm;\n exp >>= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(1, 4294967295, 4221459743)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-020", "kind": "mutant", "function": "pow_mod", "operator": "op", "orig_token": ">>=", "new_token": "<<=", "token_index": 144, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp <<= 1;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295, 4294967295, 2917660787)] orig=574928797 mutant=1377306508", "translated": true, "translate_error": null} +{"item_id": "mut-pow_mod-022", "kind": "mutant", "function": "pow_mod", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 146, "original_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 1;\n }\n acc as u32\n}", "mutant_source": "pub fn pow_mod(b: u32, e: u32, m: u32) -> u32 {\n if m == 0 {\n return 0;\n }\n let mm = m as u64;\n let mut base = (b as u64) % mm;\n let mut exp = e;\n let mut acc: u64 = 1 % mm;\n while exp > 0 {\n if exp & 1 == 1 {\n acc = (acc * base) % mm;\n }\n base = (base * base) % mm;\n exp >>= 2;\n }\n acc as u32\n}", "spec_doc": "b^e mod m, m>0 (m==0 -> 0)", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295, 4294967295, 2917660787)] orig=574928797 mutant=545236188", "translated": true, "translate_error": null} +{"item_id": "mut-varint_len-000", "kind": "mutant", "function": "varint_len", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 10, "original_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "mutant_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 0;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "spec_doc": "LEB128 byte length of n", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=1 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-varint_len-001", "kind": "mutant", "function": "varint_len", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 10, "original_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "mutant_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 2;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "spec_doc": "LEB128 byte length of n", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=1 mutant=2", "translated": true, "translate_error": null} +{"item_id": "mut-varint_len-002", "kind": "mutant", "function": "varint_len", "operator": "op", "orig_token": ">=", "new_token": ">", "token_index": 28, "original_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "mutant_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x > 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "spec_doc": "LEB128 byte length of n", "status": "kept_nonequivalent", "witness": "DIFF [(128,)] orig=2 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-varint_len-003", "kind": "mutant", "function": "varint_len", "operator": "op", "orig_token": ">=", "new_token": "<=", "token_index": 28, "original_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "mutant_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x <= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "spec_doc": "LEB128 byte length of n", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=1 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-varint_len-004", "kind": "mutant", "function": "varint_len", "operator": "const", "orig_token": "128", "new_token": "0", "token_index": 30, "original_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "mutant_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 0 {\n x >>= 7;\n len += 1;\n }\n len\n}", "spec_doc": "LEB128 byte length of n", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=1 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-varint_len-005", "kind": "mutant", "function": "varint_len", "operator": "const", "orig_token": "128", "new_token": "127", "token_index": 30, "original_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "mutant_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 127 {\n x >>= 7;\n len += 1;\n }\n len\n}", "spec_doc": "LEB128 byte length of n", "status": "kept_nonequivalent", "witness": "DIFF [(127,)] orig=1 mutant=2", "translated": true, "translate_error": null} +{"item_id": "mut-varint_len-006", "kind": "mutant", "function": "varint_len", "operator": "const", "orig_token": "128", "new_token": "129", "token_index": 30, "original_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "mutant_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 129 {\n x >>= 7;\n len += 1;\n }\n len\n}", "spec_doc": "LEB128 byte length of n", "status": "kept_nonequivalent", "witness": "DIFF [(128,)] orig=2 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-varint_len-007", "kind": "mutant", "function": "varint_len", "operator": "op", "orig_token": ">>=", "new_token": "<<=", "token_index": 36, "original_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "mutant_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x <<= 7;\n len += 1;\n }\n len\n}", "spec_doc": "LEB128 byte length of n", "status": "kept_nonequivalent", "witness": "DIFF [(18446744073709551615,)] orig=10 mutant=11", "translated": true, "translate_error": null} +{"item_id": "mut-varint_len-008", "kind": "mutant", "function": "varint_len", "operator": "const", "orig_token": "7", "new_token": "0", "token_index": 38, "original_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "mutant_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 0;\n len += 1;\n }\n len\n}", "spec_doc": "LEB128 byte length of n", "status": "kept_nonequivalent", "witness": "DIFF [(18446744073709551615,)] orig=10 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-varint_len-009", "kind": "mutant", "function": "varint_len", "operator": "const", "orig_token": "7", "new_token": "6", "token_index": 38, "original_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "mutant_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 6;\n len += 1;\n }\n len\n}", "spec_doc": "LEB128 byte length of n", "status": "kept_nonequivalent", "witness": "DIFF [(18446744073709551615,)] orig=10 mutant=11", "translated": true, "translate_error": null} +{"item_id": "mut-varint_len-010", "kind": "mutant", "function": "varint_len", "operator": "const", "orig_token": "7", "new_token": "8", "token_index": 38, "original_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "mutant_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 8;\n len += 1;\n }\n len\n}", "spec_doc": "LEB128 byte length of n", "status": "kept_nonequivalent", "witness": "DIFF [(18446744073709551615,)] orig=10 mutant=9", "translated": true, "translate_error": null} +{"item_id": "mut-varint_len-011", "kind": "mutant", "function": "varint_len", "operator": "op", "orig_token": "+=", "new_token": "-=", "token_index": 43, "original_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "mutant_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len -= 1;\n }\n len\n}", "spec_doc": "LEB128 byte length of n", "status": "kept_nonequivalent", "witness": "DIFF [(18446744073709551615,)] orig=10 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-varint_len-012", "kind": "mutant", "function": "varint_len", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 45, "original_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "mutant_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 0;\n }\n len\n}", "spec_doc": "LEB128 byte length of n", "status": "kept_nonequivalent", "witness": "DIFF [(18446744073709551615,)] orig=10 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-varint_len-013", "kind": "mutant", "function": "varint_len", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 45, "original_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 1;\n }\n len\n}", "mutant_source": "pub fn varint_len(n: u64) -> u32 {\n let mut len = 1;\n let mut x = n;\n while x >= 128 {\n x >>= 7;\n len += 2;\n }\n len\n}", "spec_doc": "LEB128 byte length of n", "status": "kept_nonequivalent", "witness": "DIFF [(18446744073709551615,)] orig=10 mutant=19", "translated": true, "translate_error": null} +{"item_id": "mut-zigzag_enc-000", "kind": "mutant", "function": "zigzag_enc", "operator": "op", "orig_token": "<<", "new_token": ">>", "token_index": 6, "original_source": "pub fn zigzag_enc(n: i32) -> u32 {\n ((n << 1) ^ (n >> 31)) as u32\n}", "mutant_source": "pub fn zigzag_enc(n: i32) -> u32 {\n ((n >> 1) ^ (n >> 31)) as u32\n}", "spec_doc": "protobuf zigzag encode", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=2 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-zigzag_enc-001", "kind": "mutant", "function": "zigzag_enc", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 8, "original_source": "pub fn zigzag_enc(n: i32) -> u32 {\n ((n << 1) ^ (n >> 31)) as u32\n}", "mutant_source": "pub fn zigzag_enc(n: i32) -> u32 {\n ((n << 0) ^ (n >> 31)) as u32\n}", "spec_doc": "protobuf zigzag encode", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=2 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-zigzag_enc-002", "kind": "mutant", "function": "zigzag_enc", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 8, "original_source": "pub fn zigzag_enc(n: i32) -> u32 {\n ((n << 1) ^ (n >> 31)) as u32\n}", "mutant_source": "pub fn zigzag_enc(n: i32) -> u32 {\n ((n << 2) ^ (n >> 31)) as u32\n}", "spec_doc": "protobuf zigzag encode", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=2 mutant=4", "translated": true, "translate_error": null} +{"item_id": "mut-zigzag_enc-003", "kind": "mutant", "function": "zigzag_enc", "operator": "op", "orig_token": "^", "new_token": "|", "token_index": 11, "original_source": "pub fn zigzag_enc(n: i32) -> u32 {\n ((n << 1) ^ (n >> 31)) as u32\n}", "mutant_source": "pub fn zigzag_enc(n: i32) -> u32 {\n ((n << 1) | (n >> 31)) as u32\n}", "spec_doc": "protobuf zigzag encode", "status": "kept_nonequivalent", "witness": "DIFF [(-1,)] orig=1 mutant=4294967295", "translated": true, "translate_error": null} +{"item_id": "mut-zigzag_enc-004", "kind": "mutant", "function": "zigzag_enc", "operator": "op", "orig_token": ">>", "new_token": "<<", "token_index": 16, "original_source": "pub fn zigzag_enc(n: i32) -> u32 {\n ((n << 1) ^ (n >> 31)) as u32\n}", "mutant_source": "pub fn zigzag_enc(n: i32) -> u32 {\n ((n << 1) ^ (n << 31)) as u32\n}", "spec_doc": "protobuf zigzag encode", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=2 mutant=2147483650", "translated": true, "translate_error": null} +{"item_id": "mut-zigzag_enc-005", "kind": "mutant", "function": "zigzag_enc", "operator": "const", "orig_token": "31", "new_token": "0", "token_index": 18, "original_source": "pub fn zigzag_enc(n: i32) -> u32 {\n ((n << 1) ^ (n >> 31)) as u32\n}", "mutant_source": "pub fn zigzag_enc(n: i32) -> u32 {\n ((n << 1) ^ (n >> 0)) as u32\n}", "spec_doc": "protobuf zigzag encode", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=2 mutant=3", "translated": true, "translate_error": null} +{"item_id": "mut-zigzag_enc-006", "kind": "mutant", "function": "zigzag_enc", "operator": "const", "orig_token": "31", "new_token": "30", "token_index": 18, "original_source": "pub fn zigzag_enc(n: i32) -> u32 {\n ((n << 1) ^ (n >> 31)) as u32\n}", "mutant_source": "pub fn zigzag_enc(n: i32) -> u32 {\n ((n << 1) ^ (n >> 30)) as u32\n}", "spec_doc": "protobuf zigzag encode", "status": "kept_nonequivalent", "witness": "DIFF [(2147483647,)] orig=4294967294 mutant=4294967295", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-001", "kind": "mutant", "function": "bit_reverse8", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 32, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 1;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=128 mutant=64", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-002", "kind": "mutant", "function": "bit_reverse8", "operator": "op", "orig_token": "<", "new_token": "<=", "token_index": 39, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i <= 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=128 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-003", "kind": "mutant", "function": "bit_reverse8", "operator": "op", "orig_token": "<", "new_token": ">", "token_index": 39, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i > 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=128 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-004", "kind": "mutant", "function": "bit_reverse8", "operator": "const", "orig_token": "8", "new_token": "0", "token_index": 41, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 0 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=128 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-005", "kind": "mutant", "function": "bit_reverse8", "operator": "const", "orig_token": "8", "new_token": "7", "token_index": 41, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 7 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=128 mutant=64", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-006", "kind": "mutant", "function": "bit_reverse8", "operator": "const", "orig_token": "8", "new_token": "9", "token_index": 41, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 9 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=128 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-007", "kind": "mutant", "function": "bit_reverse8", "operator": "op", "orig_token": "<<", "new_token": ">>", "token_index": 52, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r >> 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=128 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-008", "kind": "mutant", "function": "bit_reverse8", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 54, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 0) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=128 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-009", "kind": "mutant", "function": "bit_reverse8", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 54, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 2) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=128 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-010", "kind": "mutant", "function": "bit_reverse8", "operator": "op", "orig_token": "|", "new_token": "&", "token_index": 57, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) & (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=128 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-011", "kind": "mutant", "function": "bit_reverse8", "operator": "op", "orig_token": "&", "new_token": "|", "token_index": 62, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x | 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=0 mutant=255", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-012", "kind": "mutant", "function": "bit_reverse8", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 64, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 0);\n x >>= 1;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=128 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-013", "kind": "mutant", "function": "bit_reverse8", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 64, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 2);\n x >>= 1;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=128 mutant=0", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-014", "kind": "mutant", "function": "bit_reverse8", "operator": "op", "orig_token": ">>=", "new_token": "<<=", "token_index": 70, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x <<= 1;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(255,)] orig=255 mutant=128", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-015", "kind": "mutant", "function": "bit_reverse8", "operator": "const", "orig_token": "1", "new_token": "0", "token_index": 72, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 0;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=128 mutant=255", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-016", "kind": "mutant", "function": "bit_reverse8", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 72, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 2;\n i += 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(255,)] orig=255 mutant=240", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-017", "kind": "mutant", "function": "bit_reverse8", "operator": "op", "orig_token": "+=", "new_token": "-=", "token_index": 77, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i -= 1;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(0,)] orig=0 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-bit_reverse8-019", "kind": "mutant", "function": "bit_reverse8", "operator": "const", "orig_token": "1", "new_token": "2", "token_index": 79, "original_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 1;\n }\n r\n}", "mutant_source": "pub fn bit_reverse8(b: u8) -> u8 {\n let mut r = 0u8;\n let mut x = b;\n let mut i = 0;\n while i < 8 {\n r = (r << 1) | (x & 1);\n x >>= 1;\n i += 2;\n }\n r\n}", "spec_doc": "reverse bits of a byte", "status": "kept_nonequivalent", "witness": "DIFF [(1,)] orig=128 mutant=8", "translated": true, "translate_error": null} +{"item_id": "mut-lcm_checked-000", "kind": "mutant", "function": "lcm_checked", "operator": "op", "orig_token": "==", "new_token": "!=", "token_index": 6, "original_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "mutant_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a != 0 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "spec_doc": "lcm, None on overflow, lcm(_,0)=Some(0)", "status": "kept_nonequivalent", "witness": "DIFF [(1, 1)] orig=Some(1) mutant=Some(0)", "translated": true, "translate_error": null} +{"item_id": "mut-lcm_checked-001", "kind": "mutant", "function": "lcm_checked", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 8, "original_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "mutant_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 1 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "spec_doc": "lcm, None on overflow, lcm(_,0)=Some(0)", "status": "kept_nonequivalent", "witness": "DIFF [(1, 1)] orig=Some(1) mutant=Some(0)", "translated": true, "translate_error": null} +{"item_id": "mut-lcm_checked-003", "kind": "mutant", "function": "lcm_checked", "operator": "op", "orig_token": "==", "new_token": "!=", "token_index": 14, "original_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "mutant_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b != 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "spec_doc": "lcm, None on overflow, lcm(_,0)=Some(0)", "status": "kept_nonequivalent", "witness": "DIFF [(1, 1)] orig=Some(1) mutant=Some(0)", "translated": true, "translate_error": null} +{"item_id": "mut-lcm_checked-004", "kind": "mutant", "function": "lcm_checked", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 16, "original_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "mutant_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 1 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "spec_doc": "lcm, None on overflow, lcm(_,0)=Some(0)", "status": "kept_nonequivalent", "witness": "DIFF [(1, 1)] orig=Some(1) mutant=Some(0)", "translated": true, "translate_error": null} +{"item_id": "mut-lcm_checked-005", "kind": "mutant", "function": "lcm_checked", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 24, "original_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "mutant_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 0 {\n return Some(1);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "spec_doc": "lcm, None on overflow, lcm(_,0)=Some(0)", "status": "kept_nonequivalent", "witness": "DIFF [(0, 0)] orig=Some(0) mutant=Some(1)", "translated": true, "translate_error": null} +{"item_id": "mut-lcm_checked-006", "kind": "mutant", "function": "lcm_checked", "operator": "op", "orig_token": "!=", "new_token": "==", "token_index": 56, "original_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "mutant_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y == 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "spec_doc": "lcm, None on overflow, lcm(_,0)=Some(0)", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295, 1)] orig=Some(4294967295) mutant=Some(1)", "translated": true, "translate_error": null} +{"item_id": "mut-lcm_checked-007", "kind": "mutant", "function": "lcm_checked", "operator": "const", "orig_token": "0", "new_token": "1", "token_index": 58, "original_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "mutant_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 1 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "spec_doc": "lcm, None on overflow, lcm(_,0)=Some(0)", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295, 1)] orig=Some(4294967295) mutant=Some(1)", "translated": true, "translate_error": null} +{"item_id": "mut-lcm_checked-009", "kind": "mutant", "function": "lcm_checked", "operator": "op", "orig_token": "/", "new_token": "*", "token_index": 94, "original_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "mutant_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a * x).checked_mul(b)\n}", "spec_doc": "lcm, None on overflow, lcm(_,0)=Some(0)", "status": "kept_nonequivalent", "witness": "DIFF [(4294967295, 4294967295)] orig=Some(4294967295) mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-lcm_checked-010", "kind": "mutant", "function": "lcm_checked", "operator": "checked", "orig_token": "checked_mul", "new_token": "checked_add", "token_index": 99, "original_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_mul(b)\n}", "mutant_source": "pub fn lcm_checked(a: u32, b: u32) -> Option {\n if a == 0 || b == 0 {\n return Some(0);\n }\n let mut x = a;\n let mut y = b;\n while y != 0 {\n let t = x % y;\n x = y;\n y = t;\n }\n (a / x).checked_add(b)\n}", "spec_doc": "lcm, None on overflow, lcm(_,0)=Some(0)", "status": "kept_nonequivalent", "witness": "DIFF [(1, 1)] orig=Some(1) mutant=Some(2)", "translated": true, "translate_error": null} +{"item_id": "mut-midpoint_idx-001", "kind": "mutant", "function": "midpoint_idx", "operator": "op", "orig_token": "<=", "new_token": ">=", "token_index": 6, "original_source": "pub fn midpoint_idx(lo: usize, hi: usize) -> usize {\n if hi <= lo { lo } else { lo + (hi - lo) / 2 }\n}", "mutant_source": "pub fn midpoint_idx(lo: usize, hi: usize) -> usize {\n if hi >= lo { lo } else { lo + (hi - lo) / 2 }\n}", "spec_doc": "lo + (hi-lo)/2 for lo<=hi, else lo", "status": "kept_nonequivalent", "witness": "DIFF [(1, 0)] orig=1 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-midpoint_idx-002", "kind": "mutant", "function": "midpoint_idx", "operator": "op", "orig_token": "+", "new_token": "-", "token_index": 22, "original_source": "pub fn midpoint_idx(lo: usize, hi: usize) -> usize {\n if hi <= lo { lo } else { lo + (hi - lo) / 2 }\n}", "mutant_source": "pub fn midpoint_idx(lo: usize, hi: usize) -> usize {\n if hi <= lo { lo } else { lo - (hi - lo) / 2 }\n}", "spec_doc": "lo + (hi-lo)/2 for lo<=hi, else lo", "status": "kept_nonequivalent", "witness": "DIFF [(0, 18446744073709551615)] orig=9223372036854775807 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-midpoint_idx-003", "kind": "mutant", "function": "midpoint_idx", "operator": "op", "orig_token": "-", "new_token": "+", "token_index": 27, "original_source": "pub fn midpoint_idx(lo: usize, hi: usize) -> usize {\n if hi <= lo { lo } else { lo + (hi - lo) / 2 }\n}", "mutant_source": "pub fn midpoint_idx(lo: usize, hi: usize) -> usize {\n if hi <= lo { lo } else { lo + (hi + lo) / 2 }\n}", "spec_doc": "lo + (hi-lo)/2 for lo<=hi, else lo", "status": "kept_nonequivalent", "witness": "DIFF [(1, 18446744073709551615)] orig=9223372036854775808 mutant=PANIC", "translated": true, "translate_error": null} +{"item_id": "mut-midpoint_idx-004", "kind": "mutant", "function": "midpoint_idx", "operator": "op", "orig_token": "/", "new_token": "*", "token_index": 32, "original_source": "pub fn midpoint_idx(lo: usize, hi: usize) -> usize {\n if hi <= lo { lo } else { lo + (hi - lo) / 2 }\n}", "mutant_source": "pub fn midpoint_idx(lo: usize, hi: usize) -> usize {\n if hi <= lo { lo } else { lo + (hi - lo) * 2 }\n}", "spec_doc": "lo + (hi-lo)/2 for lo<=hi, else lo", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1)] orig=0 mutant=2", "translated": true, "translate_error": null} +{"item_id": "mut-midpoint_idx-006", "kind": "mutant", "function": "midpoint_idx", "operator": "const", "orig_token": "2", "new_token": "1", "token_index": 34, "original_source": "pub fn midpoint_idx(lo: usize, hi: usize) -> usize {\n if hi <= lo { lo } else { lo + (hi - lo) / 2 }\n}", "mutant_source": "pub fn midpoint_idx(lo: usize, hi: usize) -> usize {\n if hi <= lo { lo } else { lo + (hi - lo) / 1 }\n}", "spec_doc": "lo + (hi-lo)/2 for lo<=hi, else lo", "status": "kept_nonequivalent", "witness": "DIFF [(0, 1)] orig=0 mutant=1", "translated": true, "translate_error": null} +{"item_id": "mut-midpoint_idx-007", "kind": "mutant", "function": "midpoint_idx", "operator": "const", "orig_token": "2", "new_token": "3", "token_index": 34, "original_source": "pub fn midpoint_idx(lo: usize, hi: usize) -> usize {\n if hi <= lo { lo } else { lo + (hi - lo) / 2 }\n}", "mutant_source": "pub fn midpoint_idx(lo: usize, hi: usize) -> usize {\n if hi <= lo { lo } else { lo + (hi - lo) / 3 }\n}", "spec_doc": "lo + (hi-lo)/2 for lo<=hi, else lo", "status": "kept_nonequivalent", "witness": "DIFF [(0, 18446744073709551615)] orig=9223372036854775807 mutant=6148914691236517205", "translated": true, "translate_error": null} diff --git a/code/bugfind/bench/kernels/bcrypt_split/meta.json b/code/bugfind/bench/kernels/bcrypt_split/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..9c5c21e7f89d5c0b5ce8340280330a53522c41b7 --- /dev/null +++ b/code/bugfind/bench/kernels/bcrypt_split/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-bcrypt_split", + "kernel": "bcrypt_split", + "advisory": "RUSTSEC-2026-0199", + "crate": "bcrypt", + "pre_version": "0.19.1", + "post_version": "0.19.2", + "advisory_url": "https://github.com/Keats/rust-bcrypt/pull/103", + "title": "Panic in `bcrypt::verify` on non-ASCII hash input", + "source_file": "src/lib.rs", + "function": "split_hash_salt_len", + "signature": "pub fn split_hash_salt_len(hash: &[u8]) -> Result", + "spec_doc": "Validates a bcrypt hash string and returns the salt length (22). A valid hash is exactly 60 ASCII bytes; every other input must give Err, never panic.", + "bug_class": "panic", + "fidelity": "model_of_std", + "extraction_note": "src/lib.rs split_hash: &str slicing at a non-char-boundary on non-ASCII 60-byte input", + "witness_args": "&[b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', 0xA3, b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a']", + "labels": { + "buggy": "bcrypt@0.19.1", + "reference": "bcrypt@0.19.2" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/bcrypt_split/post/Cargo.lock b/code/bugfind/bench/kernels/bcrypt_split/post/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..d4334548fc8b679fdf7cf1c9ccdd5d2d73119420 --- /dev/null +++ b/code/bugfind/bench/kernels/bcrypt_split/post/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_bcrypt_split_post" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/bcrypt_split/post/Cargo.toml b/code/bugfind/bench/kernels/bcrypt_split/post/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..c8a6cd69c56978ec2f43d47fc603a043b9e0b74d --- /dev/null +++ b/code/bugfind/bench/kernels/bcrypt_split/post/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_bcrypt_split_post" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/bcrypt_split/post/src/lib.rs b/code/bugfind/bench/kernels/bcrypt_split/post/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..974b7347d24e6b68d3a28376b40041190998ad7d --- /dev/null +++ b/code/bugfind/bench/kernels/bcrypt_split/post/src/lib.rs @@ -0,0 +1,17 @@ +pub fn split_hash_salt_len(hash: &[u8]) -> Result { + if hash.len() != 60 { + return Err(1); + } + let mut ascii = true; + let mut i = 0usize; + while i < hash.len() { + if hash[i] >= 128 { + ascii = false; + } + i += 1; + } + if !ascii { + return Err(2); + } + Ok(22) +} diff --git a/code/bugfind/bench/kernels/bcrypt_split/pre/Cargo.lock b/code/bugfind/bench/kernels/bcrypt_split/pre/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..7f42720091f3b8cd5056726a8a2d14bd41f662bb --- /dev/null +++ b/code/bugfind/bench/kernels/bcrypt_split/pre/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_bcrypt_split_pre" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/bcrypt_split/pre/Cargo.toml b/code/bugfind/bench/kernels/bcrypt_split/pre/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..4a791d72d8fd53dc53bd1f468d4a6618de368426 --- /dev/null +++ b/code/bugfind/bench/kernels/bcrypt_split/pre/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_bcrypt_split_pre" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/bcrypt_split/pre/src/lib.rs b/code/bugfind/bench/kernels/bcrypt_split/pre/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..fd7613fa6bf31cf6fa0a63635e5683e3ec0779f9 --- /dev/null +++ b/code/bugfind/bench/kernels/bcrypt_split/pre/src/lib.rs @@ -0,0 +1,10 @@ +fn is_char_boundary(b: u8) -> bool { + b < 128 || b >= 192 +} +pub fn split_hash_salt_len(hash: &[u8]) -> Result { + if hash.len() != 60 { + return Err(1); + } + assert!(is_char_boundary(hash[22])); + Ok(22) +} diff --git a/code/bugfind/bench/kernels/bytes_reserve/meta.json b/code/bugfind/bench/kernels/bytes_reserve/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..4f7c2c5cf0e5657e031f062b29e6b88f770c476b --- /dev/null +++ b/code/bugfind/bench/kernels/bytes_reserve/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-bytes_reserve", + "kernel": "bytes_reserve", + "advisory": "RUSTSEC-2026-0007", + "crate": "bytes", + "pre_version": "1.11.0", + "post_version": "1.11.1", + "advisory_url": "https://github.com/tokio-rs/bytes/commit/d0293b0e35838123c51ca5dfdf468ecafee4398f", + "title": "Integer overflow in `BytesMut::reserve`", + "source_file": "src/bytes_mut.rs", + "function": "reserve_fits", + "signature": "pub fn reserve_fits(v_capacity: usize, new_cap: usize, offset: usize) -> bool", + "spec_doc": "Decides whether a Vec-backed buffer with capacity v_capacity can serve a reserve request of new_cap bytes when the live window starts at offset; must be true iff v_capacity >= new_cap + offset in exact arithmetic.", + "bug_class": "overflow", + "fidelity": "verbatim_logic", + "extraction_note": "src/bytes_mut.rs reserve_inner: new_cap + offset overflow", + "witness_args": "10usize, usize::MAX, 1usize", + "labels": { + "buggy": "bytes@1.11.0", + "reference": "bytes@1.11.1" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/bytes_reserve/post/Cargo.lock b/code/bugfind/bench/kernels/bytes_reserve/post/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..d473c44a816d53e02740b0ef1b602cbddb8f7fb6 --- /dev/null +++ b/code/bugfind/bench/kernels/bytes_reserve/post/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_bytes_reserve_post" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/bytes_reserve/post/Cargo.toml b/code/bugfind/bench/kernels/bytes_reserve/post/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..54335ef9403fc48b47fabf9dc44e32c3657af459 --- /dev/null +++ b/code/bugfind/bench/kernels/bytes_reserve/post/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_bytes_reserve_post" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/bytes_reserve/post/src/lib.rs b/code/bugfind/bench/kernels/bytes_reserve/post/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..cb81c637e9f70a25c9fd17cc9f84a02f840dfe54 --- /dev/null +++ b/code/bugfind/bench/kernels/bytes_reserve/post/src/lib.rs @@ -0,0 +1,6 @@ +pub fn reserve_fits(v_capacity: usize, new_cap: usize, offset: usize) -> bool { + match new_cap.checked_add(offset) { + Some(s) => v_capacity >= s, + None => false, + } +} diff --git a/code/bugfind/bench/kernels/bytes_reserve/pre/Cargo.lock b/code/bugfind/bench/kernels/bytes_reserve/pre/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..74f013f76b8f7bc5ad023ffc4e0d3a08c4e63601 --- /dev/null +++ b/code/bugfind/bench/kernels/bytes_reserve/pre/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_bytes_reserve_pre" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/bytes_reserve/pre/Cargo.toml b/code/bugfind/bench/kernels/bytes_reserve/pre/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..5c21e6886583c972e28526e9e30aa69af6a2171d --- /dev/null +++ b/code/bugfind/bench/kernels/bytes_reserve/pre/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_bytes_reserve_pre" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/bytes_reserve/pre/src/lib.rs b/code/bugfind/bench/kernels/bytes_reserve/pre/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..34a546022d94ed7af495d454b137aacd0607adfa --- /dev/null +++ b/code/bugfind/bench/kernels/bytes_reserve/pre/src/lib.rs @@ -0,0 +1,3 @@ +pub fn reserve_fits(v_capacity: usize, new_cap: usize, offset: usize) -> bool { + v_capacity >= new_cap + offset +} diff --git a/code/bugfind/bench/kernels/claxon_rice/meta.json b/code/bugfind/bench/kernels/claxon_rice/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..401ff203dd400485d676e33e85edde7c1db632e4 --- /dev/null +++ b/code/bugfind/bench/kernels/claxon_rice/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-claxon_rice", + "kernel": "claxon_rice", + "advisory": "RUSTSEC-2018-0004", + "crate": "claxon", + "pre_version": "0.3.1", + "post_version": "0.3.2", + "advisory_url": "https://github.com/ruuda/claxon/commit/8f28ec275e412dd3af4f3cda460605512faf332c", + "title": "Malicious input could cause uninitialized memory to be exposed", + "source_file": "src/subframe.rs", + "function": "rice_layout", + "signature": "pub fn rice_layout(block_size: u16, order: u32, n_warm_up: u16) -> Result", + "spec_doc": "Computes how many residual samples a FLAC Rice-coded subframe's 2^order partitions cover (order is a 4-bit field, so order > 15 is rejected with Err). On Ok(n), n must equal block_size (the partitions fill the block); otherwise return Err.", + "bug_class": "logic", + "fidelity": "verbatim_logic", + "extraction_note": "src/subframe.rs decode_residual: block size not a multiple of 2^order left buffer tail uninitialised", + "witness_args": "10u16, 2u32, 0u16", + "labels": { + "buggy": "claxon@0.3.1", + "reference": "claxon@0.3.2" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/claxon_rice/post/Cargo.lock b/code/bugfind/bench/kernels/claxon_rice/post/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..9bbf8402da88ecf41c8b2bb67af4043fa79039ff --- /dev/null +++ b/code/bugfind/bench/kernels/claxon_rice/post/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_claxon_rice_post" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/claxon_rice/post/Cargo.toml b/code/bugfind/bench/kernels/claxon_rice/post/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..abedfa880c2cec7bf54b26054c2c2ab67048bdd0 --- /dev/null +++ b/code/bugfind/bench/kernels/claxon_rice/post/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_claxon_rice_post" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/claxon_rice/post/src/lib.rs b/code/bugfind/bench/kernels/claxon_rice/post/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..faa52418cb8187b8ebbee2c8ed54d0ba3a1fd63a --- /dev/null +++ b/code/bugfind/bench/kernels/claxon_rice/post/src/lib.rs @@ -0,0 +1,14 @@ +pub fn rice_layout(block_size: u16, order: u32, n_warm_up: u16) -> Result { + if order > 15 { + return Err(3); + } + let n_partitions = 1u32 << order; + let n_samples_per_partition = block_size >> order; + if block_size & ((n_partitions - 1) as u16) != 0 { + return Err(2); + } + if n_warm_up > n_samples_per_partition { + return Err(1); + } + Ok(n_partitions * (n_samples_per_partition as u32)) +} diff --git a/code/bugfind/bench/kernels/claxon_rice/pre/Cargo.lock b/code/bugfind/bench/kernels/claxon_rice/pre/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..7fdf5426bf8c28c83898f927736397fa51e43419 --- /dev/null +++ b/code/bugfind/bench/kernels/claxon_rice/pre/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_claxon_rice_pre" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/claxon_rice/pre/Cargo.toml b/code/bugfind/bench/kernels/claxon_rice/pre/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..e471233dd779f6e738ffa6fdbfd0f93167ccf649 --- /dev/null +++ b/code/bugfind/bench/kernels/claxon_rice/pre/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_claxon_rice_pre" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/claxon_rice/pre/src/lib.rs b/code/bugfind/bench/kernels/claxon_rice/pre/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..4aba9a0a7135bae69a74a8f0cf092c64b9dc0621 --- /dev/null +++ b/code/bugfind/bench/kernels/claxon_rice/pre/src/lib.rs @@ -0,0 +1,11 @@ +pub fn rice_layout(block_size: u16, order: u32, n_warm_up: u16) -> Result { + if order > 15 { + return Err(3); + } + let n_partitions = 1u32 << order; + let n_samples_per_partition = block_size >> order; + if n_warm_up > n_samples_per_partition { + return Err(1); + } + Ok(n_partitions * (n_samples_per_partition as u32)) +} diff --git a/code/bugfind/bench/kernels/ecdh_scalar/meta.json b/code/bugfind/bench/kernels/ecdh_scalar/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..1a2f545254f3eb8e67f10e3b9fba3a48a619707b --- /dev/null +++ b/code/bugfind/bench/kernels/ecdh_scalar/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-ecdh_scalar", + "kernel": "ecdh_scalar", + "advisory": "RUSTSEC-2026-0023", + "crate": "libcrux-ecdh", + "pre_version": "0.0.5", + "post_version": "0.0.6", + "advisory_url": "https://github.com/cryspen/libcrux/pull/1301", + "title": "X25519 secret validation did not check buffer length or clamping", + "source_file": "src/ecdh.rs", + "function": "validate_x25519_scalar", + "signature": "pub fn validate_x25519_scalar(s: &[u8]) -> bool", + "spec_doc": "Validates an X25519 secret scalar: must be exactly 32 bytes, not all zero, and clamped (low 3 bits of byte 0 clear, top bit of byte 31 clear, second-highest bit of byte 31 set).", + "bug_class": "logic", + "fidelity": "verbatim_logic", + "extraction_note": "src/ecdh.rs validate_scalar: only checked all-zero", + "witness_args": "&[1u8, 2, 3]", + "labels": { + "buggy": "libcrux-ecdh@0.0.5", + "reference": "libcrux-ecdh@0.0.6" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/ecdh_scalar/post/Cargo.lock b/code/bugfind/bench/kernels/ecdh_scalar/post/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..d7f65601ec7731f37b36ffbee6b902c7cd49ab0a --- /dev/null +++ b/code/bugfind/bench/kernels/ecdh_scalar/post/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_ecdh_scalar_post" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/ecdh_scalar/post/Cargo.toml b/code/bugfind/bench/kernels/ecdh_scalar/post/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..e8b4d47be4032b6cea766e925b63ce4f84fc279b --- /dev/null +++ b/code/bugfind/bench/kernels/ecdh_scalar/post/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_ecdh_scalar_post" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/ecdh_scalar/post/src/lib.rs b/code/bugfind/bench/kernels/ecdh_scalar/post/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..f61a6257e078f265befc35651178424f27ec7900 --- /dev/null +++ b/code/bugfind/bench/kernels/ecdh_scalar/post/src/lib.rs @@ -0,0 +1,17 @@ +pub fn validate_x25519_scalar(s: &[u8]) -> bool { + if s.len() != 32 { + return false; + } + let mut all_zero = true; + let mut i = 0usize; + while i < s.len() { + if s[i] != 0 { + all_zero = false; + } + i += 1; + } + if all_zero { + return false; + } + (s[0] & 7) == 0 && (s[31] & 128) == 0 && (s[31] & 64) != 0 +} diff --git a/code/bugfind/bench/kernels/ecdh_scalar/pre/Cargo.lock b/code/bugfind/bench/kernels/ecdh_scalar/pre/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..a62b5fff1bc5a7bbfe1ebf38782cd6a79ae5bd62 --- /dev/null +++ b/code/bugfind/bench/kernels/ecdh_scalar/pre/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_ecdh_scalar_pre" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/ecdh_scalar/pre/Cargo.toml b/code/bugfind/bench/kernels/ecdh_scalar/pre/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..71bafb24cff59f1d88a426174eb75601068483fb --- /dev/null +++ b/code/bugfind/bench/kernels/ecdh_scalar/pre/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_ecdh_scalar_pre" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/ecdh_scalar/pre/src/lib.rs b/code/bugfind/bench/kernels/ecdh_scalar/pre/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..e9a813e0241c3d0667d90ece9568e85443ea3f1f --- /dev/null +++ b/code/bugfind/bench/kernels/ecdh_scalar/pre/src/lib.rs @@ -0,0 +1,11 @@ +pub fn validate_x25519_scalar(s: &[u8]) -> bool { + let mut all_zero = true; + let mut i = 0usize; + while i < s.len() { + if s[i] != 0 { + all_zero = false; + } + i += 1; + } + !all_zero +} diff --git a/code/bugfind/bench/kernels/evm_memset/meta.json b/code/bugfind/bench/kernels/evm_memset/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..5ca8ea736b8102d21e2afee6d6b75c23be87c852 --- /dev/null +++ b/code/bugfind/bench/kernels/evm_memset/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-evm_memset", + "kernel": "evm_memset", + "advisory": "RUSTSEC-2021-0066", + "crate": "evm-core", + "pre_version": "0.21.0", + "post_version": "0.21.1", + "advisory_url": "https://github.com/rust-blockchain/evm", + "title": "Denial of service on EVM execution due to memory over-allocation", + "source_file": "src/memory.rs", + "function": "memory_set_len", + "signature": "pub fn memory_set_len(cur_len: usize, offset: usize, value_len: usize, target_size: Option, limit: usize) -> Result", + "spec_doc": "New length of EVM memory after writing value (value_len bytes) at offset, zero-padded to target_size (default value_len). Err if offset+target_size exceeds limit. Writing an empty value must not grow memory.", + "bug_class": "dos_loop_or_recursion", + "fidelity": "verbatim_logic", + "extraction_note": "src/memory.rs Memory::set: empty value with large target_size over-allocates", + "witness_args": "0usize, 0usize, 0usize, Some(1000usize), 1048576usize", + "labels": { + "buggy": "evm-core@0.21.0", + "reference": "evm-core@0.21.1" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/evm_memset/post/Cargo.lock b/code/bugfind/bench/kernels/evm_memset/post/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..8fdef040aa433f4496e49e536f555b9f58e579e5 --- /dev/null +++ b/code/bugfind/bench/kernels/evm_memset/post/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_evm_memset_post" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/evm_memset/post/Cargo.toml b/code/bugfind/bench/kernels/evm_memset/post/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..9b040f6f37e5a2aaea15463d509f0b9a23c9f828 --- /dev/null +++ b/code/bugfind/bench/kernels/evm_memset/post/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_evm_memset_post" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/evm_memset/post/src/lib.rs b/code/bugfind/bench/kernels/evm_memset/post/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..2e83f0b24307b815fda62d0f2b301d1f6c916b20 --- /dev/null +++ b/code/bugfind/bench/kernels/evm_memset/post/src/lib.rs @@ -0,0 +1,22 @@ +pub fn memory_set_len(cur_len: usize, offset: usize, value_len: usize, target_size: Option, limit: usize) -> Result { + if value_len == 0 { + return Ok(cur_len); + } + let target = match target_size { + Some(t) => t, + None => value_len, + }; + match offset.checked_add(target) { + Some(pos) => { + if pos > limit { + return Err(1); + } + } + None => return Err(1), + } + if cur_len < offset + target { + Ok(offset + target) + } else { + Ok(cur_len) + } +} diff --git a/code/bugfind/bench/kernels/evm_memset/pre/Cargo.lock b/code/bugfind/bench/kernels/evm_memset/pre/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..1cb1bf841d98d2994de746431bbd44e34548200b --- /dev/null +++ b/code/bugfind/bench/kernels/evm_memset/pre/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_evm_memset_pre" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/evm_memset/pre/Cargo.toml b/code/bugfind/bench/kernels/evm_memset/pre/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..14cb8de522ed805475e0882e43556ec88f471f0e --- /dev/null +++ b/code/bugfind/bench/kernels/evm_memset/pre/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_evm_memset_pre" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/evm_memset/pre/src/lib.rs b/code/bugfind/bench/kernels/evm_memset/pre/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..e26ea860cb257aa29003b1a826fa8931d287afad --- /dev/null +++ b/code/bugfind/bench/kernels/evm_memset/pre/src/lib.rs @@ -0,0 +1,19 @@ +pub fn memory_set_len(cur_len: usize, offset: usize, value_len: usize, target_size: Option, limit: usize) -> Result { + let target = match target_size { + Some(t) => t, + None => value_len, + }; + match offset.checked_add(target) { + Some(pos) => { + if pos > limit { + return Err(1); + } + } + None => return Err(1), + } + if cur_len < offset + target { + Ok(offset + target) + } else { + Ok(cur_len) + } +} diff --git a/code/bugfind/bench/kernels/exif_discard/meta.json b/code/bugfind/bench/kernels/exif_discard/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..820fbb2ecce762cb54cfb1acf9722fdf3d1c703a --- /dev/null +++ b/code/bugfind/bench/kernels/exif_discard/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-exif_discard", + "kernel": "exif_discard", + "advisory": "RUSTSEC-2021-0143", + "crate": "kamadak-exif", + "pre_version": "0.5.2", + "post_version": "0.5.3", + "advisory_url": "https://github.com/kamadak/exif-rs/commit/1b05eab57e484cd7d576d4357b9cda7fdc57df8c", + "title": "kamadak-exif DoS with untrusted PNG data", + "source_file": "src/util.rs", + "function": "discard_exact", + "signature": "pub fn discard_exact(avail: usize, len: usize) -> Result", + "spec_doc": "Models skipping len bytes of a reader that has only avail bytes: returns Ok(number of read rounds) when the reader had enough data, Err when it hits EOF early. Must terminate on every input.", + "bug_class": "dos_loop_or_recursion", + "fidelity": "verbatim_logic", + "extraction_note": "src/util.rs discard_exact: spins forever at EOF (consume_len == 0)", + "witness_args": "3usize, 10usize", + "labels": { + "buggy": "kamadak-exif@0.5.2", + "reference": "kamadak-exif@0.5.3" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/exif_discard/post/Cargo.lock b/code/bugfind/bench/kernels/exif_discard/post/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..b38ff4218558bc902748094bd45c7dbde69cd31f --- /dev/null +++ b/code/bugfind/bench/kernels/exif_discard/post/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_exif_discard_post" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/exif_discard/post/Cargo.toml b/code/bugfind/bench/kernels/exif_discard/post/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..e12303ba6e472187acac0b980a14151e7788bfe7 --- /dev/null +++ b/code/bugfind/bench/kernels/exif_discard/post/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_exif_discard_post" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/exif_discard/post/src/lib.rs b/code/bugfind/bench/kernels/exif_discard/post/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..2734e1b149f4cbc1b1a7745eda072dedd8d28083 --- /dev/null +++ b/code/bugfind/bench/kernels/exif_discard/post/src/lib.rs @@ -0,0 +1,17 @@ +pub fn discard_exact(avail: usize, len: usize) -> Result { + let mut avail = avail; + let mut len = len; + let mut rounds = 0usize; + let mut eof = false; + while len > 0 && !eof { + let consume_len = if avail < len { avail } else { len }; + if consume_len == 0 { + eof = true; + } else { + avail -= consume_len; + len -= consume_len; + rounds += 1; + } + } + if eof { Err(1) } else { Ok(rounds) } +} diff --git a/code/bugfind/bench/kernels/exif_discard/pre/Cargo.lock b/code/bugfind/bench/kernels/exif_discard/pre/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..e0d95af39f10a728a567d50e5d246dffd8e771a0 --- /dev/null +++ b/code/bugfind/bench/kernels/exif_discard/pre/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_exif_discard_pre" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/exif_discard/pre/Cargo.toml b/code/bugfind/bench/kernels/exif_discard/pre/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..59a66266cefcd4a931b699f40d18fac319fd738b --- /dev/null +++ b/code/bugfind/bench/kernels/exif_discard/pre/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_exif_discard_pre" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/exif_discard/pre/src/lib.rs b/code/bugfind/bench/kernels/exif_discard/pre/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..e4a3bad172c7c5d7d5c8a717dc8f541431f83fe9 --- /dev/null +++ b/code/bugfind/bench/kernels/exif_discard/pre/src/lib.rs @@ -0,0 +1,12 @@ +pub fn discard_exact(avail: usize, len: usize) -> Result { + let mut avail = avail; + let mut len = len; + let mut rounds = 0usize; + while len > 0 { + let consume_len = if avail < len { avail } else { len }; + avail -= consume_len; + len -= consume_len; + rounds += 1; + } + Ok(rounds) +} diff --git a/code/bugfind/bench/kernels/matrix_power/meta.json b/code/bugfind/bench/kernels/matrix_power/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..c32ff61d7d9a35b22b9fdaa75163c50bb801dfd3 --- /dev/null +++ b/code/bugfind/bench/kernels/matrix_power/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-matrix_power", + "kernel": "matrix_power", + "advisory": "RUSTSEC-2025-0065", + "crate": "matrix-sdk-base", + "pre_version": "0.14.0", + "post_version": "0.14.1", + "advisory_url": "https://github.com/matrix-org/matrix-rust-sdk/pull/5635", + "title": "matrix-sdk-base: Panic in the `RoomMember::normalized_power_level()` method", + "source_file": "src/room/members.rs", + "function": "normalize_power_level", + "signature": "pub fn normalize_power_level(power_level: i64, max_power_level: i64) -> i64", + "spec_doc": "Scales a Matrix user power level (|power_level| < 2^53) to the range 0..=100 relative to max_power_level > 0.", + "bug_class": "panic", + "fidelity": "verbatim_logic", + "extraction_note": "src/room/members.rs normalized_power_level: expect() on out-of-range Int when max_power_level is small", + "witness_args": "9007199254740991i64, 1i64", + "labels": { + "buggy": "matrix-sdk-base@0.14.0", + "reference": "matrix-sdk-base@0.14.1" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/matrix_power/post/Cargo.lock b/code/bugfind/bench/kernels/matrix_power/post/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..658882e57f74a8d5d5bb2db810da179ba310208c --- /dev/null +++ b/code/bugfind/bench/kernels/matrix_power/post/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_matrix_power_post" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/matrix_power/post/Cargo.toml b/code/bugfind/bench/kernels/matrix_power/post/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..c0dfafa241156a514e8147b68cd895b6632e01da --- /dev/null +++ b/code/bugfind/bench/kernels/matrix_power/post/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_matrix_power_post" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/matrix_power/post/src/lib.rs b/code/bugfind/bench/kernels/matrix_power/post/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..7f2eebc361231a72067f7186e497cf2e49d7b1cf --- /dev/null +++ b/code/bugfind/bench/kernels/matrix_power/post/src/lib.rs @@ -0,0 +1,10 @@ +pub fn normalize_power_level(power_level: i64, max_power_level: i64) -> i64 { + let n = (power_level * 100) / max_power_level; + if n < 0 { + 0 + } else if n > 100 { + 100 + } else { + n + } +} diff --git a/code/bugfind/bench/kernels/matrix_power/pre/Cargo.lock b/code/bugfind/bench/kernels/matrix_power/pre/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..6f279a3206dbf1a93a13c7c8235dfbec9720f81f --- /dev/null +++ b/code/bugfind/bench/kernels/matrix_power/pre/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_matrix_power_pre" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/matrix_power/pre/Cargo.toml b/code/bugfind/bench/kernels/matrix_power/pre/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..4f6188449af169af66a38d990f3da958ced8f616 --- /dev/null +++ b/code/bugfind/bench/kernels/matrix_power/pre/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_matrix_power_pre" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/matrix_power/pre/src/lib.rs b/code/bugfind/bench/kernels/matrix_power/pre/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..d8f8ffc1d37204db0443fc2e4329ff31b6441e24 --- /dev/null +++ b/code/bugfind/bench/kernels/matrix_power/pre/src/lib.rs @@ -0,0 +1,6 @@ +const INT_MAX: i64 = 9007199254740991; +pub fn normalize_power_level(power_level: i64, max_power_level: i64) -> i64 { + let n = (power_level * 100) / max_power_level; + assert!(n >= -INT_MAX && n <= INT_MAX); + n +} diff --git a/code/bugfind/bench/kernels/mldsa_hint/meta.json b/code/bugfind/bench/kernels/mldsa_hint/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..955e2af8ee773c5fba742d8830ca71b30dd235a2 --- /dev/null +++ b/code/bugfind/bench/kernels/mldsa_hint/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-mldsa_hint", + "kernel": "mldsa_hint", + "advisory": "RUSTSEC-2026-0076", + "crate": "libcrux-ml-dsa", + "pre_version": "0.0.7", + "post_version": "0.0.8", + "advisory_url": "https://github.com/cryspen/libcrux/pull/1348", + "title": "Panic in Signature Hint Decoding During Verification", + "source_file": "src/encoding/signature.rs", + "function": "hint_weight", + "signature": "pub fn hint_weight(hint: &[u8], max_ones: usize, rows: usize) -> Option", + "spec_doc": "Decodes the ML-DSA signature hint encoding: hint[..max_ones] are positions, hint[max_ones..max_ones+rows] are cumulative counts that must be non-decreasing and at most max_ones. Returns the sum of the hint bytes it consumed, or None for a malformed encoding. Must never panic on any input of length >= max_ones+rows.", + "bug_class": "panic", + "fidelity": "verbatim_logic", + "extraction_note": "src/ml_dsa_generic.rs / encoding/signature.rs deserialize hint: checked previous instead of current against max_ones", + "witness_args": "&[0u8, 0, 200], 2usize, 1usize", + "labels": { + "buggy": "libcrux-ml-dsa@0.0.7", + "reference": "libcrux-ml-dsa@0.0.8" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/mldsa_hint/post/Cargo.lock b/code/bugfind/bench/kernels/mldsa_hint/post/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..1a1c13115dce7dbf38ea82b9192520d681f3a2dc --- /dev/null +++ b/code/bugfind/bench/kernels/mldsa_hint/post/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_mldsa_hint_post" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/mldsa_hint/post/Cargo.toml b/code/bugfind/bench/kernels/mldsa_hint/post/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..4cc8871ff8bb12142341d80566ac866d2d3a8b8f --- /dev/null +++ b/code/bugfind/bench/kernels/mldsa_hint/post/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_mldsa_hint_post" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/mldsa_hint/post/src/lib.rs b/code/bugfind/bench/kernels/mldsa_hint/post/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..720c185ac2078eaefb139f47911c8637ff22b95b --- /dev/null +++ b/code/bugfind/bench/kernels/mldsa_hint/post/src/lib.rs @@ -0,0 +1,21 @@ +pub fn hint_weight(hint: &[u8], max_ones: usize, rows: usize) -> Option { + let mut previous = 0usize; + let mut total = 0usize; + let mut bad = false; + let mut i = 0usize; + while i < rows { + let current = hint[max_ones + i] as usize; + if current < previous || current > max_ones { + bad = true; + } else { + let mut j = previous; + while j < current { + total += hint[j] as usize; + j += 1; + } + previous = current; + } + i += 1; + } + if bad { None } else { Some(total) } +} diff --git a/code/bugfind/bench/kernels/mldsa_hint/pre/Cargo.lock b/code/bugfind/bench/kernels/mldsa_hint/pre/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..5ecab709af6aee64de614b67c1d371f090451ed0 --- /dev/null +++ b/code/bugfind/bench/kernels/mldsa_hint/pre/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_mldsa_hint_pre" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/mldsa_hint/pre/Cargo.toml b/code/bugfind/bench/kernels/mldsa_hint/pre/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..cdf4d9579e786d554c3c63029cb2d7cc8402062f --- /dev/null +++ b/code/bugfind/bench/kernels/mldsa_hint/pre/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_mldsa_hint_pre" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/mldsa_hint/pre/src/lib.rs b/code/bugfind/bench/kernels/mldsa_hint/pre/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..3d827d0c6e80ca82262c8c72d595a5e304903a66 --- /dev/null +++ b/code/bugfind/bench/kernels/mldsa_hint/pre/src/lib.rs @@ -0,0 +1,21 @@ +pub fn hint_weight(hint: &[u8], max_ones: usize, rows: usize) -> Option { + let mut previous = 0usize; + let mut total = 0usize; + let mut bad = false; + let mut i = 0usize; + while i < rows { + let current = hint[max_ones + i] as usize; + if current < previous || previous > max_ones { + bad = true; + } else { + let mut j = previous; + while j < current { + total += hint[j] as usize; + j += 1; + } + previous = current; + } + i += 1; + } + if bad { None } else { Some(total) } +} diff --git a/code/bugfind/bench/kernels/mldsa_norm/meta.json b/code/bugfind/bench/kernels/mldsa_norm/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..4c17f8faab467eb470d8e484d0c6181a775042ec --- /dev/null +++ b/code/bugfind/bench/kernels/mldsa_norm/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-mldsa_norm", + "kernel": "mldsa_norm", + "advisory": "RUSTSEC-2026-0076", + "crate": "libcrux-ml-dsa", + "pre_version": "0.0.7", + "post_version": "0.0.8", + "advisory_url": "https://github.com/cryspen/libcrux/pull/1348", + "title": "Panic in Signature Hint Decoding During Verification", + "source_file": "src/ml_dsa_generic.rs", + "function": "response_bound", + "signature": "pub fn response_bound(gamma1_exponent: u32, beta: i32) -> i32", + "spec_doc": "ML-DSA verification bound for the signer response: gamma1 - beta where gamma1 = 2^gamma1_exponent.", + "bug_class": "logic", + "fidelity": "verbatim_logic", + "extraction_note": "src/ml_dsa_generic.rs verify: (2 << GAMMA1_EXPONENT) - BETA instead of (1 << ...) - BETA", + "witness_args": "17u32, 78i32", + "labels": { + "buggy": "libcrux-ml-dsa@0.0.7", + "reference": "libcrux-ml-dsa@0.0.8" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/mldsa_norm/post/Cargo.lock b/code/bugfind/bench/kernels/mldsa_norm/post/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..ee1fe4a325519da2cc9ee56fa2ad00e4735cd258 --- /dev/null +++ b/code/bugfind/bench/kernels/mldsa_norm/post/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_mldsa_norm_post" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/mldsa_norm/post/Cargo.toml b/code/bugfind/bench/kernels/mldsa_norm/post/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..2489586031b5ce114f9f85de8195239bd744a40e --- /dev/null +++ b/code/bugfind/bench/kernels/mldsa_norm/post/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "k_mldsa_norm_post" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/code/bugfind/bench/kernels/mldsa_norm/pre/Cargo.lock b/code/bugfind/bench/kernels/mldsa_norm/pre/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..7f784b88bc66ee65c52144cfd815c6f33afa9d56 --- /dev/null +++ b/code/bugfind/bench/kernels/mldsa_norm/pre/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "k_mldsa_norm_pre" +version = "0.1.0" diff --git a/code/bugfind/bench/kernels/nanoid_mask/meta.json b/code/bugfind/bench/kernels/nanoid_mask/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..ed559c34f9699a1f99d59d9d92c1db83f66a521a --- /dev/null +++ b/code/bugfind/bench/kernels/nanoid_mask/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-nanoid_mask", + "kernel": "nanoid_mask", + "advisory": "RUSTSEC-2024-0343", + "crate": "nano-id", + "pre_version": "0.3.3", + "post_version": "0.4.0", + "advisory_url": null, + "title": "Reduced entropy due to inadequate character set usage", + "source_file": "src/lib.rs", + "function": "alphabet_mask", + "signature": "pub fn alphabet_mask(len: usize) -> usize", + "spec_doc": "Bit mask used to index an alphabet of len symbols (len >= 2) from a random byte: the smallest all-ones value m with m >= len - 1, i.e. next_power_of_two(len) - 1.", + "bug_class": "logic", + "fidelity": "verbatim_logic", + "extraction_note": "src/lib.rs MASK = $len - 1 is not a bit mask for non-power-of-two alphabets (biased/short alphabet)", + "witness_args": "62usize", + "labels": { + "buggy": "nano-id@0.3.3", + "reference": "nano-id@0.4.0" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/nostr_iv/meta.json b/code/bugfind/bench/kernels/nostr_iv/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..2702371527f8a04a12ec69954dc63a4eafef4231 --- /dev/null +++ b/code/bugfind/bench/kernels/nostr_iv/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-nostr_iv", + "kernel": "nostr_iv", + "advisory": "RUSTSEC-2026-0219", + "crate": "nostr", + "pre_version": "0.44.5", + "post_version": "0.44.6", + "advisory_url": "https://github.com/nostrdevkit/nostr/commit/b24619346f666d08ef7fefe27f033b8bc871697f", + "title": "Remote Denial of Service via malformed NIP-04 IV", + "source_file": "src/nips/nip04.rs", + "function": "load_iv", + "signature": "pub fn load_iv(iv: &[u8]) -> Result<[u8; 16], u8>", + "spec_doc": "Loads a NIP-04 AES-CBC initialisation vector from untrusted bytes; must return Err unless the input is exactly 16 bytes, and must never panic.", + "bug_class": "panic", + "fidelity": "model_of_std", + "extraction_note": "src/nips/nip04.rs decrypt: iv.as_slice().into() panics on wrong length", + "witness_args": "&[1u8, 2, 3]", + "labels": { + "buggy": "nostr@0.44.5", + "reference": "nostr@0.44.6" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/odoh_split/meta.json b/code/bugfind/bench/kernels/odoh_split/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..39765d7e52df5f0e43036e35c3740dbac9169566 --- /dev/null +++ b/code/bugfind/bench/kernels/odoh_split/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-odoh_split", + "kernel": "odoh_split", + "advisory": "RUSTSEC-2023-0095", + "crate": "odoh-rs", + "pre_version": "1.0.1", + "post_version": "1.0.2", + "advisory_url": "https://github.com/cloudflare/odoh-rs/pull/28", + "title": "Invalid Slice Split Results in Server Panic", + "source_file": "src/protocol.rs", + "function": "encrypted_payload_len", + "signature": "pub fn encrypted_payload_len(msg: &[u8], key_size: usize) -> Result", + "spec_doc": "Splits an encrypted ODoH query into an encapsulated key (first key_size bytes) and ciphertext (the rest); returns the ciphertext length, or Err if the message is shorter than key_size. Must not panic on any input.", + "bug_class": "panic", + "fidelity": "model_of_std", + "extraction_note": "src/protocol.rs decrypt_query: split_at(key_size) without length check", + "witness_args": "&[1u8, 2, 3], 32usize", + "labels": { + "buggy": "odoh-rs@1.0.1", + "reference": "odoh-rs@1.0.2" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/phone_ctx/meta.json b/code/bugfind/bench/kernels/phone_ctx/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..e947f1377f2e9795ac0cf11a2a5d1898623d06c8 --- /dev/null +++ b/code/bugfind/bench/kernels/phone_ctx/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-phone_ctx", + "kernel": "phone_ctx", + "advisory": "RUSTSEC-2023-0082", + "crate": "phonenumber", + "pre_version": "0.2.4+8.11.3", + "post_version": "0.2.5+8.11.3", + "advisory_url": "https://github.com/whisperfish/rust-phonenumber/commit/2dd44be94539c051b4dee55d1d9d349bd7bedde6", + "title": "phonenumber: panic on parsing crafted RF3966 phonenumber inputs ", + "source_file": "src/parser/rfc3966.rs", + "function": "context_prefix_skip", + "signature": "pub fn context_prefix_skip(s: &[u8]) -> usize", + "spec_doc": "Returns how many leading bytes of an RFC3966 phone-context value to skip: 1 if it starts with '+', otherwise 0. Must not panic on empty input.", + "bug_class": "panic", + "fidelity": "verbatim_logic", + "extraction_note": "src/parser/rfc3966.rs: s.as_bytes()[0] on empty phone-context", + "witness_args": "&[]", + "labels": { + "buggy": "phonenumber@0.2.4+8.11.3", + "reference": "phonenumber@0.2.5+8.11.3" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/poly1305_key/meta.json b/code/bugfind/bench/kernels/poly1305_key/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..f5ca0c765b2718d26498922605077a89d41cd2d7 --- /dev/null +++ b/code/bugfind/bench/kernels/poly1305_key/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-poly1305_key", + "kernel": "poly1305_key", + "advisory": "RUSTSEC-2026-0073", + "crate": "libcrux-poly1305", + "pre_version": "0.0.4", + "post_version": "0.0.5", + "advisory_url": "https://github.com/cryspen/libcrux/pull/1351", + "title": "Panic in Standalone MAC Operations", + "source_file": "src/lib.rs", + "function": "key_len_ok", + "signature": "pub fn key_len_ok(key: &[u8]) -> bool", + "spec_doc": "Poly1305 one-time keys are r (16 bytes) followed by s (16 bytes): a key is acceptable iff it is exactly 32 bytes.", + "bug_class": "logic", + "fidelity": "verbatim_logic", + "extraction_note": "src/lib.rs KEY_LEN = 16 (standalone mac rejected/panicked on real 32-byte keys)", + "witness_args": "&[0u8; 32]", + "labels": { + "buggy": "libcrux-poly1305@0.0.4", + "reference": "libcrux-poly1305@0.0.5" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/ring_ctr/meta.json b/code/bugfind/bench/kernels/ring_ctr/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..fd2e7eb1338467e684dfdf5a5a63852e6c85ff46 --- /dev/null +++ b/code/bugfind/bench/kernels/ring_ctr/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-ring_ctr", + "kernel": "ring_ctr", + "advisory": "RUSTSEC-2025-0009", + "crate": "ring", + "pre_version": "0.17.11", + "post_version": "0.17.12", + "advisory_url": "https://github.com/briansmith/ring/blob/main/RELEASES.md#version-01712-2025-03-05", + "title": "Some AES functions may panic when overflow checking is enabled.", + "source_file": "src/aead/aes.rs", + "function": "increment_by", + "signature": "pub fn increment_by(old_value: u32, increment_by: u32) -> u32", + "spec_doc": "Increments a 32-bit big-endian AES-GCM block counter, wrapping modulo 2^32.", + "bug_class": "overflow", + "fidelity": "verbatim_logic", + "extraction_note": "src/aead/aes.rs increment_by_less_safe: + panics with overflow checks", + "witness_args": "4294967295u32, 1u32", + "labels": { + "buggy": "ring@0.17.11", + "reference": "ring@0.17.12" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/stack_insert/meta.json b/code/bugfind/bench/kernels/stack_insert/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..ec3c2404e07c779c7fa6707197c0254e4ebc450b --- /dev/null +++ b/code/bugfind/bench/kernels/stack_insert/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-stack_insert", + "kernel": "stack_insert", + "advisory": "RUSTSEC-2020-0042", + "crate": "stack", + "pre_version": "0.3.0", + "post_version": "0.3.1", + "advisory_url": "https://github.com/arcnmx/stack-rs/issues/4", + "title": "Missing check in ArrayVec leads to out-of-bounds write.", + "source_file": "src/vector.rs", + "function": "insert_shift_len", + "signature": "pub fn insert_shift_len(len: usize, index: usize) -> Result", + "spec_doc": "Number of elements to shift when inserting at index into a vector of length len; Err if index > len.", + "bug_class": "panic", + "fidelity": "model_of_std", + "extraction_note": "src/vector.rs insert: missing index <= len assert; copy length len - index wrapped (release) -> OOB write", + "witness_args": "3usize, 5usize", + "labels": { + "buggy": "stack@0.3.0", + "reference": "stack@0.3.1" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/tar_pax/meta.json b/code/bugfind/bench/kernels/tar_pax/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..7bb1a62a2090c34869a47e6fc33e08c4b1133427 --- /dev/null +++ b/code/bugfind/bench/kernels/tar_pax/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-tar_pax", + "kernel": "tar_pax", + "advisory": "RUSTSEC-2026-0145", + "crate": "astral-tokio-tar", + "pre_version": "0.6.1", + "post_version": "0.6.2", + "advisory_url": "https://github.com/astral-sh/tokio-tar/pull/82", + "title": "PAX Header Desynchronization in astral-tokio-tar", + "source_file": "src/archive.rs", + "function": "apply_pax", + "signature": "pub fn apply_pax(entry_type: u8, has_pax: bool) -> bool", + "spec_doc": "PAX extended-header data describes the next file entry. Returns whether pending PAX data must be applied to a header of the given type byte: only for real entries, never for GNU long-name 'L', long-link 'K', PAX local 'x' or global 'g' headers.", + "bug_class": "logic", + "fidelity": "verbatim_logic", + "extraction_note": "src/archive.rs: PAX data applied to extension headers (desynchronisation)", + "witness_args": "b'L', true", + "labels": { + "buggy": "astral-tokio-tar@0.6.1", + "reference": "astral-tokio-tar@0.6.2" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/tinyhttp_hdr/meta.json b/code/bugfind/bench/kernels/tinyhttp_hdr/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..c54cc4fe69ca82852f20432b5a568b8cfe50017a --- /dev/null +++ b/code/bugfind/bench/kernels/tinyhttp_hdr/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-tinyhttp_hdr", + "kernel": "tinyhttp_hdr", + "advisory": "RUSTSEC-2020-0031", + "crate": "tiny_http", + "pre_version": "0.6.2", + "post_version": "0.6.3", + "advisory_url": "https://github.com/tiny-http/tiny-http/issues/173", + "title": "HTTP Request smuggling through malformed Transfer Encoding headers", + "source_file": "src/common.rs", + "function": "header_field_ok", + "signature": "pub fn header_field_ok(s: &[u8]) -> bool", + "spec_doc": "A header field name is valid iff it is ASCII and contains no whitespace (no trimming: ' Transfer-Encoding' and 'Transfer-Encoding ' are invalid).", + "bug_class": "logic", + "fidelity": "verbatim_logic", + "extraction_note": "src/common.rs HeaderField::from_str: trimmed whitespace (request smuggling)", + "witness_args": "b\"Transfer-Encoding \"", + "labels": { + "buggy": "tiny_http@0.6.2", + "reference": "tiny_http@0.6.3" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/toodee_drain/meta.json b/code/bugfind/bench/kernels/toodee_drain/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..f2ee205a7d7c938afa183bbeb591f5ebc752671a --- /dev/null +++ b/code/bugfind/bench/kernels/toodee_drain/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-toodee_drain", + "kernel": "toodee_drain", + "advisory": "RUSTSEC-2025-0062", + "crate": "toodee", + "pre_version": "0.5.0", + "post_version": "0.6.0", + "advisory_url": "https://github.com/antonmarsden/toodee/issues/26", + "title": "Heap Buffer Overflow in the DrainCol Destructor", + "source_file": "src/toodee.rs", + "function": "drain_col_copy_len", + "signature": "pub fn drain_col_copy_len(orig_cols: usize, col: usize) -> usize", + "spec_doc": "When removing column col from a row of orig_cols cells, the number of cells to shift left: those strictly after col (orig_cols - col - 1).", + "bug_class": "overflow", + "fidelity": "verbatim_logic", + "extraction_note": "src/toodee.rs DrainCol::drop: ptr::copy length off by one (heap overflow)", + "witness_args": "5usize, 2usize", + "labels": { + "buggy": "toodee@0.5.0", + "reference": "toodee@0.6.0" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/tract_len/meta.json b/code/bugfind/bench/kernels/tract_len/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..58dc3c3a27d24e3ab307858ca098707ea7bf1de0 --- /dev/null +++ b/code/bugfind/bench/kernels/tract_len/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-tract_len", + "kernel": "tract_len", + "advisory": "RUSTSEC-2026-0217", + "crate": "tract-nnef", + "pre_version": "0.21.15", + "post_version": "0.21.16", + "advisory_url": "https://github.com/sonos/tract/commit/34c7df2c9bd2a36583e09b52f3e6319bf23102e8", + "title": "Integer overflow in tract-nnef NNEF tensor parser leads to out-of-bounds read on model load", + "source_file": "src/tensors.rs", + "function": "tensor_len_ok", + "signature": "pub fn tensor_len_ok(dims: &[usize], bits_per_item: usize, data_size_bytes: usize) -> bool", + "spec_doc": "NNEF tensor header consistency: true iff prod(dims) * (bits_per_item / 8) == data_size_bytes in exact arithmetic (false if the product does not fit usize).", + "bug_class": "overflow", + "fidelity": "verbatim_logic", + "extraction_note": "src/tensors.rs read_tensor: unchecked shape product", + "witness_args": "&[4294967296usize, 4294967296], 8usize, 0usize", + "labels": { + "buggy": "tract-nnef@0.21.15", + "reference": "tract-nnef@0.21.16" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/transpose_dims/meta.json b/code/bugfind/bench/kernels/transpose_dims/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..cab040ec0609deb03c47687334779f948c251b31 --- /dev/null +++ b/code/bugfind/bench/kernels/transpose_dims/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-transpose_dims", + "kernel": "transpose_dims", + "advisory": "RUSTSEC-2023-0080", + "crate": "transpose", + "pre_version": "0.2.2", + "post_version": "0.2.3", + "advisory_url": "https://github.com/ejmahler/transpose/issues/11", + "title": "Buffer overflow due to integer overflow in `transpose`", + "source_file": "src/lib.rs", + "function": "dims_match", + "signature": "pub fn dims_match(width: usize, height: usize, len: usize) -> bool", + "spec_doc": "True iff width * height == len in exact arithmetic (false when the product does not fit usize).", + "bug_class": "overflow", + "fidelity": "verbatim_logic", + "extraction_note": "src/lib.rs transpose: assert_eq!(w*h, len) wraps in release -> buffer overflow", + "witness_args": "4294967296usize, 4294967296usize, 0usize", + "labels": { + "buggy": "transpose@0.2.2", + "reference": "transpose@0.2.3" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/trustdns_ptr/meta.json b/code/bugfind/bench/kernels/trustdns_ptr/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..46c613d07e01a6b2aa1d645da46b9165c057d1d0 --- /dev/null +++ b/code/bugfind/bench/kernels/trustdns_ptr/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-trustdns_ptr", + "kernel": "trustdns_ptr", + "advisory": "RUSTSEC-2018-0007", + "crate": "trust-dns-proto", + "pre_version": "0.4.2", + "post_version": "0.4.3", + "advisory_url": null, + "title": "Stack overflow when parsing malicious DNS packet", + "source_file": "src/rr/domain/name.rs", + "function": "pointer_ok", + "signature": "pub fn pointer_ok(location: usize, pointer_location: usize, name_start: usize) -> bool", + "spec_doc": "A DNS name-compression pointer is acceptable iff its target lies strictly before the start of the name currently being parsed (so pointer chains cannot loop).", + "bug_class": "dos_loop_or_recursion", + "fidelity": "verbatim_logic", + "extraction_note": "src/rr/domain/name.rs Name::read: pointer compared with current label instead of name start (self-referential name)", + "witness_args": "0usize, 2usize, 0usize", + "labels": { + "buggy": "trust-dns-proto@0.4.2", + "reference": "trust-dns-proto@0.4.3" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/kernels/versionize_fam/meta.json b/code/bugfind/bench/kernels/versionize_fam/meta.json new file mode 100644 index 0000000000000000000000000000000000000000..6fd56be9ec5fb4b5d83f519858a48a25d80bacf2 --- /dev/null +++ b/code/bugfind/bench/kernels/versionize_fam/meta.json @@ -0,0 +1,22 @@ +{ + "item_id": "ker-versionize_fam", + "kernel": "versionize_fam", + "advisory": "RUSTSEC-2023-0030", + "crate": "versionize", + "pre_version": "0.1.9", + "post_version": "0.1.10", + "advisory_url": "https://github.com/firecracker-microvm/versionize/pull/53", + "title": "`Versionize::deserialize` implementation for `FamStructWrapper` is lacking bound checks, potentially leading to out of bounds memory accesses ", + "source_file": "src/primitives.rs", + "function": "fam_entry", + "signature": "pub fn fam_entry(entries: &[u32], header_len: usize, i: usize) -> Result", + "spec_doc": "Reads entry i (< header_len) of a deserialised flexible-array struct whose header declares header_len entries; Err if the header length disagrees with the actual number of entries, never panic.", + "bug_class": "panic", + "fidelity": "model_of_std", + "extraction_note": "src/primitives.rs FamStructWrapper::deserialize: header length not checked against entries", + "witness_args": "&[7u32, 8], 5usize, 3usize", + "labels": { + "buggy": "versionize@0.1.9", + "reference": "versionize@0.1.10" + } +} \ No newline at end of file diff --git a/code/bugfind/bench/ledger/baseline_fuzz_sample.jsonl b/code/bugfind/bench/ledger/baseline_fuzz_sample.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..01851edd06ff347924617e633f2eb59b95e995c2 --- /dev/null +++ b/code/bugfind/bench/ledger/baseline_fuzz_sample.jsonl @@ -0,0 +1,8 @@ +{"item_id": "ker-bytes_reserve", "revision": "pre", "property": "p1", "arm": "fuzz", "cpu_budget": 8, "build_seconds": 14.7, "flagged": true, "status": "rc1", "cpu_seconds": 0.2} +{"item_id": "ker-bytes_reserve", "revision": "pre", "property": "p2", "arm": "fuzz", "cpu_budget": 8, "build_seconds": 0.3, "flagged": true, "status": "rc1", "cpu_seconds": 0.2} +{"item_id": "ker-bytes_reserve", "revision": "pre", "property": "p3", "arm": "fuzz", "cpu_budget": 8, "build_seconds": 0.3, "flagged": true, "status": "rc1", "cpu_seconds": 0.2} +{"item_id": "ker-bytes_reserve", "revision": "pre", "property": "p4", "arm": "fuzz", "cpu_budget": 8, "build_seconds": 0.3, "flagged": true, "status": "rc1", "cpu_seconds": 0.2} +{"item_id": "ker-bytes_reserve", "revision": "post", "property": "p1", "arm": "fuzz", "cpu_budget": 8, "build_seconds": 15.6, "flagged": false, "status": "ok", "cpu_seconds": 9.4} +{"item_id": "ker-bytes_reserve", "revision": "post", "property": "p2", "arm": "fuzz", "cpu_budget": 8, "build_seconds": 0.3, "flagged": false, "status": "ok", "cpu_seconds": 9.3} +{"item_id": "ker-bytes_reserve", "revision": "post", "property": "p3", "arm": "fuzz", "cpu_budget": 8, "build_seconds": 0.3, "flagged": false, "status": "ok", "cpu_seconds": 9.3} +{"item_id": "ker-bytes_reserve", "revision": "post", "property": "p4", "arm": "fuzz", "cpu_budget": 8, "build_seconds": 0.3, "flagged": false, "status": "ok", "cpu_seconds": 9.3} diff --git a/code/bugfind/bench/ledger/baseline_kani_smoke.jsonl b/code/bugfind/bench/ledger/baseline_kani_smoke.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..30c37bc94a0320dcf30150379b90151050ce1ba9 --- /dev/null +++ b/code/bugfind/bench/ledger/baseline_kani_smoke.jsonl @@ -0,0 +1,3 @@ +{"item_id": "smoke-tiny", "revision": "pre", "property": "avg_buggy_floor_mean", "arm": "kani", "cpu_budget": 60, "flagged": true, "status": "ok", "cpu_seconds": 0.6} +{"item_id": "smoke-tiny", "revision": "pre", "property": "abs_diff_sym", "arm": "kani", "cpu_budget": 60, "flagged": false, "status": "ok", "cpu_seconds": 0.5} +{"item_id": "smoke-tiny", "revision": "pre", "property": "gcd_divides", "arm": "kani", "cpu_budget": 60, "flagged": true, "status": "ok", "cpu_seconds": 61.0} diff --git a/code/bugfind/bench/ledger/baseline_sweep_proptest.jsonl b/code/bugfind/bench/ledger/baseline_sweep_proptest.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..c56fa5acad22f9273f090b0018409a631618144c --- /dev/null +++ b/code/bugfind/bench/ledger/baseline_sweep_proptest.jsonl @@ -0,0 +1,164 @@ +{"item_id": "ker-bcrypt_split", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.4, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-bcrypt_split", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-bcrypt_split", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-bcrypt_split", "revision": "pre", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-bcrypt_split", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.8, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-bcrypt_split", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-bcrypt_split", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-bcrypt_split", "revision": "post", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-bytes_reserve", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 6.8, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-bytes_reserve", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-bytes_reserve", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-bytes_reserve", "revision": "pre", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-bytes_reserve", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.6, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-bytes_reserve", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-bytes_reserve", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-bytes_reserve", "revision": "post", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-claxon_rice", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.3, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-claxon_rice", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.1, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-claxon_rice", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-claxon_rice", "revision": "pre", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-claxon_rice", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.3, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-claxon_rice", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.1, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-claxon_rice", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-claxon_rice", "revision": "post", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-ecdh_scalar", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.5, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-ecdh_scalar", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-ecdh_scalar", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-ecdh_scalar", "revision": "pre", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-ecdh_scalar", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 6.6, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-ecdh_scalar", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-ecdh_scalar", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-ecdh_scalar", "revision": "post", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-evm_memset", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.5, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-evm_memset", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-evm_memset", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-evm_memset", "revision": "pre", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-evm_memset", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.6, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-evm_memset", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-evm_memset", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-evm_memset", "revision": "post", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-exif_discard", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.6, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-exif_discard", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.1, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-exif_discard", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-exif_discard", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.5, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-exif_discard", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-exif_discard", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-matrix_power", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.3, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-matrix_power", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-matrix_power", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-matrix_power", "revision": "pre", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-matrix_power", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.8, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-matrix_power", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-matrix_power", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-matrix_power", "revision": "post", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_hint", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.2, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_hint", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_hint", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_hint", "revision": "pre", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_hint", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_hint", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_hint", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_hint", "revision": "post", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_norm", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_norm", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_norm", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_norm", "revision": "pre", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_norm", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_norm", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_norm", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-mldsa_norm", "revision": "post", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-nanoid_mask", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.8, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-nanoid_mask", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-nanoid_mask", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-nanoid_mask", "revision": "pre", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-nanoid_mask", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.7, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-nanoid_mask", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-nanoid_mask", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-nanoid_mask", "revision": "post", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-nostr_iv", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.9, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-nostr_iv", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-nostr_iv", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-nostr_iv", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.2, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-nostr_iv", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-nostr_iv", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-odoh_split", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.8, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-odoh_split", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-odoh_split", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-odoh_split", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.6, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-odoh_split", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-odoh_split", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-phone_ctx", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 7.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-phone_ctx", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-phone_ctx", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-phone_ctx", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.7, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-phone_ctx", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-phone_ctx", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.1, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-poly1305_key", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.7, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-poly1305_key", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-poly1305_key", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-poly1305_key", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.1, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-poly1305_key", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-poly1305_key", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-stack_insert", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.8, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-stack_insert", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-stack_insert", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-stack_insert", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.1, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-stack_insert", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-stack_insert", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-tar_pax", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.9, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-tar_pax", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-tar_pax", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-tar_pax", "revision": "pre", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-tar_pax", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.7, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-tar_pax", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-tar_pax", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-tar_pax", "revision": "post", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-tinyhttp_hdr", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.6, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-tinyhttp_hdr", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.9} +{"item_id": "ker-tinyhttp_hdr", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-tinyhttp_hdr", "revision": "pre", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-tinyhttp_hdr", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.8, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-tinyhttp_hdr", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-tinyhttp_hdr", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-tinyhttp_hdr", "revision": "post", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-toodee_drain", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.8, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-toodee_drain", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-toodee_drain", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-toodee_drain", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.5, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-toodee_drain", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-toodee_drain", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-tract_len", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 6.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-tract_len", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-tract_len", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-tract_len", "revision": "pre", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-tract_len", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 7.4, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-tract_len", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-tract_len", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-tract_len", "revision": "post", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-transpose_dims", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.6, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-transpose_dims", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-transpose_dims", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.1, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-transpose_dims", "revision": "pre", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-transpose_dims", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.8, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-transpose_dims", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-transpose_dims", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-transpose_dims", "revision": "post", "property": "p4", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-trustdns_ptr", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 6.2, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-trustdns_ptr", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-trustdns_ptr", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-trustdns_ptr", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.1, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-trustdns_ptr", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-trustdns_ptr", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.0} +{"item_id": "ker-versionize_fam", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 4.8, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-versionize_fam", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-versionize_fam", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-versionize_fam", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 5.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-versionize_fam", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-versionize_fam", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.1} +{"item_id": "ker-ring_ctr", "revision": "pre", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.2, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-ring_ctr", "revision": "pre", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-ring_ctr", "revision": "pre", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": true, "status": "ok", "cpu_seconds": 0.0} +{"item_id": "ker-ring_ctr", "revision": "post", "property": "p1", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.2, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-ring_ctr", "revision": "post", "property": "p2", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} +{"item_id": "ker-ring_ctr", "revision": "post", "property": "p3", "arm": "proptest", "cpu_budget": 4, "build_seconds": 0.0, "flagged": false, "status": "ok", "cpu_seconds": 4.1} diff --git a/code/bugfind/bench/ledger/witness_ledger.jsonl b/code/bugfind/bench/ledger/witness_ledger.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..14cc0f60dba995be50bd655f98527ec669b2bb34 --- /dev/null +++ b/code/bugfind/bench/ledger/witness_ledger.jsonl @@ -0,0 +1,23 @@ +{"item_id": "ker-bcrypt_split", "kind": "kernel_witness", "witness_call": "split_hash_salt_len(&[b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', 0xA3, b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a'])", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "PANIC", "src_sha256": "b44b93d115ebac8be56e48b28f9ff16b8da5d7b2b8cd69049186e4f4626012f2"}, "post": {"outcome": "Err(2)", "src_sha256": "4ce7aa9b37f175c2307260bc7e2ed2404b185fc3cc7489ae77dbf1bb68344747"}, "discriminating": true} +{"item_id": "ker-bytes_reserve", "kind": "kernel_witness", "witness_call": "reserve_fits(10usize, usize::MAX, 1usize)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "PANIC", "src_sha256": "f5f5861e4d7ccd3dddede246d124e471d823263e8e0314c743ffddf60cd8884e"}, "post": {"outcome": "false", "src_sha256": "d2babe4ce5ffeb1ddde217591c5f89cca3dde847529f502ff426d6c703b907d4"}, "discriminating": true} +{"item_id": "ker-claxon_rice", "kind": "kernel_witness", "witness_call": "rice_layout(10u16, 2u32, 0u16)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "Ok(8)", "src_sha256": "c081e74d9538b816245a991a7e2e8e65b190107b8ffd28f9bde1d2db765431dd"}, "post": {"outcome": "Err(2)", "src_sha256": "5dffbba1bb3cd0f04d389521f2e140bfa306336af48627947ab76bac8ced6a03"}, "discriminating": true} +{"item_id": "ker-ecdh_scalar", "kind": "kernel_witness", "witness_call": "validate_x25519_scalar(&[1u8, 2, 3])", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "true", "src_sha256": "94ce460379ed5e5e6ee31d31c2105ad108ddbe61861fdf81655c0dd0c14e7b61"}, "post": {"outcome": "false", "src_sha256": "24f348e04934d1133d3b45f27dfa9582b861e0131f0ec4065b76b18663a44805"}, "discriminating": true} +{"item_id": "ker-evm_memset", "kind": "kernel_witness", "witness_call": "memory_set_len(0usize, 0usize, 0usize, Some(1000usize), 1048576usize)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "Ok(1000)", "src_sha256": "5000aee18ca681616e3b538226f7c56c649ed72dc0c6a6050a7902ce27a81ca3"}, "post": {"outcome": "Ok(0)", "src_sha256": "ca0e6fba91e7456c3f0edc604e63e8cfe25c3035c2c9d297cc269da33c806945"}, "discriminating": true} +{"item_id": "ker-exif_discard", "kind": "kernel_witness", "witness_call": "discard_exact(3usize, 10usize)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "HANG", "src_sha256": "fd930e76d835b2226f0888baa2be6dd323b6d9bee67bbf63cba1bf7d68821fb0"}, "post": {"outcome": "Err(1)", "src_sha256": "9fad60ab96c35dd5ff00c922e07b6af7e567ab0ecadc9d835dd4a56b0bc68dd3"}, "discriminating": true} +{"item_id": "ker-matrix_power", "kind": "kernel_witness", "witness_call": "normalize_power_level(9007199254740991i64, 1i64)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "PANIC", "src_sha256": "16148befb7b75270759774843e4b3592543e7d6c88c3d3b526448b030038d2d7"}, "post": {"outcome": "100", "src_sha256": "174e43989db0e153fe240924d578fa1ce599b65ff374b26db9c6b13255c065bd"}, "discriminating": true} +{"item_id": "ker-mldsa_hint", "kind": "kernel_witness", "witness_call": "hint_weight(&[0u8, 0, 200], 2usize, 1usize)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "PANIC", "src_sha256": "021b98bbb04af2d43ef9320d4b941939c8d74a4f0d88429e4871c8925f09ee15"}, "post": {"outcome": "None", "src_sha256": "a1a877ff5999b7e738546da89e294eacc460d24b84e18f23fa31655fc9538011"}, "discriminating": true} +{"item_id": "ker-mldsa_norm", "kind": "kernel_witness", "witness_call": "response_bound(17u32, 78i32)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "262066", "src_sha256": "177170302aa2db3b3c54970fb06c471bc8234f8f29909c32b24f39efd6aa8a28"}, "post": {"outcome": "130994", "src_sha256": "6200b4873cd55385fd67ffd5af16e5cca7b056c7c64854c873c78de3ff7109c0"}, "discriminating": true} +{"item_id": "ker-nanoid_mask", "kind": "kernel_witness", "witness_call": "alphabet_mask(62usize)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "61", "src_sha256": "f8196c79e8f1e0e5e5e0f77be3710380e2ed62b1acbac4655adcafd39f628c44"}, "post": {"outcome": "63", "src_sha256": "1319fc8b80cee9ae2e40019c726f13bd49888f038656584fd02ae7e2a4d9463d"}, "discriminating": true} +{"item_id": "ker-nostr_iv", "kind": "kernel_witness", "witness_call": "load_iv(&[1u8, 2, 3])", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "PANIC", "src_sha256": "eeb68bdc8d9a4b2163a0dc3a58d3cd8a49595eca7ff523f0984d8c036e2554fe"}, "post": {"outcome": "Err(1)", "src_sha256": "3e18ccb13c3a7504c2ab2c900719727454212c2b033ad8d430599d44d035a9e2"}, "discriminating": true} +{"item_id": "ker-odoh_split", "kind": "kernel_witness", "witness_call": "encrypted_payload_len(&[1u8, 2, 3], 32usize)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "PANIC", "src_sha256": "6c55c01aca43292a9ad7255f9dfbc418e1b48a31b52544d5dc8deb8dca138a38"}, "post": {"outcome": "Err(1)", "src_sha256": "1c29fb49cbf14598ea9e12050642471a38fb43225626832e2bfe36a0012eae27"}, "discriminating": true} +{"item_id": "ker-phone_ctx", "kind": "kernel_witness", "witness_call": "context_prefix_skip(&[])", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "PANIC", "src_sha256": "bab0720c7766dfddbee8353e53c9258b1612280a6942b692aa9ae2f6c1c14596"}, "post": {"outcome": "0", "src_sha256": "3a457a312f5f02bcae76d5538e43c7d6ebb3cc85fd5164ac409c196766f24e1f"}, "discriminating": true} +{"item_id": "ker-poly1305_key", "kind": "kernel_witness", "witness_call": "key_len_ok(&[0u8; 32])", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "false", "src_sha256": "65067fd7911a4f46f33aab3d0c5b7d6321cb6e4ffa5cc094103c04f188cedc5d"}, "post": {"outcome": "true", "src_sha256": "883d391defe651fdfa3322e3241d0f92596577eeebc0bccc852087c54d2d0cd0"}, "discriminating": true} +{"item_id": "ker-ring_ctr", "kind": "kernel_witness", "witness_call": "increment_by(4294967295u32, 1u32)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "PANIC", "src_sha256": "d2987131b64e858a5c01bc2994858d253ee628dc3e9e71cb3bcfbcefbfccba05"}, "post": {"outcome": "0", "src_sha256": "c03ea6ea0570e212a252ebde4f1c3caf99dc24640ce9cac6a0193182eedc5223"}, "discriminating": true} +{"item_id": "ker-stack_insert", "kind": "kernel_witness", "witness_call": "insert_shift_len(3usize, 5usize)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "Ok(18446744073709551614)", "src_sha256": "78f80f1c4315c0540f932e922e49d52fa6f3c1e90a4eaf7e68ea355b5437e839"}, "post": {"outcome": "Err(1)", "src_sha256": "2e50c7afe72e87d4447d089758935008d6e86dad6facde6481503a0c3f99fecc"}, "discriminating": true} +{"item_id": "ker-tar_pax", "kind": "kernel_witness", "witness_call": "apply_pax(b'L', true)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "true", "src_sha256": "37b54733ff78d8893fb5baa36c15002bdf8d2d1ffe0d0f11e5d3997bb5d75d7d"}, "post": {"outcome": "false", "src_sha256": "482f9f22d52fdc5828132c022ad09d724fe3b8a92a5965973a23ccd84d7e1d44"}, "discriminating": true} +{"item_id": "ker-tinyhttp_hdr", "kind": "kernel_witness", "witness_call": "header_field_ok(b\"Transfer-Encoding \")", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "true", "src_sha256": "c8784f5ec30f207faf7a912ef2b0f5a27f5a10449b9af8ded42963c06beb1f15"}, "post": {"outcome": "false", "src_sha256": "fab53ba6b6773e23f538d1dffc35b5d22ec4c0830a89247f83bae25a68641175"}, "discriminating": true} +{"item_id": "ker-toodee_drain", "kind": "kernel_witness", "witness_call": "drain_col_copy_len(5usize, 2usize)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "3", "src_sha256": "ed4c9481353d36412be6dccd1bb6aa5f16103a51e51ded260d2524d6dc7da6d5"}, "post": {"outcome": "2", "src_sha256": "a70f8cf6c2f0bcb046ae0815c8f274decff1410f0ece71023b7e66d07bfbc43b"}, "discriminating": true} +{"item_id": "ker-tract_len", "kind": "kernel_witness", "witness_call": "tensor_len_ok(&[4294967296usize, 4294967296], 8usize, 0usize)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "PANIC", "src_sha256": "5dc3b63b78b925ad828949e72fe39c6f25db1a0208f393a23895f7c748a21bd8"}, "post": {"outcome": "false", "src_sha256": "1e101b341fd568b4b15286a300fc91b12d81fce50a66ad15f587b9ec560592ed"}, "discriminating": true} +{"item_id": "ker-transpose_dims", "kind": "kernel_witness", "witness_call": "dims_match(4294967296usize, 4294967296usize, 0usize)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "PANIC", "src_sha256": "465c50651dd16d7cf162c823ad2e904cc79662d9b55912ad8887ef4d74addeb8"}, "post": {"outcome": "false", "src_sha256": "9338f9cec8a692129a040b001103226d7283b5e0b154d3f82b78ac112bf9dc92"}, "discriminating": true} +{"item_id": "ker-trustdns_ptr", "kind": "kernel_witness", "witness_call": "pointer_ok(0usize, 2usize, 0usize)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "true", "src_sha256": "65d08c5c0a1e1ebb7f0ac6bc378e416dbd207cfe8d270c2f5034d1543072b2ab"}, "post": {"outcome": "false", "src_sha256": "bcde1d1a2f2869c030eb0ac93240b74d8b1180e42ec5af5bcb80e2ecbde78a08"}, "discriminating": true} +{"item_id": "ker-versionize_fam", "kind": "kernel_witness", "witness_call": "fam_entry(&[7u32, 8], 5usize, 3usize)", "toolchain": "rustc 1.99.0 (b940084d7 2026-09-28)", "flags": "-C debug-assertions=on -C overflow-checks=on -C opt-level=0 --edition 2021", "pre": {"outcome": "PANIC", "src_sha256": "4607e9a99d19b430974bf7da1dd60b0b481d9532cbd6733341a80db9bffab302"}, "post": {"outcome": "Err(1)", "src_sha256": "6f07bdc926f36de28c2f1786ddb88913e039fafcba462162aae45c0f9807cf64"}, "discriminating": true} diff --git a/code/bugfind/bench/make_kernels.py b/code/bugfind/bench/make_kernels.py new file mode 100644 index 0000000000000000000000000000000000000000..f3cf5a2ca426302247d3aa4a527b4dfadd80a651 --- /dev/null +++ b/code/bugfind/bench/make_kernels.py @@ -0,0 +1,528 @@ +#!/usr/bin/env python3 -I +"""Minimal-extraction items (Phase 5 Part A, "extract the affected pure function into a minimal standalone crate"). + +Each KERNEL is a hand-extracted, dependency-free reduction of the *decision logic* that a RustSec fix changed +(pre = vulnerable revision's logic, post = patched revision's logic). Whole crates are not translatable (native deps, +dyn traits, early returns in loops, ...: see TOOLCHAIN.md / SUMMARY.json), so the unit is the function kernel. +`fidelity`: + verbatim_logic the changed expression/branch is copied from the crate with std/crate types replaced by integers/slices + model_of_std the vulnerable behaviour lives in a std/crate call (slice split_at, str slicing, unchecked memcpy length); + the kernel models that call's panic/UB condition explicitly. Weaker; reported separately. +Extraction was done by reading the pre/post diff, so kernels are NOT blind to the bug; only the *properties* (property bank) +are authored blind, from `spec_doc` + signature alone (see baselines/bank/README_PROVENANCE.md). + +Writes bench/kernels//{meta.json,pre/{Cargo.toml,src/lib.rs},post/{Cargo.toml,src/lib.rs}}. +""" +import json, os +HERE = os.path.dirname(os.path.abspath(__file__)) +CAND = "/apps/development/rlhf/bugfind_data/out/advisory_candidates.jsonl" +K = [] + +def k(kid, adv, fn, sig, spec_doc, bug_class, fidelity, pre, post, witness, note, file): + K.append(dict(id=kid, adv=adv, fn=fn, sig=sig, spec_doc=spec_doc, bug_class=bug_class, fidelity=fidelity, + pre=pre.strip() + "\n", post=post.strip() + "\n", witness=witness, note=note, file=file)) + +k("claxon_rice", "RUSTSEC-2018-0004", "rice_layout", "pub fn rice_layout(block_size: u16, order: u32, n_warm_up: u16) -> Result", + "Computes how many residual samples a FLAC Rice-coded subframe's 2^order partitions cover (order is a 4-bit field, so order > 15 is rejected with Err). On Ok(n), n must equal block_size (the partitions fill the block); otherwise return Err.", + "logic", "verbatim_logic", + """ +pub fn rice_layout(block_size: u16, order: u32, n_warm_up: u16) -> Result { + if order > 15 { + return Err(3); + } + let n_partitions = 1u32 << order; + let n_samples_per_partition = block_size >> order; + if n_warm_up > n_samples_per_partition { + return Err(1); + } + Ok(n_partitions * (n_samples_per_partition as u32)) +} +""", """ +pub fn rice_layout(block_size: u16, order: u32, n_warm_up: u16) -> Result { + if order > 15 { + return Err(3); + } + let n_partitions = 1u32 << order; + let n_samples_per_partition = block_size >> order; + if block_size & ((n_partitions - 1) as u16) != 0 { + return Err(2); + } + if n_warm_up > n_samples_per_partition { + return Err(1); + } + Ok(n_partitions * (n_samples_per_partition as u32)) +} +""", "10u16, 2u32, 0u16", "src/subframe.rs decode_residual: block size not a multiple of 2^order left buffer tail uninitialised", "src/subframe.rs") + +k("bytes_reserve", "RUSTSEC-2026-0007", "reserve_fits", "pub fn reserve_fits(v_capacity: usize, new_cap: usize, offset: usize) -> bool", + "Decides whether a Vec-backed buffer with capacity v_capacity can serve a reserve request of new_cap bytes when the live window starts at offset; must be true iff v_capacity >= new_cap + offset in exact arithmetic.", + "overflow", "verbatim_logic", + "pub fn reserve_fits(v_capacity: usize, new_cap: usize, offset: usize) -> bool {\n v_capacity >= new_cap + offset\n}", + """ +pub fn reserve_fits(v_capacity: usize, new_cap: usize, offset: usize) -> bool { + match new_cap.checked_add(offset) { + Some(s) => v_capacity >= s, + None => false, + } +} +""", "10usize, usize::MAX, 1usize", "src/bytes_mut.rs reserve_inner: new_cap + offset overflow", "src/bytes_mut.rs") + +k("mldsa_hint", "RUSTSEC-2026-0076", "hint_weight", "pub fn hint_weight(hint: &[u8], max_ones: usize, rows: usize) -> Option", + "Decodes the ML-DSA signature hint encoding: hint[..max_ones] are positions, hint[max_ones..max_ones+rows] are cumulative counts that must be non-decreasing and at most max_ones. Returns the sum of the hint bytes it consumed, or None for a malformed encoding. Must never panic on any input of length >= max_ones+rows.", + "panic", "verbatim_logic", + """ +pub fn hint_weight(hint: &[u8], max_ones: usize, rows: usize) -> Option { + let mut previous = 0usize; + let mut total = 0usize; + let mut bad = false; + let mut i = 0usize; + while i < rows { + let current = hint[max_ones + i] as usize; + if current < previous || previous > max_ones { + bad = true; + } else { + let mut j = previous; + while j < current { + total += hint[j] as usize; + j += 1; + } + previous = current; + } + i += 1; + } + if bad { None } else { Some(total) } +} +""", """ +pub fn hint_weight(hint: &[u8], max_ones: usize, rows: usize) -> Option { + let mut previous = 0usize; + let mut total = 0usize; + let mut bad = false; + let mut i = 0usize; + while i < rows { + let current = hint[max_ones + i] as usize; + if current < previous || current > max_ones { + bad = true; + } else { + let mut j = previous; + while j < current { + total += hint[j] as usize; + j += 1; + } + previous = current; + } + i += 1; + } + if bad { None } else { Some(total) } +} +""", "&[0u8, 0, 200], 2usize, 1usize", "src/ml_dsa_generic.rs / encoding/signature.rs deserialize hint: checked previous instead of current against max_ones", "src/encoding/signature.rs") + +k("mldsa_norm", "RUSTSEC-2026-0076", "response_bound", "pub fn response_bound(gamma1_exponent: u32, beta: i32) -> i32", + "ML-DSA verification bound for the signer response: gamma1 - beta where gamma1 = 2^gamma1_exponent.", + "logic", "verbatim_logic", + "pub fn response_bound(gamma1_exponent: u32, beta: i32) -> i32 {\n (2i32 << gamma1_exponent) - beta\n}", + "pub fn response_bound(gamma1_exponent: u32, beta: i32) -> i32 {\n (1i32 << gamma1_exponent) - beta\n}", + "17u32, 78i32", "src/ml_dsa_generic.rs verify: (2 << GAMMA1_EXPONENT) - BETA instead of (1 << ...) - BETA", "src/ml_dsa_generic.rs") + +k("odoh_split", "RUSTSEC-2023-0095", "encrypted_payload_len", "pub fn encrypted_payload_len(msg: &[u8], key_size: usize) -> Result", + "Splits an encrypted ODoH query into an encapsulated key (first key_size bytes) and ciphertext (the rest); returns the ciphertext length, or Err if the message is shorter than key_size. Must not panic on any input.", + "panic", "model_of_std", + "pub fn encrypted_payload_len(msg: &[u8], key_size: usize) -> Result {\n let ct = &msg[key_size..];\n Ok(ct.len())\n}", + "pub fn encrypted_payload_len(msg: &[u8], key_size: usize) -> Result {\n if key_size > msg.len() {\n return Err(1);\n }\n let ct = &msg[key_size..];\n Ok(ct.len())\n}", + "&[1u8, 2, 3], 32usize", "src/protocol.rs decrypt_query: split_at(key_size) without length check", "src/protocol.rs") + +k("matrix_power", "RUSTSEC-2025-0065", "normalize_power_level", "pub fn normalize_power_level(power_level: i64, max_power_level: i64) -> i64", + "Scales a Matrix user power level (|power_level| < 2^53) to the range 0..=100 relative to max_power_level > 0.", + "panic", "verbatim_logic", + """ +const INT_MAX: i64 = 9007199254740991; +pub fn normalize_power_level(power_level: i64, max_power_level: i64) -> i64 { + let n = (power_level * 100) / max_power_level; + assert!(n >= -INT_MAX && n <= INT_MAX); + n +} +""", """ +pub fn normalize_power_level(power_level: i64, max_power_level: i64) -> i64 { + let n = (power_level * 100) / max_power_level; + if n < 0 { + 0 + } else if n > 100 { + 100 + } else { + n + } +} +""", "9007199254740991i64, 1i64", "src/room/members.rs normalized_power_level: expect() on out-of-range Int when max_power_level is small", "src/room/members.rs") + +k("nostr_iv", "RUSTSEC-2026-0219", "load_iv", "pub fn load_iv(iv: &[u8]) -> Result<[u8; 16], u8>", + "Loads a NIP-04 AES-CBC initialisation vector from untrusted bytes; must return Err unless the input is exactly 16 bytes, and must never panic.", + "panic", "model_of_std", + """ +pub fn load_iv(iv: &[u8]) -> Result<[u8; 16], u8> { + let mut out = [0u8; 16]; + let mut i = 0usize; + while i < 16 { + out[i] = iv[i]; + i += 1; + } + Ok(out) +} +""", """ +pub fn load_iv(iv: &[u8]) -> Result<[u8; 16], u8> { + if iv.len() != 16 { + return Err(1); + } + let mut out = [0u8; 16]; + let mut i = 0usize; + while i < 16 { + out[i] = iv[i]; + i += 1; + } + Ok(out) +} +""", "&[1u8, 2, 3]", "src/nips/nip04.rs decrypt: iv.as_slice().into() panics on wrong length", "src/nips/nip04.rs") + +k("phone_ctx", "RUSTSEC-2023-0082", "context_prefix_skip", "pub fn context_prefix_skip(s: &[u8]) -> usize", + "Returns how many leading bytes of an RFC3966 phone-context value to skip: 1 if it starts with '+', otherwise 0. Must not panic on empty input.", + "panic", "verbatim_logic", + "pub fn context_prefix_skip(s: &[u8]) -> usize {\n if s[0] == b'+' { 1 } else { 0 }\n}", + "pub fn context_prefix_skip(s: &[u8]) -> usize {\n if !s.is_empty() && s[0] == b'+' { 1 } else { 0 }\n}", + "&[]", "src/parser/rfc3966.rs: s.as_bytes()[0] on empty phone-context", "src/parser/rfc3966.rs") + +k("poly1305_key", "RUSTSEC-2026-0073", "key_len_ok", "pub fn key_len_ok(key: &[u8]) -> bool", + "Poly1305 one-time keys are r (16 bytes) followed by s (16 bytes): a key is acceptable iff it is exactly 32 bytes.", + "logic", "verbatim_logic", + "pub const KEY_LEN: usize = 16;\npub fn key_len_ok(key: &[u8]) -> bool {\n key.len() == KEY_LEN\n}", + "pub const KEY_LEN: usize = 32;\npub fn key_len_ok(key: &[u8]) -> bool {\n key.len() == KEY_LEN\n}", + "&[0u8; 32]", "src/lib.rs KEY_LEN = 16 (standalone mac rejected/panicked on real 32-byte keys)", "src/lib.rs") + +k("ecdh_scalar", "RUSTSEC-2026-0023", "validate_x25519_scalar", "pub fn validate_x25519_scalar(s: &[u8]) -> bool", + "Validates an X25519 secret scalar: must be exactly 32 bytes, not all zero, and clamped (low 3 bits of byte 0 clear, top bit of byte 31 clear, second-highest bit of byte 31 set).", + "logic", "verbatim_logic", + """ +pub fn validate_x25519_scalar(s: &[u8]) -> bool { + let mut all_zero = true; + let mut i = 0usize; + while i < s.len() { + if s[i] != 0 { + all_zero = false; + } + i += 1; + } + !all_zero +} +""", """ +pub fn validate_x25519_scalar(s: &[u8]) -> bool { + if s.len() != 32 { + return false; + } + let mut all_zero = true; + let mut i = 0usize; + while i < s.len() { + if s[i] != 0 { + all_zero = false; + } + i += 1; + } + if all_zero { + return false; + } + (s[0] & 7) == 0 && (s[31] & 128) == 0 && (s[31] & 64) != 0 +} +""", "&[1u8, 2, 3]", "src/ecdh.rs validate_scalar: only checked all-zero", "src/ecdh.rs") + +k("nanoid_mask", "RUSTSEC-2024-0343", "alphabet_mask", "pub fn alphabet_mask(len: usize) -> usize", + "Bit mask used to index an alphabet of len symbols (len >= 2) from a random byte: the smallest all-ones value m with m >= len - 1, i.e. next_power_of_two(len) - 1.", + "logic", "verbatim_logic", + "pub fn alphabet_mask(len: usize) -> usize {\n len - 1\n}", + """ +pub fn alphabet_mask(len: usize) -> usize { + let mut p = 1usize; + while p < len { + p = p * 2; + } + p - 1 +} +""", "62usize", "src/lib.rs MASK = $len - 1 is not a bit mask for non-power-of-two alphabets (biased/short alphabet)", "src/lib.rs") + +k("tar_pax", "RUSTSEC-2026-0145", "apply_pax", "pub fn apply_pax(entry_type: u8, has_pax: bool) -> bool", + "PAX extended-header data describes the next file entry. Returns whether pending PAX data must be applied to a header of the given type byte: only for real entries, never for GNU long-name 'L', long-link 'K', PAX local 'x' or global 'g' headers.", + "logic", "verbatim_logic", + "pub fn apply_pax(entry_type: u8, has_pax: bool) -> bool {\n has_pax\n}", + """ +pub fn apply_pax(entry_type: u8, has_pax: bool) -> bool { + let mut is_extension_header = false; + if entry_type == b'L' || entry_type == b'K' || entry_type == b'x' || entry_type == b'g' { + is_extension_header = true; + } + if has_pax { + if is_extension_header { false } else { true } + } else { + false + } +} +""", "b'L', true", "src/archive.rs: PAX data applied to extension headers (desynchronisation)", "src/archive.rs") + +k("exif_discard", "RUSTSEC-2021-0143", "discard_exact", "pub fn discard_exact(avail: usize, len: usize) -> Result", + "Models skipping len bytes of a reader that has only avail bytes: returns Ok(number of read rounds) when the reader had enough data, Err when it hits EOF early. Must terminate on every input.", + "dos_loop_or_recursion", "verbatim_logic", + """ +pub fn discard_exact(avail: usize, len: usize) -> Result { + let mut avail = avail; + let mut len = len; + let mut rounds = 0usize; + while len > 0 { + let consume_len = if avail < len { avail } else { len }; + avail -= consume_len; + len -= consume_len; + rounds += 1; + } + Ok(rounds) +} +""", """ +pub fn discard_exact(avail: usize, len: usize) -> Result { + let mut avail = avail; + let mut len = len; + let mut rounds = 0usize; + let mut eof = false; + while len > 0 && !eof { + let consume_len = if avail < len { avail } else { len }; + if consume_len == 0 { + eof = true; + } else { + avail -= consume_len; + len -= consume_len; + rounds += 1; + } + } + if eof { Err(1) } else { Ok(rounds) } +} +""", "3usize, 10usize", "src/util.rs discard_exact: spins forever at EOF (consume_len == 0)", "src/util.rs") + +k("trustdns_ptr", "RUSTSEC-2018-0007", "pointer_ok", "pub fn pointer_ok(location: usize, pointer_location: usize, name_start: usize) -> bool", + "A DNS name-compression pointer is acceptable iff its target lies strictly before the start of the name currently being parsed (so pointer chains cannot loop).", + "dos_loop_or_recursion", "verbatim_logic", + "pub fn pointer_ok(location: usize, pointer_location: usize, name_start: usize) -> bool {\n let _ = name_start;\n location < pointer_location\n}", + "pub fn pointer_ok(location: usize, pointer_location: usize, name_start: usize) -> bool {\n let _ = pointer_location;\n location < name_start\n}", + "0usize, 2usize, 0usize", "src/rr/domain/name.rs Name::read: pointer compared with current label instead of name start (self-referential name)", "src/rr/domain/name.rs") + +k("ring_ctr", "RUSTSEC-2025-0009", "increment_by", "pub fn increment_by(old_value: u32, increment_by: u32) -> u32", + "Increments a 32-bit big-endian AES-GCM block counter, wrapping modulo 2^32.", + "overflow", "verbatim_logic", + "pub fn increment_by(old_value: u32, increment_by: u32) -> u32 {\n old_value + increment_by\n}", + "pub fn increment_by(old_value: u32, increment_by: u32) -> u32 {\n old_value.wrapping_add(increment_by)\n}", + "4294967295u32, 1u32", "src/aead/aes.rs increment_by_less_safe: + panics with overflow checks", "src/aead/aes.rs") + +k("stack_insert", "RUSTSEC-2020-0042", "insert_shift_len", "pub fn insert_shift_len(len: usize, index: usize) -> Result", + "Number of elements to shift when inserting at index into a vector of length len; Err if index > len.", + "panic", "model_of_std", + "pub fn insert_shift_len(len: usize, index: usize) -> Result {\n Ok(len.wrapping_sub(index))\n}", + "pub fn insert_shift_len(len: usize, index: usize) -> Result {\n if index > len {\n return Err(1);\n }\n Ok(len - index)\n}", + "3usize, 5usize", "src/vector.rs insert: missing index <= len assert; copy length len - index wrapped (release) -> OOB write", "src/vector.rs") + +k("tract_len", "RUSTSEC-2026-0217", "tensor_len_ok", "pub fn tensor_len_ok(dims: &[usize], bits_per_item: usize, data_size_bytes: usize) -> bool", + "NNEF tensor header consistency: true iff prod(dims) * (bits_per_item / 8) == data_size_bytes in exact arithmetic (false if the product does not fit usize).", + "overflow", "verbatim_logic", + """ +pub fn tensor_len_ok(dims: &[usize], bits_per_item: usize, data_size_bytes: usize) -> bool { + let mut len = 1usize; + let mut i = 0usize; + while i < dims.len() { + len = len * dims[i]; + i += 1; + } + len * (bits_per_item / 8) == data_size_bytes +} +""", """ +pub fn tensor_len_ok(dims: &[usize], bits_per_item: usize, data_size_bytes: usize) -> bool { + let mut len = 1usize; + let mut overflow = false; + let mut i = 0usize; + while i < dims.len() { + let d = dims[i]; + if d != 0 && len > usize::MAX / d { + overflow = true; + } else { + len = len * d; + } + i += 1; + } + if overflow { + return false; + } + let per = bits_per_item / 8; + if per != 0 && len > usize::MAX / per { + return false; + } + len * per == data_size_bytes +} +""", "&[4294967296usize, 4294967296], 8usize, 0usize", "src/tensors.rs read_tensor: unchecked shape product", "src/tensors.rs") + +k("transpose_dims", "RUSTSEC-2023-0080", "dims_match", "pub fn dims_match(width: usize, height: usize, len: usize) -> bool", + "True iff width * height == len in exact arithmetic (false when the product does not fit usize).", + "overflow", "verbatim_logic", + "pub fn dims_match(width: usize, height: usize, len: usize) -> bool {\n width * height == len\n}", + "pub fn dims_match(width: usize, height: usize, len: usize) -> bool {\n match width.checked_mul(height) {\n Some(p) => p == len,\n None => false,\n }\n}", + "4294967296usize, 4294967296usize, 0usize", "src/lib.rs transpose: assert_eq!(w*h, len) wraps in release -> buffer overflow", "src/lib.rs") + +k("toodee_drain", "RUSTSEC-2025-0062", "drain_col_copy_len", "pub fn drain_col_copy_len(orig_cols: usize, col: usize) -> usize", + "When removing column col from a row of orig_cols cells, the number of cells to shift left: those strictly after col (orig_cols - col - 1).", + "overflow", "verbatim_logic", + "pub fn drain_col_copy_len(orig_cols: usize, col: usize) -> usize {\n orig_cols - col\n}", + "pub fn drain_col_copy_len(orig_cols: usize, col: usize) -> usize {\n orig_cols - col - 1\n}", + "5usize, 2usize", "src/toodee.rs DrainCol::drop: ptr::copy length off by one (heap overflow)", "src/toodee.rs") + +k("tinyhttp_hdr", "RUSTSEC-2020-0031", "header_field_ok", "pub fn header_field_ok(s: &[u8]) -> bool", + "A header field name is valid iff it is ASCII and contains no whitespace (no trimming: ' Transfer-Encoding' and 'Transfer-Encoding ' are invalid).", + "logic", "verbatim_logic", + """ +fn is_ws(b: u8) -> bool { + b == b' ' || b == b'\\t' || b == b'\\n' || b == b'\\r' || b == 11u8 || b == 12u8 +} +pub fn header_field_ok(s: &[u8]) -> bool { + let mut start = 0usize; + let mut end = s.len(); + while start < end && is_ws(s[start]) { + start += 1; + } + while end > start && is_ws(s[end - 1]) { + end -= 1; + } + let mut ok = true; + let mut i = start; + while i < end { + if s[i] >= 128 { + ok = false; + } + i += 1; + } + ok +} +""", """ +fn is_ws(b: u8) -> bool { + b == b' ' || b == b'\\t' || b == b'\\n' || b == b'\\r' || b == 11u8 || b == 12u8 +} +pub fn header_field_ok(s: &[u8]) -> bool { + let mut ok = true; + let mut i = 0usize; + while i < s.len() { + if s[i] >= 128 || is_ws(s[i]) { + ok = false; + } + i += 1; + } + ok +} +""", "b\"Transfer-Encoding \"", "src/common.rs HeaderField::from_str: trimmed whitespace (request smuggling)", "src/common.rs") + +k("evm_memset", "RUSTSEC-2021-0066", "memory_set_len", "pub fn memory_set_len(cur_len: usize, offset: usize, value_len: usize, target_size: Option, limit: usize) -> Result", + "New length of EVM memory after writing value (value_len bytes) at offset, zero-padded to target_size (default value_len). Err if offset+target_size exceeds limit. Writing an empty value must not grow memory.", + "dos_loop_or_recursion", "verbatim_logic", + """ +pub fn memory_set_len(cur_len: usize, offset: usize, value_len: usize, target_size: Option, limit: usize) -> Result { + let target = match target_size { + Some(t) => t, + None => value_len, + }; + match offset.checked_add(target) { + Some(pos) => { + if pos > limit { + return Err(1); + } + } + None => return Err(1), + } + if cur_len < offset + target { + Ok(offset + target) + } else { + Ok(cur_len) + } +} +""", """ +pub fn memory_set_len(cur_len: usize, offset: usize, value_len: usize, target_size: Option, limit: usize) -> Result { + if value_len == 0 { + return Ok(cur_len); + } + let target = match target_size { + Some(t) => t, + None => value_len, + }; + match offset.checked_add(target) { + Some(pos) => { + if pos > limit { + return Err(1); + } + } + None => return Err(1), + } + if cur_len < offset + target { + Ok(offset + target) + } else { + Ok(cur_len) + } +} +""", "0usize, 0usize, 0usize, Some(1000usize), 1048576usize", "src/memory.rs Memory::set: empty value with large target_size over-allocates", "src/memory.rs") + +k("bcrypt_split", "RUSTSEC-2026-0199", "split_hash_salt_len", "pub fn split_hash_salt_len(hash: &[u8]) -> Result", + "Validates a bcrypt hash string and returns the salt length (22). A valid hash is exactly 60 ASCII bytes; every other input must give Err, never panic.", + "panic", "model_of_std", + """ +fn is_char_boundary(b: u8) -> bool { + b < 128 || b >= 192 +} +pub fn split_hash_salt_len(hash: &[u8]) -> Result { + if hash.len() != 60 { + return Err(1); + } + assert!(is_char_boundary(hash[22])); + Ok(22) +} +""", """ +pub fn split_hash_salt_len(hash: &[u8]) -> Result { + if hash.len() != 60 { + return Err(1); + } + let mut ascii = true; + let mut i = 0usize; + while i < hash.len() { + if hash[i] >= 128 { + ascii = false; + } + i += 1; + } + if !ascii { + return Err(2); + } + Ok(22) +} +""", "&[b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', 0xA3, b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a']", + "src/lib.rs split_hash: &str slicing at a non-char-boundary on non-ASCII 60-byte input", "src/lib.rs") + +k("versionize_fam", "RUSTSEC-2023-0030", "fam_entry", "pub fn fam_entry(entries: &[u32], header_len: usize, i: usize) -> Result", + "Reads entry i (< header_len) of a deserialised flexible-array struct whose header declares header_len entries; Err if the header length disagrees with the actual number of entries, never panic.", + "panic", "model_of_std", + "pub fn fam_entry(entries: &[u32], header_len: usize, i: usize) -> Result {\n if i < header_len {\n Ok(entries[i])\n } else {\n Err(2)\n }\n}", + "pub fn fam_entry(entries: &[u32], header_len: usize, i: usize) -> Result {\n if header_len != entries.len() {\n return Err(1);\n }\n if i < header_len {\n Ok(entries[i])\n } else {\n Err(2)\n }\n}", + "&[7u32, 8], 5usize, 3usize", "src/primitives.rs FamStructWrapper::deserialize: header length not checked against entries", "src/primitives.rs") + + +def main(): + cand = {} + for l in open(CAND): + r = json.loads(l); cand[r["adv_id"]] = r + root = os.path.join(HERE, "kernels") + for e in K: + c = cand[e["adv"]] + d = os.path.join(root, e["id"]) + for ver in ("pre", "post"): + os.makedirs(f"{d}/{ver}/src", exist_ok=True) + open(f"{d}/{ver}/Cargo.toml", "w").write(f'[package]\nname = "k_{e["id"]}_{ver}"\nversion = "0.1.0"\nedition = "2021"\n\n[lib]\npath = "src/lib.rs"\n\n[workspace]\n') + open(f"{d}/{ver}/src/lib.rs", "w").write(e[ver]) + meta = dict(item_id=f"ker-{e['id']}", kernel=e["id"], advisory=e["adv"], crate=c["crate"], pre_version=c["pre_version"], post_version=c["post_version"], + advisory_url=c["url"], title=c["title"], source_file=e["file"], function=e["fn"], signature=e["sig"], spec_doc=e["spec_doc"], + bug_class=e["bug_class"], fidelity=e["fidelity"], extraction_note=e["note"], witness_args=e["witness"], + labels={"buggy": f"{c['crate']}@{c['pre_version']}", "reference": f"{c['crate']}@{c['post_version']}"}) + json.dump(meta, open(f"{d}/meta.json", "w"), indent=1) + print(len(K), "kernels written to", root) + +if __name__ == "__main__": + main() diff --git a/code/bugfind/bench/mutate.py b/code/bugfind/bench/mutate.py new file mode 100644 index 0000000000000000000000000000000000000000..fad569686c2c6ef0aa1e4d2fcd945c705e28680e --- /dev/null +++ b/code/bugfind/bench/mutate.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python3 -I +"""Part A (d): cargo-mutants-style mutant generator for small pure Rust functions, with a +differential-execution non-equivalence check. + +For each function in corpus/functions.json, every (operator, site) pair yields one mutant. +A mutant is KEPT only if (1) it compiles, and (2) a concrete input exists on which the mutant's +observable outcome (return value, or panic) differs from the original's. That input is stored as +the witness, so non-equivalence is demonstrated, not assumed. Mutants with no witness within the +input budget are recorded as `no_witness` (likely equivalent) and excluded. Timeouts (mutant hangs) +are recorded as `timeout` and excluded (no witness input is available from a killed process). + +Usage: mutate.py [--out DIR] [--budget N] [--only name,...] [--workdir DIR] +Workdir/out must be under /apps (never /tmp or /home). +""" +import argparse, itertools, json, os, re, subprocess, sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +TOK = re.compile(r"\s+|//[^\n]*|\d+(?:_\d+)*(?:[ui](?:8|16|32|64|128|size))?|[A-Za-z_]\w*|<<=|>>=|<<|>>|<=|>=|==|!=|&&|\|\||->|=>|\+=|-=|\*=|/=|%=|&=|\|=|\^=|::|\.\.=?|.", re.S) + +SWAP = {"+": ["-"], "-": ["+"], "*": ["+"], "/": ["*"], "%": ["/"], "<": ["<=", ">"], "<=": ["<", ">="], ">": [">=", "<"], ">=": [">", "<="], + "==": ["!="], "!=": ["=="], "&&": ["||"], "||": ["&&"], "&": ["|"], "|": ["&"], "^": ["|"], "<<": [">>"], ">>": ["<<"], + "+=": ["-="], "-=": ["+="], "*=": ["+="], "/=": ["*="], "<<=": [">>="], ">>=": ["<<="], "&=": ["|="], "|=": ["&="]} +BINARY_PREV_OK = re.compile(r"[\w\)\]]$") + + +def split_fn(src): + i = src.index("{") # first brace: end of the signature (no generics/where in corpus) + return src[:i], src[i:] + + +def toks(body): + return TOK.findall(body) + + +def sites(body): + """Yield (token_index, kind, replacement) for every mutation site in the body.""" + t = toks(body) + sig = [i for i, x in enumerate(t) if not x.isspace() and not x.startswith("//")] + for n, i in enumerate(sig): + x = t[i] + prev = t[sig[n - 1]] if n else "" + nxt = t[sig[n + 1]] if n + 1 < len(sig) else "" + if x in SWAP: + # a binary operator needs an operand token before it; skips unary -, &, and `|closure|` + if x in ("-", "&", "*", "|") and not (BINARY_PREV_OK.search(prev) and prev not in ("as", "return", "in", "if", "while", "else", "let", "mut")): + continue + # `<`/`>` after an identifier followed by a type (generics/turbofish) are excluded by the corpus + for r in SWAP[x]: + yield i, "op", r + elif re.fullmatch(r"\d+(?:_\d+)*", x) and prev not in ("::", "."): + v = int(x.replace("_", "")) + for r in sorted({v + 1, max(v - 1, 0), 0 if v else 1} - {v}): + yield i, "const", str(r) + elif re.fullmatch(r"\d+(?:_\d+)*[ui](?:8|16|32|64|128|size)", x): + m = re.match(r"(\d+)(.*)", x); v = int(m.group(1)) + for r in sorted({v + 1, max(v - 1, 0)} - {v}): + yield i, "const", f"{r}{m.group(2)}" + elif x in ("true", "false"): + yield i, "bool", "false" if x == "true" else "true" + elif x in ("checked_add", "checked_sub", "checked_mul"): + yield i, "checked", {"checked_add": "checked_sub", "checked_sub": "checked_add", "checked_mul": "checked_add"}[x] + + +def apply(body, idx, rep): + t = toks(body) + t[idx] = rep + return "".join(t) + + +def rust_ty_gen(ty, k): + """Expression (Rust) of an input of type ty drawn from index k of a combined stream.""" + return None + + +HARNESS = r''' +#![allow(unused, arithmetic_overflow, unconditional_panic)] +mod orig { include!("orig.rs"); } +mod mutant { include!("mutant.rs"); } +use std::panic::{catch_unwind, AssertUnwindSafe}; +struct Rng(u64); +impl Rng { fn next(&mut self) -> u64 { self.0 ^= self.0 << 13; self.0 ^= self.0 >> 7; self.0 ^= self.0 << 17; self.0 } } +__GENS__ +fn main() { + std::panic::set_hook(Box::new(|_| {})); + let mut rng = Rng(0x9E3779B97F4A7C15); + let mut n: u64 = 0; + __LOOPS__ +} +''' + + +def gen_fn(ty): + if ty == "bool": + return "fn g_bool(r: &mut Rng, i: u64) -> bool { if i < 2 { i == 1 } else { r.next() & 1 == 1 } }" + bits = {"u8": 8, "u16": 16, "u32": 32, "u64": 64, "usize": 64, "i32": 32, "i64": 64}[ty] + signed = ty.startswith("i") + edge = "[0, 1, 2, 3, 7, 8, 9, 10, 15, 16, 100, 127, 128, 255, 256, 1000, 65535, 65536, 0x7fff_ffff, 0x8000_0000, 0xffff_ffff, 0x7fff_ffff_ffff_ffff, 0xffff_ffff_ffff_ffff]" + return (f"fn g_{ty}(r: &mut Rng, i: u64) -> {ty} {{ const E: [u64; 23] = {edge}; " + f"if (i as usize) < E.len() * 2 {{ let e = E[(i as usize / 2) % E.len()]; " + f"if i % 2 == 0 {{ e as {ty} }} else {{ (e as {ty}).wrapping_neg() }} }} else {{ let x = r.next(); " + f"let sh = (x >> 58) as u32 % {bits}; ((r.next() >> sh) as {ty}) }} }}") + + +def build_harness(fn): + tys = sorted(set(fn["args"])) + gens = "\n".join(gen_fn(t) for t in tys) + n = len(fn["args"]) + # edge grid over the first two args, random for the rest; then pure random + names = [f"a{k}" for k in range(n)] + loop = [] + loop.append("let budget: u64 = BUDGET;") + loop.append("let mut it: u64 = 0;") + loop.append("while it < budget {") + for k, t in enumerate(fn["args"]): + idx = {0: "it % 64", 1: "(it / 64) % 64"}.get(k, "it") + loop.append(f" let a{k}: {t} = if it < 4096 {{ g_{t}(&mut rng, {idx}) }} else {{ g_{t}(&mut rng, 1000 + it) }};") + call = ", ".join(names) + loop.append(f" let o = catch_unwind(AssertUnwindSafe(|| format!(\"{{:?}}\", orig::{fn['name']}({call}))));") + loop.append(f" let m = catch_unwind(AssertUnwindSafe(|| format!(\"{{:?}}\", mutant::{fn['name']}({call}))));") + loop.append(" let os = match &o { Ok(s) => s.clone(), Err(_) => \"PANIC\".to_string() };") + loop.append(" let ms = match &m { Ok(s) => s.clone(), Err(_) => \"PANIC\".to_string() };") + fmt = ",".join(f'"{{:?}}"' for _ in names) + loop.append(f" if os != ms {{ println!(\"DIFF [{{}}] orig={{}} mutant={{}}\", format!(\"{{:?}}\", ({call},)), os, ms); return; }}") + loop.append(" it += 1;") + loop.append("}") + loop.append('println!("SAME");') + return HARNESS.replace("__GENS__", gens).replace("__LOOPS__", "\n ".join(loop)) + + +def run(cmd, cwd, timeout): + try: + p = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, timeout=timeout) + return p.returncode, p.stdout, p.stderr + except subprocess.TimeoutExpired: + return -9, "", "timeout" + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--out", default="/apps/development/rlhf/bugfind_data/out/mutants.jsonl") + ap.add_argument("--workdir", default="/apps/development/rlhf/bugfind_data/work/mutants") + ap.add_argument("--budget", type=int, default=2_000_000) + ap.add_argument("--only", default="") + ap.add_argument("--rustc", default="/usr/bin/rustc") # system rustc 1.88 (the rustup shim has no default toolchain) + a = ap.parse_args() + for p in (a.out, a.workdir): + if not os.path.abspath(p).startswith("/apps/"): sys.exit("paths must be under /apps") + os.makedirs(a.workdir, exist_ok=True); os.makedirs(os.path.dirname(a.out), exist_ok=True) + corpus = json.load(open(os.path.join(HERE, "corpus", "functions.json"))) + only = set(filter(None, a.only.split(","))) + stats = {"generated": 0, "compile_fail": 0, "kept": 0, "no_witness": 0, "timeout": 0} + per_fn = {} + out = open(a.out, "w") + for fn in corpus: + if only and fn["name"] not in only: continue + sig, body = split_fn(fn["src"]) + d = os.path.join(a.workdir, fn["name"]); os.makedirs(d, exist_ok=True) + open(os.path.join(d, "orig.rs"), "w").write(fn["src"] + "\n") + open(os.path.join(d, "main.rs"), "w").write(build_harness(fn).replace("BUDGET", str(a.budget))) + ms = list(sites(body)) + per_fn[fn["name"]] = {"generated": len(ms), "kept": 0} + for k, (idx, kind, rep) in enumerate(ms): + stats["generated"] += 1 + mut_body = apply(body, idx, rep) + orig_tok = toks(body)[idx] + msrc = sig + mut_body + open(os.path.join(d, "mutant.rs"), "w").write(msrc + "\n") + rc, so, se = run(["nice", "-n", "15", a.rustc, "--edition", "2021", "-C", "opt-level=1", "-C", "overflow-checks=on", "-C", "debuginfo=0", + "-A", "warnings", "main.rs", "-o", "h.bin"], d, 120) + rec = dict(item_id=f"mut-{fn['name']}-{k:03d}", kind="mutant", function=fn["name"], operator=kind, orig_token=orig_tok, new_token=rep, + token_index=idx, original_source=fn["src"], mutant_source=msrc, spec_doc=fn["doc"]) + if rc != 0: + stats["compile_fail"] += 1; rec["status"] = "compile_fail"; out.write(json.dumps(rec) + "\n"); continue + rc, so, se = run(["nice", "-n", "15", "./h.bin"], d, 60) + if rc == -9: + stats["timeout"] += 1; rec["status"] = "timeout" + elif so.startswith("DIFF"): + stats["kept"] += 1; per_fn[fn["name"]]["kept"] += 1 + rec["status"] = "kept_nonequivalent"; rec["witness"] = so.strip() + else: + stats["no_witness"] += 1; rec["status"] = "no_witness" + out.write(json.dumps(rec) + "\n"); out.flush() + json.dump({"totals": stats, "per_function": per_fn}, open(os.path.join(os.path.dirname(a.out), "mutant_funnel.json"), "w"), indent=1) + print(json.dumps(stats)) + +if __name__ == "__main__": + main() diff --git a/code/bugfind/bench/replay_flag.py b/code/bugfind/bench/replay_flag.py new file mode 100644 index 0000000000000000000000000000000000000000..5533ef5617f80b8edb6586b1b35dd7d2efb5331e --- /dev/null +++ b/code/bugfind/bench/replay_flag.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 -I +"""Replay ONE arm-reported witness on the unmodified Rust of a kernel (pre and post) and emit a ledger line. +Usage (under hostguard): replay_flag.py KERNEL 'RUST_ARGS' [--arm NAME] [--claim TEXT] >> bench/ledger/flag_ledger.jsonl +A flag is credited iff replay.pre misbehaves (PANIC/HANG, or a value that violates a bank property) and replay.post does not. +Here `discriminating` is the mechanical part (outcomes differ); property-violation judging is done by the scorer.""" +import argparse, json, os, subprocess, sys +HERE = os.path.dirname(os.path.abspath(__file__)); sys.path.insert(0, HERE) +import witness_replay as W +ap = argparse.ArgumentParser(); ap.add_argument("kernel"); ap.add_argument("args"); ap.add_argument("--arm", default="manual"); ap.add_argument("--claim", default="") +a = ap.parse_args() +m = json.load(open(f"{W.KER}/{a.kernel}/meta.json")); os.makedirs(W.WORK, exist_ok=True) +src = f"{W.WORK}/flag_{a.kernel}.rs"; binp = f"{W.WORK}/flag_{a.kernel}.bin" +open(src, "w").write(W.TPL.format(pre=f"{W.KER}/{a.kernel}/pre/src/lib.rs", post=f"{W.KER}/{a.kernel}/post/src/lib.rs", fn=m["function"], args=a.args)) +c = subprocess.run(["rustc", *W.FLAGS, "-o", binp, src], capture_output=True, text=True, timeout=120) +if c.returncode: sys.exit("compile error: " + c.stderr[-300:]) +pre, post = W.run(binp, "pre"), W.run(binp, "post") +print(json.dumps(dict(item_id=m["item_id"], kind="flag_replay", arm=a.arm, claim=a.claim, witness_call=f'{m["function"]}({a.args})', + toolchain=subprocess.run(["rustc", "--version"], capture_output=True, text=True).stdout.strip(), flags=" ".join(W.FLAGS), + replay=dict(pre=pre, post=post), discriminating=pre != post, + src_sha256=dict(pre=W.sha(f"{W.KER}/{a.kernel}/pre/src/lib.rs"), post=W.sha(f"{W.KER}/{a.kernel}/post/src/lib.rs"))))) diff --git a/code/bugfind/bench/select_advisories.py b/code/bugfind/bench/select_advisories.py new file mode 100644 index 0000000000000000000000000000000000000000..8a533f211f92e042ffbf2f3780fa23b9203be4be --- /dev/null +++ b/code/bugfind/bench/select_advisories.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python3 -I +"""Part A (a)-(c): RustSec advisory-db -> candidate pre-fix/post-fix crate-version pairs. + +Stages (each counted in out/advisory_funnel.json): + parsed every crates/*/RUSTSEC-*.md advisory + has_patch not informational, has [versions].patched, not "malicious" + resolved pre-fix and post-fix versions exist on crates.io (sparse index), pre != post + downloaded both .crate tarballs fetched and unpacked + small_diff src/**/*.rs diff <= MAX_DIFF_LINES changed lines and >=1 changed .rs file + diff_safe changed lines contain no unsafe/async/io/fs/net/thread/extern/ffi tokens + strict_safe (subset of diff_safe) changed files contain no `unsafe` at all +The Charon/Aeneas translation stage is run by translate_items.py afterwards. + +Usage: select_advisories.py [--db DIR] [--data DIR] [--out FILE] [--limit N] +No state is written under /home or /tmp (urllib + a data dir under /apps). +""" +import argparse, json, os, re, subprocess, sys, tarfile, tomllib, urllib.request, io +from concurrent.futures import ThreadPoolExecutor +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import semverlite as sv + +MAX_DIFF_LINES = 300 +UA = {"User-Agent": "align-bugfind-bench (tgptsupport@trustt.com)"} +BAD = re.compile(r"\bunsafe\b|\basync\b|\.await\b|std::(io|fs|net|thread|process|env)\b|\bextern\b|\bffi\b|\bFile\b|\bTcp|\bUdp|libc::|\bmpsc\b|\bMutex\b|\bArc\b") +CLASS = [("overflow", r"overflow|underflow|wrap"), ("panic", r"\bpanic|unwrap|abort|assert|index out|out[- ]of[- ]bounds|slice"), + ("dos_loop_or_recursion", r"infinite loop|stack overflow|recursion|exhaust|unbounded|quadratic|hang"), + ("logic", r"incorrect|wrong|bypass|validation|parse|parsing|decod")] + + +def http(url): + req = urllib.request.Request(url, headers=UA) + with urllib.request.urlopen(req, timeout=60) as r: + return r.read() + + +def index_path(name): + n = name.lower() + if len(n) == 1: return f"1/{n}" + if len(n) == 2: return f"2/{n}" + if len(n) == 3: return f"3/{n[0]}/{n}" + return f"{n[:2]}/{n[2:4]}/{n}" + + +def parse_advisories(db): + out = [] + for p in sorted(os.scandir(os.path.join(db, "crates")), key=lambda e: e.name): + for f in sorted(os.listdir(p.path)): + if not f.endswith(".md"): continue + txt = open(os.path.join(p.path, f), encoding="utf8").read() + m = re.match(r"```toml\n(.*?)\n```\n(.*)", txt, re.S) + if not m: continue + try: + t = tomllib.loads(m.group(1)) + except Exception: + continue + a = t.get("advisory", {}) + out.append(dict(id=a.get("id"), package=a.get("package"), date=str(a.get("date")), url=a.get("url"), + categories=a.get("categories", []), keywords=a.get("keywords", []), + informational=a.get("informational"), withdrawn=a.get("withdrawn"), + patched=t.get("versions", {}).get("patched", []), + unaffected=t.get("versions", {}).get("unaffected", []), + functions=sorted(t.get("affected", {}).get("functions", {}).keys()), + title=m.group(2).strip().split("\n")[0].lstrip("# "), body=m.group(2)[:1500])) + return out + + +def resolve(adv, cache): + name = adv["package"] + try: + raw = http("https://index.crates.io/" + index_path(name)).decode() + except Exception as e: + return None, f"index:{e}" + vers = [] + for line in raw.splitlines(): + j = json.loads(line) + if j.get("yanked") or sv.is_pre(j["vers"]): continue + vers.append(j["vers"]) + vers.sort(key=sv.key) + patched = [v for v in vers if sv.matches_any(v, adv["patched"])] + if not patched: return None, "no_published_patched_version" + post = patched[0] + cands = [v for v in vers if sv.key(v) < sv.key(post) and not sv.matches_any(v, adv["patched"]) and not sv.matches_any(v, adv["unaffected"])] + if not cands: return None, "no_published_vulnerable_version" + return (cands[-1], post), None + + +def fetch_crate(name, ver, data): + d = os.path.join(data, "crates", f"{name}-{ver}") + if os.path.isdir(d): return d + blob = http(f"https://static.crates.io/crates/{name}/{name}-{ver}.crate") + os.makedirs(os.path.join(data, "crates"), exist_ok=True) + tmp = d + ".part" + with tarfile.open(fileobj=io.BytesIO(blob), mode="r:gz") as tf: + tf.extractall(tmp, filter="data") + os.rename(os.path.join(tmp, f"{name}-{ver}"), d) + os.rmdir(tmp) + return d + + +def rs_files(root): + r = {} + for dp, _, fs in os.walk(os.path.join(root, "src")): + for f in fs: + if f.endswith(".rs"): + p = os.path.join(dp, f) + r[os.path.relpath(p, root)] = open(p, encoding="utf8", errors="replace").read() + return r + + +def analyse_diff(pre, post): + import difflib + a, b = rs_files(pre), rs_files(post) + changed, lines, bad_lines = [], 0, [] + for f in sorted(set(a) | set(b)): + if a.get(f) == b.get(f): continue + changed.append(f) + for l in difflib.unified_diff(a.get(f, "").splitlines(), b.get(f, "").splitlines(), lineterm="", n=0): + if l.startswith(("+++", "---", "@@")): continue + lines += 1 + if BAD.search(l): bad_lines.append(l[:120]) + file_unsafe = sum(len(re.findall(r"\bunsafe\b", (a.get(f, "") + b.get(f, "")))) for f in changed) + return dict(changed_files=changed, changed_lines=lines, bad_line_count=len(bad_lines), bad_line_samples=bad_lines[:3], unsafe_in_changed_files=file_unsafe) + + +def classify(adv): + t = (adv["title"] + " " + " ".join(adv["keywords"]) + " " + adv["body"]).lower() + return [c for c, rx in CLASS if re.search(rx, t)] or ["other"] + + +def process(adv, data): + rec = dict(adv_id=adv["id"], crate=adv["package"], date=adv["date"], url=adv["url"], title=adv["title"], categories=adv["categories"], + affected_functions=adv["functions"], bug_class=classify(adv)) + r, why = resolve(adv, None) + if r is None: + rec["stage"], rec["reject"] = "has_patch", why; return rec + rec["pre_version"], rec["post_version"] = r + try: + pre = fetch_crate(adv["package"], r[0], data); post = fetch_crate(adv["package"], r[1], data) + except Exception as e: + rec["stage"], rec["reject"] = "resolved", f"download:{e}"; return rec + rec["pre_dir"], rec["post_dir"] = pre, post + rec.update(analyse_diff(pre, post)) + if not rec["changed_files"]: rec["stage"], rec["reject"] = "downloaded", "no_rs_diff"; return rec + if rec["changed_lines"] > MAX_DIFF_LINES: rec["stage"], rec["reject"] = "downloaded", "diff_too_large"; return rec + rec["stage"] = "small_diff" + if rec["bad_line_count"]: rec["reject"] = "diff_touches_unsafe_io_async"; return rec + rec["stage"] = "diff_safe" + if rec["unsafe_in_changed_files"] == 0: rec["stage"] = "strict_safe" + return rec + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--db", default="/apps/development/rlhf/bugfind_data/advisory-db") + ap.add_argument("--data", default="/apps/development/rlhf/bugfind_data") + ap.add_argument("--out", default=None) + ap.add_argument("--limit", type=int, default=0) + a = ap.parse_args() + if not a.data.startswith("/apps/"): sys.exit("data dir must be under /apps") + out = a.out or os.path.join(a.data, "out", "advisory_candidates.jsonl") + os.makedirs(os.path.dirname(out), exist_ok=True) + advs = parse_advisories(a.db) + funnel = {"parsed": len(advs)} + keep = [x for x in advs if x["patched"] and not x["informational"] and not x["withdrawn"] and "malicious" not in x["categories"]] + funnel["has_patch"] = len(keep) + if a.limit: keep = keep[: a.limit] + with ThreadPoolExecutor(4) as ex: + recs = list(ex.map(lambda x: process(x, a.data), keep)) + funnel["resolved"] = sum(1 for r in recs if "pre_version" in r) + funnel["downloaded"] = sum(1 for r in recs if "pre_dir" in r) + funnel["small_diff"] = sum(1 for r in recs if r["stage"] in ("small_diff", "diff_safe", "strict_safe")) + funnel["diff_safe"] = sum(1 for r in recs if r["stage"] in ("diff_safe", "strict_safe")) + funnel["strict_safe"] = sum(1 for r in recs if r["stage"] == "strict_safe") + funnel["reject_reasons"] = {} + for r in recs: + if r.get("reject"): funnel["reject_reasons"][r["reject"].split(":")[0]] = funnel["reject_reasons"].get(r["reject"].split(":")[0], 0) + 1 + with open(out, "w") as f: + for r in recs: f.write(json.dumps(r) + "\n") + json.dump(funnel, open(os.path.join(os.path.dirname(out), "advisory_funnel.json"), "w"), indent=1) + print(json.dumps(funnel)) + +if __name__ == "__main__": + main() diff --git a/code/bugfind/bench/semverlite.py b/code/bugfind/bench/semverlite.py new file mode 100644 index 0000000000000000000000000000000000000000..999136648fcac3512d1660523d809b29cf46b28b --- /dev/null +++ b/code/bugfind/bench/semverlite.py @@ -0,0 +1,89 @@ +"""Minimal Cargo-style semver parsing/matching (enough for RustSec version ranges).""" +import re + +_V = re.compile(r"^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-([0-9A-Za-z.-]+))?(?:\+.*)?$") + + +def parse(v): + m = _V.match(v.strip()) + if not m: + raise ValueError(v) + a, b, c, pre = m.groups() + return (int(a), int(b or 0), int(c or 0)), pre + + +def key(v): + t, pre = parse(v) + # prerelease sorts before release + return (t, 0 if pre else 1, pre or "") + + +def is_pre(v): + return parse(v)[1] is not None + + +def _parts(s): + m = _V.match(s.strip()) + a, b, c, pre = m.groups() + return int(a), (None if b is None else int(b)), (None if c is None else int(c)), pre + + +def _cmp_one(v, op, rhs): + kv = key(v) + kr = key(rhs) + if op == "=": + a, b, c, _ = _parts(rhs) + t = kv[0] + if b is None: + return t[0] == a + if c is None: + return t[0] == a and t[1] == b + return kv == kr + if op == "<": + return kv < kr + if op == "<=": + a, b, c, _ = _parts(rhs) + if c is None: # "<= 1.2" means < 1.3 style; be permissive + hi = (a, (b if b is not None else 0), 10**9) + return kv[0] <= hi + return kv <= kr + if op == ">": + return kv > kr + if op == ">=": + return kv >= kr + if op == "^" or op == "": + a, b, c, _ = _parts(rhs) + lo = kr + if a > 0 or b is None: + hi = (a + 1, 0, 0) + elif b > 0 or c is None: + hi = (0, b + 1, 0) + else: + hi = (0, 0, c + 1) + return kv >= lo and kv[0] < hi + if op == "~": + a, b, c, _ = _parts(rhs) + hi = (a + 1, 0, 0) if b is None else (a, b + 1, 0) + return kv >= kr and kv[0] < hi + raise ValueError(op) + + +_C = re.compile(r"^\s*(<=|>=|=|<|>|\^|~)?\s*(\S+)\s*$") + + +def matches_req(v, req): + """req: comma-separated comparator list; all must hold.""" + for part in req.split(","): + m = _C.match(part) + if not m: + raise ValueError(req) + op, rhs = m.groups() + if rhs.endswith(".*"): + rhs, op = rhs[:-2], "=" + if not _cmp_one(v, op or "", rhs): + return False + return True + + +def matches_any(v, reqs): + return any(matches_req(v, r) for r in reqs) diff --git a/code/bugfind/bench/translate_items.py b/code/bugfind/bench/translate_items.py new file mode 100644 index 0000000000000000000000000000000000000000..c073026a99fba674c221ea4b7d3655a4b2e8fb7d --- /dev/null +++ b/code/bugfind/bench/translate_items.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 -I +"""Translate the affected function(s) of candidate items with Charon then Aeneas (Lean backend), and check +that the generated Lean compiles against the Aeneas library. + +Advisory items: Charon `--start-from-if-exists` on the functions whose bodies changed between the vulnerable and +the patched crate version (difffuncs.py), so the unit of translation is "the changed function plus its in-crate +callees", not the whole crate (whole-crate translation of real crates fails on Aeneas limitations; see TOOLCHAIN.md). +Mutant items (--mutants): the one-function crate is translated whole. + +Per-item output fields: + charon_ok exit 0 and an .llbc was written aeneas_ok exit 0, no `[Error]` lines, .lean written + fn_present every start function appears as a `def` in the Lean output (not dropped / opaque) + lean_ok the generated Lean file compiles (lean --root, Aeneas lib on LEAN_PATH); only attempted if aeneas_ok + translated charon_ok and aeneas_ok and fn_present and lean_ok +Run after `source env.sh`. Concurrency: --jobs workers x CARGO_BUILD_JOBS=2 (default 2x2 = 4 build jobs), nice -n 15. +""" +import argparse, json, os, re, shutil, subprocess, sys, time +from concurrent.futures import ThreadPoolExecutor +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import difffuncs + +TC = os.environ.get("TC", "/apps/development/rlhf/toolchains") +CHARON = os.environ.get("CHARON", f"{TC}/src/aeneas/charon/bin/charon") +AENEAS = os.environ.get("AENEAS", f"{TC}/src/aeneas/bin/aeneas") +LEAN_DIR = f"{TC}/src/aeneas/backends/lean" +ANSI = re.compile(r"\x1b\[[0-9;?]*[a-zA-Z]") +_LP = None + + +def lean_path(): + global _LP + if _LP is None: + o = subprocess.run(["lake", "env", "printenv", "LEAN_PATH"], cwd=LEAN_DIR, capture_output=True, text=True).stdout.strip() + _LP = ":".join(dict.fromkeys(o.split(":"))) + return _LP + + +def start_patterns(fns): + pats = [] + for _rel, mod, name in fns: + base = "crate::" + (mod + "::" if mod else "") + pats += [base + name, base + "_::" + name] + return list(dict.fromkeys(pats)) + + +def lean_compile(out, leanfile, timeout): + env = dict(os.environ, LEAN_PATH=lean_path() + ":" + out) + mod = os.path.splitext(os.path.basename(leanfile))[0] + p = subprocess.run(["nice", "-n", "15", "lean", f"--root={out}", "-o", os.path.join(out, mod + ".olean"), leanfile], + cwd=LEAN_DIR, env=env, capture_output=True, text=True, timeout=timeout) + return p.returncode == 0, (p.stdout + p.stderr)[-300:] + + +def one(it, work, timeout): + t0 = time.time() + name = it.get("adv_id") or it["item_id"] + d = it["pre_dir"] + out = os.path.join(work, name); shutil.rmtree(out, ignore_errors=True); os.makedirs(out) + res = dict(item=name, crate=it.get("crate"), charon_ok=False, aeneas_ok=False, fn_present=False, lean_ok=False, translated=False) + cmd = ["nice", "-n", "15", CHARON, "cargo", "--preset=aeneas", "--dest-file", os.path.join(out, "crate.llbc")] + names = [] + if "post_dir" in it: + fns = difffuncs.changed_functions(d, it["post_dir"]) + res["changed_functions"] = [f"{m}::{n}" if m else n for _r, m, n in fns] + if not fns: + res["error"] = "no_changed_function_identified"; res["seconds"] = round(time.time() - t0, 1); return res + for p in start_patterns(fns): cmd += ["--start-from-if-exists", p] + names = sorted({n for _r, _m, n in fns}) + env = dict(os.environ, CARGO_TARGET_DIR=os.path.join(out, "target"), CARGO_BUILD_JOBS="2") + res["mode"] = "start_from_changed_fns" if names else "whole_crate" + try: + p = subprocess.run(cmd, cwd=d, env=env, capture_output=True, text=True, timeout=timeout) + log = ANSI.sub("", p.stdout + p.stderr) + res["charon_ok"] = p.returncode == 0 and os.path.exists(os.path.join(out, "crate.llbc")) + if not res["charon_ok"]: + errs = [l for l in log.splitlines() if re.match(r"\s*(error|Error)", l)] + res["error"] = ("charon: " + (errs[0] if errs else log[-300:]))[:300] + except subprocess.TimeoutExpired: + res["error"] = "charon timeout" + if res["charon_ok"]: + try: + p = subprocess.run(["nice", "-n", "15", AENEAS, "-backend", "lean", "-no-progress-bar", os.path.join(out, "crate.llbc"), "-dest", out], + capture_output=True, text=True, timeout=timeout) + log = ANSI.sub("", p.stdout + p.stderr) + leans = [f for f in os.listdir(out) if f.endswith(".lean")] + nerr = len(re.findall(r"\[\s*Error\s*\]", log)) + res["n_aeneas_errors"] = nerr + res["aeneas_ok"] = p.returncode == 0 and nerr == 0 and bool(leans) + if not res["aeneas_ok"]: + errs = [l for l in log.splitlines() if "Error" in l] + res["error"] = ("aeneas: " + (errs[0] if errs else log[-200:]))[:300] + elif leans: + src = open(os.path.join(out, leans[0]), encoding="utf8").read() + res["fn_present"] = all(re.search(rf"^(?:@\[[^\]]*\]\s*)*def\s+(?:[\w.]*\.)?{re.escape(n)}(?:_loop)?\b", src, re.M) for n in names) if names else True + res["lean_file"] = leans[0]; res["lean_lines"] = src.count("\n") + if names and not res["fn_present"] and res["mode"] == "start_from_changed_fns": + # patterns matched nothing (trait-impl methods, cfg'd-out code): retry from the whole crate + res["mode"] = "whole_crate_fallback" + cmd2 = ["nice", "-n", "15", CHARON, "cargo", "--preset=aeneas", "--dest-file", os.path.join(out, "crate.llbc")] + subprocess.run(cmd2, cwd=d, env=env, capture_output=True, text=True, timeout=timeout) + p = subprocess.run(["nice", "-n", "15", AENEAS, "-backend", "lean", "-no-progress-bar", os.path.join(out, "crate.llbc"), "-dest", out], + capture_output=True, text=True, timeout=timeout) + log = ANSI.sub("", p.stdout + p.stderr) + res["n_aeneas_errors"] = len(re.findall(r"\[\s*Error\s*\]", log)) + leans = [f for f in os.listdir(out) if f.endswith(".lean")] + if leans: + src = open(os.path.join(out, leans[0]), encoding="utf8").read() + res["fn_present"] = all(re.search(rf"^(?:@\[[^\]]*\]\s*)*def\s+(?:[\w.]*\.)?{re.escape(n)}(?:_loop)?\b", src, re.M) for n in names) + res["lean_file"] = leans[0]; res["lean_lines"] = src.count("\n") + # failures elsewhere in the crate are tolerated here: Aeneas drops failing decls, and what we need is the target fn + res["aeneas_ok"] = True + if res["fn_present"]: + ok, msg = lean_compile(out, os.path.join(out, leans[0]), timeout) + res["lean_ok"] = ok + if not ok: res["error"] = "lean: " + msg + else: + res["error"] = "start function not in generated Lean" + except subprocess.TimeoutExpired: + res["error"] = "aeneas/lean timeout" + res["translated"] = res["charon_ok"] and res["aeneas_ok"] and res["fn_present"] and res["lean_ok"] + shutil.rmtree(os.path.join(out, "target"), ignore_errors=True) # keep llbc + lean, drop build products + res["seconds"] = round(time.time() - t0, 1) + return res + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("items"); ap.add_argument("--out", required=True) + ap.add_argument("--work", default="/apps/development/rlhf/bugfind_data/work/translate") + ap.add_argument("--jobs", type=int, default=2); ap.add_argument("--timeout", type=int, default=600) + ap.add_argument("--mutants", action="store_true") + ap.add_argument("--stages", default="diff_safe,strict_safe"); ap.add_argument("--limit", type=int, default=0) + ap.add_argument("--max-changed-fns", type=int, default=3, help="advisory items touching more functions are not 'targeted fixes'") + a = ap.parse_args() + for p in (a.out, a.work): + if not os.path.abspath(p).startswith("/apps/"): sys.exit("paths must be under /apps") + items = [json.loads(l) for l in open(a.items)] + if a.mutants: # materialise each kept mutant as a one-file crate (`lib.rs` = the mutated function) + items = [i for i in items if i.get("status") == "kept_nonequivalent"] + for i in items: + d = os.path.join(a.work, "_crates", i["item_id"]); os.makedirs(d + "/src", exist_ok=True) + open(d + "/Cargo.toml", "w").write(f'[package]\nname = "m_{i["function"]}"\nversion = "0.1.0"\nedition = "2021"\n\n[workspace]\n') + open(d + "/src/lib.rs", "w").write(i["mutant_source"] + "\n") + i["pre_dir"], i["stage"] = d, "diff_safe" + items = [i for i in items if "pre_dir" in i and i.get("stage") in a.stages.split(",")] + pre_skip = [] + if not a.mutants: + keep = [] + for i in items: + n = len(difffuncs.changed_functions(i["pre_dir"], i["post_dir"])) + i["n_changed_fns"] = n + (keep if 1 <= n <= a.max_changed_fns else pre_skip).append(i) + items = keep + json.dump({"skipped_not_targeted_or_no_fn": len(pre_skip), "to_attempt": len(items)}, open(a.out + ".prefilter.json", "w")) + items.sort(key=lambda i: (i.get("stage") != "strict_safe", i.get("n_changed_fns", 0))) + if a.limit: items = items[: a.limit] + done = {} + if os.path.exists(a.out): + for l in open(a.out): r = json.loads(l); done[r["item"]] = r + todo = [i for i in items if (i.get("adv_id") or i["item_id"]) not in done] + os.makedirs(a.work, exist_ok=True) + with open(a.out, "a") as f, ThreadPoolExecutor(a.jobs) as ex: + for r in ex.map(lambda i: one(i, a.work, a.timeout), todo): + f.write(json.dumps(r) + "\n"); f.flush() + print(r["item"], "T" if r["translated"] else "-", r.get("error", "")[:80], r["seconds"], flush=True) + +if __name__ == "__main__": + main() diff --git a/code/bugfind/bench/translate_kernels.py b/code/bugfind/bench/translate_kernels.py new file mode 100644 index 0000000000000000000000000000000000000000..41e583305f885365bd0a9151d12d5447d5a16b7a --- /dev/null +++ b/code/bugfind/bench/translate_kernels.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 -I +"""Translate every kernel (pre AND post revision) with Charon -> Aeneas(Lean) and compile the Lean against the pinned +Aeneas library, by reusing translate_items.one() in whole-crate mode. SERIAL by design (host-safety rules); run under hostguard. +Output: JSONL, one line per (kernel, version), with sha256 of the generated Lean (ledger hash of translated definitions). +An item (kernel) is KEPT iff both revisions translate and compile (a pair is needed: pre = positive, post = negative control).""" +import hashlib, json, os, sys +HERE = os.path.dirname(os.path.abspath(__file__)); sys.path.insert(0, HERE) +import translate_items as T +OUTF = sys.argv[1] if len(sys.argv) > 1 else "/apps/development/rlhf/bugfind_data/out/kernel_translate.jsonl" +WORK = "/apps/development/rlhf/bugfind_data/work/kernels" +only = set(sys.argv[2].split(",")) if len(sys.argv) > 2 else None +os.makedirs(WORK, exist_ok=True) +done = {} +if os.path.exists(OUTF): + for l in open(OUTF): r = json.loads(l); done[r["item"]] = r +with open(OUTF, "a") as f: + for kid in sorted(os.listdir(f"{HERE}/kernels")): + if only and kid not in only: continue + for ver in ("pre", "post"): + name = f"{kid}.{ver}" + if name in done: continue + d = f"{HERE}/kernels/{kid}/{ver}" + r = T.one(dict(item_id=name, crate=kid, pre_dir=d, stage="diff_safe"), WORK, 600) + r["kernel"], r["version"] = kid, ver + if r.get("lean_file"): + r["lean_sha256"] = hashlib.sha256(open(os.path.join(WORK, name, r["lean_file"]), "rb").read()).hexdigest() + f.write(json.dumps(r) + "\n"); f.flush() + print(name, "T" if r["translated"] else "-", r.get("error", "")[:100], r["seconds"], flush=True) diff --git a/code/bugfind/bench/witness_replay.py b/code/bugfind/bench/witness_replay.py new file mode 100644 index 0000000000000000000000000000000000000000..5d045a02f0571b77f9d50e433ca7d380a8b113f1 --- /dev/null +++ b/code/bugfind/bench/witness_replay.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 -I +"""Witness ledger writer: replay each kernel's witness on the ORIGINAL Rust (pre and post revisions of the kernel) under +the pinned system rustc with debug-assertions + overflow-checks ON, and record the observed outcomes. +An item is `discriminating` iff outcomes differ (pre misbehaves, post is the fix). Outcome strings: `Ok(..)`/value Debug +text, `PANIC`, `HANG` (5 s wall-clock kill). +Ledger line (bench/ledger/witness_ledger.jsonl): + {item_id, kind:"kernel_witness", witness_call, toolchain, flags, pre:{outcome,src_sha256}, post:{outcome,src_sha256}, discriminating} +The same line format is used by arm flags (prover/reviewer/baseline): {item_id, arm, claim, witness_call, replay:{pre,post}, ...}; +a flag is only credited if `replay.pre` shows the claimed misbehaviour on the unmodified original and `replay.post` does not. +Run under hostguard (it compiles with rustc): see TOOLCHAIN.md. +""" +import hashlib, json, os, subprocess, sys +HERE = os.path.dirname(os.path.abspath(__file__)) +KER = os.path.join(HERE, "kernels"); OUT = os.path.join(HERE, "ledger"); os.makedirs(OUT, exist_ok=True) +WORK = os.environ.get("WITNESS_WORK", "/apps/development/rlhf/bugfind_data/work/witness") +FLAGS = ["-C", "debug-assertions=on", "-C", "overflow-checks=on", "-C", "opt-level=0", "--edition", "2021"] +TPL = """#![allow(dead_code, unused_variables, unused_comparisons)] +mod pre {{ include!("{pre}"); }} +mod post {{ include!("{post}"); }} +fn main() {{ + let which = std::env::args().nth(1).unwrap(); + std::panic::set_hook(Box::new(|_| {{}})); + let r = std::panic::catch_unwind(|| {{ + if which == "pre" {{ format!("{{:?}}", pre::{fn}({args})) }} else {{ format!("{{:?}}", post::{fn}({args})) }} + }}); + match r {{ Ok(s) => println!("{{}}", s), Err(_) => println!("PANIC") }} +}} +""" + +def sha(p): return hashlib.sha256(open(p, "rb").read()).hexdigest() + +def run(binp, which): + try: + p = subprocess.run(["nice", "-n", "15", binp, which], capture_output=True, text=True, timeout=5) + return p.stdout.strip() or ("PANIC" if p.returncode else "EMPTY") + except subprocess.TimeoutExpired: + return "HANG" + +def main(): + os.makedirs(WORK, exist_ok=True) + ver = subprocess.run(["rustc", "--version"], capture_output=True, text=True).stdout.strip() + rows = [] + for kid in sorted(os.listdir(KER)): + m = json.load(open(f"{KER}/{kid}/meta.json")) + src = f"{WORK}/{kid}.rs"; binp = f"{WORK}/{kid}.bin" + open(src, "w").write(TPL.format(pre=f"{KER}/{kid}/pre/src/lib.rs", post=f"{KER}/{kid}/post/src/lib.rs", fn=m["function"], args=m["witness_args"])) + c = subprocess.run(["rustc", *FLAGS, "-o", binp, src], capture_output=True, text=True, timeout=120) + if c.returncode: + rows.append(dict(item_id=m["item_id"], error="compile: " + c.stderr[-300:], discriminating=False)); continue + a, b = run(binp, "pre"), run(binp, "post") + rows.append(dict(item_id=m["item_id"], kind="kernel_witness", witness_call=f'{m["function"]}({m["witness_args"]})', toolchain=ver, + flags=" ".join(FLAGS), pre=dict(outcome=a, src_sha256=sha(f"{KER}/{kid}/pre/src/lib.rs")), + post=dict(outcome=b, src_sha256=sha(f"{KER}/{kid}/post/src/lib.rs")), discriminating=a != b)) + print(m["item_id"], "pre=", a[:40], "post=", b[:40], "DISC" if a != b else "SAME", flush=True) + with open(f"{OUT}/witness_ledger.jsonl", "w") as f: + for r in rows: f.write(json.dumps(r) + "\n") + print("discriminating:", sum(r["discriminating"] for r in rows), "of", len(rows)) + +if __name__ == "__main__": + main() diff --git a/code/bugfind/smoke/Check.lean b/code/bugfind/smoke/Check.lean new file mode 100644 index 0000000000000000000000000000000000000000..d5adbc4036ac36d625c676c5f29d187ab934a8b4 --- /dev/null +++ b/code/bugfind/smoke/Check.lean @@ -0,0 +1,25 @@ +import Aeneas +import Tiny +open Aeneas Aeneas.Std Result + +-- Seeded bug: `avg_buggy` is meant to be floor((a+b)/2) but `a + b` overflows U32. +-- Kernel-checked witness that it panics (integer overflow) on a valid input pair. +theorem avg_buggy_overflows : + tiny.avg_buggy 4294967295#u32 4294967295#u32 = fail Error.integerOverflow := by + unfold tiny.avg_buggy + simp +decide [HAdd.hAdd, Std.UScalar.add, Std.UScalar.tryMk, Std.UScalar.tryMkOpt] + +-- The functional spec only holds under a no-overflow precondition (this is the property a prover arm would +-- have to find; the negation above is the disproof of the unconditional version). +theorem avg_buggy_spec_needs_pre (a b : U32) (h : a.val + b.val ≤ U32.max) : + tiny.avg_buggy a b ⦃ r => r.val = (a.val + b.val) / 2 ⦄ := by + unfold tiny.avg_buggy + step* + +-- A correct function: total (no panic) and correct on every input. +theorem abs_diff_correct (a b : U32) : + tiny.abs_diff a b ⦃ r => r.val = Int.natAbs (a.val - b.val) ⦄ := by + unfold tiny.abs_diff + split + · step* + · step* diff --git a/code/bugfind/smoke/run_smoke.sh b/code/bugfind/smoke/run_smoke.sh new file mode 100644 index 0000000000000000000000000000000000000000..deb8c56f004a1091f672fa8b9802fef9b7288cd3 --- /dev/null +++ b/code/bugfind/smoke/run_smoke.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Smoke test: tiny pure-Rust crate -> LLBC (Charon) -> Lean (Aeneas) -> Lean compiles; the seeded overflow bug +# (`avg_buggy`) is exhibited as a kernel-checked failure witness, the correct functions are proved panic-free. +set -euo pipefail +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$HERE/../env.sh"; eval "$(opam env --switch=5.3.0 --set-switch)" +AEN=$TC/src/aeneas +OUT=${SMOKE_OUT:-$TC/work/smoke}; rm -rf "$OUT"; mkdir -p "$OUT"; cp -r "$HERE/tiny" "$OUT/tiny" +cd "$OUT/tiny" +export CARGO_TARGET_DIR=$OUT/target +echo "== charon"; nice -n 15 "$AEN/charon/bin/charon" cargo --preset=aeneas --dest-file "$OUT/tiny.llbc" 2>&1 | tail -3 +echo "== aeneas"; nice -n 15 "$AEN/bin/aeneas" -backend lean "$OUT/tiny.llbc" -dest "$OUT" 2>&1 | sed 's/\x1b\[[0-9;?]*[a-zA-Z]//g' | tail -2 +test -f "$OUT/Tiny.lean" +echo "== lean (generated file + checks)" +cp "$HERE/Check.lean" "$OUT/Check.lean" +cd "$AEN/backends/lean" # cwd selects the pinned Lean toolchain via lean-toolchain +LP=$(lake env printenv LEAN_PATH | tr ':' '\n' | awk '!s[$0]++' | paste -sd:) +export LEAN_PATH="$LP:$OUT" +nice -n 15 lean --root="$OUT" -o "$OUT/Tiny.olean" "$OUT/Tiny.lean" +nice -n 15 lean "$OUT/Check.lean" +echo "SMOKE OK"