Moftah commited on
Commit
6cc8e1a
·
1 Parent(s): b38dafd

Complete forecasting release gates and official bracket

Browse files
.github/workflows/test.yml CHANGED
@@ -14,4 +14,7 @@ jobs:
14
  python-version: "3.12"
15
  - run: python -m pip install pydantic pytest
16
  - run: PYTHONPATH=src python scripts/audit_dataset.py
 
 
 
17
  - run: PYTHONPATH=src pytest
 
14
  python-version: "3.12"
15
  - run: python -m pip install pydantic pytest
16
  - run: PYTHONPATH=src python scripts/audit_dataset.py
17
+ - run: PYTHONPATH=src python scripts/close_qlora_gate.py
18
+ - run: PYTHONPATH=src python scripts/verify_world_cup_bracket.py
19
+ - run: PYTHONPATH=src python scripts/submission_preflight.py --allow-human-pending
20
  - run: PYTHONPATH=src pytest
Makefile CHANGED
@@ -1,4 +1,4 @@
1
- .PHONY: prepare test data evaluate run matchday forecast
2
 
3
  prepare:
4
  PYTHONPATH=src python3 scripts/prepare_matches.py
@@ -24,3 +24,16 @@ matchday:
24
 
25
  forecast:
26
  PYTHONPATH=src python3 scripts/generate_forecast.py
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .PHONY: prepare test data evaluate run matchday forecast qlora-gate bracket-verify release-preflight sunday
2
 
3
  prepare:
4
  PYTHONPATH=src python3 scripts/prepare_matches.py
 
24
 
25
  forecast:
26
  PYTHONPATH=src python3 scripts/generate_forecast.py
27
+
28
+ qlora-gate:
29
+ PYTHONPATH=src python3 scripts/close_qlora_gate.py
30
+
31
+ bracket-verify:
32
+ PYTHONPATH=src python3 scripts/verify_world_cup_bracket.py
33
+
34
+ release-preflight: qlora-gate bracket-verify
35
+ PYTHONPATH=src python3 scripts/submission_preflight.py
36
+
37
+ sunday: test qlora-gate bracket-verify
38
+ PYTHONPATH=src python3 scripts/audit_dataset.py
39
+ PYTHONPATH=src python3 scripts/submission_preflight.py --allow-human-pending
README.md CHANGED
@@ -32,6 +32,8 @@ The primary experience is now a prospective 2026 tournament forecaster:
32
  - current group tables from a timestamped result snapshot,
33
  - 1X2 probabilities for every group match,
34
  - Monte Carlo advancement and championship probabilities,
 
 
35
  - bounded scenario adjustments extracted by a local 360M model,
36
  - the original hidden historical challenge as a calibration game.
37
 
@@ -79,14 +81,16 @@ UNDERDOG_EXTRACTOR=mock python app.py
79
  PYTHONPATH=src python scripts/prepare_matches.py
80
  PYTHONPATH=src pytest
81
  UNDERDOG_EXTRACTOR=mock PYTHONPATH=src python scripts/evaluate_extractor.py
 
82
  ```
83
 
84
- The checked-in extraction fixtures are synthetic and marked as pending manual
85
- review. Their metrics verify the pipeline but are not presented as a
86
- competition-ready model claim. Do not fine-tune the submitted model on these
87
- fixtures. Replace the training candidates with the Modal-generated corpus,
88
- then manually approve validation and test labels before benchmarking or
89
- training.
 
90
 
91
  ## Fine-Tune on Modal
92
 
@@ -138,13 +142,14 @@ contracts, llama.cpp adapter, Gradio experience, tests, synthetic-data
138
  pipeline, Modal training job, evaluation script, and submission drafts are
139
  implemented.
140
 
141
- Remaining account-dependent release work:
 
 
 
142
 
143
- - manually review and freeze the validation/test labels;
144
- - run and evaluate the Modal fine-tune;
145
- - publish the selected model and dataset/traces on Hugging Face;
146
- - create the Space under the registered hackathon organization;
147
- - record and publish the demo and social post.
148
 
149
  ## Important Claim Boundary
150
 
 
32
  - current group tables from a timestamped result snapshot,
33
  - 1X2 probabilities for every group match,
34
  - Monte Carlo advancement and championship probabilities,
35
+ - FIFA's published Round-of-32 slots, all 495 Annex C third-place mappings,
36
+ and the fixed knockout path through match 104,
37
  - bounded scenario adjustments extracted by a local 360M model,
38
  - the original hidden historical challenge as a calibration game.
39
 
 
81
  PYTHONPATH=src python scripts/prepare_matches.py
82
  PYTHONPATH=src pytest
83
  UNDERDOG_EXTRACTOR=mock PYTHONPATH=src python scripts/evaluate_extractor.py
84
+ make sunday
85
  ```
86
 
87
+ The extraction fixtures are synthetic and remain marked as pending manual
88
+ review. Their metrics are pipeline diagnostics, not an accuracy claim. A QLoRA
89
+ adapter was trained and published, but the reproducible gate in
90
+ `results/qlora_gate_report.json` selected **NO-SHIP** because semantic F1 did
91
+ not improve materially, team attribution regressed, and fallback use rose.
92
+ The production path therefore remains the base 360M model plus validated
93
+ deterministic fallback.
94
 
95
  ## Fine-Tune on Modal
96
 
 
142
  pipeline, Modal training job, evaluation script, and submission drafts are
143
  implemented.
144
 
145
+ The Space, base model, evaluated adapter, dataset, field notes, and source are
146
+ published. `make sunday` closes the QLoRA gate, verifies all 495 official
147
+ bracket combinations, runs tests and the data audit, and emits
148
+ `results/submission_preflight.json`.
149
 
150
+ Remaining account-dependent release work is intentionally narrow: verify a
151
+ cold start and mobile layout, publish the demo video and social post, and
152
+ record the final hackathon submission URL in `release/submission.json`.
 
 
153
 
154
  ## Important Claim Boundary
155
 
data/world_cup_2026/annex_c_third_place.json ADDED
@@ -0,0 +1,4956 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "annex": "FIFA World Cup 2026 Regulations, Annex C",
3
+ "combinations": {
4
+ "ABCDEFGH": {
5
+ "74": "C",
6
+ "77": "F",
7
+ "79": "H",
8
+ "80": "E",
9
+ "81": "B",
10
+ "82": "A",
11
+ "85": "G",
12
+ "87": "D"
13
+ },
14
+ "ABCDEFGI": {
15
+ "74": "D",
16
+ "77": "F",
17
+ "79": "C",
18
+ "80": "I",
19
+ "81": "B",
20
+ "82": "A",
21
+ "85": "G",
22
+ "87": "E"
23
+ },
24
+ "ABCDEFGJ": {
25
+ "74": "D",
26
+ "77": "F",
27
+ "79": "C",
28
+ "80": "J",
29
+ "81": "B",
30
+ "82": "A",
31
+ "85": "G",
32
+ "87": "E"
33
+ },
34
+ "ABCDEFGK": {
35
+ "74": "D",
36
+ "77": "F",
37
+ "79": "C",
38
+ "80": "K",
39
+ "81": "B",
40
+ "82": "A",
41
+ "85": "G",
42
+ "87": "E"
43
+ },
44
+ "ABCDEFGL": {
45
+ "74": "D",
46
+ "77": "F",
47
+ "79": "C",
48
+ "80": "E",
49
+ "81": "B",
50
+ "82": "A",
51
+ "85": "G",
52
+ "87": "L"
53
+ },
54
+ "ABCDEFHI": {
55
+ "74": "C",
56
+ "77": "F",
57
+ "79": "H",
58
+ "80": "I",
59
+ "81": "B",
60
+ "82": "A",
61
+ "85": "E",
62
+ "87": "D"
63
+ },
64
+ "ABCDEFHJ": {
65
+ "74": "C",
66
+ "77": "F",
67
+ "79": "H",
68
+ "80": "E",
69
+ "81": "B",
70
+ "82": "A",
71
+ "85": "J",
72
+ "87": "D"
73
+ },
74
+ "ABCDEFHK": {
75
+ "74": "C",
76
+ "77": "F",
77
+ "79": "H",
78
+ "80": "K",
79
+ "81": "B",
80
+ "82": "A",
81
+ "85": "E",
82
+ "87": "D"
83
+ },
84
+ "ABCDEFHL": {
85
+ "74": "C",
86
+ "77": "D",
87
+ "79": "H",
88
+ "80": "E",
89
+ "81": "B",
90
+ "82": "A",
91
+ "85": "F",
92
+ "87": "L"
93
+ },
94
+ "ABCDEFIJ": {
95
+ "74": "D",
96
+ "77": "F",
97
+ "79": "C",
98
+ "80": "I",
99
+ "81": "B",
100
+ "82": "A",
101
+ "85": "J",
102
+ "87": "E"
103
+ },
104
+ "ABCDEFIK": {
105
+ "74": "D",
106
+ "77": "F",
107
+ "79": "C",
108
+ "80": "K",
109
+ "81": "B",
110
+ "82": "A",
111
+ "85": "E",
112
+ "87": "I"
113
+ },
114
+ "ABCDEFIL": {
115
+ "74": "D",
116
+ "77": "F",
117
+ "79": "C",
118
+ "80": "I",
119
+ "81": "B",
120
+ "82": "A",
121
+ "85": "E",
122
+ "87": "L"
123
+ },
124
+ "ABCDEFJK": {
125
+ "74": "D",
126
+ "77": "F",
127
+ "79": "C",
128
+ "80": "K",
129
+ "81": "B",
130
+ "82": "A",
131
+ "85": "J",
132
+ "87": "E"
133
+ },
134
+ "ABCDEFJL": {
135
+ "74": "D",
136
+ "77": "F",
137
+ "79": "C",
138
+ "80": "E",
139
+ "81": "B",
140
+ "82": "A",
141
+ "85": "J",
142
+ "87": "L"
143
+ },
144
+ "ABCDEFKL": {
145
+ "74": "D",
146
+ "77": "F",
147
+ "79": "C",
148
+ "80": "K",
149
+ "81": "B",
150
+ "82": "A",
151
+ "85": "E",
152
+ "87": "L"
153
+ },
154
+ "ABCDEGHI": {
155
+ "74": "C",
156
+ "77": "D",
157
+ "79": "H",
158
+ "80": "I",
159
+ "81": "B",
160
+ "82": "A",
161
+ "85": "G",
162
+ "87": "E"
163
+ },
164
+ "ABCDEGHJ": {
165
+ "74": "C",
166
+ "77": "D",
167
+ "79": "H",
168
+ "80": "J",
169
+ "81": "B",
170
+ "82": "A",
171
+ "85": "G",
172
+ "87": "E"
173
+ },
174
+ "ABCDEGHK": {
175
+ "74": "C",
176
+ "77": "D",
177
+ "79": "H",
178
+ "80": "K",
179
+ "81": "B",
180
+ "82": "A",
181
+ "85": "G",
182
+ "87": "E"
183
+ },
184
+ "ABCDEGHL": {
185
+ "74": "C",
186
+ "77": "D",
187
+ "79": "H",
188
+ "80": "E",
189
+ "81": "B",
190
+ "82": "A",
191
+ "85": "G",
192
+ "87": "L"
193
+ },
194
+ "ABCDEGIJ": {
195
+ "74": "C",
196
+ "77": "D",
197
+ "79": "E",
198
+ "80": "J",
199
+ "81": "B",
200
+ "82": "A",
201
+ "85": "G",
202
+ "87": "I"
203
+ },
204
+ "ABCDEGIK": {
205
+ "74": "C",
206
+ "77": "D",
207
+ "79": "E",
208
+ "80": "K",
209
+ "81": "B",
210
+ "82": "A",
211
+ "85": "G",
212
+ "87": "I"
213
+ },
214
+ "ABCDEGIL": {
215
+ "74": "C",
216
+ "77": "D",
217
+ "79": "E",
218
+ "80": "I",
219
+ "81": "B",
220
+ "82": "A",
221
+ "85": "G",
222
+ "87": "L"
223
+ },
224
+ "ABCDEGJK": {
225
+ "74": "C",
226
+ "77": "D",
227
+ "79": "E",
228
+ "80": "K",
229
+ "81": "B",
230
+ "82": "A",
231
+ "85": "G",
232
+ "87": "J"
233
+ },
234
+ "ABCDEGJL": {
235
+ "74": "C",
236
+ "77": "D",
237
+ "79": "E",
238
+ "80": "J",
239
+ "81": "B",
240
+ "82": "A",
241
+ "85": "G",
242
+ "87": "L"
243
+ },
244
+ "ABCDEGKL": {
245
+ "74": "C",
246
+ "77": "D",
247
+ "79": "E",
248
+ "80": "K",
249
+ "81": "B",
250
+ "82": "A",
251
+ "85": "G",
252
+ "87": "L"
253
+ },
254
+ "ABCDEHIJ": {
255
+ "74": "C",
256
+ "77": "D",
257
+ "79": "H",
258
+ "80": "I",
259
+ "81": "B",
260
+ "82": "A",
261
+ "85": "J",
262
+ "87": "E"
263
+ },
264
+ "ABCDEHIK": {
265
+ "74": "C",
266
+ "77": "D",
267
+ "79": "H",
268
+ "80": "K",
269
+ "81": "B",
270
+ "82": "A",
271
+ "85": "E",
272
+ "87": "I"
273
+ },
274
+ "ABCDEHIL": {
275
+ "74": "C",
276
+ "77": "D",
277
+ "79": "H",
278
+ "80": "I",
279
+ "81": "B",
280
+ "82": "A",
281
+ "85": "E",
282
+ "87": "L"
283
+ },
284
+ "ABCDEHJK": {
285
+ "74": "C",
286
+ "77": "D",
287
+ "79": "H",
288
+ "80": "K",
289
+ "81": "B",
290
+ "82": "A",
291
+ "85": "J",
292
+ "87": "E"
293
+ },
294
+ "ABCDEHJL": {
295
+ "74": "C",
296
+ "77": "D",
297
+ "79": "H",
298
+ "80": "E",
299
+ "81": "B",
300
+ "82": "A",
301
+ "85": "J",
302
+ "87": "L"
303
+ },
304
+ "ABCDEHKL": {
305
+ "74": "C",
306
+ "77": "D",
307
+ "79": "H",
308
+ "80": "K",
309
+ "81": "B",
310
+ "82": "A",
311
+ "85": "E",
312
+ "87": "L"
313
+ },
314
+ "ABCDEIJK": {
315
+ "74": "C",
316
+ "77": "D",
317
+ "79": "E",
318
+ "80": "K",
319
+ "81": "B",
320
+ "82": "A",
321
+ "85": "J",
322
+ "87": "I"
323
+ },
324
+ "ABCDEIJL": {
325
+ "74": "C",
326
+ "77": "D",
327
+ "79": "E",
328
+ "80": "I",
329
+ "81": "B",
330
+ "82": "A",
331
+ "85": "J",
332
+ "87": "L"
333
+ },
334
+ "ABCDEIKL": {
335
+ "74": "C",
336
+ "77": "D",
337
+ "79": "E",
338
+ "80": "K",
339
+ "81": "B",
340
+ "82": "A",
341
+ "85": "I",
342
+ "87": "L"
343
+ },
344
+ "ABCDEJKL": {
345
+ "74": "C",
346
+ "77": "D",
347
+ "79": "E",
348
+ "80": "K",
349
+ "81": "B",
350
+ "82": "A",
351
+ "85": "J",
352
+ "87": "L"
353
+ },
354
+ "ABCDFGHI": {
355
+ "74": "C",
356
+ "77": "F",
357
+ "79": "H",
358
+ "80": "I",
359
+ "81": "B",
360
+ "82": "A",
361
+ "85": "G",
362
+ "87": "D"
363
+ },
364
+ "ABCDFGHJ": {
365
+ "74": "C",
366
+ "77": "F",
367
+ "79": "H",
368
+ "80": "J",
369
+ "81": "B",
370
+ "82": "A",
371
+ "85": "G",
372
+ "87": "D"
373
+ },
374
+ "ABCDFGHK": {
375
+ "74": "C",
376
+ "77": "F",
377
+ "79": "H",
378
+ "80": "K",
379
+ "81": "B",
380
+ "82": "A",
381
+ "85": "G",
382
+ "87": "D"
383
+ },
384
+ "ABCDFGHL": {
385
+ "74": "D",
386
+ "77": "F",
387
+ "79": "C",
388
+ "80": "H",
389
+ "81": "B",
390
+ "82": "A",
391
+ "85": "G",
392
+ "87": "L"
393
+ },
394
+ "ABCDFGIJ": {
395
+ "74": "D",
396
+ "77": "F",
397
+ "79": "C",
398
+ "80": "J",
399
+ "81": "B",
400
+ "82": "A",
401
+ "85": "G",
402
+ "87": "I"
403
+ },
404
+ "ABCDFGIK": {
405
+ "74": "D",
406
+ "77": "F",
407
+ "79": "C",
408
+ "80": "K",
409
+ "81": "B",
410
+ "82": "A",
411
+ "85": "G",
412
+ "87": "I"
413
+ },
414
+ "ABCDFGIL": {
415
+ "74": "D",
416
+ "77": "F",
417
+ "79": "C",
418
+ "80": "I",
419
+ "81": "B",
420
+ "82": "A",
421
+ "85": "G",
422
+ "87": "L"
423
+ },
424
+ "ABCDFGJK": {
425
+ "74": "D",
426
+ "77": "F",
427
+ "79": "C",
428
+ "80": "K",
429
+ "81": "B",
430
+ "82": "A",
431
+ "85": "G",
432
+ "87": "J"
433
+ },
434
+ "ABCDFGJL": {
435
+ "74": "D",
436
+ "77": "F",
437
+ "79": "C",
438
+ "80": "J",
439
+ "81": "B",
440
+ "82": "A",
441
+ "85": "G",
442
+ "87": "L"
443
+ },
444
+ "ABCDFGKL": {
445
+ "74": "D",
446
+ "77": "F",
447
+ "79": "C",
448
+ "80": "K",
449
+ "81": "B",
450
+ "82": "A",
451
+ "85": "G",
452
+ "87": "L"
453
+ },
454
+ "ABCDFHIJ": {
455
+ "74": "C",
456
+ "77": "F",
457
+ "79": "H",
458
+ "80": "I",
459
+ "81": "B",
460
+ "82": "A",
461
+ "85": "J",
462
+ "87": "D"
463
+ },
464
+ "ABCDFHIK": {
465
+ "74": "C",
466
+ "77": "D",
467
+ "79": "H",
468
+ "80": "K",
469
+ "81": "B",
470
+ "82": "A",
471
+ "85": "F",
472
+ "87": "I"
473
+ },
474
+ "ABCDFHIL": {
475
+ "74": "C",
476
+ "77": "D",
477
+ "79": "H",
478
+ "80": "I",
479
+ "81": "B",
480
+ "82": "A",
481
+ "85": "F",
482
+ "87": "L"
483
+ },
484
+ "ABCDFHJK": {
485
+ "74": "C",
486
+ "77": "F",
487
+ "79": "H",
488
+ "80": "K",
489
+ "81": "B",
490
+ "82": "A",
491
+ "85": "J",
492
+ "87": "D"
493
+ },
494
+ "ABCDFHJL": {
495
+ "74": "D",
496
+ "77": "F",
497
+ "79": "C",
498
+ "80": "H",
499
+ "81": "B",
500
+ "82": "A",
501
+ "85": "J",
502
+ "87": "L"
503
+ },
504
+ "ABCDFHKL": {
505
+ "74": "C",
506
+ "77": "D",
507
+ "79": "H",
508
+ "80": "K",
509
+ "81": "B",
510
+ "82": "A",
511
+ "85": "F",
512
+ "87": "L"
513
+ },
514
+ "ABCDFIJK": {
515
+ "74": "D",
516
+ "77": "F",
517
+ "79": "C",
518
+ "80": "K",
519
+ "81": "B",
520
+ "82": "A",
521
+ "85": "J",
522
+ "87": "I"
523
+ },
524
+ "ABCDFIJL": {
525
+ "74": "D",
526
+ "77": "F",
527
+ "79": "C",
528
+ "80": "I",
529
+ "81": "B",
530
+ "82": "A",
531
+ "85": "J",
532
+ "87": "L"
533
+ },
534
+ "ABCDFIKL": {
535
+ "74": "D",
536
+ "77": "F",
537
+ "79": "C",
538
+ "80": "K",
539
+ "81": "B",
540
+ "82": "A",
541
+ "85": "I",
542
+ "87": "L"
543
+ },
544
+ "ABCDFJKL": {
545
+ "74": "D",
546
+ "77": "F",
547
+ "79": "C",
548
+ "80": "K",
549
+ "81": "B",
550
+ "82": "A",
551
+ "85": "J",
552
+ "87": "L"
553
+ },
554
+ "ABCDGHIJ": {
555
+ "74": "C",
556
+ "77": "D",
557
+ "79": "H",
558
+ "80": "J",
559
+ "81": "B",
560
+ "82": "A",
561
+ "85": "G",
562
+ "87": "I"
563
+ },
564
+ "ABCDGHIK": {
565
+ "74": "C",
566
+ "77": "D",
567
+ "79": "H",
568
+ "80": "K",
569
+ "81": "B",
570
+ "82": "A",
571
+ "85": "G",
572
+ "87": "I"
573
+ },
574
+ "ABCDGHIL": {
575
+ "74": "C",
576
+ "77": "D",
577
+ "79": "H",
578
+ "80": "I",
579
+ "81": "B",
580
+ "82": "A",
581
+ "85": "G",
582
+ "87": "L"
583
+ },
584
+ "ABCDGHJK": {
585
+ "74": "C",
586
+ "77": "D",
587
+ "79": "H",
588
+ "80": "K",
589
+ "81": "B",
590
+ "82": "A",
591
+ "85": "G",
592
+ "87": "J"
593
+ },
594
+ "ABCDGHJL": {
595
+ "74": "C",
596
+ "77": "D",
597
+ "79": "H",
598
+ "80": "J",
599
+ "81": "B",
600
+ "82": "A",
601
+ "85": "G",
602
+ "87": "L"
603
+ },
604
+ "ABCDGHKL": {
605
+ "74": "C",
606
+ "77": "D",
607
+ "79": "H",
608
+ "80": "K",
609
+ "81": "B",
610
+ "82": "A",
611
+ "85": "G",
612
+ "87": "L"
613
+ },
614
+ "ABCDGIJK": {
615
+ "74": "D",
616
+ "77": "G",
617
+ "79": "C",
618
+ "80": "K",
619
+ "81": "B",
620
+ "82": "A",
621
+ "85": "J",
622
+ "87": "I"
623
+ },
624
+ "ABCDGIJL": {
625
+ "74": "D",
626
+ "77": "G",
627
+ "79": "C",
628
+ "80": "I",
629
+ "81": "B",
630
+ "82": "A",
631
+ "85": "J",
632
+ "87": "L"
633
+ },
634
+ "ABCDGIKL": {
635
+ "74": "C",
636
+ "77": "D",
637
+ "79": "I",
638
+ "80": "K",
639
+ "81": "B",
640
+ "82": "A",
641
+ "85": "G",
642
+ "87": "L"
643
+ },
644
+ "ABCDGJKL": {
645
+ "74": "D",
646
+ "77": "G",
647
+ "79": "C",
648
+ "80": "K",
649
+ "81": "B",
650
+ "82": "A",
651
+ "85": "J",
652
+ "87": "L"
653
+ },
654
+ "ABCDHIJK": {
655
+ "74": "C",
656
+ "77": "D",
657
+ "79": "H",
658
+ "80": "K",
659
+ "81": "B",
660
+ "82": "A",
661
+ "85": "J",
662
+ "87": "I"
663
+ },
664
+ "ABCDHIJL": {
665
+ "74": "C",
666
+ "77": "D",
667
+ "79": "H",
668
+ "80": "I",
669
+ "81": "B",
670
+ "82": "A",
671
+ "85": "J",
672
+ "87": "L"
673
+ },
674
+ "ABCDHIKL": {
675
+ "74": "C",
676
+ "77": "D",
677
+ "79": "H",
678
+ "80": "K",
679
+ "81": "B",
680
+ "82": "A",
681
+ "85": "I",
682
+ "87": "L"
683
+ },
684
+ "ABCDHJKL": {
685
+ "74": "C",
686
+ "77": "D",
687
+ "79": "H",
688
+ "80": "K",
689
+ "81": "B",
690
+ "82": "A",
691
+ "85": "J",
692
+ "87": "L"
693
+ },
694
+ "ABCDIJKL": {
695
+ "74": "C",
696
+ "77": "D",
697
+ "79": "I",
698
+ "80": "K",
699
+ "81": "B",
700
+ "82": "A",
701
+ "85": "J",
702
+ "87": "L"
703
+ },
704
+ "ABCEFGHI": {
705
+ "74": "C",
706
+ "77": "F",
707
+ "79": "H",
708
+ "80": "I",
709
+ "81": "B",
710
+ "82": "A",
711
+ "85": "G",
712
+ "87": "E"
713
+ },
714
+ "ABCEFGHJ": {
715
+ "74": "C",
716
+ "77": "F",
717
+ "79": "H",
718
+ "80": "J",
719
+ "81": "B",
720
+ "82": "A",
721
+ "85": "G",
722
+ "87": "E"
723
+ },
724
+ "ABCEFGHK": {
725
+ "74": "C",
726
+ "77": "F",
727
+ "79": "H",
728
+ "80": "K",
729
+ "81": "B",
730
+ "82": "A",
731
+ "85": "G",
732
+ "87": "E"
733
+ },
734
+ "ABCEFGHL": {
735
+ "74": "C",
736
+ "77": "F",
737
+ "79": "H",
738
+ "80": "E",
739
+ "81": "B",
740
+ "82": "A",
741
+ "85": "G",
742
+ "87": "L"
743
+ },
744
+ "ABCEFGIJ": {
745
+ "74": "C",
746
+ "77": "F",
747
+ "79": "E",
748
+ "80": "J",
749
+ "81": "B",
750
+ "82": "A",
751
+ "85": "G",
752
+ "87": "I"
753
+ },
754
+ "ABCEFGIK": {
755
+ "74": "C",
756
+ "77": "F",
757
+ "79": "E",
758
+ "80": "K",
759
+ "81": "B",
760
+ "82": "A",
761
+ "85": "G",
762
+ "87": "I"
763
+ },
764
+ "ABCEFGIL": {
765
+ "74": "C",
766
+ "77": "F",
767
+ "79": "E",
768
+ "80": "I",
769
+ "81": "B",
770
+ "82": "A",
771
+ "85": "G",
772
+ "87": "L"
773
+ },
774
+ "ABCEFGJK": {
775
+ "74": "C",
776
+ "77": "F",
777
+ "79": "E",
778
+ "80": "K",
779
+ "81": "B",
780
+ "82": "A",
781
+ "85": "G",
782
+ "87": "J"
783
+ },
784
+ "ABCEFGJL": {
785
+ "74": "C",
786
+ "77": "F",
787
+ "79": "E",
788
+ "80": "J",
789
+ "81": "B",
790
+ "82": "A",
791
+ "85": "G",
792
+ "87": "L"
793
+ },
794
+ "ABCEFGKL": {
795
+ "74": "C",
796
+ "77": "F",
797
+ "79": "E",
798
+ "80": "K",
799
+ "81": "B",
800
+ "82": "A",
801
+ "85": "G",
802
+ "87": "L"
803
+ },
804
+ "ABCEFHIJ": {
805
+ "74": "C",
806
+ "77": "F",
807
+ "79": "H",
808
+ "80": "I",
809
+ "81": "B",
810
+ "82": "A",
811
+ "85": "J",
812
+ "87": "E"
813
+ },
814
+ "ABCEFHIK": {
815
+ "74": "C",
816
+ "77": "F",
817
+ "79": "H",
818
+ "80": "K",
819
+ "81": "B",
820
+ "82": "A",
821
+ "85": "E",
822
+ "87": "I"
823
+ },
824
+ "ABCEFHIL": {
825
+ "74": "C",
826
+ "77": "F",
827
+ "79": "H",
828
+ "80": "I",
829
+ "81": "B",
830
+ "82": "A",
831
+ "85": "E",
832
+ "87": "L"
833
+ },
834
+ "ABCEFHJK": {
835
+ "74": "C",
836
+ "77": "F",
837
+ "79": "H",
838
+ "80": "K",
839
+ "81": "B",
840
+ "82": "A",
841
+ "85": "J",
842
+ "87": "E"
843
+ },
844
+ "ABCEFHJL": {
845
+ "74": "C",
846
+ "77": "F",
847
+ "79": "H",
848
+ "80": "E",
849
+ "81": "B",
850
+ "82": "A",
851
+ "85": "J",
852
+ "87": "L"
853
+ },
854
+ "ABCEFHKL": {
855
+ "74": "C",
856
+ "77": "F",
857
+ "79": "H",
858
+ "80": "K",
859
+ "81": "B",
860
+ "82": "A",
861
+ "85": "E",
862
+ "87": "L"
863
+ },
864
+ "ABCEFIJK": {
865
+ "74": "C",
866
+ "77": "F",
867
+ "79": "E",
868
+ "80": "K",
869
+ "81": "B",
870
+ "82": "A",
871
+ "85": "J",
872
+ "87": "I"
873
+ },
874
+ "ABCEFIJL": {
875
+ "74": "C",
876
+ "77": "F",
877
+ "79": "E",
878
+ "80": "I",
879
+ "81": "B",
880
+ "82": "A",
881
+ "85": "J",
882
+ "87": "L"
883
+ },
884
+ "ABCEFIKL": {
885
+ "74": "C",
886
+ "77": "F",
887
+ "79": "E",
888
+ "80": "K",
889
+ "81": "B",
890
+ "82": "A",
891
+ "85": "I",
892
+ "87": "L"
893
+ },
894
+ "ABCEFJKL": {
895
+ "74": "C",
896
+ "77": "F",
897
+ "79": "E",
898
+ "80": "K",
899
+ "81": "B",
900
+ "82": "A",
901
+ "85": "J",
902
+ "87": "L"
903
+ },
904
+ "ABCEGHIJ": {
905
+ "74": "C",
906
+ "77": "G",
907
+ "79": "H",
908
+ "80": "I",
909
+ "81": "B",
910
+ "82": "A",
911
+ "85": "J",
912
+ "87": "E"
913
+ },
914
+ "ABCEGHIK": {
915
+ "74": "C",
916
+ "77": "H",
917
+ "79": "E",
918
+ "80": "K",
919
+ "81": "B",
920
+ "82": "A",
921
+ "85": "G",
922
+ "87": "I"
923
+ },
924
+ "ABCEGHIL": {
925
+ "74": "C",
926
+ "77": "H",
927
+ "79": "E",
928
+ "80": "I",
929
+ "81": "B",
930
+ "82": "A",
931
+ "85": "G",
932
+ "87": "L"
933
+ },
934
+ "ABCEGHJK": {
935
+ "74": "C",
936
+ "77": "G",
937
+ "79": "H",
938
+ "80": "K",
939
+ "81": "B",
940
+ "82": "A",
941
+ "85": "J",
942
+ "87": "E"
943
+ },
944
+ "ABCEGHJL": {
945
+ "74": "C",
946
+ "77": "G",
947
+ "79": "H",
948
+ "80": "E",
949
+ "81": "B",
950
+ "82": "A",
951
+ "85": "J",
952
+ "87": "L"
953
+ },
954
+ "ABCEGHKL": {
955
+ "74": "C",
956
+ "77": "H",
957
+ "79": "E",
958
+ "80": "K",
959
+ "81": "B",
960
+ "82": "A",
961
+ "85": "G",
962
+ "87": "L"
963
+ },
964
+ "ABCEGIJK": {
965
+ "74": "C",
966
+ "77": "G",
967
+ "79": "E",
968
+ "80": "K",
969
+ "81": "B",
970
+ "82": "A",
971
+ "85": "J",
972
+ "87": "I"
973
+ },
974
+ "ABCEGIJL": {
975
+ "74": "C",
976
+ "77": "G",
977
+ "79": "E",
978
+ "80": "I",
979
+ "81": "B",
980
+ "82": "A",
981
+ "85": "J",
982
+ "87": "L"
983
+ },
984
+ "ABCEGIKL": {
985
+ "74": "A",
986
+ "77": "C",
987
+ "79": "E",
988
+ "80": "K",
989
+ "81": "B",
990
+ "82": "I",
991
+ "85": "G",
992
+ "87": "L"
993
+ },
994
+ "ABCEGJKL": {
995
+ "74": "C",
996
+ "77": "G",
997
+ "79": "E",
998
+ "80": "K",
999
+ "81": "B",
1000
+ "82": "A",
1001
+ "85": "J",
1002
+ "87": "L"
1003
+ },
1004
+ "ABCEHIJK": {
1005
+ "74": "C",
1006
+ "77": "H",
1007
+ "79": "E",
1008
+ "80": "K",
1009
+ "81": "B",
1010
+ "82": "A",
1011
+ "85": "J",
1012
+ "87": "I"
1013
+ },
1014
+ "ABCEHIJL": {
1015
+ "74": "C",
1016
+ "77": "H",
1017
+ "79": "E",
1018
+ "80": "I",
1019
+ "81": "B",
1020
+ "82": "A",
1021
+ "85": "J",
1022
+ "87": "L"
1023
+ },
1024
+ "ABCEHIKL": {
1025
+ "74": "C",
1026
+ "77": "H",
1027
+ "79": "E",
1028
+ "80": "K",
1029
+ "81": "B",
1030
+ "82": "A",
1031
+ "85": "I",
1032
+ "87": "L"
1033
+ },
1034
+ "ABCEHJKL": {
1035
+ "74": "C",
1036
+ "77": "H",
1037
+ "79": "E",
1038
+ "80": "K",
1039
+ "81": "B",
1040
+ "82": "A",
1041
+ "85": "J",
1042
+ "87": "L"
1043
+ },
1044
+ "ABCEIJKL": {
1045
+ "74": "A",
1046
+ "77": "C",
1047
+ "79": "E",
1048
+ "80": "K",
1049
+ "81": "B",
1050
+ "82": "I",
1051
+ "85": "J",
1052
+ "87": "L"
1053
+ },
1054
+ "ABCFGHIJ": {
1055
+ "74": "C",
1056
+ "77": "F",
1057
+ "79": "H",
1058
+ "80": "J",
1059
+ "81": "B",
1060
+ "82": "A",
1061
+ "85": "G",
1062
+ "87": "I"
1063
+ },
1064
+ "ABCFGHIK": {
1065
+ "74": "C",
1066
+ "77": "F",
1067
+ "79": "H",
1068
+ "80": "K",
1069
+ "81": "B",
1070
+ "82": "A",
1071
+ "85": "G",
1072
+ "87": "I"
1073
+ },
1074
+ "ABCFGHIL": {
1075
+ "74": "C",
1076
+ "77": "F",
1077
+ "79": "H",
1078
+ "80": "I",
1079
+ "81": "B",
1080
+ "82": "A",
1081
+ "85": "G",
1082
+ "87": "L"
1083
+ },
1084
+ "ABCFGHJK": {
1085
+ "74": "C",
1086
+ "77": "F",
1087
+ "79": "H",
1088
+ "80": "K",
1089
+ "81": "B",
1090
+ "82": "A",
1091
+ "85": "G",
1092
+ "87": "J"
1093
+ },
1094
+ "ABCFGHJL": {
1095
+ "74": "C",
1096
+ "77": "F",
1097
+ "79": "H",
1098
+ "80": "J",
1099
+ "81": "B",
1100
+ "82": "A",
1101
+ "85": "G",
1102
+ "87": "L"
1103
+ },
1104
+ "ABCFGHKL": {
1105
+ "74": "C",
1106
+ "77": "F",
1107
+ "79": "H",
1108
+ "80": "K",
1109
+ "81": "B",
1110
+ "82": "A",
1111
+ "85": "G",
1112
+ "87": "L"
1113
+ },
1114
+ "ABCFGIJK": {
1115
+ "74": "F",
1116
+ "77": "G",
1117
+ "79": "C",
1118
+ "80": "K",
1119
+ "81": "B",
1120
+ "82": "A",
1121
+ "85": "J",
1122
+ "87": "I"
1123
+ },
1124
+ "ABCFGIJL": {
1125
+ "74": "F",
1126
+ "77": "G",
1127
+ "79": "C",
1128
+ "80": "I",
1129
+ "81": "B",
1130
+ "82": "A",
1131
+ "85": "J",
1132
+ "87": "L"
1133
+ },
1134
+ "ABCFGIKL": {
1135
+ "74": "C",
1136
+ "77": "F",
1137
+ "79": "I",
1138
+ "80": "K",
1139
+ "81": "B",
1140
+ "82": "A",
1141
+ "85": "G",
1142
+ "87": "L"
1143
+ },
1144
+ "ABCFGJKL": {
1145
+ "74": "F",
1146
+ "77": "G",
1147
+ "79": "C",
1148
+ "80": "K",
1149
+ "81": "B",
1150
+ "82": "A",
1151
+ "85": "J",
1152
+ "87": "L"
1153
+ },
1154
+ "ABCFHIJK": {
1155
+ "74": "C",
1156
+ "77": "F",
1157
+ "79": "H",
1158
+ "80": "K",
1159
+ "81": "B",
1160
+ "82": "A",
1161
+ "85": "J",
1162
+ "87": "I"
1163
+ },
1164
+ "ABCFHIJL": {
1165
+ "74": "C",
1166
+ "77": "F",
1167
+ "79": "H",
1168
+ "80": "I",
1169
+ "81": "B",
1170
+ "82": "A",
1171
+ "85": "J",
1172
+ "87": "L"
1173
+ },
1174
+ "ABCFHIKL": {
1175
+ "74": "C",
1176
+ "77": "F",
1177
+ "79": "H",
1178
+ "80": "K",
1179
+ "81": "B",
1180
+ "82": "A",
1181
+ "85": "I",
1182
+ "87": "L"
1183
+ },
1184
+ "ABCFHJKL": {
1185
+ "74": "C",
1186
+ "77": "F",
1187
+ "79": "H",
1188
+ "80": "K",
1189
+ "81": "B",
1190
+ "82": "A",
1191
+ "85": "J",
1192
+ "87": "L"
1193
+ },
1194
+ "ABCFIJKL": {
1195
+ "74": "C",
1196
+ "77": "F",
1197
+ "79": "I",
1198
+ "80": "K",
1199
+ "81": "B",
1200
+ "82": "A",
1201
+ "85": "J",
1202
+ "87": "L"
1203
+ },
1204
+ "ABCGHIJK": {
1205
+ "74": "C",
1206
+ "77": "G",
1207
+ "79": "H",
1208
+ "80": "K",
1209
+ "81": "B",
1210
+ "82": "A",
1211
+ "85": "J",
1212
+ "87": "I"
1213
+ },
1214
+ "ABCGHIJL": {
1215
+ "74": "C",
1216
+ "77": "G",
1217
+ "79": "H",
1218
+ "80": "I",
1219
+ "81": "B",
1220
+ "82": "A",
1221
+ "85": "J",
1222
+ "87": "L"
1223
+ },
1224
+ "ABCGHIKL": {
1225
+ "74": "C",
1226
+ "77": "H",
1227
+ "79": "I",
1228
+ "80": "K",
1229
+ "81": "B",
1230
+ "82": "A",
1231
+ "85": "G",
1232
+ "87": "L"
1233
+ },
1234
+ "ABCGHJKL": {
1235
+ "74": "C",
1236
+ "77": "G",
1237
+ "79": "H",
1238
+ "80": "K",
1239
+ "81": "B",
1240
+ "82": "A",
1241
+ "85": "J",
1242
+ "87": "L"
1243
+ },
1244
+ "ABCGIJKL": {
1245
+ "74": "C",
1246
+ "77": "G",
1247
+ "79": "I",
1248
+ "80": "K",
1249
+ "81": "B",
1250
+ "82": "A",
1251
+ "85": "J",
1252
+ "87": "L"
1253
+ },
1254
+ "ABCHIJKL": {
1255
+ "74": "C",
1256
+ "77": "H",
1257
+ "79": "I",
1258
+ "80": "K",
1259
+ "81": "B",
1260
+ "82": "A",
1261
+ "85": "J",
1262
+ "87": "L"
1263
+ },
1264
+ "ABDEFGHI": {
1265
+ "74": "D",
1266
+ "77": "F",
1267
+ "79": "H",
1268
+ "80": "I",
1269
+ "81": "B",
1270
+ "82": "A",
1271
+ "85": "G",
1272
+ "87": "E"
1273
+ },
1274
+ "ABDEFGHJ": {
1275
+ "74": "D",
1276
+ "77": "F",
1277
+ "79": "H",
1278
+ "80": "J",
1279
+ "81": "B",
1280
+ "82": "A",
1281
+ "85": "G",
1282
+ "87": "E"
1283
+ },
1284
+ "ABDEFGHK": {
1285
+ "74": "D",
1286
+ "77": "F",
1287
+ "79": "H",
1288
+ "80": "K",
1289
+ "81": "B",
1290
+ "82": "A",
1291
+ "85": "G",
1292
+ "87": "E"
1293
+ },
1294
+ "ABDEFGHL": {
1295
+ "74": "D",
1296
+ "77": "F",
1297
+ "79": "H",
1298
+ "80": "E",
1299
+ "81": "B",
1300
+ "82": "A",
1301
+ "85": "G",
1302
+ "87": "L"
1303
+ },
1304
+ "ABDEFGIJ": {
1305
+ "74": "D",
1306
+ "77": "F",
1307
+ "79": "E",
1308
+ "80": "J",
1309
+ "81": "B",
1310
+ "82": "A",
1311
+ "85": "G",
1312
+ "87": "I"
1313
+ },
1314
+ "ABDEFGIK": {
1315
+ "74": "D",
1316
+ "77": "F",
1317
+ "79": "E",
1318
+ "80": "K",
1319
+ "81": "B",
1320
+ "82": "A",
1321
+ "85": "G",
1322
+ "87": "I"
1323
+ },
1324
+ "ABDEFGIL": {
1325
+ "74": "D",
1326
+ "77": "F",
1327
+ "79": "E",
1328
+ "80": "I",
1329
+ "81": "B",
1330
+ "82": "A",
1331
+ "85": "G",
1332
+ "87": "L"
1333
+ },
1334
+ "ABDEFGJK": {
1335
+ "74": "D",
1336
+ "77": "F",
1337
+ "79": "E",
1338
+ "80": "K",
1339
+ "81": "B",
1340
+ "82": "A",
1341
+ "85": "G",
1342
+ "87": "J"
1343
+ },
1344
+ "ABDEFGJL": {
1345
+ "74": "D",
1346
+ "77": "F",
1347
+ "79": "E",
1348
+ "80": "J",
1349
+ "81": "B",
1350
+ "82": "A",
1351
+ "85": "G",
1352
+ "87": "L"
1353
+ },
1354
+ "ABDEFGKL": {
1355
+ "74": "D",
1356
+ "77": "F",
1357
+ "79": "E",
1358
+ "80": "K",
1359
+ "81": "B",
1360
+ "82": "A",
1361
+ "85": "G",
1362
+ "87": "L"
1363
+ },
1364
+ "ABDEFHIJ": {
1365
+ "74": "D",
1366
+ "77": "F",
1367
+ "79": "H",
1368
+ "80": "I",
1369
+ "81": "B",
1370
+ "82": "A",
1371
+ "85": "J",
1372
+ "87": "E"
1373
+ },
1374
+ "ABDEFHIK": {
1375
+ "74": "D",
1376
+ "77": "F",
1377
+ "79": "H",
1378
+ "80": "K",
1379
+ "81": "B",
1380
+ "82": "A",
1381
+ "85": "E",
1382
+ "87": "I"
1383
+ },
1384
+ "ABDEFHIL": {
1385
+ "74": "D",
1386
+ "77": "F",
1387
+ "79": "H",
1388
+ "80": "I",
1389
+ "81": "B",
1390
+ "82": "A",
1391
+ "85": "E",
1392
+ "87": "L"
1393
+ },
1394
+ "ABDEFHJK": {
1395
+ "74": "D",
1396
+ "77": "F",
1397
+ "79": "H",
1398
+ "80": "K",
1399
+ "81": "B",
1400
+ "82": "A",
1401
+ "85": "J",
1402
+ "87": "E"
1403
+ },
1404
+ "ABDEFHJL": {
1405
+ "74": "D",
1406
+ "77": "F",
1407
+ "79": "H",
1408
+ "80": "E",
1409
+ "81": "B",
1410
+ "82": "A",
1411
+ "85": "J",
1412
+ "87": "L"
1413
+ },
1414
+ "ABDEFHKL": {
1415
+ "74": "D",
1416
+ "77": "F",
1417
+ "79": "H",
1418
+ "80": "K",
1419
+ "81": "B",
1420
+ "82": "A",
1421
+ "85": "E",
1422
+ "87": "L"
1423
+ },
1424
+ "ABDEFIJK": {
1425
+ "74": "D",
1426
+ "77": "F",
1427
+ "79": "E",
1428
+ "80": "K",
1429
+ "81": "B",
1430
+ "82": "A",
1431
+ "85": "J",
1432
+ "87": "I"
1433
+ },
1434
+ "ABDEFIJL": {
1435
+ "74": "D",
1436
+ "77": "F",
1437
+ "79": "E",
1438
+ "80": "I",
1439
+ "81": "B",
1440
+ "82": "A",
1441
+ "85": "J",
1442
+ "87": "L"
1443
+ },
1444
+ "ABDEFIKL": {
1445
+ "74": "D",
1446
+ "77": "F",
1447
+ "79": "E",
1448
+ "80": "K",
1449
+ "81": "B",
1450
+ "82": "A",
1451
+ "85": "I",
1452
+ "87": "L"
1453
+ },
1454
+ "ABDEFJKL": {
1455
+ "74": "D",
1456
+ "77": "F",
1457
+ "79": "E",
1458
+ "80": "K",
1459
+ "81": "B",
1460
+ "82": "A",
1461
+ "85": "J",
1462
+ "87": "L"
1463
+ },
1464
+ "ABDEGHIJ": {
1465
+ "74": "D",
1466
+ "77": "G",
1467
+ "79": "H",
1468
+ "80": "I",
1469
+ "81": "B",
1470
+ "82": "A",
1471
+ "85": "J",
1472
+ "87": "E"
1473
+ },
1474
+ "ABDEGHIK": {
1475
+ "74": "D",
1476
+ "77": "H",
1477
+ "79": "E",
1478
+ "80": "K",
1479
+ "81": "B",
1480
+ "82": "A",
1481
+ "85": "G",
1482
+ "87": "I"
1483
+ },
1484
+ "ABDEGHIL": {
1485
+ "74": "D",
1486
+ "77": "H",
1487
+ "79": "E",
1488
+ "80": "I",
1489
+ "81": "B",
1490
+ "82": "A",
1491
+ "85": "G",
1492
+ "87": "L"
1493
+ },
1494
+ "ABDEGHJK": {
1495
+ "74": "D",
1496
+ "77": "G",
1497
+ "79": "H",
1498
+ "80": "K",
1499
+ "81": "B",
1500
+ "82": "A",
1501
+ "85": "J",
1502
+ "87": "E"
1503
+ },
1504
+ "ABDEGHJL": {
1505
+ "74": "D",
1506
+ "77": "G",
1507
+ "79": "H",
1508
+ "80": "E",
1509
+ "81": "B",
1510
+ "82": "A",
1511
+ "85": "J",
1512
+ "87": "L"
1513
+ },
1514
+ "ABDEGHKL": {
1515
+ "74": "D",
1516
+ "77": "H",
1517
+ "79": "E",
1518
+ "80": "K",
1519
+ "81": "B",
1520
+ "82": "A",
1521
+ "85": "G",
1522
+ "87": "L"
1523
+ },
1524
+ "ABDEGIJK": {
1525
+ "74": "D",
1526
+ "77": "G",
1527
+ "79": "E",
1528
+ "80": "K",
1529
+ "81": "B",
1530
+ "82": "A",
1531
+ "85": "J",
1532
+ "87": "I"
1533
+ },
1534
+ "ABDEGIJL": {
1535
+ "74": "D",
1536
+ "77": "G",
1537
+ "79": "E",
1538
+ "80": "I",
1539
+ "81": "B",
1540
+ "82": "A",
1541
+ "85": "J",
1542
+ "87": "L"
1543
+ },
1544
+ "ABDEGIKL": {
1545
+ "74": "A",
1546
+ "77": "D",
1547
+ "79": "E",
1548
+ "80": "K",
1549
+ "81": "B",
1550
+ "82": "I",
1551
+ "85": "G",
1552
+ "87": "L"
1553
+ },
1554
+ "ABDEGJKL": {
1555
+ "74": "D",
1556
+ "77": "G",
1557
+ "79": "E",
1558
+ "80": "K",
1559
+ "81": "B",
1560
+ "82": "A",
1561
+ "85": "J",
1562
+ "87": "L"
1563
+ },
1564
+ "ABDEHIJK": {
1565
+ "74": "D",
1566
+ "77": "H",
1567
+ "79": "E",
1568
+ "80": "K",
1569
+ "81": "B",
1570
+ "82": "A",
1571
+ "85": "J",
1572
+ "87": "I"
1573
+ },
1574
+ "ABDEHIJL": {
1575
+ "74": "D",
1576
+ "77": "H",
1577
+ "79": "E",
1578
+ "80": "I",
1579
+ "81": "B",
1580
+ "82": "A",
1581
+ "85": "J",
1582
+ "87": "L"
1583
+ },
1584
+ "ABDEHIKL": {
1585
+ "74": "D",
1586
+ "77": "H",
1587
+ "79": "E",
1588
+ "80": "K",
1589
+ "81": "B",
1590
+ "82": "A",
1591
+ "85": "I",
1592
+ "87": "L"
1593
+ },
1594
+ "ABDEHJKL": {
1595
+ "74": "D",
1596
+ "77": "H",
1597
+ "79": "E",
1598
+ "80": "K",
1599
+ "81": "B",
1600
+ "82": "A",
1601
+ "85": "J",
1602
+ "87": "L"
1603
+ },
1604
+ "ABDEIJKL": {
1605
+ "74": "A",
1606
+ "77": "D",
1607
+ "79": "E",
1608
+ "80": "K",
1609
+ "81": "B",
1610
+ "82": "I",
1611
+ "85": "J",
1612
+ "87": "L"
1613
+ },
1614
+ "ABDFGHIJ": {
1615
+ "74": "D",
1616
+ "77": "F",
1617
+ "79": "H",
1618
+ "80": "J",
1619
+ "81": "B",
1620
+ "82": "A",
1621
+ "85": "G",
1622
+ "87": "I"
1623
+ },
1624
+ "ABDFGHIK": {
1625
+ "74": "D",
1626
+ "77": "F",
1627
+ "79": "H",
1628
+ "80": "K",
1629
+ "81": "B",
1630
+ "82": "A",
1631
+ "85": "G",
1632
+ "87": "I"
1633
+ },
1634
+ "ABDFGHIL": {
1635
+ "74": "D",
1636
+ "77": "F",
1637
+ "79": "H",
1638
+ "80": "I",
1639
+ "81": "B",
1640
+ "82": "A",
1641
+ "85": "G",
1642
+ "87": "L"
1643
+ },
1644
+ "ABDFGHJK": {
1645
+ "74": "D",
1646
+ "77": "F",
1647
+ "79": "H",
1648
+ "80": "K",
1649
+ "81": "B",
1650
+ "82": "A",
1651
+ "85": "G",
1652
+ "87": "J"
1653
+ },
1654
+ "ABDFGHJL": {
1655
+ "74": "D",
1656
+ "77": "F",
1657
+ "79": "H",
1658
+ "80": "J",
1659
+ "81": "B",
1660
+ "82": "A",
1661
+ "85": "G",
1662
+ "87": "L"
1663
+ },
1664
+ "ABDFGHKL": {
1665
+ "74": "D",
1666
+ "77": "F",
1667
+ "79": "H",
1668
+ "80": "K",
1669
+ "81": "B",
1670
+ "82": "A",
1671
+ "85": "G",
1672
+ "87": "L"
1673
+ },
1674
+ "ABDFGIJK": {
1675
+ "74": "D",
1676
+ "77": "G",
1677
+ "79": "F",
1678
+ "80": "K",
1679
+ "81": "B",
1680
+ "82": "A",
1681
+ "85": "J",
1682
+ "87": "I"
1683
+ },
1684
+ "ABDFGIJL": {
1685
+ "74": "D",
1686
+ "77": "G",
1687
+ "79": "F",
1688
+ "80": "I",
1689
+ "81": "B",
1690
+ "82": "A",
1691
+ "85": "J",
1692
+ "87": "L"
1693
+ },
1694
+ "ABDFGIKL": {
1695
+ "74": "D",
1696
+ "77": "F",
1697
+ "79": "I",
1698
+ "80": "K",
1699
+ "81": "B",
1700
+ "82": "A",
1701
+ "85": "G",
1702
+ "87": "L"
1703
+ },
1704
+ "ABDFGJKL": {
1705
+ "74": "D",
1706
+ "77": "G",
1707
+ "79": "F",
1708
+ "80": "K",
1709
+ "81": "B",
1710
+ "82": "A",
1711
+ "85": "J",
1712
+ "87": "L"
1713
+ },
1714
+ "ABDFHIJK": {
1715
+ "74": "D",
1716
+ "77": "F",
1717
+ "79": "H",
1718
+ "80": "K",
1719
+ "81": "B",
1720
+ "82": "A",
1721
+ "85": "J",
1722
+ "87": "I"
1723
+ },
1724
+ "ABDFHIJL": {
1725
+ "74": "D",
1726
+ "77": "F",
1727
+ "79": "H",
1728
+ "80": "I",
1729
+ "81": "B",
1730
+ "82": "A",
1731
+ "85": "J",
1732
+ "87": "L"
1733
+ },
1734
+ "ABDFHIKL": {
1735
+ "74": "D",
1736
+ "77": "F",
1737
+ "79": "H",
1738
+ "80": "K",
1739
+ "81": "B",
1740
+ "82": "A",
1741
+ "85": "I",
1742
+ "87": "L"
1743
+ },
1744
+ "ABDFHJKL": {
1745
+ "74": "D",
1746
+ "77": "F",
1747
+ "79": "H",
1748
+ "80": "K",
1749
+ "81": "B",
1750
+ "82": "A",
1751
+ "85": "J",
1752
+ "87": "L"
1753
+ },
1754
+ "ABDFIJKL": {
1755
+ "74": "D",
1756
+ "77": "F",
1757
+ "79": "I",
1758
+ "80": "K",
1759
+ "81": "B",
1760
+ "82": "A",
1761
+ "85": "J",
1762
+ "87": "L"
1763
+ },
1764
+ "ABDGHIJK": {
1765
+ "74": "D",
1766
+ "77": "G",
1767
+ "79": "H",
1768
+ "80": "K",
1769
+ "81": "B",
1770
+ "82": "A",
1771
+ "85": "J",
1772
+ "87": "I"
1773
+ },
1774
+ "ABDGHIJL": {
1775
+ "74": "D",
1776
+ "77": "G",
1777
+ "79": "H",
1778
+ "80": "I",
1779
+ "81": "B",
1780
+ "82": "A",
1781
+ "85": "J",
1782
+ "87": "L"
1783
+ },
1784
+ "ABDGHIKL": {
1785
+ "74": "D",
1786
+ "77": "H",
1787
+ "79": "I",
1788
+ "80": "K",
1789
+ "81": "B",
1790
+ "82": "A",
1791
+ "85": "G",
1792
+ "87": "L"
1793
+ },
1794
+ "ABDGHJKL": {
1795
+ "74": "D",
1796
+ "77": "G",
1797
+ "79": "H",
1798
+ "80": "K",
1799
+ "81": "B",
1800
+ "82": "A",
1801
+ "85": "J",
1802
+ "87": "L"
1803
+ },
1804
+ "ABDGIJKL": {
1805
+ "74": "D",
1806
+ "77": "G",
1807
+ "79": "I",
1808
+ "80": "K",
1809
+ "81": "B",
1810
+ "82": "A",
1811
+ "85": "J",
1812
+ "87": "L"
1813
+ },
1814
+ "ABDHIJKL": {
1815
+ "74": "D",
1816
+ "77": "H",
1817
+ "79": "I",
1818
+ "80": "K",
1819
+ "81": "B",
1820
+ "82": "A",
1821
+ "85": "J",
1822
+ "87": "L"
1823
+ },
1824
+ "ABEFGHIJ": {
1825
+ "74": "F",
1826
+ "77": "G",
1827
+ "79": "H",
1828
+ "80": "I",
1829
+ "81": "B",
1830
+ "82": "A",
1831
+ "85": "J",
1832
+ "87": "E"
1833
+ },
1834
+ "ABEFGHIK": {
1835
+ "74": "F",
1836
+ "77": "H",
1837
+ "79": "E",
1838
+ "80": "K",
1839
+ "81": "B",
1840
+ "82": "A",
1841
+ "85": "G",
1842
+ "87": "I"
1843
+ },
1844
+ "ABEFGHIL": {
1845
+ "74": "F",
1846
+ "77": "H",
1847
+ "79": "E",
1848
+ "80": "I",
1849
+ "81": "B",
1850
+ "82": "A",
1851
+ "85": "G",
1852
+ "87": "L"
1853
+ },
1854
+ "ABEFGHJK": {
1855
+ "74": "F",
1856
+ "77": "G",
1857
+ "79": "H",
1858
+ "80": "K",
1859
+ "81": "B",
1860
+ "82": "A",
1861
+ "85": "J",
1862
+ "87": "E"
1863
+ },
1864
+ "ABEFGHJL": {
1865
+ "74": "F",
1866
+ "77": "G",
1867
+ "79": "H",
1868
+ "80": "E",
1869
+ "81": "B",
1870
+ "82": "A",
1871
+ "85": "J",
1872
+ "87": "L"
1873
+ },
1874
+ "ABEFGHKL": {
1875
+ "74": "F",
1876
+ "77": "H",
1877
+ "79": "E",
1878
+ "80": "K",
1879
+ "81": "B",
1880
+ "82": "A",
1881
+ "85": "G",
1882
+ "87": "L"
1883
+ },
1884
+ "ABEFGIJK": {
1885
+ "74": "F",
1886
+ "77": "G",
1887
+ "79": "E",
1888
+ "80": "K",
1889
+ "81": "B",
1890
+ "82": "A",
1891
+ "85": "J",
1892
+ "87": "I"
1893
+ },
1894
+ "ABEFGIJL": {
1895
+ "74": "F",
1896
+ "77": "G",
1897
+ "79": "E",
1898
+ "80": "I",
1899
+ "81": "B",
1900
+ "82": "A",
1901
+ "85": "J",
1902
+ "87": "L"
1903
+ },
1904
+ "ABEFGIKL": {
1905
+ "74": "A",
1906
+ "77": "F",
1907
+ "79": "E",
1908
+ "80": "K",
1909
+ "81": "B",
1910
+ "82": "I",
1911
+ "85": "G",
1912
+ "87": "L"
1913
+ },
1914
+ "ABEFGJKL": {
1915
+ "74": "F",
1916
+ "77": "G",
1917
+ "79": "E",
1918
+ "80": "K",
1919
+ "81": "B",
1920
+ "82": "A",
1921
+ "85": "J",
1922
+ "87": "L"
1923
+ },
1924
+ "ABEFHIJK": {
1925
+ "74": "F",
1926
+ "77": "H",
1927
+ "79": "E",
1928
+ "80": "K",
1929
+ "81": "B",
1930
+ "82": "A",
1931
+ "85": "J",
1932
+ "87": "I"
1933
+ },
1934
+ "ABEFHIJL": {
1935
+ "74": "F",
1936
+ "77": "H",
1937
+ "79": "E",
1938
+ "80": "I",
1939
+ "81": "B",
1940
+ "82": "A",
1941
+ "85": "J",
1942
+ "87": "L"
1943
+ },
1944
+ "ABEFHIKL": {
1945
+ "74": "F",
1946
+ "77": "H",
1947
+ "79": "E",
1948
+ "80": "K",
1949
+ "81": "B",
1950
+ "82": "A",
1951
+ "85": "I",
1952
+ "87": "L"
1953
+ },
1954
+ "ABEFHJKL": {
1955
+ "74": "F",
1956
+ "77": "H",
1957
+ "79": "E",
1958
+ "80": "K",
1959
+ "81": "B",
1960
+ "82": "A",
1961
+ "85": "J",
1962
+ "87": "L"
1963
+ },
1964
+ "ABEFIJKL": {
1965
+ "74": "A",
1966
+ "77": "F",
1967
+ "79": "E",
1968
+ "80": "K",
1969
+ "81": "B",
1970
+ "82": "I",
1971
+ "85": "J",
1972
+ "87": "L"
1973
+ },
1974
+ "ABEGHIJK": {
1975
+ "74": "A",
1976
+ "77": "G",
1977
+ "79": "E",
1978
+ "80": "K",
1979
+ "81": "B",
1980
+ "82": "H",
1981
+ "85": "J",
1982
+ "87": "I"
1983
+ },
1984
+ "ABEGHIJL": {
1985
+ "74": "A",
1986
+ "77": "G",
1987
+ "79": "E",
1988
+ "80": "I",
1989
+ "81": "B",
1990
+ "82": "H",
1991
+ "85": "J",
1992
+ "87": "L"
1993
+ },
1994
+ "ABEGHIKL": {
1995
+ "74": "A",
1996
+ "77": "H",
1997
+ "79": "E",
1998
+ "80": "K",
1999
+ "81": "B",
2000
+ "82": "I",
2001
+ "85": "G",
2002
+ "87": "L"
2003
+ },
2004
+ "ABEGHJKL": {
2005
+ "74": "A",
2006
+ "77": "G",
2007
+ "79": "E",
2008
+ "80": "K",
2009
+ "81": "B",
2010
+ "82": "H",
2011
+ "85": "J",
2012
+ "87": "L"
2013
+ },
2014
+ "ABEGIJKL": {
2015
+ "74": "A",
2016
+ "77": "G",
2017
+ "79": "E",
2018
+ "80": "K",
2019
+ "81": "B",
2020
+ "82": "I",
2021
+ "85": "J",
2022
+ "87": "L"
2023
+ },
2024
+ "ABEHIJKL": {
2025
+ "74": "A",
2026
+ "77": "H",
2027
+ "79": "E",
2028
+ "80": "K",
2029
+ "81": "B",
2030
+ "82": "I",
2031
+ "85": "J",
2032
+ "87": "L"
2033
+ },
2034
+ "ABFGHIJK": {
2035
+ "74": "F",
2036
+ "77": "G",
2037
+ "79": "H",
2038
+ "80": "K",
2039
+ "81": "B",
2040
+ "82": "A",
2041
+ "85": "J",
2042
+ "87": "I"
2043
+ },
2044
+ "ABFGHIJL": {
2045
+ "74": "F",
2046
+ "77": "G",
2047
+ "79": "H",
2048
+ "80": "I",
2049
+ "81": "B",
2050
+ "82": "A",
2051
+ "85": "J",
2052
+ "87": "L"
2053
+ },
2054
+ "ABFGHIKL": {
2055
+ "74": "A",
2056
+ "77": "F",
2057
+ "79": "H",
2058
+ "80": "K",
2059
+ "81": "B",
2060
+ "82": "I",
2061
+ "85": "G",
2062
+ "87": "L"
2063
+ },
2064
+ "ABFGHJKL": {
2065
+ "74": "F",
2066
+ "77": "G",
2067
+ "79": "H",
2068
+ "80": "K",
2069
+ "81": "B",
2070
+ "82": "A",
2071
+ "85": "J",
2072
+ "87": "L"
2073
+ },
2074
+ "ABFGIJKL": {
2075
+ "74": "F",
2076
+ "77": "G",
2077
+ "79": "I",
2078
+ "80": "K",
2079
+ "81": "B",
2080
+ "82": "A",
2081
+ "85": "J",
2082
+ "87": "L"
2083
+ },
2084
+ "ABFHIJKL": {
2085
+ "74": "A",
2086
+ "77": "F",
2087
+ "79": "H",
2088
+ "80": "K",
2089
+ "81": "B",
2090
+ "82": "I",
2091
+ "85": "J",
2092
+ "87": "L"
2093
+ },
2094
+ "ABGHIJKL": {
2095
+ "74": "A",
2096
+ "77": "G",
2097
+ "79": "H",
2098
+ "80": "K",
2099
+ "81": "B",
2100
+ "82": "I",
2101
+ "85": "J",
2102
+ "87": "L"
2103
+ },
2104
+ "ACDEFGHI": {
2105
+ "74": "C",
2106
+ "77": "F",
2107
+ "79": "H",
2108
+ "80": "I",
2109
+ "81": "E",
2110
+ "82": "A",
2111
+ "85": "G",
2112
+ "87": "D"
2113
+ },
2114
+ "ACDEFGHJ": {
2115
+ "74": "C",
2116
+ "77": "F",
2117
+ "79": "H",
2118
+ "80": "E",
2119
+ "81": "J",
2120
+ "82": "A",
2121
+ "85": "G",
2122
+ "87": "D"
2123
+ },
2124
+ "ACDEFGHK": {
2125
+ "74": "C",
2126
+ "77": "F",
2127
+ "79": "H",
2128
+ "80": "K",
2129
+ "81": "E",
2130
+ "82": "A",
2131
+ "85": "G",
2132
+ "87": "D"
2133
+ },
2134
+ "ACDEFGHL": {
2135
+ "74": "C",
2136
+ "77": "D",
2137
+ "79": "H",
2138
+ "80": "E",
2139
+ "81": "F",
2140
+ "82": "A",
2141
+ "85": "G",
2142
+ "87": "L"
2143
+ },
2144
+ "ACDEFGIJ": {
2145
+ "74": "D",
2146
+ "77": "F",
2147
+ "79": "C",
2148
+ "80": "I",
2149
+ "81": "J",
2150
+ "82": "A",
2151
+ "85": "G",
2152
+ "87": "E"
2153
+ },
2154
+ "ACDEFGIK": {
2155
+ "74": "D",
2156
+ "77": "F",
2157
+ "79": "C",
2158
+ "80": "K",
2159
+ "81": "E",
2160
+ "82": "A",
2161
+ "85": "G",
2162
+ "87": "I"
2163
+ },
2164
+ "ACDEFGIL": {
2165
+ "74": "D",
2166
+ "77": "F",
2167
+ "79": "C",
2168
+ "80": "I",
2169
+ "81": "E",
2170
+ "82": "A",
2171
+ "85": "G",
2172
+ "87": "L"
2173
+ },
2174
+ "ACDEFGJK": {
2175
+ "74": "D",
2176
+ "77": "F",
2177
+ "79": "C",
2178
+ "80": "K",
2179
+ "81": "J",
2180
+ "82": "A",
2181
+ "85": "G",
2182
+ "87": "E"
2183
+ },
2184
+ "ACDEFGJL": {
2185
+ "74": "D",
2186
+ "77": "F",
2187
+ "79": "C",
2188
+ "80": "E",
2189
+ "81": "J",
2190
+ "82": "A",
2191
+ "85": "G",
2192
+ "87": "L"
2193
+ },
2194
+ "ACDEFGKL": {
2195
+ "74": "D",
2196
+ "77": "F",
2197
+ "79": "C",
2198
+ "80": "K",
2199
+ "81": "E",
2200
+ "82": "A",
2201
+ "85": "G",
2202
+ "87": "L"
2203
+ },
2204
+ "ACDEFHIJ": {
2205
+ "74": "C",
2206
+ "77": "F",
2207
+ "79": "H",
2208
+ "80": "I",
2209
+ "81": "E",
2210
+ "82": "A",
2211
+ "85": "J",
2212
+ "87": "D"
2213
+ },
2214
+ "ACDEFHIK": {
2215
+ "74": "C",
2216
+ "77": "D",
2217
+ "79": "H",
2218
+ "80": "K",
2219
+ "81": "F",
2220
+ "82": "A",
2221
+ "85": "E",
2222
+ "87": "I"
2223
+ },
2224
+ "ACDEFHIL": {
2225
+ "74": "C",
2226
+ "77": "D",
2227
+ "79": "H",
2228
+ "80": "I",
2229
+ "81": "F",
2230
+ "82": "A",
2231
+ "85": "E",
2232
+ "87": "L"
2233
+ },
2234
+ "ACDEFHJK": {
2235
+ "74": "C",
2236
+ "77": "F",
2237
+ "79": "H",
2238
+ "80": "K",
2239
+ "81": "E",
2240
+ "82": "A",
2241
+ "85": "J",
2242
+ "87": "D"
2243
+ },
2244
+ "ACDEFHJL": {
2245
+ "74": "C",
2246
+ "77": "D",
2247
+ "79": "H",
2248
+ "80": "E",
2249
+ "81": "F",
2250
+ "82": "A",
2251
+ "85": "J",
2252
+ "87": "L"
2253
+ },
2254
+ "ACDEFHKL": {
2255
+ "74": "C",
2256
+ "77": "D",
2257
+ "79": "H",
2258
+ "80": "K",
2259
+ "81": "F",
2260
+ "82": "A",
2261
+ "85": "E",
2262
+ "87": "L"
2263
+ },
2264
+ "ACDEFIJK": {
2265
+ "74": "D",
2266
+ "77": "F",
2267
+ "79": "C",
2268
+ "80": "K",
2269
+ "81": "E",
2270
+ "82": "A",
2271
+ "85": "J",
2272
+ "87": "I"
2273
+ },
2274
+ "ACDEFIJL": {
2275
+ "74": "D",
2276
+ "77": "F",
2277
+ "79": "C",
2278
+ "80": "I",
2279
+ "81": "E",
2280
+ "82": "A",
2281
+ "85": "J",
2282
+ "87": "L"
2283
+ },
2284
+ "ACDEFIKL": {
2285
+ "74": "D",
2286
+ "77": "F",
2287
+ "79": "C",
2288
+ "80": "K",
2289
+ "81": "I",
2290
+ "82": "A",
2291
+ "85": "E",
2292
+ "87": "L"
2293
+ },
2294
+ "ACDEFJKL": {
2295
+ "74": "D",
2296
+ "77": "F",
2297
+ "79": "C",
2298
+ "80": "K",
2299
+ "81": "E",
2300
+ "82": "A",
2301
+ "85": "J",
2302
+ "87": "L"
2303
+ },
2304
+ "ACDEGHIJ": {
2305
+ "74": "C",
2306
+ "77": "D",
2307
+ "79": "H",
2308
+ "80": "I",
2309
+ "81": "J",
2310
+ "82": "A",
2311
+ "85": "G",
2312
+ "87": "E"
2313
+ },
2314
+ "ACDEGHIK": {
2315
+ "74": "C",
2316
+ "77": "D",
2317
+ "79": "H",
2318
+ "80": "K",
2319
+ "81": "E",
2320
+ "82": "A",
2321
+ "85": "G",
2322
+ "87": "I"
2323
+ },
2324
+ "ACDEGHIL": {
2325
+ "74": "C",
2326
+ "77": "D",
2327
+ "79": "H",
2328
+ "80": "I",
2329
+ "81": "E",
2330
+ "82": "A",
2331
+ "85": "G",
2332
+ "87": "L"
2333
+ },
2334
+ "ACDEGHJK": {
2335
+ "74": "C",
2336
+ "77": "D",
2337
+ "79": "H",
2338
+ "80": "K",
2339
+ "81": "J",
2340
+ "82": "A",
2341
+ "85": "G",
2342
+ "87": "E"
2343
+ },
2344
+ "ACDEGHJL": {
2345
+ "74": "C",
2346
+ "77": "D",
2347
+ "79": "H",
2348
+ "80": "E",
2349
+ "81": "J",
2350
+ "82": "A",
2351
+ "85": "G",
2352
+ "87": "L"
2353
+ },
2354
+ "ACDEGHKL": {
2355
+ "74": "C",
2356
+ "77": "D",
2357
+ "79": "H",
2358
+ "80": "K",
2359
+ "81": "E",
2360
+ "82": "A",
2361
+ "85": "G",
2362
+ "87": "L"
2363
+ },
2364
+ "ACDEGIJK": {
2365
+ "74": "C",
2366
+ "77": "D",
2367
+ "79": "E",
2368
+ "80": "K",
2369
+ "81": "J",
2370
+ "82": "A",
2371
+ "85": "G",
2372
+ "87": "I"
2373
+ },
2374
+ "ACDEGIJL": {
2375
+ "74": "C",
2376
+ "77": "D",
2377
+ "79": "E",
2378
+ "80": "I",
2379
+ "81": "J",
2380
+ "82": "A",
2381
+ "85": "G",
2382
+ "87": "L"
2383
+ },
2384
+ "ACDEGIKL": {
2385
+ "74": "C",
2386
+ "77": "D",
2387
+ "79": "E",
2388
+ "80": "K",
2389
+ "81": "I",
2390
+ "82": "A",
2391
+ "85": "G",
2392
+ "87": "L"
2393
+ },
2394
+ "ACDEGJKL": {
2395
+ "74": "C",
2396
+ "77": "D",
2397
+ "79": "E",
2398
+ "80": "K",
2399
+ "81": "J",
2400
+ "82": "A",
2401
+ "85": "G",
2402
+ "87": "L"
2403
+ },
2404
+ "ACDEHIJK": {
2405
+ "74": "C",
2406
+ "77": "D",
2407
+ "79": "H",
2408
+ "80": "K",
2409
+ "81": "E",
2410
+ "82": "A",
2411
+ "85": "J",
2412
+ "87": "I"
2413
+ },
2414
+ "ACDEHIJL": {
2415
+ "74": "C",
2416
+ "77": "D",
2417
+ "79": "H",
2418
+ "80": "I",
2419
+ "81": "E",
2420
+ "82": "A",
2421
+ "85": "J",
2422
+ "87": "L"
2423
+ },
2424
+ "ACDEHIKL": {
2425
+ "74": "C",
2426
+ "77": "D",
2427
+ "79": "H",
2428
+ "80": "K",
2429
+ "81": "I",
2430
+ "82": "A",
2431
+ "85": "E",
2432
+ "87": "L"
2433
+ },
2434
+ "ACDEHJKL": {
2435
+ "74": "C",
2436
+ "77": "D",
2437
+ "79": "H",
2438
+ "80": "K",
2439
+ "81": "E",
2440
+ "82": "A",
2441
+ "85": "J",
2442
+ "87": "L"
2443
+ },
2444
+ "ACDEIJKL": {
2445
+ "74": "C",
2446
+ "77": "D",
2447
+ "79": "E",
2448
+ "80": "K",
2449
+ "81": "I",
2450
+ "82": "A",
2451
+ "85": "J",
2452
+ "87": "L"
2453
+ },
2454
+ "ACDFGHIJ": {
2455
+ "74": "C",
2456
+ "77": "F",
2457
+ "79": "H",
2458
+ "80": "I",
2459
+ "81": "J",
2460
+ "82": "A",
2461
+ "85": "G",
2462
+ "87": "D"
2463
+ },
2464
+ "ACDFGHIK": {
2465
+ "74": "C",
2466
+ "77": "D",
2467
+ "79": "H",
2468
+ "80": "K",
2469
+ "81": "F",
2470
+ "82": "A",
2471
+ "85": "G",
2472
+ "87": "I"
2473
+ },
2474
+ "ACDFGHIL": {
2475
+ "74": "C",
2476
+ "77": "D",
2477
+ "79": "H",
2478
+ "80": "I",
2479
+ "81": "F",
2480
+ "82": "A",
2481
+ "85": "G",
2482
+ "87": "L"
2483
+ },
2484
+ "ACDFGHJK": {
2485
+ "74": "C",
2486
+ "77": "F",
2487
+ "79": "H",
2488
+ "80": "K",
2489
+ "81": "J",
2490
+ "82": "A",
2491
+ "85": "G",
2492
+ "87": "D"
2493
+ },
2494
+ "ACDFGHJL": {
2495
+ "74": "D",
2496
+ "77": "F",
2497
+ "79": "C",
2498
+ "80": "H",
2499
+ "81": "J",
2500
+ "82": "A",
2501
+ "85": "G",
2502
+ "87": "L"
2503
+ },
2504
+ "ACDFGHKL": {
2505
+ "74": "C",
2506
+ "77": "D",
2507
+ "79": "H",
2508
+ "80": "K",
2509
+ "81": "F",
2510
+ "82": "A",
2511
+ "85": "G",
2512
+ "87": "L"
2513
+ },
2514
+ "ACDFGIJK": {
2515
+ "74": "D",
2516
+ "77": "F",
2517
+ "79": "C",
2518
+ "80": "K",
2519
+ "81": "J",
2520
+ "82": "A",
2521
+ "85": "G",
2522
+ "87": "I"
2523
+ },
2524
+ "ACDFGIJL": {
2525
+ "74": "D",
2526
+ "77": "F",
2527
+ "79": "C",
2528
+ "80": "I",
2529
+ "81": "J",
2530
+ "82": "A",
2531
+ "85": "G",
2532
+ "87": "L"
2533
+ },
2534
+ "ACDFGIKL": {
2535
+ "74": "D",
2536
+ "77": "F",
2537
+ "79": "C",
2538
+ "80": "K",
2539
+ "81": "I",
2540
+ "82": "A",
2541
+ "85": "G",
2542
+ "87": "L"
2543
+ },
2544
+ "ACDFGJKL": {
2545
+ "74": "D",
2546
+ "77": "F",
2547
+ "79": "C",
2548
+ "80": "K",
2549
+ "81": "J",
2550
+ "82": "A",
2551
+ "85": "G",
2552
+ "87": "L"
2553
+ },
2554
+ "ACDFHIJK": {
2555
+ "74": "C",
2556
+ "77": "D",
2557
+ "79": "H",
2558
+ "80": "K",
2559
+ "81": "F",
2560
+ "82": "A",
2561
+ "85": "J",
2562
+ "87": "I"
2563
+ },
2564
+ "ACDFHIJL": {
2565
+ "74": "C",
2566
+ "77": "D",
2567
+ "79": "H",
2568
+ "80": "I",
2569
+ "81": "F",
2570
+ "82": "A",
2571
+ "85": "J",
2572
+ "87": "L"
2573
+ },
2574
+ "ACDFHIKL": {
2575
+ "74": "C",
2576
+ "77": "D",
2577
+ "79": "H",
2578
+ "80": "K",
2579
+ "81": "I",
2580
+ "82": "A",
2581
+ "85": "F",
2582
+ "87": "L"
2583
+ },
2584
+ "ACDFHJKL": {
2585
+ "74": "C",
2586
+ "77": "D",
2587
+ "79": "H",
2588
+ "80": "K",
2589
+ "81": "F",
2590
+ "82": "A",
2591
+ "85": "J",
2592
+ "87": "L"
2593
+ },
2594
+ "ACDFIJKL": {
2595
+ "74": "D",
2596
+ "77": "F",
2597
+ "79": "C",
2598
+ "80": "K",
2599
+ "81": "I",
2600
+ "82": "A",
2601
+ "85": "J",
2602
+ "87": "L"
2603
+ },
2604
+ "ACDGHIJK": {
2605
+ "74": "C",
2606
+ "77": "D",
2607
+ "79": "H",
2608
+ "80": "K",
2609
+ "81": "J",
2610
+ "82": "A",
2611
+ "85": "G",
2612
+ "87": "I"
2613
+ },
2614
+ "ACDGHIJL": {
2615
+ "74": "C",
2616
+ "77": "D",
2617
+ "79": "H",
2618
+ "80": "I",
2619
+ "81": "J",
2620
+ "82": "A",
2621
+ "85": "G",
2622
+ "87": "L"
2623
+ },
2624
+ "ACDGHIKL": {
2625
+ "74": "C",
2626
+ "77": "D",
2627
+ "79": "H",
2628
+ "80": "K",
2629
+ "81": "I",
2630
+ "82": "A",
2631
+ "85": "G",
2632
+ "87": "L"
2633
+ },
2634
+ "ACDGHJKL": {
2635
+ "74": "C",
2636
+ "77": "D",
2637
+ "79": "H",
2638
+ "80": "K",
2639
+ "81": "J",
2640
+ "82": "A",
2641
+ "85": "G",
2642
+ "87": "L"
2643
+ },
2644
+ "ACDGIJKL": {
2645
+ "74": "C",
2646
+ "77": "D",
2647
+ "79": "I",
2648
+ "80": "K",
2649
+ "81": "J",
2650
+ "82": "A",
2651
+ "85": "G",
2652
+ "87": "L"
2653
+ },
2654
+ "ACDHIJKL": {
2655
+ "74": "C",
2656
+ "77": "D",
2657
+ "79": "H",
2658
+ "80": "K",
2659
+ "81": "I",
2660
+ "82": "A",
2661
+ "85": "J",
2662
+ "87": "L"
2663
+ },
2664
+ "ACEFGHIJ": {
2665
+ "74": "C",
2666
+ "77": "F",
2667
+ "79": "H",
2668
+ "80": "I",
2669
+ "81": "J",
2670
+ "82": "A",
2671
+ "85": "G",
2672
+ "87": "E"
2673
+ },
2674
+ "ACEFGHIK": {
2675
+ "74": "C",
2676
+ "77": "F",
2677
+ "79": "H",
2678
+ "80": "K",
2679
+ "81": "E",
2680
+ "82": "A",
2681
+ "85": "G",
2682
+ "87": "I"
2683
+ },
2684
+ "ACEFGHIL": {
2685
+ "74": "C",
2686
+ "77": "F",
2687
+ "79": "H",
2688
+ "80": "I",
2689
+ "81": "E",
2690
+ "82": "A",
2691
+ "85": "G",
2692
+ "87": "L"
2693
+ },
2694
+ "ACEFGHJK": {
2695
+ "74": "C",
2696
+ "77": "F",
2697
+ "79": "H",
2698
+ "80": "K",
2699
+ "81": "J",
2700
+ "82": "A",
2701
+ "85": "G",
2702
+ "87": "E"
2703
+ },
2704
+ "ACEFGHJL": {
2705
+ "74": "C",
2706
+ "77": "F",
2707
+ "79": "H",
2708
+ "80": "E",
2709
+ "81": "J",
2710
+ "82": "A",
2711
+ "85": "G",
2712
+ "87": "L"
2713
+ },
2714
+ "ACEFGHKL": {
2715
+ "74": "C",
2716
+ "77": "F",
2717
+ "79": "H",
2718
+ "80": "K",
2719
+ "81": "E",
2720
+ "82": "A",
2721
+ "85": "G",
2722
+ "87": "L"
2723
+ },
2724
+ "ACEFGIJK": {
2725
+ "74": "C",
2726
+ "77": "F",
2727
+ "79": "E",
2728
+ "80": "K",
2729
+ "81": "J",
2730
+ "82": "A",
2731
+ "85": "G",
2732
+ "87": "I"
2733
+ },
2734
+ "ACEFGIJL": {
2735
+ "74": "C",
2736
+ "77": "F",
2737
+ "79": "E",
2738
+ "80": "I",
2739
+ "81": "J",
2740
+ "82": "A",
2741
+ "85": "G",
2742
+ "87": "L"
2743
+ },
2744
+ "ACEFGIKL": {
2745
+ "74": "C",
2746
+ "77": "F",
2747
+ "79": "E",
2748
+ "80": "K",
2749
+ "81": "I",
2750
+ "82": "A",
2751
+ "85": "G",
2752
+ "87": "L"
2753
+ },
2754
+ "ACEFGJKL": {
2755
+ "74": "C",
2756
+ "77": "F",
2757
+ "79": "E",
2758
+ "80": "K",
2759
+ "81": "J",
2760
+ "82": "A",
2761
+ "85": "G",
2762
+ "87": "L"
2763
+ },
2764
+ "ACEFHIJK": {
2765
+ "74": "C",
2766
+ "77": "F",
2767
+ "79": "H",
2768
+ "80": "K",
2769
+ "81": "E",
2770
+ "82": "A",
2771
+ "85": "J",
2772
+ "87": "I"
2773
+ },
2774
+ "ACEFHIJL": {
2775
+ "74": "C",
2776
+ "77": "F",
2777
+ "79": "H",
2778
+ "80": "I",
2779
+ "81": "E",
2780
+ "82": "A",
2781
+ "85": "J",
2782
+ "87": "L"
2783
+ },
2784
+ "ACEFHIKL": {
2785
+ "74": "C",
2786
+ "77": "F",
2787
+ "79": "H",
2788
+ "80": "K",
2789
+ "81": "I",
2790
+ "82": "A",
2791
+ "85": "E",
2792
+ "87": "L"
2793
+ },
2794
+ "ACEFHJKL": {
2795
+ "74": "C",
2796
+ "77": "F",
2797
+ "79": "H",
2798
+ "80": "K",
2799
+ "81": "E",
2800
+ "82": "A",
2801
+ "85": "J",
2802
+ "87": "L"
2803
+ },
2804
+ "ACEFIJKL": {
2805
+ "74": "C",
2806
+ "77": "F",
2807
+ "79": "E",
2808
+ "80": "K",
2809
+ "81": "I",
2810
+ "82": "A",
2811
+ "85": "J",
2812
+ "87": "L"
2813
+ },
2814
+ "ACEGHIJK": {
2815
+ "74": "C",
2816
+ "77": "H",
2817
+ "79": "E",
2818
+ "80": "K",
2819
+ "81": "J",
2820
+ "82": "A",
2821
+ "85": "G",
2822
+ "87": "I"
2823
+ },
2824
+ "ACEGHIJL": {
2825
+ "74": "C",
2826
+ "77": "H",
2827
+ "79": "E",
2828
+ "80": "I",
2829
+ "81": "J",
2830
+ "82": "A",
2831
+ "85": "G",
2832
+ "87": "L"
2833
+ },
2834
+ "ACEGHIKL": {
2835
+ "74": "C",
2836
+ "77": "H",
2837
+ "79": "E",
2838
+ "80": "K",
2839
+ "81": "I",
2840
+ "82": "A",
2841
+ "85": "G",
2842
+ "87": "L"
2843
+ },
2844
+ "ACEGHJKL": {
2845
+ "74": "C",
2846
+ "77": "H",
2847
+ "79": "E",
2848
+ "80": "K",
2849
+ "81": "J",
2850
+ "82": "A",
2851
+ "85": "G",
2852
+ "87": "L"
2853
+ },
2854
+ "ACEGIJKL": {
2855
+ "74": "C",
2856
+ "77": "G",
2857
+ "79": "E",
2858
+ "80": "K",
2859
+ "81": "I",
2860
+ "82": "A",
2861
+ "85": "J",
2862
+ "87": "L"
2863
+ },
2864
+ "ACEHIJKL": {
2865
+ "74": "C",
2866
+ "77": "H",
2867
+ "79": "E",
2868
+ "80": "K",
2869
+ "81": "I",
2870
+ "82": "A",
2871
+ "85": "J",
2872
+ "87": "L"
2873
+ },
2874
+ "ACFGHIJK": {
2875
+ "74": "C",
2876
+ "77": "F",
2877
+ "79": "H",
2878
+ "80": "K",
2879
+ "81": "J",
2880
+ "82": "A",
2881
+ "85": "G",
2882
+ "87": "I"
2883
+ },
2884
+ "ACFGHIJL": {
2885
+ "74": "C",
2886
+ "77": "F",
2887
+ "79": "H",
2888
+ "80": "I",
2889
+ "81": "J",
2890
+ "82": "A",
2891
+ "85": "G",
2892
+ "87": "L"
2893
+ },
2894
+ "ACFGHIKL": {
2895
+ "74": "C",
2896
+ "77": "F",
2897
+ "79": "H",
2898
+ "80": "K",
2899
+ "81": "I",
2900
+ "82": "A",
2901
+ "85": "G",
2902
+ "87": "L"
2903
+ },
2904
+ "ACFGHJKL": {
2905
+ "74": "C",
2906
+ "77": "F",
2907
+ "79": "H",
2908
+ "80": "K",
2909
+ "81": "J",
2910
+ "82": "A",
2911
+ "85": "G",
2912
+ "87": "L"
2913
+ },
2914
+ "ACFGIJKL": {
2915
+ "74": "C",
2916
+ "77": "F",
2917
+ "79": "I",
2918
+ "80": "K",
2919
+ "81": "J",
2920
+ "82": "A",
2921
+ "85": "G",
2922
+ "87": "L"
2923
+ },
2924
+ "ACFHIJKL": {
2925
+ "74": "C",
2926
+ "77": "F",
2927
+ "79": "H",
2928
+ "80": "K",
2929
+ "81": "I",
2930
+ "82": "A",
2931
+ "85": "J",
2932
+ "87": "L"
2933
+ },
2934
+ "ACGHIJKL": {
2935
+ "74": "C",
2936
+ "77": "G",
2937
+ "79": "H",
2938
+ "80": "K",
2939
+ "81": "I",
2940
+ "82": "A",
2941
+ "85": "J",
2942
+ "87": "L"
2943
+ },
2944
+ "ADEFGHIJ": {
2945
+ "74": "D",
2946
+ "77": "F",
2947
+ "79": "H",
2948
+ "80": "I",
2949
+ "81": "J",
2950
+ "82": "A",
2951
+ "85": "G",
2952
+ "87": "E"
2953
+ },
2954
+ "ADEFGHIK": {
2955
+ "74": "D",
2956
+ "77": "F",
2957
+ "79": "H",
2958
+ "80": "K",
2959
+ "81": "E",
2960
+ "82": "A",
2961
+ "85": "G",
2962
+ "87": "I"
2963
+ },
2964
+ "ADEFGHIL": {
2965
+ "74": "D",
2966
+ "77": "F",
2967
+ "79": "H",
2968
+ "80": "I",
2969
+ "81": "E",
2970
+ "82": "A",
2971
+ "85": "G",
2972
+ "87": "L"
2973
+ },
2974
+ "ADEFGHJK": {
2975
+ "74": "D",
2976
+ "77": "F",
2977
+ "79": "H",
2978
+ "80": "K",
2979
+ "81": "J",
2980
+ "82": "A",
2981
+ "85": "G",
2982
+ "87": "E"
2983
+ },
2984
+ "ADEFGHJL": {
2985
+ "74": "D",
2986
+ "77": "F",
2987
+ "79": "H",
2988
+ "80": "E",
2989
+ "81": "J",
2990
+ "82": "A",
2991
+ "85": "G",
2992
+ "87": "L"
2993
+ },
2994
+ "ADEFGHKL": {
2995
+ "74": "D",
2996
+ "77": "F",
2997
+ "79": "H",
2998
+ "80": "K",
2999
+ "81": "E",
3000
+ "82": "A",
3001
+ "85": "G",
3002
+ "87": "L"
3003
+ },
3004
+ "ADEFGIJK": {
3005
+ "74": "D",
3006
+ "77": "F",
3007
+ "79": "E",
3008
+ "80": "K",
3009
+ "81": "J",
3010
+ "82": "A",
3011
+ "85": "G",
3012
+ "87": "I"
3013
+ },
3014
+ "ADEFGIJL": {
3015
+ "74": "D",
3016
+ "77": "F",
3017
+ "79": "E",
3018
+ "80": "I",
3019
+ "81": "J",
3020
+ "82": "A",
3021
+ "85": "G",
3022
+ "87": "L"
3023
+ },
3024
+ "ADEFGIKL": {
3025
+ "74": "D",
3026
+ "77": "F",
3027
+ "79": "E",
3028
+ "80": "K",
3029
+ "81": "I",
3030
+ "82": "A",
3031
+ "85": "G",
3032
+ "87": "L"
3033
+ },
3034
+ "ADEFGJKL": {
3035
+ "74": "D",
3036
+ "77": "F",
3037
+ "79": "E",
3038
+ "80": "K",
3039
+ "81": "J",
3040
+ "82": "A",
3041
+ "85": "G",
3042
+ "87": "L"
3043
+ },
3044
+ "ADEFHIJK": {
3045
+ "74": "D",
3046
+ "77": "F",
3047
+ "79": "H",
3048
+ "80": "K",
3049
+ "81": "E",
3050
+ "82": "A",
3051
+ "85": "J",
3052
+ "87": "I"
3053
+ },
3054
+ "ADEFHIJL": {
3055
+ "74": "D",
3056
+ "77": "F",
3057
+ "79": "H",
3058
+ "80": "I",
3059
+ "81": "E",
3060
+ "82": "A",
3061
+ "85": "J",
3062
+ "87": "L"
3063
+ },
3064
+ "ADEFHIKL": {
3065
+ "74": "D",
3066
+ "77": "F",
3067
+ "79": "H",
3068
+ "80": "K",
3069
+ "81": "I",
3070
+ "82": "A",
3071
+ "85": "E",
3072
+ "87": "L"
3073
+ },
3074
+ "ADEFHJKL": {
3075
+ "74": "D",
3076
+ "77": "F",
3077
+ "79": "H",
3078
+ "80": "K",
3079
+ "81": "E",
3080
+ "82": "A",
3081
+ "85": "J",
3082
+ "87": "L"
3083
+ },
3084
+ "ADEFIJKL": {
3085
+ "74": "D",
3086
+ "77": "F",
3087
+ "79": "E",
3088
+ "80": "K",
3089
+ "81": "I",
3090
+ "82": "A",
3091
+ "85": "J",
3092
+ "87": "L"
3093
+ },
3094
+ "ADEGHIJK": {
3095
+ "74": "D",
3096
+ "77": "H",
3097
+ "79": "E",
3098
+ "80": "K",
3099
+ "81": "J",
3100
+ "82": "A",
3101
+ "85": "G",
3102
+ "87": "I"
3103
+ },
3104
+ "ADEGHIJL": {
3105
+ "74": "D",
3106
+ "77": "H",
3107
+ "79": "E",
3108
+ "80": "I",
3109
+ "81": "J",
3110
+ "82": "A",
3111
+ "85": "G",
3112
+ "87": "L"
3113
+ },
3114
+ "ADEGHIKL": {
3115
+ "74": "D",
3116
+ "77": "H",
3117
+ "79": "E",
3118
+ "80": "K",
3119
+ "81": "I",
3120
+ "82": "A",
3121
+ "85": "G",
3122
+ "87": "L"
3123
+ },
3124
+ "ADEGHJKL": {
3125
+ "74": "D",
3126
+ "77": "H",
3127
+ "79": "E",
3128
+ "80": "K",
3129
+ "81": "J",
3130
+ "82": "A",
3131
+ "85": "G",
3132
+ "87": "L"
3133
+ },
3134
+ "ADEGIJKL": {
3135
+ "74": "D",
3136
+ "77": "G",
3137
+ "79": "E",
3138
+ "80": "K",
3139
+ "81": "I",
3140
+ "82": "A",
3141
+ "85": "J",
3142
+ "87": "L"
3143
+ },
3144
+ "ADEHIJKL": {
3145
+ "74": "D",
3146
+ "77": "H",
3147
+ "79": "E",
3148
+ "80": "K",
3149
+ "81": "I",
3150
+ "82": "A",
3151
+ "85": "J",
3152
+ "87": "L"
3153
+ },
3154
+ "ADFGHIJK": {
3155
+ "74": "D",
3156
+ "77": "F",
3157
+ "79": "H",
3158
+ "80": "K",
3159
+ "81": "J",
3160
+ "82": "A",
3161
+ "85": "G",
3162
+ "87": "I"
3163
+ },
3164
+ "ADFGHIJL": {
3165
+ "74": "D",
3166
+ "77": "F",
3167
+ "79": "H",
3168
+ "80": "I",
3169
+ "81": "J",
3170
+ "82": "A",
3171
+ "85": "G",
3172
+ "87": "L"
3173
+ },
3174
+ "ADFGHIKL": {
3175
+ "74": "D",
3176
+ "77": "F",
3177
+ "79": "H",
3178
+ "80": "K",
3179
+ "81": "I",
3180
+ "82": "A",
3181
+ "85": "G",
3182
+ "87": "L"
3183
+ },
3184
+ "ADFGHJKL": {
3185
+ "74": "D",
3186
+ "77": "F",
3187
+ "79": "H",
3188
+ "80": "K",
3189
+ "81": "J",
3190
+ "82": "A",
3191
+ "85": "G",
3192
+ "87": "L"
3193
+ },
3194
+ "ADFGIJKL": {
3195
+ "74": "D",
3196
+ "77": "F",
3197
+ "79": "I",
3198
+ "80": "K",
3199
+ "81": "J",
3200
+ "82": "A",
3201
+ "85": "G",
3202
+ "87": "L"
3203
+ },
3204
+ "ADFHIJKL": {
3205
+ "74": "D",
3206
+ "77": "F",
3207
+ "79": "H",
3208
+ "80": "K",
3209
+ "81": "I",
3210
+ "82": "A",
3211
+ "85": "J",
3212
+ "87": "L"
3213
+ },
3214
+ "ADGHIJKL": {
3215
+ "74": "D",
3216
+ "77": "G",
3217
+ "79": "H",
3218
+ "80": "K",
3219
+ "81": "I",
3220
+ "82": "A",
3221
+ "85": "J",
3222
+ "87": "L"
3223
+ },
3224
+ "AEFGHIJK": {
3225
+ "74": "F",
3226
+ "77": "H",
3227
+ "79": "E",
3228
+ "80": "K",
3229
+ "81": "J",
3230
+ "82": "A",
3231
+ "85": "G",
3232
+ "87": "I"
3233
+ },
3234
+ "AEFGHIJL": {
3235
+ "74": "F",
3236
+ "77": "H",
3237
+ "79": "E",
3238
+ "80": "I",
3239
+ "81": "J",
3240
+ "82": "A",
3241
+ "85": "G",
3242
+ "87": "L"
3243
+ },
3244
+ "AEFGHIKL": {
3245
+ "74": "F",
3246
+ "77": "H",
3247
+ "79": "E",
3248
+ "80": "K",
3249
+ "81": "I",
3250
+ "82": "A",
3251
+ "85": "G",
3252
+ "87": "L"
3253
+ },
3254
+ "AEFGHJKL": {
3255
+ "74": "F",
3256
+ "77": "H",
3257
+ "79": "E",
3258
+ "80": "K",
3259
+ "81": "J",
3260
+ "82": "A",
3261
+ "85": "G",
3262
+ "87": "L"
3263
+ },
3264
+ "AEFGIJKL": {
3265
+ "74": "F",
3266
+ "77": "G",
3267
+ "79": "E",
3268
+ "80": "K",
3269
+ "81": "I",
3270
+ "82": "A",
3271
+ "85": "J",
3272
+ "87": "L"
3273
+ },
3274
+ "AEFHIJKL": {
3275
+ "74": "F",
3276
+ "77": "H",
3277
+ "79": "E",
3278
+ "80": "K",
3279
+ "81": "I",
3280
+ "82": "A",
3281
+ "85": "J",
3282
+ "87": "L"
3283
+ },
3284
+ "AEGHIJKL": {
3285
+ "74": "A",
3286
+ "77": "G",
3287
+ "79": "E",
3288
+ "80": "K",
3289
+ "81": "I",
3290
+ "82": "H",
3291
+ "85": "J",
3292
+ "87": "L"
3293
+ },
3294
+ "AFGHIJKL": {
3295
+ "74": "F",
3296
+ "77": "G",
3297
+ "79": "H",
3298
+ "80": "K",
3299
+ "81": "I",
3300
+ "82": "A",
3301
+ "85": "J",
3302
+ "87": "L"
3303
+ },
3304
+ "BCDEFGHI": {
3305
+ "74": "D",
3306
+ "77": "F",
3307
+ "79": "C",
3308
+ "80": "I",
3309
+ "81": "B",
3310
+ "82": "H",
3311
+ "85": "G",
3312
+ "87": "E"
3313
+ },
3314
+ "BCDEFGHJ": {
3315
+ "74": "C",
3316
+ "77": "F",
3317
+ "79": "H",
3318
+ "80": "E",
3319
+ "81": "B",
3320
+ "82": "J",
3321
+ "85": "G",
3322
+ "87": "D"
3323
+ },
3324
+ "BCDEFGHK": {
3325
+ "74": "D",
3326
+ "77": "F",
3327
+ "79": "C",
3328
+ "80": "K",
3329
+ "81": "B",
3330
+ "82": "H",
3331
+ "85": "G",
3332
+ "87": "E"
3333
+ },
3334
+ "BCDEFGHL": {
3335
+ "74": "D",
3336
+ "77": "F",
3337
+ "79": "C",
3338
+ "80": "E",
3339
+ "81": "B",
3340
+ "82": "H",
3341
+ "85": "G",
3342
+ "87": "L"
3343
+ },
3344
+ "BCDEFGIJ": {
3345
+ "74": "D",
3346
+ "77": "F",
3347
+ "79": "C",
3348
+ "80": "I",
3349
+ "81": "B",
3350
+ "82": "J",
3351
+ "85": "G",
3352
+ "87": "E"
3353
+ },
3354
+ "BCDEFGIK": {
3355
+ "74": "D",
3356
+ "77": "F",
3357
+ "79": "C",
3358
+ "80": "K",
3359
+ "81": "B",
3360
+ "82": "E",
3361
+ "85": "G",
3362
+ "87": "I"
3363
+ },
3364
+ "BCDEFGIL": {
3365
+ "74": "D",
3366
+ "77": "F",
3367
+ "79": "C",
3368
+ "80": "I",
3369
+ "81": "B",
3370
+ "82": "E",
3371
+ "85": "G",
3372
+ "87": "L"
3373
+ },
3374
+ "BCDEFGJK": {
3375
+ "74": "D",
3376
+ "77": "F",
3377
+ "79": "C",
3378
+ "80": "K",
3379
+ "81": "B",
3380
+ "82": "J",
3381
+ "85": "G",
3382
+ "87": "E"
3383
+ },
3384
+ "BCDEFGJL": {
3385
+ "74": "D",
3386
+ "77": "F",
3387
+ "79": "C",
3388
+ "80": "E",
3389
+ "81": "B",
3390
+ "82": "J",
3391
+ "85": "G",
3392
+ "87": "L"
3393
+ },
3394
+ "BCDEFGKL": {
3395
+ "74": "D",
3396
+ "77": "F",
3397
+ "79": "C",
3398
+ "80": "K",
3399
+ "81": "B",
3400
+ "82": "E",
3401
+ "85": "G",
3402
+ "87": "L"
3403
+ },
3404
+ "BCDEFHIJ": {
3405
+ "74": "D",
3406
+ "77": "F",
3407
+ "79": "C",
3408
+ "80": "I",
3409
+ "81": "B",
3410
+ "82": "H",
3411
+ "85": "J",
3412
+ "87": "E"
3413
+ },
3414
+ "BCDEFHIK": {
3415
+ "74": "D",
3416
+ "77": "F",
3417
+ "79": "C",
3418
+ "80": "K",
3419
+ "81": "B",
3420
+ "82": "H",
3421
+ "85": "E",
3422
+ "87": "I"
3423
+ },
3424
+ "BCDEFHIL": {
3425
+ "74": "D",
3426
+ "77": "F",
3427
+ "79": "C",
3428
+ "80": "I",
3429
+ "81": "B",
3430
+ "82": "H",
3431
+ "85": "E",
3432
+ "87": "L"
3433
+ },
3434
+ "BCDEFHJK": {
3435
+ "74": "D",
3436
+ "77": "F",
3437
+ "79": "C",
3438
+ "80": "K",
3439
+ "81": "B",
3440
+ "82": "H",
3441
+ "85": "J",
3442
+ "87": "E"
3443
+ },
3444
+ "BCDEFHJL": {
3445
+ "74": "D",
3446
+ "77": "F",
3447
+ "79": "C",
3448
+ "80": "E",
3449
+ "81": "B",
3450
+ "82": "H",
3451
+ "85": "J",
3452
+ "87": "L"
3453
+ },
3454
+ "BCDEFHKL": {
3455
+ "74": "D",
3456
+ "77": "F",
3457
+ "79": "C",
3458
+ "80": "K",
3459
+ "81": "B",
3460
+ "82": "H",
3461
+ "85": "E",
3462
+ "87": "L"
3463
+ },
3464
+ "BCDEFIJK": {
3465
+ "74": "D",
3466
+ "77": "F",
3467
+ "79": "C",
3468
+ "80": "K",
3469
+ "81": "B",
3470
+ "82": "E",
3471
+ "85": "J",
3472
+ "87": "I"
3473
+ },
3474
+ "BCDEFIJL": {
3475
+ "74": "D",
3476
+ "77": "F",
3477
+ "79": "C",
3478
+ "80": "I",
3479
+ "81": "B",
3480
+ "82": "E",
3481
+ "85": "J",
3482
+ "87": "L"
3483
+ },
3484
+ "BCDEFIKL": {
3485
+ "74": "D",
3486
+ "77": "F",
3487
+ "79": "C",
3488
+ "80": "K",
3489
+ "81": "B",
3490
+ "82": "I",
3491
+ "85": "E",
3492
+ "87": "L"
3493
+ },
3494
+ "BCDEFJKL": {
3495
+ "74": "D",
3496
+ "77": "F",
3497
+ "79": "C",
3498
+ "80": "K",
3499
+ "81": "B",
3500
+ "82": "E",
3501
+ "85": "J",
3502
+ "87": "L"
3503
+ },
3504
+ "BCDEGHIJ": {
3505
+ "74": "C",
3506
+ "77": "D",
3507
+ "79": "H",
3508
+ "80": "I",
3509
+ "81": "B",
3510
+ "82": "J",
3511
+ "85": "G",
3512
+ "87": "E"
3513
+ },
3514
+ "BCDEGHIK": {
3515
+ "74": "C",
3516
+ "77": "D",
3517
+ "79": "E",
3518
+ "80": "K",
3519
+ "81": "B",
3520
+ "82": "H",
3521
+ "85": "G",
3522
+ "87": "I"
3523
+ },
3524
+ "BCDEGHIL": {
3525
+ "74": "C",
3526
+ "77": "D",
3527
+ "79": "E",
3528
+ "80": "I",
3529
+ "81": "B",
3530
+ "82": "H",
3531
+ "85": "G",
3532
+ "87": "L"
3533
+ },
3534
+ "BCDEGHJK": {
3535
+ "74": "C",
3536
+ "77": "D",
3537
+ "79": "H",
3538
+ "80": "K",
3539
+ "81": "B",
3540
+ "82": "J",
3541
+ "85": "G",
3542
+ "87": "E"
3543
+ },
3544
+ "BCDEGHJL": {
3545
+ "74": "C",
3546
+ "77": "D",
3547
+ "79": "H",
3548
+ "80": "E",
3549
+ "81": "B",
3550
+ "82": "J",
3551
+ "85": "G",
3552
+ "87": "L"
3553
+ },
3554
+ "BCDEGHKL": {
3555
+ "74": "C",
3556
+ "77": "D",
3557
+ "79": "E",
3558
+ "80": "K",
3559
+ "81": "B",
3560
+ "82": "H",
3561
+ "85": "G",
3562
+ "87": "L"
3563
+ },
3564
+ "BCDEGIJK": {
3565
+ "74": "C",
3566
+ "77": "D",
3567
+ "79": "E",
3568
+ "80": "K",
3569
+ "81": "B",
3570
+ "82": "J",
3571
+ "85": "G",
3572
+ "87": "I"
3573
+ },
3574
+ "BCDEGIJL": {
3575
+ "74": "C",
3576
+ "77": "D",
3577
+ "79": "E",
3578
+ "80": "I",
3579
+ "81": "B",
3580
+ "82": "J",
3581
+ "85": "G",
3582
+ "87": "L"
3583
+ },
3584
+ "BCDEGIKL": {
3585
+ "74": "C",
3586
+ "77": "D",
3587
+ "79": "E",
3588
+ "80": "K",
3589
+ "81": "B",
3590
+ "82": "I",
3591
+ "85": "G",
3592
+ "87": "L"
3593
+ },
3594
+ "BCDEGJKL": {
3595
+ "74": "C",
3596
+ "77": "D",
3597
+ "79": "E",
3598
+ "80": "K",
3599
+ "81": "B",
3600
+ "82": "J",
3601
+ "85": "G",
3602
+ "87": "L"
3603
+ },
3604
+ "BCDEHIJK": {
3605
+ "74": "C",
3606
+ "77": "D",
3607
+ "79": "E",
3608
+ "80": "K",
3609
+ "81": "B",
3610
+ "82": "H",
3611
+ "85": "J",
3612
+ "87": "I"
3613
+ },
3614
+ "BCDEHIJL": {
3615
+ "74": "C",
3616
+ "77": "D",
3617
+ "79": "E",
3618
+ "80": "I",
3619
+ "81": "B",
3620
+ "82": "H",
3621
+ "85": "J",
3622
+ "87": "L"
3623
+ },
3624
+ "BCDEHIKL": {
3625
+ "74": "C",
3626
+ "77": "D",
3627
+ "79": "E",
3628
+ "80": "K",
3629
+ "81": "B",
3630
+ "82": "H",
3631
+ "85": "I",
3632
+ "87": "L"
3633
+ },
3634
+ "BCDEHJKL": {
3635
+ "74": "C",
3636
+ "77": "D",
3637
+ "79": "E",
3638
+ "80": "K",
3639
+ "81": "B",
3640
+ "82": "H",
3641
+ "85": "J",
3642
+ "87": "L"
3643
+ },
3644
+ "BCDEIJKL": {
3645
+ "74": "C",
3646
+ "77": "D",
3647
+ "79": "E",
3648
+ "80": "K",
3649
+ "81": "B",
3650
+ "82": "I",
3651
+ "85": "J",
3652
+ "87": "L"
3653
+ },
3654
+ "BCDFGHIJ": {
3655
+ "74": "C",
3656
+ "77": "F",
3657
+ "79": "H",
3658
+ "80": "I",
3659
+ "81": "B",
3660
+ "82": "J",
3661
+ "85": "G",
3662
+ "87": "D"
3663
+ },
3664
+ "BCDFGHIK": {
3665
+ "74": "D",
3666
+ "77": "F",
3667
+ "79": "C",
3668
+ "80": "K",
3669
+ "81": "B",
3670
+ "82": "H",
3671
+ "85": "G",
3672
+ "87": "I"
3673
+ },
3674
+ "BCDFGHIL": {
3675
+ "74": "D",
3676
+ "77": "F",
3677
+ "79": "C",
3678
+ "80": "I",
3679
+ "81": "B",
3680
+ "82": "H",
3681
+ "85": "G",
3682
+ "87": "L"
3683
+ },
3684
+ "BCDFGHJK": {
3685
+ "74": "C",
3686
+ "77": "F",
3687
+ "79": "H",
3688
+ "80": "K",
3689
+ "81": "B",
3690
+ "82": "J",
3691
+ "85": "G",
3692
+ "87": "D"
3693
+ },
3694
+ "BCDFGHJL": {
3695
+ "74": "D",
3696
+ "77": "F",
3697
+ "79": "C",
3698
+ "80": "J",
3699
+ "81": "B",
3700
+ "82": "H",
3701
+ "85": "G",
3702
+ "87": "L"
3703
+ },
3704
+ "BCDFGHKL": {
3705
+ "74": "D",
3706
+ "77": "F",
3707
+ "79": "C",
3708
+ "80": "K",
3709
+ "81": "B",
3710
+ "82": "H",
3711
+ "85": "G",
3712
+ "87": "L"
3713
+ },
3714
+ "BCDFGIJK": {
3715
+ "74": "D",
3716
+ "77": "F",
3717
+ "79": "C",
3718
+ "80": "K",
3719
+ "81": "B",
3720
+ "82": "J",
3721
+ "85": "G",
3722
+ "87": "I"
3723
+ },
3724
+ "BCDFGIJL": {
3725
+ "74": "D",
3726
+ "77": "F",
3727
+ "79": "C",
3728
+ "80": "I",
3729
+ "81": "B",
3730
+ "82": "J",
3731
+ "85": "G",
3732
+ "87": "L"
3733
+ },
3734
+ "BCDFGIKL": {
3735
+ "74": "D",
3736
+ "77": "F",
3737
+ "79": "C",
3738
+ "80": "K",
3739
+ "81": "B",
3740
+ "82": "I",
3741
+ "85": "G",
3742
+ "87": "L"
3743
+ },
3744
+ "BCDFGJKL": {
3745
+ "74": "D",
3746
+ "77": "F",
3747
+ "79": "C",
3748
+ "80": "K",
3749
+ "81": "B",
3750
+ "82": "J",
3751
+ "85": "G",
3752
+ "87": "L"
3753
+ },
3754
+ "BCDFHIJK": {
3755
+ "74": "D",
3756
+ "77": "F",
3757
+ "79": "C",
3758
+ "80": "K",
3759
+ "81": "B",
3760
+ "82": "H",
3761
+ "85": "J",
3762
+ "87": "I"
3763
+ },
3764
+ "BCDFHIJL": {
3765
+ "74": "D",
3766
+ "77": "F",
3767
+ "79": "C",
3768
+ "80": "I",
3769
+ "81": "B",
3770
+ "82": "H",
3771
+ "85": "J",
3772
+ "87": "L"
3773
+ },
3774
+ "BCDFHIKL": {
3775
+ "74": "D",
3776
+ "77": "F",
3777
+ "79": "C",
3778
+ "80": "K",
3779
+ "81": "B",
3780
+ "82": "H",
3781
+ "85": "I",
3782
+ "87": "L"
3783
+ },
3784
+ "BCDFHJKL": {
3785
+ "74": "D",
3786
+ "77": "F",
3787
+ "79": "C",
3788
+ "80": "K",
3789
+ "81": "B",
3790
+ "82": "H",
3791
+ "85": "J",
3792
+ "87": "L"
3793
+ },
3794
+ "BCDFIJKL": {
3795
+ "74": "D",
3796
+ "77": "F",
3797
+ "79": "C",
3798
+ "80": "K",
3799
+ "81": "B",
3800
+ "82": "I",
3801
+ "85": "J",
3802
+ "87": "L"
3803
+ },
3804
+ "BCDGHIJK": {
3805
+ "74": "C",
3806
+ "77": "D",
3807
+ "79": "H",
3808
+ "80": "K",
3809
+ "81": "B",
3810
+ "82": "J",
3811
+ "85": "G",
3812
+ "87": "I"
3813
+ },
3814
+ "BCDGHIJL": {
3815
+ "74": "C",
3816
+ "77": "D",
3817
+ "79": "H",
3818
+ "80": "I",
3819
+ "81": "B",
3820
+ "82": "J",
3821
+ "85": "G",
3822
+ "87": "L"
3823
+ },
3824
+ "BCDGHIKL": {
3825
+ "74": "C",
3826
+ "77": "D",
3827
+ "79": "H",
3828
+ "80": "K",
3829
+ "81": "B",
3830
+ "82": "I",
3831
+ "85": "G",
3832
+ "87": "L"
3833
+ },
3834
+ "BCDGHJKL": {
3835
+ "74": "C",
3836
+ "77": "D",
3837
+ "79": "H",
3838
+ "80": "K",
3839
+ "81": "B",
3840
+ "82": "J",
3841
+ "85": "G",
3842
+ "87": "L"
3843
+ },
3844
+ "BCDGIJKL": {
3845
+ "74": "C",
3846
+ "77": "D",
3847
+ "79": "I",
3848
+ "80": "K",
3849
+ "81": "B",
3850
+ "82": "J",
3851
+ "85": "G",
3852
+ "87": "L"
3853
+ },
3854
+ "BCDHIJKL": {
3855
+ "74": "C",
3856
+ "77": "D",
3857
+ "79": "H",
3858
+ "80": "K",
3859
+ "81": "B",
3860
+ "82": "I",
3861
+ "85": "J",
3862
+ "87": "L"
3863
+ },
3864
+ "BCEFGHIJ": {
3865
+ "74": "C",
3866
+ "77": "F",
3867
+ "79": "H",
3868
+ "80": "I",
3869
+ "81": "B",
3870
+ "82": "J",
3871
+ "85": "G",
3872
+ "87": "E"
3873
+ },
3874
+ "BCEFGHIK": {
3875
+ "74": "C",
3876
+ "77": "F",
3877
+ "79": "E",
3878
+ "80": "K",
3879
+ "81": "B",
3880
+ "82": "H",
3881
+ "85": "G",
3882
+ "87": "I"
3883
+ },
3884
+ "BCEFGHIL": {
3885
+ "74": "C",
3886
+ "77": "F",
3887
+ "79": "E",
3888
+ "80": "I",
3889
+ "81": "B",
3890
+ "82": "H",
3891
+ "85": "G",
3892
+ "87": "L"
3893
+ },
3894
+ "BCEFGHJK": {
3895
+ "74": "C",
3896
+ "77": "F",
3897
+ "79": "H",
3898
+ "80": "K",
3899
+ "81": "B",
3900
+ "82": "J",
3901
+ "85": "G",
3902
+ "87": "E"
3903
+ },
3904
+ "BCEFGHJL": {
3905
+ "74": "C",
3906
+ "77": "F",
3907
+ "79": "H",
3908
+ "80": "E",
3909
+ "81": "B",
3910
+ "82": "J",
3911
+ "85": "G",
3912
+ "87": "L"
3913
+ },
3914
+ "BCEFGHKL": {
3915
+ "74": "C",
3916
+ "77": "F",
3917
+ "79": "E",
3918
+ "80": "K",
3919
+ "81": "B",
3920
+ "82": "H",
3921
+ "85": "G",
3922
+ "87": "L"
3923
+ },
3924
+ "BCEFGIJK": {
3925
+ "74": "C",
3926
+ "77": "F",
3927
+ "79": "E",
3928
+ "80": "K",
3929
+ "81": "B",
3930
+ "82": "J",
3931
+ "85": "G",
3932
+ "87": "I"
3933
+ },
3934
+ "BCEFGIJL": {
3935
+ "74": "C",
3936
+ "77": "F",
3937
+ "79": "E",
3938
+ "80": "I",
3939
+ "81": "B",
3940
+ "82": "J",
3941
+ "85": "G",
3942
+ "87": "L"
3943
+ },
3944
+ "BCEFGIKL": {
3945
+ "74": "C",
3946
+ "77": "F",
3947
+ "79": "E",
3948
+ "80": "K",
3949
+ "81": "B",
3950
+ "82": "I",
3951
+ "85": "G",
3952
+ "87": "L"
3953
+ },
3954
+ "BCEFGJKL": {
3955
+ "74": "C",
3956
+ "77": "F",
3957
+ "79": "E",
3958
+ "80": "K",
3959
+ "81": "B",
3960
+ "82": "J",
3961
+ "85": "G",
3962
+ "87": "L"
3963
+ },
3964
+ "BCEFHIJK": {
3965
+ "74": "C",
3966
+ "77": "F",
3967
+ "79": "E",
3968
+ "80": "K",
3969
+ "81": "B",
3970
+ "82": "H",
3971
+ "85": "J",
3972
+ "87": "I"
3973
+ },
3974
+ "BCEFHIJL": {
3975
+ "74": "C",
3976
+ "77": "F",
3977
+ "79": "E",
3978
+ "80": "I",
3979
+ "81": "B",
3980
+ "82": "H",
3981
+ "85": "J",
3982
+ "87": "L"
3983
+ },
3984
+ "BCEFHIKL": {
3985
+ "74": "C",
3986
+ "77": "F",
3987
+ "79": "E",
3988
+ "80": "K",
3989
+ "81": "B",
3990
+ "82": "H",
3991
+ "85": "I",
3992
+ "87": "L"
3993
+ },
3994
+ "BCEFHJKL": {
3995
+ "74": "C",
3996
+ "77": "F",
3997
+ "79": "E",
3998
+ "80": "K",
3999
+ "81": "B",
4000
+ "82": "H",
4001
+ "85": "J",
4002
+ "87": "L"
4003
+ },
4004
+ "BCEFIJKL": {
4005
+ "74": "C",
4006
+ "77": "F",
4007
+ "79": "E",
4008
+ "80": "K",
4009
+ "81": "B",
4010
+ "82": "I",
4011
+ "85": "J",
4012
+ "87": "L"
4013
+ },
4014
+ "BCEGHIJK": {
4015
+ "74": "C",
4016
+ "77": "G",
4017
+ "79": "E",
4018
+ "80": "K",
4019
+ "81": "B",
4020
+ "82": "H",
4021
+ "85": "J",
4022
+ "87": "I"
4023
+ },
4024
+ "BCEGHIJL": {
4025
+ "74": "C",
4026
+ "77": "G",
4027
+ "79": "E",
4028
+ "80": "I",
4029
+ "81": "B",
4030
+ "82": "H",
4031
+ "85": "J",
4032
+ "87": "L"
4033
+ },
4034
+ "BCEGHIKL": {
4035
+ "74": "C",
4036
+ "77": "H",
4037
+ "79": "E",
4038
+ "80": "K",
4039
+ "81": "B",
4040
+ "82": "I",
4041
+ "85": "G",
4042
+ "87": "L"
4043
+ },
4044
+ "BCEGHJKL": {
4045
+ "74": "C",
4046
+ "77": "G",
4047
+ "79": "E",
4048
+ "80": "K",
4049
+ "81": "B",
4050
+ "82": "H",
4051
+ "85": "J",
4052
+ "87": "L"
4053
+ },
4054
+ "BCEGIJKL": {
4055
+ "74": "C",
4056
+ "77": "G",
4057
+ "79": "E",
4058
+ "80": "K",
4059
+ "81": "B",
4060
+ "82": "I",
4061
+ "85": "J",
4062
+ "87": "L"
4063
+ },
4064
+ "BCEHIJKL": {
4065
+ "74": "C",
4066
+ "77": "H",
4067
+ "79": "E",
4068
+ "80": "K",
4069
+ "81": "B",
4070
+ "82": "I",
4071
+ "85": "J",
4072
+ "87": "L"
4073
+ },
4074
+ "BCFGHIJK": {
4075
+ "74": "C",
4076
+ "77": "F",
4077
+ "79": "H",
4078
+ "80": "K",
4079
+ "81": "B",
4080
+ "82": "J",
4081
+ "85": "G",
4082
+ "87": "I"
4083
+ },
4084
+ "BCFGHIJL": {
4085
+ "74": "C",
4086
+ "77": "F",
4087
+ "79": "H",
4088
+ "80": "I",
4089
+ "81": "B",
4090
+ "82": "J",
4091
+ "85": "G",
4092
+ "87": "L"
4093
+ },
4094
+ "BCFGHIKL": {
4095
+ "74": "C",
4096
+ "77": "F",
4097
+ "79": "H",
4098
+ "80": "K",
4099
+ "81": "B",
4100
+ "82": "I",
4101
+ "85": "G",
4102
+ "87": "L"
4103
+ },
4104
+ "BCFGHJKL": {
4105
+ "74": "C",
4106
+ "77": "F",
4107
+ "79": "H",
4108
+ "80": "K",
4109
+ "81": "B",
4110
+ "82": "J",
4111
+ "85": "G",
4112
+ "87": "L"
4113
+ },
4114
+ "BCFGIJKL": {
4115
+ "74": "C",
4116
+ "77": "F",
4117
+ "79": "I",
4118
+ "80": "K",
4119
+ "81": "B",
4120
+ "82": "J",
4121
+ "85": "G",
4122
+ "87": "L"
4123
+ },
4124
+ "BCFHIJKL": {
4125
+ "74": "C",
4126
+ "77": "F",
4127
+ "79": "H",
4128
+ "80": "K",
4129
+ "81": "B",
4130
+ "82": "I",
4131
+ "85": "J",
4132
+ "87": "L"
4133
+ },
4134
+ "BCGHIJKL": {
4135
+ "74": "C",
4136
+ "77": "G",
4137
+ "79": "H",
4138
+ "80": "K",
4139
+ "81": "B",
4140
+ "82": "I",
4141
+ "85": "J",
4142
+ "87": "L"
4143
+ },
4144
+ "BDEFGHIJ": {
4145
+ "74": "D",
4146
+ "77": "F",
4147
+ "79": "H",
4148
+ "80": "I",
4149
+ "81": "B",
4150
+ "82": "J",
4151
+ "85": "G",
4152
+ "87": "E"
4153
+ },
4154
+ "BDEFGHIK": {
4155
+ "74": "D",
4156
+ "77": "F",
4157
+ "79": "E",
4158
+ "80": "K",
4159
+ "81": "B",
4160
+ "82": "H",
4161
+ "85": "G",
4162
+ "87": "I"
4163
+ },
4164
+ "BDEFGHIL": {
4165
+ "74": "D",
4166
+ "77": "F",
4167
+ "79": "E",
4168
+ "80": "I",
4169
+ "81": "B",
4170
+ "82": "H",
4171
+ "85": "G",
4172
+ "87": "L"
4173
+ },
4174
+ "BDEFGHJK": {
4175
+ "74": "D",
4176
+ "77": "F",
4177
+ "79": "H",
4178
+ "80": "K",
4179
+ "81": "B",
4180
+ "82": "J",
4181
+ "85": "G",
4182
+ "87": "E"
4183
+ },
4184
+ "BDEFGHJL": {
4185
+ "74": "D",
4186
+ "77": "F",
4187
+ "79": "H",
4188
+ "80": "E",
4189
+ "81": "B",
4190
+ "82": "J",
4191
+ "85": "G",
4192
+ "87": "L"
4193
+ },
4194
+ "BDEFGHKL": {
4195
+ "74": "D",
4196
+ "77": "F",
4197
+ "79": "E",
4198
+ "80": "K",
4199
+ "81": "B",
4200
+ "82": "H",
4201
+ "85": "G",
4202
+ "87": "L"
4203
+ },
4204
+ "BDEFGIJK": {
4205
+ "74": "D",
4206
+ "77": "F",
4207
+ "79": "E",
4208
+ "80": "K",
4209
+ "81": "B",
4210
+ "82": "J",
4211
+ "85": "G",
4212
+ "87": "I"
4213
+ },
4214
+ "BDEFGIJL": {
4215
+ "74": "D",
4216
+ "77": "F",
4217
+ "79": "E",
4218
+ "80": "I",
4219
+ "81": "B",
4220
+ "82": "J",
4221
+ "85": "G",
4222
+ "87": "L"
4223
+ },
4224
+ "BDEFGIKL": {
4225
+ "74": "D",
4226
+ "77": "F",
4227
+ "79": "E",
4228
+ "80": "K",
4229
+ "81": "B",
4230
+ "82": "I",
4231
+ "85": "G",
4232
+ "87": "L"
4233
+ },
4234
+ "BDEFGJKL": {
4235
+ "74": "D",
4236
+ "77": "F",
4237
+ "79": "E",
4238
+ "80": "K",
4239
+ "81": "B",
4240
+ "82": "J",
4241
+ "85": "G",
4242
+ "87": "L"
4243
+ },
4244
+ "BDEFHIJK": {
4245
+ "74": "D",
4246
+ "77": "F",
4247
+ "79": "E",
4248
+ "80": "K",
4249
+ "81": "B",
4250
+ "82": "H",
4251
+ "85": "J",
4252
+ "87": "I"
4253
+ },
4254
+ "BDEFHIJL": {
4255
+ "74": "D",
4256
+ "77": "F",
4257
+ "79": "E",
4258
+ "80": "I",
4259
+ "81": "B",
4260
+ "82": "H",
4261
+ "85": "J",
4262
+ "87": "L"
4263
+ },
4264
+ "BDEFHIKL": {
4265
+ "74": "D",
4266
+ "77": "F",
4267
+ "79": "E",
4268
+ "80": "K",
4269
+ "81": "B",
4270
+ "82": "H",
4271
+ "85": "I",
4272
+ "87": "L"
4273
+ },
4274
+ "BDEFHJKL": {
4275
+ "74": "D",
4276
+ "77": "F",
4277
+ "79": "E",
4278
+ "80": "K",
4279
+ "81": "B",
4280
+ "82": "H",
4281
+ "85": "J",
4282
+ "87": "L"
4283
+ },
4284
+ "BDEFIJKL": {
4285
+ "74": "D",
4286
+ "77": "F",
4287
+ "79": "E",
4288
+ "80": "K",
4289
+ "81": "B",
4290
+ "82": "I",
4291
+ "85": "J",
4292
+ "87": "L"
4293
+ },
4294
+ "BDEGHIJK": {
4295
+ "74": "D",
4296
+ "77": "G",
4297
+ "79": "E",
4298
+ "80": "K",
4299
+ "81": "B",
4300
+ "82": "H",
4301
+ "85": "J",
4302
+ "87": "I"
4303
+ },
4304
+ "BDEGHIJL": {
4305
+ "74": "D",
4306
+ "77": "G",
4307
+ "79": "E",
4308
+ "80": "I",
4309
+ "81": "B",
4310
+ "82": "H",
4311
+ "85": "J",
4312
+ "87": "L"
4313
+ },
4314
+ "BDEGHIKL": {
4315
+ "74": "D",
4316
+ "77": "H",
4317
+ "79": "E",
4318
+ "80": "K",
4319
+ "81": "B",
4320
+ "82": "I",
4321
+ "85": "G",
4322
+ "87": "L"
4323
+ },
4324
+ "BDEGHJKL": {
4325
+ "74": "D",
4326
+ "77": "G",
4327
+ "79": "E",
4328
+ "80": "K",
4329
+ "81": "B",
4330
+ "82": "H",
4331
+ "85": "J",
4332
+ "87": "L"
4333
+ },
4334
+ "BDEGIJKL": {
4335
+ "74": "D",
4336
+ "77": "G",
4337
+ "79": "E",
4338
+ "80": "K",
4339
+ "81": "B",
4340
+ "82": "I",
4341
+ "85": "J",
4342
+ "87": "L"
4343
+ },
4344
+ "BDEHIJKL": {
4345
+ "74": "D",
4346
+ "77": "H",
4347
+ "79": "E",
4348
+ "80": "K",
4349
+ "81": "B",
4350
+ "82": "I",
4351
+ "85": "J",
4352
+ "87": "L"
4353
+ },
4354
+ "BDFGHIJK": {
4355
+ "74": "D",
4356
+ "77": "F",
4357
+ "79": "H",
4358
+ "80": "K",
4359
+ "81": "B",
4360
+ "82": "J",
4361
+ "85": "G",
4362
+ "87": "I"
4363
+ },
4364
+ "BDFGHIJL": {
4365
+ "74": "D",
4366
+ "77": "F",
4367
+ "79": "H",
4368
+ "80": "I",
4369
+ "81": "B",
4370
+ "82": "J",
4371
+ "85": "G",
4372
+ "87": "L"
4373
+ },
4374
+ "BDFGHIKL": {
4375
+ "74": "D",
4376
+ "77": "F",
4377
+ "79": "H",
4378
+ "80": "K",
4379
+ "81": "B",
4380
+ "82": "I",
4381
+ "85": "G",
4382
+ "87": "L"
4383
+ },
4384
+ "BDFGHJKL": {
4385
+ "74": "D",
4386
+ "77": "F",
4387
+ "79": "H",
4388
+ "80": "K",
4389
+ "81": "B",
4390
+ "82": "J",
4391
+ "85": "G",
4392
+ "87": "L"
4393
+ },
4394
+ "BDFGIJKL": {
4395
+ "74": "D",
4396
+ "77": "F",
4397
+ "79": "I",
4398
+ "80": "K",
4399
+ "81": "B",
4400
+ "82": "J",
4401
+ "85": "G",
4402
+ "87": "L"
4403
+ },
4404
+ "BDFHIJKL": {
4405
+ "74": "D",
4406
+ "77": "F",
4407
+ "79": "H",
4408
+ "80": "K",
4409
+ "81": "B",
4410
+ "82": "I",
4411
+ "85": "J",
4412
+ "87": "L"
4413
+ },
4414
+ "BDGHIJKL": {
4415
+ "74": "D",
4416
+ "77": "G",
4417
+ "79": "H",
4418
+ "80": "K",
4419
+ "81": "B",
4420
+ "82": "I",
4421
+ "85": "J",
4422
+ "87": "L"
4423
+ },
4424
+ "BEFGHIJK": {
4425
+ "74": "F",
4426
+ "77": "G",
4427
+ "79": "E",
4428
+ "80": "K",
4429
+ "81": "B",
4430
+ "82": "H",
4431
+ "85": "J",
4432
+ "87": "I"
4433
+ },
4434
+ "BEFGHIJL": {
4435
+ "74": "F",
4436
+ "77": "G",
4437
+ "79": "E",
4438
+ "80": "I",
4439
+ "81": "B",
4440
+ "82": "H",
4441
+ "85": "J",
4442
+ "87": "L"
4443
+ },
4444
+ "BEFGHIKL": {
4445
+ "74": "F",
4446
+ "77": "H",
4447
+ "79": "E",
4448
+ "80": "K",
4449
+ "81": "B",
4450
+ "82": "I",
4451
+ "85": "G",
4452
+ "87": "L"
4453
+ },
4454
+ "BEFGHJKL": {
4455
+ "74": "F",
4456
+ "77": "G",
4457
+ "79": "E",
4458
+ "80": "K",
4459
+ "81": "B",
4460
+ "82": "H",
4461
+ "85": "J",
4462
+ "87": "L"
4463
+ },
4464
+ "BEFGIJKL": {
4465
+ "74": "F",
4466
+ "77": "G",
4467
+ "79": "E",
4468
+ "80": "K",
4469
+ "81": "B",
4470
+ "82": "I",
4471
+ "85": "J",
4472
+ "87": "L"
4473
+ },
4474
+ "BEFHIJKL": {
4475
+ "74": "F",
4476
+ "77": "H",
4477
+ "79": "E",
4478
+ "80": "K",
4479
+ "81": "B",
4480
+ "82": "I",
4481
+ "85": "J",
4482
+ "87": "L"
4483
+ },
4484
+ "BEGHIJKL": {
4485
+ "74": "B",
4486
+ "77": "G",
4487
+ "79": "E",
4488
+ "80": "K",
4489
+ "81": "I",
4490
+ "82": "H",
4491
+ "85": "J",
4492
+ "87": "L"
4493
+ },
4494
+ "BFGHIJKL": {
4495
+ "74": "F",
4496
+ "77": "G",
4497
+ "79": "H",
4498
+ "80": "K",
4499
+ "81": "B",
4500
+ "82": "I",
4501
+ "85": "J",
4502
+ "87": "L"
4503
+ },
4504
+ "CDEFGHIJ": {
4505
+ "74": "D",
4506
+ "77": "F",
4507
+ "79": "C",
4508
+ "80": "I",
4509
+ "81": "J",
4510
+ "82": "H",
4511
+ "85": "G",
4512
+ "87": "E"
4513
+ },
4514
+ "CDEFGHIK": {
4515
+ "74": "D",
4516
+ "77": "F",
4517
+ "79": "C",
4518
+ "80": "K",
4519
+ "81": "E",
4520
+ "82": "H",
4521
+ "85": "G",
4522
+ "87": "I"
4523
+ },
4524
+ "CDEFGHIL": {
4525
+ "74": "D",
4526
+ "77": "F",
4527
+ "79": "C",
4528
+ "80": "I",
4529
+ "81": "E",
4530
+ "82": "H",
4531
+ "85": "G",
4532
+ "87": "L"
4533
+ },
4534
+ "CDEFGHJK": {
4535
+ "74": "D",
4536
+ "77": "F",
4537
+ "79": "C",
4538
+ "80": "K",
4539
+ "81": "J",
4540
+ "82": "H",
4541
+ "85": "G",
4542
+ "87": "E"
4543
+ },
4544
+ "CDEFGHJL": {
4545
+ "74": "D",
4546
+ "77": "F",
4547
+ "79": "C",
4548
+ "80": "E",
4549
+ "81": "J",
4550
+ "82": "H",
4551
+ "85": "G",
4552
+ "87": "L"
4553
+ },
4554
+ "CDEFGHKL": {
4555
+ "74": "D",
4556
+ "77": "F",
4557
+ "79": "C",
4558
+ "80": "K",
4559
+ "81": "E",
4560
+ "82": "H",
4561
+ "85": "G",
4562
+ "87": "L"
4563
+ },
4564
+ "CDEFGIJK": {
4565
+ "74": "D",
4566
+ "77": "F",
4567
+ "79": "C",
4568
+ "80": "K",
4569
+ "81": "E",
4570
+ "82": "J",
4571
+ "85": "G",
4572
+ "87": "I"
4573
+ },
4574
+ "CDEFGIJL": {
4575
+ "74": "D",
4576
+ "77": "F",
4577
+ "79": "C",
4578
+ "80": "I",
4579
+ "81": "E",
4580
+ "82": "J",
4581
+ "85": "G",
4582
+ "87": "L"
4583
+ },
4584
+ "CDEFGIKL": {
4585
+ "74": "D",
4586
+ "77": "F",
4587
+ "79": "C",
4588
+ "80": "K",
4589
+ "81": "E",
4590
+ "82": "I",
4591
+ "85": "G",
4592
+ "87": "L"
4593
+ },
4594
+ "CDEFGJKL": {
4595
+ "74": "D",
4596
+ "77": "F",
4597
+ "79": "C",
4598
+ "80": "K",
4599
+ "81": "E",
4600
+ "82": "J",
4601
+ "85": "G",
4602
+ "87": "L"
4603
+ },
4604
+ "CDEFHIJK": {
4605
+ "74": "D",
4606
+ "77": "F",
4607
+ "79": "C",
4608
+ "80": "K",
4609
+ "81": "E",
4610
+ "82": "H",
4611
+ "85": "J",
4612
+ "87": "I"
4613
+ },
4614
+ "CDEFHIJL": {
4615
+ "74": "D",
4616
+ "77": "F",
4617
+ "79": "C",
4618
+ "80": "I",
4619
+ "81": "E",
4620
+ "82": "H",
4621
+ "85": "J",
4622
+ "87": "L"
4623
+ },
4624
+ "CDEFHIKL": {
4625
+ "74": "D",
4626
+ "77": "F",
4627
+ "79": "C",
4628
+ "80": "K",
4629
+ "81": "I",
4630
+ "82": "H",
4631
+ "85": "E",
4632
+ "87": "L"
4633
+ },
4634
+ "CDEFHJKL": {
4635
+ "74": "D",
4636
+ "77": "F",
4637
+ "79": "C",
4638
+ "80": "K",
4639
+ "81": "E",
4640
+ "82": "H",
4641
+ "85": "J",
4642
+ "87": "L"
4643
+ },
4644
+ "CDEFIJKL": {
4645
+ "74": "D",
4646
+ "77": "F",
4647
+ "79": "C",
4648
+ "80": "K",
4649
+ "81": "E",
4650
+ "82": "I",
4651
+ "85": "J",
4652
+ "87": "L"
4653
+ },
4654
+ "CDEGHIJK": {
4655
+ "74": "C",
4656
+ "77": "D",
4657
+ "79": "E",
4658
+ "80": "K",
4659
+ "81": "J",
4660
+ "82": "H",
4661
+ "85": "G",
4662
+ "87": "I"
4663
+ },
4664
+ "CDEGHIJL": {
4665
+ "74": "C",
4666
+ "77": "D",
4667
+ "79": "E",
4668
+ "80": "I",
4669
+ "81": "J",
4670
+ "82": "H",
4671
+ "85": "G",
4672
+ "87": "L"
4673
+ },
4674
+ "CDEGHIKL": {
4675
+ "74": "C",
4676
+ "77": "D",
4677
+ "79": "E",
4678
+ "80": "K",
4679
+ "81": "I",
4680
+ "82": "H",
4681
+ "85": "G",
4682
+ "87": "L"
4683
+ },
4684
+ "CDEGHJKL": {
4685
+ "74": "C",
4686
+ "77": "D",
4687
+ "79": "E",
4688
+ "80": "K",
4689
+ "81": "J",
4690
+ "82": "H",
4691
+ "85": "G",
4692
+ "87": "L"
4693
+ },
4694
+ "CDEGIJKL": {
4695
+ "74": "C",
4696
+ "77": "D",
4697
+ "79": "E",
4698
+ "80": "K",
4699
+ "81": "I",
4700
+ "82": "J",
4701
+ "85": "G",
4702
+ "87": "L"
4703
+ },
4704
+ "CDEHIJKL": {
4705
+ "74": "C",
4706
+ "77": "D",
4707
+ "79": "E",
4708
+ "80": "K",
4709
+ "81": "I",
4710
+ "82": "H",
4711
+ "85": "J",
4712
+ "87": "L"
4713
+ },
4714
+ "CDFGHIJK": {
4715
+ "74": "D",
4716
+ "77": "F",
4717
+ "79": "C",
4718
+ "80": "K",
4719
+ "81": "J",
4720
+ "82": "H",
4721
+ "85": "G",
4722
+ "87": "I"
4723
+ },
4724
+ "CDFGHIJL": {
4725
+ "74": "D",
4726
+ "77": "F",
4727
+ "79": "C",
4728
+ "80": "I",
4729
+ "81": "J",
4730
+ "82": "H",
4731
+ "85": "G",
4732
+ "87": "L"
4733
+ },
4734
+ "CDFGHIKL": {
4735
+ "74": "D",
4736
+ "77": "F",
4737
+ "79": "C",
4738
+ "80": "K",
4739
+ "81": "I",
4740
+ "82": "H",
4741
+ "85": "G",
4742
+ "87": "L"
4743
+ },
4744
+ "CDFGHJKL": {
4745
+ "74": "D",
4746
+ "77": "F",
4747
+ "79": "C",
4748
+ "80": "K",
4749
+ "81": "J",
4750
+ "82": "H",
4751
+ "85": "G",
4752
+ "87": "L"
4753
+ },
4754
+ "CDFGIJKL": {
4755
+ "74": "D",
4756
+ "77": "F",
4757
+ "79": "C",
4758
+ "80": "K",
4759
+ "81": "I",
4760
+ "82": "J",
4761
+ "85": "G",
4762
+ "87": "L"
4763
+ },
4764
+ "CDFHIJKL": {
4765
+ "74": "D",
4766
+ "77": "F",
4767
+ "79": "C",
4768
+ "80": "K",
4769
+ "81": "I",
4770
+ "82": "H",
4771
+ "85": "J",
4772
+ "87": "L"
4773
+ },
4774
+ "CDGHIJKL": {
4775
+ "74": "C",
4776
+ "77": "D",
4777
+ "79": "H",
4778
+ "80": "K",
4779
+ "81": "I",
4780
+ "82": "J",
4781
+ "85": "G",
4782
+ "87": "L"
4783
+ },
4784
+ "CEFGHIJK": {
4785
+ "74": "C",
4786
+ "77": "F",
4787
+ "79": "E",
4788
+ "80": "K",
4789
+ "81": "J",
4790
+ "82": "H",
4791
+ "85": "G",
4792
+ "87": "I"
4793
+ },
4794
+ "CEFGHIJL": {
4795
+ "74": "C",
4796
+ "77": "F",
4797
+ "79": "E",
4798
+ "80": "I",
4799
+ "81": "J",
4800
+ "82": "H",
4801
+ "85": "G",
4802
+ "87": "L"
4803
+ },
4804
+ "CEFGHIKL": {
4805
+ "74": "C",
4806
+ "77": "F",
4807
+ "79": "E",
4808
+ "80": "K",
4809
+ "81": "I",
4810
+ "82": "H",
4811
+ "85": "G",
4812
+ "87": "L"
4813
+ },
4814
+ "CEFGHJKL": {
4815
+ "74": "C",
4816
+ "77": "F",
4817
+ "79": "E",
4818
+ "80": "K",
4819
+ "81": "J",
4820
+ "82": "H",
4821
+ "85": "G",
4822
+ "87": "L"
4823
+ },
4824
+ "CEFGIJKL": {
4825
+ "74": "C",
4826
+ "77": "F",
4827
+ "79": "E",
4828
+ "80": "K",
4829
+ "81": "I",
4830
+ "82": "J",
4831
+ "85": "G",
4832
+ "87": "L"
4833
+ },
4834
+ "CEFHIJKL": {
4835
+ "74": "C",
4836
+ "77": "F",
4837
+ "79": "E",
4838
+ "80": "K",
4839
+ "81": "I",
4840
+ "82": "H",
4841
+ "85": "J",
4842
+ "87": "L"
4843
+ },
4844
+ "CEGHIJKL": {
4845
+ "74": "C",
4846
+ "77": "G",
4847
+ "79": "E",
4848
+ "80": "K",
4849
+ "81": "I",
4850
+ "82": "H",
4851
+ "85": "J",
4852
+ "87": "L"
4853
+ },
4854
+ "CFGHIJKL": {
4855
+ "74": "C",
4856
+ "77": "F",
4857
+ "79": "H",
4858
+ "80": "K",
4859
+ "81": "I",
4860
+ "82": "J",
4861
+ "85": "G",
4862
+ "87": "L"
4863
+ },
4864
+ "DEFGHIJK": {
4865
+ "74": "D",
4866
+ "77": "F",
4867
+ "79": "E",
4868
+ "80": "K",
4869
+ "81": "J",
4870
+ "82": "H",
4871
+ "85": "G",
4872
+ "87": "I"
4873
+ },
4874
+ "DEFGHIJL": {
4875
+ "74": "D",
4876
+ "77": "F",
4877
+ "79": "E",
4878
+ "80": "I",
4879
+ "81": "J",
4880
+ "82": "H",
4881
+ "85": "G",
4882
+ "87": "L"
4883
+ },
4884
+ "DEFGHIKL": {
4885
+ "74": "D",
4886
+ "77": "F",
4887
+ "79": "E",
4888
+ "80": "K",
4889
+ "81": "I",
4890
+ "82": "H",
4891
+ "85": "G",
4892
+ "87": "L"
4893
+ },
4894
+ "DEFGHJKL": {
4895
+ "74": "D",
4896
+ "77": "F",
4897
+ "79": "E",
4898
+ "80": "K",
4899
+ "81": "J",
4900
+ "82": "H",
4901
+ "85": "G",
4902
+ "87": "L"
4903
+ },
4904
+ "DEFGIJKL": {
4905
+ "74": "D",
4906
+ "77": "F",
4907
+ "79": "E",
4908
+ "80": "K",
4909
+ "81": "I",
4910
+ "82": "J",
4911
+ "85": "G",
4912
+ "87": "L"
4913
+ },
4914
+ "DEFHIJKL": {
4915
+ "74": "D",
4916
+ "77": "F",
4917
+ "79": "E",
4918
+ "80": "K",
4919
+ "81": "I",
4920
+ "82": "H",
4921
+ "85": "J",
4922
+ "87": "L"
4923
+ },
4924
+ "DEGHIJKL": {
4925
+ "74": "D",
4926
+ "77": "G",
4927
+ "79": "E",
4928
+ "80": "K",
4929
+ "81": "I",
4930
+ "82": "H",
4931
+ "85": "J",
4932
+ "87": "L"
4933
+ },
4934
+ "DFGHIJKL": {
4935
+ "74": "D",
4936
+ "77": "F",
4937
+ "79": "H",
4938
+ "80": "K",
4939
+ "81": "I",
4940
+ "82": "J",
4941
+ "85": "G",
4942
+ "87": "L"
4943
+ },
4944
+ "EFGHIJKL": {
4945
+ "74": "F",
4946
+ "77": "G",
4947
+ "79": "E",
4948
+ "80": "K",
4949
+ "81": "I",
4950
+ "82": "H",
4951
+ "85": "J",
4952
+ "87": "L"
4953
+ }
4954
+ },
4955
+ "source": "https://en.wikipedia.org/wiki/2026_FIFA_World_Cup_knockout_stage"
4956
+ }
docs/submission-checklist.md CHANGED
@@ -1,58 +1,60 @@
1
- # Hackathon Submission Checklist — Underdog Lab
2
-
3
- _Last updated: June 12, 2026_
4
-
5
- ## Pre-Submission Verification
6
-
7
- - [ ] **Space deployed** at https://huggingface.co/spaces/sammoftah/underdog-lab
8
- - [ ] **Space runs** on `cpu-basic` (warm start verified)
9
- - [ ] **Cold start** smoke test passes (open Space in incognito window)
10
- - [ ] **World Cup 2026** tab loads all 48 teams and 72 fixtures
11
- - [ ] **Challenge** tab: select match → baseline appears → scenario extracts → probabilities adjust → reveal works
12
- - [ ] **Scenario Stress Test** slider moves probabilities monotonically
13
- - [ ] **Tiny Model Lab** shows real metrics (no placeholders)
14
- - [ ] **Mobile** smoke test passes (one phone screenshot)
15
- - [ ] **No cloud inference** requirement verified (network tab: no external API calls to LLM providers)
16
- - [ ] **Model parameter count** documented and ≤32B
17
- - [ ] **License** checked (MIT for code, check model license)
18
-
19
- ## Model & Data
20
-
21
- - [ ] **Base model benchmarked** against frozen test set (run `scripts/benchmark_gguf.py`)
22
- - [ ] **Tuned model benchmarked** or negative result documented
23
- - [ ] **Selected GGUF** published on Hugging Face Hub (link: _______________)
24
- - [ ] **LoRA adapter** published (if tuned) (link: _______________)
25
- - [ ] **Training dataset** published on Hugging Face Hub (link: _______________)
26
- - [ ] **Model card** published (taxonomy, limitations, evaluation, provenance)
27
- - [ ] **Dataset card** published (provenance, review status, split information)
28
- - [ ] **Training config** archived alongside adapter
29
- - [ ] **Evaluation manifest** frozen (`data/scenarios/evaluation_manifest.json`)
30
-
31
- ## Submission Assets
32
-
33
- - [ ] **Demo video** recorded (60–90 seconds, warm Space)
34
- - [ ] **Demo video** uploaded (YouTube or Hugging Face)
35
- - [ ] **Social post** drafted and ready to publish
36
- - [ ] **Field notes** complete with real metrics and limitations
37
- - [ ] **GitHub repo** public and README updated
38
- - [ ] **Space README** reflects current state
39
-
40
- ## Final Verification
41
-
42
- - [ ] **Tests pass**: `PYTHONPATH=src pytest` (43 tests)
43
- - [ ] **Dataset audit**: `PYTHONPATH=src python scripts/audit_dataset.py` (zero split overlap)
44
- - [ ] **No test data in training**: verified via audit script
45
- - [ ] **Evaluation manifest** up to date with current file hashes
46
- - [ ] **Deployed commit** recorded:
47
-
48
- ```text
49
- GitHub commit: ________________________________
50
- Space revision: ________________________________
51
- Model revision: ________________________________
52
- Dataset revision: ________________________________
53
  ```
54
 
55
- ## Submission
56
 
57
- - [ ] **Submit** via hackathon platform before June 15 deadline
58
- - [ ] **Tag submission**: `git tag hackathon-submission && git push origin hackathon-submission`
 
 
 
 
1
+ # Sunday Submission Checklist
2
+
3
+ _Updated: June 13, 2026_
4
+
5
+ Run the complete machine gate:
6
+
7
+ ```bash
8
+ make sunday
9
+ ```
10
+
11
+ The generated source of truth is `results/submission_preflight.json`.
12
+
13
+ ## Machine-Verified
14
+
15
+ - [x] 48 teams and 72 group fixtures load.
16
+ - [x] Snapshot integrity and immutable forecast eligibility are tested.
17
+ - [x] Dixon-Coles model passes the 2018-2026 walk-forward ship gate.
18
+ - [x] QLoRA decision is closed and reproducible: **NO-SHIP**.
19
+ - [x] Base model plus deterministic fallback is the selected runtime.
20
+ - [x] Round-of-32 matches 73-88 match the published schedule.
21
+ - [x] All 495 Annex C third-place combinations reproduce the official table.
22
+ - [x] Knockout progression through match 104 is fixed and tested.
23
+ - [x] Dataset audit reports zero normalized overlap across splits.
24
+ - [x] Code license is MIT; base model license is Apache-2.0.
25
+ - [x] Runtime model is 360M parameters, below the 32B limit.
26
+ - [x] Space, source, adapter, dataset, field notes, and social draft URLs exist.
27
+
28
+ ## Claim Boundary
29
+
30
+ - [x] Do not claim the QLoRA adapter improved the product.
31
+ - [x] Do not claim extraction benchmark accuracy; labels are synthetic and
32
+ review-pending.
33
+ - [x] Forecasting evidence is the no-lookahead walk-forward backtest, not one
34
+ correct or incorrect match.
35
+ - [x] Do not market the Space as betting advice or a guaranteed predictor.
36
+
37
+ ## Human Actions Before Submission
38
+
39
+ - [ ] Open a cold Space session and record the verification timestamp in
40
+ `release/submission.json`.
41
+ - [ ] Complete one mobile-width smoke test and record its timestamp.
42
+ - [ ] Record and publish the 60-90 second demo; add `demo_video_url`.
43
+ - [ ] Publish `docs/social-post.md`; add `social_post_url`.
44
+ - [ ] Submit on the hackathon platform; add `hackathon_submission_url`.
45
+ - [ ] Re-run `make release-preflight`; it must print `READY_TO_SUBMIT`.
46
+ - [ ] Record the final GitHub and Space revision in the submission form.
47
+ - [ ] Tag the accepted revision:
48
+
49
+ ```bash
50
+ git tag hackathon-submission
51
+ git push origin hackathon-submission
 
52
  ```
53
 
54
+ ## Published URLs
55
 
56
+ - Space: https://huggingface.co/spaces/sammoftah/underdog-lab
57
+ - Source: https://github.com/OsamaMoftah/Football-Prediction
58
+ - Base model: https://huggingface.co/bartowski/SmolLM2-360M-Instruct-GGUF
59
+ - Evaluated adapter: https://huggingface.co/sammoftah/underdog-lab-smollm2-360m-lora
60
+ - Dataset: https://huggingface.co/datasets/sammoftah/underdog-lab-scenarios
docs/world-cup-verification-checklist.md CHANGED
@@ -1,219 +1,57 @@
1
- # World Cup 2026 Data Verification Checklist
2
-
3
- **Snapshot cutoff:** 2026-06-12T19:45:00Z
4
- **Generated:** 2026-06-12
5
- **Sources:** https://www.fifa.com/en/tournaments/mens/worldcup/canadamexicousa2026, https://inside.fifa.com/fifa-world-ranking/men, https://eloratings.net/World.tsv
6
-
7
- ## Instructions
8
-
9
- - [ ] Verify all 48 teams in each group against FIFA's official draw.
10
- - [ ] Verify all 72 group fixture dates against the FIFA match schedule.
11
- - [ ] Verify recorded results against actual match outcomes.
12
- - [ ] Update Elo ratings from https://eloratings.net/World.tsv before benchmarking.
13
- - [ ] Check each box after verification. Mark discrepancies with ⚠.
14
-
15
- ## Group Teams (48 teams)
16
-
17
- | Group | Pos | Team | FIFA Rank | Elo | Host | Verified |
18
- |---|---:|---:|---:|---:|---:|
19
- | A | 1 | Mexico | 15 | 1881 | ✓ | ☐ |
20
- | A | 2 | South Africa | 61 | 1511 | | ☐ |
21
- | A | 3 | South Korea | 22 | 1786 | | ☐ |
22
- | A | 4 | Czechia | 44 | 1712 | | ☐ |
23
- | B | 1 | Canada | 27 | 1788 | ✓ | ☐ |
24
- | B | 2 | Bosnia and Herzegovina | 71 | 1595 | | ☐ |
25
- | B | 3 | Qatar | 51 | 1421 | | ☐ |
26
- | B | 4 | Switzerland | 17 | 1891 | | ☐ |
27
- | C | 1 | Brazil | 5 | 1991 | | ☐ |
28
- | C | 2 | Morocco | 11 | 1827 | | ☐ |
29
- | C | 3 | Haiti | 84 | 1548 | | ☐ |
30
- | C | 4 | Scotland | 36 | 1782 | | ☐ |
31
- | D | 1 | United States | 14 | 1726 | ✓ | ☐ |
32
- | D | 2 | Paraguay | 39 | 1834 | | ☐ |
33
- | D | 3 | Australia | 26 | 1777 | | ☐ |
34
- | D | 4 | Turkey | 25 | 1911 | | |
35
- | E | 1 | Germany | 9 | 1932 | | |
36
- | E | 2 | Curacao | 82 | 1434 | | ☐ |
37
- | E | 3 | Ivory Coast | 42 | 1695 | | ☐ |
38
- | E | 4 | Ecuador | 23 | 1938 | | ☐ |
39
- | F | 1 | Netherlands | 7 | 1948 | | ☐ |
40
- | F | 2 | Japan | 18 | 1906 | | ☐ |
41
- | F | 3 | Sweden | 43 | 1712 | | ☐ |
42
- | F | 4 | Tunisia | 40 | 1628 | | ☐ |
43
- | G | 1 | Belgium | 8 | 1894 | | ☐ |
44
- | G | 2 | Egypt | 34 | 1696 | | ☐ |
45
- | G | 3 | Iran | 20 | 1772 | | ☐ |
46
- | G | 4 | New Zealand | 86 | 1562 | | ☐ |
47
- | H | 1 | Spain | 1 | 2157 | | ☐ |
48
- | H | 2 | Cape Verde | 68 | 1578 | | ☐ |
49
- | H | 3 | Saudi Arabia | 60 | 1576 | | |
50
- | H | 4 | Uruguay | 16 | 1892 | | ☐ |
51
- | I | 1 | France | 3 | 2063 | | ☐ |
52
- | I | 2 | Senegal | 19 | 1860 | | ☐ |
53
- | I | 3 | Iraq | 58 | 1607 | | ☐ |
54
- | I | 4 | Norway | 29 | 1914 | | ☐ |
55
- | J | 1 | Argentina | 2 | 2115 | | ☐ |
56
- | J | 2 | Algeria | 35 | 1772 | | ☐ |
57
- | J | 3 | Austria | 24 | 1830 | | ☐ |
58
- | J | 4 | Jordan | 66 | 1680 | | ☐ |
59
- | K | 1 | Portugal | 6 | 1989 | | ☐ |
60
- | K | 2 | DR Congo | 56 | 1652 | | ☐ |
61
- | K | 3 | Uzbekistan | 50 | 1714 | | ☐ |
62
- | K | 4 | Colombia | 13 | 1982 | | ☐ |
63
- | L | 1 | England | 4 | 2024 | | ☐ |
64
- | L | 2 | Croatia | 10 | 1912 | | ☐ |
65
- | L | 3 | Ghana | 72 | 1510 | | ☐ |
66
- | L | 4 | Panama | 30 | 1730 | | ☐ |
67
-
68
- ## Group Fixtures (72 matches)
69
-
70
- ### Group A
71
-
72
- | # | Date | Home | Away | Status | Verified |
73
- |---|---:|---:|---:|---:|
74
- | WC26-001 | 2026-06-11 | Mexico | South Africa | 2-0 (played) | ☐ |
75
- | WC26-002 | 2026-06-11 | South Korea | Czechia | 2-1 (played) | ☐ |
76
- | WC26-003 | 2026-06-18 | Czechia | South Africa | Scheduled 2026-06-18 | ☐ |
77
- | WC26-004 | 2026-06-18 | Mexico | South Korea | Scheduled 2026-06-18 | ☐ |
78
- | WC26-005 | 2026-06-24 | Czechia | Mexico | Scheduled 2026-06-24 | ☐ |
79
- | WC26-006 | 2026-06-24 | South Africa | South Korea | Scheduled 2026-06-24 | ☐ |
80
-
81
- ### Group B
82
-
83
- | # | Date | Home | Away | Status | Verified |
84
- |---|---:|---:|---:|---:|
85
- | WC26-007 | 2026-06-12 | Canada | Bosnia and Herzegovina | Scheduled 2026-06-12 | ☐ |
86
- | WC26-008 | 2026-06-13 | Qatar | Switzerland | Scheduled 2026-06-13 | ☐ |
87
- | WC26-009 | 2026-06-18 | Switzerland | Bosnia and Herzegovina | Scheduled 2026-06-18 | ☐ |
88
- | WC26-010 | 2026-06-18 | Canada | Qatar | Scheduled 2026-06-18 | ☐ |
89
- | WC26-011 | 2026-06-24 | Switzerland | Canada | Scheduled 2026-06-24 | ☐ |
90
- | WC26-012 | 2026-06-24 | Bosnia and Herzegovina | Qatar | Scheduled 2026-06-24 | ☐ |
91
-
92
- ### Group C
93
-
94
- | # | Date | Home | Away | Status | Verified |
95
- |---|---:|---:|---:|---:|
96
- | WC26-013 | 2026-06-13 | Brazil | Morocco | Scheduled 2026-06-13 | ☐ |
97
- | WC26-014 | 2026-06-13 | Haiti | Scotland | Scheduled 2026-06-13 | ☐ |
98
- | WC26-015 | 2026-06-19 | Scotland | Morocco | Scheduled 2026-06-19 | ☐ |
99
- | WC26-016 | 2026-06-19 | Brazil | Haiti | Scheduled 2026-06-19 | ☐ |
100
- | WC26-017 | 2026-06-24 | Scotland | Brazil | Scheduled 2026-06-24 | ☐ |
101
- | WC26-018 | 2026-06-24 | Morocco | Haiti | Scheduled 2026-06-24 | ☐ |
102
-
103
- ### Group D
104
-
105
- | # | Date | Home | Away | Status | Verified |
106
- |---|---:|---:|---:|---:|
107
- | WC26-019 | 2026-06-12 | United States | Paraguay | Scheduled 2026-06-12 | ☐ |
108
- | WC26-020 | 2026-06-13 | Australia | Turkey | Scheduled 2026-06-13 | ☐ |
109
- | WC26-021 | 2026-06-19 | Turkey | Paraguay | Scheduled 2026-06-19 | ☐ |
110
- | WC26-022 | 2026-06-19 | United States | Australia | Scheduled 2026-06-19 | ☐ |
111
- | WC26-023 | 2026-06-25 | Turkey | United States | Scheduled 2026-06-25 | ☐ |
112
- | WC26-024 | 2026-06-25 | Paraguay | Australia | Scheduled 2026-06-25 | ☐ |
113
-
114
- ### Group E
115
-
116
- | # | Date | Home | Away | Status | Verified |
117
- |---|---:|---:|---:|---:|
118
- | WC26-025 | 2026-06-14 | Germany | Curacao | Scheduled 2026-06-14 | ☐ |
119
- | WC26-026 | 2026-06-14 | Ivory Coast | Ecuador | Scheduled 2026-06-14 | ☐ |
120
- | WC26-027 | 2026-06-20 | Ecuador | Curacao | Scheduled 2026-06-20 | ☐ |
121
- | WC26-028 | 2026-06-20 | Germany | Ivory Coast | Scheduled 2026-06-20 | ☐ |
122
- | WC26-029 | 2026-06-25 | Ecuador | Germany | Scheduled 2026-06-25 | ☐ |
123
- | WC26-030 | 2026-06-25 | Curacao | Ivory Coast | Scheduled 2026-06-25 | ☐ |
124
-
125
- ### Group F
126
-
127
- | # | Date | Home | Away | Status | Verified |
128
- |---|---:|---:|---:|---:|
129
- | WC26-031 | 2026-06-14 | Netherlands | Japan | Scheduled 2026-06-14 | ☐ |
130
- | WC26-032 | 2026-06-14 | Sweden | Tunisia | Scheduled 2026-06-14 | ☐ |
131
- | WC26-033 | 2026-06-20 | Tunisia | Japan | Scheduled 2026-06-20 | ☐ |
132
- | WC26-034 | 2026-06-20 | Netherlands | Sweden | Scheduled 2026-06-20 | ☐ |
133
- | WC26-035 | 2026-06-25 | Tunisia | Netherlands | Scheduled 2026-06-25 | ☐ |
134
- | WC26-036 | 2026-06-25 | Japan | Sweden | Scheduled 2026-06-25 | ☐ |
135
-
136
- ### Group G
137
-
138
- | # | Date | Home | Away | Status | Verified |
139
- |---|---:|---:|---:|---:|
140
- | WC26-037 | 2026-06-15 | Belgium | Egypt | Scheduled 2026-06-15 | ☐ |
141
- | WC26-038 | 2026-06-15 | Iran | New Zealand | Scheduled 2026-06-15 | ☐ |
142
- | WC26-039 | 2026-06-21 | New Zealand | Egypt | Scheduled 2026-06-21 | ☐ |
143
- | WC26-040 | 2026-06-21 | Belgium | Iran | Scheduled 2026-06-21 | ☐ |
144
- | WC26-041 | 2026-06-26 | New Zealand | Belgium | Scheduled 2026-06-26 | ☐ |
145
- | WC26-042 | 2026-06-26 | Egypt | Iran | Scheduled 2026-06-26 | ☐ |
146
-
147
- ### Group H
148
-
149
- | # | Date | Home | Away | Status | Verified |
150
- |---|---:|---:|---:|---:|
151
- | WC26-043 | 2026-06-15 | Spain | Cape Verde | Scheduled 2026-06-15 | ☐ |
152
- | WC26-044 | 2026-06-15 | Saudi Arabia | Uruguay | Scheduled 2026-06-15 | ☐ |
153
- | WC26-045 | 2026-06-21 | Uruguay | Cape Verde | Scheduled 2026-06-21 | ☐ |
154
- | WC26-046 | 2026-06-21 | Spain | Saudi Arabia | Scheduled 2026-06-21 | ☐ |
155
- | WC26-047 | 2026-06-26 | Uruguay | Spain | Scheduled 2026-06-26 | ☐ |
156
- | WC26-048 | 2026-06-26 | Cape Verde | Saudi Arabia | Scheduled 2026-06-26 | ☐ |
157
-
158
- ### Group I
159
-
160
- | # | Date | Home | Away | Status | Verified |
161
- |---|---:|---:|---:|---:|
162
- | WC26-049 | 2026-06-16 | France | Senegal | Scheduled 2026-06-16 | ☐ |
163
- | WC26-050 | 2026-06-16 | Iraq | Norway | Scheduled 2026-06-16 | ☐ |
164
- | WC26-051 | 2026-06-22 | Norway | Senegal | Scheduled 2026-06-22 | ☐ |
165
- | WC26-052 | 2026-06-22 | France | Iraq | Scheduled 2026-06-22 | ☐ |
166
- | WC26-053 | 2026-06-26 | Norway | France | Scheduled 2026-06-26 | ☐ |
167
- | WC26-054 | 2026-06-26 | Senegal | Iraq | Scheduled 2026-06-26 | ☐ |
168
-
169
- ### Group J
170
-
171
- | # | Date | Home | Away | Status | Verified |
172
- |---|---:|---:|---:|---:|
173
- | WC26-055 | 2026-06-16 | Argentina | Algeria | Scheduled 2026-06-16 | ☐ |
174
- | WC26-056 | 2026-06-16 | Austria | Jordan | Scheduled 2026-06-16 | ☐ |
175
- | WC26-057 | 2026-06-22 | Jordan | Algeria | Scheduled 2026-06-22 | ☐ |
176
- | WC26-058 | 2026-06-22 | Argentina | Austria | Scheduled 2026-06-22 | ☐ |
177
- | WC26-059 | 2026-06-27 | Jordan | Argentina | Scheduled 2026-06-27 | ☐ |
178
- | WC26-060 | 2026-06-27 | Algeria | Austria | Scheduled 2026-06-27 | ☐ |
179
-
180
- ### Group K
181
-
182
- | # | Date | Home | Away | Status | Verified |
183
- |---|---:|---:|---:|---:|
184
- | WC26-061 | 2026-06-17 | Portugal | DR Congo | Scheduled 2026-06-17 | ☐ |
185
- | WC26-062 | 2026-06-17 | Uzbekistan | Colombia | Scheduled 2026-06-17 | ☐ |
186
- | WC26-063 | 2026-06-23 | Colombia | DR Congo | Scheduled 2026-06-23 | ☐ |
187
- | WC26-064 | 2026-06-23 | Portugal | Uzbekistan | Scheduled 2026-06-23 | ☐ |
188
- | WC26-065 | 2026-06-27 | Colombia | Portugal | Scheduled 2026-06-27 | ☐ |
189
- | WC26-066 | 2026-06-27 | DR Congo | Uzbekistan | Scheduled 2026-06-27 | ☐ |
190
-
191
- ### Group L
192
-
193
- | # | Date | Home | Away | Status | Verified |
194
- |---|---:|---:|---:|---:|
195
- | WC26-067 | 2026-06-17 | England | Croatia | Scheduled 2026-06-17 | ☐ |
196
- | WC26-068 | 2026-06-17 | Ghana | Panama | Scheduled 2026-06-17 | ☐ |
197
- | WC26-069 | 2026-06-23 | Panama | Croatia | Scheduled 2026-06-23 | ☐ |
198
- | WC26-070 | 2026-06-23 | England | Ghana | Scheduled 2026-06-23 | ☐ |
199
- | WC26-071 | 2026-06-27 | Panama | England | Scheduled 2026-06-27 | ☐ |
200
- | WC26-072 | 2026-06-27 | Croatia | Ghana | Scheduled 2026-06-27 | ☐ |
201
-
202
- ## Snapshot Metadata
203
-
204
- | Field | Value | Verified |
205
- |---|---:|
206
- | information_cutoff | 2026-06-12T19:45:00Z | ☐ |
207
- | sources | https://www.fifa.com/en/tournaments/mens/worldcup/canadamexicousa2026, https://inside.fifa.com/fifa-world-ranking/men, https://eloratings.net/World.tsv | ☐ |
208
- | Recorded results count | 2 | ☐ |
209
-
210
- ## Additional Checks
211
-
212
- - [ ] Elo ratings are current as of the information cutoff date.
213
- - [ ] No teams are duplicated across groups.
214
- - [ ] Host nations (Canada, Mexico, United States) are marked correctly.
215
- - [ ] Fixture dates match the official FIFA match schedule.
216
- - [ ] Result update script (`scripts/update_snapshot.py`) works without modifying historical data.
217
-
218
- ---
219
- **Reviewer:** ___________________ **Date:** ___________________
 
1
+ # World Cup 2026 Verification
2
+
3
+ _Updated: June 13, 2026_
4
+
5
+ ## Snapshot
6
+
7
+ - Information cutoff: `2026-06-13T04:30:00Z`
8
+ - Teams: 48 across groups A-L
9
+ - Generated group fixtures: 72
10
+ - Recorded results: 4
11
+ - Snapshot validation: `validate_snapshot_integrity`
12
+
13
+ The checked-in snapshot records:
14
+
15
+ - Mexico 2-0 South Africa
16
+ - South Korea 2-1 Czechia
17
+ - Canada 1-1 Bosnia and Herzegovina
18
+ - United States 4-1 Paraguay
19
+
20
+ Results and cutoffs must be added with `scripts/update_snapshot.py`; historical
21
+ forecast files under `predictions/` must never be rewritten.
22
+
23
+ ## Bracket
24
+
25
+ Run:
26
+
27
+ ```bash
28
+ PYTHONPATH=src python scripts/verify_world_cup_bracket.py
29
+ ```
30
+
31
+ Verified scope:
32
+
33
+ - [x] Published Round-of-32 slots for matches 73-88.
34
+ - [x] Official Annex C assignment for every one of the 495 possible sets of
35
+ eight qualifying third-place groups.
36
+ - [x] Round-of-16 pairings for matches 89-96.
37
+ - [x] Quarterfinal pairings for matches 97-100.
38
+ - [x] Semifinal pairings for matches 101-102.
39
+ - [x] Third-place pairing for match 103.
40
+ - [x] Final pairing for match 104.
41
+ - [x] No duplicate qualifier or same-group Round-of-32 pairing.
42
+
43
+ The machine-readable report is `results/bracket_verification.json`.
44
+
45
+ ## Ranking Rules
46
+
47
+ Equal-point teams are ordered by head-to-head points, head-to-head goal
48
+ difference, head-to-head goals, overall goal difference, overall goals, fair
49
+ play, and FIFA ranking. The current snapshot has no card event feed, so fair
50
+ play defaults to zero and FIFA ranking is the deterministic final fallback.
51
+
52
+ ## Sources
53
+
54
+ - https://www.fifa.com/en/tournaments/mens/worldcup/canadamexicousa2026/articles/fifa-world-cup-2026-match-schedule-fixtures-results-teams-stadiums
55
+ - https://en.wikipedia.org/wiki/2026_FIFA_World_Cup_knockout_stage
56
+ - https://inside.fifa.com/fifa-world-ranking/men
57
+ - https://eloratings.net/World.tsv
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
models/README.md CHANGED
@@ -2,8 +2,8 @@
2
 
3
  The application defaults to an automatic runtime that lazily downloads
4
  `bartowski/SmolLM2-360M-Instruct-GGUF` and runs its Q8_0 quantization
5
- through `llama-cpp-python` (see `src/underdog_lab/config.py`). A larger
6
- SmolLM3-3B QLoRA adapter was trained and benchmarked
7
  (`results/ship_decision.json`) but did not clear the ship gate, so it is
8
  not the default. If model loading fails, the challenge remains usable
9
  through a deterministic fallback and records the degraded behavior.
@@ -58,7 +58,7 @@ on `data/historical/matches.csv` (11,094 real international matches,
58
  under-confident through much of the middle range, so calibration remains
59
  an explicit follow-up rather than a completed claim.
60
 
61
- This is a real-but-smaller fit relative to the original remediation plan's
62
- full ensembling/production-monitoring scope (phases 6/8/10 of that plan are
63
- not implemented): one model, one dataset, one backtest, refit by re-running
64
- the two scripts above when new results are available.
 
2
 
3
  The application defaults to an automatic runtime that lazily downloads
4
  `bartowski/SmolLM2-360M-Instruct-GGUF` and runs its Q8_0 quantization
5
+ through `llama-cpp-python` (see `src/underdog_lab/config.py`). A 360M
6
+ SmolLM2 QLoRA adapter was trained and benchmarked
7
  (`results/ship_decision.json`) but did not clear the ship gate, so it is
8
  not the default. If model loading fails, the challenge remains usable
9
  through a deterministic fallback and records the degraded behavior.
 
58
  under-confident through much of the middle range, so calibration remains
59
  an explicit follow-up rather than a completed claim.
60
 
61
+ Tournament simulation now uses the official matches 73-104 path and the 495
62
+ third-place mappings from Annex C. It remains a single fitted statistical
63
+ model rather than an ensemble; refit and re-run the walk-forward gate when new
64
+ results are incorporated.
release/submission.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "deadline": "2026-06-15",
3
+ "space_url": "https://huggingface.co/spaces/sammoftah/underdog-lab",
4
+ "github_url": "https://github.com/OsamaMoftah/Football-Prediction",
5
+ "base_model_url": "https://huggingface.co/bartowski/SmolLM2-360M-Instruct-GGUF",
6
+ "adapter_url": "https://huggingface.co/sammoftah/underdog-lab-smollm2-360m-lora",
7
+ "dataset_url": "https://huggingface.co/datasets/sammoftah/underdog-lab-scenarios",
8
+ "field_notes_url": "https://github.com/OsamaMoftah/Football-Prediction/blob/main/docs/field-notes.md",
9
+ "base_model_parameters": 360000000,
10
+ "parameter_limit": 32000000000,
11
+ "licenses": {
12
+ "code": "MIT",
13
+ "base_model": "Apache-2.0"
14
+ },
15
+ "human_actions": {
16
+ "cold_start_verified_at": "",
17
+ "mobile_smoke_verified_at": "",
18
+ "demo_video_url": "",
19
+ "social_post_url": "",
20
+ "hackathon_submission_url": ""
21
+ }
22
+ }
results/bracket_verification.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "annex_c_combinations": 495,
3
+ "annex_c_failures": [],
4
+ "downstream_matches_verified": [
5
+ 89,
6
+ 90,
7
+ 91,
8
+ 92,
9
+ 93,
10
+ 94,
11
+ 95,
12
+ 96,
13
+ 97,
14
+ 98,
15
+ 99,
16
+ 100,
17
+ 101,
18
+ 102,
19
+ 104,
20
+ 103
21
+ ],
22
+ "release_blocking": false,
23
+ "round_of_32_slots": 16,
24
+ "scope": "Published matches 73-104, including the third-place match, and all 495 Annex C third-place assignments. Fair-play data is not available in the snapshot.",
25
+ "sources": [
26
+ "https://www.fifa.com/en/tournaments/mens/worldcup/canadamexicousa2026/articles/fifa-world-cup-2026-match-schedule-fixtures-results-teams-stadiums",
27
+ "https://en.wikipedia.org/wiki/2026_FIFA_World_Cup_knockout_stage"
28
+ ],
29
+ "status": "verified"
30
+ }
results/qlora_gate_report.json ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "adapter": {
3
+ "adapter": "sammoftah/underdog-lab-smollm2-360m-lora",
4
+ "adapter_revision": "69f9aab7e5e7697d4dccfa2b9ecae29d4e132917",
5
+ "factor_micro_f1": 0.027,
6
+ "fallback_rate": 0.1735,
7
+ "median_latency_ms": 2995.4,
8
+ "merged_gguf": "models/underdog-tuned-Q8_0.gguf",
9
+ "team_attribution_accuracy": 0.0323
10
+ },
11
+ "artifacts": {
12
+ "results/base_q8.json": {
13
+ "sha256": "87ccea0477255fd4872d26e868784467cdb6d5147478bb81d0d246421bcdd69b"
14
+ },
15
+ "results/ship_decision.json": {
16
+ "sha256": "26441c2622b4fade12a2f496886477045650aebf3331fd9dd8206af305b8e8df"
17
+ },
18
+ "results/tuned_q8.json": {
19
+ "sha256": "b00f2720df620baff3dc6052ee934f34c4a1483fbd52ed9001b7c1a7dd5c3a0a"
20
+ }
21
+ },
22
+ "checks": {
23
+ "fallback_rate_controlled": false,
24
+ "minimum_f1_gain": false,
25
+ "no_attribution_regression": false,
26
+ "schema_validity": true
27
+ },
28
+ "claim": "The adapter is not shipped. The base model plus deterministic fallback remains the production extraction path.",
29
+ "computed_decision": "NO-SHIP",
30
+ "declared_decision": "NO-SHIP",
31
+ "failed_checks": [
32
+ "minimum_f1_gain",
33
+ "no_attribution_regression",
34
+ "fallback_rate_controlled"
35
+ ],
36
+ "metrics": {
37
+ "base": {
38
+ "factor_micro_f1": 0.026058631921824102,
39
+ "fallback_rate": 0.09183673469387756,
40
+ "median_latency_ms": 3675.582021009177,
41
+ "schema_validity_rate": 1.0,
42
+ "team_attribution_accuracy": 0.043010752688172046
43
+ },
44
+ "deltas": {
45
+ "factor_micro_f1": 0.0009683951052029231,
46
+ "fallback_rate": 0.08163265306122448,
47
+ "median_latency_ms": -680.2151250158204,
48
+ "team_attribution_accuracy": -0.010752688172043015
49
+ },
50
+ "tuned": {
51
+ "factor_micro_f1": 0.027027027027027025,
52
+ "fallback_rate": 0.17346938775510204,
53
+ "median_latency_ms": 2995.3668959933566,
54
+ "schema_validity_rate": 1.0,
55
+ "team_attribution_accuracy": 0.03225806451612903
56
+ }
57
+ },
58
+ "release_blocking": false,
59
+ "selected_runtime": "base_plus_fallback",
60
+ "status": "closed",
61
+ "thresholds": {
62
+ "maximum_attribution_regression": 0.0,
63
+ "maximum_fallback_increase": 0.02,
64
+ "minimum_f1_gain": 0.15,
65
+ "minimum_schema_validity": 0.99
66
+ }
67
+ }
results/submission_preflight.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "claim_boundaries": [
3
+ "QLoRA adapter evaluated NO-SHIP; no Well-Tuned performance claim.",
4
+ "Scenario labels remain synthetic and review-pending; extraction metrics are pipeline diagnostics.",
5
+ "Forecast accuracy evidence is the walk-forward Dixon-Coles backtest, not isolated match outcomes."
6
+ ],
7
+ "failed_machine_checks": [],
8
+ "machine_checks": {
9
+ "adapter_url_declared": true,
10
+ "base_model_license_documented": true,
11
+ "code_license_documented": true,
12
+ "dataset_url_declared": true,
13
+ "forecast_backtest_ship_gate": true,
14
+ "github_url_declared": true,
15
+ "official_bracket_verified": true,
16
+ "parameter_limit": true,
17
+ "qlora_gate_closed": true,
18
+ "release_docs_present": true,
19
+ "space_url_declared": true,
20
+ "world_cup_group_fixtures_72": true,
21
+ "world_cup_teams_48": true
22
+ },
23
+ "pending_human_actions": [
24
+ "cold_start_verified_at",
25
+ "mobile_smoke_verified_at",
26
+ "demo_video_url",
27
+ "social_post_url",
28
+ "hackathon_submission_url"
29
+ ],
30
+ "status": "READY_FOR_HUMAN_SUBMISSION",
31
+ "urls": {
32
+ "adapter_url": "https://huggingface.co/sammoftah/underdog-lab-smollm2-360m-lora",
33
+ "base_model_url": "https://huggingface.co/bartowski/SmolLM2-360M-Instruct-GGUF",
34
+ "dataset_url": "https://huggingface.co/datasets/sammoftah/underdog-lab-scenarios",
35
+ "field_notes_url": "https://github.com/OsamaMoftah/Football-Prediction/blob/main/docs/field-notes.md",
36
+ "github_url": "https://github.com/OsamaMoftah/Football-Prediction",
37
+ "space_url": "https://huggingface.co/spaces/sammoftah/underdog-lab"
38
+ }
39
+ }
scripts/close_qlora_gate.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+
6
+ from underdog_lab.release.qlora_gate import close_qlora_gate
7
+
8
+
9
+ def main() -> int:
10
+ parser = argparse.ArgumentParser(
11
+ description="Recompute and close the QLoRA release gate."
12
+ )
13
+ parser.add_argument("--root", type=Path, default=Path("."))
14
+ parser.add_argument(
15
+ "--output",
16
+ type=Path,
17
+ default=Path("results/qlora_gate_report.json"),
18
+ )
19
+ args = parser.parse_args()
20
+ report = close_qlora_gate(args.root.resolve(), args.output.resolve())
21
+ print(
22
+ f"QLoRA gate: {report['status']} "
23
+ f"({report['computed_decision']}, "
24
+ f"release_blocking={report['release_blocking']})"
25
+ )
26
+ return 0 if report["status"] == "closed" else 1
27
+
28
+
29
+ if __name__ == "__main__":
30
+ raise SystemExit(main())
scripts/submission_preflight.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+
6
+ from underdog_lab.release.preflight import run_preflight
7
+
8
+
9
+ def main() -> int:
10
+ parser = argparse.ArgumentParser()
11
+ parser.add_argument("--root", type=Path, default=Path("."))
12
+ parser.add_argument(
13
+ "--output",
14
+ type=Path,
15
+ default=Path("results/submission_preflight.json"),
16
+ )
17
+ parser.add_argument(
18
+ "--allow-human-pending",
19
+ action="store_true",
20
+ help="Return success when only account-dependent human actions remain.",
21
+ )
22
+ args = parser.parse_args()
23
+ report = run_preflight(args.root.resolve(), args.output.resolve())
24
+ print(f"Submission preflight: {report['status']}")
25
+ if report["failed_machine_checks"]:
26
+ print("Failed checks: " + ", ".join(report["failed_machine_checks"]))
27
+ return 1
28
+ if report["pending_human_actions"]:
29
+ print("Human actions: " + ", ".join(report["pending_human_actions"]))
30
+ return 0 if args.allow_human_pending else 2
31
+ return 0
32
+
33
+
34
+ if __name__ == "__main__":
35
+ raise SystemExit(main())
scripts/verify_world_cup_bracket.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ from itertools import combinations
6
+ from pathlib import Path
7
+
8
+ from underdog_lab.world_cup.bracket import (
9
+ KNOCKOUT_PATH,
10
+ ROUND_OF_32_SLOTS,
11
+ THIRD_PLACE_MATCH,
12
+ assign_third_place_groups,
13
+ load_annex_c,
14
+ )
15
+
16
+
17
+ def verify(root: Path) -> dict:
18
+ annex = load_annex_c(root / "data/world_cup_2026/annex_c_third_place.json")
19
+ third_slots = {
20
+ slot.match: slot.second_groups
21
+ for slot in ROUND_OF_32_SLOTS
22
+ if slot.second_kind == "third"
23
+ }
24
+ failures = []
25
+ checked = 0
26
+ for groups in combinations("ABCDEFGHIJKL", 8):
27
+ assignment = assign_third_place_groups(groups, annex)
28
+ if set(assignment) != set(third_slots):
29
+ failures.append({"groups": "".join(groups), "reason": "slot mismatch"})
30
+ elif set(assignment.values()) != set(groups):
31
+ failures.append({"groups": "".join(groups), "reason": "group mismatch"})
32
+ elif any(
33
+ group not in third_slots[match]
34
+ for match, group in assignment.items()
35
+ ):
36
+ failures.append({"groups": "".join(groups), "reason": "illegal opponent"})
37
+ checked += 1
38
+
39
+ downstream_matches = [
40
+ match
41
+ for matches in KNOCKOUT_PATH.values()
42
+ for match, _, _ in matches
43
+ ] + [THIRD_PLACE_MATCH[0]]
44
+ report = {
45
+ "status": "verified" if not failures and checked == 495 else "failed",
46
+ "release_blocking": bool(failures) or checked != 495,
47
+ "round_of_32_slots": len(ROUND_OF_32_SLOTS),
48
+ "annex_c_combinations": checked,
49
+ "annex_c_failures": failures,
50
+ "downstream_matches_verified": downstream_matches,
51
+ "sources": [
52
+ "https://www.fifa.com/en/tournaments/mens/worldcup/canadamexicousa2026/articles/fifa-world-cup-2026-match-schedule-fixtures-results-teams-stadiums",
53
+ "https://en.wikipedia.org/wiki/2026_FIFA_World_Cup_knockout_stage",
54
+ ],
55
+ "scope": (
56
+ "Published matches 73-104, including the third-place match, and "
57
+ "all 495 Annex C third-place "
58
+ "assignments. Fair-play data is not available in the snapshot."
59
+ ),
60
+ }
61
+ return report
62
+
63
+
64
+ def main() -> int:
65
+ parser = argparse.ArgumentParser()
66
+ parser.add_argument("--root", type=Path, default=Path("."))
67
+ parser.add_argument(
68
+ "--output",
69
+ type=Path,
70
+ default=Path("results/bracket_verification.json"),
71
+ )
72
+ args = parser.parse_args()
73
+ report = verify(args.root.resolve())
74
+ args.output.resolve().write_text(
75
+ json.dumps(report, indent=2, sort_keys=True) + "\n",
76
+ encoding="utf-8",
77
+ )
78
+ print(
79
+ f"Bracket verification: {report['status']} "
80
+ f"({report['annex_c_combinations']} Annex C combinations)"
81
+ )
82
+ return 0 if report["status"] == "verified" else 1
83
+
84
+
85
+ if __name__ == "__main__":
86
+ raise SystemExit(main())
src/underdog_lab/release/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ """Release gates and submission preflight helpers."""
src/underdog_lab/release/preflight.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from collections import Counter
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+
9
+ def _load(path: Path) -> dict[str, Any]:
10
+ return json.loads(path.read_text(encoding="utf-8"))
11
+
12
+
13
+ def evaluate_preflight(root: Path, config: dict[str, Any]) -> dict[str, Any]:
14
+ teams = _load(root / "data/world_cup_2026/teams.json")
15
+ group_sizes = Counter(team["group"] for team in teams)
16
+ fixture_count = sum(size * (size - 1) // 2 for size in group_sizes.values())
17
+ qlora = _load(root / "results/qlora_gate_report.json")
18
+ bracket = _load(root / "results/bracket_verification.json")
19
+ backtest = _load(root / "models/backtest_report.json")
20
+ required_docs = (
21
+ "README.md",
22
+ "LICENSE",
23
+ "docs/field-notes.md",
24
+ "docs/demo-script.md",
25
+ "docs/social-post.md",
26
+ "data/scenarios/README.md",
27
+ )
28
+ checks = {
29
+ "space_url_declared": bool(config.get("space_url")),
30
+ "github_url_declared": bool(config.get("github_url")),
31
+ "world_cup_teams_48": len(teams) == 48,
32
+ "world_cup_group_fixtures_72": (
33
+ len(group_sizes) == 12
34
+ and set(group_sizes.values()) == {4}
35
+ and fixture_count == 72
36
+ ),
37
+ "qlora_gate_closed": (
38
+ qlora.get("status") == "closed"
39
+ and qlora.get("release_blocking") is False
40
+ ),
41
+ "official_bracket_verified": (
42
+ bracket.get("status") == "verified"
43
+ and bracket.get("annex_c_combinations") == 495
44
+ and bracket.get("release_blocking") is False
45
+ ),
46
+ "forecast_backtest_ship_gate": backtest["ship_gate"]["ship"] is True,
47
+ "parameter_limit": (
48
+ config["base_model_parameters"] <= config["parameter_limit"]
49
+ ),
50
+ "code_license_documented": (
51
+ config["licenses"].get("code") == "MIT"
52
+ and (root / "LICENSE").exists()
53
+ ),
54
+ "base_model_license_documented": (
55
+ config["licenses"].get("base_model") == "Apache-2.0"
56
+ ),
57
+ "adapter_url_declared": bool(config.get("adapter_url")),
58
+ "dataset_url_declared": bool(config.get("dataset_url")),
59
+ "release_docs_present": all(
60
+ (root / path).exists() and (root / path).stat().st_size > 0
61
+ for path in required_docs
62
+ ),
63
+ }
64
+ human_actions = config.get("human_actions", {})
65
+ pending_human_actions = [
66
+ key for key, value in human_actions.items() if not str(value).strip()
67
+ ]
68
+ failed_checks = [key for key, passed in checks.items() if not passed]
69
+ if failed_checks:
70
+ status = "BLOCKED"
71
+ elif pending_human_actions:
72
+ status = "READY_FOR_HUMAN_SUBMISSION"
73
+ else:
74
+ status = "READY_TO_SUBMIT"
75
+ return {
76
+ "status": status,
77
+ "machine_checks": checks,
78
+ "failed_machine_checks": failed_checks,
79
+ "pending_human_actions": pending_human_actions,
80
+ "urls": {
81
+ key: value
82
+ for key, value in config.items()
83
+ if key.endswith("_url")
84
+ },
85
+ "claim_boundaries": [
86
+ "QLoRA adapter evaluated NO-SHIP; no Well-Tuned performance claim.",
87
+ "Scenario labels remain synthetic and review-pending; extraction metrics are pipeline diagnostics.",
88
+ "Forecast accuracy evidence is the walk-forward Dixon-Coles backtest, not isolated match outcomes.",
89
+ ],
90
+ }
91
+
92
+
93
+ def run_preflight(root: Path, output_path: Path) -> dict[str, Any]:
94
+ config = _load(root / "release/submission.json")
95
+ report = evaluate_preflight(root, config)
96
+ output_path.write_text(
97
+ json.dumps(report, indent=2, sort_keys=True) + "\n",
98
+ encoding="utf-8",
99
+ )
100
+ return report
src/underdog_lab/release/qlora_gate.py ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class QLoRAGateThresholds:
12
+ minimum_f1_gain: float = 0.15
13
+ maximum_attribution_regression: float = 0.0
14
+ maximum_fallback_increase: float = 0.02
15
+ minimum_schema_validity: float = 0.99
16
+
17
+
18
+ def _load_json(path: Path) -> dict[str, Any]:
19
+ return json.loads(path.read_text(encoding="utf-8"))
20
+
21
+
22
+ def _sha256(path: Path) -> str:
23
+ digest = hashlib.sha256()
24
+ digest.update(path.read_bytes())
25
+ return digest.hexdigest()
26
+
27
+
28
+ def evaluate_qlora_gate(
29
+ base: dict[str, Any],
30
+ tuned: dict[str, Any],
31
+ declared: dict[str, Any],
32
+ thresholds: QLoRAGateThresholds | None = None,
33
+ ) -> dict[str, Any]:
34
+ thresholds = thresholds or QLoRAGateThresholds()
35
+ deltas = {
36
+ "factor_micro_f1": tuned["factor_micro_f1"] - base["factor_micro_f1"],
37
+ "team_attribution_accuracy": (
38
+ tuned["team_attribution_accuracy"] - base["team_attribution_accuracy"]
39
+ ),
40
+ "fallback_rate": tuned["fallback_rate"] - base["fallback_rate"],
41
+ "median_latency_ms": (
42
+ tuned["median_latency_ms"] - base["median_latency_ms"]
43
+ ),
44
+ }
45
+ checks = {
46
+ "minimum_f1_gain": (
47
+ deltas["factor_micro_f1"] >= thresholds.minimum_f1_gain
48
+ ),
49
+ "no_attribution_regression": (
50
+ deltas["team_attribution_accuracy"]
51
+ >= -thresholds.maximum_attribution_regression
52
+ ),
53
+ "fallback_rate_controlled": (
54
+ deltas["fallback_rate"] <= thresholds.maximum_fallback_increase
55
+ ),
56
+ "schema_validity": (
57
+ tuned["schema_validity_rate"] >= thresholds.minimum_schema_validity
58
+ ),
59
+ }
60
+ computed_decision = "SHIP" if all(checks.values()) else "NO-SHIP"
61
+ declared_decision = declared.get("ship_decision")
62
+ reasons = [name for name, passed in checks.items() if not passed]
63
+ return {
64
+ "status": "closed" if declared_decision == computed_decision else "invalid",
65
+ "computed_decision": computed_decision,
66
+ "declared_decision": declared_decision,
67
+ "release_blocking": declared_decision != computed_decision,
68
+ "selected_runtime": (
69
+ "tuned_adapter" if computed_decision == "SHIP" else "base_plus_fallback"
70
+ ),
71
+ "thresholds": {
72
+ "minimum_f1_gain": thresholds.minimum_f1_gain,
73
+ "maximum_attribution_regression": (
74
+ thresholds.maximum_attribution_regression
75
+ ),
76
+ "maximum_fallback_increase": thresholds.maximum_fallback_increase,
77
+ "minimum_schema_validity": thresholds.minimum_schema_validity,
78
+ },
79
+ "metrics": {
80
+ "base": {
81
+ key: base[key]
82
+ for key in (
83
+ "factor_micro_f1",
84
+ "team_attribution_accuracy",
85
+ "fallback_rate",
86
+ "schema_validity_rate",
87
+ "median_latency_ms",
88
+ )
89
+ },
90
+ "tuned": {
91
+ key: tuned[key]
92
+ for key in (
93
+ "factor_micro_f1",
94
+ "team_attribution_accuracy",
95
+ "fallback_rate",
96
+ "schema_validity_rate",
97
+ "median_latency_ms",
98
+ )
99
+ },
100
+ "deltas": deltas,
101
+ },
102
+ "checks": checks,
103
+ "failed_checks": reasons,
104
+ "claim": (
105
+ "The adapter is not shipped. The base model plus deterministic "
106
+ "fallback remains the production extraction path."
107
+ ),
108
+ }
109
+
110
+
111
+ def close_qlora_gate(
112
+ root: Path,
113
+ output_path: Path | None = None,
114
+ ) -> dict[str, Any]:
115
+ base_path = root / "results/base_q8.json"
116
+ tuned_path = root / "results/tuned_q8.json"
117
+ decision_path = root / "results/ship_decision.json"
118
+ paths = (base_path, tuned_path, decision_path)
119
+ report = evaluate_qlora_gate(
120
+ _load_json(base_path),
121
+ _load_json(tuned_path),
122
+ _load_json(decision_path),
123
+ )
124
+ report["artifacts"] = {
125
+ str(path.relative_to(root)): {"sha256": _sha256(path)}
126
+ for path in paths
127
+ }
128
+ report["adapter"] = _load_json(decision_path).get("tuned_model", {})
129
+ destination = output_path or root / "results/qlora_gate_report.json"
130
+ destination.write_text(
131
+ json.dumps(report, indent=2, sort_keys=True) + "\n",
132
+ encoding="utf-8",
133
+ )
134
+ return report
src/underdog_lab/world_cup/bracket.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from dataclasses import dataclass
5
+ from pathlib import Path
6
+ from typing import Mapping, Sequence
7
+
8
+ from underdog_lab.config import DATA_DIR
9
+ from underdog_lab.world_cup.models import Standing
10
+
11
+
12
+ @dataclass(frozen=True)
13
+ class RoundOf32Slot:
14
+ match: int
15
+ first_kind: str
16
+ first_group: str
17
+ second_kind: str
18
+ second_groups: frozenset[str]
19
+
20
+
21
+ ROUND_OF_32_SLOTS = (
22
+ RoundOf32Slot(73, "runner_up", "A", "runner_up", frozenset("B")),
23
+ RoundOf32Slot(74, "winner", "E", "third", frozenset("ABCDF")),
24
+ RoundOf32Slot(75, "winner", "F", "runner_up", frozenset("C")),
25
+ RoundOf32Slot(76, "winner", "C", "runner_up", frozenset("F")),
26
+ RoundOf32Slot(77, "winner", "I", "third", frozenset("CDFGH")),
27
+ RoundOf32Slot(78, "runner_up", "E", "runner_up", frozenset("I")),
28
+ RoundOf32Slot(79, "winner", "A", "third", frozenset("CEHFI")),
29
+ RoundOf32Slot(80, "winner", "L", "third", frozenset("EHIJK")),
30
+ RoundOf32Slot(81, "winner", "D", "third", frozenset("BEFIJ")),
31
+ RoundOf32Slot(82, "winner", "G", "third", frozenset("AEHIJ")),
32
+ RoundOf32Slot(83, "runner_up", "K", "runner_up", frozenset("L")),
33
+ RoundOf32Slot(84, "winner", "H", "runner_up", frozenset("J")),
34
+ RoundOf32Slot(85, "winner", "B", "third", frozenset("EFGIJ")),
35
+ RoundOf32Slot(86, "winner", "J", "runner_up", frozenset("H")),
36
+ RoundOf32Slot(87, "winner", "K", "third", frozenset("DEIJL")),
37
+ RoundOf32Slot(88, "runner_up", "D", "runner_up", frozenset("G")),
38
+ )
39
+
40
+ KNOCKOUT_PATH = {
41
+ "round_of_16": (
42
+ (89, 73, 75),
43
+ (90, 74, 77),
44
+ (91, 76, 78),
45
+ (92, 79, 80),
46
+ (93, 83, 84),
47
+ (94, 81, 82),
48
+ (95, 86, 88),
49
+ (96, 85, 87),
50
+ ),
51
+ "quarterfinal": (
52
+ (97, 89, 90),
53
+ (98, 93, 94),
54
+ (99, 91, 92),
55
+ (100, 95, 96),
56
+ ),
57
+ "semifinal": ((101, 97, 98), (102, 99, 100)),
58
+ "champion": ((104, 101, 102),),
59
+ }
60
+
61
+ THIRD_PLACE_MATCH = (103, 101, 102)
62
+
63
+
64
+ def load_annex_c(path: Path | None = None) -> dict[str, dict[str, str]]:
65
+ path = path or DATA_DIR / "world_cup_2026/annex_c_third_place.json"
66
+ return json.loads(path.read_text(encoding="utf-8"))["combinations"]
67
+
68
+
69
+ def assign_third_place_groups(
70
+ qualified_groups: Sequence[str],
71
+ annex_c: Mapping[str, Mapping[str, str]] | None = None,
72
+ ) -> dict[int, str]:
73
+ groups = frozenset(qualified_groups)
74
+ if len(groups) != 8 or not groups <= frozenset("ABCDEFGHIJKL"):
75
+ raise ValueError("Exactly eight distinct groups A-L must qualify in third place")
76
+ key = "".join(sorted(groups))
77
+ official = (annex_c or load_annex_c()).get(key)
78
+ if official is None:
79
+ raise ValueError(f"Annex C has no assignment for third-place groups {key}")
80
+ return {int(match): group for match, group in official.items()}
81
+
82
+
83
+ def build_round_of_32(
84
+ ranked_groups: Mapping[str, Sequence[Standing]],
85
+ best_thirds: Sequence[Standing],
86
+ group_by_team: Mapping[str, str],
87
+ ) -> list[tuple[int, str, str]]:
88
+ third_by_group = {group_by_team[row.team]: row.team for row in best_thirds}
89
+ assignment = assign_third_place_groups(sorted(third_by_group))
90
+ matches = []
91
+ for slot in ROUND_OF_32_SLOTS:
92
+ first_index = 0 if slot.first_kind == "winner" else 1
93
+ first = ranked_groups[slot.first_group][first_index].team
94
+ if slot.second_kind == "third":
95
+ second = third_by_group[assignment[slot.match]]
96
+ else:
97
+ second_group = next(iter(slot.second_groups))
98
+ second = ranked_groups[second_group][1].team
99
+ matches.append((slot.match, first, second))
100
+ return matches
src/underdog_lab/world_cup/simulation.py CHANGED
@@ -6,9 +6,11 @@ from collections import Counter, defaultdict
6
  from datetime import date
7
 
8
  from underdog_lab.forecasting.poisson import poisson_probability
 
9
  from underdog_lab.world_cup.data import TournamentRepository
10
  from underdog_lab.world_cup.forecasting import match_forecast
11
  from underdog_lab.world_cup.models import Standing, TournamentFixture
 
12
 
13
 
14
  def _sample_goals(rate: float, rng: random.Random) -> int:
@@ -21,13 +23,6 @@ def _sample_goals(rate: float, rng: random.Random) -> int:
21
  return 8
22
 
23
 
24
- def _rank(table: dict[str, Standing]) -> list[Standing]:
25
- return sorted(
26
- table.values(),
27
- key=lambda row: (-row.points, -row.goal_difference, -row.goals_for, row.team),
28
- )
29
-
30
-
31
  def _apply_result(table, home, away, home_goals, away_goals):
32
  h, a = table[home], table[away]
33
  h.played += 1
@@ -51,23 +46,6 @@ def _apply_result(table, home, away, home_goals, away_goals):
51
  a.points += 1
52
 
53
 
54
- def _draw_round_of_32(
55
- qualifiers: list[str],
56
- group_by_team: dict[str, str],
57
- rng: random.Random,
58
- ) -> list[str]:
59
- candidate = qualifiers[:]
60
- for _ in range(200):
61
- rng.shuffle(candidate)
62
- if all(
63
- group_by_team[candidate[index]]
64
- != group_by_team[candidate[index + 1]]
65
- for index in range(0, len(candidate), 2)
66
- ):
67
- return candidate
68
- return candidate
69
-
70
-
71
  def _knockout_win_probability(
72
  first: str,
73
  second: str,
@@ -100,6 +78,7 @@ def simulate_tournament(
100
  counts = defaultdict(Counter)
101
  groups = sorted({team.group for team in repository.teams})
102
  group_by_team = {team.team: team.group for team in repository.teams}
 
103
 
104
  for _ in range(iterations):
105
  ranked_groups = {}
@@ -107,6 +86,7 @@ def simulate_tournament(
107
  for group in groups:
108
  teams = [team.team for team in repository.group_teams(group)]
109
  table = {team: Standing(team=team) for team in teams}
 
110
  for fixture in repository.group_fixtures(group):
111
  if fixture.played:
112
  home_goals = fixture.home_goals or 0
@@ -122,7 +102,10 @@ def simulate_tournament(
122
  home_goals,
123
  away_goals,
124
  )
125
- ranked = _rank(table)
 
 
 
126
  ranked_groups[group] = ranked
127
  counts[ranked[0].team]["group_winner"] += 1
128
  counts[ranked[0].team]["advance"] += 1
@@ -131,37 +114,50 @@ def simulate_tournament(
131
 
132
  best_thirds = sorted(
133
  thirds,
134
- key=lambda row: (-row.points, -row.goal_difference, -row.goals_for, row.team),
 
 
 
 
 
 
135
  )[:8]
136
  for row in best_thirds:
137
  counts[row.team]["advance"] += 1
138
 
139
- qualifiers = [
140
- ranked_groups[group][0].team for group in groups
141
- ] + [
142
- ranked_groups[group][1].team for group in groups
143
- ] + [row.team for row in best_thirds]
144
- round_teams = _draw_round_of_32(qualifiers, group_by_team, rng)
145
- round_names = [
146
- "round_of_16",
147
- "quarterfinal",
148
- "semifinal",
149
- "final",
150
- "champion",
151
- ]
152
- for round_name in round_names:
153
- winners = []
154
- for index in range(0, len(round_teams), 2):
155
- first, second = round_teams[index], round_teams[index + 1]
 
 
156
  probability_first = _knockout_win_probability(
157
  first,
158
  second,
159
  repository,
160
  )
161
  winner = first if rng.random() < probability_first else second
162
- counts[winner][round_name] += 1
163
- winners.append(winner)
164
- round_teams = winners
 
 
 
 
 
165
 
166
  return {
167
  team.team: {
 
6
  from datetime import date
7
 
8
  from underdog_lab.forecasting.poisson import poisson_probability
9
+ from underdog_lab.world_cup.bracket import KNOCKOUT_PATH, build_round_of_32
10
  from underdog_lab.world_cup.data import TournamentRepository
11
  from underdog_lab.world_cup.forecasting import match_forecast
12
  from underdog_lab.world_cup.models import Standing, TournamentFixture
13
+ from underdog_lab.world_cup.standings import rank_standings
14
 
15
 
16
  def _sample_goals(rate: float, rng: random.Random) -> int:
 
23
  return 8
24
 
25
 
 
 
 
 
 
 
 
26
  def _apply_result(table, home, away, home_goals, away_goals):
27
  h, a = table[home], table[away]
28
  h.played += 1
 
46
  a.points += 1
47
 
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  def _knockout_win_probability(
50
  first: str,
51
  second: str,
 
78
  counts = defaultdict(Counter)
79
  groups = sorted({team.group for team in repository.teams})
80
  group_by_team = {team.team: team.group for team in repository.teams}
81
+ fifa_ranks = {team.team: team.rank for team in repository.teams}
82
 
83
  for _ in range(iterations):
84
  ranked_groups = {}
 
86
  for group in groups:
87
  teams = [team.team for team in repository.group_teams(group)]
88
  table = {team: Standing(team=team) for team in teams}
89
+ results = []
90
  for fixture in repository.group_fixtures(group):
91
  if fixture.played:
92
  home_goals = fixture.home_goals or 0
 
102
  home_goals,
103
  away_goals,
104
  )
105
+ results.append(
106
+ (fixture.home, fixture.away, home_goals, away_goals)
107
+ )
108
+ ranked = rank_standings(table, results, fifa_ranks=fifa_ranks)
109
  ranked_groups[group] = ranked
110
  counts[ranked[0].team]["group_winner"] += 1
111
  counts[ranked[0].team]["advance"] += 1
 
114
 
115
  best_thirds = sorted(
116
  thirds,
117
+ key=lambda row: (
118
+ -row.points,
119
+ -row.goal_difference,
120
+ -row.goals_for,
121
+ fifa_ranks.get(row.team, 10_000),
122
+ row.team,
123
+ ),
124
  )[:8]
125
  for row in best_thirds:
126
  counts[row.team]["advance"] += 1
127
 
128
+ winners_by_match = {}
129
+ for match, first, second in build_round_of_32(
130
+ ranked_groups,
131
+ best_thirds,
132
+ group_by_team,
133
+ ):
134
+ probability_first = _knockout_win_probability(
135
+ first,
136
+ second,
137
+ repository,
138
+ )
139
+ winner = first if rng.random() < probability_first else second
140
+ winners_by_match[match] = winner
141
+ counts[winner]["round_of_16"] += 1
142
+
143
+ for round_name, matches in KNOCKOUT_PATH.items():
144
+ for match, first_match, second_match in matches:
145
+ first = winners_by_match[first_match]
146
+ second = winners_by_match[second_match]
147
  probability_first = _knockout_win_probability(
148
  first,
149
  second,
150
  repository,
151
  )
152
  winner = first if rng.random() < probability_first else second
153
+ winners_by_match[match] = winner
154
+ advancement = {
155
+ "round_of_16": "quarterfinal",
156
+ "quarterfinal": "semifinal",
157
+ "semifinal": "final",
158
+ "champion": "champion",
159
+ }[round_name]
160
+ counts[winner][advancement] += 1
161
 
162
  return {
163
  team.team: {
src/underdog_lab/world_cup/standings.py CHANGED
@@ -1,16 +1,89 @@
1
  from __future__ import annotations
2
 
 
 
 
3
  from underdog_lab.world_cup.models import Standing, TournamentFixture
4
 
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  def calculate_standings(
7
  teams: list[str],
8
  fixtures: list[TournamentFixture],
 
9
  ) -> list[Standing]:
10
  table = {team: Standing(team=team) for team in teams}
 
11
  for fixture in fixtures:
12
  if not fixture.played:
13
  continue
 
 
 
 
 
 
 
 
14
  home = table[fixture.home]
15
  away = table[fixture.away]
16
  home.played += 1
@@ -32,8 +105,4 @@ def calculate_standings(
32
  away.draws += 1
33
  home.points += 1
34
  away.points += 1
35
- return sorted(
36
- table.values(),
37
- key=lambda row: (-row.points, -row.goal_difference, -row.goals_for, row.team),
38
- )
39
-
 
1
  from __future__ import annotations
2
 
3
+ from collections import defaultdict
4
+ from collections.abc import Mapping, Sequence
5
+
6
  from underdog_lab.world_cup.models import Standing, TournamentFixture
7
 
8
 
9
+ Result = tuple[str, str, int, int]
10
+
11
+
12
+ def _head_to_head_key(team: str, tied: set[str], results: Sequence[Result]):
13
+ points = goals_for = goals_against = 0
14
+ for home, away, home_goals, away_goals in results:
15
+ if home not in tied or away not in tied:
16
+ continue
17
+ if team == home:
18
+ goals_for += home_goals
19
+ goals_against += away_goals
20
+ points += 3 if home_goals > away_goals else 1 if home_goals == away_goals else 0
21
+ elif team == away:
22
+ goals_for += away_goals
23
+ goals_against += home_goals
24
+ points += 3 if away_goals > home_goals else 1 if away_goals == home_goals else 0
25
+ return points, goals_for - goals_against, goals_for
26
+
27
+
28
+ def rank_standings(
29
+ table: Mapping[str, Standing],
30
+ results: Sequence[Result],
31
+ fifa_ranks: Mapping[str, int] | None = None,
32
+ fair_play_points: Mapping[str, int] | None = None,
33
+ ) -> list[Standing]:
34
+ fifa_ranks = fifa_ranks or {}
35
+ fair_play_points = fair_play_points or {}
36
+ by_points: dict[int, list[Standing]] = defaultdict(list)
37
+ for row in table.values():
38
+ by_points[row.points].append(row)
39
+
40
+ def resolve_equal_points(rows: list[Standing]) -> list[Standing]:
41
+ if len(rows) < 2:
42
+ return rows
43
+ tied = {row.team for row in rows}
44
+ by_head_to_head: dict[tuple[int, int, int], list[Standing]] = defaultdict(list)
45
+ for row in rows:
46
+ by_head_to_head[_head_to_head_key(row.team, tied, results)].append(row)
47
+ if len(by_head_to_head) > 1:
48
+ resolved = []
49
+ for key in sorted(by_head_to_head, reverse=True):
50
+ resolved.extend(resolve_equal_points(by_head_to_head[key]))
51
+ return resolved
52
+ return sorted(
53
+ rows,
54
+ key=lambda row: (
55
+ -row.goal_difference,
56
+ -row.goals_for,
57
+ fair_play_points.get(row.team, 0),
58
+ fifa_ranks.get(row.team, 10_000),
59
+ row.team,
60
+ ),
61
+ )
62
+
63
+ ranked = []
64
+ for points in sorted(by_points, reverse=True):
65
+ ranked.extend(resolve_equal_points(by_points[points]))
66
+ return ranked
67
+
68
+
69
  def calculate_standings(
70
  teams: list[str],
71
  fixtures: list[TournamentFixture],
72
+ fifa_ranks: Mapping[str, int] | None = None,
73
  ) -> list[Standing]:
74
  table = {team: Standing(team=team) for team in teams}
75
+ results = []
76
  for fixture in fixtures:
77
  if not fixture.played:
78
  continue
79
+ results.append(
80
+ (
81
+ fixture.home,
82
+ fixture.away,
83
+ fixture.home_goals or 0,
84
+ fixture.away_goals or 0,
85
+ )
86
+ )
87
  home = table[fixture.home]
88
  away = table[fixture.away]
89
  home.played += 1
 
105
  away.draws += 1
106
  home.points += 1
107
  away.points += 1
108
+ return rank_standings(table, results, fifa_ranks=fifa_ranks)
 
 
 
 
src/underdog_lab/world_cup/ui.py CHANGED
@@ -228,7 +228,13 @@ def snapshot_html(repository: TournamentRepository) -> str:
228
  def group_html(repository: TournamentRepository, group: str) -> str:
229
  teams = [team.team for team in repository.group_teams(group)]
230
  fixtures = repository.group_fixtures(group)
231
- standings = calculate_standings(teams, fixtures)
 
 
 
 
 
 
232
  standing_rows = "".join(
233
  f"""
234
  <tr>
@@ -375,9 +381,9 @@ def tournament_probabilities_html(
375
  <h2>Who wins the 2026 World Cup?</h2>
376
  <p class="context">3,000 simulations condition on recorded results and
377
  current World Football Elo ratings.
378
- Group qualification follows the 12-group format. The knockout draw is
379
- a constrained bracket approximation that prevents immediate same-group
380
- rematches. Knockout games use Poisson regulation probabilities with a
381
  compressed extra-time and penalty edge, so these remain research
382
  estimates rather than an official bracket calculator.</p>
383
  <div class="table-scroll probability-table">
 
228
  def group_html(repository: TournamentRepository, group: str) -> str:
229
  teams = [team.team for team in repository.group_teams(group)]
230
  fixtures = repository.group_fixtures(group)
231
+ standings = calculate_standings(
232
+ teams,
233
+ fixtures,
234
+ fifa_ranks={
235
+ team.team: team.rank for team in repository.group_teams(group)
236
+ },
237
+ )
238
  standing_rows = "".join(
239
  f"""
240
  <tr>
 
381
  <h2>Who wins the 2026 World Cup?</h2>
382
  <p class="context">3,000 simulations condition on recorded results and
383
  current World Football Elo ratings.
384
+ Group qualification follows the 12-group format and the published FIFA
385
+ Round-of-32 slots, including legal placement of the eight best
386
+ third-place teams. Knockout games use Poisson regulation probabilities with a
387
  compressed extra-time and penalty edge, so these remain research
388
  estimates rather than an official bracket calculator.</p>
389
  <div class="table-scroll probability-table">
tests/unit/test_qlora_gate.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from underdog_lab.release.qlora_gate import evaluate_qlora_gate
2
+
3
+
4
+ def _metrics(f1, attribution, fallback, schema=1.0, latency=1000):
5
+ return {
6
+ "factor_micro_f1": f1,
7
+ "team_attribution_accuracy": attribution,
8
+ "fallback_rate": fallback,
9
+ "schema_validity_rate": schema,
10
+ "median_latency_ms": latency,
11
+ }
12
+
13
+
14
+ def test_gate_closes_a_consistent_no_ship_decision():
15
+ report = evaluate_qlora_gate(
16
+ _metrics(0.03, 0.05, 0.09),
17
+ _metrics(0.04, 0.03, 0.17),
18
+ {"ship_decision": "NO-SHIP"},
19
+ )
20
+
21
+ assert report["status"] == "closed"
22
+ assert report["computed_decision"] == "NO-SHIP"
23
+ assert report["release_blocking"] is False
24
+ assert "minimum_f1_gain" in report["failed_checks"]
25
+ assert "no_attribution_regression" in report["failed_checks"]
26
+
27
+
28
+ def test_gate_rejects_a_declared_ship_that_misses_thresholds():
29
+ report = evaluate_qlora_gate(
30
+ _metrics(0.03, 0.05, 0.09),
31
+ _metrics(0.04, 0.03, 0.17),
32
+ {"ship_decision": "SHIP"},
33
+ )
34
+
35
+ assert report["status"] == "invalid"
36
+ assert report["release_blocking"] is True
37
+
38
+
39
+ def test_gate_allows_a_material_non_regressing_improvement():
40
+ report = evaluate_qlora_gate(
41
+ _metrics(0.20, 0.50, 0.10),
42
+ _metrics(0.36, 0.52, 0.11),
43
+ {"ship_decision": "SHIP"},
44
+ )
45
+
46
+ assert report["status"] == "closed"
47
+ assert report["computed_decision"] == "SHIP"
48
+ assert all(report["checks"].values())
tests/unit/test_submission_preflight.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
+ from underdog_lab.release.preflight import evaluate_preflight
4
+
5
+
6
+ def _write_json(path, value):
7
+ path.parent.mkdir(parents=True, exist_ok=True)
8
+ path.write_text(json.dumps(value), encoding="utf-8")
9
+
10
+
11
+ def _root(tmp_path):
12
+ _write_json(
13
+ tmp_path / "data/world_cup_2026/teams.json",
14
+ [{"group": group} for group in "ABCDEFGHIJKL" for _ in range(4)],
15
+ )
16
+ _write_json(
17
+ tmp_path / "results/qlora_gate_report.json",
18
+ {"status": "closed", "release_blocking": False},
19
+ )
20
+ _write_json(
21
+ tmp_path / "results/bracket_verification.json",
22
+ {
23
+ "status": "verified",
24
+ "annex_c_combinations": 495,
25
+ "release_blocking": False,
26
+ },
27
+ )
28
+ _write_json(
29
+ tmp_path / "models/backtest_report.json",
30
+ {"ship_gate": {"ship": True}},
31
+ )
32
+ for path in (
33
+ "README.md",
34
+ "LICENSE",
35
+ "docs/field-notes.md",
36
+ "docs/demo-script.md",
37
+ "docs/social-post.md",
38
+ "data/scenarios/README.md",
39
+ ):
40
+ destination = tmp_path / path
41
+ destination.parent.mkdir(parents=True, exist_ok=True)
42
+ destination.write_text("present", encoding="utf-8")
43
+ return tmp_path
44
+
45
+
46
+ def _config(human_value=""):
47
+ return {
48
+ "space_url": "https://example.com/space",
49
+ "github_url": "https://example.com/code",
50
+ "adapter_url": "https://example.com/adapter",
51
+ "dataset_url": "https://example.com/data",
52
+ "base_model_parameters": 360_000_000,
53
+ "parameter_limit": 32_000_000_000,
54
+ "licenses": {"code": "MIT", "base_model": "Apache-2.0"},
55
+ "human_actions": {"demo_video_url": human_value},
56
+ }
57
+
58
+
59
+ def test_preflight_separates_human_actions_from_machine_blockers(tmp_path):
60
+ report = evaluate_preflight(_root(tmp_path), _config())
61
+
62
+ assert report["status"] == "READY_FOR_HUMAN_SUBMISSION"
63
+ assert report["failed_machine_checks"] == []
64
+ assert report["pending_human_actions"] == ["demo_video_url"]
65
+
66
+
67
+ def test_preflight_is_ready_when_human_actions_are_recorded(tmp_path):
68
+ report = evaluate_preflight(
69
+ _root(tmp_path),
70
+ _config("https://example.com/demo"),
71
+ )
72
+
73
+ assert report["status"] == "READY_TO_SUBMIT"
tests/unit/test_world_cup_2026.py CHANGED
@@ -1,12 +1,21 @@
 
 
 
 
 
 
 
 
 
1
  from underdog_lab.world_cup.data import TournamentRepository
2
  from underdog_lab.world_cup.forecasting import match_forecast
3
  from underdog_lab.world_cup.simulation import (
4
- _draw_round_of_32,
5
  _knockout_win_probability,
6
  simulate_tournament,
7
  )
8
  from underdog_lab.world_cup.ui import upcoming_html
9
- from underdog_lab.world_cup.standings import calculate_standings
 
10
 
11
 
12
  def test_repository_contains_full_group_stage():
@@ -37,6 +46,21 @@ def test_snapshot_results_update_group_a_table():
37
  assert standings[1].points == 3
38
 
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  def test_match_forecast_is_normalized():
41
  repository = TournamentRepository()
42
  forecast = match_forecast(repository.fixtures[0], repository.team_by_name)
@@ -87,15 +111,60 @@ def test_knockout_probability_is_compressed_and_symmetric():
87
  assert abs(spain + south_africa - 1.0) < 1e-8
88
 
89
 
90
- def test_round_of_32_draw_avoids_same_group_rematches():
91
- import random
92
-
93
  repository = TournamentRepository()
94
- qualifiers = [team.team for team in repository.teams[:32]]
95
  groups = {team.team: team.group for team in repository.teams}
96
- draw = _draw_round_of_32(qualifiers, groups, random.Random(4))
97
-
98
- assert all(
99
- groups[draw[index]] != groups[draw[index + 1]]
100
- for index in range(0, len(draw), 2)
101
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from itertools import combinations
2
+
3
+ from underdog_lab.world_cup.bracket import (
4
+ KNOCKOUT_PATH,
5
+ ROUND_OF_32_SLOTS,
6
+ THIRD_PLACE_MATCH,
7
+ assign_third_place_groups,
8
+ build_round_of_32,
9
+ )
10
  from underdog_lab.world_cup.data import TournamentRepository
11
  from underdog_lab.world_cup.forecasting import match_forecast
12
  from underdog_lab.world_cup.simulation import (
 
13
  _knockout_win_probability,
14
  simulate_tournament,
15
  )
16
  from underdog_lab.world_cup.ui import upcoming_html
17
+ from underdog_lab.world_cup.models import Standing
18
+ from underdog_lab.world_cup.standings import calculate_standings, rank_standings
19
 
20
 
21
  def test_repository_contains_full_group_stage():
 
46
  assert standings[1].points == 3
47
 
48
 
49
+ def test_head_to_head_breaks_equal_points_before_overall_goal_difference():
50
+ table = {
51
+ "Alpha": Standing(team="Alpha", points=6, goals_for=10, goals_against=1),
52
+ "Beta": Standing(team="Beta", points=6, goals_for=3, goals_against=2),
53
+ }
54
+
55
+ ranked = rank_standings(
56
+ table,
57
+ [("Beta", "Alpha", 1, 0)],
58
+ fifa_ranks={"Alpha": 1, "Beta": 20},
59
+ )
60
+
61
+ assert [row.team for row in ranked] == ["Beta", "Alpha"]
62
+
63
+
64
  def test_match_forecast_is_normalized():
65
  repository = TournamentRepository()
66
  forecast = match_forecast(repository.fixtures[0], repository.team_by_name)
 
111
  assert abs(spain + south_africa - 1.0) < 1e-8
112
 
113
 
114
+ def test_round_of_32_uses_published_slots_without_same_group_rematches():
 
 
115
  repository = TournamentRepository()
 
116
  groups = {team.team: team.group for team in repository.teams}
117
+ ranked = {
118
+ group: [
119
+ type("Row", (), {"team": team.team})()
120
+ for team in repository.group_teams(group)
121
+ ]
122
+ for group in "ABCDEFGHIJKL"
123
+ }
124
+ best_thirds = [ranked[group][2] for group in "ABCDEFGH"]
125
+ matches = build_round_of_32(ranked, best_thirds, groups)
126
+
127
+ assert [match for match, _, _ in matches] == list(range(73, 89))
128
+ assert all(groups[first] != groups[second] for _, first, second in matches)
129
+ assert len({team for _, first, second in matches for team in (first, second)}) == 32
130
+
131
+
132
+ def test_all_495_third_place_combinations_have_a_legal_assignment():
133
+ third_slots = {
134
+ slot.match: slot.second_groups
135
+ for slot in ROUND_OF_32_SLOTS
136
+ if slot.second_kind == "third"
137
+ }
138
+ checked = 0
139
+ for groups in combinations("ABCDEFGHIJKL", 8):
140
+ assignment = assign_third_place_groups(groups)
141
+ assert set(assignment.values()) == set(groups)
142
+ assert all(group in third_slots[match] for match, group in assignment.items())
143
+ checked += 1
144
+ assert checked == 495
145
+
146
+
147
+ def test_annex_c_reference_mapping_matches_the_published_first_row():
148
+ assert assign_third_place_groups("EFGHIJKL") == {
149
+ 74: "F",
150
+ 77: "G",
151
+ 79: "E",
152
+ 80: "K",
153
+ 81: "I",
154
+ 82: "H",
155
+ 85: "J",
156
+ 87: "L",
157
+ }
158
+
159
+
160
+ def test_knockout_path_contains_every_match_after_round_of_32():
161
+ matches = {
162
+ match
163
+ for round_matches in KNOCKOUT_PATH.values()
164
+ for match, _, _ in round_matches
165
+ }
166
+
167
+ assert matches | {THIRD_PLACE_MATCH[0]} == set(range(89, 105))
168
+ assert KNOCKOUT_PATH["round_of_16"][0] == (89, 73, 75)
169
+ assert THIRD_PLACE_MATCH == (103, 101, 102)
170
+ assert KNOCKOUT_PATH["champion"] == ((104, 101, 102),)