diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc9cd420..d6aab5f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -190,27 +190,39 @@ jobs: assert policyengine_chronicle.__name__ == "policyengine_chronicle" # Every consumer-fact contract must ship inside the wheel: frozen v1, - # the v2 labels contract, the v3 geography-name contract, and the v4 - # contract rows are emitted under. + # the v2 labels contract, the v3 geography-name contract, the v4 + # geography-register contract, and the v5 contract rows are emitted + # under. assert ( consumer_fact_schema("ledger.consumer_fact.v1")["title"] == "Ledger consumer fact contract row" ) assert consumer_fact_schema()["title"] == "Chronicle consumer fact contract row" assert consumer_fact_schema()["properties"]["schema_version"] == { - "const": "chronicle.consumer_fact.v4" + "const": "chronicle.consumer_fact.v5" } assert set(CONSUMER_FACT_SCHEMA_SHA256_BY_VERSION) == { "ledger.consumer_fact.v1", "chronicle.consumer_fact.v2", "chronicle.consumer_fact.v3", "chronicle.consumer_fact.v4", + "chronicle.consumer_fact.v5", } # v4 rows take their UK area names from the register, which the # export reads from package data, so the wheel must carry it. from chronicle.geography_names import canonical_geography_name assert canonical_geography_name("E06000001") == "Hartlepool" + # v5 rows take shared dimension value labels from the register, which + # facts read from package data at build time. + from chronicle.dimension_labels import canonical_value_label + + assert ( + canonical_value_label( + "us:statutes/26/62#adjusted_gross_income", "under_1" + ) + == "No adjusted gross income" + ) assert len(CONSUMER_FACT_SCHEMA_SHA256) == 64 PY /tmp/chronicle-wheel-smoke/bin/chronicle --help >/dev/null diff --git a/README.md b/README.md index b46c9ce1..14904016 100644 --- a/README.md +++ b/README.md @@ -289,9 +289,17 @@ carry canonical constraints explicitly in `universe_constraints`; source-layout `dimensions` are metadata and are not target constraints. Rows also carry Chronicle-owned labels for every dimension and dimension value (`dimension_labels`, `dimension_value_labels`, `layout.groupby_dimension_label`; -chronicle#261), which Microcosm's calibration hierarchy displays. Every UK -package must label all of them, and `build-bundle` reports a gap as an error; -see `docs/agent-source-package-harness.md` for where labels come from. +chronicle#261), which Microcosm's calibration hierarchy displays. Every package +must label all of them, and `build-bundle` reports a gap as an error +(chronicle#265). One dimension value carries one label (chronicle#376): a value +two or more packages emit takes the label in +`chronicle/dimension_values/canonical_labels.json` at every build year, and the +package's own wording, where it differs, rides in +`package_dimension_value_labels` (the package's text, which is not checked +against the publisher's file and is often Chronicle's). A value labelled two ways is an error, never +a warning: `validate-package` and `build-suite` refuse one a package's rows label +two ways, and `build-bundle` also refuses one two packages label differently. +See `docs/agent-source-package-harness.md` for where labels come from. For the UK source-package feed, build the curated UK suite and then a facts-only consumer artifact: @@ -605,15 +613,19 @@ payload as its Ledger key; only the prefix differs. - **The row contract moves on its own.** Each contract in `CONSUMER_FACT_ROW_CONTRACTS` adds to the one before it, so a row restamped with a later id stays valid: `chronicle.consumer_fact.v2` (chronicle#261) is - the frozen v1 row plus optional dimension and value labels, and + the frozen v1 row plus optional dimension and value labels, `chronicle.consumer_fact.v3` (chronicle#266) is v2 plus the publisher's name - for the fact's geography. Rows are emitted as v3 with Ledger-named keys, and - each row validates against the schema of the contract it names. Only v1 and - v2 name a naming epoch: the epoch table renames identifiers, it does not - version the row. + for the fact's geography, `chronicle.consumer_fact.v4` (chronicle#281) is v3 + with one name per UK geography identifier and the publisher's text in an + optional `geography.publisher_name`, and `chronicle.consumer_fact.v5` + (chronicle#376) is v4 with one label per dimension value and the package's + own wording in an optional `package_dimension_value_labels`. Rows are + emitted as v5 with Ledger-named keys, and each row validates against the + schema of the contract it names. Only v1 and v2 name a naming epoch: the + epoch table renames identifiers, it does not version the row. - **Artifacts canonicalize on emit.** The consumer artifact pins the sha256 of - the v3 consumer-fact schema, so `build_consumer_artifact` rewrites every row - it read to Ledger-named keys and the v3 contract before writing it; an + the v5 consumer-fact schema, so `build_consumer_artifact` rewrites every row + it read to Ledger-named keys and the v5 contract before writing it; an artifact built from mixed-epoch rows is byte-identical to one built from the same rows written Ledger-named. Loads accept an artifact pinned to any packaged schema whose rows use that contract. Asking an artifact boundary to diff --git a/changelog.d/376.fixed.md b/changelog.d/376.fixed.md new file mode 100644 index 00000000..0935b9bd --- /dev/null +++ b/changelog.d/376.fixed.md @@ -0,0 +1 @@ +One dimension value now carries one label, whichever packages and build years a consumer combines. Every value that two or more packages emit, or that its packages word more than one way, has one label in Chronicle's register, `chronicle/dimension_values/canonical_labels.json` (4,824 values). Facts take that label in `dimension_value_labels` and `layout.groupby_value_label` when they are built, and keep the package's own wording, where it differs, in the new optional `package_dimension_value_labels`, which is the package's text (not checked against the publisher's file, and often Chronicle's own); rows are emitted as `chronicle.consumer_fact.v5`, v4 plus that field. The IRS filing-season week-47 rows for adjusted gross income `under_1` keep the IRS header "No adjusted gross income and deficit" as their label and in that field, and their facts carry "No adjusted gross income", as every other IRS SOI package does. A value labelled two ways is an error, never a warning: `validate-package` and `build-suite` refuse one that a package labels two ways, and `build-bundle` also refuses one that two packages label differently; the list of accepted label variants is gone. A package may not declare a label the register contradicts, and `scripts/build_dimension_value_register.py` regenerates the register, with a `--static-check` that compares it with the package files in CI. No fact key or value moves (chronicle#376). diff --git a/chronicle/bundle.py b/chronicle/bundle.py index 3adf78b5..a6da732d 100644 --- a/chronicle/bundle.py +++ b/chronicle/bundle.py @@ -9,7 +9,11 @@ from pathlib import Path from typing import Any, Callable, Sequence -from chronicle.dimension_labels import dimension_label_issues, dimension_labels_by_id +from chronicle.dimension_labels import ( + cross_package_value_label_remedy, + dimension_label_issues, + dimension_labels_by_id, +) from chronicle.epoch import canonicalize_key, schema_id from chronicle.source_package import ( ARTIFACT_YEAR_RESTAMP_CODE, @@ -852,8 +856,8 @@ def build_bundle( ).append(source) errors.extend(_cross_package_dimension_label_errors(dimension_labels)) + errors.extend(_cross_package_value_label_errors(value_labels)) warnings.extend(_cross_package_geography_name_warnings(geography_names)) - warnings.extend(_cross_package_value_label_warnings(value_labels)) aggregate_duplicates = _duplicate_key_reports( consumer_rows, "aggregate_fact_key", @@ -934,13 +938,15 @@ def _dimension_label_reports( source: str, rows: list[dict[str, Any]], ) -> tuple[list[BuildBundleIssue], list[BuildBundleIssue]]: - """Report one source's dimension-label issues (chronicle#261, #265). + """Report one source's dimension-label issues (chronicle#261, #265, #376). Every package must label every dimension and value it emits, whichever country it publishes for: the row contract is one contract, and a consumer - reads the labels the same way everywhere. The exception is publisher row - labels that differ across the rows of one groupby value: Chronicle keeps - that text as published and warns. + reads the labels the same way everywhere. A value one package labels two + ways, the package's row labels (its record-set rows' ``label:``) that + differ across one groupby value's rows included, is an error too: a + consumer would see one value under two names (chronicle#376). Nothing + about labels is only a warning. """ errors: list[BuildBundleIssue] = [] warnings: list[BuildBundleIssue] = [] @@ -955,10 +961,7 @@ def _dimension_label_reports( else f"{issue.dimension_id}={issue.value_id}" ), ) - if issue.code == "conflicting_groupby_value_label": - warnings.append(report) - else: - errors.append(report) + errors.append(report) return errors, warnings @@ -1073,16 +1076,21 @@ def _value_labels(rows: list[dict[str, Any]]) -> dict[tuple[str, str], set[str]] return found -def _cross_package_value_label_warnings( +def _cross_package_value_label_errors( labels_by_value: dict[tuple[str, str], dict[str, list[str]]], ) -> list[BuildBundleIssue]: - """Report a dimension value two packages label differently (chronicle#265). - - One label per dimension id is an error because a consumer selects on the - id; one label per value is a warning because the wording belongs to the - table the value was read from, and two tables of one publisher may word a - band or a total differently. A consumer target that spans both sees both, - so the bundle says where that is possible. + """Refuse a dimension value two packages label differently (chronicle#376). + + Microcosm copies each fact's labels into every target it compiles, so a + release built from both packages would label one value two ways, and a + consumer that groups targets by value cannot show it as one (the IRS + filing-season week-47 table labelled adjusted gross income ``under_1`` "No + adjusted gross income and deficit" where every other IRS SOI package writes + "No adjusted gross income"). Every fact takes the label Chronicle's + register gives a value it lists, so this finds values the register does not + list yet. There are no accepted exceptions: two packages emit the value, + so the one remedy is a register entry, and the message says how to choose + its label (or names the register's label, for rows built before it). """ return [ BuildBundleIssue( @@ -1094,7 +1102,7 @@ def _cross_package_value_label_warnings( f"{label!r} in {sorted(sources)}" for label, sources in sorted(labels.items()) ) - + "." + + f". {cross_package_value_label_remedy(dimension_id, value_id)}" ), key=f"{dimension_id}={value_id}", ) diff --git a/chronicle/consumer_contract.py b/chronicle/consumer_contract.py index 170a0b3b..78793194 100644 --- a/chronicle/consumer_contract.py +++ b/chronicle/consumer_contract.py @@ -689,6 +689,14 @@ def _consumer_fact_row( dimension_id: dict(value_labels) for dimension_id, value_labels in fact.dimension_value_labels.items() }, + # The package's own wording where Chronicle's register relabels a value + # (chronicle#376); display metadata, like the labels, never in a key. + "package_dimension_value_labels": { + dimension_id: dict(value_labels) + for dimension_id, value_labels in ( + fact.package_dimension_value_labels.items() + ) + }, "universe_constraints": _universe_constraint_set_payload(fact), "source": _clean(fact_to_mapping(fact)["source"]), "lineage": { diff --git a/chronicle/core.py b/chronicle/core.py index 8ab671f2..85b29018 100644 --- a/chronicle/core.py +++ b/chronicle/core.py @@ -290,6 +290,13 @@ class AggregateFact: # keyed by ``consumer_contract.dimension_value_id``. dimension_labels: dict[str, str] = field(default_factory=dict) dimension_value_labels: dict[str, dict[str, str]] = field(default_factory=dict) + # The package's own wording of a value, keyed like dimension_value_labels, + # where it differs from the label Chronicle's register gives the value + # (chronicle#376). Display metadata too, and not checked against the + # publisher's file: often it is text Chronicle wrote. + package_dimension_value_labels: dict[str, dict[str, str]] = field( + default_factory=dict + ) @dataclass(frozen=True) diff --git a/chronicle/database.py b/chronicle/database.py index 41d2dab5..a7325fac 100644 --- a/chronicle/database.py +++ b/chronicle/database.py @@ -1058,9 +1058,14 @@ def _build_id( def _canonical_fact_mapping(fact: AggregateFact) -> dict[str, Any]: """Return a build-hash payload independent of accepted key epochs.""" mapping = asdict(fact) - # Labels (chronicle#261) enter the hash only when present, so a fact - # without them keeps the build hash it had before they existed. - for label_field in ("dimension_labels", "dimension_value_labels"): + # Labels (chronicle#261) and the package's own value wording (chronicle#376) + # enter the hash only when present, so a fact without them keeps the build + # hash it had before they existed. + for label_field in ( + "dimension_labels", + "dimension_value_labels", + "package_dimension_value_labels", + ): if not mapping[label_field]: mapping.pop(label_field) if mapping["layout"] and mapping["layout"]["groupby_dimension_label"] is None: diff --git a/chronicle/dimension_labels.py b/chronicle/dimension_labels.py index f8713760..121bedd1 100644 --- a/chronicle/dimension_labels.py +++ b/chronicle/dimension_labels.py @@ -8,29 +8,53 @@ ``filters`` and, when it has one, its ``layout.groupby_dimension``, whose label is also stamped on ``layout.groupby_dimension_label``. -Labels resolve per package; the first source that has one wins. - -Dimension ids: +Dimension ids take the first label one of these gives: 1. the package's ``dimension_labels`` declaration; 2. the publisher's field label, for a Stat-Xplore field the parser read; 3. the label on the package's ``==`` constraints for that filter, when they agree on one label that is not the identifier itself. -Dimension values: - -1. the package's ``dimension_value_labels`` declaration; -2. the fact's publisher row label (``layout.groupby_value_label``) when the - dimension is the record set's groupby axis (the same id, or the same leaf - name source-filter canonicalization matches on) and the value is the row's - value id; -3. the publisher's text in the matching column of the fact's source row, when - the row-semantic acceptance matches the filter to it (for ``all``, the - publisher's aggregate item, such as Stat-Xplore's ``Total``); -4. a number or an ISO date, which labels itself. - -Everything else must be declared. :func:`dimension_label_issues` checks rows -the way Microcosm reads them and reports what is missing or labelled two ways. +One dimension value carries one label (chronicle#376). Microcosm merges facts +from packages built for different years into one feed, so the label cannot +depend on which packages one build happens to compare. A value takes the first +label one of these gives: + +1. Chronicle's register, :data:`REGISTER_PATH` + (``chronicle/dimension_values/canonical_labels.json``), which lists every + value that two or more packages emit, or that its packages word more than + one way, with one label; +2. the package's ``dimension_value_labels`` declaration; +3. the package's row label for the fact (``layout.groupby_value_label``, the + record-set row's ``label:``) when the dimension is the record set's groupby + axis (the same id, or the same leaf name source-filter canonicalization + matches on) and the value is the row's value id; +4. the text in the matching column of the fact's source row, as Chronicle's + parser read it (from the publisher's file or from an extract Chronicle + prepared), when the row-semantic acceptance matches the filter to it (for + ``all``, the source's aggregate item, such as Stat-Xplore's ``Total``); +5. a number or an ISO date, which labels itself. + +That label goes on ``dimension_value_labels`` and, for the groupby value, on +``layout.groupby_value_label``. The package's own wording of the value (its row +label, else its declaration, else its source-row text) is kept in +``package_dimension_value_labels`` where it differs. That wording is the +package's, and nothing checks it against the publisher's file: it is the +publisher's text only where a row guard happens to compare the same text with a +source cell (week 47's IRS column header), and elsewhere it is often text +Chronicle wrote (a parser's constant, a value id in an extract Chronicle +prepared, or a package author's phrase). The publisher's cells stay reachable +through each fact's lineage. + +A package may not declare a label the register contradicts: ``validate-package`` +refuses it (:func:`declared_value_label_issues`), so the register is the one +source of the label of every value it lists. A value the register does not list +is one that only one package emits (``scripts/build_dimension_value_register.py +--static-check`` checks this), so its package's label is its one label. +:func:`dimension_label_issues` reports such a value labelled two ways inside one +package, and ``build-bundle`` reports it labelled two ways by two packages; both +are errors, with no exceptions. Everything else that is unlabelled must be +declared. """ from __future__ import annotations @@ -41,6 +65,9 @@ from collections.abc import Iterable, Mapping from dataclasses import asdict, dataclass, replace from decimal import Decimal +from functools import cache +from pathlib import Path +from types import MappingProxyType from typing import Any from chronicle.consumer_contract import _concept_leaf @@ -50,6 +77,116 @@ _ISO_DATE = re.compile(r"\d{4}-\d{2}-\d{2}") +#: Chronicle's register of dimension value labels (chronicle#376). +REGISTER_PATH = Path(__file__).with_name("dimension_values") / "canonical_labels.json" +#: The register's path as error messages name it, relative to the repository. +REGISTER_DISPLAY_PATH = "chronicle/dimension_values/canonical_labels.json" +#: Where the rule for choosing a register label is written down. +LABEL_RULE_DISPLAY_PATH = "docs/agent-source-package-harness.md" +#: The script that regenerates the register, as error messages name it. +REGISTER_SCRIPT_DISPLAY_PATH = "scripts/build_dimension_value_register.py" +#: The command that compares the register with the package files. +REGISTER_STATIC_CHECK = f"uv run python {REGISTER_SCRIPT_DISPLAY_PATH} --static-check" + + +def _register_label_remedy(canonical: str) -> str: + return ( + f"Chronicle's register labels this value {canonical!r} " + f"({REGISTER_DISPLAY_PATH}), and every fact built at this Chronicle " + "version carries that label, so rebuild these facts (chronicle#376)." + ) + + +def in_package_value_label_remedy(dimension_id: str, value_id: str) -> str: + """Return the one remedy for a value one package labels two ways. + + A value the register lists already has its label, which the message names. + Any other value is one only this package emits, so the remedy is one + declaration in the package, never a register entry. + """ + + canonical = canonical_value_label(dimension_id, value_id) + if canonical is not None: + return _register_label_remedy(canonical) + return ( + "Declare one label for it in this package's dimension_value_labels " + "(chronicle#376): the publisher's wording of the value itself, without " + "words that name the measure, cell or table it was read from. Each " + "row's own wording is then kept in package_dimension_value_labels." + ) + + +def cross_package_value_label_remedy(dimension_id: str, value_id: str) -> str: + """Return the one remedy for a value two packages label differently. + + Two packages emit the value, so a package declaration cannot settle it: + the remedy is a register entry, and the message says how to choose its + label. The packages word it differently, so the script that regenerates + the register needs the same label in its ``CHOSEN_LABELS``, or it no longer + reproduces the register. A value the register lists already has its label. + """ + + canonical = canonical_value_label(dimension_id, value_id) + if canonical is not None: + return _register_label_remedy(canonical) + return ( + f"Add it to {REGISTER_DISPLAY_PATH} with one label (chronicle#376), " + f"chosen by the rule in {LABEL_RULE_DISPLAY_PATH}: the wording most of " + "these packages use, a tie going to the national statistics office's " + "wording, without footnote markers or words that name the measure, " + f"and add that label to CHOSEN_LABELS in {REGISTER_SCRIPT_DISPLAY_PATH}, " + "so the script still reproduces the register. " + f"Then run `{REGISTER_STATIC_CHECK}`." + ) + + +def declared_value_label_issues( + dimension_value_labels: Mapping[str, Mapping[str, Any]], +) -> list[tuple[str, str, str, str]]: + """Return each declaration the register contradicts. + + Returns ``(dimension id, value id, declared label, register label)``. The + register's label wins on every fact, so a different declaration would only + mislead someone reading the package file. + """ + + found = [] + for dimension_id, value_labels in (dimension_value_labels or {}).items(): + for value_id, declared in (value_labels or {}).items(): + canonical = canonical_value_label(str(dimension_id), str(value_id)) + if canonical is not None and str(declared).strip() != canonical: + found.append( + (str(dimension_id), str(value_id), str(declared), canonical) + ) + return sorted(found) + + +@cache +def _register() -> Mapping[str, Mapping[str, str]]: + payload = json.loads(REGISTER_PATH.read_text(encoding="utf-8")) + return MappingProxyType( + { + dimension_id: MappingProxyType(dict(value_labels)) + for dimension_id, value_labels in payload["labels"].items() + } + ) + + +def canonical_value_label(dimension_id: str, value_id: str) -> str | None: + """Return the register's label for one dimension value, or None. + + *value_id* is the value's :func:`dimension_value_id` form. A value the + register does not list takes its package's label. + """ + + return _register().get(str(dimension_id), {}).get(str(value_id)) + + +def register_size() -> int: + """Return how many dimension values the register labels.""" + + return sum(len(value_labels) for value_labels in _register().values()) + def dimension_value_id(value: Any) -> str: """Return the ``dimension_value_labels`` key of one dimension value. @@ -80,8 +217,11 @@ def label_facts( ``dimension_labels`` and ``dimension_value_labels`` are the package's declarations, ``field_labels`` the publisher's labels for parsed source-row columns, and ``source_rows`` the parsed rows the facts' lineage points at. - A dimension or value no source labels is left unlabelled for - :func:`dimension_label_issues` to report. + A value the register lists takes the register's label, in + ``dimension_value_labels`` and ``layout.groupby_value_label`` alike, and + the package's own wording goes to ``package_dimension_value_labels`` + where it differs. A dimension or value no source labels is left + unlabelled for :func:`dimension_label_issues` to report. """ facts = list(facts) declared = dict(dimension_labels or {}) @@ -118,43 +258,106 @@ def label_facts( if key in rows_by_key ] value_labels: dict[str, dict[str, str]] = defaultdict(dict) + package_wordings: dict[str, dict[str, str]] = defaultdict(dict) + + def resolve( + dimension_id: str, + value_id: str, + *, + row_label: str | None, + source_text: str | None = None, + self_label: str | None = None, + ) -> None: + declared_label = declared_values.get(dimension_id, {}).get(value_id) + label = ( + canonical_value_label(dimension_id, value_id) + or declared_label + or row_label + or source_text + or self_label + ) + if not label: + return + value_labels[dimension_id][value_id] = label + # The package's own wording: its row's label, else its declaration, + # else the source-row text. Nothing checks it against the + # publisher's file, and it is often Chronicle's text. + package_wording = row_label or declared_label or source_text + if package_wording and package_wording != label: + package_wordings[dimension_id][value_id] = package_wording + for dimension_id, value in dimensions.items(): value_id = dimension_value_id(value) - label = ( - declared_values.get(dimension_id, {}).get(value_id) - or _groupby_row_label(layout, dimension_id, value_id) - or _source_row_label(rows, dimension_id, value) - or _self_label(value) + resolve( + dimension_id, + value_id, + row_label=_groupby_row_label(layout, dimension_id, value_id), + source_text=_source_row_label(rows, dimension_id, value), + self_label=_self_label(value), ) - if label: - value_labels[dimension_id][value_id] = label - if ( - groupby - and groupby not in dimensions - and layout.groupby_value_id is not None - ): - value_id = dimension_value_id(layout.groupby_value_id) - label = declared_values.get(groupby, {}).get(value_id) or ( - _groupby_row_label(layout, groupby, value_id) + groupby_value_id = ( + dimension_value_id(layout.groupby_value_id) + if groupby and layout.groupby_value_id is not None + else None + ) + if groupby_value_id is not None and groupby not in dimensions: + resolve( + groupby, + groupby_value_id, + row_label=_groupby_row_label(layout, groupby, groupby_value_id), ) - if label: - value_labels[groupby][value_id] = label + if layout is not None: + layout = replace(layout, groupby_dimension_label=labels.get(groupby)) + if groupby_value_id is not None: + layout = replace( + layout, + groupby_value_label=_groupby_value_label( + layout, value_labels, package_wordings, declared_values + ), + ) labelled.append( replace( fact, dimension_labels=labels, dimension_value_labels=dict(value_labels), - layout=( - replace(layout, groupby_dimension_label=labels.get(groupby)) - if layout - else layout - ), + package_dimension_value_labels=dict(package_wordings), + layout=layout, ) ) return labelled +def _groupby_value_label( + layout: SourceRecordLayout, + value_labels: Mapping[str, Mapping[str, str]], + package_wordings: dict[str, dict[str, str]], + declared_values: Mapping[str, Mapping[str, str]], +) -> str | None: + """Return the one label of a fact's groupby value (chronicle#376). + + The groupby value is usually in ``value_labels`` already. When the groupby + axis is also a filter whose value differs from the row's, the row's value + is not, so its label is resolved here the same way, and the row's own + wording is kept with the others. + """ + + groupby = layout.groupby_dimension + value_id = dimension_value_id(layout.groupby_value_id) + row_label = (layout.groupby_value_label or "").strip() or None + resolved = value_labels.get(groupby, {}).get(value_id) + if resolved is not None: + return resolved + label = ( + canonical_value_label(groupby, value_id) + or declared_values.get(groupby, {}).get(value_id) + or row_label + ) + if row_label and label and row_label != label: + package_wordings.setdefault(groupby, {})[value_id] = row_label + return label + + def unused_label_declarations( facts: Iterable[AggregateFact], *, @@ -210,9 +413,15 @@ def message(self) -> str: target = f"{target} value {self.value_id!r}" if self.code == "conflicting_groupby_value_label": return ( - f"{target} carries publisher row labels that differ across " - f"facts: {list(self.labels)!r}; a consumer selecting facts " - "from more than one of those rows sees conflicting labels." + f"{target} carries row labels that differ across facts: " + f"{list(self.labels)!r}; a consumer selecting facts from more " + "than one of those rows sees conflicting labels. " + f"{in_package_value_label_remedy(self.dimension_id, self.value_id)}" + ) + if self.code == "conflicting_dimension_value_label": + return ( + f"{target} carries more than one label: {list(self.labels)!r}. " + f"{in_package_value_label_remedy(self.dimension_id, self.value_id)}" ) if self.code.startswith("conflicting"): return f"{target} carries more than one label: {list(self.labels)!r}." @@ -246,13 +455,16 @@ def dimension_label_issues( dimension, ``layout.groupby_dimension_label``; each value likewise, from ``dimension_value_labels`` or, for the groupby value, ``layout.groupby_value_label``. Across *rows*, every dimension id and every - value must carry a single label. Values that only ever appear as a groupby - value, whose publisher row labels differ across rows, are reported - separately as ``conflicting_groupby_value_label``: that text is the - publisher's, kept as published — including the row value of a groupby axis - that is also a filter, whose own value the row names and the filter does - not. Issues are aggregated per dimension or value, with a fact count and an - example fact key. + value must carry a single label (chronicle#376). A value labelled two ways + that only ever appears as a groupby value is reported as + ``conflicting_groupby_value_label`` (including the row value of a groupby + axis that is also a filter, whose own value the row names and the filter + does not), and any other as ``conflicting_dimension_value_label``. Facts a + package builds take the register's label for every value it lists, so + either code means a value the register does not list, labelled two ways + by the package's rows or declarations; both are errors. Issues are + aggregated per dimension or value, with a fact count and an example fact + key. """ missing: dict[tuple[str, str, str | None], list[Any]] = {} row_conflicts: dict[tuple[str, str | None], set[str]] = defaultdict(set) @@ -494,10 +706,20 @@ def _count( __all__ = [ + "LABEL_RULE_DISPLAY_PATH", + "REGISTER_DISPLAY_PATH", + "REGISTER_PATH", + "REGISTER_SCRIPT_DISPLAY_PATH", + "REGISTER_STATIC_CHECK", "DimensionLabelIssue", + "canonical_value_label", + "cross_package_value_label_remedy", + "declared_value_label_issues", "dimension_label_issues", "dimension_labels_by_id", "dimension_value_id", + "in_package_value_label_remedy", "label_facts", + "register_size", "unused_label_declarations", ] diff --git a/chronicle/dimension_values/canonical_labels.json b/chronicle/dimension_values/canonical_labels.json new file mode 100644 index 00000000..77c9273f --- /dev/null +++ b/chronicle/dimension_values/canonical_labels.json @@ -0,0 +1,8564 @@ +{ + "schema_version": "chronicle.dimension_value_labels.v1", + "description": "One label per dimension value (chronicle#376). Every fact built from a source package carries the label listed here for a value in dimension_value_labels and, for its groupby value, layout.groupby_value_label; the package's own wording, where it differs, is kept in package_dimension_value_labels. A value enters this register when two or more packages emit it or when its packages word it more than one way. These are Chronicle's display labels, not a publisher's file: a value with one wording keeps it, and a value worded more than one way takes the label chosen in scripts/build_dimension_value_register.py. A package may not declare a different label for a listed value. A value no entry covers takes its package's label, and build-bundle refuses it if two packages label it differently.", + "sources": { + "script": "scripts/build_dimension_value_register.py", + "packages": "chronicle.bundle.DEFAULT_BUNDLE_SOURCES", + "built_at_chronicle_commit": "dece5e9", + "default_build_year": 2023, + "build_years": { + "census-acs-s0101-congressional-district-age-2024": 2024, + "census-acs-s0101-national-age-2024": 2024, + "census-acs-s0101-state-age-2024": 2024, + "census-acs-s1501-state-attainment-2024": 2024, + "census-acs-s2201-congressional-district-snap-2024": 2024, + "census-acs5-b01003-county-2024": 2024, + "census-acs5-b11001-county-2024": 2024, + "census-acs5-b19001-county-2024": 2024, + "census-acs5-b19013-county-2024": 2024, + "census-acs5-b19025-county-2024": 2024, + "census-acs5-b19051-county-2024": 2024, + "census-acs5-b19061-county-2024": 2024, + "cms-aca-effectuated-enrollment-2022": 2022, + "cms-aca-oep-state-level": 2024, + "cms-aca-oep-state-level-2022": 2022, + "cms-aca-oep-state-level-2025": 2025, + "ed-fsa-dl-portfolio-by-repayment-plan-fy2026-q3": 2026, + "ed-fsa-portfolio-by-age-fy2026-q2": 2026, + "ed-fsa-portfolio-by-debt-size-fy2026-q2": 2026, + "ed-fsa-portfolio-by-loan-type-fy2026-q3": 2026, + "ed-fsa-portfolio-by-location-fy2026-q2": 2026, + "ed-fsa-portfolio-summary-fy2026-q3": 2026, + "jct-obbba-revenue-estimates-2025": 2026, + "jct-tax-expenditures-2024": 2024 + }, + "chosen_labels": [ + "age=85_plus", + "age=age_20", + "age=age_21", + "age=age_25_to_29", + "age=age_30_to_34", + "age=age_35_to_39", + "age=age_40_to_44", + "age_band=30 to 39", + "age_band=40 to 49", + "early_year_award_line=new_returning_total_returning_31_33_35", + "freq=A", + "gambling_commission.gsgb_activity=national_lottery_draws_in_person", + "groeipakket.component=pleegzorgtoeslag", + "groeipakket.component=sociale_toeslag", + "groeipakket.component=wezentoeslag", + "groeipakket.component=zorgtoeslag", + "household_type=couple_3_plus_children_households", + "income_range=all", + "measure=country_total", + "na_item=belgium_household_disposable_income_gross", + "na_item=belgium_household_mixed_income_gross", + "na_item=belgium_household_operating_surplus_gross", + "ons.coicop=coicop_01", + "ons.coicop=coicop_02", + "ons.coicop=coicop_04", + "ons.coicop=coicop_05", + "ons.coicop=coicop_11", + "ons.coicop=coicop_12", + "ons.household_type=couple_3_plus_children_households", + "person.age_band=65_plus", + "property_type=detached", + "property_type=semi_detached", + "property_type=terraced", + "quant_inc=d1", + "quant_inc=d2", + "quant_inc=d3", + "quant_inc=d4", + "quant_inc=d5", + "quant_inc=d6", + "quant_inc=d7", + "quant_inc=d8", + "quant_inc=d9", + "salary_sacrifice_threshold_position=all", + "sex=female", + "sex=male", + "us:statutes/26/62#adjusted_gross_income=all", + "us:statutes/26/62#adjusted_gross_income=under_1" + ] + }, + "labels": { + "Age": { + "0 - 4": "0 - 4", + "10 - 14": "10 - 14", + "15": "15", + "16 - 17": "16 - 17", + "18 - 19": "18 - 19", + "20 - 24": "20 - 24", + "25 - 29": "25 - 29", + "30 - 34": "30 - 34", + "35 - 39": "35 - 39", + "40 - 44": "40 - 44", + "45 - 49": "45 - 49", + "5 - 9": "5 - 9", + "50 - 54": "50 - 54", + "55 - 59": "55 - 59", + "60 - 64": "60 - 64", + "65 - 69": "65 - 69", + "70 - 74": "70 - 74", + "75 - 79": "75 - 79", + "80 - 84": "80 - 84", + "85 and over": "85 and over", + "Total": "Total" + }, + "Age Label": { + "0 years": "0 years", + "1 year": "1 year", + "10 years": "10 years", + "100+ years": "100+ years", + "11 years": "11 years", + "12 years": "12 years", + "13 years": "13 years", + "14 years": "14 years", + "15 years": "15 years", + "16 years": "16 years", + "17 years": "17 years", + "18 years": "18 years", + "19 years": "19 years", + "2 years": "2 years", + "20 years": "20 years", + "21 years": "21 years", + "22 years": "22 years", + "23 years": "23 years", + "24 years": "24 years", + "25 years": "25 years", + "26 years": "26 years", + "27 years": "27 years", + "28 years": "28 years", + "29 years": "29 years", + "3 years": "3 years", + "30 years": "30 years", + "31 years": "31 years", + "32 years": "32 years", + "33 years": "33 years", + "34 years": "34 years", + "35 years": "35 years", + "36 years": "36 years", + "37 years": "37 years", + "38 years": "38 years", + "39 years": "39 years", + "4 years": "4 years", + "40 years": "40 years", + "41 years": "41 years", + "42 years": "42 years", + "43 years": "43 years", + "44 years": "44 years", + "45 years": "45 years", + "46 years": "46 years", + "47 years": "47 years", + "48 years": "48 years", + "49 years": "49 years", + "5 years": "5 years", + "50 years": "50 years", + "51 years": "51 years", + "52 years": "52 years", + "53 years": "53 years", + "54 years": "54 years", + "55 years": "55 years", + "56 years": "56 years", + "57 years": "57 years", + "58 years": "58 years", + "59 years": "59 years", + "6 years": "6 years", + "60 years": "60 years", + "61 years": "61 years", + "62 years": "62 years", + "63 years": "63 years", + "64 years": "64 years", + "65 years": "65 years", + "66 years": "66 years", + "67 years": "67 years", + "68 years": "68 years", + "69 years": "69 years", + "7 years": "7 years", + "70 years": "70 years", + "71 years": "71 years", + "72 years": "72 years", + "73 years": "73 years", + "74 years": "74 years", + "75 years": "75 years", + "76 years": "76 years", + "77 years": "77 years", + "78 years": "78 years", + "79 years": "79 years", + "8 years": "8 years", + "80 years": "80 years", + "81 years": "81 years", + "82 years": "82 years", + "83 years": "83 years", + "84 years": "84 years", + "85 years": "85 years", + "86 years": "86 years", + "87 years": "87 years", + "88 years": "88 years", + "89 years": "89 years", + "9 years": "9 years", + "90 years": "90 years", + "91 years": "91 years", + "92 years": "92 years", + "93 years": "93 years", + "94 years": "94 years", + "95 years": "95 years", + "96 years": "96 years", + "97 years": "97 years", + "98 years": "98 years", + "99 years": "99 years", + "age_0": "0 years", + "age_1": "1 year", + "age_10": "10 years", + "age_100": "100+ years", + "age_11": "11 years", + "age_12": "12 years", + "age_13": "13 years", + "age_14": "14 years", + "age_15": "15 years", + "age_16": "16 years", + "age_17": "17 years", + "age_18": "18 years", + "age_19": "19 years", + "age_2": "2 years", + "age_20": "20 years", + "age_21": "21 years", + "age_22": "22 years", + "age_23": "23 years", + "age_24": "24 years", + "age_25": "25 years", + "age_26": "26 years", + "age_27": "27 years", + "age_28": "28 years", + "age_29": "29 years", + "age_3": "3 years", + "age_30": "30 years", + "age_31": "31 years", + "age_32": "32 years", + "age_33": "33 years", + "age_34": "34 years", + "age_35": "35 years", + "age_36": "36 years", + "age_37": "37 years", + "age_38": "38 years", + "age_39": "39 years", + "age_4": "4 years", + "age_40": "40 years", + "age_41": "41 years", + "age_42": "42 years", + "age_43": "43 years", + "age_44": "44 years", + "age_45": "45 years", + "age_46": "46 years", + "age_47": "47 years", + "age_48": "48 years", + "age_49": "49 years", + "age_5": "5 years", + "age_50": "50 years", + "age_51": "51 years", + "age_52": "52 years", + "age_53": "53 years", + "age_54": "54 years", + "age_55": "55 years", + "age_56": "56 years", + "age_57": "57 years", + "age_58": "58 years", + "age_59": "59 years", + "age_6": "6 years", + "age_60": "60 years", + "age_61": "61 years", + "age_62": "62 years", + "age_63": "63 years", + "age_64": "64 years", + "age_65": "65 years", + "age_66": "66 years", + "age_67": "67 years", + "age_68": "68 years", + "age_69": "69 years", + "age_7": "7 years", + "age_70": "70 years", + "age_71": "71 years", + "age_72": "72 years", + "age_73": "73 years", + "age_74": "74 years", + "age_75": "75 years", + "age_76": "76 years", + "age_77": "77 years", + "age_78": "78 years", + "age_79": "79 years", + "age_8": "8 years", + "age_80": "80 years", + "age_81": "81 years", + "age_82": "82 years", + "age_83": "83 years", + "age_84": "84 years", + "age_85": "85 years", + "age_86": "86 years", + "age_87": "87 years", + "age_88": "88 years", + "age_89": "89 years", + "age_9": "9 years", + "age_90": "90 years", + "age_91": "91 years", + "age_92": "92 years", + "age_93": "93 years", + "age_94": "94 years", + "age_95": "95 years", + "age_96": "96 years", + "age_97": "97 years", + "age_98": "98 years", + "age_99": "99 years", + "n05000001__age_0": "0 years", + "n05000001__age_1": "1 year", + "n05000001__age_10": "10 years", + "n05000001__age_100": "100+ years", + "n05000001__age_11": "11 years", + "n05000001__age_12": "12 years", + "n05000001__age_13": "13 years", + "n05000001__age_14": "14 years", + "n05000001__age_15": "15 years", + "n05000001__age_16": "16 years", + "n05000001__age_17": "17 years", + "n05000001__age_18": "18 years", + "n05000001__age_19": "19 years", + "n05000001__age_2": "2 years", + "n05000001__age_20": "20 years", + "n05000001__age_21": "21 years", + "n05000001__age_22": "22 years", + "n05000001__age_23": "23 years", + "n05000001__age_24": "24 years", + "n05000001__age_25": "25 years", + "n05000001__age_26": "26 years", + "n05000001__age_27": "27 years", + "n05000001__age_28": "28 years", + "n05000001__age_29": "29 years", + "n05000001__age_3": "3 years", + "n05000001__age_30": "30 years", + "n05000001__age_31": "31 years", + "n05000001__age_32": "32 years", + "n05000001__age_33": "33 years", + "n05000001__age_34": "34 years", + "n05000001__age_35": "35 years", + "n05000001__age_36": "36 years", + "n05000001__age_37": "37 years", + "n05000001__age_38": "38 years", + "n05000001__age_39": "39 years", + "n05000001__age_4": "4 years", + "n05000001__age_40": "40 years", + "n05000001__age_41": "41 years", + "n05000001__age_42": "42 years", + "n05000001__age_43": "43 years", + "n05000001__age_44": "44 years", + "n05000001__age_45": "45 years", + "n05000001__age_46": "46 years", + "n05000001__age_47": "47 years", + "n05000001__age_48": "48 years", + "n05000001__age_49": "49 years", + "n05000001__age_5": "5 years", + "n05000001__age_50": "50 years", + "n05000001__age_51": "51 years", + "n05000001__age_52": "52 years", + "n05000001__age_53": "53 years", + "n05000001__age_54": "54 years", + "n05000001__age_55": "55 years", + "n05000001__age_56": "56 years", + "n05000001__age_57": "57 years", + "n05000001__age_58": "58 years", + "n05000001__age_59": "59 years", + "n05000001__age_6": "6 years", + "n05000001__age_60": "60 years", + "n05000001__age_61": "61 years", + "n05000001__age_62": "62 years", + "n05000001__age_63": "63 years", + "n05000001__age_64": "64 years", + "n05000001__age_65": "65 years", + "n05000001__age_66": "66 years", + "n05000001__age_67": "67 years", + "n05000001__age_68": "68 years", + "n05000001__age_69": "69 years", + "n05000001__age_7": "7 years", + "n05000001__age_70": "70 years", + "n05000001__age_71": "71 years", + "n05000001__age_72": "72 years", + "n05000001__age_73": "73 years", + "n05000001__age_74": "74 years", + "n05000001__age_75": "75 years", + "n05000001__age_76": "76 years", + "n05000001__age_77": "77 years", + "n05000001__age_78": "78 years", + "n05000001__age_79": "79 years", + "n05000001__age_8": "8 years", + "n05000001__age_80": "80 years", + "n05000001__age_81": "81 years", + "n05000001__age_82": "82 years", + "n05000001__age_83": "83 years", + "n05000001__age_84": "84 years", + "n05000001__age_85": "85 years", + "n05000001__age_86": "86 years", + "n05000001__age_87": "87 years", + "n05000001__age_88": "88 years", + "n05000001__age_89": "89 years", + "n05000001__age_9": "9 years", + "n05000001__age_90": "90 years", + "n05000001__age_91": "91 years", + "n05000001__age_92": "92 years", + "n05000001__age_93": "93 years", + "n05000001__age_94": "94 years", + "n05000001__age_95": "95 years", + "n05000001__age_96": "96 years", + "n05000001__age_97": "97 years", + "n05000001__age_98": "98 years", + "n05000001__age_99": "99 years", + "n05000002__age_0": "0 years", + "n05000002__age_1": "1 year", + "n05000002__age_10": "10 years", + "n05000002__age_100": "100+ years", + "n05000002__age_11": "11 years", + "n05000002__age_12": "12 years", + "n05000002__age_13": "13 years", + "n05000002__age_14": "14 years", + "n05000002__age_15": "15 years", + "n05000002__age_16": "16 years", + "n05000002__age_17": "17 years", + "n05000002__age_18": "18 years", + "n05000002__age_19": "19 years", + "n05000002__age_2": "2 years", + "n05000002__age_20": "20 years", + "n05000002__age_21": "21 years", + "n05000002__age_22": "22 years", + "n05000002__age_23": "23 years", + "n05000002__age_24": "24 years", + "n05000002__age_25": "25 years", + "n05000002__age_26": "26 years", + "n05000002__age_27": "27 years", + "n05000002__age_28": "28 years", + "n05000002__age_29": "29 years", + "n05000002__age_3": "3 years", + "n05000002__age_30": "30 years", + "n05000002__age_31": "31 years", + "n05000002__age_32": "32 years", + "n05000002__age_33": "33 years", + "n05000002__age_34": "34 years", + "n05000002__age_35": "35 years", + "n05000002__age_36": "36 years", + "n05000002__age_37": "37 years", + "n05000002__age_38": "38 years", + "n05000002__age_39": "39 years", + "n05000002__age_4": "4 years", + "n05000002__age_40": "40 years", + "n05000002__age_41": "41 years", + "n05000002__age_42": "42 years", + "n05000002__age_43": "43 years", + "n05000002__age_44": "44 years", + "n05000002__age_45": "45 years", + "n05000002__age_46": "46 years", + "n05000002__age_47": "47 years", + "n05000002__age_48": "48 years", + "n05000002__age_49": "49 years", + "n05000002__age_5": "5 years", + "n05000002__age_50": "50 years", + "n05000002__age_51": "51 years", + "n05000002__age_52": "52 years", + "n05000002__age_53": "53 years", + "n05000002__age_54": "54 years", + "n05000002__age_55": "55 years", + "n05000002__age_56": "56 years", + "n05000002__age_57": "57 years", + "n05000002__age_58": "58 years", + "n05000002__age_59": "59 years", + "n05000002__age_6": "6 years", + "n05000002__age_60": "60 years", + "n05000002__age_61": "61 years", + "n05000002__age_62": "62 years", + "n05000002__age_63": "63 years", + "n05000002__age_64": "64 years", + "n05000002__age_65": "65 years", + "n05000002__age_66": "66 years", + "n05000002__age_67": "67 years", + "n05000002__age_68": "68 years", + "n05000002__age_69": "69 years", + "n05000002__age_7": "7 years", + "n05000002__age_70": "70 years", + "n05000002__age_71": "71 years", + "n05000002__age_72": "72 years", + "n05000002__age_73": "73 years", + "n05000002__age_74": "74 years", + "n05000002__age_75": "75 years", + "n05000002__age_76": "76 years", + "n05000002__age_77": "77 years", + "n05000002__age_78": "78 years", + "n05000002__age_79": "79 years", + "n05000002__age_8": "8 years", + "n05000002__age_80": "80 years", + "n05000002__age_81": "81 years", + "n05000002__age_82": "82 years", + "n05000002__age_83": "83 years", + "n05000002__age_84": "84 years", + "n05000002__age_85": "85 years", + "n05000002__age_86": "86 years", + "n05000002__age_87": "87 years", + "n05000002__age_88": "88 years", + "n05000002__age_89": "89 years", + "n05000002__age_9": "9 years", + "n05000002__age_90": "90 years", + "n05000002__age_91": "91 years", + "n05000002__age_92": "92 years", + "n05000002__age_93": "93 years", + "n05000002__age_94": "94 years", + "n05000002__age_95": "95 years", + "n05000002__age_96": "96 years", + "n05000002__age_97": "97 years", + "n05000002__age_98": "98 years", + "n05000002__age_99": "99 years", + "n05000003__age_0": "0 years", + "n05000003__age_1": "1 year", + "n05000003__age_10": "10 years", + "n05000003__age_100": "100+ years", + "n05000003__age_11": "11 years", + "n05000003__age_12": "12 years", + "n05000003__age_13": "13 years", + "n05000003__age_14": "14 years", + "n05000003__age_15": "15 years", + "n05000003__age_16": "16 years", + "n05000003__age_17": "17 years", + "n05000003__age_18": "18 years", + "n05000003__age_19": "19 years", + "n05000003__age_2": "2 years", + "n05000003__age_20": "20 years", + "n05000003__age_21": "21 years", + "n05000003__age_22": "22 years", + "n05000003__age_23": "23 years", + "n05000003__age_24": "24 years", + "n05000003__age_25": "25 years", + "n05000003__age_26": "26 years", + "n05000003__age_27": "27 years", + "n05000003__age_28": "28 years", + "n05000003__age_29": "29 years", + "n05000003__age_3": "3 years", + "n05000003__age_30": "30 years", + "n05000003__age_31": "31 years", + "n05000003__age_32": "32 years", + "n05000003__age_33": "33 years", + "n05000003__age_34": "34 years", + "n05000003__age_35": "35 years", + "n05000003__age_36": "36 years", + "n05000003__age_37": "37 years", + "n05000003__age_38": "38 years", + "n05000003__age_39": "39 years", + "n05000003__age_4": "4 years", + "n05000003__age_40": "40 years", + "n05000003__age_41": "41 years", + "n05000003__age_42": "42 years", + "n05000003__age_43": "43 years", + "n05000003__age_44": "44 years", + "n05000003__age_45": "45 years", + "n05000003__age_46": "46 years", + "n05000003__age_47": "47 years", + "n05000003__age_48": "48 years", + "n05000003__age_49": "49 years", + "n05000003__age_5": "5 years", + "n05000003__age_50": "50 years", + "n05000003__age_51": "51 years", + "n05000003__age_52": "52 years", + "n05000003__age_53": "53 years", + "n05000003__age_54": "54 years", + "n05000003__age_55": "55 years", + "n05000003__age_56": "56 years", + "n05000003__age_57": "57 years", + "n05000003__age_58": "58 years", + "n05000003__age_59": "59 years", + "n05000003__age_6": "6 years", + "n05000003__age_60": "60 years", + "n05000003__age_61": "61 years", + "n05000003__age_62": "62 years", + "n05000003__age_63": "63 years", + "n05000003__age_64": "64 years", + "n05000003__age_65": "65 years", + "n05000003__age_66": "66 years", + "n05000003__age_67": "67 years", + "n05000003__age_68": "68 years", + "n05000003__age_69": "69 years", + "n05000003__age_7": "7 years", + "n05000003__age_70": "70 years", + "n05000003__age_71": "71 years", + "n05000003__age_72": "72 years", + "n05000003__age_73": "73 years", + "n05000003__age_74": "74 years", + "n05000003__age_75": "75 years", + "n05000003__age_76": "76 years", + "n05000003__age_77": "77 years", + "n05000003__age_78": "78 years", + "n05000003__age_79": "79 years", + "n05000003__age_8": "8 years", + "n05000003__age_80": "80 years", + "n05000003__age_81": "81 years", + "n05000003__age_82": "82 years", + "n05000003__age_83": "83 years", + "n05000003__age_84": "84 years", + "n05000003__age_85": "85 years", + "n05000003__age_86": "86 years", + "n05000003__age_87": "87 years", + "n05000003__age_88": "88 years", + "n05000003__age_89": "89 years", + "n05000003__age_9": "9 years", + "n05000003__age_90": "90 years", + "n05000003__age_91": "91 years", + "n05000003__age_92": "92 years", + "n05000003__age_93": "93 years", + "n05000003__age_94": "94 years", + "n05000003__age_95": "95 years", + "n05000003__age_96": "96 years", + "n05000003__age_97": "97 years", + "n05000003__age_98": "98 years", + "n05000003__age_99": "99 years", + "n05000004__age_0": "0 years", + "n05000004__age_1": "1 year", + "n05000004__age_10": "10 years", + "n05000004__age_100": "100+ years", + "n05000004__age_11": "11 years", + "n05000004__age_12": "12 years", + "n05000004__age_13": "13 years", + "n05000004__age_14": "14 years", + "n05000004__age_15": "15 years", + "n05000004__age_16": "16 years", + "n05000004__age_17": "17 years", + "n05000004__age_18": "18 years", + "n05000004__age_19": "19 years", + "n05000004__age_2": "2 years", + "n05000004__age_20": "20 years", + "n05000004__age_21": "21 years", + "n05000004__age_22": "22 years", + "n05000004__age_23": "23 years", + "n05000004__age_24": "24 years", + "n05000004__age_25": "25 years", + "n05000004__age_26": "26 years", + "n05000004__age_27": "27 years", + "n05000004__age_28": "28 years", + "n05000004__age_29": "29 years", + "n05000004__age_3": "3 years", + "n05000004__age_30": "30 years", + "n05000004__age_31": "31 years", + "n05000004__age_32": "32 years", + "n05000004__age_33": "33 years", + "n05000004__age_34": "34 years", + "n05000004__age_35": "35 years", + "n05000004__age_36": "36 years", + "n05000004__age_37": "37 years", + "n05000004__age_38": "38 years", + "n05000004__age_39": "39 years", + "n05000004__age_4": "4 years", + "n05000004__age_40": "40 years", + "n05000004__age_41": "41 years", + "n05000004__age_42": "42 years", + "n05000004__age_43": "43 years", + "n05000004__age_44": "44 years", + "n05000004__age_45": "45 years", + "n05000004__age_46": "46 years", + "n05000004__age_47": "47 years", + "n05000004__age_48": "48 years", + "n05000004__age_49": "49 years", + "n05000004__age_5": "5 years", + "n05000004__age_50": "50 years", + "n05000004__age_51": "51 years", + "n05000004__age_52": "52 years", + "n05000004__age_53": "53 years", + "n05000004__age_54": "54 years", + "n05000004__age_55": "55 years", + "n05000004__age_56": "56 years", + "n05000004__age_57": "57 years", + "n05000004__age_58": "58 years", + "n05000004__age_59": "59 years", + "n05000004__age_6": "6 years", + "n05000004__age_60": "60 years", + "n05000004__age_61": "61 years", + "n05000004__age_62": "62 years", + "n05000004__age_63": "63 years", + "n05000004__age_64": "64 years", + "n05000004__age_65": "65 years", + "n05000004__age_66": "66 years", + "n05000004__age_67": "67 years", + "n05000004__age_68": "68 years", + "n05000004__age_69": "69 years", + "n05000004__age_7": "7 years", + "n05000004__age_70": "70 years", + "n05000004__age_71": "71 years", + "n05000004__age_72": "72 years", + "n05000004__age_73": "73 years", + "n05000004__age_74": "74 years", + "n05000004__age_75": "75 years", + "n05000004__age_76": "76 years", + "n05000004__age_77": "77 years", + "n05000004__age_78": "78 years", + "n05000004__age_79": "79 years", + "n05000004__age_8": "8 years", + "n05000004__age_80": "80 years", + "n05000004__age_81": "81 years", + "n05000004__age_82": "82 years", + "n05000004__age_83": "83 years", + "n05000004__age_84": "84 years", + "n05000004__age_85": "85 years", + "n05000004__age_86": "86 years", + "n05000004__age_87": "87 years", + "n05000004__age_88": "88 years", + "n05000004__age_89": "89 years", + "n05000004__age_9": "9 years", + "n05000004__age_90": "90 years", + "n05000004__age_91": "91 years", + "n05000004__age_92": "92 years", + "n05000004__age_93": "93 years", + "n05000004__age_94": "94 years", + "n05000004__age_95": "95 years", + "n05000004__age_96": "96 years", + "n05000004__age_97": "97 years", + "n05000004__age_98": "98 years", + "n05000004__age_99": "99 years", + "n05000005__age_0": "0 years", + "n05000005__age_1": "1 year", + "n05000005__age_10": "10 years", + "n05000005__age_100": "100+ years", + "n05000005__age_11": "11 years", + "n05000005__age_12": "12 years", + "n05000005__age_13": "13 years", + "n05000005__age_14": "14 years", + "n05000005__age_15": "15 years", + "n05000005__age_16": "16 years", + "n05000005__age_17": "17 years", + "n05000005__age_18": "18 years", + "n05000005__age_19": "19 years", + "n05000005__age_2": "2 years", + "n05000005__age_20": "20 years", + "n05000005__age_21": "21 years", + "n05000005__age_22": "22 years", + "n05000005__age_23": "23 years", + "n05000005__age_24": "24 years", + "n05000005__age_25": "25 years", + "n05000005__age_26": "26 years", + "n05000005__age_27": "27 years", + "n05000005__age_28": "28 years", + "n05000005__age_29": "29 years", + "n05000005__age_3": "3 years", + "n05000005__age_30": "30 years", + "n05000005__age_31": "31 years", + "n05000005__age_32": "32 years", + "n05000005__age_33": "33 years", + "n05000005__age_34": "34 years", + "n05000005__age_35": "35 years", + "n05000005__age_36": "36 years", + "n05000005__age_37": "37 years", + "n05000005__age_38": "38 years", + "n05000005__age_39": "39 years", + "n05000005__age_4": "4 years", + "n05000005__age_40": "40 years", + "n05000005__age_41": "41 years", + "n05000005__age_42": "42 years", + "n05000005__age_43": "43 years", + "n05000005__age_44": "44 years", + "n05000005__age_45": "45 years", + "n05000005__age_46": "46 years", + "n05000005__age_47": "47 years", + "n05000005__age_48": "48 years", + "n05000005__age_49": "49 years", + "n05000005__age_5": "5 years", + "n05000005__age_50": "50 years", + "n05000005__age_51": "51 years", + "n05000005__age_52": "52 years", + "n05000005__age_53": "53 years", + "n05000005__age_54": "54 years", + "n05000005__age_55": "55 years", + "n05000005__age_56": "56 years", + "n05000005__age_57": "57 years", + "n05000005__age_58": "58 years", + "n05000005__age_59": "59 years", + "n05000005__age_6": "6 years", + "n05000005__age_60": "60 years", + "n05000005__age_61": "61 years", + "n05000005__age_62": "62 years", + "n05000005__age_63": "63 years", + "n05000005__age_64": "64 years", + "n05000005__age_65": "65 years", + "n05000005__age_66": "66 years", + "n05000005__age_67": "67 years", + "n05000005__age_68": "68 years", + "n05000005__age_69": "69 years", + "n05000005__age_7": "7 years", + "n05000005__age_70": "70 years", + "n05000005__age_71": "71 years", + "n05000005__age_72": "72 years", + "n05000005__age_73": "73 years", + "n05000005__age_74": "74 years", + "n05000005__age_75": "75 years", + "n05000005__age_76": "76 years", + "n05000005__age_77": "77 years", + "n05000005__age_78": "78 years", + "n05000005__age_79": "79 years", + "n05000005__age_8": "8 years", + "n05000005__age_80": "80 years", + "n05000005__age_81": "81 years", + "n05000005__age_82": "82 years", + "n05000005__age_83": "83 years", + "n05000005__age_84": "84 years", + "n05000005__age_85": "85 years", + "n05000005__age_86": "86 years", + "n05000005__age_87": "87 years", + "n05000005__age_88": "88 years", + "n05000005__age_89": "89 years", + "n05000005__age_9": "9 years", + "n05000005__age_90": "90 years", + "n05000005__age_91": "91 years", + "n05000005__age_92": "92 years", + "n05000005__age_93": "93 years", + "n05000005__age_94": "94 years", + "n05000005__age_95": "95 years", + "n05000005__age_96": "96 years", + "n05000005__age_97": "97 years", + "n05000005__age_98": "98 years", + "n05000005__age_99": "99 years", + "n05000006__age_0": "0 years", + "n05000006__age_1": "1 year", + "n05000006__age_10": "10 years", + "n05000006__age_100": "100+ years", + "n05000006__age_11": "11 years", + "n05000006__age_12": "12 years", + "n05000006__age_13": "13 years", + "n05000006__age_14": "14 years", + "n05000006__age_15": "15 years", + "n05000006__age_16": "16 years", + "n05000006__age_17": "17 years", + "n05000006__age_18": "18 years", + "n05000006__age_19": "19 years", + "n05000006__age_2": "2 years", + "n05000006__age_20": "20 years", + "n05000006__age_21": "21 years", + "n05000006__age_22": "22 years", + "n05000006__age_23": "23 years", + "n05000006__age_24": "24 years", + "n05000006__age_25": "25 years", + "n05000006__age_26": "26 years", + "n05000006__age_27": "27 years", + "n05000006__age_28": "28 years", + "n05000006__age_29": "29 years", + "n05000006__age_3": "3 years", + "n05000006__age_30": "30 years", + "n05000006__age_31": "31 years", + "n05000006__age_32": "32 years", + "n05000006__age_33": "33 years", + "n05000006__age_34": "34 years", + "n05000006__age_35": "35 years", + "n05000006__age_36": "36 years", + "n05000006__age_37": "37 years", + "n05000006__age_38": "38 years", + "n05000006__age_39": "39 years", + "n05000006__age_4": "4 years", + "n05000006__age_40": "40 years", + "n05000006__age_41": "41 years", + "n05000006__age_42": "42 years", + "n05000006__age_43": "43 years", + "n05000006__age_44": "44 years", + "n05000006__age_45": "45 years", + "n05000006__age_46": "46 years", + "n05000006__age_47": "47 years", + "n05000006__age_48": "48 years", + "n05000006__age_49": "49 years", + "n05000006__age_5": "5 years", + "n05000006__age_50": "50 years", + "n05000006__age_51": "51 years", + "n05000006__age_52": "52 years", + "n05000006__age_53": "53 years", + "n05000006__age_54": "54 years", + "n05000006__age_55": "55 years", + "n05000006__age_56": "56 years", + "n05000006__age_57": "57 years", + "n05000006__age_58": "58 years", + "n05000006__age_59": "59 years", + "n05000006__age_6": "6 years", + "n05000006__age_60": "60 years", + "n05000006__age_61": "61 years", + "n05000006__age_62": "62 years", + "n05000006__age_63": "63 years", + "n05000006__age_64": "64 years", + "n05000006__age_65": "65 years", + "n05000006__age_66": "66 years", + "n05000006__age_67": "67 years", + "n05000006__age_68": "68 years", + "n05000006__age_69": "69 years", + "n05000006__age_7": "7 years", + "n05000006__age_70": "70 years", + "n05000006__age_71": "71 years", + "n05000006__age_72": "72 years", + "n05000006__age_73": "73 years", + "n05000006__age_74": "74 years", + "n05000006__age_75": "75 years", + "n05000006__age_76": "76 years", + "n05000006__age_77": "77 years", + "n05000006__age_78": "78 years", + "n05000006__age_79": "79 years", + "n05000006__age_8": "8 years", + "n05000006__age_80": "80 years", + "n05000006__age_81": "81 years", + "n05000006__age_82": "82 years", + "n05000006__age_83": "83 years", + "n05000006__age_84": "84 years", + "n05000006__age_85": "85 years", + "n05000006__age_86": "86 years", + "n05000006__age_87": "87 years", + "n05000006__age_88": "88 years", + "n05000006__age_89": "89 years", + "n05000006__age_9": "9 years", + "n05000006__age_90": "90 years", + "n05000006__age_91": "91 years", + "n05000006__age_92": "92 years", + "n05000006__age_93": "93 years", + "n05000006__age_94": "94 years", + "n05000006__age_95": "95 years", + "n05000006__age_96": "96 years", + "n05000006__age_97": "97 years", + "n05000006__age_98": "98 years", + "n05000006__age_99": "99 years", + "n05000007__age_0": "0 years", + "n05000007__age_1": "1 year", + "n05000007__age_10": "10 years", + "n05000007__age_100": "100+ years", + "n05000007__age_11": "11 years", + "n05000007__age_12": "12 years", + "n05000007__age_13": "13 years", + "n05000007__age_14": "14 years", + "n05000007__age_15": "15 years", + "n05000007__age_16": "16 years", + "n05000007__age_17": "17 years", + "n05000007__age_18": "18 years", + "n05000007__age_19": "19 years", + "n05000007__age_2": "2 years", + "n05000007__age_20": "20 years", + "n05000007__age_21": "21 years", + "n05000007__age_22": "22 years", + "n05000007__age_23": "23 years", + "n05000007__age_24": "24 years", + "n05000007__age_25": "25 years", + "n05000007__age_26": "26 years", + "n05000007__age_27": "27 years", + "n05000007__age_28": "28 years", + "n05000007__age_29": "29 years", + "n05000007__age_3": "3 years", + "n05000007__age_30": "30 years", + "n05000007__age_31": "31 years", + "n05000007__age_32": "32 years", + "n05000007__age_33": "33 years", + "n05000007__age_34": "34 years", + "n05000007__age_35": "35 years", + "n05000007__age_36": "36 years", + "n05000007__age_37": "37 years", + "n05000007__age_38": "38 years", + "n05000007__age_39": "39 years", + "n05000007__age_4": "4 years", + "n05000007__age_40": "40 years", + "n05000007__age_41": "41 years", + "n05000007__age_42": "42 years", + "n05000007__age_43": "43 years", + "n05000007__age_44": "44 years", + "n05000007__age_45": "45 years", + "n05000007__age_46": "46 years", + "n05000007__age_47": "47 years", + "n05000007__age_48": "48 years", + "n05000007__age_49": "49 years", + "n05000007__age_5": "5 years", + "n05000007__age_50": "50 years", + "n05000007__age_51": "51 years", + "n05000007__age_52": "52 years", + "n05000007__age_53": "53 years", + "n05000007__age_54": "54 years", + "n05000007__age_55": "55 years", + "n05000007__age_56": "56 years", + "n05000007__age_57": "57 years", + "n05000007__age_58": "58 years", + "n05000007__age_59": "59 years", + "n05000007__age_6": "6 years", + "n05000007__age_60": "60 years", + "n05000007__age_61": "61 years", + "n05000007__age_62": "62 years", + "n05000007__age_63": "63 years", + "n05000007__age_64": "64 years", + "n05000007__age_65": "65 years", + "n05000007__age_66": "66 years", + "n05000007__age_67": "67 years", + "n05000007__age_68": "68 years", + "n05000007__age_69": "69 years", + "n05000007__age_7": "7 years", + "n05000007__age_70": "70 years", + "n05000007__age_71": "71 years", + "n05000007__age_72": "72 years", + "n05000007__age_73": "73 years", + "n05000007__age_74": "74 years", + "n05000007__age_75": "75 years", + "n05000007__age_76": "76 years", + "n05000007__age_77": "77 years", + "n05000007__age_78": "78 years", + "n05000007__age_79": "79 years", + "n05000007__age_8": "8 years", + "n05000007__age_80": "80 years", + "n05000007__age_81": "81 years", + "n05000007__age_82": "82 years", + "n05000007__age_83": "83 years", + "n05000007__age_84": "84 years", + "n05000007__age_85": "85 years", + "n05000007__age_86": "86 years", + "n05000007__age_87": "87 years", + "n05000007__age_88": "88 years", + "n05000007__age_89": "89 years", + "n05000007__age_9": "9 years", + "n05000007__age_90": "90 years", + "n05000007__age_91": "91 years", + "n05000007__age_92": "92 years", + "n05000007__age_93": "93 years", + "n05000007__age_94": "94 years", + "n05000007__age_95": "95 years", + "n05000007__age_96": "96 years", + "n05000007__age_97": "97 years", + "n05000007__age_98": "98 years", + "n05000007__age_99": "99 years", + "n05000008__age_0": "0 years", + "n05000008__age_1": "1 year", + "n05000008__age_10": "10 years", + "n05000008__age_100": "100+ years", + "n05000008__age_11": "11 years", + "n05000008__age_12": "12 years", + "n05000008__age_13": "13 years", + "n05000008__age_14": "14 years", + "n05000008__age_15": "15 years", + "n05000008__age_16": "16 years", + "n05000008__age_17": "17 years", + "n05000008__age_18": "18 years", + "n05000008__age_19": "19 years", + "n05000008__age_2": "2 years", + "n05000008__age_20": "20 years", + "n05000008__age_21": "21 years", + "n05000008__age_22": "22 years", + "n05000008__age_23": "23 years", + "n05000008__age_24": "24 years", + "n05000008__age_25": "25 years", + "n05000008__age_26": "26 years", + "n05000008__age_27": "27 years", + "n05000008__age_28": "28 years", + "n05000008__age_29": "29 years", + "n05000008__age_3": "3 years", + "n05000008__age_30": "30 years", + "n05000008__age_31": "31 years", + "n05000008__age_32": "32 years", + "n05000008__age_33": "33 years", + "n05000008__age_34": "34 years", + "n05000008__age_35": "35 years", + "n05000008__age_36": "36 years", + "n05000008__age_37": "37 years", + "n05000008__age_38": "38 years", + "n05000008__age_39": "39 years", + "n05000008__age_4": "4 years", + "n05000008__age_40": "40 years", + "n05000008__age_41": "41 years", + "n05000008__age_42": "42 years", + "n05000008__age_43": "43 years", + "n05000008__age_44": "44 years", + "n05000008__age_45": "45 years", + "n05000008__age_46": "46 years", + "n05000008__age_47": "47 years", + "n05000008__age_48": "48 years", + "n05000008__age_49": "49 years", + "n05000008__age_5": "5 years", + "n05000008__age_50": "50 years", + "n05000008__age_51": "51 years", + "n05000008__age_52": "52 years", + "n05000008__age_53": "53 years", + "n05000008__age_54": "54 years", + "n05000008__age_55": "55 years", + "n05000008__age_56": "56 years", + "n05000008__age_57": "57 years", + "n05000008__age_58": "58 years", + "n05000008__age_59": "59 years", + "n05000008__age_6": "6 years", + "n05000008__age_60": "60 years", + "n05000008__age_61": "61 years", + "n05000008__age_62": "62 years", + "n05000008__age_63": "63 years", + "n05000008__age_64": "64 years", + "n05000008__age_65": "65 years", + "n05000008__age_66": "66 years", + "n05000008__age_67": "67 years", + "n05000008__age_68": "68 years", + "n05000008__age_69": "69 years", + "n05000008__age_7": "7 years", + "n05000008__age_70": "70 years", + "n05000008__age_71": "71 years", + "n05000008__age_72": "72 years", + "n05000008__age_73": "73 years", + "n05000008__age_74": "74 years", + "n05000008__age_75": "75 years", + "n05000008__age_76": "76 years", + "n05000008__age_77": "77 years", + "n05000008__age_78": "78 years", + "n05000008__age_79": "79 years", + "n05000008__age_8": "8 years", + "n05000008__age_80": "80 years", + "n05000008__age_81": "81 years", + "n05000008__age_82": "82 years", + "n05000008__age_83": "83 years", + "n05000008__age_84": "84 years", + "n05000008__age_85": "85 years", + "n05000008__age_86": "86 years", + "n05000008__age_87": "87 years", + "n05000008__age_88": "88 years", + "n05000008__age_89": "89 years", + "n05000008__age_9": "9 years", + "n05000008__age_90": "90 years", + "n05000008__age_91": "91 years", + "n05000008__age_92": "92 years", + "n05000008__age_93": "93 years", + "n05000008__age_94": "94 years", + "n05000008__age_95": "95 years", + "n05000008__age_96": "96 years", + "n05000008__age_97": "97 years", + "n05000008__age_98": "98 years", + "n05000008__age_99": "99 years", + "n05000009__age_0": "0 years", + "n05000009__age_1": "1 year", + "n05000009__age_10": "10 years", + "n05000009__age_100": "100+ years", + "n05000009__age_11": "11 years", + "n05000009__age_12": "12 years", + "n05000009__age_13": "13 years", + "n05000009__age_14": "14 years", + "n05000009__age_15": "15 years", + "n05000009__age_16": "16 years", + "n05000009__age_17": "17 years", + "n05000009__age_18": "18 years", + "n05000009__age_19": "19 years", + "n05000009__age_2": "2 years", + "n05000009__age_20": "20 years", + "n05000009__age_21": "21 years", + "n05000009__age_22": "22 years", + "n05000009__age_23": "23 years", + "n05000009__age_24": "24 years", + "n05000009__age_25": "25 years", + "n05000009__age_26": "26 years", + "n05000009__age_27": "27 years", + "n05000009__age_28": "28 years", + "n05000009__age_29": "29 years", + "n05000009__age_3": "3 years", + "n05000009__age_30": "30 years", + "n05000009__age_31": "31 years", + "n05000009__age_32": "32 years", + "n05000009__age_33": "33 years", + "n05000009__age_34": "34 years", + "n05000009__age_35": "35 years", + "n05000009__age_36": "36 years", + "n05000009__age_37": "37 years", + "n05000009__age_38": "38 years", + "n05000009__age_39": "39 years", + "n05000009__age_4": "4 years", + "n05000009__age_40": "40 years", + "n05000009__age_41": "41 years", + "n05000009__age_42": "42 years", + "n05000009__age_43": "43 years", + "n05000009__age_44": "44 years", + "n05000009__age_45": "45 years", + "n05000009__age_46": "46 years", + "n05000009__age_47": "47 years", + "n05000009__age_48": "48 years", + "n05000009__age_49": "49 years", + "n05000009__age_5": "5 years", + "n05000009__age_50": "50 years", + "n05000009__age_51": "51 years", + "n05000009__age_52": "52 years", + "n05000009__age_53": "53 years", + "n05000009__age_54": "54 years", + "n05000009__age_55": "55 years", + "n05000009__age_56": "56 years", + "n05000009__age_57": "57 years", + "n05000009__age_58": "58 years", + "n05000009__age_59": "59 years", + "n05000009__age_6": "6 years", + "n05000009__age_60": "60 years", + "n05000009__age_61": "61 years", + "n05000009__age_62": "62 years", + "n05000009__age_63": "63 years", + "n05000009__age_64": "64 years", + "n05000009__age_65": "65 years", + "n05000009__age_66": "66 years", + "n05000009__age_67": "67 years", + "n05000009__age_68": "68 years", + "n05000009__age_69": "69 years", + "n05000009__age_7": "7 years", + "n05000009__age_70": "70 years", + "n05000009__age_71": "71 years", + "n05000009__age_72": "72 years", + "n05000009__age_73": "73 years", + "n05000009__age_74": "74 years", + "n05000009__age_75": "75 years", + "n05000009__age_76": "76 years", + "n05000009__age_77": "77 years", + "n05000009__age_78": "78 years", + "n05000009__age_79": "79 years", + "n05000009__age_8": "8 years", + "n05000009__age_80": "80 years", + "n05000009__age_81": "81 years", + "n05000009__age_82": "82 years", + "n05000009__age_83": "83 years", + "n05000009__age_84": "84 years", + "n05000009__age_85": "85 years", + "n05000009__age_86": "86 years", + "n05000009__age_87": "87 years", + "n05000009__age_88": "88 years", + "n05000009__age_89": "89 years", + "n05000009__age_9": "9 years", + "n05000009__age_90": "90 years", + "n05000009__age_91": "91 years", + "n05000009__age_92": "92 years", + "n05000009__age_93": "93 years", + "n05000009__age_94": "94 years", + "n05000009__age_95": "95 years", + "n05000009__age_96": "96 years", + "n05000009__age_97": "97 years", + "n05000009__age_98": "98 years", + "n05000009__age_99": "99 years", + "n05000010__age_0": "0 years", + "n05000010__age_1": "1 year", + "n05000010__age_10": "10 years", + "n05000010__age_100": "100+ years", + "n05000010__age_11": "11 years", + "n05000010__age_12": "12 years", + "n05000010__age_13": "13 years", + "n05000010__age_14": "14 years", + "n05000010__age_15": "15 years", + "n05000010__age_16": "16 years", + "n05000010__age_17": "17 years", + "n05000010__age_18": "18 years", + "n05000010__age_19": "19 years", + "n05000010__age_2": "2 years", + "n05000010__age_20": "20 years", + "n05000010__age_21": "21 years", + "n05000010__age_22": "22 years", + "n05000010__age_23": "23 years", + "n05000010__age_24": "24 years", + "n05000010__age_25": "25 years", + "n05000010__age_26": "26 years", + "n05000010__age_27": "27 years", + "n05000010__age_28": "28 years", + "n05000010__age_29": "29 years", + "n05000010__age_3": "3 years", + "n05000010__age_30": "30 years", + "n05000010__age_31": "31 years", + "n05000010__age_32": "32 years", + "n05000010__age_33": "33 years", + "n05000010__age_34": "34 years", + "n05000010__age_35": "35 years", + "n05000010__age_36": "36 years", + "n05000010__age_37": "37 years", + "n05000010__age_38": "38 years", + "n05000010__age_39": "39 years", + "n05000010__age_4": "4 years", + "n05000010__age_40": "40 years", + "n05000010__age_41": "41 years", + "n05000010__age_42": "42 years", + "n05000010__age_43": "43 years", + "n05000010__age_44": "44 years", + "n05000010__age_45": "45 years", + "n05000010__age_46": "46 years", + "n05000010__age_47": "47 years", + "n05000010__age_48": "48 years", + "n05000010__age_49": "49 years", + "n05000010__age_5": "5 years", + "n05000010__age_50": "50 years", + "n05000010__age_51": "51 years", + "n05000010__age_52": "52 years", + "n05000010__age_53": "53 years", + "n05000010__age_54": "54 years", + "n05000010__age_55": "55 years", + "n05000010__age_56": "56 years", + "n05000010__age_57": "57 years", + "n05000010__age_58": "58 years", + "n05000010__age_59": "59 years", + "n05000010__age_6": "6 years", + "n05000010__age_60": "60 years", + "n05000010__age_61": "61 years", + "n05000010__age_62": "62 years", + "n05000010__age_63": "63 years", + "n05000010__age_64": "64 years", + "n05000010__age_65": "65 years", + "n05000010__age_66": "66 years", + "n05000010__age_67": "67 years", + "n05000010__age_68": "68 years", + "n05000010__age_69": "69 years", + "n05000010__age_7": "7 years", + "n05000010__age_70": "70 years", + "n05000010__age_71": "71 years", + "n05000010__age_72": "72 years", + "n05000010__age_73": "73 years", + "n05000010__age_74": "74 years", + "n05000010__age_75": "75 years", + "n05000010__age_76": "76 years", + "n05000010__age_77": "77 years", + "n05000010__age_78": "78 years", + "n05000010__age_79": "79 years", + "n05000010__age_8": "8 years", + "n05000010__age_80": "80 years", + "n05000010__age_81": "81 years", + "n05000010__age_82": "82 years", + "n05000010__age_83": "83 years", + "n05000010__age_84": "84 years", + "n05000010__age_85": "85 years", + "n05000010__age_86": "86 years", + "n05000010__age_87": "87 years", + "n05000010__age_88": "88 years", + "n05000010__age_89": "89 years", + "n05000010__age_9": "9 years", + "n05000010__age_90": "90 years", + "n05000010__age_91": "91 years", + "n05000010__age_92": "92 years", + "n05000010__age_93": "93 years", + "n05000010__age_94": "94 years", + "n05000010__age_95": "95 years", + "n05000010__age_96": "96 years", + "n05000010__age_97": "97 years", + "n05000010__age_98": "98 years", + "n05000010__age_99": "99 years", + "n05000011__age_0": "0 years", + "n05000011__age_1": "1 year", + "n05000011__age_10": "10 years", + "n05000011__age_100": "100+ years", + "n05000011__age_11": "11 years", + "n05000011__age_12": "12 years", + "n05000011__age_13": "13 years", + "n05000011__age_14": "14 years", + "n05000011__age_15": "15 years", + "n05000011__age_16": "16 years", + "n05000011__age_17": "17 years", + "n05000011__age_18": "18 years", + "n05000011__age_19": "19 years", + "n05000011__age_2": "2 years", + "n05000011__age_20": "20 years", + "n05000011__age_21": "21 years", + "n05000011__age_22": "22 years", + "n05000011__age_23": "23 years", + "n05000011__age_24": "24 years", + "n05000011__age_25": "25 years", + "n05000011__age_26": "26 years", + "n05000011__age_27": "27 years", + "n05000011__age_28": "28 years", + "n05000011__age_29": "29 years", + "n05000011__age_3": "3 years", + "n05000011__age_30": "30 years", + "n05000011__age_31": "31 years", + "n05000011__age_32": "32 years", + "n05000011__age_33": "33 years", + "n05000011__age_34": "34 years", + "n05000011__age_35": "35 years", + "n05000011__age_36": "36 years", + "n05000011__age_37": "37 years", + "n05000011__age_38": "38 years", + "n05000011__age_39": "39 years", + "n05000011__age_4": "4 years", + "n05000011__age_40": "40 years", + "n05000011__age_41": "41 years", + "n05000011__age_42": "42 years", + "n05000011__age_43": "43 years", + "n05000011__age_44": "44 years", + "n05000011__age_45": "45 years", + "n05000011__age_46": "46 years", + "n05000011__age_47": "47 years", + "n05000011__age_48": "48 years", + "n05000011__age_49": "49 years", + "n05000011__age_5": "5 years", + "n05000011__age_50": "50 years", + "n05000011__age_51": "51 years", + "n05000011__age_52": "52 years", + "n05000011__age_53": "53 years", + "n05000011__age_54": "54 years", + "n05000011__age_55": "55 years", + "n05000011__age_56": "56 years", + "n05000011__age_57": "57 years", + "n05000011__age_58": "58 years", + "n05000011__age_59": "59 years", + "n05000011__age_6": "6 years", + "n05000011__age_60": "60 years", + "n05000011__age_61": "61 years", + "n05000011__age_62": "62 years", + "n05000011__age_63": "63 years", + "n05000011__age_64": "64 years", + "n05000011__age_65": "65 years", + "n05000011__age_66": "66 years", + "n05000011__age_67": "67 years", + "n05000011__age_68": "68 years", + "n05000011__age_69": "69 years", + "n05000011__age_7": "7 years", + "n05000011__age_70": "70 years", + "n05000011__age_71": "71 years", + "n05000011__age_72": "72 years", + "n05000011__age_73": "73 years", + "n05000011__age_74": "74 years", + "n05000011__age_75": "75 years", + "n05000011__age_76": "76 years", + "n05000011__age_77": "77 years", + "n05000011__age_78": "78 years", + "n05000011__age_79": "79 years", + "n05000011__age_8": "8 years", + "n05000011__age_80": "80 years", + "n05000011__age_81": "81 years", + "n05000011__age_82": "82 years", + "n05000011__age_83": "83 years", + "n05000011__age_84": "84 years", + "n05000011__age_85": "85 years", + "n05000011__age_86": "86 years", + "n05000011__age_87": "87 years", + "n05000011__age_88": "88 years", + "n05000011__age_89": "89 years", + "n05000011__age_9": "9 years", + "n05000011__age_90": "90 years", + "n05000011__age_91": "91 years", + "n05000011__age_92": "92 years", + "n05000011__age_93": "93 years", + "n05000011__age_94": "94 years", + "n05000011__age_95": "95 years", + "n05000011__age_96": "96 years", + "n05000011__age_97": "97 years", + "n05000011__age_98": "98 years", + "n05000011__age_99": "99 years", + "n05000012__age_0": "0 years", + "n05000012__age_1": "1 year", + "n05000012__age_10": "10 years", + "n05000012__age_100": "100+ years", + "n05000012__age_11": "11 years", + "n05000012__age_12": "12 years", + "n05000012__age_13": "13 years", + "n05000012__age_14": "14 years", + "n05000012__age_15": "15 years", + "n05000012__age_16": "16 years", + "n05000012__age_17": "17 years", + "n05000012__age_18": "18 years", + "n05000012__age_19": "19 years", + "n05000012__age_2": "2 years", + "n05000012__age_20": "20 years", + "n05000012__age_21": "21 years", + "n05000012__age_22": "22 years", + "n05000012__age_23": "23 years", + "n05000012__age_24": "24 years", + "n05000012__age_25": "25 years", + "n05000012__age_26": "26 years", + "n05000012__age_27": "27 years", + "n05000012__age_28": "28 years", + "n05000012__age_29": "29 years", + "n05000012__age_3": "3 years", + "n05000012__age_30": "30 years", + "n05000012__age_31": "31 years", + "n05000012__age_32": "32 years", + "n05000012__age_33": "33 years", + "n05000012__age_34": "34 years", + "n05000012__age_35": "35 years", + "n05000012__age_36": "36 years", + "n05000012__age_37": "37 years", + "n05000012__age_38": "38 years", + "n05000012__age_39": "39 years", + "n05000012__age_4": "4 years", + "n05000012__age_40": "40 years", + "n05000012__age_41": "41 years", + "n05000012__age_42": "42 years", + "n05000012__age_43": "43 years", + "n05000012__age_44": "44 years", + "n05000012__age_45": "45 years", + "n05000012__age_46": "46 years", + "n05000012__age_47": "47 years", + "n05000012__age_48": "48 years", + "n05000012__age_49": "49 years", + "n05000012__age_5": "5 years", + "n05000012__age_50": "50 years", + "n05000012__age_51": "51 years", + "n05000012__age_52": "52 years", + "n05000012__age_53": "53 years", + "n05000012__age_54": "54 years", + "n05000012__age_55": "55 years", + "n05000012__age_56": "56 years", + "n05000012__age_57": "57 years", + "n05000012__age_58": "58 years", + "n05000012__age_59": "59 years", + "n05000012__age_6": "6 years", + "n05000012__age_60": "60 years", + "n05000012__age_61": "61 years", + "n05000012__age_62": "62 years", + "n05000012__age_63": "63 years", + "n05000012__age_64": "64 years", + "n05000012__age_65": "65 years", + "n05000012__age_66": "66 years", + "n05000012__age_67": "67 years", + "n05000012__age_68": "68 years", + "n05000012__age_69": "69 years", + "n05000012__age_7": "7 years", + "n05000012__age_70": "70 years", + "n05000012__age_71": "71 years", + "n05000012__age_72": "72 years", + "n05000012__age_73": "73 years", + "n05000012__age_74": "74 years", + "n05000012__age_75": "75 years", + "n05000012__age_76": "76 years", + "n05000012__age_77": "77 years", + "n05000012__age_78": "78 years", + "n05000012__age_79": "79 years", + "n05000012__age_8": "8 years", + "n05000012__age_80": "80 years", + "n05000012__age_81": "81 years", + "n05000012__age_82": "82 years", + "n05000012__age_83": "83 years", + "n05000012__age_84": "84 years", + "n05000012__age_85": "85 years", + "n05000012__age_86": "86 years", + "n05000012__age_87": "87 years", + "n05000012__age_88": "88 years", + "n05000012__age_89": "89 years", + "n05000012__age_9": "9 years", + "n05000012__age_90": "90 years", + "n05000012__age_91": "91 years", + "n05000012__age_92": "92 years", + "n05000012__age_93": "93 years", + "n05000012__age_94": "94 years", + "n05000012__age_95": "95 years", + "n05000012__age_96": "96 years", + "n05000012__age_97": "97 years", + "n05000012__age_98": "98 years", + "n05000012__age_99": "99 years", + "n05000013__age_0": "0 years", + "n05000013__age_1": "1 year", + "n05000013__age_10": "10 years", + "n05000013__age_100": "100+ years", + "n05000013__age_11": "11 years", + "n05000013__age_12": "12 years", + "n05000013__age_13": "13 years", + "n05000013__age_14": "14 years", + "n05000013__age_15": "15 years", + "n05000013__age_16": "16 years", + "n05000013__age_17": "17 years", + "n05000013__age_18": "18 years", + "n05000013__age_19": "19 years", + "n05000013__age_2": "2 years", + "n05000013__age_20": "20 years", + "n05000013__age_21": "21 years", + "n05000013__age_22": "22 years", + "n05000013__age_23": "23 years", + "n05000013__age_24": "24 years", + "n05000013__age_25": "25 years", + "n05000013__age_26": "26 years", + "n05000013__age_27": "27 years", + "n05000013__age_28": "28 years", + "n05000013__age_29": "29 years", + "n05000013__age_3": "3 years", + "n05000013__age_30": "30 years", + "n05000013__age_31": "31 years", + "n05000013__age_32": "32 years", + "n05000013__age_33": "33 years", + "n05000013__age_34": "34 years", + "n05000013__age_35": "35 years", + "n05000013__age_36": "36 years", + "n05000013__age_37": "37 years", + "n05000013__age_38": "38 years", + "n05000013__age_39": "39 years", + "n05000013__age_4": "4 years", + "n05000013__age_40": "40 years", + "n05000013__age_41": "41 years", + "n05000013__age_42": "42 years", + "n05000013__age_43": "43 years", + "n05000013__age_44": "44 years", + "n05000013__age_45": "45 years", + "n05000013__age_46": "46 years", + "n05000013__age_47": "47 years", + "n05000013__age_48": "48 years", + "n05000013__age_49": "49 years", + "n05000013__age_5": "5 years", + "n05000013__age_50": "50 years", + "n05000013__age_51": "51 years", + "n05000013__age_52": "52 years", + "n05000013__age_53": "53 years", + "n05000013__age_54": "54 years", + "n05000013__age_55": "55 years", + "n05000013__age_56": "56 years", + "n05000013__age_57": "57 years", + "n05000013__age_58": "58 years", + "n05000013__age_59": "59 years", + "n05000013__age_6": "6 years", + "n05000013__age_60": "60 years", + "n05000013__age_61": "61 years", + "n05000013__age_62": "62 years", + "n05000013__age_63": "63 years", + "n05000013__age_64": "64 years", + "n05000013__age_65": "65 years", + "n05000013__age_66": "66 years", + "n05000013__age_67": "67 years", + "n05000013__age_68": "68 years", + "n05000013__age_69": "69 years", + "n05000013__age_7": "7 years", + "n05000013__age_70": "70 years", + "n05000013__age_71": "71 years", + "n05000013__age_72": "72 years", + "n05000013__age_73": "73 years", + "n05000013__age_74": "74 years", + "n05000013__age_75": "75 years", + "n05000013__age_76": "76 years", + "n05000013__age_77": "77 years", + "n05000013__age_78": "78 years", + "n05000013__age_79": "79 years", + "n05000013__age_8": "8 years", + "n05000013__age_80": "80 years", + "n05000013__age_81": "81 years", + "n05000013__age_82": "82 years", + "n05000013__age_83": "83 years", + "n05000013__age_84": "84 years", + "n05000013__age_85": "85 years", + "n05000013__age_86": "86 years", + "n05000013__age_87": "87 years", + "n05000013__age_88": "88 years", + "n05000013__age_89": "89 years", + "n05000013__age_9": "9 years", + "n05000013__age_90": "90 years", + "n05000013__age_91": "91 years", + "n05000013__age_92": "92 years", + "n05000013__age_93": "93 years", + "n05000013__age_94": "94 years", + "n05000013__age_95": "95 years", + "n05000013__age_96": "96 years", + "n05000013__age_97": "97 years", + "n05000013__age_98": "98 years", + "n05000013__age_99": "99 years", + "n05000014__age_0": "0 years", + "n05000014__age_1": "1 year", + "n05000014__age_10": "10 years", + "n05000014__age_100": "100+ years", + "n05000014__age_11": "11 years", + "n05000014__age_12": "12 years", + "n05000014__age_13": "13 years", + "n05000014__age_14": "14 years", + "n05000014__age_15": "15 years", + "n05000014__age_16": "16 years", + "n05000014__age_17": "17 years", + "n05000014__age_18": "18 years", + "n05000014__age_19": "19 years", + "n05000014__age_2": "2 years", + "n05000014__age_20": "20 years", + "n05000014__age_21": "21 years", + "n05000014__age_22": "22 years", + "n05000014__age_23": "23 years", + "n05000014__age_24": "24 years", + "n05000014__age_25": "25 years", + "n05000014__age_26": "26 years", + "n05000014__age_27": "27 years", + "n05000014__age_28": "28 years", + "n05000014__age_29": "29 years", + "n05000014__age_3": "3 years", + "n05000014__age_30": "30 years", + "n05000014__age_31": "31 years", + "n05000014__age_32": "32 years", + "n05000014__age_33": "33 years", + "n05000014__age_34": "34 years", + "n05000014__age_35": "35 years", + "n05000014__age_36": "36 years", + "n05000014__age_37": "37 years", + "n05000014__age_38": "38 years", + "n05000014__age_39": "39 years", + "n05000014__age_4": "4 years", + "n05000014__age_40": "40 years", + "n05000014__age_41": "41 years", + "n05000014__age_42": "42 years", + "n05000014__age_43": "43 years", + "n05000014__age_44": "44 years", + "n05000014__age_45": "45 years", + "n05000014__age_46": "46 years", + "n05000014__age_47": "47 years", + "n05000014__age_48": "48 years", + "n05000014__age_49": "49 years", + "n05000014__age_5": "5 years", + "n05000014__age_50": "50 years", + "n05000014__age_51": "51 years", + "n05000014__age_52": "52 years", + "n05000014__age_53": "53 years", + "n05000014__age_54": "54 years", + "n05000014__age_55": "55 years", + "n05000014__age_56": "56 years", + "n05000014__age_57": "57 years", + "n05000014__age_58": "58 years", + "n05000014__age_59": "59 years", + "n05000014__age_6": "6 years", + "n05000014__age_60": "60 years", + "n05000014__age_61": "61 years", + "n05000014__age_62": "62 years", + "n05000014__age_63": "63 years", + "n05000014__age_64": "64 years", + "n05000014__age_65": "65 years", + "n05000014__age_66": "66 years", + "n05000014__age_67": "67 years", + "n05000014__age_68": "68 years", + "n05000014__age_69": "69 years", + "n05000014__age_7": "7 years", + "n05000014__age_70": "70 years", + "n05000014__age_71": "71 years", + "n05000014__age_72": "72 years", + "n05000014__age_73": "73 years", + "n05000014__age_74": "74 years", + "n05000014__age_75": "75 years", + "n05000014__age_76": "76 years", + "n05000014__age_77": "77 years", + "n05000014__age_78": "78 years", + "n05000014__age_79": "79 years", + "n05000014__age_8": "8 years", + "n05000014__age_80": "80 years", + "n05000014__age_81": "81 years", + "n05000014__age_82": "82 years", + "n05000014__age_83": "83 years", + "n05000014__age_84": "84 years", + "n05000014__age_85": "85 years", + "n05000014__age_86": "86 years", + "n05000014__age_87": "87 years", + "n05000014__age_88": "88 years", + "n05000014__age_89": "89 years", + "n05000014__age_9": "9 years", + "n05000014__age_90": "90 years", + "n05000014__age_91": "91 years", + "n05000014__age_92": "92 years", + "n05000014__age_93": "93 years", + "n05000014__age_94": "94 years", + "n05000014__age_95": "95 years", + "n05000014__age_96": "96 years", + "n05000014__age_97": "97 years", + "n05000014__age_98": "98 years", + "n05000014__age_99": "99 years", + "n05000015__age_0": "0 years", + "n05000015__age_1": "1 year", + "n05000015__age_10": "10 years", + "n05000015__age_100": "100+ years", + "n05000015__age_11": "11 years", + "n05000015__age_12": "12 years", + "n05000015__age_13": "13 years", + "n05000015__age_14": "14 years", + "n05000015__age_15": "15 years", + "n05000015__age_16": "16 years", + "n05000015__age_17": "17 years", + "n05000015__age_18": "18 years", + "n05000015__age_19": "19 years", + "n05000015__age_2": "2 years", + "n05000015__age_20": "20 years", + "n05000015__age_21": "21 years", + "n05000015__age_22": "22 years", + "n05000015__age_23": "23 years", + "n05000015__age_24": "24 years", + "n05000015__age_25": "25 years", + "n05000015__age_26": "26 years", + "n05000015__age_27": "27 years", + "n05000015__age_28": "28 years", + "n05000015__age_29": "29 years", + "n05000015__age_3": "3 years", + "n05000015__age_30": "30 years", + "n05000015__age_31": "31 years", + "n05000015__age_32": "32 years", + "n05000015__age_33": "33 years", + "n05000015__age_34": "34 years", + "n05000015__age_35": "35 years", + "n05000015__age_36": "36 years", + "n05000015__age_37": "37 years", + "n05000015__age_38": "38 years", + "n05000015__age_39": "39 years", + "n05000015__age_4": "4 years", + "n05000015__age_40": "40 years", + "n05000015__age_41": "41 years", + "n05000015__age_42": "42 years", + "n05000015__age_43": "43 years", + "n05000015__age_44": "44 years", + "n05000015__age_45": "45 years", + "n05000015__age_46": "46 years", + "n05000015__age_47": "47 years", + "n05000015__age_48": "48 years", + "n05000015__age_49": "49 years", + "n05000015__age_5": "5 years", + "n05000015__age_50": "50 years", + "n05000015__age_51": "51 years", + "n05000015__age_52": "52 years", + "n05000015__age_53": "53 years", + "n05000015__age_54": "54 years", + "n05000015__age_55": "55 years", + "n05000015__age_56": "56 years", + "n05000015__age_57": "57 years", + "n05000015__age_58": "58 years", + "n05000015__age_59": "59 years", + "n05000015__age_6": "6 years", + "n05000015__age_60": "60 years", + "n05000015__age_61": "61 years", + "n05000015__age_62": "62 years", + "n05000015__age_63": "63 years", + "n05000015__age_64": "64 years", + "n05000015__age_65": "65 years", + "n05000015__age_66": "66 years", + "n05000015__age_67": "67 years", + "n05000015__age_68": "68 years", + "n05000015__age_69": "69 years", + "n05000015__age_7": "7 years", + "n05000015__age_70": "70 years", + "n05000015__age_71": "71 years", + "n05000015__age_72": "72 years", + "n05000015__age_73": "73 years", + "n05000015__age_74": "74 years", + "n05000015__age_75": "75 years", + "n05000015__age_76": "76 years", + "n05000015__age_77": "77 years", + "n05000015__age_78": "78 years", + "n05000015__age_79": "79 years", + "n05000015__age_8": "8 years", + "n05000015__age_80": "80 years", + "n05000015__age_81": "81 years", + "n05000015__age_82": "82 years", + "n05000015__age_83": "83 years", + "n05000015__age_84": "84 years", + "n05000015__age_85": "85 years", + "n05000015__age_86": "86 years", + "n05000015__age_87": "87 years", + "n05000015__age_88": "88 years", + "n05000015__age_89": "89 years", + "n05000015__age_9": "9 years", + "n05000015__age_90": "90 years", + "n05000015__age_91": "91 years", + "n05000015__age_92": "92 years", + "n05000015__age_93": "93 years", + "n05000015__age_94": "94 years", + "n05000015__age_95": "95 years", + "n05000015__age_96": "96 years", + "n05000015__age_97": "97 years", + "n05000015__age_98": "98 years", + "n05000015__age_99": "99 years", + "n05000016__age_0": "0 years", + "n05000016__age_1": "1 year", + "n05000016__age_10": "10 years", + "n05000016__age_100": "100+ years", + "n05000016__age_11": "11 years", + "n05000016__age_12": "12 years", + "n05000016__age_13": "13 years", + "n05000016__age_14": "14 years", + "n05000016__age_15": "15 years", + "n05000016__age_16": "16 years", + "n05000016__age_17": "17 years", + "n05000016__age_18": "18 years", + "n05000016__age_19": "19 years", + "n05000016__age_2": "2 years", + "n05000016__age_20": "20 years", + "n05000016__age_21": "21 years", + "n05000016__age_22": "22 years", + "n05000016__age_23": "23 years", + "n05000016__age_24": "24 years", + "n05000016__age_25": "25 years", + "n05000016__age_26": "26 years", + "n05000016__age_27": "27 years", + "n05000016__age_28": "28 years", + "n05000016__age_29": "29 years", + "n05000016__age_3": "3 years", + "n05000016__age_30": "30 years", + "n05000016__age_31": "31 years", + "n05000016__age_32": "32 years", + "n05000016__age_33": "33 years", + "n05000016__age_34": "34 years", + "n05000016__age_35": "35 years", + "n05000016__age_36": "36 years", + "n05000016__age_37": "37 years", + "n05000016__age_38": "38 years", + "n05000016__age_39": "39 years", + "n05000016__age_4": "4 years", + "n05000016__age_40": "40 years", + "n05000016__age_41": "41 years", + "n05000016__age_42": "42 years", + "n05000016__age_43": "43 years", + "n05000016__age_44": "44 years", + "n05000016__age_45": "45 years", + "n05000016__age_46": "46 years", + "n05000016__age_47": "47 years", + "n05000016__age_48": "48 years", + "n05000016__age_49": "49 years", + "n05000016__age_5": "5 years", + "n05000016__age_50": "50 years", + "n05000016__age_51": "51 years", + "n05000016__age_52": "52 years", + "n05000016__age_53": "53 years", + "n05000016__age_54": "54 years", + "n05000016__age_55": "55 years", + "n05000016__age_56": "56 years", + "n05000016__age_57": "57 years", + "n05000016__age_58": "58 years", + "n05000016__age_59": "59 years", + "n05000016__age_6": "6 years", + "n05000016__age_60": "60 years", + "n05000016__age_61": "61 years", + "n05000016__age_62": "62 years", + "n05000016__age_63": "63 years", + "n05000016__age_64": "64 years", + "n05000016__age_65": "65 years", + "n05000016__age_66": "66 years", + "n05000016__age_67": "67 years", + "n05000016__age_68": "68 years", + "n05000016__age_69": "69 years", + "n05000016__age_7": "7 years", + "n05000016__age_70": "70 years", + "n05000016__age_71": "71 years", + "n05000016__age_72": "72 years", + "n05000016__age_73": "73 years", + "n05000016__age_74": "74 years", + "n05000016__age_75": "75 years", + "n05000016__age_76": "76 years", + "n05000016__age_77": "77 years", + "n05000016__age_78": "78 years", + "n05000016__age_79": "79 years", + "n05000016__age_8": "8 years", + "n05000016__age_80": "80 years", + "n05000016__age_81": "81 years", + "n05000016__age_82": "82 years", + "n05000016__age_83": "83 years", + "n05000016__age_84": "84 years", + "n05000016__age_85": "85 years", + "n05000016__age_86": "86 years", + "n05000016__age_87": "87 years", + "n05000016__age_88": "88 years", + "n05000016__age_89": "89 years", + "n05000016__age_9": "9 years", + "n05000016__age_90": "90 years", + "n05000016__age_91": "91 years", + "n05000016__age_92": "92 years", + "n05000016__age_93": "93 years", + "n05000016__age_94": "94 years", + "n05000016__age_95": "95 years", + "n05000016__age_96": "96 years", + "n05000016__age_97": "97 years", + "n05000016__age_98": "98 years", + "n05000016__age_99": "99 years", + "n05000017__age_0": "0 years", + "n05000017__age_1": "1 year", + "n05000017__age_10": "10 years", + "n05000017__age_100": "100+ years", + "n05000017__age_11": "11 years", + "n05000017__age_12": "12 years", + "n05000017__age_13": "13 years", + "n05000017__age_14": "14 years", + "n05000017__age_15": "15 years", + "n05000017__age_16": "16 years", + "n05000017__age_17": "17 years", + "n05000017__age_18": "18 years", + "n05000017__age_19": "19 years", + "n05000017__age_2": "2 years", + "n05000017__age_20": "20 years", + "n05000017__age_21": "21 years", + "n05000017__age_22": "22 years", + "n05000017__age_23": "23 years", + "n05000017__age_24": "24 years", + "n05000017__age_25": "25 years", + "n05000017__age_26": "26 years", + "n05000017__age_27": "27 years", + "n05000017__age_28": "28 years", + "n05000017__age_29": "29 years", + "n05000017__age_3": "3 years", + "n05000017__age_30": "30 years", + "n05000017__age_31": "31 years", + "n05000017__age_32": "32 years", + "n05000017__age_33": "33 years", + "n05000017__age_34": "34 years", + "n05000017__age_35": "35 years", + "n05000017__age_36": "36 years", + "n05000017__age_37": "37 years", + "n05000017__age_38": "38 years", + "n05000017__age_39": "39 years", + "n05000017__age_4": "4 years", + "n05000017__age_40": "40 years", + "n05000017__age_41": "41 years", + "n05000017__age_42": "42 years", + "n05000017__age_43": "43 years", + "n05000017__age_44": "44 years", + "n05000017__age_45": "45 years", + "n05000017__age_46": "46 years", + "n05000017__age_47": "47 years", + "n05000017__age_48": "48 years", + "n05000017__age_49": "49 years", + "n05000017__age_5": "5 years", + "n05000017__age_50": "50 years", + "n05000017__age_51": "51 years", + "n05000017__age_52": "52 years", + "n05000017__age_53": "53 years", + "n05000017__age_54": "54 years", + "n05000017__age_55": "55 years", + "n05000017__age_56": "56 years", + "n05000017__age_57": "57 years", + "n05000017__age_58": "58 years", + "n05000017__age_59": "59 years", + "n05000017__age_6": "6 years", + "n05000017__age_60": "60 years", + "n05000017__age_61": "61 years", + "n05000017__age_62": "62 years", + "n05000017__age_63": "63 years", + "n05000017__age_64": "64 years", + "n05000017__age_65": "65 years", + "n05000017__age_66": "66 years", + "n05000017__age_67": "67 years", + "n05000017__age_68": "68 years", + "n05000017__age_69": "69 years", + "n05000017__age_7": "7 years", + "n05000017__age_70": "70 years", + "n05000017__age_71": "71 years", + "n05000017__age_72": "72 years", + "n05000017__age_73": "73 years", + "n05000017__age_74": "74 years", + "n05000017__age_75": "75 years", + "n05000017__age_76": "76 years", + "n05000017__age_77": "77 years", + "n05000017__age_78": "78 years", + "n05000017__age_79": "79 years", + "n05000017__age_8": "8 years", + "n05000017__age_80": "80 years", + "n05000017__age_81": "81 years", + "n05000017__age_82": "82 years", + "n05000017__age_83": "83 years", + "n05000017__age_84": "84 years", + "n05000017__age_85": "85 years", + "n05000017__age_86": "86 years", + "n05000017__age_87": "87 years", + "n05000017__age_88": "88 years", + "n05000017__age_89": "89 years", + "n05000017__age_9": "9 years", + "n05000017__age_90": "90 years", + "n05000017__age_91": "91 years", + "n05000017__age_92": "92 years", + "n05000017__age_93": "93 years", + "n05000017__age_94": "94 years", + "n05000017__age_95": "95 years", + "n05000017__age_96": "96 years", + "n05000017__age_97": "97 years", + "n05000017__age_98": "98 years", + "n05000017__age_99": "99 years", + "n05000018__age_0": "0 years", + "n05000018__age_1": "1 year", + "n05000018__age_10": "10 years", + "n05000018__age_100": "100+ years", + "n05000018__age_11": "11 years", + "n05000018__age_12": "12 years", + "n05000018__age_13": "13 years", + "n05000018__age_14": "14 years", + "n05000018__age_15": "15 years", + "n05000018__age_16": "16 years", + "n05000018__age_17": "17 years", + "n05000018__age_18": "18 years", + "n05000018__age_19": "19 years", + "n05000018__age_2": "2 years", + "n05000018__age_20": "20 years", + "n05000018__age_21": "21 years", + "n05000018__age_22": "22 years", + "n05000018__age_23": "23 years", + "n05000018__age_24": "24 years", + "n05000018__age_25": "25 years", + "n05000018__age_26": "26 years", + "n05000018__age_27": "27 years", + "n05000018__age_28": "28 years", + "n05000018__age_29": "29 years", + "n05000018__age_3": "3 years", + "n05000018__age_30": "30 years", + "n05000018__age_31": "31 years", + "n05000018__age_32": "32 years", + "n05000018__age_33": "33 years", + "n05000018__age_34": "34 years", + "n05000018__age_35": "35 years", + "n05000018__age_36": "36 years", + "n05000018__age_37": "37 years", + "n05000018__age_38": "38 years", + "n05000018__age_39": "39 years", + "n05000018__age_4": "4 years", + "n05000018__age_40": "40 years", + "n05000018__age_41": "41 years", + "n05000018__age_42": "42 years", + "n05000018__age_43": "43 years", + "n05000018__age_44": "44 years", + "n05000018__age_45": "45 years", + "n05000018__age_46": "46 years", + "n05000018__age_47": "47 years", + "n05000018__age_48": "48 years", + "n05000018__age_49": "49 years", + "n05000018__age_5": "5 years", + "n05000018__age_50": "50 years", + "n05000018__age_51": "51 years", + "n05000018__age_52": "52 years", + "n05000018__age_53": "53 years", + "n05000018__age_54": "54 years", + "n05000018__age_55": "55 years", + "n05000018__age_56": "56 years", + "n05000018__age_57": "57 years", + "n05000018__age_58": "58 years", + "n05000018__age_59": "59 years", + "n05000018__age_6": "6 years", + "n05000018__age_60": "60 years", + "n05000018__age_61": "61 years", + "n05000018__age_62": "62 years", + "n05000018__age_63": "63 years", + "n05000018__age_64": "64 years", + "n05000018__age_65": "65 years", + "n05000018__age_66": "66 years", + "n05000018__age_67": "67 years", + "n05000018__age_68": "68 years", + "n05000018__age_69": "69 years", + "n05000018__age_7": "7 years", + "n05000018__age_70": "70 years", + "n05000018__age_71": "71 years", + "n05000018__age_72": "72 years", + "n05000018__age_73": "73 years", + "n05000018__age_74": "74 years", + "n05000018__age_75": "75 years", + "n05000018__age_76": "76 years", + "n05000018__age_77": "77 years", + "n05000018__age_78": "78 years", + "n05000018__age_79": "79 years", + "n05000018__age_8": "8 years", + "n05000018__age_80": "80 years", + "n05000018__age_81": "81 years", + "n05000018__age_82": "82 years", + "n05000018__age_83": "83 years", + "n05000018__age_84": "84 years", + "n05000018__age_85": "85 years", + "n05000018__age_86": "86 years", + "n05000018__age_87": "87 years", + "n05000018__age_88": "88 years", + "n05000018__age_89": "89 years", + "n05000018__age_9": "9 years", + "n05000018__age_90": "90 years", + "n05000018__age_91": "91 years", + "n05000018__age_92": "92 years", + "n05000018__age_93": "93 years", + "n05000018__age_94": "94 years", + "n05000018__age_95": "95 years", + "n05000018__age_96": "96 years", + "n05000018__age_97": "97 years", + "n05000018__age_98": "98 years", + "n05000018__age_99": "99 years", + "n09000001__age_0": "0 years", + "n09000001__age_1": "1 year", + "n09000001__age_10": "10 years", + "n09000001__age_100": "100+ years", + "n09000001__age_11": "11 years", + "n09000001__age_12": "12 years", + "n09000001__age_13": "13 years", + "n09000001__age_14": "14 years", + "n09000001__age_15": "15 years", + "n09000001__age_16": "16 years", + "n09000001__age_17": "17 years", + "n09000001__age_18": "18 years", + "n09000001__age_19": "19 years", + "n09000001__age_2": "2 years", + "n09000001__age_20": "20 years", + "n09000001__age_21": "21 years", + "n09000001__age_22": "22 years", + "n09000001__age_23": "23 years", + "n09000001__age_24": "24 years", + "n09000001__age_25": "25 years", + "n09000001__age_26": "26 years", + "n09000001__age_27": "27 years", + "n09000001__age_28": "28 years", + "n09000001__age_29": "29 years", + "n09000001__age_3": "3 years", + "n09000001__age_30": "30 years", + "n09000001__age_31": "31 years", + "n09000001__age_32": "32 years", + "n09000001__age_33": "33 years", + "n09000001__age_34": "34 years", + "n09000001__age_35": "35 years", + "n09000001__age_36": "36 years", + "n09000001__age_37": "37 years", + "n09000001__age_38": "38 years", + "n09000001__age_39": "39 years", + "n09000001__age_4": "4 years", + "n09000001__age_40": "40 years", + "n09000001__age_41": "41 years", + "n09000001__age_42": "42 years", + "n09000001__age_43": "43 years", + "n09000001__age_44": "44 years", + "n09000001__age_45": "45 years", + "n09000001__age_46": "46 years", + "n09000001__age_47": "47 years", + "n09000001__age_48": "48 years", + "n09000001__age_49": "49 years", + "n09000001__age_5": "5 years", + "n09000001__age_50": "50 years", + "n09000001__age_51": "51 years", + "n09000001__age_52": "52 years", + "n09000001__age_53": "53 years", + "n09000001__age_54": "54 years", + "n09000001__age_55": "55 years", + "n09000001__age_56": "56 years", + "n09000001__age_57": "57 years", + "n09000001__age_58": "58 years", + "n09000001__age_59": "59 years", + "n09000001__age_6": "6 years", + "n09000001__age_60": "60 years", + "n09000001__age_61": "61 years", + "n09000001__age_62": "62 years", + "n09000001__age_63": "63 years", + "n09000001__age_64": "64 years", + "n09000001__age_65": "65 years", + "n09000001__age_66": "66 years", + "n09000001__age_67": "67 years", + "n09000001__age_68": "68 years", + "n09000001__age_69": "69 years", + "n09000001__age_7": "7 years", + "n09000001__age_70": "70 years", + "n09000001__age_71": "71 years", + "n09000001__age_72": "72 years", + "n09000001__age_73": "73 years", + "n09000001__age_74": "74 years", + "n09000001__age_75": "75 years", + "n09000001__age_76": "76 years", + "n09000001__age_77": "77 years", + "n09000001__age_78": "78 years", + "n09000001__age_79": "79 years", + "n09000001__age_8": "8 years", + "n09000001__age_80": "80 years", + "n09000001__age_81": "81 years", + "n09000001__age_82": "82 years", + "n09000001__age_83": "83 years", + "n09000001__age_84": "84 years", + "n09000001__age_85": "85 years", + "n09000001__age_86": "86 years", + "n09000001__age_87": "87 years", + "n09000001__age_88": "88 years", + "n09000001__age_89": "89 years", + "n09000001__age_9": "9 years", + "n09000001__age_90": "90 years", + "n09000001__age_91": "91 years", + "n09000001__age_92": "92 years", + "n09000001__age_93": "93 years", + "n09000001__age_94": "94 years", + "n09000001__age_95": "95 years", + "n09000001__age_96": "96 years", + "n09000001__age_97": "97 years", + "n09000001__age_98": "98 years", + "n09000001__age_99": "99 years", + "n09000002__age_0": "0 years", + "n09000002__age_1": "1 year", + "n09000002__age_10": "10 years", + "n09000002__age_100": "100+ years", + "n09000002__age_11": "11 years", + "n09000002__age_12": "12 years", + "n09000002__age_13": "13 years", + "n09000002__age_14": "14 years", + "n09000002__age_15": "15 years", + "n09000002__age_16": "16 years", + "n09000002__age_17": "17 years", + "n09000002__age_18": "18 years", + "n09000002__age_19": "19 years", + "n09000002__age_2": "2 years", + "n09000002__age_20": "20 years", + "n09000002__age_21": "21 years", + "n09000002__age_22": "22 years", + "n09000002__age_23": "23 years", + "n09000002__age_24": "24 years", + "n09000002__age_25": "25 years", + "n09000002__age_26": "26 years", + "n09000002__age_27": "27 years", + "n09000002__age_28": "28 years", + "n09000002__age_29": "29 years", + "n09000002__age_3": "3 years", + "n09000002__age_30": "30 years", + "n09000002__age_31": "31 years", + "n09000002__age_32": "32 years", + "n09000002__age_33": "33 years", + "n09000002__age_34": "34 years", + "n09000002__age_35": "35 years", + "n09000002__age_36": "36 years", + "n09000002__age_37": "37 years", + "n09000002__age_38": "38 years", + "n09000002__age_39": "39 years", + "n09000002__age_4": "4 years", + "n09000002__age_40": "40 years", + "n09000002__age_41": "41 years", + "n09000002__age_42": "42 years", + "n09000002__age_43": "43 years", + "n09000002__age_44": "44 years", + "n09000002__age_45": "45 years", + "n09000002__age_46": "46 years", + "n09000002__age_47": "47 years", + "n09000002__age_48": "48 years", + "n09000002__age_49": "49 years", + "n09000002__age_5": "5 years", + "n09000002__age_50": "50 years", + "n09000002__age_51": "51 years", + "n09000002__age_52": "52 years", + "n09000002__age_53": "53 years", + "n09000002__age_54": "54 years", + "n09000002__age_55": "55 years", + "n09000002__age_56": "56 years", + "n09000002__age_57": "57 years", + "n09000002__age_58": "58 years", + "n09000002__age_59": "59 years", + "n09000002__age_6": "6 years", + "n09000002__age_60": "60 years", + "n09000002__age_61": "61 years", + "n09000002__age_62": "62 years", + "n09000002__age_63": "63 years", + "n09000002__age_64": "64 years", + "n09000002__age_65": "65 years", + "n09000002__age_66": "66 years", + "n09000002__age_67": "67 years", + "n09000002__age_68": "68 years", + "n09000002__age_69": "69 years", + "n09000002__age_7": "7 years", + "n09000002__age_70": "70 years", + "n09000002__age_71": "71 years", + "n09000002__age_72": "72 years", + "n09000002__age_73": "73 years", + "n09000002__age_74": "74 years", + "n09000002__age_75": "75 years", + "n09000002__age_76": "76 years", + "n09000002__age_77": "77 years", + "n09000002__age_78": "78 years", + "n09000002__age_79": "79 years", + "n09000002__age_8": "8 years", + "n09000002__age_80": "80 years", + "n09000002__age_81": "81 years", + "n09000002__age_82": "82 years", + "n09000002__age_83": "83 years", + "n09000002__age_84": "84 years", + "n09000002__age_85": "85 years", + "n09000002__age_86": "86 years", + "n09000002__age_87": "87 years", + "n09000002__age_88": "88 years", + "n09000002__age_89": "89 years", + "n09000002__age_9": "9 years", + "n09000002__age_90": "90 years", + "n09000002__age_91": "91 years", + "n09000002__age_92": "92 years", + "n09000002__age_93": "93 years", + "n09000002__age_94": "94 years", + "n09000002__age_95": "95 years", + "n09000002__age_96": "96 years", + "n09000002__age_97": "97 years", + "n09000002__age_98": "98 years", + "n09000002__age_99": "99 years", + "n09000003__age_0": "0 years", + "n09000003__age_1": "1 year", + "n09000003__age_10": "10 years", + "n09000003__age_100": "100+ years", + "n09000003__age_11": "11 years", + "n09000003__age_12": "12 years", + "n09000003__age_13": "13 years", + "n09000003__age_14": "14 years", + "n09000003__age_15": "15 years", + "n09000003__age_16": "16 years", + "n09000003__age_17": "17 years", + "n09000003__age_18": "18 years", + "n09000003__age_19": "19 years", + "n09000003__age_2": "2 years", + "n09000003__age_20": "20 years", + "n09000003__age_21": "21 years", + "n09000003__age_22": "22 years", + "n09000003__age_23": "23 years", + "n09000003__age_24": "24 years", + "n09000003__age_25": "25 years", + "n09000003__age_26": "26 years", + "n09000003__age_27": "27 years", + "n09000003__age_28": "28 years", + "n09000003__age_29": "29 years", + "n09000003__age_3": "3 years", + "n09000003__age_30": "30 years", + "n09000003__age_31": "31 years", + "n09000003__age_32": "32 years", + "n09000003__age_33": "33 years", + "n09000003__age_34": "34 years", + "n09000003__age_35": "35 years", + "n09000003__age_36": "36 years", + "n09000003__age_37": "37 years", + "n09000003__age_38": "38 years", + "n09000003__age_39": "39 years", + "n09000003__age_4": "4 years", + "n09000003__age_40": "40 years", + "n09000003__age_41": "41 years", + "n09000003__age_42": "42 years", + "n09000003__age_43": "43 years", + "n09000003__age_44": "44 years", + "n09000003__age_45": "45 years", + "n09000003__age_46": "46 years", + "n09000003__age_47": "47 years", + "n09000003__age_48": "48 years", + "n09000003__age_49": "49 years", + "n09000003__age_5": "5 years", + "n09000003__age_50": "50 years", + "n09000003__age_51": "51 years", + "n09000003__age_52": "52 years", + "n09000003__age_53": "53 years", + "n09000003__age_54": "54 years", + "n09000003__age_55": "55 years", + "n09000003__age_56": "56 years", + "n09000003__age_57": "57 years", + "n09000003__age_58": "58 years", + "n09000003__age_59": "59 years", + "n09000003__age_6": "6 years", + "n09000003__age_60": "60 years", + "n09000003__age_61": "61 years", + "n09000003__age_62": "62 years", + "n09000003__age_63": "63 years", + "n09000003__age_64": "64 years", + "n09000003__age_65": "65 years", + "n09000003__age_66": "66 years", + "n09000003__age_67": "67 years", + "n09000003__age_68": "68 years", + "n09000003__age_69": "69 years", + "n09000003__age_7": "7 years", + "n09000003__age_70": "70 years", + "n09000003__age_71": "71 years", + "n09000003__age_72": "72 years", + "n09000003__age_73": "73 years", + "n09000003__age_74": "74 years", + "n09000003__age_75": "75 years", + "n09000003__age_76": "76 years", + "n09000003__age_77": "77 years", + "n09000003__age_78": "78 years", + "n09000003__age_79": "79 years", + "n09000003__age_8": "8 years", + "n09000003__age_80": "80 years", + "n09000003__age_81": "81 years", + "n09000003__age_82": "82 years", + "n09000003__age_83": "83 years", + "n09000003__age_84": "84 years", + "n09000003__age_85": "85 years", + "n09000003__age_86": "86 years", + "n09000003__age_87": "87 years", + "n09000003__age_88": "88 years", + "n09000003__age_89": "89 years", + "n09000003__age_9": "9 years", + "n09000003__age_90": "90 years", + "n09000003__age_91": "91 years", + "n09000003__age_92": "92 years", + "n09000003__age_93": "93 years", + "n09000003__age_94": "94 years", + "n09000003__age_95": "95 years", + "n09000003__age_96": "96 years", + "n09000003__age_97": "97 years", + "n09000003__age_98": "98 years", + "n09000003__age_99": "99 years", + "n09000004__age_0": "0 years", + "n09000004__age_1": "1 year", + "n09000004__age_10": "10 years", + "n09000004__age_100": "100+ years", + "n09000004__age_11": "11 years", + "n09000004__age_12": "12 years", + "n09000004__age_13": "13 years", + "n09000004__age_14": "14 years", + "n09000004__age_15": "15 years", + "n09000004__age_16": "16 years", + "n09000004__age_17": "17 years", + "n09000004__age_18": "18 years", + "n09000004__age_19": "19 years", + "n09000004__age_2": "2 years", + "n09000004__age_20": "20 years", + "n09000004__age_21": "21 years", + "n09000004__age_22": "22 years", + "n09000004__age_23": "23 years", + "n09000004__age_24": "24 years", + "n09000004__age_25": "25 years", + "n09000004__age_26": "26 years", + "n09000004__age_27": "27 years", + "n09000004__age_28": "28 years", + "n09000004__age_29": "29 years", + "n09000004__age_3": "3 years", + "n09000004__age_30": "30 years", + "n09000004__age_31": "31 years", + "n09000004__age_32": "32 years", + "n09000004__age_33": "33 years", + "n09000004__age_34": "34 years", + "n09000004__age_35": "35 years", + "n09000004__age_36": "36 years", + "n09000004__age_37": "37 years", + "n09000004__age_38": "38 years", + "n09000004__age_39": "39 years", + "n09000004__age_4": "4 years", + "n09000004__age_40": "40 years", + "n09000004__age_41": "41 years", + "n09000004__age_42": "42 years", + "n09000004__age_43": "43 years", + "n09000004__age_44": "44 years", + "n09000004__age_45": "45 years", + "n09000004__age_46": "46 years", + "n09000004__age_47": "47 years", + "n09000004__age_48": "48 years", + "n09000004__age_49": "49 years", + "n09000004__age_5": "5 years", + "n09000004__age_50": "50 years", + "n09000004__age_51": "51 years", + "n09000004__age_52": "52 years", + "n09000004__age_53": "53 years", + "n09000004__age_54": "54 years", + "n09000004__age_55": "55 years", + "n09000004__age_56": "56 years", + "n09000004__age_57": "57 years", + "n09000004__age_58": "58 years", + "n09000004__age_59": "59 years", + "n09000004__age_6": "6 years", + "n09000004__age_60": "60 years", + "n09000004__age_61": "61 years", + "n09000004__age_62": "62 years", + "n09000004__age_63": "63 years", + "n09000004__age_64": "64 years", + "n09000004__age_65": "65 years", + "n09000004__age_66": "66 years", + "n09000004__age_67": "67 years", + "n09000004__age_68": "68 years", + "n09000004__age_69": "69 years", + "n09000004__age_7": "7 years", + "n09000004__age_70": "70 years", + "n09000004__age_71": "71 years", + "n09000004__age_72": "72 years", + "n09000004__age_73": "73 years", + "n09000004__age_74": "74 years", + "n09000004__age_75": "75 years", + "n09000004__age_76": "76 years", + "n09000004__age_77": "77 years", + "n09000004__age_78": "78 years", + "n09000004__age_79": "79 years", + "n09000004__age_8": "8 years", + "n09000004__age_80": "80 years", + "n09000004__age_81": "81 years", + "n09000004__age_82": "82 years", + "n09000004__age_83": "83 years", + "n09000004__age_84": "84 years", + "n09000004__age_85": "85 years", + "n09000004__age_86": "86 years", + "n09000004__age_87": "87 years", + "n09000004__age_88": "88 years", + "n09000004__age_89": "89 years", + "n09000004__age_9": "9 years", + "n09000004__age_90": "90 years", + "n09000004__age_91": "91 years", + "n09000004__age_92": "92 years", + "n09000004__age_93": "93 years", + "n09000004__age_94": "94 years", + "n09000004__age_95": "95 years", + "n09000004__age_96": "96 years", + "n09000004__age_97": "97 years", + "n09000004__age_98": "98 years", + "n09000004__age_99": "99 years", + "n09000005__age_0": "0 years", + "n09000005__age_1": "1 year", + "n09000005__age_10": "10 years", + "n09000005__age_100": "100+ years", + "n09000005__age_11": "11 years", + "n09000005__age_12": "12 years", + "n09000005__age_13": "13 years", + "n09000005__age_14": "14 years", + "n09000005__age_15": "15 years", + "n09000005__age_16": "16 years", + "n09000005__age_17": "17 years", + "n09000005__age_18": "18 years", + "n09000005__age_19": "19 years", + "n09000005__age_2": "2 years", + "n09000005__age_20": "20 years", + "n09000005__age_21": "21 years", + "n09000005__age_22": "22 years", + "n09000005__age_23": "23 years", + "n09000005__age_24": "24 years", + "n09000005__age_25": "25 years", + "n09000005__age_26": "26 years", + "n09000005__age_27": "27 years", + "n09000005__age_28": "28 years", + "n09000005__age_29": "29 years", + "n09000005__age_3": "3 years", + "n09000005__age_30": "30 years", + "n09000005__age_31": "31 years", + "n09000005__age_32": "32 years", + "n09000005__age_33": "33 years", + "n09000005__age_34": "34 years", + "n09000005__age_35": "35 years", + "n09000005__age_36": "36 years", + "n09000005__age_37": "37 years", + "n09000005__age_38": "38 years", + "n09000005__age_39": "39 years", + "n09000005__age_4": "4 years", + "n09000005__age_40": "40 years", + "n09000005__age_41": "41 years", + "n09000005__age_42": "42 years", + "n09000005__age_43": "43 years", + "n09000005__age_44": "44 years", + "n09000005__age_45": "45 years", + "n09000005__age_46": "46 years", + "n09000005__age_47": "47 years", + "n09000005__age_48": "48 years", + "n09000005__age_49": "49 years", + "n09000005__age_5": "5 years", + "n09000005__age_50": "50 years", + "n09000005__age_51": "51 years", + "n09000005__age_52": "52 years", + "n09000005__age_53": "53 years", + "n09000005__age_54": "54 years", + "n09000005__age_55": "55 years", + "n09000005__age_56": "56 years", + "n09000005__age_57": "57 years", + "n09000005__age_58": "58 years", + "n09000005__age_59": "59 years", + "n09000005__age_6": "6 years", + "n09000005__age_60": "60 years", + "n09000005__age_61": "61 years", + "n09000005__age_62": "62 years", + "n09000005__age_63": "63 years", + "n09000005__age_64": "64 years", + "n09000005__age_65": "65 years", + "n09000005__age_66": "66 years", + "n09000005__age_67": "67 years", + "n09000005__age_68": "68 years", + "n09000005__age_69": "69 years", + "n09000005__age_7": "7 years", + "n09000005__age_70": "70 years", + "n09000005__age_71": "71 years", + "n09000005__age_72": "72 years", + "n09000005__age_73": "73 years", + "n09000005__age_74": "74 years", + "n09000005__age_75": "75 years", + "n09000005__age_76": "76 years", + "n09000005__age_77": "77 years", + "n09000005__age_78": "78 years", + "n09000005__age_79": "79 years", + "n09000005__age_8": "8 years", + "n09000005__age_80": "80 years", + "n09000005__age_81": "81 years", + "n09000005__age_82": "82 years", + "n09000005__age_83": "83 years", + "n09000005__age_84": "84 years", + "n09000005__age_85": "85 years", + "n09000005__age_86": "86 years", + "n09000005__age_87": "87 years", + "n09000005__age_88": "88 years", + "n09000005__age_89": "89 years", + "n09000005__age_9": "9 years", + "n09000005__age_90": "90 years", + "n09000005__age_91": "91 years", + "n09000005__age_92": "92 years", + "n09000005__age_93": "93 years", + "n09000005__age_94": "94 years", + "n09000005__age_95": "95 years", + "n09000005__age_96": "96 years", + "n09000005__age_97": "97 years", + "n09000005__age_98": "98 years", + "n09000005__age_99": "99 years", + "n09000006__age_0": "0 years", + "n09000006__age_1": "1 year", + "n09000006__age_10": "10 years", + "n09000006__age_100": "100+ years", + "n09000006__age_11": "11 years", + "n09000006__age_12": "12 years", + "n09000006__age_13": "13 years", + "n09000006__age_14": "14 years", + "n09000006__age_15": "15 years", + "n09000006__age_16": "16 years", + "n09000006__age_17": "17 years", + "n09000006__age_18": "18 years", + "n09000006__age_19": "19 years", + "n09000006__age_2": "2 years", + "n09000006__age_20": "20 years", + "n09000006__age_21": "21 years", + "n09000006__age_22": "22 years", + "n09000006__age_23": "23 years", + "n09000006__age_24": "24 years", + "n09000006__age_25": "25 years", + "n09000006__age_26": "26 years", + "n09000006__age_27": "27 years", + "n09000006__age_28": "28 years", + "n09000006__age_29": "29 years", + "n09000006__age_3": "3 years", + "n09000006__age_30": "30 years", + "n09000006__age_31": "31 years", + "n09000006__age_32": "32 years", + "n09000006__age_33": "33 years", + "n09000006__age_34": "34 years", + "n09000006__age_35": "35 years", + "n09000006__age_36": "36 years", + "n09000006__age_37": "37 years", + "n09000006__age_38": "38 years", + "n09000006__age_39": "39 years", + "n09000006__age_4": "4 years", + "n09000006__age_40": "40 years", + "n09000006__age_41": "41 years", + "n09000006__age_42": "42 years", + "n09000006__age_43": "43 years", + "n09000006__age_44": "44 years", + "n09000006__age_45": "45 years", + "n09000006__age_46": "46 years", + "n09000006__age_47": "47 years", + "n09000006__age_48": "48 years", + "n09000006__age_49": "49 years", + "n09000006__age_5": "5 years", + "n09000006__age_50": "50 years", + "n09000006__age_51": "51 years", + "n09000006__age_52": "52 years", + "n09000006__age_53": "53 years", + "n09000006__age_54": "54 years", + "n09000006__age_55": "55 years", + "n09000006__age_56": "56 years", + "n09000006__age_57": "57 years", + "n09000006__age_58": "58 years", + "n09000006__age_59": "59 years", + "n09000006__age_6": "6 years", + "n09000006__age_60": "60 years", + "n09000006__age_61": "61 years", + "n09000006__age_62": "62 years", + "n09000006__age_63": "63 years", + "n09000006__age_64": "64 years", + "n09000006__age_65": "65 years", + "n09000006__age_66": "66 years", + "n09000006__age_67": "67 years", + "n09000006__age_68": "68 years", + "n09000006__age_69": "69 years", + "n09000006__age_7": "7 years", + "n09000006__age_70": "70 years", + "n09000006__age_71": "71 years", + "n09000006__age_72": "72 years", + "n09000006__age_73": "73 years", + "n09000006__age_74": "74 years", + "n09000006__age_75": "75 years", + "n09000006__age_76": "76 years", + "n09000006__age_77": "77 years", + "n09000006__age_78": "78 years", + "n09000006__age_79": "79 years", + "n09000006__age_8": "8 years", + "n09000006__age_80": "80 years", + "n09000006__age_81": "81 years", + "n09000006__age_82": "82 years", + "n09000006__age_83": "83 years", + "n09000006__age_84": "84 years", + "n09000006__age_85": "85 years", + "n09000006__age_86": "86 years", + "n09000006__age_87": "87 years", + "n09000006__age_88": "88 years", + "n09000006__age_89": "89 years", + "n09000006__age_9": "9 years", + "n09000006__age_90": "90 years", + "n09000006__age_91": "91 years", + "n09000006__age_92": "92 years", + "n09000006__age_93": "93 years", + "n09000006__age_94": "94 years", + "n09000006__age_95": "95 years", + "n09000006__age_96": "96 years", + "n09000006__age_97": "97 years", + "n09000006__age_98": "98 years", + "n09000006__age_99": "99 years", + "n09000007__age_0": "0 years", + "n09000007__age_1": "1 year", + "n09000007__age_10": "10 years", + "n09000007__age_100": "100+ years", + "n09000007__age_11": "11 years", + "n09000007__age_12": "12 years", + "n09000007__age_13": "13 years", + "n09000007__age_14": "14 years", + "n09000007__age_15": "15 years", + "n09000007__age_16": "16 years", + "n09000007__age_17": "17 years", + "n09000007__age_18": "18 years", + "n09000007__age_19": "19 years", + "n09000007__age_2": "2 years", + "n09000007__age_20": "20 years", + "n09000007__age_21": "21 years", + "n09000007__age_22": "22 years", + "n09000007__age_23": "23 years", + "n09000007__age_24": "24 years", + "n09000007__age_25": "25 years", + "n09000007__age_26": "26 years", + "n09000007__age_27": "27 years", + "n09000007__age_28": "28 years", + "n09000007__age_29": "29 years", + "n09000007__age_3": "3 years", + "n09000007__age_30": "30 years", + "n09000007__age_31": "31 years", + "n09000007__age_32": "32 years", + "n09000007__age_33": "33 years", + "n09000007__age_34": "34 years", + "n09000007__age_35": "35 years", + "n09000007__age_36": "36 years", + "n09000007__age_37": "37 years", + "n09000007__age_38": "38 years", + "n09000007__age_39": "39 years", + "n09000007__age_4": "4 years", + "n09000007__age_40": "40 years", + "n09000007__age_41": "41 years", + "n09000007__age_42": "42 years", + "n09000007__age_43": "43 years", + "n09000007__age_44": "44 years", + "n09000007__age_45": "45 years", + "n09000007__age_46": "46 years", + "n09000007__age_47": "47 years", + "n09000007__age_48": "48 years", + "n09000007__age_49": "49 years", + "n09000007__age_5": "5 years", + "n09000007__age_50": "50 years", + "n09000007__age_51": "51 years", + "n09000007__age_52": "52 years", + "n09000007__age_53": "53 years", + "n09000007__age_54": "54 years", + "n09000007__age_55": "55 years", + "n09000007__age_56": "56 years", + "n09000007__age_57": "57 years", + "n09000007__age_58": "58 years", + "n09000007__age_59": "59 years", + "n09000007__age_6": "6 years", + "n09000007__age_60": "60 years", + "n09000007__age_61": "61 years", + "n09000007__age_62": "62 years", + "n09000007__age_63": "63 years", + "n09000007__age_64": "64 years", + "n09000007__age_65": "65 years", + "n09000007__age_66": "66 years", + "n09000007__age_67": "67 years", + "n09000007__age_68": "68 years", + "n09000007__age_69": "69 years", + "n09000007__age_7": "7 years", + "n09000007__age_70": "70 years", + "n09000007__age_71": "71 years", + "n09000007__age_72": "72 years", + "n09000007__age_73": "73 years", + "n09000007__age_74": "74 years", + "n09000007__age_75": "75 years", + "n09000007__age_76": "76 years", + "n09000007__age_77": "77 years", + "n09000007__age_78": "78 years", + "n09000007__age_79": "79 years", + "n09000007__age_8": "8 years", + "n09000007__age_80": "80 years", + "n09000007__age_81": "81 years", + "n09000007__age_82": "82 years", + "n09000007__age_83": "83 years", + "n09000007__age_84": "84 years", + "n09000007__age_85": "85 years", + "n09000007__age_86": "86 years", + "n09000007__age_87": "87 years", + "n09000007__age_88": "88 years", + "n09000007__age_89": "89 years", + "n09000007__age_9": "9 years", + "n09000007__age_90": "90 years", + "n09000007__age_91": "91 years", + "n09000007__age_92": "92 years", + "n09000007__age_93": "93 years", + "n09000007__age_94": "94 years", + "n09000007__age_95": "95 years", + "n09000007__age_96": "96 years", + "n09000007__age_97": "97 years", + "n09000007__age_98": "98 years", + "n09000007__age_99": "99 years", + "n09000008__age_0": "0 years", + "n09000008__age_1": "1 year", + "n09000008__age_10": "10 years", + "n09000008__age_100": "100+ years", + "n09000008__age_11": "11 years", + "n09000008__age_12": "12 years", + "n09000008__age_13": "13 years", + "n09000008__age_14": "14 years", + "n09000008__age_15": "15 years", + "n09000008__age_16": "16 years", + "n09000008__age_17": "17 years", + "n09000008__age_18": "18 years", + "n09000008__age_19": "19 years", + "n09000008__age_2": "2 years", + "n09000008__age_20": "20 years", + "n09000008__age_21": "21 years", + "n09000008__age_22": "22 years", + "n09000008__age_23": "23 years", + "n09000008__age_24": "24 years", + "n09000008__age_25": "25 years", + "n09000008__age_26": "26 years", + "n09000008__age_27": "27 years", + "n09000008__age_28": "28 years", + "n09000008__age_29": "29 years", + "n09000008__age_3": "3 years", + "n09000008__age_30": "30 years", + "n09000008__age_31": "31 years", + "n09000008__age_32": "32 years", + "n09000008__age_33": "33 years", + "n09000008__age_34": "34 years", + "n09000008__age_35": "35 years", + "n09000008__age_36": "36 years", + "n09000008__age_37": "37 years", + "n09000008__age_38": "38 years", + "n09000008__age_39": "39 years", + "n09000008__age_4": "4 years", + "n09000008__age_40": "40 years", + "n09000008__age_41": "41 years", + "n09000008__age_42": "42 years", + "n09000008__age_43": "43 years", + "n09000008__age_44": "44 years", + "n09000008__age_45": "45 years", + "n09000008__age_46": "46 years", + "n09000008__age_47": "47 years", + "n09000008__age_48": "48 years", + "n09000008__age_49": "49 years", + "n09000008__age_5": "5 years", + "n09000008__age_50": "50 years", + "n09000008__age_51": "51 years", + "n09000008__age_52": "52 years", + "n09000008__age_53": "53 years", + "n09000008__age_54": "54 years", + "n09000008__age_55": "55 years", + "n09000008__age_56": "56 years", + "n09000008__age_57": "57 years", + "n09000008__age_58": "58 years", + "n09000008__age_59": "59 years", + "n09000008__age_6": "6 years", + "n09000008__age_60": "60 years", + "n09000008__age_61": "61 years", + "n09000008__age_62": "62 years", + "n09000008__age_63": "63 years", + "n09000008__age_64": "64 years", + "n09000008__age_65": "65 years", + "n09000008__age_66": "66 years", + "n09000008__age_67": "67 years", + "n09000008__age_68": "68 years", + "n09000008__age_69": "69 years", + "n09000008__age_7": "7 years", + "n09000008__age_70": "70 years", + "n09000008__age_71": "71 years", + "n09000008__age_72": "72 years", + "n09000008__age_73": "73 years", + "n09000008__age_74": "74 years", + "n09000008__age_75": "75 years", + "n09000008__age_76": "76 years", + "n09000008__age_77": "77 years", + "n09000008__age_78": "78 years", + "n09000008__age_79": "79 years", + "n09000008__age_8": "8 years", + "n09000008__age_80": "80 years", + "n09000008__age_81": "81 years", + "n09000008__age_82": "82 years", + "n09000008__age_83": "83 years", + "n09000008__age_84": "84 years", + "n09000008__age_85": "85 years", + "n09000008__age_86": "86 years", + "n09000008__age_87": "87 years", + "n09000008__age_88": "88 years", + "n09000008__age_89": "89 years", + "n09000008__age_9": "9 years", + "n09000008__age_90": "90 years", + "n09000008__age_91": "91 years", + "n09000008__age_92": "92 years", + "n09000008__age_93": "93 years", + "n09000008__age_94": "94 years", + "n09000008__age_95": "95 years", + "n09000008__age_96": "96 years", + "n09000008__age_97": "97 years", + "n09000008__age_98": "98 years", + "n09000008__age_99": "99 years", + "n09000009__age_0": "0 years", + "n09000009__age_1": "1 year", + "n09000009__age_10": "10 years", + "n09000009__age_100": "100+ years", + "n09000009__age_11": "11 years", + "n09000009__age_12": "12 years", + "n09000009__age_13": "13 years", + "n09000009__age_14": "14 years", + "n09000009__age_15": "15 years", + "n09000009__age_16": "16 years", + "n09000009__age_17": "17 years", + "n09000009__age_18": "18 years", + "n09000009__age_19": "19 years", + "n09000009__age_2": "2 years", + "n09000009__age_20": "20 years", + "n09000009__age_21": "21 years", + "n09000009__age_22": "22 years", + "n09000009__age_23": "23 years", + "n09000009__age_24": "24 years", + "n09000009__age_25": "25 years", + "n09000009__age_26": "26 years", + "n09000009__age_27": "27 years", + "n09000009__age_28": "28 years", + "n09000009__age_29": "29 years", + "n09000009__age_3": "3 years", + "n09000009__age_30": "30 years", + "n09000009__age_31": "31 years", + "n09000009__age_32": "32 years", + "n09000009__age_33": "33 years", + "n09000009__age_34": "34 years", + "n09000009__age_35": "35 years", + "n09000009__age_36": "36 years", + "n09000009__age_37": "37 years", + "n09000009__age_38": "38 years", + "n09000009__age_39": "39 years", + "n09000009__age_4": "4 years", + "n09000009__age_40": "40 years", + "n09000009__age_41": "41 years", + "n09000009__age_42": "42 years", + "n09000009__age_43": "43 years", + "n09000009__age_44": "44 years", + "n09000009__age_45": "45 years", + "n09000009__age_46": "46 years", + "n09000009__age_47": "47 years", + "n09000009__age_48": "48 years", + "n09000009__age_49": "49 years", + "n09000009__age_5": "5 years", + "n09000009__age_50": "50 years", + "n09000009__age_51": "51 years", + "n09000009__age_52": "52 years", + "n09000009__age_53": "53 years", + "n09000009__age_54": "54 years", + "n09000009__age_55": "55 years", + "n09000009__age_56": "56 years", + "n09000009__age_57": "57 years", + "n09000009__age_58": "58 years", + "n09000009__age_59": "59 years", + "n09000009__age_6": "6 years", + "n09000009__age_60": "60 years", + "n09000009__age_61": "61 years", + "n09000009__age_62": "62 years", + "n09000009__age_63": "63 years", + "n09000009__age_64": "64 years", + "n09000009__age_65": "65 years", + "n09000009__age_66": "66 years", + "n09000009__age_67": "67 years", + "n09000009__age_68": "68 years", + "n09000009__age_69": "69 years", + "n09000009__age_7": "7 years", + "n09000009__age_70": "70 years", + "n09000009__age_71": "71 years", + "n09000009__age_72": "72 years", + "n09000009__age_73": "73 years", + "n09000009__age_74": "74 years", + "n09000009__age_75": "75 years", + "n09000009__age_76": "76 years", + "n09000009__age_77": "77 years", + "n09000009__age_78": "78 years", + "n09000009__age_79": "79 years", + "n09000009__age_8": "8 years", + "n09000009__age_80": "80 years", + "n09000009__age_81": "81 years", + "n09000009__age_82": "82 years", + "n09000009__age_83": "83 years", + "n09000009__age_84": "84 years", + "n09000009__age_85": "85 years", + "n09000009__age_86": "86 years", + "n09000009__age_87": "87 years", + "n09000009__age_88": "88 years", + "n09000009__age_89": "89 years", + "n09000009__age_9": "9 years", + "n09000009__age_90": "90 years", + "n09000009__age_91": "91 years", + "n09000009__age_92": "92 years", + "n09000009__age_93": "93 years", + "n09000009__age_94": "94 years", + "n09000009__age_95": "95 years", + "n09000009__age_96": "96 years", + "n09000009__age_97": "97 years", + "n09000009__age_98": "98 years", + "n09000009__age_99": "99 years", + "n09000010__age_0": "0 years", + "n09000010__age_1": "1 year", + "n09000010__age_10": "10 years", + "n09000010__age_100": "100+ years", + "n09000010__age_11": "11 years", + "n09000010__age_12": "12 years", + "n09000010__age_13": "13 years", + "n09000010__age_14": "14 years", + "n09000010__age_15": "15 years", + "n09000010__age_16": "16 years", + "n09000010__age_17": "17 years", + "n09000010__age_18": "18 years", + "n09000010__age_19": "19 years", + "n09000010__age_2": "2 years", + "n09000010__age_20": "20 years", + "n09000010__age_21": "21 years", + "n09000010__age_22": "22 years", + "n09000010__age_23": "23 years", + "n09000010__age_24": "24 years", + "n09000010__age_25": "25 years", + "n09000010__age_26": "26 years", + "n09000010__age_27": "27 years", + "n09000010__age_28": "28 years", + "n09000010__age_29": "29 years", + "n09000010__age_3": "3 years", + "n09000010__age_30": "30 years", + "n09000010__age_31": "31 years", + "n09000010__age_32": "32 years", + "n09000010__age_33": "33 years", + "n09000010__age_34": "34 years", + "n09000010__age_35": "35 years", + "n09000010__age_36": "36 years", + "n09000010__age_37": "37 years", + "n09000010__age_38": "38 years", + "n09000010__age_39": "39 years", + "n09000010__age_4": "4 years", + "n09000010__age_40": "40 years", + "n09000010__age_41": "41 years", + "n09000010__age_42": "42 years", + "n09000010__age_43": "43 years", + "n09000010__age_44": "44 years", + "n09000010__age_45": "45 years", + "n09000010__age_46": "46 years", + "n09000010__age_47": "47 years", + "n09000010__age_48": "48 years", + "n09000010__age_49": "49 years", + "n09000010__age_5": "5 years", + "n09000010__age_50": "50 years", + "n09000010__age_51": "51 years", + "n09000010__age_52": "52 years", + "n09000010__age_53": "53 years", + "n09000010__age_54": "54 years", + "n09000010__age_55": "55 years", + "n09000010__age_56": "56 years", + "n09000010__age_57": "57 years", + "n09000010__age_58": "58 years", + "n09000010__age_59": "59 years", + "n09000010__age_6": "6 years", + "n09000010__age_60": "60 years", + "n09000010__age_61": "61 years", + "n09000010__age_62": "62 years", + "n09000010__age_63": "63 years", + "n09000010__age_64": "64 years", + "n09000010__age_65": "65 years", + "n09000010__age_66": "66 years", + "n09000010__age_67": "67 years", + "n09000010__age_68": "68 years", + "n09000010__age_69": "69 years", + "n09000010__age_7": "7 years", + "n09000010__age_70": "70 years", + "n09000010__age_71": "71 years", + "n09000010__age_72": "72 years", + "n09000010__age_73": "73 years", + "n09000010__age_74": "74 years", + "n09000010__age_75": "75 years", + "n09000010__age_76": "76 years", + "n09000010__age_77": "77 years", + "n09000010__age_78": "78 years", + "n09000010__age_79": "79 years", + "n09000010__age_8": "8 years", + "n09000010__age_80": "80 years", + "n09000010__age_81": "81 years", + "n09000010__age_82": "82 years", + "n09000010__age_83": "83 years", + "n09000010__age_84": "84 years", + "n09000010__age_85": "85 years", + "n09000010__age_86": "86 years", + "n09000010__age_87": "87 years", + "n09000010__age_88": "88 years", + "n09000010__age_89": "89 years", + "n09000010__age_9": "9 years", + "n09000010__age_90": "90 years", + "n09000010__age_91": "91 years", + "n09000010__age_92": "92 years", + "n09000010__age_93": "93 years", + "n09000010__age_94": "94 years", + "n09000010__age_95": "95 years", + "n09000010__age_96": "96 years", + "n09000010__age_97": "97 years", + "n09000010__age_98": "98 years", + "n09000010__age_99": "99 years", + "n09000011__age_0": "0 years", + "n09000011__age_1": "1 year", + "n09000011__age_10": "10 years", + "n09000011__age_100": "100+ years", + "n09000011__age_11": "11 years", + "n09000011__age_12": "12 years", + "n09000011__age_13": "13 years", + "n09000011__age_14": "14 years", + "n09000011__age_15": "15 years", + "n09000011__age_16": "16 years", + "n09000011__age_17": "17 years", + "n09000011__age_18": "18 years", + "n09000011__age_19": "19 years", + "n09000011__age_2": "2 years", + "n09000011__age_20": "20 years", + "n09000011__age_21": "21 years", + "n09000011__age_22": "22 years", + "n09000011__age_23": "23 years", + "n09000011__age_24": "24 years", + "n09000011__age_25": "25 years", + "n09000011__age_26": "26 years", + "n09000011__age_27": "27 years", + "n09000011__age_28": "28 years", + "n09000011__age_29": "29 years", + "n09000011__age_3": "3 years", + "n09000011__age_30": "30 years", + "n09000011__age_31": "31 years", + "n09000011__age_32": "32 years", + "n09000011__age_33": "33 years", + "n09000011__age_34": "34 years", + "n09000011__age_35": "35 years", + "n09000011__age_36": "36 years", + "n09000011__age_37": "37 years", + "n09000011__age_38": "38 years", + "n09000011__age_39": "39 years", + "n09000011__age_4": "4 years", + "n09000011__age_40": "40 years", + "n09000011__age_41": "41 years", + "n09000011__age_42": "42 years", + "n09000011__age_43": "43 years", + "n09000011__age_44": "44 years", + "n09000011__age_45": "45 years", + "n09000011__age_46": "46 years", + "n09000011__age_47": "47 years", + "n09000011__age_48": "48 years", + "n09000011__age_49": "49 years", + "n09000011__age_5": "5 years", + "n09000011__age_50": "50 years", + "n09000011__age_51": "51 years", + "n09000011__age_52": "52 years", + "n09000011__age_53": "53 years", + "n09000011__age_54": "54 years", + "n09000011__age_55": "55 years", + "n09000011__age_56": "56 years", + "n09000011__age_57": "57 years", + "n09000011__age_58": "58 years", + "n09000011__age_59": "59 years", + "n09000011__age_6": "6 years", + "n09000011__age_60": "60 years", + "n09000011__age_61": "61 years", + "n09000011__age_62": "62 years", + "n09000011__age_63": "63 years", + "n09000011__age_64": "64 years", + "n09000011__age_65": "65 years", + "n09000011__age_66": "66 years", + "n09000011__age_67": "67 years", + "n09000011__age_68": "68 years", + "n09000011__age_69": "69 years", + "n09000011__age_7": "7 years", + "n09000011__age_70": "70 years", + "n09000011__age_71": "71 years", + "n09000011__age_72": "72 years", + "n09000011__age_73": "73 years", + "n09000011__age_74": "74 years", + "n09000011__age_75": "75 years", + "n09000011__age_76": "76 years", + "n09000011__age_77": "77 years", + "n09000011__age_78": "78 years", + "n09000011__age_79": "79 years", + "n09000011__age_8": "8 years", + "n09000011__age_80": "80 years", + "n09000011__age_81": "81 years", + "n09000011__age_82": "82 years", + "n09000011__age_83": "83 years", + "n09000011__age_84": "84 years", + "n09000011__age_85": "85 years", + "n09000011__age_86": "86 years", + "n09000011__age_87": "87 years", + "n09000011__age_88": "88 years", + "n09000011__age_89": "89 years", + "n09000011__age_9": "9 years", + "n09000011__age_90": "90 years", + "n09000011__age_91": "91 years", + "n09000011__age_92": "92 years", + "n09000011__age_93": "93 years", + "n09000011__age_94": "94 years", + "n09000011__age_95": "95 years", + "n09000011__age_96": "96 years", + "n09000011__age_97": "97 years", + "n09000011__age_98": "98 years", + "n09000011__age_99": "99 years" + }, + "C2021_AGE_24_NAME": { + "Aged 10 to 14 years": "Aged 10 to 14 years", + "Aged 15 years": "Aged 15 years", + "Aged 16 to 17 years": "Aged 16 to 17 years", + "Aged 18 to 19 years": "Aged 18 to 19 years", + "Aged 2 years and under": "Aged 2 years and under", + "Aged 20 to 24 years": "Aged 20 to 24 years", + "Aged 25 to 29 years": "Aged 25 to 29 years", + "Aged 3 to 4 years": "Aged 3 to 4 years", + "Aged 30 to 34 years": "Aged 30 to 34 years", + "Aged 35 to 39 years": "Aged 35 to 39 years", + "Aged 40 to 44 years": "Aged 40 to 44 years", + "Aged 45 to 49 years": "Aged 45 to 49 years", + "Aged 5 to 7 years": "Aged 5 to 7 years", + "Aged 50 to 54 years": "Aged 50 to 54 years", + "Aged 55 to 59 years": "Aged 55 to 59 years", + "Aged 60 to 64 years": "Aged 60 to 64 years", + "Aged 65 years": "Aged 65 years", + "Aged 66 to 69 years": "Aged 66 to 69 years", + "Aged 70 to 74 years": "Aged 70 to 74 years", + "Aged 75 to 79 years": "Aged 75 to 79 years", + "Aged 8 to 9 years": "Aged 8 to 9 years", + "Aged 80 to 84 years": "Aged 80 to 84 years", + "Aged 85 years and over": "Aged 85 years and over", + "Total": "Total" + }, + "C2021_RESTYPE_3_NAME": { + "Lives in a communal establishment": "Lives in a communal establishment", + "Lives in a household": "Lives in a household" + }, + "C_SEX_NAME": { + "All persons": "All persons", + "Female": "Female", + "Male": "Male" + }, + "Household Type": { + "Total households": "Total households" + }, + "Residence Type Indicator": { + "Lives in a communal establishment": "Lives in a communal establishment", + "Lives in a household": "Lives in a household" + }, + "Residence Type Label": { + "Person in a communal establishment": "Person in a communal establishment", + "Person in a household": "Person in a household" + }, + "Sex": { + "All people": "All people", + "Female": "Female", + "Male": "Male" + }, + "Sex Label": { + "Female": "Female", + "Male": "Male" + }, + "accounting_basis": { + "accrual": "Accrued basis", + "cash": "Cash basis" + }, + "administering_entity": { + "state_programs": "State programs" + }, + "age": { + "0": "0", + "0_to_4": "Age 0 to 4", + "1": "1", + "10": "10", + "10_to_14": "Age 10 to 14", + "11": "11", + "12": "12", + "13": "13", + "14": "14", + "15": "15", + "15_to_19": "Age 15 to 19", + "16": "16", + "17": "17", + "18": "18", + "19": "19", + "2": "2", + "20": "20", + "20_to_24": "Age 20 to 24", + "21": "21", + "22": "22", + "23": "23", + "24": "24", + "25": "25", + "25_to_29": "Age 25 to 29", + "26": "26", + "27": "27", + "28": "28", + "29": "29", + "3": "3", + "30": "30", + "30_to_34": "Age 30 to 34", + "31": "31", + "32": "32", + "33": "33", + "34": "34", + "35": "35", + "35_to_39": "Age 35 to 39", + "36": "36", + "37": "37", + "38": "38", + "39": "39", + "4": "4", + "40": "40", + "40_to_44": "Age 40 to 44", + "41": "41", + "42": "42", + "43": "43", + "44": "44", + "45": "45", + "45_to_49": "Age 45 to 49", + "46": "46", + "47": "47", + "48": "48", + "49": "49", + "5": "5", + "50": "50", + "50_to_54": "Age 50 to 54", + "51": "51", + "52": "52", + "53": "53", + "54": "54", + "55": "55", + "55_to_59": "Age 55 to 59", + "56": "56", + "57": "57", + "58": "58", + "59": "59", + "5_to_9": "Age 5 to 9", + "6": "6", + "60": "60", + "60_to_64": "Age 60 to 64", + "61": "61", + "62": "62", + "63": "63", + "64": "64", + "65": "65", + "65_to_69": "Age 65 to 69", + "66": "66", + "67": "67", + "68": "68", + "69": "69", + "7": "7", + "70": "70", + "70_to_74": "Age 70 to 74", + "71": "71", + "72": "72", + "73": "73", + "74": "74", + "75": "75", + "75_to_79": "Age 75 to 79", + "76": "76", + "77": "77", + "78": "78", + "79": "79", + "8": "8", + "80": "80", + "80_to_84": "Age 80 to 84", + "81": "81", + "82": "82", + "83": "83", + "84": "84", + "85": "85", + "85_plus": "Age 85 plus", + "86": "86", + "87": "87", + "88": "88", + "89": "89", + "9": "9", + "90_plus": "90 and over", + "age_0_to_4": "Age 0 to 4", + "age_10_to_14": "Age 10 to 14", + "age_15_to_19": "Age 15 to 19", + "age_20": "Age 20", + "age_20_to_24": "Age 20 to 24", + "age_21": "Age 21", + "age_25_to_29": "Age 25 to 29", + "age_30_to_34": "Age 30 to 34", + "age_35_to_39": "Age 35 to 39", + "age_40_to_44": "Age 40 to 44", + "age_45_to_49": "Age 45 to 49", + "age_50_to_54": "Age 50 to 54", + "age_55_to_59": "Age 55 to 59", + "age_5_to_9": "Age 5 to 9", + "age_60_to_64": "Age 60 to 64", + "age_65_to_69": "Age 65 to 69", + "age_70_to_74": "Age 70 to 74", + "age_75_to_79": "Age 75 to 79", + "age_80_to_84": "Age 80 to 84", + "age_85_plus": "Age 85 and over", + "all": "All ages", + "northern_ireland": "Northern Ireland", + "scotland": "Scotland", + "uk": "United Kingdom", + "wales": "Wales" + }, + "age_band": { + "16 to 21": "16 to 21", + "22 to 29": "22 to 29", + "30 to 39": "30 to 39", + "40 to 49": "40 to 49", + "50 to 54": "50 to 54", + "55 to 59": "55 to 59", + "60 to 64": "60 to 64", + "65 and over": "65 and over", + "66-69": "66-69", + "70 to 74": "70 to 74", + "70-74": "70-74", + "75 to 79": "75 to 79", + "75-79": "75-79", + "80 and over": "80 and over", + "80-84": "80-84", + "85-89": "85-89", + "90 and over": "90 and over", + "age_25_to_34": "25 to 34", + "age_35_to_44": "35 to 44", + "age_45_to_54": "45 to 54", + "age_55_to_64": "55 to 64", + "age_65_to_74": "65 to 74", + "age_66_69": "Aged 66-69", + "age_70_74": "Aged 70-74", + "age_75_79": "Aged 75-79", + "age_80_84": "Aged 80-84", + "age_85_89": "Aged 85-89", + "age_90_plus": "Aged 90 and over", + "all": "All ages", + "all_ages": "All", + "up to 69": "up to 69" + }, + "age_bands_and_single_year": { + "65-69": "65-69", + "70-74": "70-74", + "75-79": "75-79", + "80-84": "80-84", + "85-89": "85-89", + "90 and over": "90 and over", + "Unknown": "Unknown", + "all": "Total" + }, + "age_name": { + "Aged 1 - 4 years": "Aged 1 - 4 years", + "Aged 10 - 14 years": "Aged 10 - 14 years", + "Aged 15 - 19 years": "Aged 15 - 19 years", + "Aged 20 - 24 years": "Aged 20 - 24 years", + "Aged 25 - 29 years": "Aged 25 - 29 years", + "Aged 30 - 34 years": "Aged 30 - 34 years", + "Aged 35 - 39 years": "Aged 35 - 39 years", + "Aged 40 - 44 years": "Aged 40 - 44 years", + "Aged 45 - 49 years": "Aged 45 - 49 years", + "Aged 5 - 9 years": "Aged 5 - 9 years", + "Aged 50 - 54 years": "Aged 50 - 54 years", + "Aged 55 - 59 years": "Aged 55 - 59 years", + "Aged 60 - 64 years": "Aged 60 - 64 years", + "Aged 65 - 69 years": "Aged 65 - 69 years", + "Aged 70 - 74 years": "Aged 70 - 74 years", + "Aged 75 - 79 years": "Aged 75 - 79 years", + "Aged 80 - 84 years": "Aged 80 - 84 years", + "Aged 85 and over": "Aged 85 and over", + "Aged under 1 year": "Aged under 1 year", + "All ages": "All ages" + }, + "agi_lower_usd": { + "1": "1", + "10000": "10000", + "100000": "100000", + "1000000": "1000000", + "10000000": "10000000", + "15000": "15000", + "1500000": "1500000", + "20000": "20000", + "200000": "200000", + "2000000": "2000000", + "25000": "25000", + "30000": "30000", + "40000": "40000", + "5000": "5000", + "50000": "50000", + "500000": "500000", + "5000000": "5000000", + "75000": "75000" + }, + "agi_upper_usd": { + "1": "1", + "10000": "10000", + "100000": "100000", + "1000000": "1000000", + "10000000": "10000000", + "15000": "15000", + "1500000": "1500000", + "20000": "20000", + "200000": "200000", + "2000000": "2000000", + "25000": "25000", + "30000": "30000", + "40000": "40000", + "5000": "5000", + "50000": "50000", + "500000": "500000", + "5000000": "5000000", + "75000": "75000" + }, + "amount": { + "all": "Total", + "£100": "£100", + "£150": "£150", + "£200": "£200", + "£250": "£250", + "£300": "£300", + "£350": "£350", + "£500": "£500", + "£600": "£600" + }, + "benefit_expense_component": { + "Accommodation Assistance": "Accommodation Assistance", + "Disability Assistance": "Disability Assistance", + "Hardship Assistance": "Hardship Assistance", + "Jobseeker Support and Emergency Benefit": "Jobseeker Support and Emergency Benefit", + "New Zealand Superannuation": "New Zealand Superannuation", + "Orphan's/Unsupported Child's Benefit": "Orphan's/Unsupported Child's Benefit", + "Sole Parent Support": "Sole Parent Support", + "Student Allowances": "Student Allowances", + "Supported Living Payment": "Supported Living Payment" + }, + "business_size_band": { + "1 to 12 employees": "1 to 12 employees", + "100 to 499 employees": "100 to 499 employees", + "1000 or more employees": "1000 or more employees", + "13 to 99 employees": "13 to 99 employees", + "500 to 999 employees": "500 to 999 employees" + }, + "c2021_hh_1_name": { + "Number of households": "Number of households" + }, + "category_of_pension": { + "Category A": "Category A", + "Category AB": "Category AB", + "Category ABL": "Category ABL", + "Category B": "Category B", + "Category BL": "Category BL", + "Category D": "Category D", + "New State Pension": "New State Pension", + "Pre-2016 State Pension": "Pre-2016 State Pension", + "all": "Total" + }, + "census_acs.county": { + "01001": "Autauga County, Alabama", + "01003": "Baldwin County, Alabama", + "01005": "Barbour County, Alabama", + "01007": "Bibb County, Alabama", + "01009": "Blount County, Alabama", + "01011": "Bullock County, Alabama", + "01013": "Butler County, Alabama", + "01015": "Calhoun County, Alabama", + "01017": "Chambers County, Alabama", + "01019": "Cherokee County, Alabama", + "01021": "Chilton County, Alabama", + "01023": "Choctaw County, Alabama", + "01025": "Clarke County, Alabama", + "01027": "Clay County, Alabama", + "01029": "Cleburne County, Alabama", + "01031": "Coffee County, Alabama", + "01033": "Colbert County, Alabama", + "01035": "Conecuh County, Alabama", + "01037": "Coosa County, Alabama", + "01039": "Covington County, Alabama", + "01041": "Crenshaw County, Alabama", + "01043": "Cullman County, Alabama", + "01045": "Dale County, Alabama", + "01047": "Dallas County, Alabama", + "01049": "DeKalb County, Alabama", + "01051": "Elmore County, Alabama", + "01053": "Escambia County, Alabama", + "01055": "Etowah County, Alabama", + "01057": "Fayette County, Alabama", + "01059": "Franklin County, Alabama", + "01061": "Geneva County, Alabama", + "01063": "Greene County, Alabama", + "01065": "Hale County, Alabama", + "01067": "Henry County, Alabama", + "01069": "Houston County, Alabama", + "01071": "Jackson County, Alabama", + "01073": "Jefferson County, Alabama", + "01075": "Lamar County, Alabama", + "01077": "Lauderdale County, Alabama", + "01079": "Lawrence County, Alabama", + "01081": "Lee County, Alabama", + "01083": "Limestone County, Alabama", + "01085": "Lowndes County, Alabama", + "01087": "Macon County, Alabama", + "01089": "Madison County, Alabama", + "01091": "Marengo County, Alabama", + "01093": "Marion County, Alabama", + "01095": "Marshall County, Alabama", + "01097": "Mobile County, Alabama", + "01099": "Monroe County, Alabama", + "01101": "Montgomery County, Alabama", + "01103": "Morgan County, Alabama", + "01105": "Perry County, Alabama", + "01107": "Pickens County, Alabama", + "01109": "Pike County, Alabama", + "01111": "Randolph County, Alabama", + "01113": "Russell County, Alabama", + "01115": "St. Clair County, Alabama", + "01117": "Shelby County, Alabama", + "01119": "Sumter County, Alabama", + "01121": "Talladega County, Alabama", + "01123": "Tallapoosa County, Alabama", + "01125": "Tuscaloosa County, Alabama", + "01127": "Walker County, Alabama", + "01129": "Washington County, Alabama", + "01131": "Wilcox County, Alabama", + "01133": "Winston County, Alabama", + "02013": "Aleutians East Borough, Alaska", + "02016": "Aleutians West Census Area, Alaska", + "02020": "Anchorage Municipality, Alaska", + "02050": "Bethel Census Area, Alaska", + "02060": "Bristol Bay Borough, Alaska", + "02063": "Chugach Census Area, Alaska", + "02066": "Copper River Census Area, Alaska", + "02068": "Denali Borough, Alaska", + "02070": "Dillingham Census Area, Alaska", + "02090": "Fairbanks North Star Borough, Alaska", + "02100": "Haines Borough, Alaska", + "02105": "Hoonah-Angoon Census Area, Alaska", + "02110": "Juneau City and Borough, Alaska", + "02122": "Kenai Peninsula Borough, Alaska", + "02130": "Ketchikan Gateway Borough, Alaska", + "02150": "Kodiak Island Borough, Alaska", + "02158": "Kusilvak Census Area, Alaska", + "02164": "Lake and Peninsula Borough, Alaska", + "02170": "Matanuska-Susitna Borough, Alaska", + "02180": "Nome Census Area, Alaska", + "02185": "North Slope Borough, Alaska", + "02188": "Northwest Arctic Borough, Alaska", + "02195": "Petersburg Borough, Alaska", + "02198": "Prince of Wales-Hyder Census Area, Alaska", + "02220": "Sitka City and Borough, Alaska", + "02230": "Skagway Municipality, Alaska", + "02240": "Southeast Fairbanks Census Area, Alaska", + "02275": "Wrangell City and Borough, Alaska", + "02282": "Yakutat City and Borough, Alaska", + "02290": "Yukon-Koyukuk Census Area, Alaska", + "04001": "Apache County, Arizona", + "04003": "Cochise County, Arizona", + "04005": "Coconino County, Arizona", + "04007": "Gila County, Arizona", + "04009": "Graham County, Arizona", + "04011": "Greenlee County, Arizona", + "04012": "La Paz County, Arizona", + "04013": "Maricopa County, Arizona", + "04015": "Mohave County, Arizona", + "04017": "Navajo County, Arizona", + "04019": "Pima County, Arizona", + "04021": "Pinal County, Arizona", + "04023": "Santa Cruz County, Arizona", + "04025": "Yavapai County, Arizona", + "04027": "Yuma County, Arizona", + "05001": "Arkansas County, Arkansas", + "05003": "Ashley County, Arkansas", + "05005": "Baxter County, Arkansas", + "05007": "Benton County, Arkansas", + "05009": "Boone County, Arkansas", + "05011": "Bradley County, Arkansas", + "05013": "Calhoun County, Arkansas", + "05015": "Carroll County, Arkansas", + "05017": "Chicot County, Arkansas", + "05019": "Clark County, Arkansas", + "05021": "Clay County, Arkansas", + "05023": "Cleburne County, Arkansas", + "05025": "Cleveland County, Arkansas", + "05027": "Columbia County, Arkansas", + "05029": "Conway County, Arkansas", + "05031": "Craighead County, Arkansas", + "05033": "Crawford County, Arkansas", + "05035": "Crittenden County, Arkansas", + "05037": "Cross County, Arkansas", + "05039": "Dallas County, Arkansas", + "05041": "Desha County, Arkansas", + "05043": "Drew County, Arkansas", + "05045": "Faulkner County, Arkansas", + "05047": "Franklin County, Arkansas", + "05049": "Fulton County, Arkansas", + "05051": "Garland County, Arkansas", + "05053": "Grant County, Arkansas", + "05055": "Greene County, Arkansas", + "05057": "Hempstead County, Arkansas", + "05059": "Hot Spring County, Arkansas", + "05061": "Howard County, Arkansas", + "05063": "Independence County, Arkansas", + "05065": "Izard County, Arkansas", + "05067": "Jackson County, Arkansas", + "05069": "Jefferson County, Arkansas", + "05071": "Johnson County, Arkansas", + "05073": "Lafayette County, Arkansas", + "05075": "Lawrence County, Arkansas", + "05077": "Lee County, Arkansas", + "05079": "Lincoln County, Arkansas", + "05081": "Little River County, Arkansas", + "05083": "Logan County, Arkansas", + "05085": "Lonoke County, Arkansas", + "05087": "Madison County, Arkansas", + "05089": "Marion County, Arkansas", + "05091": "Miller County, Arkansas", + "05093": "Mississippi County, Arkansas", + "05095": "Monroe County, Arkansas", + "05097": "Montgomery County, Arkansas", + "05099": "Nevada County, Arkansas", + "05101": "Newton County, Arkansas", + "05103": "Ouachita County, Arkansas", + "05105": "Perry County, Arkansas", + "05107": "Phillips County, Arkansas", + "05109": "Pike County, Arkansas", + "05111": "Poinsett County, Arkansas", + "05113": "Polk County, Arkansas", + "05115": "Pope County, Arkansas", + "05117": "Prairie County, Arkansas", + "05119": "Pulaski County, Arkansas", + "05121": "Randolph County, Arkansas", + "05123": "St. Francis County, Arkansas", + "05125": "Saline County, Arkansas", + "05127": "Scott County, Arkansas", + "05129": "Searcy County, Arkansas", + "05131": "Sebastian County, Arkansas", + "05133": "Sevier County, Arkansas", + "05135": "Sharp County, Arkansas", + "05137": "Stone County, Arkansas", + "05139": "Union County, Arkansas", + "05141": "Van Buren County, Arkansas", + "05143": "Washington County, Arkansas", + "05145": "White County, Arkansas", + "05147": "Woodruff County, Arkansas", + "05149": "Yell County, Arkansas", + "06001": "Alameda County, California", + "06003": "Alpine County, California", + "06005": "Amador County, California", + "06007": "Butte County, California", + "06009": "Calaveras County, California", + "06011": "Colusa County, California", + "06013": "Contra Costa County, California", + "06015": "Del Norte County, California", + "06017": "El Dorado County, California", + "06019": "Fresno County, California", + "06021": "Glenn County, California", + "06023": "Humboldt County, California", + "06025": "Imperial County, California", + "06027": "Inyo County, California", + "06029": "Kern County, California", + "06031": "Kings County, California", + "06033": "Lake County, California", + "06035": "Lassen County, California", + "06037": "Los Angeles County, California", + "06039": "Madera County, California", + "06041": "Marin County, California", + "06043": "Mariposa County, California", + "06045": "Mendocino County, California", + "06047": "Merced County, California", + "06049": "Modoc County, California", + "06051": "Mono County, California", + "06053": "Monterey County, California", + "06055": "Napa County, California", + "06057": "Nevada County, California", + "06059": "Orange County, California", + "06061": "Placer County, California", + "06063": "Plumas County, California", + "06065": "Riverside County, California", + "06067": "Sacramento County, California", + "06069": "San Benito County, California", + "06071": "San Bernardino County, California", + "06073": "San Diego County, California", + "06075": "San Francisco County, California", + "06077": "San Joaquin County, California", + "06079": "San Luis Obispo County, California", + "06081": "San Mateo County, California", + "06083": "Santa Barbara County, California", + "06085": "Santa Clara County, California", + "06087": "Santa Cruz County, California", + "06089": "Shasta County, California", + "06091": "Sierra County, California", + "06093": "Siskiyou County, California", + "06095": "Solano County, California", + "06097": "Sonoma County, California", + "06099": "Stanislaus County, California", + "06101": "Sutter County, California", + "06103": "Tehama County, California", + "06105": "Trinity County, California", + "06107": "Tulare County, California", + "06109": "Tuolumne County, California", + "06111": "Ventura County, California", + "06113": "Yolo County, California", + "06115": "Yuba County, California", + "08001": "Adams County, Colorado", + "08003": "Alamosa County, Colorado", + "08005": "Arapahoe County, Colorado", + "08007": "Archuleta County, Colorado", + "08009": "Baca County, Colorado", + "08011": "Bent County, Colorado", + "08013": "Boulder County, Colorado", + "08014": "Broomfield County, Colorado", + "08015": "Chaffee County, Colorado", + "08017": "Cheyenne County, Colorado", + "08019": "Clear Creek County, Colorado", + "08021": "Conejos County, Colorado", + "08023": "Costilla County, Colorado", + "08025": "Crowley County, Colorado", + "08027": "Custer County, Colorado", + "08029": "Delta County, Colorado", + "08031": "Denver County, Colorado", + "08033": "Dolores County, Colorado", + "08035": "Douglas County, Colorado", + "08037": "Eagle County, Colorado", + "08039": "Elbert County, Colorado", + "08041": "El Paso County, Colorado", + "08043": "Fremont County, Colorado", + "08045": "Garfield County, Colorado", + "08047": "Gilpin County, Colorado", + "08049": "Grand County, Colorado", + "08051": "Gunnison County, Colorado", + "08053": "Hinsdale County, Colorado", + "08055": "Huerfano County, Colorado", + "08057": "Jackson County, Colorado", + "08059": "Jefferson County, Colorado", + "08061": "Kiowa County, Colorado", + "08063": "Kit Carson County, Colorado", + "08065": "Lake County, Colorado", + "08067": "La Plata County, Colorado", + "08069": "Larimer County, Colorado", + "08071": "Las Animas County, Colorado", + "08073": "Lincoln County, Colorado", + "08075": "Logan County, Colorado", + "08077": "Mesa County, Colorado", + "08079": "Mineral County, Colorado", + "08081": "Moffat County, Colorado", + "08083": "Montezuma County, Colorado", + "08085": "Montrose County, Colorado", + "08087": "Morgan County, Colorado", + "08089": "Otero County, Colorado", + "08091": "Ouray County, Colorado", + "08093": "Park County, Colorado", + "08095": "Phillips County, Colorado", + "08097": "Pitkin County, Colorado", + "08099": "Prowers County, Colorado", + "08101": "Pueblo County, Colorado", + "08103": "Rio Blanco County, Colorado", + "08105": "Rio Grande County, Colorado", + "08107": "Routt County, Colorado", + "08109": "Saguache County, Colorado", + "08111": "San Juan County, Colorado", + "08113": "San Miguel County, Colorado", + "08115": "Sedgwick County, Colorado", + "08117": "Summit County, Colorado", + "08119": "Teller County, Colorado", + "08121": "Washington County, Colorado", + "08123": "Weld County, Colorado", + "08125": "Yuma County, Colorado", + "09110": "Capitol Planning Region, Connecticut", + "09120": "Greater Bridgeport Planning Region, Connecticut", + "09130": "Lower Connecticut River Valley Planning Region, Connecticut", + "09140": "Naugatuck Valley Planning Region, Connecticut", + "09150": "Northeastern Connecticut Planning Region, Connecticut", + "09160": "Northwest Hills Planning Region, Connecticut", + "09170": "South Central Connecticut Planning Region, Connecticut", + "09180": "Southeastern Connecticut Planning Region, Connecticut", + "09190": "Western Connecticut Planning Region, Connecticut", + "10001": "Kent County, Delaware", + "10003": "New Castle County, Delaware", + "10005": "Sussex County, Delaware", + "11001": "District of Columbia, District of Columbia", + "12001": "Alachua County, Florida", + "12003": "Baker County, Florida", + "12005": "Bay County, Florida", + "12007": "Bradford County, Florida", + "12009": "Brevard County, Florida", + "12011": "Broward County, Florida", + "12013": "Calhoun County, Florida", + "12015": "Charlotte County, Florida", + "12017": "Citrus County, Florida", + "12019": "Clay County, Florida", + "12021": "Collier County, Florida", + "12023": "Columbia County, Florida", + "12027": "DeSoto County, Florida", + "12029": "Dixie County, Florida", + "12031": "Duval County, Florida", + "12033": "Escambia County, Florida", + "12035": "Flagler County, Florida", + "12037": "Franklin County, Florida", + "12039": "Gadsden County, Florida", + "12041": "Gilchrist County, Florida", + "12043": "Glades County, Florida", + "12045": "Gulf County, Florida", + "12047": "Hamilton County, Florida", + "12049": "Hardee County, Florida", + "12051": "Hendry County, Florida", + "12053": "Hernando County, Florida", + "12055": "Highlands County, Florida", + "12057": "Hillsborough County, Florida", + "12059": "Holmes County, Florida", + "12061": "Indian River County, Florida", + "12063": "Jackson County, Florida", + "12065": "Jefferson County, Florida", + "12067": "Lafayette County, Florida", + "12069": "Lake County, Florida", + "12071": "Lee County, Florida", + "12073": "Leon County, Florida", + "12075": "Levy County, Florida", + "12077": "Liberty County, Florida", + "12079": "Madison County, Florida", + "12081": "Manatee County, Florida", + "12083": "Marion County, Florida", + "12085": "Martin County, Florida", + "12086": "Miami-Dade County, Florida", + "12087": "Monroe County, Florida", + "12089": "Nassau County, Florida", + "12091": "Okaloosa County, Florida", + "12093": "Okeechobee County, Florida", + "12095": "Orange County, Florida", + "12097": "Osceola County, Florida", + "12099": "Palm Beach County, Florida", + "12101": "Pasco County, Florida", + "12103": "Pinellas County, Florida", + "12105": "Polk County, Florida", + "12107": "Putnam County, Florida", + "12109": "St. Johns County, Florida", + "12111": "St. Lucie County, Florida", + "12113": "Santa Rosa County, Florida", + "12115": "Sarasota County, Florida", + "12117": "Seminole County, Florida", + "12119": "Sumter County, Florida", + "12121": "Suwannee County, Florida", + "12123": "Taylor County, Florida", + "12125": "Union County, Florida", + "12127": "Volusia County, Florida", + "12129": "Wakulla County, Florida", + "12131": "Walton County, Florida", + "12133": "Washington County, Florida", + "13001": "Appling County, Georgia", + "13003": "Atkinson County, Georgia", + "13005": "Bacon County, Georgia", + "13007": "Baker County, Georgia", + "13009": "Baldwin County, Georgia", + "13011": "Banks County, Georgia", + "13013": "Barrow County, Georgia", + "13015": "Bartow County, Georgia", + "13017": "Ben Hill County, Georgia", + "13019": "Berrien County, Georgia", + "13021": "Bibb County, Georgia", + "13023": "Bleckley County, Georgia", + "13025": "Brantley County, Georgia", + "13027": "Brooks County, Georgia", + "13029": "Bryan County, Georgia", + "13031": "Bulloch County, Georgia", + "13033": "Burke County, Georgia", + "13035": "Butts County, Georgia", + "13037": "Calhoun County, Georgia", + "13039": "Camden County, Georgia", + "13043": "Candler County, Georgia", + "13045": "Carroll County, Georgia", + "13047": "Catoosa County, Georgia", + "13049": "Charlton County, Georgia", + "13051": "Chatham County, Georgia", + "13053": "Chattahoochee County, Georgia", + "13055": "Chattooga County, Georgia", + "13057": "Cherokee County, Georgia", + "13059": "Clarke County, Georgia", + "13061": "Clay County, Georgia", + "13063": "Clayton County, Georgia", + "13065": "Clinch County, Georgia", + "13067": "Cobb County, Georgia", + "13069": "Coffee County, Georgia", + "13071": "Colquitt County, Georgia", + "13073": "Columbia County, Georgia", + "13075": "Cook County, Georgia", + "13077": "Coweta County, Georgia", + "13079": "Crawford County, Georgia", + "13081": "Crisp County, Georgia", + "13083": "Dade County, Georgia", + "13085": "Dawson County, Georgia", + "13087": "Decatur County, Georgia", + "13089": "DeKalb County, Georgia", + "13091": "Dodge County, Georgia", + "13093": "Dooly County, Georgia", + "13095": "Dougherty County, Georgia", + "13097": "Douglas County, Georgia", + "13099": "Early County, Georgia", + "13101": "Echols County, Georgia", + "13103": "Effingham County, Georgia", + "13105": "Elbert County, Georgia", + "13107": "Emanuel County, Georgia", + "13109": "Evans County, Georgia", + "13111": "Fannin County, Georgia", + "13113": "Fayette County, Georgia", + "13115": "Floyd County, Georgia", + "13117": "Forsyth County, Georgia", + "13119": "Franklin County, Georgia", + "13121": "Fulton County, Georgia", + "13123": "Gilmer County, Georgia", + "13125": "Glascock County, Georgia", + "13127": "Glynn County, Georgia", + "13129": "Gordon County, Georgia", + "13131": "Grady County, Georgia", + "13133": "Greene County, Georgia", + "13135": "Gwinnett County, Georgia", + "13137": "Habersham County, Georgia", + "13139": "Hall County, Georgia", + "13141": "Hancock County, Georgia", + "13143": "Haralson County, Georgia", + "13145": "Harris County, Georgia", + "13147": "Hart County, Georgia", + "13149": "Heard County, Georgia", + "13151": "Henry County, Georgia", + "13153": "Houston County, Georgia", + "13155": "Irwin County, Georgia", + "13157": "Jackson County, Georgia", + "13159": "Jasper County, Georgia", + "13161": "Jeff Davis County, Georgia", + "13163": "Jefferson County, Georgia", + "13165": "Jenkins County, Georgia", + "13167": "Johnson County, Georgia", + "13169": "Jones County, Georgia", + "13171": "Lamar County, Georgia", + "13173": "Lanier County, Georgia", + "13175": "Laurens County, Georgia", + "13177": "Lee County, Georgia", + "13179": "Liberty County, Georgia", + "13181": "Lincoln County, Georgia", + "13183": "Long County, Georgia", + "13185": "Lowndes County, Georgia", + "13187": "Lumpkin County, Georgia", + "13189": "McDuffie County, Georgia", + "13191": "McIntosh County, Georgia", + "13193": "Macon County, Georgia", + "13195": "Madison County, Georgia", + "13197": "Marion County, Georgia", + "13199": "Meriwether County, Georgia", + "13201": "Miller County, Georgia", + "13205": "Mitchell County, Georgia", + "13207": "Monroe County, Georgia", + "13209": "Montgomery County, Georgia", + "13211": "Morgan County, Georgia", + "13213": "Murray County, Georgia", + "13215": "Muscogee County, Georgia", + "13217": "Newton County, Georgia", + "13219": "Oconee County, Georgia", + "13221": "Oglethorpe County, Georgia", + "13223": "Paulding County, Georgia", + "13225": "Peach County, Georgia", + "13227": "Pickens County, Georgia", + "13229": "Pierce County, Georgia", + "13231": "Pike County, Georgia", + "13233": "Polk County, Georgia", + "13235": "Pulaski County, Georgia", + "13237": "Putnam County, Georgia", + "13239": "Quitman County, Georgia", + "13241": "Rabun County, Georgia", + "13243": "Randolph County, Georgia", + "13245": "Richmond County, Georgia", + "13247": "Rockdale County, Georgia", + "13249": "Schley County, Georgia", + "13251": "Screven County, Georgia", + "13253": "Seminole County, Georgia", + "13255": "Spalding County, Georgia", + "13257": "Stephens County, Georgia", + "13259": "Stewart County, Georgia", + "13261": "Sumter County, Georgia", + "13263": "Talbot County, Georgia", + "13265": "Taliaferro County, Georgia", + "13267": "Tattnall County, Georgia", + "13269": "Taylor County, Georgia", + "13271": "Telfair County, Georgia", + "13273": "Terrell County, Georgia", + "13275": "Thomas County, Georgia", + "13277": "Tift County, Georgia", + "13279": "Toombs County, Georgia", + "13281": "Towns County, Georgia", + "13283": "Treutlen County, Georgia", + "13285": "Troup County, Georgia", + "13287": "Turner County, Georgia", + "13289": "Twiggs County, Georgia", + "13291": "Union County, Georgia", + "13293": "Upson County, Georgia", + "13295": "Walker County, Georgia", + "13297": "Walton County, Georgia", + "13299": "Ware County, Georgia", + "13301": "Warren County, Georgia", + "13303": "Washington County, Georgia", + "13305": "Wayne County, Georgia", + "13307": "Webster County, Georgia", + "13309": "Wheeler County, Georgia", + "13311": "White County, Georgia", + "13313": "Whitfield County, Georgia", + "13315": "Wilcox County, Georgia", + "13317": "Wilkes County, Georgia", + "13319": "Wilkinson County, Georgia", + "13321": "Worth County, Georgia", + "15001": "Hawaii County, Hawaii", + "15003": "Honolulu County, Hawaii", + "15005": "Kalawao County, Hawaii", + "15007": "Kauai County, Hawaii", + "15009": "Maui County, Hawaii", + "16001": "Ada County, Idaho", + "16003": "Adams County, Idaho", + "16005": "Bannock County, Idaho", + "16007": "Bear Lake County, Idaho", + "16009": "Benewah County, Idaho", + "16011": "Bingham County, Idaho", + "16013": "Blaine County, Idaho", + "16015": "Boise County, Idaho", + "16017": "Bonner County, Idaho", + "16019": "Bonneville County, Idaho", + "16021": "Boundary County, Idaho", + "16023": "Butte County, Idaho", + "16025": "Camas County, Idaho", + "16027": "Canyon County, Idaho", + "16029": "Caribou County, Idaho", + "16031": "Cassia County, Idaho", + "16033": "Clark County, Idaho", + "16035": "Clearwater County, Idaho", + "16037": "Custer County, Idaho", + "16039": "Elmore County, Idaho", + "16041": "Franklin County, Idaho", + "16043": "Fremont County, Idaho", + "16045": "Gem County, Idaho", + "16047": "Gooding County, Idaho", + "16049": "Idaho County, Idaho", + "16051": "Jefferson County, Idaho", + "16053": "Jerome County, Idaho", + "16055": "Kootenai County, Idaho", + "16057": "Latah County, Idaho", + "16059": "Lemhi County, Idaho", + "16061": "Lewis County, Idaho", + "16063": "Lincoln County, Idaho", + "16065": "Madison County, Idaho", + "16067": "Minidoka County, Idaho", + "16069": "Nez Perce County, Idaho", + "16071": "Oneida County, Idaho", + "16073": "Owyhee County, Idaho", + "16075": "Payette County, Idaho", + "16077": "Power County, Idaho", + "16079": "Shoshone County, Idaho", + "16081": "Teton County, Idaho", + "16083": "Twin Falls County, Idaho", + "16085": "Valley County, Idaho", + "16087": "Washington County, Idaho", + "17001": "Adams County, Illinois", + "17003": "Alexander County, Illinois", + "17005": "Bond County, Illinois", + "17007": "Boone County, Illinois", + "17009": "Brown County, Illinois", + "17011": "Bureau County, Illinois", + "17013": "Calhoun County, Illinois", + "17015": "Carroll County, Illinois", + "17017": "Cass County, Illinois", + "17019": "Champaign County, Illinois", + "17021": "Christian County, Illinois", + "17023": "Clark County, Illinois", + "17025": "Clay County, Illinois", + "17027": "Clinton County, Illinois", + "17029": "Coles County, Illinois", + "17031": "Cook County, Illinois", + "17033": "Crawford County, Illinois", + "17035": "Cumberland County, Illinois", + "17037": "DeKalb County, Illinois", + "17039": "De Witt County, Illinois", + "17041": "Douglas County, Illinois", + "17043": "DuPage County, Illinois", + "17045": "Edgar County, Illinois", + "17047": "Edwards County, Illinois", + "17049": "Effingham County, Illinois", + "17051": "Fayette County, Illinois", + "17053": "Ford County, Illinois", + "17055": "Franklin County, Illinois", + "17057": "Fulton County, Illinois", + "17059": "Gallatin County, Illinois", + "17061": "Greene County, Illinois", + "17063": "Grundy County, Illinois", + "17065": "Hamilton County, Illinois", + "17067": "Hancock County, Illinois", + "17069": "Hardin County, Illinois", + "17071": "Henderson County, Illinois", + "17073": "Henry County, Illinois", + "17075": "Iroquois County, Illinois", + "17077": "Jackson County, Illinois", + "17079": "Jasper County, Illinois", + "17081": "Jefferson County, Illinois", + "17083": "Jersey County, Illinois", + "17085": "Jo Daviess County, Illinois", + "17087": "Johnson County, Illinois", + "17089": "Kane County, Illinois", + "17091": "Kankakee County, Illinois", + "17093": "Kendall County, Illinois", + "17095": "Knox County, Illinois", + "17097": "Lake County, Illinois", + "17099": "LaSalle County, Illinois", + "17101": "Lawrence County, Illinois", + "17103": "Lee County, Illinois", + "17105": "Livingston County, Illinois", + "17107": "Logan County, Illinois", + "17109": "McDonough County, Illinois", + "17111": "McHenry County, Illinois", + "17113": "McLean County, Illinois", + "17115": "Macon County, Illinois", + "17117": "Macoupin County, Illinois", + "17119": "Madison County, Illinois", + "17121": "Marion County, Illinois", + "17123": "Marshall County, Illinois", + "17125": "Mason County, Illinois", + "17127": "Massac County, Illinois", + "17129": "Menard County, Illinois", + "17131": "Mercer County, Illinois", + "17133": "Monroe County, Illinois", + "17135": "Montgomery County, Illinois", + "17137": "Morgan County, Illinois", + "17139": "Moultrie County, Illinois", + "17141": "Ogle County, Illinois", + "17143": "Peoria County, Illinois", + "17145": "Perry County, Illinois", + "17147": "Piatt County, Illinois", + "17149": "Pike County, Illinois", + "17151": "Pope County, Illinois", + "17153": "Pulaski County, Illinois", + "17155": "Putnam County, Illinois", + "17157": "Randolph County, Illinois", + "17159": "Richland County, Illinois", + "17161": "Rock Island County, Illinois", + "17163": "St. Clair County, Illinois", + "17165": "Saline County, Illinois", + "17167": "Sangamon County, Illinois", + "17169": "Schuyler County, Illinois", + "17171": "Scott County, Illinois", + "17173": "Shelby County, Illinois", + "17175": "Stark County, Illinois", + "17177": "Stephenson County, Illinois", + "17179": "Tazewell County, Illinois", + "17181": "Union County, Illinois", + "17183": "Vermilion County, Illinois", + "17185": "Wabash County, Illinois", + "17187": "Warren County, Illinois", + "17189": "Washington County, Illinois", + "17191": "Wayne County, Illinois", + "17193": "White County, Illinois", + "17195": "Whiteside County, Illinois", + "17197": "Will County, Illinois", + "17199": "Williamson County, Illinois", + "17201": "Winnebago County, Illinois", + "17203": "Woodford County, Illinois", + "18001": "Adams County, Indiana", + "18003": "Allen County, Indiana", + "18005": "Bartholomew County, Indiana", + "18007": "Benton County, Indiana", + "18009": "Blackford County, Indiana", + "18011": "Boone County, Indiana", + "18013": "Brown County, Indiana", + "18015": "Carroll County, Indiana", + "18017": "Cass County, Indiana", + "18019": "Clark County, Indiana", + "18021": "Clay County, Indiana", + "18023": "Clinton County, Indiana", + "18025": "Crawford County, Indiana", + "18027": "Daviess County, Indiana", + "18029": "Dearborn County, Indiana", + "18031": "Decatur County, Indiana", + "18033": "DeKalb County, Indiana", + "18035": "Delaware County, Indiana", + "18037": "Dubois County, Indiana", + "18039": "Elkhart County, Indiana", + "18041": "Fayette County, Indiana", + "18043": "Floyd County, Indiana", + "18045": "Fountain County, Indiana", + "18047": "Franklin County, Indiana", + "18049": "Fulton County, Indiana", + "18051": "Gibson County, Indiana", + "18053": "Grant County, Indiana", + "18055": "Greene County, Indiana", + "18057": "Hamilton County, Indiana", + "18059": "Hancock County, Indiana", + "18061": "Harrison County, Indiana", + "18063": "Hendricks County, Indiana", + "18065": "Henry County, Indiana", + "18067": "Howard County, Indiana", + "18069": "Huntington County, Indiana", + "18071": "Jackson County, Indiana", + "18073": "Jasper County, Indiana", + "18075": "Jay County, Indiana", + "18077": "Jefferson County, Indiana", + "18079": "Jennings County, Indiana", + "18081": "Johnson County, Indiana", + "18083": "Knox County, Indiana", + "18085": "Kosciusko County, Indiana", + "18087": "LaGrange County, Indiana", + "18089": "Lake County, Indiana", + "18091": "LaPorte County, Indiana", + "18093": "Lawrence County, Indiana", + "18095": "Madison County, Indiana", + "18097": "Marion County, Indiana", + "18099": "Marshall County, Indiana", + "18101": "Martin County, Indiana", + "18103": "Miami County, Indiana", + "18105": "Monroe County, Indiana", + "18107": "Montgomery County, Indiana", + "18109": "Morgan County, Indiana", + "18111": "Newton County, Indiana", + "18113": "Noble County, Indiana", + "18115": "Ohio County, Indiana", + "18117": "Orange County, Indiana", + "18119": "Owen County, Indiana", + "18121": "Parke County, Indiana", + "18123": "Perry County, Indiana", + "18125": "Pike County, Indiana", + "18127": "Porter County, Indiana", + "18129": "Posey County, Indiana", + "18131": "Pulaski County, Indiana", + "18133": "Putnam County, Indiana", + "18135": "Randolph County, Indiana", + "18137": "Ripley County, Indiana", + "18139": "Rush County, Indiana", + "18141": "St. Joseph County, Indiana", + "18143": "Scott County, Indiana", + "18145": "Shelby County, Indiana", + "18147": "Spencer County, Indiana", + "18149": "Starke County, Indiana", + "18151": "Steuben County, Indiana", + "18153": "Sullivan County, Indiana", + "18155": "Switzerland County, Indiana", + "18157": "Tippecanoe County, Indiana", + "18159": "Tipton County, Indiana", + "18161": "Union County, Indiana", + "18163": "Vanderburgh County, Indiana", + "18165": "Vermillion County, Indiana", + "18167": "Vigo County, Indiana", + "18169": "Wabash County, Indiana", + "18171": "Warren County, Indiana", + "18173": "Warrick County, Indiana", + "18175": "Washington County, Indiana", + "18177": "Wayne County, Indiana", + "18179": "Wells County, Indiana", + "18181": "White County, Indiana", + "18183": "Whitley County, Indiana", + "19001": "Adair County, Iowa", + "19003": "Adams County, Iowa", + "19005": "Allamakee County, Iowa", + "19007": "Appanoose County, Iowa", + "19009": "Audubon County, Iowa", + "19011": "Benton County, Iowa", + "19013": "Black Hawk County, Iowa", + "19015": "Boone County, Iowa", + "19017": "Bremer County, Iowa", + "19019": "Buchanan County, Iowa", + "19021": "Buena Vista County, Iowa", + "19023": "Butler County, Iowa", + "19025": "Calhoun County, Iowa", + "19027": "Carroll County, Iowa", + "19029": "Cass County, Iowa", + "19031": "Cedar County, Iowa", + "19033": "Cerro Gordo County, Iowa", + "19035": "Cherokee County, Iowa", + "19037": "Chickasaw County, Iowa", + "19039": "Clarke County, Iowa", + "19041": "Clay County, Iowa", + "19043": "Clayton County, Iowa", + "19045": "Clinton County, Iowa", + "19047": "Crawford County, Iowa", + "19049": "Dallas County, Iowa", + "19051": "Davis County, Iowa", + "19053": "Decatur County, Iowa", + "19055": "Delaware County, Iowa", + "19057": "Des Moines County, Iowa", + "19059": "Dickinson County, Iowa", + "19061": "Dubuque County, Iowa", + "19063": "Emmet County, Iowa", + "19065": "Fayette County, Iowa", + "19067": "Floyd County, Iowa", + "19069": "Franklin County, Iowa", + "19071": "Fremont County, Iowa", + "19073": "Greene County, Iowa", + "19075": "Grundy County, Iowa", + "19077": "Guthrie County, Iowa", + "19079": "Hamilton County, Iowa", + "19081": "Hancock County, Iowa", + "19083": "Hardin County, Iowa", + "19085": "Harrison County, Iowa", + "19087": "Henry County, Iowa", + "19089": "Howard County, Iowa", + "19091": "Humboldt County, Iowa", + "19093": "Ida County, Iowa", + "19095": "Iowa County, Iowa", + "19097": "Jackson County, Iowa", + "19099": "Jasper County, Iowa", + "19101": "Jefferson County, Iowa", + "19103": "Johnson County, Iowa", + "19105": "Jones County, Iowa", + "19107": "Keokuk County, Iowa", + "19109": "Kossuth County, Iowa", + "19111": "Lee County, Iowa", + "19113": "Linn County, Iowa", + "19115": "Louisa County, Iowa", + "19117": "Lucas County, Iowa", + "19119": "Lyon County, Iowa", + "19121": "Madison County, Iowa", + "19123": "Mahaska County, Iowa", + "19125": "Marion County, Iowa", + "19127": "Marshall County, Iowa", + "19129": "Mills County, Iowa", + "19131": "Mitchell County, Iowa", + "19133": "Monona County, Iowa", + "19135": "Monroe County, Iowa", + "19137": "Montgomery County, Iowa", + "19139": "Muscatine County, Iowa", + "19141": "O'Brien County, Iowa", + "19143": "Osceola County, Iowa", + "19145": "Page County, Iowa", + "19147": "Palo Alto County, Iowa", + "19149": "Plymouth County, Iowa", + "19151": "Pocahontas County, Iowa", + "19153": "Polk County, Iowa", + "19155": "Pottawattamie County, Iowa", + "19157": "Poweshiek County, Iowa", + "19159": "Ringgold County, Iowa", + "19161": "Sac County, Iowa", + "19163": "Scott County, Iowa", + "19165": "Shelby County, Iowa", + "19167": "Sioux County, Iowa", + "19169": "Story County, Iowa", + "19171": "Tama County, Iowa", + "19173": "Taylor County, Iowa", + "19175": "Union County, Iowa", + "19177": "Van Buren County, Iowa", + "19179": "Wapello County, Iowa", + "19181": "Warren County, Iowa", + "19183": "Washington County, Iowa", + "19185": "Wayne County, Iowa", + "19187": "Webster County, Iowa", + "19189": "Winnebago County, Iowa", + "19191": "Winneshiek County, Iowa", + "19193": "Woodbury County, Iowa", + "19195": "Worth County, Iowa", + "19197": "Wright County, Iowa", + "20001": "Allen County, Kansas", + "20003": "Anderson County, Kansas", + "20005": "Atchison County, Kansas", + "20007": "Barber County, Kansas", + "20009": "Barton County, Kansas", + "20011": "Bourbon County, Kansas", + "20013": "Brown County, Kansas", + "20015": "Butler County, Kansas", + "20017": "Chase County, Kansas", + "20019": "Chautauqua County, Kansas", + "20021": "Cherokee County, Kansas", + "20023": "Cheyenne County, Kansas", + "20025": "Clark County, Kansas", + "20027": "Clay County, Kansas", + "20029": "Cloud County, Kansas", + "20031": "Coffey County, Kansas", + "20033": "Comanche County, Kansas", + "20035": "Cowley County, Kansas", + "20037": "Crawford County, Kansas", + "20039": "Decatur County, Kansas", + "20041": "Dickinson County, Kansas", + "20043": "Doniphan County, Kansas", + "20045": "Douglas County, Kansas", + "20047": "Edwards County, Kansas", + "20049": "Elk County, Kansas", + "20051": "Ellis County, Kansas", + "20053": "Ellsworth County, Kansas", + "20055": "Finney County, Kansas", + "20057": "Ford County, Kansas", + "20059": "Franklin County, Kansas", + "20061": "Geary County, Kansas", + "20063": "Gove County, Kansas", + "20065": "Graham County, Kansas", + "20067": "Grant County, Kansas", + "20069": "Gray County, Kansas", + "20071": "Greeley County, Kansas", + "20073": "Greenwood County, Kansas", + "20075": "Hamilton County, Kansas", + "20077": "Harper County, Kansas", + "20079": "Harvey County, Kansas", + "20081": "Haskell County, Kansas", + "20083": "Hodgeman County, Kansas", + "20085": "Jackson County, Kansas", + "20087": "Jefferson County, Kansas", + "20089": "Jewell County, Kansas", + "20091": "Johnson County, Kansas", + "20093": "Kearny County, Kansas", + "20095": "Kingman County, Kansas", + "20097": "Kiowa County, Kansas", + "20099": "Labette County, Kansas", + "20101": "Lane County, Kansas", + "20103": "Leavenworth County, Kansas", + "20105": "Lincoln County, Kansas", + "20107": "Linn County, Kansas", + "20109": "Logan County, Kansas", + "20111": "Lyon County, Kansas", + "20113": "McPherson County, Kansas", + "20115": "Marion County, Kansas", + "20117": "Marshall County, Kansas", + "20119": "Meade County, Kansas", + "20121": "Miami County, Kansas", + "20123": "Mitchell County, Kansas", + "20125": "Montgomery County, Kansas", + "20127": "Morris County, Kansas", + "20129": "Morton County, Kansas", + "20131": "Nemaha County, Kansas", + "20133": "Neosho County, Kansas", + "20135": "Ness County, Kansas", + "20137": "Norton County, Kansas", + "20139": "Osage County, Kansas", + "20141": "Osborne County, Kansas", + "20143": "Ottawa County, Kansas", + "20145": "Pawnee County, Kansas", + "20147": "Phillips County, Kansas", + "20149": "Pottawatomie County, Kansas", + "20151": "Pratt County, Kansas", + "20153": "Rawlins County, Kansas", + "20155": "Reno County, Kansas", + "20157": "Republic County, Kansas", + "20159": "Rice County, Kansas", + "20161": "Riley County, Kansas", + "20163": "Rooks County, Kansas", + "20165": "Rush County, Kansas", + "20167": "Russell County, Kansas", + "20169": "Saline County, Kansas", + "20171": "Scott County, Kansas", + "20173": "Sedgwick County, Kansas", + "20175": "Seward County, Kansas", + "20177": "Shawnee County, Kansas", + "20179": "Sheridan County, Kansas", + "20181": "Sherman County, Kansas", + "20183": "Smith County, Kansas", + "20185": "Stafford County, Kansas", + "20187": "Stanton County, Kansas", + "20189": "Stevens County, Kansas", + "20191": "Sumner County, Kansas", + "20193": "Thomas County, Kansas", + "20195": "Trego County, Kansas", + "20197": "Wabaunsee County, Kansas", + "20199": "Wallace County, Kansas", + "20201": "Washington County, Kansas", + "20203": "Wichita County, Kansas", + "20205": "Wilson County, Kansas", + "20207": "Woodson County, Kansas", + "20209": "Wyandotte County, Kansas", + "21001": "Adair County, Kentucky", + "21003": "Allen County, Kentucky", + "21005": "Anderson County, Kentucky", + "21007": "Ballard County, Kentucky", + "21009": "Barren County, Kentucky", + "21011": "Bath County, Kentucky", + "21013": "Bell County, Kentucky", + "21015": "Boone County, Kentucky", + "21017": "Bourbon County, Kentucky", + "21019": "Boyd County, Kentucky", + "21021": "Boyle County, Kentucky", + "21023": "Bracken County, Kentucky", + "21025": "Breathitt County, Kentucky", + "21027": "Breckinridge County, Kentucky", + "21029": "Bullitt County, Kentucky", + "21031": "Butler County, Kentucky", + "21033": "Caldwell County, Kentucky", + "21035": "Calloway County, Kentucky", + "21037": "Campbell County, Kentucky", + "21039": "Carlisle County, Kentucky", + "21041": "Carroll County, Kentucky", + "21043": "Carter County, Kentucky", + "21045": "Casey County, Kentucky", + "21047": "Christian County, Kentucky", + "21049": "Clark County, Kentucky", + "21051": "Clay County, Kentucky", + "21053": "Clinton County, Kentucky", + "21055": "Crittenden County, Kentucky", + "21057": "Cumberland County, Kentucky", + "21059": "Daviess County, Kentucky", + "21061": "Edmonson County, Kentucky", + "21063": "Elliott County, Kentucky", + "21065": "Estill County, Kentucky", + "21067": "Fayette County, Kentucky", + "21069": "Fleming County, Kentucky", + "21071": "Floyd County, Kentucky", + "21073": "Franklin County, Kentucky", + "21075": "Fulton County, Kentucky", + "21077": "Gallatin County, Kentucky", + "21079": "Garrard County, Kentucky", + "21081": "Grant County, Kentucky", + "21083": "Graves County, Kentucky", + "21085": "Grayson County, Kentucky", + "21087": "Green County, Kentucky", + "21089": "Greenup County, Kentucky", + "21091": "Hancock County, Kentucky", + "21093": "Hardin County, Kentucky", + "21095": "Harlan County, Kentucky", + "21097": "Harrison County, Kentucky", + "21099": "Hart County, Kentucky", + "21101": "Henderson County, Kentucky", + "21103": "Henry County, Kentucky", + "21105": "Hickman County, Kentucky", + "21107": "Hopkins County, Kentucky", + "21109": "Jackson County, Kentucky", + "21111": "Jefferson County, Kentucky", + "21113": "Jessamine County, Kentucky", + "21115": "Johnson County, Kentucky", + "21117": "Kenton County, Kentucky", + "21119": "Knott County, Kentucky", + "21121": "Knox County, Kentucky", + "21123": "Larue County, Kentucky", + "21125": "Laurel County, Kentucky", + "21127": "Lawrence County, Kentucky", + "21129": "Lee County, Kentucky", + "21131": "Leslie County, Kentucky", + "21133": "Letcher County, Kentucky", + "21135": "Lewis County, Kentucky", + "21137": "Lincoln County, Kentucky", + "21139": "Livingston County, Kentucky", + "21141": "Logan County, Kentucky", + "21143": "Lyon County, Kentucky", + "21145": "McCracken County, Kentucky", + "21147": "McCreary County, Kentucky", + "21149": "McLean County, Kentucky", + "21151": "Madison County, Kentucky", + "21153": "Magoffin County, Kentucky", + "21155": "Marion County, Kentucky", + "21157": "Marshall County, Kentucky", + "21159": "Martin County, Kentucky", + "21161": "Mason County, Kentucky", + "21163": "Meade County, Kentucky", + "21165": "Menifee County, Kentucky", + "21167": "Mercer County, Kentucky", + "21169": "Metcalfe County, Kentucky", + "21171": "Monroe County, Kentucky", + "21173": "Montgomery County, Kentucky", + "21175": "Morgan County, Kentucky", + "21177": "Muhlenberg County, Kentucky", + "21179": "Nelson County, Kentucky", + "21181": "Nicholas County, Kentucky", + "21183": "Ohio County, Kentucky", + "21185": "Oldham County, Kentucky", + "21187": "Owen County, Kentucky", + "21189": "Owsley County, Kentucky", + "21191": "Pendleton County, Kentucky", + "21193": "Perry County, Kentucky", + "21195": "Pike County, Kentucky", + "21197": "Powell County, Kentucky", + "21199": "Pulaski County, Kentucky", + "21201": "Robertson County, Kentucky", + "21203": "Rockcastle County, Kentucky", + "21205": "Rowan County, Kentucky", + "21207": "Russell County, Kentucky", + "21209": "Scott County, Kentucky", + "21211": "Shelby County, Kentucky", + "21213": "Simpson County, Kentucky", + "21215": "Spencer County, Kentucky", + "21217": "Taylor County, Kentucky", + "21219": "Todd County, Kentucky", + "21221": "Trigg County, Kentucky", + "21223": "Trimble County, Kentucky", + "21225": "Union County, Kentucky", + "21227": "Warren County, Kentucky", + "21229": "Washington County, Kentucky", + "21231": "Wayne County, Kentucky", + "21233": "Webster County, Kentucky", + "21235": "Whitley County, Kentucky", + "21237": "Wolfe County, Kentucky", + "21239": "Woodford County, Kentucky", + "22001": "Acadia Parish, Louisiana", + "22003": "Allen Parish, Louisiana", + "22005": "Ascension Parish, Louisiana", + "22007": "Assumption Parish, Louisiana", + "22009": "Avoyelles Parish, Louisiana", + "22011": "Beauregard Parish, Louisiana", + "22013": "Bienville Parish, Louisiana", + "22015": "Bossier Parish, Louisiana", + "22017": "Caddo Parish, Louisiana", + "22019": "Calcasieu Parish, Louisiana", + "22021": "Caldwell Parish, Louisiana", + "22023": "Cameron Parish, Louisiana", + "22025": "Catahoula Parish, Louisiana", + "22027": "Claiborne Parish, Louisiana", + "22029": "Concordia Parish, Louisiana", + "22031": "De Soto Parish, Louisiana", + "22033": "East Baton Rouge Parish, Louisiana", + "22035": "East Carroll Parish, Louisiana", + "22037": "East Feliciana Parish, Louisiana", + "22039": "Evangeline Parish, Louisiana", + "22041": "Franklin Parish, Louisiana", + "22043": "Grant Parish, Louisiana", + "22045": "Iberia Parish, Louisiana", + "22047": "Iberville Parish, Louisiana", + "22049": "Jackson Parish, Louisiana", + "22051": "Jefferson Parish, Louisiana", + "22053": "Jefferson Davis Parish, Louisiana", + "22055": "Lafayette Parish, Louisiana", + "22057": "Lafourche Parish, Louisiana", + "22059": "LaSalle Parish, Louisiana", + "22061": "Lincoln Parish, Louisiana", + "22063": "Livingston Parish, Louisiana", + "22065": "Madison Parish, Louisiana", + "22067": "Morehouse Parish, Louisiana", + "22069": "Natchitoches Parish, Louisiana", + "22071": "Orleans Parish, Louisiana", + "22073": "Ouachita Parish, Louisiana", + "22075": "Plaquemines Parish, Louisiana", + "22077": "Pointe Coupee Parish, Louisiana", + "22079": "Rapides Parish, Louisiana", + "22081": "Red River Parish, Louisiana", + "22083": "Richland Parish, Louisiana", + "22085": "Sabine Parish, Louisiana", + "22087": "St. Bernard Parish, Louisiana", + "22089": "St. Charles Parish, Louisiana", + "22091": "St. Helena Parish, Louisiana", + "22093": "St. James Parish, Louisiana", + "22095": "St. John the Baptist Parish, Louisiana", + "22097": "St. Landry Parish, Louisiana", + "22099": "St. Martin Parish, Louisiana", + "22101": "St. Mary Parish, Louisiana", + "22103": "St. Tammany Parish, Louisiana", + "22105": "Tangipahoa Parish, Louisiana", + "22107": "Tensas Parish, Louisiana", + "22109": "Terrebonne Parish, Louisiana", + "22111": "Union Parish, Louisiana", + "22113": "Vermilion Parish, Louisiana", + "22115": "Vernon Parish, Louisiana", + "22117": "Washington Parish, Louisiana", + "22119": "Webster Parish, Louisiana", + "22121": "West Baton Rouge Parish, Louisiana", + "22123": "West Carroll Parish, Louisiana", + "22125": "West Feliciana Parish, Louisiana", + "22127": "Winn Parish, Louisiana", + "23001": "Androscoggin County, Maine", + "23003": "Aroostook County, Maine", + "23005": "Cumberland County, Maine", + "23007": "Franklin County, Maine", + "23009": "Hancock County, Maine", + "23011": "Kennebec County, Maine", + "23013": "Knox County, Maine", + "23015": "Lincoln County, Maine", + "23017": "Oxford County, Maine", + "23019": "Penobscot County, Maine", + "23021": "Piscataquis County, Maine", + "23023": "Sagadahoc County, Maine", + "23025": "Somerset County, Maine", + "23027": "Waldo County, Maine", + "23029": "Washington County, Maine", + "23031": "York County, Maine", + "24001": "Allegany County, Maryland", + "24003": "Anne Arundel County, Maryland", + "24005": "Baltimore County, Maryland", + "24009": "Calvert County, Maryland", + "24011": "Caroline County, Maryland", + "24013": "Carroll County, Maryland", + "24015": "Cecil County, Maryland", + "24017": "Charles County, Maryland", + "24019": "Dorchester County, Maryland", + "24021": "Frederick County, Maryland", + "24023": "Garrett County, Maryland", + "24025": "Harford County, Maryland", + "24027": "Howard County, Maryland", + "24029": "Kent County, Maryland", + "24031": "Montgomery County, Maryland", + "24033": "Prince George's County, Maryland", + "24035": "Queen Anne's County, Maryland", + "24037": "St. Mary's County, Maryland", + "24039": "Somerset County, Maryland", + "24041": "Talbot County, Maryland", + "24043": "Washington County, Maryland", + "24045": "Wicomico County, Maryland", + "24047": "Worcester County, Maryland", + "24510": "Baltimore city, Maryland", + "25001": "Barnstable County, Massachusetts", + "25003": "Berkshire County, Massachusetts", + "25005": "Bristol County, Massachusetts", + "25007": "Dukes County, Massachusetts", + "25009": "Essex County, Massachusetts", + "25011": "Franklin County, Massachusetts", + "25013": "Hampden County, Massachusetts", + "25015": "Hampshire County, Massachusetts", + "25017": "Middlesex County, Massachusetts", + "25019": "Nantucket County, Massachusetts", + "25021": "Norfolk County, Massachusetts", + "25023": "Plymouth County, Massachusetts", + "25025": "Suffolk County, Massachusetts", + "25027": "Worcester County, Massachusetts", + "26001": "Alcona County, Michigan", + "26003": "Alger County, Michigan", + "26005": "Allegan County, Michigan", + "26007": "Alpena County, Michigan", + "26009": "Antrim County, Michigan", + "26011": "Arenac County, Michigan", + "26013": "Baraga County, Michigan", + "26015": "Barry County, Michigan", + "26017": "Bay County, Michigan", + "26019": "Benzie County, Michigan", + "26021": "Berrien County, Michigan", + "26023": "Branch County, Michigan", + "26025": "Calhoun County, Michigan", + "26027": "Cass County, Michigan", + "26029": "Charlevoix County, Michigan", + "26031": "Cheboygan County, Michigan", + "26033": "Chippewa County, Michigan", + "26035": "Clare County, Michigan", + "26037": "Clinton County, Michigan", + "26039": "Crawford County, Michigan", + "26041": "Delta County, Michigan", + "26043": "Dickinson County, Michigan", + "26045": "Eaton County, Michigan", + "26047": "Emmet County, Michigan", + "26049": "Genesee County, Michigan", + "26051": "Gladwin County, Michigan", + "26053": "Gogebic County, Michigan", + "26055": "Grand Traverse County, Michigan", + "26057": "Gratiot County, Michigan", + "26059": "Hillsdale County, Michigan", + "26061": "Houghton County, Michigan", + "26063": "Huron County, Michigan", + "26065": "Ingham County, Michigan", + "26067": "Ionia County, Michigan", + "26069": "Iosco County, Michigan", + "26071": "Iron County, Michigan", + "26073": "Isabella County, Michigan", + "26075": "Jackson County, Michigan", + "26077": "Kalamazoo County, Michigan", + "26079": "Kalkaska County, Michigan", + "26081": "Kent County, Michigan", + "26083": "Keweenaw County, Michigan", + "26085": "Lake County, Michigan", + "26087": "Lapeer County, Michigan", + "26089": "Leelanau County, Michigan", + "26091": "Lenawee County, Michigan", + "26093": "Livingston County, Michigan", + "26095": "Luce County, Michigan", + "26097": "Mackinac County, Michigan", + "26099": "Macomb County, Michigan", + "26101": "Manistee County, Michigan", + "26103": "Marquette County, Michigan", + "26105": "Mason County, Michigan", + "26107": "Mecosta County, Michigan", + "26109": "Menominee County, Michigan", + "26111": "Midland County, Michigan", + "26113": "Missaukee County, Michigan", + "26115": "Monroe County, Michigan", + "26117": "Montcalm County, Michigan", + "26119": "Montmorency County, Michigan", + "26121": "Muskegon County, Michigan", + "26123": "Newaygo County, Michigan", + "26125": "Oakland County, Michigan", + "26127": "Oceana County, Michigan", + "26129": "Ogemaw County, Michigan", + "26131": "Ontonagon County, Michigan", + "26133": "Osceola County, Michigan", + "26135": "Oscoda County, Michigan", + "26137": "Otsego County, Michigan", + "26139": "Ottawa County, Michigan", + "26141": "Presque Isle County, Michigan", + "26143": "Roscommon County, Michigan", + "26145": "Saginaw County, Michigan", + "26147": "St. Clair County, Michigan", + "26149": "St. Joseph County, Michigan", + "26151": "Sanilac County, Michigan", + "26153": "Schoolcraft County, Michigan", + "26155": "Shiawassee County, Michigan", + "26157": "Tuscola County, Michigan", + "26159": "Van Buren County, Michigan", + "26161": "Washtenaw County, Michigan", + "26163": "Wayne County, Michigan", + "26165": "Wexford County, Michigan", + "27001": "Aitkin County, Minnesota", + "27003": "Anoka County, Minnesota", + "27005": "Becker County, Minnesota", + "27007": "Beltrami County, Minnesota", + "27009": "Benton County, Minnesota", + "27011": "Big Stone County, Minnesota", + "27013": "Blue Earth County, Minnesota", + "27015": "Brown County, Minnesota", + "27017": "Carlton County, Minnesota", + "27019": "Carver County, Minnesota", + "27021": "Cass County, Minnesota", + "27023": "Chippewa County, Minnesota", + "27025": "Chisago County, Minnesota", + "27027": "Clay County, Minnesota", + "27029": "Clearwater County, Minnesota", + "27031": "Cook County, Minnesota", + "27033": "Cottonwood County, Minnesota", + "27035": "Crow Wing County, Minnesota", + "27037": "Dakota County, Minnesota", + "27039": "Dodge County, Minnesota", + "27041": "Douglas County, Minnesota", + "27043": "Faribault County, Minnesota", + "27045": "Fillmore County, Minnesota", + "27047": "Freeborn County, Minnesota", + "27049": "Goodhue County, Minnesota", + "27051": "Grant County, Minnesota", + "27053": "Hennepin County, Minnesota", + "27055": "Houston County, Minnesota", + "27057": "Hubbard County, Minnesota", + "27059": "Isanti County, Minnesota", + "27061": "Itasca County, Minnesota", + "27063": "Jackson County, Minnesota", + "27065": "Kanabec County, Minnesota", + "27067": "Kandiyohi County, Minnesota", + "27069": "Kittson County, Minnesota", + "27071": "Koochiching County, Minnesota", + "27073": "Lac qui Parle County, Minnesota", + "27075": "Lake County, Minnesota", + "27077": "Lake of the Woods County, Minnesota", + "27079": "Le Sueur County, Minnesota", + "27081": "Lincoln County, Minnesota", + "27083": "Lyon County, Minnesota", + "27085": "McLeod County, Minnesota", + "27087": "Mahnomen County, Minnesota", + "27089": "Marshall County, Minnesota", + "27091": "Martin County, Minnesota", + "27093": "Meeker County, Minnesota", + "27095": "Mille Lacs County, Minnesota", + "27097": "Morrison County, Minnesota", + "27099": "Mower County, Minnesota", + "27101": "Murray County, Minnesota", + "27103": "Nicollet County, Minnesota", + "27105": "Nobles County, Minnesota", + "27107": "Norman County, Minnesota", + "27109": "Olmsted County, Minnesota", + "27111": "Otter Tail County, Minnesota", + "27113": "Pennington County, Minnesota", + "27115": "Pine County, Minnesota", + "27117": "Pipestone County, Minnesota", + "27119": "Polk County, Minnesota", + "27121": "Pope County, Minnesota", + "27123": "Ramsey County, Minnesota", + "27125": "Red Lake County, Minnesota", + "27127": "Redwood County, Minnesota", + "27129": "Renville County, Minnesota", + "27131": "Rice County, Minnesota", + "27133": "Rock County, Minnesota", + "27135": "Roseau County, Minnesota", + "27137": "St. Louis County, Minnesota", + "27139": "Scott County, Minnesota", + "27141": "Sherburne County, Minnesota", + "27143": "Sibley County, Minnesota", + "27145": "Stearns County, Minnesota", + "27147": "Steele County, Minnesota", + "27149": "Stevens County, Minnesota", + "27151": "Swift County, Minnesota", + "27153": "Todd County, Minnesota", + "27155": "Traverse County, Minnesota", + "27157": "Wabasha County, Minnesota", + "27159": "Wadena County, Minnesota", + "27161": "Waseca County, Minnesota", + "27163": "Washington County, Minnesota", + "27165": "Watonwan County, Minnesota", + "27167": "Wilkin County, Minnesota", + "27169": "Winona County, Minnesota", + "27171": "Wright County, Minnesota", + "27173": "Yellow Medicine County, Minnesota", + "28001": "Adams County, Mississippi", + "28003": "Alcorn County, Mississippi", + "28005": "Amite County, Mississippi", + "28007": "Attala County, Mississippi", + "28009": "Benton County, Mississippi", + "28011": "Bolivar County, Mississippi", + "28013": "Calhoun County, Mississippi", + "28015": "Carroll County, Mississippi", + "28017": "Chickasaw County, Mississippi", + "28019": "Choctaw County, Mississippi", + "28021": "Claiborne County, Mississippi", + "28023": "Clarke County, Mississippi", + "28025": "Clay County, Mississippi", + "28027": "Coahoma County, Mississippi", + "28029": "Copiah County, Mississippi", + "28031": "Covington County, Mississippi", + "28033": "DeSoto County, Mississippi", + "28035": "Forrest County, Mississippi", + "28037": "Franklin County, Mississippi", + "28039": "George County, Mississippi", + "28041": "Greene County, Mississippi", + "28043": "Grenada County, Mississippi", + "28045": "Hancock County, Mississippi", + "28047": "Harrison County, Mississippi", + "28049": "Hinds County, Mississippi", + "28051": "Holmes County, Mississippi", + "28053": "Humphreys County, Mississippi", + "28055": "Issaquena County, Mississippi", + "28057": "Itawamba County, Mississippi", + "28059": "Jackson County, Mississippi", + "28061": "Jasper County, Mississippi", + "28063": "Jefferson County, Mississippi", + "28065": "Jefferson Davis County, Mississippi", + "28067": "Jones County, Mississippi", + "28069": "Kemper County, Mississippi", + "28071": "Lafayette County, Mississippi", + "28073": "Lamar County, Mississippi", + "28075": "Lauderdale County, Mississippi", + "28077": "Lawrence County, Mississippi", + "28079": "Leake County, Mississippi", + "28081": "Lee County, Mississippi", + "28083": "Leflore County, Mississippi", + "28085": "Lincoln County, Mississippi", + "28087": "Lowndes County, Mississippi", + "28089": "Madison County, Mississippi", + "28091": "Marion County, Mississippi", + "28093": "Marshall County, Mississippi", + "28095": "Monroe County, Mississippi", + "28097": "Montgomery County, Mississippi", + "28099": "Neshoba County, Mississippi", + "28101": "Newton County, Mississippi", + "28103": "Noxubee County, Mississippi", + "28105": "Oktibbeha County, Mississippi", + "28107": "Panola County, Mississippi", + "28109": "Pearl River County, Mississippi", + "28111": "Perry County, Mississippi", + "28113": "Pike County, Mississippi", + "28115": "Pontotoc County, Mississippi", + "28117": "Prentiss County, Mississippi", + "28119": "Quitman County, Mississippi", + "28121": "Rankin County, Mississippi", + "28123": "Scott County, Mississippi", + "28125": "Sharkey County, Mississippi", + "28127": "Simpson County, Mississippi", + "28129": "Smith County, Mississippi", + "28131": "Stone County, Mississippi", + "28133": "Sunflower County, Mississippi", + "28135": "Tallahatchie County, Mississippi", + "28137": "Tate County, Mississippi", + "28139": "Tippah County, Mississippi", + "28141": "Tishomingo County, Mississippi", + "28143": "Tunica County, Mississippi", + "28145": "Union County, Mississippi", + "28147": "Walthall County, Mississippi", + "28149": "Warren County, Mississippi", + "28151": "Washington County, Mississippi", + "28153": "Wayne County, Mississippi", + "28155": "Webster County, Mississippi", + "28157": "Wilkinson County, Mississippi", + "28159": "Winston County, Mississippi", + "28161": "Yalobusha County, Mississippi", + "28163": "Yazoo County, Mississippi", + "29001": "Adair County, Missouri", + "29003": "Andrew County, Missouri", + "29005": "Atchison County, Missouri", + "29007": "Audrain County, Missouri", + "29009": "Barry County, Missouri", + "29011": "Barton County, Missouri", + "29013": "Bates County, Missouri", + "29015": "Benton County, Missouri", + "29017": "Bollinger County, Missouri", + "29019": "Boone County, Missouri", + "29021": "Buchanan County, Missouri", + "29023": "Butler County, Missouri", + "29025": "Caldwell County, Missouri", + "29027": "Callaway County, Missouri", + "29029": "Camden County, Missouri", + "29031": "Cape Girardeau County, Missouri", + "29033": "Carroll County, Missouri", + "29035": "Carter County, Missouri", + "29037": "Cass County, Missouri", + "29039": "Cedar County, Missouri", + "29041": "Chariton County, Missouri", + "29043": "Christian County, Missouri", + "29045": "Clark County, Missouri", + "29047": "Clay County, Missouri", + "29049": "Clinton County, Missouri", + "29051": "Cole County, Missouri", + "29053": "Cooper County, Missouri", + "29055": "Crawford County, Missouri", + "29057": "Dade County, Missouri", + "29059": "Dallas County, Missouri", + "29061": "Daviess County, Missouri", + "29063": "DeKalb County, Missouri", + "29065": "Dent County, Missouri", + "29067": "Douglas County, Missouri", + "29069": "Dunklin County, Missouri", + "29071": "Franklin County, Missouri", + "29073": "Gasconade County, Missouri", + "29075": "Gentry County, Missouri", + "29077": "Greene County, Missouri", + "29079": "Grundy County, Missouri", + "29081": "Harrison County, Missouri", + "29083": "Henry County, Missouri", + "29085": "Hickory County, Missouri", + "29087": "Holt County, Missouri", + "29089": "Howard County, Missouri", + "29091": "Howell County, Missouri", + "29093": "Iron County, Missouri", + "29095": "Jackson County, Missouri", + "29097": "Jasper County, Missouri", + "29099": "Jefferson County, Missouri", + "29101": "Johnson County, Missouri", + "29103": "Knox County, Missouri", + "29105": "Laclede County, Missouri", + "29107": "Lafayette County, Missouri", + "29109": "Lawrence County, Missouri", + "29111": "Lewis County, Missouri", + "29113": "Lincoln County, Missouri", + "29115": "Linn County, Missouri", + "29117": "Livingston County, Missouri", + "29119": "McDonald County, Missouri", + "29121": "Macon County, Missouri", + "29123": "Madison County, Missouri", + "29125": "Maries County, Missouri", + "29127": "Marion County, Missouri", + "29129": "Mercer County, Missouri", + "29131": "Miller County, Missouri", + "29133": "Mississippi County, Missouri", + "29135": "Moniteau County, Missouri", + "29137": "Monroe County, Missouri", + "29139": "Montgomery County, Missouri", + "29141": "Morgan County, Missouri", + "29143": "New Madrid County, Missouri", + "29145": "Newton County, Missouri", + "29147": "Nodaway County, Missouri", + "29149": "Oregon County, Missouri", + "29151": "Osage County, Missouri", + "29153": "Ozark County, Missouri", + "29155": "Pemiscot County, Missouri", + "29157": "Perry County, Missouri", + "29159": "Pettis County, Missouri", + "29161": "Phelps County, Missouri", + "29163": "Pike County, Missouri", + "29165": "Platte County, Missouri", + "29167": "Polk County, Missouri", + "29169": "Pulaski County, Missouri", + "29171": "Putnam County, Missouri", + "29173": "Ralls County, Missouri", + "29175": "Randolph County, Missouri", + "29177": "Ray County, Missouri", + "29179": "Reynolds County, Missouri", + "29181": "Ripley County, Missouri", + "29183": "St. Charles County, Missouri", + "29185": "St. Clair County, Missouri", + "29186": "Ste. Genevieve County, Missouri", + "29187": "St. Francois County, Missouri", + "29189": "St. Louis County, Missouri", + "29195": "Saline County, Missouri", + "29197": "Schuyler County, Missouri", + "29199": "Scotland County, Missouri", + "29201": "Scott County, Missouri", + "29203": "Shannon County, Missouri", + "29205": "Shelby County, Missouri", + "29207": "Stoddard County, Missouri", + "29209": "Stone County, Missouri", + "29211": "Sullivan County, Missouri", + "29213": "Taney County, Missouri", + "29215": "Texas County, Missouri", + "29217": "Vernon County, Missouri", + "29219": "Warren County, Missouri", + "29221": "Washington County, Missouri", + "29223": "Wayne County, Missouri", + "29225": "Webster County, Missouri", + "29227": "Worth County, Missouri", + "29229": "Wright County, Missouri", + "29510": "St. Louis city, Missouri", + "30001": "Beaverhead County, Montana", + "30003": "Big Horn County, Montana", + "30005": "Blaine County, Montana", + "30007": "Broadwater County, Montana", + "30009": "Carbon County, Montana", + "30011": "Carter County, Montana", + "30013": "Cascade County, Montana", + "30015": "Chouteau County, Montana", + "30017": "Custer County, Montana", + "30019": "Daniels County, Montana", + "30021": "Dawson County, Montana", + "30023": "Deer Lodge County, Montana", + "30025": "Fallon County, Montana", + "30027": "Fergus County, Montana", + "30029": "Flathead County, Montana", + "30031": "Gallatin County, Montana", + "30033": "Garfield County, Montana", + "30035": "Glacier County, Montana", + "30037": "Golden Valley County, Montana", + "30039": "Granite County, Montana", + "30041": "Hill County, Montana", + "30043": "Jefferson County, Montana", + "30045": "Judith Basin County, Montana", + "30047": "Lake County, Montana", + "30049": "Lewis and Clark County, Montana", + "30051": "Liberty County, Montana", + "30053": "Lincoln County, Montana", + "30055": "McCone County, Montana", + "30057": "Madison County, Montana", + "30059": "Meagher County, Montana", + "30061": "Mineral County, Montana", + "30063": "Missoula County, Montana", + "30065": "Musselshell County, Montana", + "30067": "Park County, Montana", + "30069": "Petroleum County, Montana", + "30071": "Phillips County, Montana", + "30073": "Pondera County, Montana", + "30075": "Powder River County, Montana", + "30077": "Powell County, Montana", + "30079": "Prairie County, Montana", + "30081": "Ravalli County, Montana", + "30083": "Richland County, Montana", + "30085": "Roosevelt County, Montana", + "30087": "Rosebud County, Montana", + "30089": "Sanders County, Montana", + "30091": "Sheridan County, Montana", + "30093": "Silver Bow County, Montana", + "30095": "Stillwater County, Montana", + "30097": "Sweet Grass County, Montana", + "30099": "Teton County, Montana", + "30101": "Toole County, Montana", + "30103": "Treasure County, Montana", + "30105": "Valley County, Montana", + "30107": "Wheatland County, Montana", + "30109": "Wibaux County, Montana", + "30111": "Yellowstone County, Montana", + "31001": "Adams County, Nebraska", + "31003": "Antelope County, Nebraska", + "31005": "Arthur County, Nebraska", + "31007": "Banner County, Nebraska", + "31009": "Blaine County, Nebraska", + "31011": "Boone County, Nebraska", + "31013": "Box Butte County, Nebraska", + "31015": "Boyd County, Nebraska", + "31017": "Brown County, Nebraska", + "31019": "Buffalo County, Nebraska", + "31021": "Burt County, Nebraska", + "31023": "Butler County, Nebraska", + "31025": "Cass County, Nebraska", + "31027": "Cedar County, Nebraska", + "31029": "Chase County, Nebraska", + "31031": "Cherry County, Nebraska", + "31033": "Cheyenne County, Nebraska", + "31035": "Clay County, Nebraska", + "31037": "Colfax County, Nebraska", + "31039": "Cuming County, Nebraska", + "31041": "Custer County, Nebraska", + "31043": "Dakota County, Nebraska", + "31045": "Dawes County, Nebraska", + "31047": "Dawson County, Nebraska", + "31049": "Deuel County, Nebraska", + "31051": "Dixon County, Nebraska", + "31053": "Dodge County, Nebraska", + "31055": "Douglas County, Nebraska", + "31057": "Dundy County, Nebraska", + "31059": "Fillmore County, Nebraska", + "31061": "Franklin County, Nebraska", + "31063": "Frontier County, Nebraska", + "31065": "Furnas County, Nebraska", + "31067": "Gage County, Nebraska", + "31069": "Garden County, Nebraska", + "31071": "Garfield County, Nebraska", + "31073": "Gosper County, Nebraska", + "31075": "Grant County, Nebraska", + "31077": "Greeley County, Nebraska", + "31079": "Hall County, Nebraska", + "31081": "Hamilton County, Nebraska", + "31083": "Harlan County, Nebraska", + "31085": "Hayes County, Nebraska", + "31087": "Hitchcock County, Nebraska", + "31089": "Holt County, Nebraska", + "31091": "Hooker County, Nebraska", + "31093": "Howard County, Nebraska", + "31095": "Jefferson County, Nebraska", + "31097": "Johnson County, Nebraska", + "31099": "Kearney County, Nebraska", + "31101": "Keith County, Nebraska", + "31103": "Keya Paha County, Nebraska", + "31105": "Kimball County, Nebraska", + "31107": "Knox County, Nebraska", + "31109": "Lancaster County, Nebraska", + "31111": "Lincoln County, Nebraska", + "31113": "Logan County, Nebraska", + "31115": "Loup County, Nebraska", + "31117": "McPherson County, Nebraska", + "31119": "Madison County, Nebraska", + "31121": "Merrick County, Nebraska", + "31123": "Morrill County, Nebraska", + "31125": "Nance County, Nebraska", + "31127": "Nemaha County, Nebraska", + "31129": "Nuckolls County, Nebraska", + "31131": "Otoe County, Nebraska", + "31133": "Pawnee County, Nebraska", + "31135": "Perkins County, Nebraska", + "31137": "Phelps County, Nebraska", + "31139": "Pierce County, Nebraska", + "31141": "Platte County, Nebraska", + "31143": "Polk County, Nebraska", + "31145": "Red Willow County, Nebraska", + "31147": "Richardson County, Nebraska", + "31149": "Rock County, Nebraska", + "31151": "Saline County, Nebraska", + "31153": "Sarpy County, Nebraska", + "31155": "Saunders County, Nebraska", + "31157": "Scotts Bluff County, Nebraska", + "31159": "Seward County, Nebraska", + "31161": "Sheridan County, Nebraska", + "31163": "Sherman County, Nebraska", + "31165": "Sioux County, Nebraska", + "31167": "Stanton County, Nebraska", + "31169": "Thayer County, Nebraska", + "31171": "Thomas County, Nebraska", + "31173": "Thurston County, Nebraska", + "31175": "Valley County, Nebraska", + "31177": "Washington County, Nebraska", + "31179": "Wayne County, Nebraska", + "31181": "Webster County, Nebraska", + "31183": "Wheeler County, Nebraska", + "31185": "York County, Nebraska", + "32001": "Churchill County, Nevada", + "32003": "Clark County, Nevada", + "32005": "Douglas County, Nevada", + "32007": "Elko County, Nevada", + "32009": "Esmeralda County, Nevada", + "32011": "Eureka County, Nevada", + "32013": "Humboldt County, Nevada", + "32015": "Lander County, Nevada", + "32017": "Lincoln County, Nevada", + "32019": "Lyon County, Nevada", + "32021": "Mineral County, Nevada", + "32023": "Nye County, Nevada", + "32027": "Pershing County, Nevada", + "32029": "Storey County, Nevada", + "32031": "Washoe County, Nevada", + "32033": "White Pine County, Nevada", + "32510": "Carson City, Nevada", + "33001": "Belknap County, New Hampshire", + "33003": "Carroll County, New Hampshire", + "33005": "Cheshire County, New Hampshire", + "33007": "Coos County, New Hampshire", + "33009": "Grafton County, New Hampshire", + "33011": "Hillsborough County, New Hampshire", + "33013": "Merrimack County, New Hampshire", + "33015": "Rockingham County, New Hampshire", + "33017": "Strafford County, New Hampshire", + "33019": "Sullivan County, New Hampshire", + "34001": "Atlantic County, New Jersey", + "34003": "Bergen County, New Jersey", + "34005": "Burlington County, New Jersey", + "34007": "Camden County, New Jersey", + "34009": "Cape May County, New Jersey", + "34011": "Cumberland County, New Jersey", + "34013": "Essex County, New Jersey", + "34015": "Gloucester County, New Jersey", + "34017": "Hudson County, New Jersey", + "34019": "Hunterdon County, New Jersey", + "34021": "Mercer County, New Jersey", + "34023": "Middlesex County, New Jersey", + "34025": "Monmouth County, New Jersey", + "34027": "Morris County, New Jersey", + "34029": "Ocean County, New Jersey", + "34031": "Passaic County, New Jersey", + "34033": "Salem County, New Jersey", + "34035": "Somerset County, New Jersey", + "34037": "Sussex County, New Jersey", + "34039": "Union County, New Jersey", + "34041": "Warren County, New Jersey", + "35001": "Bernalillo County, New Mexico", + "35003": "Catron County, New Mexico", + "35005": "Chaves County, New Mexico", + "35006": "Cibola County, New Mexico", + "35007": "Colfax County, New Mexico", + "35009": "Curry County, New Mexico", + "35011": "De Baca County, New Mexico", + "35013": "Doña Ana County, New Mexico", + "35015": "Eddy County, New Mexico", + "35017": "Grant County, New Mexico", + "35019": "Guadalupe County, New Mexico", + "35021": "Harding County, New Mexico", + "35023": "Hidalgo County, New Mexico", + "35025": "Lea County, New Mexico", + "35027": "Lincoln County, New Mexico", + "35028": "Los Alamos County, New Mexico", + "35029": "Luna County, New Mexico", + "35031": "McKinley County, New Mexico", + "35033": "Mora County, New Mexico", + "35035": "Otero County, New Mexico", + "35037": "Quay County, New Mexico", + "35039": "Rio Arriba County, New Mexico", + "35041": "Roosevelt County, New Mexico", + "35043": "Sandoval County, New Mexico", + "35045": "San Juan County, New Mexico", + "35047": "San Miguel County, New Mexico", + "35049": "Santa Fe County, New Mexico", + "35051": "Sierra County, New Mexico", + "35053": "Socorro County, New Mexico", + "35055": "Taos County, New Mexico", + "35057": "Torrance County, New Mexico", + "35059": "Union County, New Mexico", + "35061": "Valencia County, New Mexico", + "36001": "Albany County, New York", + "36003": "Allegany County, New York", + "36005": "Bronx County, New York", + "36007": "Broome County, New York", + "36009": "Cattaraugus County, New York", + "36011": "Cayuga County, New York", + "36013": "Chautauqua County, New York", + "36015": "Chemung County, New York", + "36017": "Chenango County, New York", + "36019": "Clinton County, New York", + "36021": "Columbia County, New York", + "36023": "Cortland County, New York", + "36025": "Delaware County, New York", + "36027": "Dutchess County, New York", + "36029": "Erie County, New York", + "36031": "Essex County, New York", + "36033": "Franklin County, New York", + "36035": "Fulton County, New York", + "36037": "Genesee County, New York", + "36039": "Greene County, New York", + "36041": "Hamilton County, New York", + "36043": "Herkimer County, New York", + "36045": "Jefferson County, New York", + "36047": "Kings County, New York", + "36049": "Lewis County, New York", + "36051": "Livingston County, New York", + "36053": "Madison County, New York", + "36055": "Monroe County, New York", + "36057": "Montgomery County, New York", + "36059": "Nassau County, New York", + "36061": "New York County, New York", + "36063": "Niagara County, New York", + "36065": "Oneida County, New York", + "36067": "Onondaga County, New York", + "36069": "Ontario County, New York", + "36071": "Orange County, New York", + "36073": "Orleans County, New York", + "36075": "Oswego County, New York", + "36077": "Otsego County, New York", + "36079": "Putnam County, New York", + "36081": "Queens County, New York", + "36083": "Rensselaer County, New York", + "36085": "Richmond County, New York", + "36087": "Rockland County, New York", + "36089": "St. Lawrence County, New York", + "36091": "Saratoga County, New York", + "36093": "Schenectady County, New York", + "36095": "Schoharie County, New York", + "36097": "Schuyler County, New York", + "36099": "Seneca County, New York", + "36101": "Steuben County, New York", + "36103": "Suffolk County, New York", + "36105": "Sullivan County, New York", + "36107": "Tioga County, New York", + "36109": "Tompkins County, New York", + "36111": "Ulster County, New York", + "36113": "Warren County, New York", + "36115": "Washington County, New York", + "36117": "Wayne County, New York", + "36119": "Westchester County, New York", + "36121": "Wyoming County, New York", + "36123": "Yates County, New York", + "37001": "Alamance County, North Carolina", + "37003": "Alexander County, North Carolina", + "37005": "Alleghany County, North Carolina", + "37007": "Anson County, North Carolina", + "37009": "Ashe County, North Carolina", + "37011": "Avery County, North Carolina", + "37013": "Beaufort County, North Carolina", + "37015": "Bertie County, North Carolina", + "37017": "Bladen County, North Carolina", + "37019": "Brunswick County, North Carolina", + "37021": "Buncombe County, North Carolina", + "37023": "Burke County, North Carolina", + "37025": "Cabarrus County, North Carolina", + "37027": "Caldwell County, North Carolina", + "37029": "Camden County, North Carolina", + "37031": "Carteret County, North Carolina", + "37033": "Caswell County, North Carolina", + "37035": "Catawba County, North Carolina", + "37037": "Chatham County, North Carolina", + "37039": "Cherokee County, North Carolina", + "37041": "Chowan County, North Carolina", + "37043": "Clay County, North Carolina", + "37045": "Cleveland County, North Carolina", + "37047": "Columbus County, North Carolina", + "37049": "Craven County, North Carolina", + "37051": "Cumberland County, North Carolina", + "37053": "Currituck County, North Carolina", + "37055": "Dare County, North Carolina", + "37057": "Davidson County, North Carolina", + "37059": "Davie County, North Carolina", + "37061": "Duplin County, North Carolina", + "37063": "Durham County, North Carolina", + "37065": "Edgecombe County, North Carolina", + "37067": "Forsyth County, North Carolina", + "37069": "Franklin County, North Carolina", + "37071": "Gaston County, North Carolina", + "37073": "Gates County, North Carolina", + "37075": "Graham County, North Carolina", + "37077": "Granville County, North Carolina", + "37079": "Greene County, North Carolina", + "37081": "Guilford County, North Carolina", + "37083": "Halifax County, North Carolina", + "37085": "Harnett County, North Carolina", + "37087": "Haywood County, North Carolina", + "37089": "Henderson County, North Carolina", + "37091": "Hertford County, North Carolina", + "37093": "Hoke County, North Carolina", + "37095": "Hyde County, North Carolina", + "37097": "Iredell County, North Carolina", + "37099": "Jackson County, North Carolina", + "37101": "Johnston County, North Carolina", + "37103": "Jones County, North Carolina", + "37105": "Lee County, North Carolina", + "37107": "Lenoir County, North Carolina", + "37109": "Lincoln County, North Carolina", + "37111": "McDowell County, North Carolina", + "37113": "Macon County, North Carolina", + "37115": "Madison County, North Carolina", + "37117": "Martin County, North Carolina", + "37119": "Mecklenburg County, North Carolina", + "37121": "Mitchell County, North Carolina", + "37123": "Montgomery County, North Carolina", + "37125": "Moore County, North Carolina", + "37127": "Nash County, North Carolina", + "37129": "New Hanover County, North Carolina", + "37131": "Northampton County, North Carolina", + "37133": "Onslow County, North Carolina", + "37135": "Orange County, North Carolina", + "37137": "Pamlico County, North Carolina", + "37139": "Pasquotank County, North Carolina", + "37141": "Pender County, North Carolina", + "37143": "Perquimans County, North Carolina", + "37145": "Person County, North Carolina", + "37147": "Pitt County, North Carolina", + "37149": "Polk County, North Carolina", + "37151": "Randolph County, North Carolina", + "37153": "Richmond County, North Carolina", + "37155": "Robeson County, North Carolina", + "37157": "Rockingham County, North Carolina", + "37159": "Rowan County, North Carolina", + "37161": "Rutherford County, North Carolina", + "37163": "Sampson County, North Carolina", + "37165": "Scotland County, North Carolina", + "37167": "Stanly County, North Carolina", + "37169": "Stokes County, North Carolina", + "37171": "Surry County, North Carolina", + "37173": "Swain County, North Carolina", + "37175": "Transylvania County, North Carolina", + "37177": "Tyrrell County, North Carolina", + "37179": "Union County, North Carolina", + "37181": "Vance County, North Carolina", + "37183": "Wake County, North Carolina", + "37185": "Warren County, North Carolina", + "37187": "Washington County, North Carolina", + "37189": "Watauga County, North Carolina", + "37191": "Wayne County, North Carolina", + "37193": "Wilkes County, North Carolina", + "37195": "Wilson County, North Carolina", + "37197": "Yadkin County, North Carolina", + "37199": "Yancey County, North Carolina", + "38001": "Adams County, North Dakota", + "38003": "Barnes County, North Dakota", + "38005": "Benson County, North Dakota", + "38007": "Billings County, North Dakota", + "38009": "Bottineau County, North Dakota", + "38011": "Bowman County, North Dakota", + "38013": "Burke County, North Dakota", + "38015": "Burleigh County, North Dakota", + "38017": "Cass County, North Dakota", + "38019": "Cavalier County, North Dakota", + "38021": "Dickey County, North Dakota", + "38023": "Divide County, North Dakota", + "38025": "Dunn County, North Dakota", + "38027": "Eddy County, North Dakota", + "38029": "Emmons County, North Dakota", + "38031": "Foster County, North Dakota", + "38033": "Golden Valley County, North Dakota", + "38035": "Grand Forks County, North Dakota", + "38037": "Grant County, North Dakota", + "38039": "Griggs County, North Dakota", + "38041": "Hettinger County, North Dakota", + "38043": "Kidder County, North Dakota", + "38045": "LaMoure County, North Dakota", + "38047": "Logan County, North Dakota", + "38049": "McHenry County, North Dakota", + "38051": "McIntosh County, North Dakota", + "38053": "McKenzie County, North Dakota", + "38055": "McLean County, North Dakota", + "38057": "Mercer County, North Dakota", + "38059": "Morton County, North Dakota", + "38061": "Mountrail County, North Dakota", + "38063": "Nelson County, North Dakota", + "38065": "Oliver County, North Dakota", + "38067": "Pembina County, North Dakota", + "38069": "Pierce County, North Dakota", + "38071": "Ramsey County, North Dakota", + "38073": "Ransom County, North Dakota", + "38075": "Renville County, North Dakota", + "38077": "Richland County, North Dakota", + "38079": "Rolette County, North Dakota", + "38081": "Sargent County, North Dakota", + "38083": "Sheridan County, North Dakota", + "38085": "Sioux County, North Dakota", + "38087": "Slope County, North Dakota", + "38089": "Stark County, North Dakota", + "38091": "Steele County, North Dakota", + "38093": "Stutsman County, North Dakota", + "38095": "Towner County, North Dakota", + "38097": "Traill County, North Dakota", + "38099": "Walsh County, North Dakota", + "38101": "Ward County, North Dakota", + "38103": "Wells County, North Dakota", + "38105": "Williams County, North Dakota", + "39001": "Adams County, Ohio", + "39003": "Allen County, Ohio", + "39005": "Ashland County, Ohio", + "39007": "Ashtabula County, Ohio", + "39009": "Athens County, Ohio", + "39011": "Auglaize County, Ohio", + "39013": "Belmont County, Ohio", + "39015": "Brown County, Ohio", + "39017": "Butler County, Ohio", + "39019": "Carroll County, Ohio", + "39021": "Champaign County, Ohio", + "39023": "Clark County, Ohio", + "39025": "Clermont County, Ohio", + "39027": "Clinton County, Ohio", + "39029": "Columbiana County, Ohio", + "39031": "Coshocton County, Ohio", + "39033": "Crawford County, Ohio", + "39035": "Cuyahoga County, Ohio", + "39037": "Darke County, Ohio", + "39039": "Defiance County, Ohio", + "39041": "Delaware County, Ohio", + "39043": "Erie County, Ohio", + "39045": "Fairfield County, Ohio", + "39047": "Fayette County, Ohio", + "39049": "Franklin County, Ohio", + "39051": "Fulton County, Ohio", + "39053": "Gallia County, Ohio", + "39055": "Geauga County, Ohio", + "39057": "Greene County, Ohio", + "39059": "Guernsey County, Ohio", + "39061": "Hamilton County, Ohio", + "39063": "Hancock County, Ohio", + "39065": "Hardin County, Ohio", + "39067": "Harrison County, Ohio", + "39069": "Henry County, Ohio", + "39071": "Highland County, Ohio", + "39073": "Hocking County, Ohio", + "39075": "Holmes County, Ohio", + "39077": "Huron County, Ohio", + "39079": "Jackson County, Ohio", + "39081": "Jefferson County, Ohio", + "39083": "Knox County, Ohio", + "39085": "Lake County, Ohio", + "39087": "Lawrence County, Ohio", + "39089": "Licking County, Ohio", + "39091": "Logan County, Ohio", + "39093": "Lorain County, Ohio", + "39095": "Lucas County, Ohio", + "39097": "Madison County, Ohio", + "39099": "Mahoning County, Ohio", + "39101": "Marion County, Ohio", + "39103": "Medina County, Ohio", + "39105": "Meigs County, Ohio", + "39107": "Mercer County, Ohio", + "39109": "Miami County, Ohio", + "39111": "Monroe County, Ohio", + "39113": "Montgomery County, Ohio", + "39115": "Morgan County, Ohio", + "39117": "Morrow County, Ohio", + "39119": "Muskingum County, Ohio", + "39121": "Noble County, Ohio", + "39123": "Ottawa County, Ohio", + "39125": "Paulding County, Ohio", + "39127": "Perry County, Ohio", + "39129": "Pickaway County, Ohio", + "39131": "Pike County, Ohio", + "39133": "Portage County, Ohio", + "39135": "Preble County, Ohio", + "39137": "Putnam County, Ohio", + "39139": "Richland County, Ohio", + "39141": "Ross County, Ohio", + "39143": "Sandusky County, Ohio", + "39145": "Scioto County, Ohio", + "39147": "Seneca County, Ohio", + "39149": "Shelby County, Ohio", + "39151": "Stark County, Ohio", + "39153": "Summit County, Ohio", + "39155": "Trumbull County, Ohio", + "39157": "Tuscarawas County, Ohio", + "39159": "Union County, Ohio", + "39161": "Van Wert County, Ohio", + "39163": "Vinton County, Ohio", + "39165": "Warren County, Ohio", + "39167": "Washington County, Ohio", + "39169": "Wayne County, Ohio", + "39171": "Williams County, Ohio", + "39173": "Wood County, Ohio", + "39175": "Wyandot County, Ohio", + "40001": "Adair County, Oklahoma", + "40003": "Alfalfa County, Oklahoma", + "40005": "Atoka County, Oklahoma", + "40007": "Beaver County, Oklahoma", + "40009": "Beckham County, Oklahoma", + "40011": "Blaine County, Oklahoma", + "40013": "Bryan County, Oklahoma", + "40015": "Caddo County, Oklahoma", + "40017": "Canadian County, Oklahoma", + "40019": "Carter County, Oklahoma", + "40021": "Cherokee County, Oklahoma", + "40023": "Choctaw County, Oklahoma", + "40025": "Cimarron County, Oklahoma", + "40027": "Cleveland County, Oklahoma", + "40029": "Coal County, Oklahoma", + "40031": "Comanche County, Oklahoma", + "40033": "Cotton County, Oklahoma", + "40035": "Craig County, Oklahoma", + "40037": "Creek County, Oklahoma", + "40039": "Custer County, Oklahoma", + "40041": "Delaware County, Oklahoma", + "40043": "Dewey County, Oklahoma", + "40045": "Ellis County, Oklahoma", + "40047": "Garfield County, Oklahoma", + "40049": "Garvin County, Oklahoma", + "40051": "Grady County, Oklahoma", + "40053": "Grant County, Oklahoma", + "40055": "Greer County, Oklahoma", + "40057": "Harmon County, Oklahoma", + "40059": "Harper County, Oklahoma", + "40061": "Haskell County, Oklahoma", + "40063": "Hughes County, Oklahoma", + "40065": "Jackson County, Oklahoma", + "40067": "Jefferson County, Oklahoma", + "40069": "Johnston County, Oklahoma", + "40071": "Kay County, Oklahoma", + "40073": "Kingfisher County, Oklahoma", + "40075": "Kiowa County, Oklahoma", + "40077": "Latimer County, Oklahoma", + "40079": "Le Flore County, Oklahoma", + "40081": "Lincoln County, Oklahoma", + "40083": "Logan County, Oklahoma", + "40085": "Love County, Oklahoma", + "40087": "McClain County, Oklahoma", + "40089": "McCurtain County, Oklahoma", + "40091": "McIntosh County, Oklahoma", + "40093": "Major County, Oklahoma", + "40095": "Marshall County, Oklahoma", + "40097": "Mayes County, Oklahoma", + "40099": "Murray County, Oklahoma", + "40101": "Muskogee County, Oklahoma", + "40103": "Noble County, Oklahoma", + "40105": "Nowata County, Oklahoma", + "40107": "Okfuskee County, Oklahoma", + "40109": "Oklahoma County, Oklahoma", + "40111": "Okmulgee County, Oklahoma", + "40113": "Osage County, Oklahoma", + "40115": "Ottawa County, Oklahoma", + "40117": "Pawnee County, Oklahoma", + "40119": "Payne County, Oklahoma", + "40121": "Pittsburg County, Oklahoma", + "40123": "Pontotoc County, Oklahoma", + "40125": "Pottawatomie County, Oklahoma", + "40127": "Pushmataha County, Oklahoma", + "40129": "Roger Mills County, Oklahoma", + "40131": "Rogers County, Oklahoma", + "40133": "Seminole County, Oklahoma", + "40135": "Sequoyah County, Oklahoma", + "40137": "Stephens County, Oklahoma", + "40139": "Texas County, Oklahoma", + "40141": "Tillman County, Oklahoma", + "40143": "Tulsa County, Oklahoma", + "40145": "Wagoner County, Oklahoma", + "40147": "Washington County, Oklahoma", + "40149": "Washita County, Oklahoma", + "40151": "Woods County, Oklahoma", + "40153": "Woodward County, Oklahoma", + "41001": "Baker County, Oregon", + "41003": "Benton County, Oregon", + "41005": "Clackamas County, Oregon", + "41007": "Clatsop County, Oregon", + "41009": "Columbia County, Oregon", + "41011": "Coos County, Oregon", + "41013": "Crook County, Oregon", + "41015": "Curry County, Oregon", + "41017": "Deschutes County, Oregon", + "41019": "Douglas County, Oregon", + "41021": "Gilliam County, Oregon", + "41023": "Grant County, Oregon", + "41025": "Harney County, Oregon", + "41027": "Hood River County, Oregon", + "41029": "Jackson County, Oregon", + "41031": "Jefferson County, Oregon", + "41033": "Josephine County, Oregon", + "41035": "Klamath County, Oregon", + "41037": "Lake County, Oregon", + "41039": "Lane County, Oregon", + "41041": "Lincoln County, Oregon", + "41043": "Linn County, Oregon", + "41045": "Malheur County, Oregon", + "41047": "Marion County, Oregon", + "41049": "Morrow County, Oregon", + "41051": "Multnomah County, Oregon", + "41053": "Polk County, Oregon", + "41055": "Sherman County, Oregon", + "41057": "Tillamook County, Oregon", + "41059": "Umatilla County, Oregon", + "41061": "Union County, Oregon", + "41063": "Wallowa County, Oregon", + "41065": "Wasco County, Oregon", + "41067": "Washington County, Oregon", + "41069": "Wheeler County, Oregon", + "41071": "Yamhill County, Oregon", + "42001": "Adams County, Pennsylvania", + "42003": "Allegheny County, Pennsylvania", + "42005": "Armstrong County, Pennsylvania", + "42007": "Beaver County, Pennsylvania", + "42009": "Bedford County, Pennsylvania", + "42011": "Berks County, Pennsylvania", + "42013": "Blair County, Pennsylvania", + "42015": "Bradford County, Pennsylvania", + "42017": "Bucks County, Pennsylvania", + "42019": "Butler County, Pennsylvania", + "42021": "Cambria County, Pennsylvania", + "42023": "Cameron County, Pennsylvania", + "42025": "Carbon County, Pennsylvania", + "42027": "Centre County, Pennsylvania", + "42029": "Chester County, Pennsylvania", + "42031": "Clarion County, Pennsylvania", + "42033": "Clearfield County, Pennsylvania", + "42035": "Clinton County, Pennsylvania", + "42037": "Columbia County, Pennsylvania", + "42039": "Crawford County, Pennsylvania", + "42041": "Cumberland County, Pennsylvania", + "42043": "Dauphin County, Pennsylvania", + "42045": "Delaware County, Pennsylvania", + "42047": "Elk County, Pennsylvania", + "42049": "Erie County, Pennsylvania", + "42051": "Fayette County, Pennsylvania", + "42053": "Forest County, Pennsylvania", + "42055": "Franklin County, Pennsylvania", + "42057": "Fulton County, Pennsylvania", + "42059": "Greene County, Pennsylvania", + "42061": "Huntingdon County, Pennsylvania", + "42063": "Indiana County, Pennsylvania", + "42065": "Jefferson County, Pennsylvania", + "42067": "Juniata County, Pennsylvania", + "42069": "Lackawanna County, Pennsylvania", + "42071": "Lancaster County, Pennsylvania", + "42073": "Lawrence County, Pennsylvania", + "42075": "Lebanon County, Pennsylvania", + "42077": "Lehigh County, Pennsylvania", + "42079": "Luzerne County, Pennsylvania", + "42081": "Lycoming County, Pennsylvania", + "42083": "McKean County, Pennsylvania", + "42085": "Mercer County, Pennsylvania", + "42087": "Mifflin County, Pennsylvania", + "42089": "Monroe County, Pennsylvania", + "42091": "Montgomery County, Pennsylvania", + "42093": "Montour County, Pennsylvania", + "42095": "Northampton County, Pennsylvania", + "42097": "Northumberland County, Pennsylvania", + "42099": "Perry County, Pennsylvania", + "42101": "Philadelphia County, Pennsylvania", + "42103": "Pike County, Pennsylvania", + "42105": "Potter County, Pennsylvania", + "42107": "Schuylkill County, Pennsylvania", + "42109": "Snyder County, Pennsylvania", + "42111": "Somerset County, Pennsylvania", + "42113": "Sullivan County, Pennsylvania", + "42115": "Susquehanna County, Pennsylvania", + "42117": "Tioga County, Pennsylvania", + "42119": "Union County, Pennsylvania", + "42121": "Venango County, Pennsylvania", + "42123": "Warren County, Pennsylvania", + "42125": "Washington County, Pennsylvania", + "42127": "Wayne County, Pennsylvania", + "42129": "Westmoreland County, Pennsylvania", + "42131": "Wyoming County, Pennsylvania", + "42133": "York County, Pennsylvania", + "44001": "Bristol County, Rhode Island", + "44003": "Kent County, Rhode Island", + "44005": "Newport County, Rhode Island", + "44007": "Providence County, Rhode Island", + "44009": "Washington County, Rhode Island", + "45001": "Abbeville County, South Carolina", + "45003": "Aiken County, South Carolina", + "45005": "Allendale County, South Carolina", + "45007": "Anderson County, South Carolina", + "45009": "Bamberg County, South Carolina", + "45011": "Barnwell County, South Carolina", + "45013": "Beaufort County, South Carolina", + "45015": "Berkeley County, South Carolina", + "45017": "Calhoun County, South Carolina", + "45019": "Charleston County, South Carolina", + "45021": "Cherokee County, South Carolina", + "45023": "Chester County, South Carolina", + "45025": "Chesterfield County, South Carolina", + "45027": "Clarendon County, South Carolina", + "45029": "Colleton County, South Carolina", + "45031": "Darlington County, South Carolina", + "45033": "Dillon County, South Carolina", + "45035": "Dorchester County, South Carolina", + "45037": "Edgefield County, South Carolina", + "45039": "Fairfield County, South Carolina", + "45041": "Florence County, South Carolina", + "45043": "Georgetown County, South Carolina", + "45045": "Greenville County, South Carolina", + "45047": "Greenwood County, South Carolina", + "45049": "Hampton County, South Carolina", + "45051": "Horry County, South Carolina", + "45053": "Jasper County, South Carolina", + "45055": "Kershaw County, South Carolina", + "45057": "Lancaster County, South Carolina", + "45059": "Laurens County, South Carolina", + "45061": "Lee County, South Carolina", + "45063": "Lexington County, South Carolina", + "45065": "McCormick County, South Carolina", + "45067": "Marion County, South Carolina", + "45069": "Marlboro County, South Carolina", + "45071": "Newberry County, South Carolina", + "45073": "Oconee County, South Carolina", + "45075": "Orangeburg County, South Carolina", + "45077": "Pickens County, South Carolina", + "45079": "Richland County, South Carolina", + "45081": "Saluda County, South Carolina", + "45083": "Spartanburg County, South Carolina", + "45085": "Sumter County, South Carolina", + "45087": "Union County, South Carolina", + "45089": "Williamsburg County, South Carolina", + "45091": "York County, South Carolina", + "46003": "Aurora County, South Dakota", + "46005": "Beadle County, South Dakota", + "46007": "Bennett County, South Dakota", + "46009": "Bon Homme County, South Dakota", + "46011": "Brookings County, South Dakota", + "46013": "Brown County, South Dakota", + "46015": "Brule County, South Dakota", + "46017": "Buffalo County, South Dakota", + "46019": "Butte County, South Dakota", + "46021": "Campbell County, South Dakota", + "46023": "Charles Mix County, South Dakota", + "46025": "Clark County, South Dakota", + "46027": "Clay County, South Dakota", + "46029": "Codington County, South Dakota", + "46031": "Corson County, South Dakota", + "46033": "Custer County, South Dakota", + "46035": "Davison County, South Dakota", + "46037": "Day County, South Dakota", + "46039": "Deuel County, South Dakota", + "46041": "Dewey County, South Dakota", + "46043": "Douglas County, South Dakota", + "46045": "Edmunds County, South Dakota", + "46047": "Fall River County, South Dakota", + "46049": "Faulk County, South Dakota", + "46051": "Grant County, South Dakota", + "46053": "Gregory County, South Dakota", + "46055": "Haakon County, South Dakota", + "46057": "Hamlin County, South Dakota", + "46059": "Hand County, South Dakota", + "46061": "Hanson County, South Dakota", + "46063": "Harding County, South Dakota", + "46065": "Hughes County, South Dakota", + "46067": "Hutchinson County, South Dakota", + "46069": "Hyde County, South Dakota", + "46071": "Jackson County, South Dakota", + "46073": "Jerauld County, South Dakota", + "46075": "Jones County, South Dakota", + "46077": "Kingsbury County, South Dakota", + "46079": "Lake County, South Dakota", + "46081": "Lawrence County, South Dakota", + "46083": "Lincoln County, South Dakota", + "46085": "Lyman County, South Dakota", + "46087": "McCook County, South Dakota", + "46089": "McPherson County, South Dakota", + "46091": "Marshall County, South Dakota", + "46093": "Meade County, South Dakota", + "46095": "Mellette County, South Dakota", + "46097": "Miner County, South Dakota", + "46099": "Minnehaha County, South Dakota", + "46101": "Moody County, South Dakota", + "46102": "Oglala Lakota County, South Dakota", + "46103": "Pennington County, South Dakota", + "46105": "Perkins County, South Dakota", + "46107": "Potter County, South Dakota", + "46109": "Roberts County, South Dakota", + "46111": "Sanborn County, South Dakota", + "46115": "Spink County, South Dakota", + "46117": "Stanley County, South Dakota", + "46119": "Sully County, South Dakota", + "46121": "Todd County, South Dakota", + "46123": "Tripp County, South Dakota", + "46125": "Turner County, South Dakota", + "46127": "Union County, South Dakota", + "46129": "Walworth County, South Dakota", + "46135": "Yankton County, South Dakota", + "46137": "Ziebach County, South Dakota", + "47001": "Anderson County, Tennessee", + "47003": "Bedford County, Tennessee", + "47005": "Benton County, Tennessee", + "47007": "Bledsoe County, Tennessee", + "47009": "Blount County, Tennessee", + "47011": "Bradley County, Tennessee", + "47013": "Campbell County, Tennessee", + "47015": "Cannon County, Tennessee", + "47017": "Carroll County, Tennessee", + "47019": "Carter County, Tennessee", + "47021": "Cheatham County, Tennessee", + "47023": "Chester County, Tennessee", + "47025": "Claiborne County, Tennessee", + "47027": "Clay County, Tennessee", + "47029": "Cocke County, Tennessee", + "47031": "Coffee County, Tennessee", + "47033": "Crockett County, Tennessee", + "47035": "Cumberland County, Tennessee", + "47037": "Davidson County, Tennessee", + "47039": "Decatur County, Tennessee", + "47041": "DeKalb County, Tennessee", + "47043": "Dickson County, Tennessee", + "47045": "Dyer County, Tennessee", + "47047": "Fayette County, Tennessee", + "47049": "Fentress County, Tennessee", + "47051": "Franklin County, Tennessee", + "47053": "Gibson County, Tennessee", + "47055": "Giles County, Tennessee", + "47057": "Grainger County, Tennessee", + "47059": "Greene County, Tennessee", + "47061": "Grundy County, Tennessee", + "47063": "Hamblen County, Tennessee", + "47065": "Hamilton County, Tennessee", + "47067": "Hancock County, Tennessee", + "47069": "Hardeman County, Tennessee", + "47071": "Hardin County, Tennessee", + "47073": "Hawkins County, Tennessee", + "47075": "Haywood County, Tennessee", + "47077": "Henderson County, Tennessee", + "47079": "Henry County, Tennessee", + "47081": "Hickman County, Tennessee", + "47083": "Houston County, Tennessee", + "47085": "Humphreys County, Tennessee", + "47087": "Jackson County, Tennessee", + "47089": "Jefferson County, Tennessee", + "47091": "Johnson County, Tennessee", + "47093": "Knox County, Tennessee", + "47095": "Lake County, Tennessee", + "47097": "Lauderdale County, Tennessee", + "47099": "Lawrence County, Tennessee", + "47101": "Lewis County, Tennessee", + "47103": "Lincoln County, Tennessee", + "47105": "Loudon County, Tennessee", + "47107": "McMinn County, Tennessee", + "47109": "McNairy County, Tennessee", + "47111": "Macon County, Tennessee", + "47113": "Madison County, Tennessee", + "47115": "Marion County, Tennessee", + "47117": "Marshall County, Tennessee", + "47119": "Maury County, Tennessee", + "47121": "Meigs County, Tennessee", + "47123": "Monroe County, Tennessee", + "47125": "Montgomery County, Tennessee", + "47127": "Moore County, Tennessee", + "47129": "Morgan County, Tennessee", + "47131": "Obion County, Tennessee", + "47133": "Overton County, Tennessee", + "47135": "Perry County, Tennessee", + "47137": "Pickett County, Tennessee", + "47139": "Polk County, Tennessee", + "47141": "Putnam County, Tennessee", + "47143": "Rhea County, Tennessee", + "47145": "Roane County, Tennessee", + "47147": "Robertson County, Tennessee", + "47149": "Rutherford County, Tennessee", + "47151": "Scott County, Tennessee", + "47153": "Sequatchie County, Tennessee", + "47155": "Sevier County, Tennessee", + "47157": "Shelby County, Tennessee", + "47159": "Smith County, Tennessee", + "47161": "Stewart County, Tennessee", + "47163": "Sullivan County, Tennessee", + "47165": "Sumner County, Tennessee", + "47167": "Tipton County, Tennessee", + "47169": "Trousdale County, Tennessee", + "47171": "Unicoi County, Tennessee", + "47173": "Union County, Tennessee", + "47175": "Van Buren County, Tennessee", + "47177": "Warren County, Tennessee", + "47179": "Washington County, Tennessee", + "47181": "Wayne County, Tennessee", + "47183": "Weakley County, Tennessee", + "47185": "White County, Tennessee", + "47187": "Williamson County, Tennessee", + "47189": "Wilson County, Tennessee", + "48001": "Anderson County, Texas", + "48003": "Andrews County, Texas", + "48005": "Angelina County, Texas", + "48007": "Aransas County, Texas", + "48009": "Archer County, Texas", + "48011": "Armstrong County, Texas", + "48013": "Atascosa County, Texas", + "48015": "Austin County, Texas", + "48017": "Bailey County, Texas", + "48019": "Bandera County, Texas", + "48021": "Bastrop County, Texas", + "48023": "Baylor County, Texas", + "48025": "Bee County, Texas", + "48027": "Bell County, Texas", + "48029": "Bexar County, Texas", + "48031": "Blanco County, Texas", + "48033": "Borden County, Texas", + "48035": "Bosque County, Texas", + "48037": "Bowie County, Texas", + "48039": "Brazoria County, Texas", + "48041": "Brazos County, Texas", + "48043": "Brewster County, Texas", + "48045": "Briscoe County, Texas", + "48047": "Brooks County, Texas", + "48049": "Brown County, Texas", + "48051": "Burleson County, Texas", + "48053": "Burnet County, Texas", + "48055": "Caldwell County, Texas", + "48057": "Calhoun County, Texas", + "48059": "Callahan County, Texas", + "48061": "Cameron County, Texas", + "48063": "Camp County, Texas", + "48065": "Carson County, Texas", + "48067": "Cass County, Texas", + "48069": "Castro County, Texas", + "48071": "Chambers County, Texas", + "48073": "Cherokee County, Texas", + "48075": "Childress County, Texas", + "48077": "Clay County, Texas", + "48079": "Cochran County, Texas", + "48081": "Coke County, Texas", + "48083": "Coleman County, Texas", + "48085": "Collin County, Texas", + "48087": "Collingsworth County, Texas", + "48089": "Colorado County, Texas", + "48091": "Comal County, Texas", + "48093": "Comanche County, Texas", + "48095": "Concho County, Texas", + "48097": "Cooke County, Texas", + "48099": "Coryell County, Texas", + "48101": "Cottle County, Texas", + "48103": "Crane County, Texas", + "48105": "Crockett County, Texas", + "48107": "Crosby County, Texas", + "48109": "Culberson County, Texas", + "48111": "Dallam County, Texas", + "48113": "Dallas County, Texas", + "48115": "Dawson County, Texas", + "48117": "Deaf Smith County, Texas", + "48119": "Delta County, Texas", + "48121": "Denton County, Texas", + "48123": "DeWitt County, Texas", + "48125": "Dickens County, Texas", + "48127": "Dimmit County, Texas", + "48129": "Donley County, Texas", + "48131": "Duval County, Texas", + "48133": "Eastland County, Texas", + "48135": "Ector County, Texas", + "48137": "Edwards County, Texas", + "48139": "Ellis County, Texas", + "48141": "El Paso County, Texas", + "48143": "Erath County, Texas", + "48145": "Falls County, Texas", + "48147": "Fannin County, Texas", + "48149": "Fayette County, Texas", + "48151": "Fisher County, Texas", + "48153": "Floyd County, Texas", + "48155": "Foard County, Texas", + "48157": "Fort Bend County, Texas", + "48159": "Franklin County, Texas", + "48161": "Freestone County, Texas", + "48163": "Frio County, Texas", + "48165": "Gaines County, Texas", + "48167": "Galveston County, Texas", + "48169": "Garza County, Texas", + "48171": "Gillespie County, Texas", + "48173": "Glasscock County, Texas", + "48175": "Goliad County, Texas", + "48177": "Gonzales County, Texas", + "48179": "Gray County, Texas", + "48181": "Grayson County, Texas", + "48183": "Gregg County, Texas", + "48185": "Grimes County, Texas", + "48187": "Guadalupe County, Texas", + "48189": "Hale County, Texas", + "48191": "Hall County, Texas", + "48193": "Hamilton County, Texas", + "48195": "Hansford County, Texas", + "48197": "Hardeman County, Texas", + "48199": "Hardin County, Texas", + "48201": "Harris County, Texas", + "48203": "Harrison County, Texas", + "48205": "Hartley County, Texas", + "48207": "Haskell County, Texas", + "48209": "Hays County, Texas", + "48211": "Hemphill County, Texas", + "48213": "Henderson County, Texas", + "48215": "Hidalgo County, Texas", + "48217": "Hill County, Texas", + "48219": "Hockley County, Texas", + "48221": "Hood County, Texas", + "48223": "Hopkins County, Texas", + "48225": "Houston County, Texas", + "48227": "Howard County, Texas", + "48229": "Hudspeth County, Texas", + "48231": "Hunt County, Texas", + "48233": "Hutchinson County, Texas", + "48235": "Irion County, Texas", + "48237": "Jack County, Texas", + "48239": "Jackson County, Texas", + "48241": "Jasper County, Texas", + "48243": "Jeff Davis County, Texas", + "48245": "Jefferson County, Texas", + "48247": "Jim Hogg County, Texas", + "48249": "Jim Wells County, Texas", + "48251": "Johnson County, Texas", + "48253": "Jones County, Texas", + "48255": "Karnes County, Texas", + "48257": "Kaufman County, Texas", + "48259": "Kendall County, Texas", + "48261": "Kenedy County, Texas", + "48263": "Kent County, Texas", + "48265": "Kerr County, Texas", + "48267": "Kimble County, Texas", + "48269": "King County, Texas", + "48271": "Kinney County, Texas", + "48273": "Kleberg County, Texas", + "48275": "Knox County, Texas", + "48277": "Lamar County, Texas", + "48279": "Lamb County, Texas", + "48281": "Lampasas County, Texas", + "48283": "La Salle County, Texas", + "48285": "Lavaca County, Texas", + "48287": "Lee County, Texas", + "48289": "Leon County, Texas", + "48291": "Liberty County, Texas", + "48293": "Limestone County, Texas", + "48295": "Lipscomb County, Texas", + "48297": "Live Oak County, Texas", + "48299": "Llano County, Texas", + "48301": "Loving County, Texas", + "48303": "Lubbock County, Texas", + "48305": "Lynn County, Texas", + "48307": "McCulloch County, Texas", + "48309": "McLennan County, Texas", + "48311": "McMullen County, Texas", + "48313": "Madison County, Texas", + "48315": "Marion County, Texas", + "48317": "Martin County, Texas", + "48319": "Mason County, Texas", + "48321": "Matagorda County, Texas", + "48323": "Maverick County, Texas", + "48325": "Medina County, Texas", + "48327": "Menard County, Texas", + "48329": "Midland County, Texas", + "48331": "Milam County, Texas", + "48333": "Mills County, Texas", + "48335": "Mitchell County, Texas", + "48337": "Montague County, Texas", + "48339": "Montgomery County, Texas", + "48341": "Moore County, Texas", + "48343": "Morris County, Texas", + "48345": "Motley County, Texas", + "48347": "Nacogdoches County, Texas", + "48349": "Navarro County, Texas", + "48351": "Newton County, Texas", + "48353": "Nolan County, Texas", + "48355": "Nueces County, Texas", + "48357": "Ochiltree County, Texas", + "48359": "Oldham County, Texas", + "48361": "Orange County, Texas", + "48363": "Palo Pinto County, Texas", + "48365": "Panola County, Texas", + "48367": "Parker County, Texas", + "48369": "Parmer County, Texas", + "48371": "Pecos County, Texas", + "48373": "Polk County, Texas", + "48375": "Potter County, Texas", + "48377": "Presidio County, Texas", + "48379": "Rains County, Texas", + "48381": "Randall County, Texas", + "48383": "Reagan County, Texas", + "48385": "Real County, Texas", + "48387": "Red River County, Texas", + "48389": "Reeves County, Texas", + "48391": "Refugio County, Texas", + "48393": "Roberts County, Texas", + "48395": "Robertson County, Texas", + "48397": "Rockwall County, Texas", + "48399": "Runnels County, Texas", + "48401": "Rusk County, Texas", + "48403": "Sabine County, Texas", + "48405": "San Augustine County, Texas", + "48407": "San Jacinto County, Texas", + "48409": "San Patricio County, Texas", + "48411": "San Saba County, Texas", + "48413": "Schleicher County, Texas", + "48415": "Scurry County, Texas", + "48417": "Shackelford County, Texas", + "48419": "Shelby County, Texas", + "48421": "Sherman County, Texas", + "48423": "Smith County, Texas", + "48425": "Somervell County, Texas", + "48427": "Starr County, Texas", + "48429": "Stephens County, Texas", + "48431": "Sterling County, Texas", + "48433": "Stonewall County, Texas", + "48435": "Sutton County, Texas", + "48437": "Swisher County, Texas", + "48439": "Tarrant County, Texas", + "48441": "Taylor County, Texas", + "48443": "Terrell County, Texas", + "48445": "Terry County, Texas", + "48447": "Throckmorton County, Texas", + "48449": "Titus County, Texas", + "48451": "Tom Green County, Texas", + "48453": "Travis County, Texas", + "48455": "Trinity County, Texas", + "48457": "Tyler County, Texas", + "48459": "Upshur County, Texas", + "48461": "Upton County, Texas", + "48463": "Uvalde County, Texas", + "48465": "Val Verde County, Texas", + "48467": "Van Zandt County, Texas", + "48469": "Victoria County, Texas", + "48471": "Walker County, Texas", + "48473": "Waller County, Texas", + "48475": "Ward County, Texas", + "48477": "Washington County, Texas", + "48479": "Webb County, Texas", + "48481": "Wharton County, Texas", + "48483": "Wheeler County, Texas", + "48485": "Wichita County, Texas", + "48487": "Wilbarger County, Texas", + "48489": "Willacy County, Texas", + "48491": "Williamson County, Texas", + "48493": "Wilson County, Texas", + "48495": "Winkler County, Texas", + "48497": "Wise County, Texas", + "48499": "Wood County, Texas", + "48501": "Yoakum County, Texas", + "48503": "Young County, Texas", + "48505": "Zapata County, Texas", + "48507": "Zavala County, Texas", + "49001": "Beaver County, Utah", + "49003": "Box Elder County, Utah", + "49005": "Cache County, Utah", + "49007": "Carbon County, Utah", + "49009": "Daggett County, Utah", + "49011": "Davis County, Utah", + "49013": "Duchesne County, Utah", + "49015": "Emery County, Utah", + "49017": "Garfield County, Utah", + "49019": "Grand County, Utah", + "49021": "Iron County, Utah", + "49023": "Juab County, Utah", + "49025": "Kane County, Utah", + "49027": "Millard County, Utah", + "49029": "Morgan County, Utah", + "49031": "Piute County, Utah", + "49033": "Rich County, Utah", + "49035": "Salt Lake County, Utah", + "49037": "San Juan County, Utah", + "49039": "Sanpete County, Utah", + "49041": "Sevier County, Utah", + "49043": "Summit County, Utah", + "49045": "Tooele County, Utah", + "49047": "Uintah County, Utah", + "49049": "Utah County, Utah", + "49051": "Wasatch County, Utah", + "49053": "Washington County, Utah", + "49055": "Wayne County, Utah", + "49057": "Weber County, Utah", + "50001": "Addison County, Vermont", + "50003": "Bennington County, Vermont", + "50005": "Caledonia County, Vermont", + "50007": "Chittenden County, Vermont", + "50009": "Essex County, Vermont", + "50011": "Franklin County, Vermont", + "50013": "Grand Isle County, Vermont", + "50015": "Lamoille County, Vermont", + "50017": "Orange County, Vermont", + "50019": "Orleans County, Vermont", + "50021": "Rutland County, Vermont", + "50023": "Washington County, Vermont", + "50025": "Windham County, Vermont", + "50027": "Windsor County, Vermont", + "51001": "Accomack County, Virginia", + "51003": "Albemarle County, Virginia", + "51005": "Alleghany County, Virginia", + "51007": "Amelia County, Virginia", + "51009": "Amherst County, Virginia", + "51011": "Appomattox County, Virginia", + "51013": "Arlington County, Virginia", + "51015": "Augusta County, Virginia", + "51017": "Bath County, Virginia", + "51019": "Bedford County, Virginia", + "51021": "Bland County, Virginia", + "51023": "Botetourt County, Virginia", + "51025": "Brunswick County, Virginia", + "51027": "Buchanan County, Virginia", + "51029": "Buckingham County, Virginia", + "51031": "Campbell County, Virginia", + "51033": "Caroline County, Virginia", + "51035": "Carroll County, Virginia", + "51036": "Charles City County, Virginia", + "51037": "Charlotte County, Virginia", + "51041": "Chesterfield County, Virginia", + "51043": "Clarke County, Virginia", + "51045": "Craig County, Virginia", + "51047": "Culpeper County, Virginia", + "51049": "Cumberland County, Virginia", + "51051": "Dickenson County, Virginia", + "51053": "Dinwiddie County, Virginia", + "51057": "Essex County, Virginia", + "51059": "Fairfax County, Virginia", + "51061": "Fauquier County, Virginia", + "51063": "Floyd County, Virginia", + "51065": "Fluvanna County, Virginia", + "51067": "Franklin County, Virginia", + "51069": "Frederick County, Virginia", + "51071": "Giles County, Virginia", + "51073": "Gloucester County, Virginia", + "51075": "Goochland County, Virginia", + "51077": "Grayson County, Virginia", + "51079": "Greene County, Virginia", + "51081": "Greensville County, Virginia", + "51083": "Halifax County, Virginia", + "51085": "Hanover County, Virginia", + "51087": "Henrico County, Virginia", + "51089": "Henry County, Virginia", + "51091": "Highland County, Virginia", + "51093": "Isle of Wight County, Virginia", + "51095": "James City County, Virginia", + "51097": "King and Queen County, Virginia", + "51099": "King George County, Virginia", + "51101": "King William County, Virginia", + "51103": "Lancaster County, Virginia", + "51105": "Lee County, Virginia", + "51107": "Loudoun County, Virginia", + "51109": "Louisa County, Virginia", + "51111": "Lunenburg County, Virginia", + "51113": "Madison County, Virginia", + "51115": "Mathews County, Virginia", + "51117": "Mecklenburg County, Virginia", + "51119": "Middlesex County, Virginia", + "51121": "Montgomery County, Virginia", + "51125": "Nelson County, Virginia", + "51127": "New Kent County, Virginia", + "51131": "Northampton County, Virginia", + "51133": "Northumberland County, Virginia", + "51135": "Nottoway County, Virginia", + "51137": "Orange County, Virginia", + "51139": "Page County, Virginia", + "51141": "Patrick County, Virginia", + "51143": "Pittsylvania County, Virginia", + "51145": "Powhatan County, Virginia", + "51147": "Prince Edward County, Virginia", + "51149": "Prince George County, Virginia", + "51153": "Prince William County, Virginia", + "51155": "Pulaski County, Virginia", + "51157": "Rappahannock County, Virginia", + "51159": "Richmond County, Virginia", + "51161": "Roanoke County, Virginia", + "51163": "Rockbridge County, Virginia", + "51165": "Rockingham County, Virginia", + "51167": "Russell County, Virginia", + "51169": "Scott County, Virginia", + "51171": "Shenandoah County, Virginia", + "51173": "Smyth County, Virginia", + "51175": "Southampton County, Virginia", + "51177": "Spotsylvania County, Virginia", + "51179": "Stafford County, Virginia", + "51181": "Surry County, Virginia", + "51183": "Sussex County, Virginia", + "51185": "Tazewell County, Virginia", + "51187": "Warren County, Virginia", + "51191": "Washington County, Virginia", + "51193": "Westmoreland County, Virginia", + "51195": "Wise County, Virginia", + "51197": "Wythe County, Virginia", + "51199": "York County, Virginia", + "51510": "Alexandria city, Virginia", + "51520": "Bristol city, Virginia", + "51530": "Buena Vista city, Virginia", + "51540": "Charlottesville city, Virginia", + "51550": "Chesapeake city, Virginia", + "51570": "Colonial Heights city, Virginia", + "51580": "Covington city, Virginia", + "51590": "Danville city, Virginia", + "51595": "Emporia city, Virginia", + "51600": "Fairfax city, Virginia", + "51610": "Falls Church city, Virginia", + "51620": "Franklin city, Virginia", + "51630": "Fredericksburg city, Virginia", + "51640": "Galax city, Virginia", + "51650": "Hampton city, Virginia", + "51660": "Harrisonburg city, Virginia", + "51670": "Hopewell city, Virginia", + "51678": "Lexington city, Virginia", + "51680": "Lynchburg city, Virginia", + "51683": "Manassas city, Virginia", + "51685": "Manassas Park city, Virginia", + "51690": "Martinsville city, Virginia", + "51700": "Newport News city, Virginia", + "51710": "Norfolk city, Virginia", + "51720": "Norton city, Virginia", + "51730": "Petersburg city, Virginia", + "51735": "Poquoson city, Virginia", + "51740": "Portsmouth city, Virginia", + "51750": "Radford city, Virginia", + "51760": "Richmond city, Virginia", + "51770": "Roanoke city, Virginia", + "51775": "Salem city, Virginia", + "51790": "Staunton city, Virginia", + "51800": "Suffolk city, Virginia", + "51810": "Virginia Beach city, Virginia", + "51820": "Waynesboro city, Virginia", + "51830": "Williamsburg city, Virginia", + "51840": "Winchester city, Virginia", + "53001": "Adams County, Washington", + "53003": "Asotin County, Washington", + "53005": "Benton County, Washington", + "53007": "Chelan County, Washington", + "53009": "Clallam County, Washington", + "53011": "Clark County, Washington", + "53013": "Columbia County, Washington", + "53015": "Cowlitz County, Washington", + "53017": "Douglas County, Washington", + "53019": "Ferry County, Washington", + "53021": "Franklin County, Washington", + "53023": "Garfield County, Washington", + "53025": "Grant County, Washington", + "53027": "Grays Harbor County, Washington", + "53029": "Island County, Washington", + "53031": "Jefferson County, Washington", + "53033": "King County, Washington", + "53035": "Kitsap County, Washington", + "53037": "Kittitas County, Washington", + "53039": "Klickitat County, Washington", + "53041": "Lewis County, Washington", + "53043": "Lincoln County, Washington", + "53045": "Mason County, Washington", + "53047": "Okanogan County, Washington", + "53049": "Pacific County, Washington", + "53051": "Pend Oreille County, Washington", + "53053": "Pierce County, Washington", + "53055": "San Juan County, Washington", + "53057": "Skagit County, Washington", + "53059": "Skamania County, Washington", + "53061": "Snohomish County, Washington", + "53063": "Spokane County, Washington", + "53065": "Stevens County, Washington", + "53067": "Thurston County, Washington", + "53069": "Wahkiakum County, Washington", + "53071": "Walla Walla County, Washington", + "53073": "Whatcom County, Washington", + "53075": "Whitman County, Washington", + "53077": "Yakima County, Washington", + "54001": "Barbour County, West Virginia", + "54003": "Berkeley County, West Virginia", + "54005": "Boone County, West Virginia", + "54007": "Braxton County, West Virginia", + "54009": "Brooke County, West Virginia", + "54011": "Cabell County, West Virginia", + "54013": "Calhoun County, West Virginia", + "54015": "Clay County, West Virginia", + "54017": "Doddridge County, West Virginia", + "54019": "Fayette County, West Virginia", + "54021": "Gilmer County, West Virginia", + "54023": "Grant County, West Virginia", + "54025": "Greenbrier County, West Virginia", + "54027": "Hampshire County, West Virginia", + "54029": "Hancock County, West Virginia", + "54031": "Hardy County, West Virginia", + "54033": "Harrison County, West Virginia", + "54035": "Jackson County, West Virginia", + "54037": "Jefferson County, West Virginia", + "54039": "Kanawha County, West Virginia", + "54041": "Lewis County, West Virginia", + "54043": "Lincoln County, West Virginia", + "54045": "Logan County, West Virginia", + "54047": "McDowell County, West Virginia", + "54049": "Marion County, West Virginia", + "54051": "Marshall County, West Virginia", + "54053": "Mason County, West Virginia", + "54055": "Mercer County, West Virginia", + "54057": "Mineral County, West Virginia", + "54059": "Mingo County, West Virginia", + "54061": "Monongalia County, West Virginia", + "54063": "Monroe County, West Virginia", + "54065": "Morgan County, West Virginia", + "54067": "Nicholas County, West Virginia", + "54069": "Ohio County, West Virginia", + "54071": "Pendleton County, West Virginia", + "54073": "Pleasants County, West Virginia", + "54075": "Pocahontas County, West Virginia", + "54077": "Preston County, West Virginia", + "54079": "Putnam County, West Virginia", + "54081": "Raleigh County, West Virginia", + "54083": "Randolph County, West Virginia", + "54085": "Ritchie County, West Virginia", + "54087": "Roane County, West Virginia", + "54089": "Summers County, West Virginia", + "54091": "Taylor County, West Virginia", + "54093": "Tucker County, West Virginia", + "54095": "Tyler County, West Virginia", + "54097": "Upshur County, West Virginia", + "54099": "Wayne County, West Virginia", + "54101": "Webster County, West Virginia", + "54103": "Wetzel County, West Virginia", + "54105": "Wirt County, West Virginia", + "54107": "Wood County, West Virginia", + "54109": "Wyoming County, West Virginia", + "55001": "Adams County, Wisconsin", + "55003": "Ashland County, Wisconsin", + "55005": "Barron County, Wisconsin", + "55007": "Bayfield County, Wisconsin", + "55009": "Brown County, Wisconsin", + "55011": "Buffalo County, Wisconsin", + "55013": "Burnett County, Wisconsin", + "55015": "Calumet County, Wisconsin", + "55017": "Chippewa County, Wisconsin", + "55019": "Clark County, Wisconsin", + "55021": "Columbia County, Wisconsin", + "55023": "Crawford County, Wisconsin", + "55025": "Dane County, Wisconsin", + "55027": "Dodge County, Wisconsin", + "55029": "Door County, Wisconsin", + "55031": "Douglas County, Wisconsin", + "55033": "Dunn County, Wisconsin", + "55035": "Eau Claire County, Wisconsin", + "55037": "Florence County, Wisconsin", + "55039": "Fond du Lac County, Wisconsin", + "55041": "Forest County, Wisconsin", + "55043": "Grant County, Wisconsin", + "55045": "Green County, Wisconsin", + "55047": "Green Lake County, Wisconsin", + "55049": "Iowa County, Wisconsin", + "55051": "Iron County, Wisconsin", + "55053": "Jackson County, Wisconsin", + "55055": "Jefferson County, Wisconsin", + "55057": "Juneau County, Wisconsin", + "55059": "Kenosha County, Wisconsin", + "55061": "Kewaunee County, Wisconsin", + "55063": "La Crosse County, Wisconsin", + "55065": "Lafayette County, Wisconsin", + "55067": "Langlade County, Wisconsin", + "55069": "Lincoln County, Wisconsin", + "55071": "Manitowoc County, Wisconsin", + "55073": "Marathon County, Wisconsin", + "55075": "Marinette County, Wisconsin", + "55077": "Marquette County, Wisconsin", + "55078": "Menominee County, Wisconsin", + "55079": "Milwaukee County, Wisconsin", + "55081": "Monroe County, Wisconsin", + "55083": "Oconto County, Wisconsin", + "55085": "Oneida County, Wisconsin", + "55087": "Outagamie County, Wisconsin", + "55089": "Ozaukee County, Wisconsin", + "55091": "Pepin County, Wisconsin", + "55093": "Pierce County, Wisconsin", + "55095": "Polk County, Wisconsin", + "55097": "Portage County, Wisconsin", + "55099": "Price County, Wisconsin", + "55101": "Racine County, Wisconsin", + "55103": "Richland County, Wisconsin", + "55105": "Rock County, Wisconsin", + "55107": "Rusk County, Wisconsin", + "55109": "St. Croix County, Wisconsin", + "55111": "Sauk County, Wisconsin", + "55113": "Sawyer County, Wisconsin", + "55115": "Shawano County, Wisconsin", + "55117": "Sheboygan County, Wisconsin", + "55119": "Taylor County, Wisconsin", + "55121": "Trempealeau County, Wisconsin", + "55123": "Vernon County, Wisconsin", + "55125": "Vilas County, Wisconsin", + "55127": "Walworth County, Wisconsin", + "55129": "Washburn County, Wisconsin", + "55131": "Washington County, Wisconsin", + "55133": "Waukesha County, Wisconsin", + "55135": "Waupaca County, Wisconsin", + "55137": "Waushara County, Wisconsin", + "55139": "Winnebago County, Wisconsin", + "55141": "Wood County, Wisconsin", + "56001": "Albany County, Wyoming", + "56003": "Big Horn County, Wyoming", + "56005": "Campbell County, Wyoming", + "56007": "Carbon County, Wyoming", + "56009": "Converse County, Wyoming", + "56011": "Crook County, Wyoming", + "56013": "Fremont County, Wyoming", + "56015": "Goshen County, Wyoming", + "56017": "Hot Springs County, Wyoming", + "56019": "Johnson County, Wyoming", + "56021": "Laramie County, Wyoming", + "56023": "Lincoln County, Wyoming", + "56025": "Natrona County, Wyoming", + "56027": "Niobrara County, Wyoming", + "56029": "Park County, Wyoming", + "56031": "Platte County, Wyoming", + "56033": "Sheridan County, Wyoming", + "56035": "Sublette County, Wyoming", + "56037": "Sweetwater County, Wyoming", + "56039": "Teton County, Wyoming", + "56041": "Uinta County, Wyoming", + "56043": "Washakie County, Wyoming", + "56045": "Weston County, Wyoming", + "72001": "Adjuntas Municipio, Puerto Rico", + "72003": "Aguada Municipio, Puerto Rico", + "72005": "Aguadilla Municipio, Puerto Rico", + "72007": "Aguas Buenas Municipio, Puerto Rico", + "72009": "Aibonito Municipio, Puerto Rico", + "72011": "Añasco Municipio, Puerto Rico", + "72013": "Arecibo Municipio, Puerto Rico", + "72015": "Arroyo Municipio, Puerto Rico", + "72017": "Barceloneta Municipio, Puerto Rico", + "72019": "Barranquitas Municipio, Puerto Rico", + "72021": "Bayamón Municipio, Puerto Rico", + "72023": "Cabo Rojo Municipio, Puerto Rico", + "72025": "Caguas Municipio, Puerto Rico", + "72027": "Camuy Municipio, Puerto Rico", + "72029": "Canóvanas Municipio, Puerto Rico", + "72031": "Carolina Municipio, Puerto Rico", + "72033": "Cataño Municipio, Puerto Rico", + "72035": "Cayey Municipio, Puerto Rico", + "72037": "Ceiba Municipio, Puerto Rico", + "72039": "Ciales Municipio, Puerto Rico", + "72041": "Cidra Municipio, Puerto Rico", + "72043": "Coamo Municipio, Puerto Rico", + "72045": "Comerío Municipio, Puerto Rico", + "72047": "Corozal Municipio, Puerto Rico", + "72049": "Culebra Municipio, Puerto Rico", + "72051": "Dorado Municipio, Puerto Rico", + "72053": "Fajardo Municipio, Puerto Rico", + "72054": "Florida Municipio, Puerto Rico", + "72055": "Guánica Municipio, Puerto Rico", + "72057": "Guayama Municipio, Puerto Rico", + "72059": "Guayanilla Municipio, Puerto Rico", + "72061": "Guaynabo Municipio, Puerto Rico", + "72063": "Gurabo Municipio, Puerto Rico", + "72065": "Hatillo Municipio, Puerto Rico", + "72067": "Hormigueros Municipio, Puerto Rico", + "72069": "Humacao Municipio, Puerto Rico", + "72071": "Isabela Municipio, Puerto Rico", + "72073": "Jayuya Municipio, Puerto Rico", + "72075": "Juana Díaz Municipio, Puerto Rico", + "72077": "Juncos Municipio, Puerto Rico", + "72079": "Lajas Municipio, Puerto Rico", + "72081": "Lares Municipio, Puerto Rico", + "72083": "Las Marías Municipio, Puerto Rico", + "72085": "Las Piedras Municipio, Puerto Rico", + "72087": "Loíza Municipio, Puerto Rico", + "72089": "Luquillo Municipio, Puerto Rico", + "72091": "Manatí Municipio, Puerto Rico", + "72093": "Maricao Municipio, Puerto Rico", + "72095": "Maunabo Municipio, Puerto Rico", + "72097": "Mayagüez Municipio, Puerto Rico", + "72099": "Moca Municipio, Puerto Rico", + "72101": "Morovis Municipio, Puerto Rico", + "72103": "Naguabo Municipio, Puerto Rico", + "72105": "Naranjito Municipio, Puerto Rico", + "72107": "Orocovis Municipio, Puerto Rico", + "72109": "Patillas Municipio, Puerto Rico", + "72111": "Peñuelas Municipio, Puerto Rico", + "72113": "Ponce Municipio, Puerto Rico", + "72115": "Quebradillas Municipio, Puerto Rico", + "72117": "Rincón Municipio, Puerto Rico", + "72119": "Río Grande Municipio, Puerto Rico", + "72121": "Sabana Grande Municipio, Puerto Rico", + "72123": "Salinas Municipio, Puerto Rico", + "72125": "San Germán Municipio, Puerto Rico", + "72127": "San Juan Municipio, Puerto Rico", + "72129": "San Lorenzo Municipio, Puerto Rico", + "72131": "San Sebastián Municipio, Puerto Rico", + "72133": "Santa Isabel Municipio, Puerto Rico", + "72135": "Toa Alta Municipio, Puerto Rico", + "72137": "Toa Baja Municipio, Puerto Rico", + "72139": "Trujillo Alto Municipio, Puerto Rico", + "72141": "Utuado Municipio, Puerto Rico", + "72143": "Vega Alta Municipio, Puerto Rico", + "72145": "Vega Baja Municipio, Puerto Rico", + "72147": "Vieques Municipio, Puerto Rico", + "72149": "Villalba Municipio, Puerto Rico", + "72151": "Yabucoa Municipio, Puerto Rico", + "72153": "Yauco Municipio, Puerto Rico" + }, + "cgt_gain_band": { + "gain_1000000_to_1999999": "GBP 1,000,000 to GBP 1,999,999", + "gain_100000_to_249999": "GBP 100,000 to GBP 249,999", + "gain_2000000_to_4999999": "GBP 2,000,000 to GBP 4,999,999", + "gain_250000_to_499999": "GBP 250,000 to GBP 499,999", + "gain_25000_to_49999": "GBP 25,000 to GBP 49,999", + "gain_5000000_plus": "GBP 5,000,000 and over", + "gain_500000_to_999999": "GBP 500,000 to GBP 999,999", + "gain_50000_to_99999": "GBP 50,000 to GBP 99,999" + }, + "child_entitlement": { + "No": "No", + "Yes": "Yes" + }, + "client_type": { + "Pension age": "Pension age", + "Working age": "Working age", + "all": "Total" + }, + "cms_aca.state_abrvtn": { + "ak": "Alaska", + "al": "Alabama", + "ar": "Arkansas", + "az": "Arizona", + "ca": "California", + "co": "Colorado", + "ct": "Connecticut", + "dc": "District of Columbia", + "de": "Delaware", + "fl": "Florida", + "ga": "Georgia", + "hi": "Hawaii", + "ia": "Iowa", + "id": "Idaho", + "il": "Illinois", + "in": "Indiana", + "ks": "Kansas", + "ky": "Kentucky", + "la": "Louisiana", + "ma": "Massachusetts", + "md": "Maryland", + "me": "Maine", + "mi": "Michigan", + "mn": "Minnesota", + "mo": "Missouri", + "ms": "Mississippi", + "mt": "Montana", + "nc": "North Carolina", + "nd": "North Dakota", + "ne": "Nebraska", + "nh": "New Hampshire", + "nj": "New Jersey", + "nm": "New Mexico", + "nv": "Nevada", + "ny": "New York", + "oh": "Ohio", + "ok": "Oklahoma", + "or": "Oregon", + "pa": "Pennsylvania", + "ri": "Rhode Island", + "sc": "South Carolina", + "sd": "South Dakota", + "tn": "Tennessee", + "tx": "Texas", + "ut": "Utah", + "va": "Virginia", + "vt": "Vermont", + "wa": "Washington", + "wi": "Wisconsin", + "wv": "West Virginia", + "wy": "Wyoming" + }, + "cms_medicaid.state_abbreviation": { + "ak": "Alaska", + "al": "Alabama", + "ar": "Arkansas", + "az": "Arizona", + "ca": "California", + "co": "Colorado", + "ct": "Connecticut", + "dc": "District of Columbia", + "de": "Delaware", + "fl": "Florida", + "ga": "Georgia", + "hi": "Hawaii", + "ia": "Iowa", + "id": "Idaho", + "il": "Illinois", + "in": "Indiana", + "ks": "Kansas", + "ky": "Kentucky", + "la": "Louisiana", + "ma": "Massachusetts", + "md": "Maryland", + "me": "Maine", + "mi": "Michigan", + "mn": "Minnesota", + "mo": "Missouri", + "ms": "Mississippi", + "mt": "Montana", + "nc": "North Carolina", + "nd": "North Dakota", + "ne": "Nebraska", + "nh": "New Hampshire", + "nj": "New Jersey", + "nm": "New Mexico", + "nv": "Nevada", + "ny": "New York", + "oh": "Ohio", + "ok": "Oklahoma", + "or": "Oregon", + "pa": "Pennsylvania", + "ri": "Rhode Island", + "sc": "South Carolina", + "sd": "South Dakota", + "tn": "Tennessee", + "tx": "Texas", + "ut": "Utah", + "va": "Virginia", + "vt": "Vermont", + "wa": "Washington", + "wi": "Wisconsin", + "wv": "West Virginia", + "wy": "Wyoming" + }, + "contribution_basis": { + "full_pay": "Percentage of full pay", + "qualifying_earnings": "Percentage of qualifying earnings" + }, + "contribution_type": { + "Employer contributions to net pay arrangements and on employer deficit reduction contributions": "Employer contributions to net pay arrangements plus deficit reduction contributions", + "Employer contributions to net pay arrangements plus deficit reduction contributions": "Employer contributions to net pay arrangements plus deficit reduction contributions", + "Employer contributions to relief at source schemes": "Employer contributions to relief at source schemes", + "Individual contributions to net pay arrangements": "Individual contributions to net pay arrangements", + "Individual contributions to relief at source schemes": "Individual contributions to relief at source schemes", + "Salary sacrificed contributions": "Salary sacrificed contributions" + }, + "council_tax_band": { + "A": "Band A", + "A-": "Band A-", + "B": "Band B", + "C": "Band C", + "D": "Band D", + "E": "Band E", + "F": "Band F", + "G": "Band G", + "H": "Band H" + }, + "demographic_group": { + "be1_female_0_17": "Brussels Capital Region female aged 0 to 17", + "be1_female_18_64": "Brussels Capital Region female aged 18 to 64", + "be1_female_65_plus": "Brussels Capital Region female aged 65 and over", + "be1_male_0_17": "Brussels Capital Region male aged 0 to 17", + "be1_male_18_64": "Brussels Capital Region male aged 18 to 64", + "be1_male_65_plus": "Brussels Capital Region male aged 65 and over", + "be2_female_0_17": "Flemish Region female aged 0 to 17", + "be2_female_18_64": "Flemish Region female aged 18 to 64", + "be2_female_65_plus": "Flemish Region female aged 65 and over", + "be2_male_0_17": "Flemish Region male aged 0 to 17", + "be2_male_18_64": "Flemish Region male aged 18 to 64", + "be2_male_65_plus": "Flemish Region male aged 65 and over", + "be3_female_0_17": "Walloon Region female aged 0 to 17", + "be3_female_18_64": "Walloon Region female aged 18 to 64", + "be3_female_65_plus": "Walloon Region female aged 65 and over", + "be3_male_0_17": "Walloon Region male aged 0 to 17", + "be3_male_18_64": "Walloon Region male aged 18 to 64", + "be3_male_65_plus": "Walloon Region male aged 65 and over" + }, + "desnz.energy_trends.series": { + "domestic_consumption": "Domestic consumption" + }, + "desnz.need.household_income_band": { + "all_dwellings": "All dwellings", + "gbp100_000_gbp149_999": "£100,000 - £149,999", + "gbp150_000_or_more": "£150,000 or more", + "gbp15_000_gbp19_999": "£15,000 - £19,999", + "gbp20_000_gbp29_999": "£20,000 - £29,999", + "gbp30_000_gbp39_999": "£30,000 - £39,999", + "gbp40_000_gbp49_999": "£40,000 - £49,999", + "gbp50_000_gbp59_999": "£50,000 - £59,999", + "gbp60_000_gbp69_999": "£60,000 - £69,999", + "gbp70_000_gbp99_999": "£70,000 - £99,999", + "less_than_gbp15_000": "Less than £15,000" + }, + "desnz.need.property_type": { + "all_dwellings": "All dwellings", + "all_flats": "All flats", + "all_houses": "All houses", + "bungalow": "Bungalow", + "converted_flat": "Converted flat", + "detached": "Detached", + "end_terrace": "End terrace", + "mid_terrace": "Mid terrace", + "purpose_built_flat": "Purpose built flat", + "semi_detached": "Semi detached", + "terraced": "Terraced" + }, + "desnz.need.region": { + "all_dwellings": "All dwellings", + "east_midlands": "East Midlands", + "east_of_england": "East of England", + "london": "London", + "north_east": "North East", + "north_west": "North West", + "south_east": "South East", + "south_west": "South West", + "wales": "Wales", + "west_midlands": "West Midlands", + "yorkshire_and_the_humber": "Yorkshire and The Humber" + }, + "desnz.need.tenure": { + "all_dwellings": "All dwellings", + "council_or_housing_association": "Council or Housing Association", + "owner_occupied": "Owner-occupied", + "privately_rented": "Privately rented" + }, + "desnz.qep.bill_scope": { + "united_kingdom": "United Kingdom" + }, + "desnz.qep.price_region": { + "east_midlands": "East Midlands", + "eastern": "Eastern", + "london": "London", + "merseyside_north_wales": "Merseyside & North Wales", + "north_east": "North East", + "north_scotland": "North Scotland", + "north_west": "North West", + "south_east": "South East", + "south_scotland": "South Scotland", + "south_wales": "South Wales", + "south_west": "South West", + "southern": "Southern", + "united_kingdom": "United Kingdom", + "west_midlands": "West Midlands", + "yorkshire": "Yorkshire" + }, + "desnz.subnational.area": { + "unallocated": "Unallocated" + }, + "dfi_ni.bus_service": { + "metro_glider": "Metro / Glider" + }, + "dft.bus_area": { + "england": "England", + "england_outside_london": "England outside London", + "english_metropolitan_areas": "English metropolitan areas", + "english_non_metropolitan_areas": "English non-metropolitan areas", + "london": "London" + }, + "dft.survey_year": { + "cy2023": "2023", + "cy2024": "2024", + "cy2025": "2025" + }, + "domestic_scope": { + "all_domestic": "All domestic meters", + "all_meters": "All meters", + "all_non_domestic": "All non-domestic meters" + }, + "dwp.winter_fuel_payment_country_age_amount_gender": { + "e92000001__70_74__amount_all__female": "England, 70-74, all amounts, Female", + "e92000001__70_74__amount_all__gender_all": "England, 70-74, all amounts, all genders", + "e92000001__70_74__amount_all__male": "England, 70-74, all amounts, Male", + "e92000001__75_79__amount_all__female": "England, 75-79, all amounts, Female", + "e92000001__75_79__amount_all__gender_all": "England, 75-79, all amounts, all genders", + "e92000001__75_79__amount_all__male": "England, 75-79, all amounts, Male", + "e92000001__80_84__300__female": "England, 80-84, £300, Female", + "e92000001__80_84__300__gender_all": "England, 80-84, £300, all genders", + "e92000001__80_84__300__male": "England, 80-84, £300, Male", + "e92000001__80_84__amount_all__female": "England, 80-84, all amounts, Female", + "e92000001__80_84__amount_all__gender_all": "England, 80-84, all amounts, all genders", + "e92000001__80_84__amount_all__male": "England, 80-84, all amounts, Male", + "e92000001__85_89__300__female": "England, 85-89, £300, Female", + "e92000001__85_89__300__gender_all": "England, 85-89, £300, all genders", + "e92000001__85_89__300__male": "England, 85-89, £300, Male", + "e92000001__85_89__amount_all__female": "England, 85-89, all amounts, Female", + "e92000001__85_89__amount_all__gender_all": "England, 85-89, all amounts, all genders", + "e92000001__85_89__amount_all__male": "England, 85-89, all amounts, Male", + "e92000001__90_and_over__300__female": "England, 90 and over, £300, Female", + "e92000001__90_and_over__300__gender_all": "England, 90 and over, £300, all genders", + "e92000001__90_and_over__300__male": "England, 90 and over, £300, Male", + "e92000001__90_and_over__amount_all__female": "England, 90 and over, all amounts, Female", + "e92000001__90_and_over__amount_all__gender_all": "England, 90 and over, all amounts, all genders", + "e92000001__90_and_over__amount_all__male": "England, 90 and over, all amounts, Male", + "e92000001__age_bands_and_single_year_all__300__female": "England, all ages, £300, Female", + "e92000001__age_bands_and_single_year_all__300__gender_all": "England, all ages, £300, all genders", + "e92000001__age_bands_and_single_year_all__300__male": "England, all ages, £300, Male", + "e92000001__age_bands_and_single_year_all__amount_all__female": "England, all ages, all amounts, Female", + "e92000001__age_bands_and_single_year_all__amount_all__gender_all": "England, all ages, all amounts, all genders", + "e92000001__age_bands_and_single_year_all__amount_all__male": "England, all ages, all amounts, Male", + "w92000004__70_74__amount_all__female": "Wales, 70-74, all amounts, Female", + "w92000004__70_74__amount_all__gender_all": "Wales, 70-74, all amounts, all genders", + "w92000004__70_74__amount_all__male": "Wales, 70-74, all amounts, Male", + "w92000004__75_79__amount_all__female": "Wales, 75-79, all amounts, Female", + "w92000004__75_79__amount_all__gender_all": "Wales, 75-79, all amounts, all genders", + "w92000004__75_79__amount_all__male": "Wales, 75-79, all amounts, Male", + "w92000004__80_84__300__female": "Wales, 80-84, £300, Female", + "w92000004__80_84__300__gender_all": "Wales, 80-84, £300, all genders", + "w92000004__80_84__300__male": "Wales, 80-84, £300, Male", + "w92000004__80_84__amount_all__female": "Wales, 80-84, all amounts, Female", + "w92000004__80_84__amount_all__gender_all": "Wales, 80-84, all amounts, all genders", + "w92000004__80_84__amount_all__male": "Wales, 80-84, all amounts, Male", + "w92000004__85_89__300__female": "Wales, 85-89, £300, Female", + "w92000004__85_89__300__gender_all": "Wales, 85-89, £300, all genders", + "w92000004__85_89__300__male": "Wales, 85-89, £300, Male", + "w92000004__85_89__amount_all__female": "Wales, 85-89, all amounts, Female", + "w92000004__85_89__amount_all__gender_all": "Wales, 85-89, all amounts, all genders", + "w92000004__85_89__amount_all__male": "Wales, 85-89, all amounts, Male", + "w92000004__90_and_over__300__female": "Wales, 90 and over, £300, Female", + "w92000004__90_and_over__300__gender_all": "Wales, 90 and over, £300, all genders", + "w92000004__90_and_over__300__male": "Wales, 90 and over, £300, Male", + "w92000004__90_and_over__amount_all__female": "Wales, 90 and over, all amounts, Female", + "w92000004__90_and_over__amount_all__gender_all": "Wales, 90 and over, all amounts, all genders", + "w92000004__90_and_over__amount_all__male": "Wales, 90 and over, all amounts, Male", + "w92000004__age_bands_and_single_year_all__300__female": "Wales, all ages, £300, Female", + "w92000004__age_bands_and_single_year_all__300__gender_all": "Wales, all ages, £300, all genders", + "w92000004__age_bands_and_single_year_all__300__male": "Wales, all ages, £300, Male", + "w92000004__age_bands_and_single_year_all__amount_all__female": "Wales, all ages, all amounts, Female", + "w92000004__age_bands_and_single_year_all__amount_all__gender_all": "Wales, all ages, all amounts, all genders", + "w92000004__age_bands_and_single_year_all__amount_all__male": "Wales, all ages, all amounts, Male" + }, + "early_year_award_line": { + "new_returning_total_returning_31_33_35": "Total returning [31][33][35]" + }, + "earnings_component": { + "ordinary_time": "Ordinary time", + "total": "Total (ordinary time and overtime)" + }, + "earnings_denominator": { + "fte": "Full-time equivalent employees (FTEs)" + }, + "earnings_sector": { + "all_sectors": "All sectors" + }, + "earnings_series_reference": { + "QEMQ.SBSZ9A": "QEMQ.SBSZ9A — all-sector ordinary-time average weekly earnings per FTE, actual (not seasonally adjusted)", + "QEMQ.SBSZ9Z": "QEMQ.SBSZ9Z — all-sector total average weekly earnings per FTE, actual (not seasonally adjusted)" + }, + "eitc_child_count": { + "0": "0", + "1": "1", + "2": "2", + "3plus": "Three or more qualifying children" + }, + "employee_contribution_rate_band": { + "0%": "0%", + "2% to < 3%": "2% to < 3%", + "3% to < 4%": "3% to < 4%", + "4% to < 5%": "4% to < 5%", + "5% to < 6%": "5% to < 6%", + "6% to < 7%": "6% to < 7%", + "7% and over": "7% and over", + "Under 2%": "Under 2%" + }, + "employer_contribution_rate_band": { + "10% to < 12%": "10% to < 12%", + "12% to < 15%": "12% to < 15%", + "15% to < 20%": "15% to < 20%", + "20% and over": "20% and over", + "4% to < 8%": "4% to < 8%", + "8% to < 10%": "8% to < 10%", + "Under 4%": "Under 4%" + }, + "family_type": { + "Couple, no children": "Couple, no children", + "Couple, with children": "Couple, with children", + "Single, no children": "Single, no children", + "Single, with children": "Single, with children", + "Unknown or missing family type": "Unknown or missing family type" + }, + "filing_status": { + "all": "All filing statuses" + }, + "freq": { + "A": "Annual" + }, + "frequency": { + "annual": "Annual", + "quarterly": "Quarterly" + }, + "fuel": { + "electricity": "Electricity", + "gas": "Gas" + }, + "funding_component": { + "all_government_support": "All government support", + "concessionary_fares": "Concessionary fares", + "local_authority_bus_support": "Local authority bus support", + "network_support_grant": "Network Support Grant" + }, + "gambling_commission.gsgb_activity": { + "national_lottery_draws_in_person": "Tickets for National Lottery draws bought in person" + }, + "gender": { + "Female": "Female", + "Male": "Male", + "Unknown": "Unknown", + "all": "Total" + }, + "geography": { + "northern_ireland": "Northern Ireland" + }, + "groeipakket.component": { + "pleegzorgtoeslag": "Foster care supplement", + "sociale_toeslag": "Social supplement", + "wezentoeslag": "Orphan supplement", + "zorgtoeslag": "Care supplement" + }, + "grouped_amount_of_benefit": { + "Under £20.00": "Under £20.00", + "all": "Total", + "£100.00 to under £150.00": "£100.00 to under £150.00", + "£20.00 to under £40.00": "£20.00 to under £40.00", + "£40.00 to under £60.00": "£40.00 to under £60.00", + "£60.00 to under £80.00": "£60.00 to under £80.00", + "£80.00 to under £100.00": "£80.00 to under £100.00" + }, + "heating_type": { + "no_central_heating": "No central heating" + }, + "hmrc.pension_relief_breakdown": { + "additional_rate": "Additional Rate", + "basic_rate": "Basic Rate", + "defined_benefit": "Defined benefit", + "defined_contribution": "Defined contribution", + "higher_rate": "Higher Rate", + "main_rate": "Main Rate", + "personal_or_private_sector_occupational_scheme": "Personal or private sector occupational scheme", + "public_sector_occupational_scheme": "Public sector occupational scheme", + "total": "Total" + }, + "hmrc.ss_relief_line": { + "it_relief_additional_rate": "Income tax relief, additional rate", + "it_relief_basic_rate": "Income tax relief, basic rate", + "it_relief_higher_rate": "Income tax relief, higher rate", + "it_relief_total": "Income tax relief on salary sacrificed contributions, total", + "nics_relief_employee": "Class 1 primary (employee) NICs relief", + "nics_relief_employer": "Class 1 secondary (employer) NICs relief" + }, + "hmrc.tax_year": { + "tax_year_2023": "Tax year 2023 to 2024", + "tax_year_2024": "Tax year 2024 to 2025", + "tax_year_2025": "Tax year 2025 to 2026" + }, + "hmrc.total_income_band": { + "all_ranges": "All ranges of total income", + "band_100000_150000": "Total income from GBP 100 000 to GBP 150 000", + "band_12570_15000": "Total income from GBP 12 570 to GBP 15 000", + "band_150000_200000": "Total income from GBP 150 000 to GBP 200 000", + "band_15000_20000": "Total income from GBP 15 000 to GBP 20 000", + "band_20000_30000": "Total income from GBP 20 000 to GBP 30 000", + "band_500000_1000000": "Total income from GBP 500 000 to GBP 1 000 000" + }, + "household_income_band": { + "all_dwellings": "All dwellings", + "gbp100_000_gbp149_999": "£100,000 - £149,999", + "gbp150_000_or_more": "£150,000 or more", + "gbp15_000_gbp19_999": "£15,000 - £19,999", + "gbp20_000_gbp29_999": "£20,000 - £29,999", + "gbp30_000_gbp39_999": "£30,000 - £39,999", + "gbp40_000_gbp49_999": "£40,000 - £49,999", + "gbp50_000_gbp59_999": "£50,000 - £59,999", + "gbp60_000_gbp69_999": "£60,000 - £69,999", + "gbp70_000_gbp99_999": "£70,000 - £99,999", + "less_than_gbp15_000": "Less than £15,000" + }, + "household_tenure": { + "All occupied households": "All occupied households" + }, + "household_type": { + "couple_3_plus_children_households": "3 or more dependent children" + }, + "housing_costs": { + "after_housing_costs": "After housing costs", + "before_housing_costs": "Before housing costs" + }, + "income_range": { + "100k_to_200k": "$100,000 under $200,000", + "10k_to_11k": "$10,000 under $11,000", + "10k_to_15k": "$10,000 under $15,000", + "10k_to_25k": "$10,000 under $25,000", + "10m_plus": "$10,000,000 or more", + "11k_to_12k": "$11,000 under $12,000", + "12k_to_13k": "$12,000 under $13,000", + "13k_to_14k": "$13,000 under $14,000", + "14k_to_15k": "$14,000 under $15,000", + "15k_to_16k": "$15,000 under $16,000", + "15k_to_20k": "$15,000 under $20,000", + "16k_to_17k": "$16,000 under $17,000", + "17k_to_18k": "$17,000 under $18,000", + "18k_to_19k": "$18,000 under $19,000", + "19k_to_20k": "$19,000 under $20,000", + "1_5m_to_2m": "$1,500,000 under $2,000,000", + "1_to_10k": "$1 under $10,000", + "1_to_1k": "$1 under $1,000", + "1_to_5k": "$1 under $5,000", + "1k_to_2k": "$1,000 under $2,000", + "1m_plus": "$1,000,000 or more", + "1m_to_1_5m": "$1,000,000 under $1,500,000", + "200k_to_500k": "$200,000 under $500,000", + "20k_to_25k": "$20,000 under $25,000", + "25k_to_30k": "$25,000 under $30,000", + "25k_to_50k": "$25,000 under $50,000", + "2k_to_3k": "$2,000 under $3,000", + "2m_to_5m": "$2,000,000 under $5,000,000", + "30k_to_35k": "$30,000 under $35,000", + "30k_to_40k": "$30,000 under $40,000", + "35k_to_40k": "$35,000 under $40,000", + "3k_to_4k": "$3,000 under $4,000", + "40k_to_45k": "$40,000 under $45,000", + "40k_to_50k": "$40,000 under $50,000", + "45k_to_50k": "$45,000 under $50,000", + "4k_to_5k": "$4,000 under $5,000", + "500k_to_1m": "$500,000 under $1,000,000", + "50k_plus": "$50,000 and over", + "50k_to_75k": "$50,000 under $75,000", + "5k_to_10k": "$5,000 under $10,000", + "5k_to_6k": "$5,000 under $6,000", + "5m_to_10m": "$5,000,000 under $10,000,000", + "6k_to_7k": "$6,000 under $7,000", + "75k_to_100k": "$75,000 under $100,000", + "7k_to_8k": "$7,000 under $8,000", + "8k_to_9k": "$8,000 under $9,000", + "9k_to_10k": "$9,000 under $10,000", + "all": "All income ranges", + "under_1": "No adjusted gross income" + }, + "irs_soi.ira_contribution_size": { + "all_taxpayers": "All taxpayers" + }, + "isc.census_line": { + "pupils_at_isc_schools": "Pupils at ISC member schools" + }, + "journey_category": { + "concessionary": "Concessionary passenger journeys", + "elderly_disabled_concessionary": "Elderly/Disabled journeys", + "total_concessionary": "Total concessionary journeys" + }, + "low_income_threshold": { + "below_60pct_contemporary_median": "Below 60% of the same year's median income" + }, + "lps.district_council": { + "antrim_and_newtownabbey": "Antrim and Newtownabbey", + "ards_and_north_down": "Ards and North Down", + "armagh_city_banbridge_and_craigavon": "Armagh City, Banbridge and Craigavon", + "belfast": "Belfast", + "causeway_coast_and_glens": "Causeway Coast and Glens", + "derry_city_and_strabane": "Derry City and Strabane", + "fermanagh_and_omagh": "Fermanagh and Omagh", + "lisburn_and_castlereagh": "Lisburn and Castlereagh", + "mid_and_east_antrim": "Mid and East Antrim", + "mid_ulster": "Mid Ulster", + "newry_mourne_and_down": "Newry, Mourne and Down", + "northern_ireland": "Northern Ireland" + }, + "marginal_rate": { + "additional": "Additional rate", + "basic": "Basic rate", + "higher": "Higher rate", + "savers": "Savers rate" + }, + "measure": { + "country_total": "Country total" + }, + "metering_arrangement": { + "standard": "Standard electricity" + }, + "metric": { + "consumption": "Consumption", + "mean_consumption_per_meter": "Mean consumption per meter", + "meter_count": "Meter count" + }, + "msd_supplementary_assistance_type": { + "accommodation_supplement": "Accommodation Supplement (AS)", + "disability_allowance": "Disability Allowance (DA)", + "special_benefit_or_temporary_additional_support": "Special Benefit (SPB) or Temporary Additional Support (TAS)" + }, + "na_item": { + "D2": "D2", + "D5": "D5", + "D51": "D51", + "D61": "D61", + "belgium_household_disposable_income_gross": "Disposable income, gross (B.6G)", + "belgium_household_mixed_income_gross": "Mixed income, gross (B.3G)", + "belgium_household_operating_surplus_gross": "Operating surplus, gross (B.2G)", + "d2_be": "Belgium taxes on production and imports", + "d51_be": "Belgium taxes on income", + "d5_be": "Belgium current taxes on income and wealth", + "d61_be": "Belgium net social contributions" + }, + "nics_relief_class": { + "Class 1 Primary (employee)": "Class 1 Primary (employee)", + "Class 1 Secondary (employer)": "Class 1 Secondary (employer)" + }, + "number_of_children": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5 or more": "5 or more", + "Not available prior to April 2019": "Not available prior to April 2019", + "Unknown or missing": "Unknown or missing" + }, + "nz_census_2023.family_type_source_label": { + "1": "Couple Without Children", + "2": "Couple With Child(ren)", + "3": "One Parent With Child(ren)" + }, + "nz_census_2023.household_size_source_label": { + "1": "One usual resident", + "2": "Two usual residents", + "3": "Three usual residents", + "4": "Four usual residents", + "5": "Five usual residents", + "6": "Six usual residents", + "7": "Seven usual residents", + "8": "Eight or more usual residents" + }, + "nz_census_2023.household_tenure_source_label": { + "1": "Owned", + "2": "Not owned", + "3": "In family trust" + }, + "nz_census_2023.total_kind": { + "families": "Families", + "households": "Households" + }, + "nz_census_2023.weekly_rent_source_label": { + "1": "Under $200", + "2": "$200 - $299", + "3": "$300 - $399", + "4": "$400 - $499", + "5": "$500 - $599", + "6": "$600 - $699", + "7": "$700 - $799", + "8": "$800 and over" + }, + "nz_census_2023.weekly_rent_statistic": { + "median": "Median weekly rent paid by households" + }, + "obr.efo_line": { + "attendance_allowance": "Attendance allowance", + "bank_rate": "Bank Rate", + "beer_and_cider_clearances": "Beer and cider clearances", + "beer_and_cider_duties": "Beer and cider duties", + "beer_and_cider_duties_accrued": "Beer and cider duties (accrued)", + "betting_and_gaming_duties": "Betting and gaming duties", + "bingo_duty": "Bingo duty", + "camelot_payments_to_national_lottery_distribution_fund": "Camelot payments to National Lottery Distribution Fund", + "capital_gains_tax": "Capital gains tax", + "carers_allowance": "Carer's allowance", + "child_benefit": "Child benefit", + "cigarette_clearances": "Cigarette clearances", + "council_tax_accruals_adjustment": "Council tax accruals adjustment", + "council_tax_england": "England council tax receipts", + "council_tax_receipts_england_scotland_wales": "Total council tax receipts", + "council_tax_scotland": "Scotland council tax receipts", + "council_tax_total": "Total net council tax receipts1", + "council_tax_wales": "Wales council tax receipts", + "cpi_inflation": "CPI year-on-year growth", + "dla_and_pip": "Disability living allowance and personal independence payments", + "domestic_rates": "NI domestic rates", + "employment_16_plus": "Employment (16+, millions)", + "fuel_duties": "Fuel duties", + "gaming_duty": "Gaming duty", + "general_betting_duty": "General betting duty", + "hand_rolled_tobacco_clearances": "Hand rolled tobacco clearances", + "horserace_betting_levy": "Horserace betting levy", + "housing_benefit": "Housing benefit (not on JSA)1", + "ilo_unemployment_rate_16_plus": "ILO unemployment rate (16+, per cent)", + "incapacity_benefits": "Incapacity benefits2", + "income_tax": "Income tax (gross of tax credits)", + "jobseekers_allowance": "Jobseeker's allowance", + "lottery_duty": "Lottery duty", + "machine_games_duty": "Machine games duty", + "ni_employee": "Class 1 Employee NICs", + "ni_employer": "Class 1 Employer NICs", + "ni_self_employed": "Class 4 and Class 2 Self employed NICs", + "ni_social_security_in_welfare_cap": "NI social security in welfare cap", + "ni_social_security_outside_welfare_cap": "NI social security outside welfare cap", + "ni_total": "National insurance contributions", + "nominal_gdp_nsa": "Nominal GDP NSA, billions", + "non_cigarette_tobacco_clearances": "Non-cigarette tobacco clearances", + "other_tobacco_products_clearances": "Other tobacco products clearances", + "pension_credit": "Pension credit", + "pool_betting_duty": "Pool betting duty", + "public_sector_current_receipts": "Current Receipts", + "public_sector_net_borrowing": "Net borrowing", + "public_sector_net_debt_percent_gdp": "Public sector net debt (PSND), per cent of GDP", + "remote_gaming_duty": "Remote gaming duty", + "rpi_inflation": "RPI year-on-year growth", + "sdlt": "Stamp duty land tax", + "sdlt_non_residential": "SDLT from non-residential property", + "sdlt_residential": "SDLT from residential property", + "sdlt_residential_higher_rates_additional_dwellings": "SDLT from residential property: higher rates on additional dwellings", + "sdlt_residential_main_rates": "SDLT from residential property: main rates", + "sdlt_residential_non_uk_resident_surcharge": "SDLT from residential property: non-UK resident surcharge", + "spirits_clearances": "Spirits clearances", + "spirits_duties": "Spirits duties", + "spirits_duties_accrued": "Spirits duties (accrued)", + "state_pension": "State pension", + "statutory_gaming_levy": "Statutory gaming levy", + "statutory_maternity_pay": "Statutory maternity pay", + "tobacco_duties": "Tobacco duties", + "total_managed_expenditure": "Total Managed Expenditure1", + "tv_licence_fee": "BBC licence fee receipts", + "universal_credit_in_cap": "Universal credit", + "universal_credit_outside_cap": "Universal credit", + "vaping_tax": "Vaping tax", + "vat": "Value added tax", + "vehicle_excise_duties": "Vehicle excise duties", + "wine_clearances": "Wine clearances", + "wine_duties": "Wine duties", + "wine_duties_accrued": "Wine duties (accrued)", + "winter_fuel_payment": "Winter fuel payment" + }, + "ons.ashe_age_pension_type": { + "16_to_21__all_pension_types": "Aged 16 to 21, all employee jobs with a pension", + "16_to_21__defined_benefit": "Aged 16 to 21, defined benefit", + "16_to_21__defined_contribution": "Aged 16 to 21, defined contribution", + "16_to_21__group_personal_pension": "Aged 16 to 21, group personal pension", + "16_to_21__group_stakeholder_pension": "Aged 16 to 21, group stakeholder pension", + "22_to_29__all_pension_types": "Aged 22 to 29, all employee jobs with a pension", + "22_to_29__defined_benefit": "Aged 22 to 29, defined benefit", + "22_to_29__defined_contribution": "Aged 22 to 29, defined contribution", + "22_to_29__group_personal_pension": "Aged 22 to 29, group personal pension", + "22_to_29__group_self_invested_personal_pension": "Aged 22 to 29, group self-invested personal pension", + "22_to_29__group_stakeholder_pension": "Aged 22 to 29, group stakeholder pension", + "30_to_39__all_pension_types": "Aged 30 to 39, all employee jobs with a pension", + "30_to_39__defined_benefit": "Aged 30 to 39, defined benefit", + "30_to_39__defined_contribution": "Aged 30 to 39, defined contribution", + "30_to_39__group_personal_pension": "Aged 30 to 39, group personal pension", + "30_to_39__group_self_invested_personal_pension": "Aged 30 to 39, group self-invested personal pension", + "30_to_39__group_stakeholder_pension": "Aged 30 to 39, group stakeholder pension", + "40_to_49__all_pension_types": "Aged 40 to 49, all employee jobs with a pension", + "40_to_49__defined_benefit": "Aged 40 to 49, defined benefit", + "40_to_49__defined_contribution": "Aged 40 to 49, defined contribution", + "40_to_49__group_personal_pension": "Aged 40 to 49, group personal pension", + "40_to_49__group_self_invested_personal_pension": "Aged 40 to 49, group self-invested personal pension", + "40_to_49__group_stakeholder_pension": "Aged 40 to 49, group stakeholder pension", + "50_to_54__all_pension_types": "Aged 50 to 54, all employee jobs with a pension", + "50_to_54__defined_benefit": "Aged 50 to 54, defined benefit", + "50_to_54__defined_contribution": "Aged 50 to 54, defined contribution", + "50_to_54__group_personal_pension": "Aged 50 to 54, group personal pension", + "50_to_54__group_self_invested_personal_pension": "Aged 50 to 54, group self-invested personal pension", + "50_to_54__group_stakeholder_pension": "Aged 50 to 54, group stakeholder pension", + "55_to_59__all_pension_types": "Aged 55 to 59, all employee jobs with a pension", + "55_to_59__defined_benefit": "Aged 55 to 59, defined benefit", + "55_to_59__defined_contribution": "Aged 55 to 59, defined contribution", + "55_to_59__group_personal_pension": "Aged 55 to 59, group personal pension", + "55_to_59__group_self_invested_personal_pension": "Aged 55 to 59, group self-invested personal pension", + "55_to_59__group_stakeholder_pension": "Aged 55 to 59, group stakeholder pension", + "60_to_64__all_pension_types": "Aged 60 to 64, all employee jobs with a pension", + "60_to_64__defined_benefit": "Aged 60 to 64, defined benefit", + "60_to_64__defined_contribution": "Aged 60 to 64, defined contribution", + "60_to_64__group_personal_pension": "Aged 60 to 64, group personal pension", + "60_to_64__group_self_invested_personal_pension": "Aged 60 to 64, group self-invested personal pension", + "60_to_64__group_stakeholder_pension": "Aged 60 to 64, group stakeholder pension", + "65_and_over__all_pension_types": "Aged 65 and over, all employee jobs with a pension", + "65_and_over__defined_benefit": "Aged 65 and over, defined benefit", + "65_and_over__defined_contribution": "Aged 65 and over, defined contribution", + "65_and_over__group_personal_pension": "Aged 65 and over, group personal pension", + "65_and_over__group_self_invested_personal_pension": "Aged 65 and over, group self-invested personal pension", + "65_and_over__group_stakeholder_pension": "Aged 65 and over, group stakeholder pension", + "all_ages__all_pension_types": "All ages, all employee jobs with a pension", + "all_ages__defined_benefit": "All ages, defined benefit", + "all_ages__defined_contribution": "All ages, defined contribution", + "all_ages__group_personal_pension": "All ages, group personal pension", + "all_ages__group_self_invested_personal_pension": "All ages, group self-invested personal pension", + "all_ages__group_stakeholder_pension": "All ages, group stakeholder pension" + }, + "ons.ashe_business_size_pension_type": { + "1000_or_more_employees__all_pension_types": "1000 or more employees, all employee jobs with a pension", + "1000_or_more_employees__defined_benefit": "1000 or more employees, defined benefit", + "1000_or_more_employees__defined_contribution": "1000 or more employees, defined contribution", + "1000_or_more_employees__group_personal_pension": "1000 or more employees, group personal pension", + "1000_or_more_employees__group_self_invested_personal_pension": "1000 or more employees, group self-invested personal pension", + "1000_or_more_employees__group_stakeholder_pension": "1000 or more employees, group stakeholder pension", + "100_to_499_employees__all_pension_types": "100 to 499 employees, all employee jobs with a pension", + "100_to_499_employees__defined_benefit": "100 to 499 employees, defined benefit", + "100_to_499_employees__defined_contribution": "100 to 499 employees, defined contribution", + "100_to_499_employees__group_personal_pension": "100 to 499 employees, group personal pension", + "100_to_499_employees__group_self_invested_personal_pension": "100 to 499 employees, group self-invested personal pension", + "100_to_499_employees__group_stakeholder_pension": "100 to 499 employees, group stakeholder pension", + "13_to_99_employees__all_pension_types": "13 to 99 employees, all employee jobs with a pension", + "13_to_99_employees__defined_benefit": "13 to 99 employees, defined benefit", + "13_to_99_employees__defined_contribution": "13 to 99 employees, defined contribution", + "13_to_99_employees__group_personal_pension": "13 to 99 employees, group personal pension", + "13_to_99_employees__group_self_invested_personal_pension": "13 to 99 employees, group self-invested personal pension", + "13_to_99_employees__group_stakeholder_pension": "13 to 99 employees, group stakeholder pension", + "1_to_12_employees__all_pension_types": "1 to 12 employees, all employee jobs with a pension", + "1_to_12_employees__defined_benefit": "1 to 12 employees, defined benefit", + "1_to_12_employees__defined_contribution": "1 to 12 employees, defined contribution", + "1_to_12_employees__group_personal_pension": "1 to 12 employees, group personal pension", + "1_to_12_employees__group_self_invested_personal_pension": "1 to 12 employees, group self-invested personal pension", + "1_to_12_employees__group_stakeholder_pension": "1 to 12 employees, group stakeholder pension", + "500_to_999_employees__all_pension_types": "500 to 999 employees, all employee jobs with a pension", + "500_to_999_employees__defined_benefit": "500 to 999 employees, defined benefit", + "500_to_999_employees__defined_contribution": "500 to 999 employees, defined contribution", + "500_to_999_employees__group_personal_pension": "500 to 999 employees, group personal pension", + "500_to_999_employees__group_self_invested_personal_pension": "500 to 999 employees, group self-invested personal pension", + "500_to_999_employees__group_stakeholder_pension": "500 to 999 employees, group stakeholder pension" + }, + "ons.ashe_industry_pension_type": { + "index_of_production__all_pension_types": "All Index of Production industries (SIC 2007 sections B to E), all employee jobs with a pension", + "index_of_production__defined_benefit": "All Index of Production industries (SIC 2007 sections B to E), defined benefit", + "index_of_production__defined_contribution": "All Index of Production industries (SIC 2007 sections B to E), defined contribution", + "index_of_production__group_personal_pension": "All Index of Production industries (SIC 2007 sections B to E), group personal pension", + "index_of_production__group_self_invested_personal_pension": "All Index of Production industries (SIC 2007 sections B to E), group self-invested personal pension", + "index_of_production__group_stakeholder_pension": "All Index of Production industries (SIC 2007 sections B to E), group stakeholder pension", + "private_sector__all_pension_types": "Private sector, all employee jobs with a pension", + "private_sector__defined_benefit": "Private sector, defined benefit", + "private_sector__defined_contribution": "Private sector, defined contribution", + "private_sector__group_personal_pension": "Private sector, group personal pension", + "private_sector__group_self_invested_personal_pension": "Private sector, group self-invested personal pension", + "private_sector__group_stakeholder_pension": "Private sector, group stakeholder pension", + "public_sector__all_pension_types": "Public sector, all employee jobs with a pension", + "public_sector__defined_benefit": "Public sector, defined benefit", + "public_sector__defined_contribution": "Public sector, defined contribution", + "public_sector__group_personal_pension": "Public sector, group personal pension", + "public_sector__group_stakeholder_pension": "Public sector, group stakeholder pension", + "service_industries__all_pension_types": "All service industries (SIC 2007 sections G to U), all employee jobs with a pension", + "service_industries__defined_benefit": "All service industries (SIC 2007 sections G to U), defined benefit", + "service_industries__defined_contribution": "All service industries (SIC 2007 sections G to U), defined contribution", + "service_industries__group_personal_pension": "All service industries (SIC 2007 sections G to U), group personal pension", + "service_industries__group_self_invested_personal_pension": "All service industries (SIC 2007 sections G to U), group self-invested personal pension", + "service_industries__group_stakeholder_pension": "All service industries (SIC 2007 sections G to U), group stakeholder pension", + "sic_a__all_pension_types": "Agriculture, Forestry and Fishing, all employee jobs with a pension", + "sic_a__defined_benefit": "Agriculture, Forestry and Fishing, defined benefit", + "sic_a__defined_contribution": "Agriculture, Forestry and Fishing, defined contribution", + "sic_a__group_personal_pension": "Agriculture, Forestry and Fishing, group personal pension", + "sic_a__group_self_invested_personal_pension": "Agriculture, Forestry and Fishing, group self-invested personal pension", + "sic_b__all_pension_types": "Mining and Quarrying, all employee jobs with a pension", + "sic_b__defined_contribution": "Mining and Quarrying, defined contribution", + "sic_b__group_personal_pension": "Mining and Quarrying, group personal pension", + "sic_c__all_pension_types": "Manufacturing, all employee jobs with a pension", + "sic_c__defined_benefit": "Manufacturing, defined benefit", + "sic_c__defined_contribution": "Manufacturing, defined contribution", + "sic_c__group_personal_pension": "Manufacturing, group personal pension", + "sic_c__group_self_invested_personal_pension": "Manufacturing, group self-invested personal pension", + "sic_c__group_stakeholder_pension": "Manufacturing, group stakeholder pension", + "sic_d__all_pension_types": "Electricity, Gas, Steam and Air Conditioning Supply, all employee jobs with a pension", + "sic_d__defined_benefit": "Electricity, Gas, Steam and Air Conditioning Supply, defined benefit", + "sic_d__defined_contribution": "Electricity, Gas, Steam and Air Conditioning Supply, defined contribution", + "sic_d__group_personal_pension": "Electricity, Gas, Steam and Air Conditioning Supply, group personal pension", + "sic_d__group_stakeholder_pension": "Electricity, Gas, Steam and Air Conditioning Supply, group stakeholder pension", + "sic_e__all_pension_types": "Water supply; sewerage, waste management and remediation activities, all employee jobs with a pension", + "sic_e__defined_benefit": "Water supply; sewerage, waste management and remediation activities, defined benefit", + "sic_e__defined_contribution": "Water supply; sewerage, waste management and remediation activities, defined contribution", + "sic_e__group_personal_pension": "Water supply; sewerage, waste management and remediation activities, group personal pension", + "sic_e__group_stakeholder_pension": "Water supply; sewerage, waste management and remediation activities, group stakeholder pension", + "sic_f__all_pension_types": "Construction, all employee jobs with a pension", + "sic_f__defined_benefit": "Construction, defined benefit", + "sic_f__defined_contribution": "Construction, defined contribution", + "sic_f__group_personal_pension": "Construction, group personal pension", + "sic_f__group_self_invested_personal_pension": "Construction, group self-invested personal pension", + "sic_f__group_stakeholder_pension": "Construction, group stakeholder pension", + "sic_g__all_pension_types": "Wholesale and retail trade; repair of motor vehicles and motorcycles, all employee jobs with a pension", + "sic_g__defined_benefit": "Wholesale and retail trade; repair of motor vehicles and motorcycles, defined benefit", + "sic_g__defined_contribution": "Wholesale and retail trade; repair of motor vehicles and motorcycles, defined contribution", + "sic_g__group_personal_pension": "Wholesale and retail trade; repair of motor vehicles and motorcycles, group personal pension", + "sic_g__group_self_invested_personal_pension": "Wholesale and retail trade; repair of motor vehicles and motorcycles, group self-invested personal pension", + "sic_g__group_stakeholder_pension": "Wholesale and retail trade; repair of motor vehicles and motorcycles, group stakeholder pension", + "sic_h__all_pension_types": "Transportation and storage, all employee jobs with a pension", + "sic_h__defined_benefit": "Transportation and storage, defined benefit", + "sic_h__defined_contribution": "Transportation and storage, defined contribution", + "sic_h__group_personal_pension": "Transportation and storage, group personal pension", + "sic_h__group_self_invested_personal_pension": "Transportation and storage, group self-invested personal pension", + "sic_h__group_stakeholder_pension": "Transportation and storage, group stakeholder pension", + "sic_i__all_pension_types": "Accommodation and food service activities, all employee jobs with a pension", + "sic_i__defined_benefit": "Accommodation and food service activities, defined benefit", + "sic_i__defined_contribution": "Accommodation and food service activities, defined contribution", + "sic_i__group_personal_pension": "Accommodation and food service activities, group personal pension", + "sic_i__group_self_invested_personal_pension": "Accommodation and food service activities, group self-invested personal pension", + "sic_i__group_stakeholder_pension": "Accommodation and food service activities, group stakeholder pension", + "sic_j__all_pension_types": "Information and communication, all employee jobs with a pension", + "sic_j__defined_benefit": "Information and communication, defined benefit", + "sic_j__defined_contribution": "Information and communication, defined contribution", + "sic_j__group_personal_pension": "Information and communication, group personal pension", + "sic_j__group_self_invested_personal_pension": "Information and communication, group self-invested personal pension", + "sic_j__group_stakeholder_pension": "Information and communication, group stakeholder pension", + "sic_k__all_pension_types": "Financial and insurance activities, all employee jobs with a pension", + "sic_k__defined_benefit": "Financial and insurance activities, defined benefit", + "sic_k__defined_contribution": "Financial and insurance activities, defined contribution", + "sic_k__group_personal_pension": "Financial and insurance activities, group personal pension", + "sic_k__group_self_invested_personal_pension": "Financial and insurance activities, group self-invested personal pension", + "sic_k__group_stakeholder_pension": "Financial and insurance activities, group stakeholder pension", + "sic_l__all_pension_types": "Real estate activities, all employee jobs with a pension", + "sic_l__defined_benefit": "Real estate activities, defined benefit", + "sic_l__defined_contribution": "Real estate activities, defined contribution", + "sic_l__group_personal_pension": "Real estate activities, group personal pension", + "sic_l__group_self_invested_personal_pension": "Real estate activities, group self-invested personal pension", + "sic_l__group_stakeholder_pension": "Real estate activities, group stakeholder pension", + "sic_m__all_pension_types": "Professional, scientific and technical activities, all employee jobs with a pension", + "sic_m__defined_benefit": "Professional, scientific and technical activities, defined benefit", + "sic_m__defined_contribution": "Professional, scientific and technical activities, defined contribution", + "sic_m__group_personal_pension": "Professional, scientific and technical activities, group personal pension", + "sic_m__group_self_invested_personal_pension": "Professional, scientific and technical activities, group self-invested personal pension", + "sic_m__group_stakeholder_pension": "Professional, scientific and technical activities, group stakeholder pension", + "sic_n__all_pension_types": "Administrative and support service activities, all employee jobs with a pension", + "sic_n__defined_benefit": "Administrative and support service activities, defined benefit", + "sic_n__defined_contribution": "Administrative and support service activities, defined contribution", + "sic_n__group_personal_pension": "Administrative and support service activities, group personal pension", + "sic_n__group_self_invested_personal_pension": "Administrative and support service activities, group self-invested personal pension", + "sic_n__group_stakeholder_pension": "Administrative and support service activities, group stakeholder pension", + "sic_o__all_pension_types": "Public administration and defence; compulsory social security, all employee jobs with a pension", + "sic_o__defined_benefit": "Public administration and defence; compulsory social security, defined benefit", + "sic_o__defined_contribution": "Public administration and defence; compulsory social security, defined contribution", + "sic_o__group_personal_pension": "Public administration and defence; compulsory social security, group personal pension", + "sic_o__group_stakeholder_pension": "Public administration and defence; compulsory social security, group stakeholder pension", + "sic_p__all_pension_types": "Education, all employee jobs with a pension", + "sic_p__defined_benefit": "Education, defined benefit", + "sic_p__defined_contribution": "Education, defined contribution", + "sic_p__group_personal_pension": "Education, group personal pension", + "sic_p__group_stakeholder_pension": "Education, group stakeholder pension", + "sic_q__all_pension_types": "Human health and social work activities, all employee jobs with a pension", + "sic_q__defined_benefit": "Human health and social work activities, defined benefit", + "sic_q__defined_contribution": "Human health and social work activities, defined contribution", + "sic_q__group_personal_pension": "Human health and social work activities, group personal pension", + "sic_q__group_self_invested_personal_pension": "Human health and social work activities, group self-invested personal pension", + "sic_q__group_stakeholder_pension": "Human health and social work activities, group stakeholder pension", + "sic_r__all_pension_types": "Arts, entertainment and recreation, all employee jobs with a pension", + "sic_r__defined_benefit": "Arts, entertainment and recreation, defined benefit", + "sic_r__defined_contribution": "Arts, entertainment and recreation, defined contribution", + "sic_r__group_personal_pension": "Arts, entertainment and recreation, group personal pension", + "sic_r__group_stakeholder_pension": "Arts, entertainment and recreation, group stakeholder pension", + "sic_s__all_pension_types": "Other service activities, all employee jobs with a pension", + "sic_s__defined_benefit": "Other service activities, defined benefit", + "sic_s__defined_contribution": "Other service activities, defined contribution", + "sic_s__group_personal_pension": "Other service activities, group personal pension", + "sic_s__group_self_invested_personal_pension": "Other service activities, group self-invested personal pension", + "sic_s__group_stakeholder_pension": "Other service activities, group stakeholder pension" + }, + "ons.ashe_occupation_pension_type": { + "soc_1__all_pension_types": "Managers, directors and senior officials, all employee jobs with a pension", + "soc_1__defined_benefit": "Managers, directors and senior officials, defined benefit", + "soc_1__defined_contribution": "Managers, directors and senior officials, defined contribution", + "soc_1__group_personal_pension": "Managers, directors and senior officials, group personal pension", + "soc_1__group_self_invested_personal_pension": "Managers, directors and senior officials, group self-invested personal pension", + "soc_1__group_stakeholder_pension": "Managers, directors and senior officials, group stakeholder pension", + "soc_2__all_pension_types": "Professional occupations, all employee jobs with a pension", + "soc_2__defined_benefit": "Professional occupations, defined benefit", + "soc_2__defined_contribution": "Professional occupations, defined contribution", + "soc_2__group_personal_pension": "Professional occupations, group personal pension", + "soc_2__group_self_invested_personal_pension": "Professional occupations, group self-invested personal pension", + "soc_2__group_stakeholder_pension": "Professional occupations, group stakeholder pension", + "soc_3__all_pension_types": "Associate professional and technical occupations, all employee jobs with a pension", + "soc_3__defined_benefit": "Associate professional and technical occupations, defined benefit", + "soc_3__defined_contribution": "Associate professional and technical occupations, defined contribution", + "soc_3__group_personal_pension": "Associate professional and technical occupations, group personal pension", + "soc_3__group_self_invested_personal_pension": "Associate professional and technical occupations, group self-invested personal pension", + "soc_3__group_stakeholder_pension": "Associate professional and technical occupations, group stakeholder pension", + "soc_4__all_pension_types": "Administrative and secretarial occupations, all employee jobs with a pension", + "soc_4__defined_benefit": "Administrative and secretarial occupations, defined benefit", + "soc_4__defined_contribution": "Administrative and secretarial occupations, defined contribution", + "soc_4__group_personal_pension": "Administrative and secretarial occupations, group personal pension", + "soc_4__group_self_invested_personal_pension": "Administrative and secretarial occupations, group self-invested personal pension", + "soc_4__group_stakeholder_pension": "Administrative and secretarial occupations, group stakeholder pension", + "soc_5__all_pension_types": "Skilled trades occupations, all employee jobs with a pension", + "soc_5__defined_benefit": "Skilled trades occupations, defined benefit", + "soc_5__defined_contribution": "Skilled trades occupations, defined contribution", + "soc_5__group_personal_pension": "Skilled trades occupations, group personal pension", + "soc_5__group_self_invested_personal_pension": "Skilled trades occupations, group self-invested personal pension", + "soc_5__group_stakeholder_pension": "Skilled trades occupations, group stakeholder pension", + "soc_6__all_pension_types": "Caring, leisure and other service occupations, all employee jobs with a pension", + "soc_6__defined_benefit": "Caring, leisure and other service occupations, defined benefit", + "soc_6__defined_contribution": "Caring, leisure and other service occupations, defined contribution", + "soc_6__group_personal_pension": "Caring, leisure and other service occupations, group personal pension", + "soc_6__group_self_invested_personal_pension": "Caring, leisure and other service occupations, group self-invested personal pension", + "soc_6__group_stakeholder_pension": "Caring, leisure and other service occupations, group stakeholder pension", + "soc_7__all_pension_types": "Sales and customer service occupations, all employee jobs with a pension", + "soc_7__defined_benefit": "Sales and customer service occupations, defined benefit", + "soc_7__defined_contribution": "Sales and customer service occupations, defined contribution", + "soc_7__group_personal_pension": "Sales and customer service occupations, group personal pension", + "soc_7__group_self_invested_personal_pension": "Sales and customer service occupations, group self-invested personal pension", + "soc_7__group_stakeholder_pension": "Sales and customer service occupations, group stakeholder pension", + "soc_8__all_pension_types": "Process, plant and machine operatives, all employee jobs with a pension", + "soc_8__defined_benefit": "Process, plant and machine operatives, defined benefit", + "soc_8__defined_contribution": "Process, plant and machine operatives, defined contribution", + "soc_8__group_personal_pension": "Process, plant and machine operatives, group personal pension", + "soc_8__group_self_invested_personal_pension": "Process, plant and machine operatives, group self-invested personal pension", + "soc_8__group_stakeholder_pension": "Process, plant and machine operatives, group stakeholder pension", + "soc_9__all_pension_types": "Elementary occupations, all employee jobs with a pension", + "soc_9__defined_benefit": "Elementary occupations, defined benefit", + "soc_9__defined_contribution": "Elementary occupations, defined contribution", + "soc_9__group_personal_pension": "Elementary occupations, group personal pension", + "soc_9__group_self_invested_personal_pension": "Elementary occupations, group self-invested personal pension", + "soc_9__group_stakeholder_pension": "Elementary occupations, group stakeholder pension" + }, + "ons.coicop": { + "coicop_01": "Food and non-alcoholic beverages", + "coicop_02": "Alcohol, tobacco and narcotics", + "coicop_04": "Housing, water, electricity, gas and other fuel", + "coicop_05": "Furnishings, household equipment and routine maintenance of the house", + "coicop_11": "Restaurants and hotels", + "coicop_12": "Miscellaneous goods and services" + }, + "ons.household_type": { + "couple_3_plus_children_households": "3 or more dependent children" + }, + "partner_indicator": { + "Has a partner": "Has a partner", + "Has no partner": "Has no partner", + "all": "Total" + }, + "payment_indicator": { + "No": "No", + "Yes": "Yes", + "all": "Total" + }, + "payment_method": { + "all": "All payment methods", + "direct_debit": "Direct debit", + "prepayment": "Prepayment", + "standard_credit": "Standard credit" + }, + "pension_type": { + "all": "All employee jobs", + "defined_benefit": "Defined benefit", + "defined_contribution": "Defined contribution", + "group_personal_pension": "Group personal pension", + "group_self_invested_personal_pension": "Group self-invested personal pension", + "group_stakeholder_pension": "Group stakeholder pension", + "no_pension_provision": "No pension provision", + "unknown_pension_provision": "Unknown pension provision" + }, + "person.age_band": { + "0_17": "0_17", + "18_64": "18_64", + "65_plus": "65+" + }, + "person.sex": { + "female": "female", + "male": "male" + }, + "population_type": { + "UR_CE": "All usual residents in communal establishments", + "UR_HH": "All usual residents in households" + }, + "price_basis": { + "average_2024_25_prices": "Average 2024/25 prices" + }, + "price_component": { + "annual_bill": "Average annual bill", + "fixed_cost": "Average fixed cost", + "variable_unit_cost": "Average variable unit cost" + }, + "private_or_social_rented": { + "Private Rented Sector": "Private Rented Sector", + "Social Rented Sector": "Social Rented Sector", + "Unknown or missing housing sector": "Unknown or missing housing sector", + "all": "Total" + }, + "program": { + "liheap": "LIHEAP", + "state_programs": "State programs" + }, + "property_type": { + "all_dwellings": "All dwellings", + "all_flats": "All flats", + "all_houses": "All houses", + "bungalow": "Bungalow", + "converted_flat": "Converted flat", + "detached": "Detached", + "end_terrace": "End terrace", + "mid_terrace": "Mid terrace", + "purpose_built_flat": "Purpose built flat", + "semi_detached": "Semi detached", + "terraced": "Terraced" + }, + "publication_status": { + "provisional": "Provisional" + }, + "published_unit": { + "gbp_million": "£ million", + "million_sticks": "Million sticks", + "thousand_hectolitres_of_alcohol": "Thousand hectolitres of alcohol", + "thousand_kilograms": "Thousand kilograms" + }, + "quant_inc": { + "d1": "First income decile", + "d2": "Second income decile", + "d3": "Third income decile", + "d4": "Fourth income decile", + "d5": "Fifth income decile", + "d6": "Sixth income decile", + "d7": "Seventh income decile", + "d8": "Eighth income decile", + "d9": "Ninth income decile" + }, + "quarter": { + "Q1": "Q1" + }, + "region": { + "all_dwellings": "All dwellings", + "east_midlands": "East Midlands", + "east_of_england": "East of England", + "london": "London", + "north_east": "North East", + "north_west": "North West", + "south_east": "South East", + "south_west": "South West", + "wales": "Wales", + "west_midlands": "West Midlands", + "yorkshire_and_the_humber": "Yorkshire and The Humber" + }, + "residence_type": { + "Lives in a communal establishment": "Lives in a communal establishment" + }, + "resident_age_101a": { + "Aged 1 year": "Aged 1 year", + "Aged 10 years": "Aged 10 years", + "Aged 100 years and over": "Aged 100 years and over", + "Aged 11 years": "Aged 11 years", + "Aged 12 years": "Aged 12 years", + "Aged 13 years": "Aged 13 years", + "Aged 14 years": "Aged 14 years", + "Aged 15 years": "Aged 15 years", + "Aged 16 years": "Aged 16 years", + "Aged 17 years": "Aged 17 years", + "Aged 18 years": "Aged 18 years", + "Aged 19 years": "Aged 19 years", + "Aged 2 years": "Aged 2 years", + "Aged 20 years": "Aged 20 years", + "Aged 21 years": "Aged 21 years", + "Aged 22 years": "Aged 22 years", + "Aged 23 years": "Aged 23 years", + "Aged 24 years": "Aged 24 years", + "Aged 25 years": "Aged 25 years", + "Aged 26 years": "Aged 26 years", + "Aged 27 years": "Aged 27 years", + "Aged 28 years": "Aged 28 years", + "Aged 29 years": "Aged 29 years", + "Aged 3 years": "Aged 3 years", + "Aged 30 years": "Aged 30 years", + "Aged 31 years": "Aged 31 years", + "Aged 32 years": "Aged 32 years", + "Aged 33 years": "Aged 33 years", + "Aged 34 years": "Aged 34 years", + "Aged 35 years": "Aged 35 years", + "Aged 36 years": "Aged 36 years", + "Aged 37 years": "Aged 37 years", + "Aged 38 years": "Aged 38 years", + "Aged 39 years": "Aged 39 years", + "Aged 4 years": "Aged 4 years", + "Aged 40 years": "Aged 40 years", + "Aged 41 years": "Aged 41 years", + "Aged 42 years": "Aged 42 years", + "Aged 43 years": "Aged 43 years", + "Aged 44 years": "Aged 44 years", + "Aged 45 years": "Aged 45 years", + "Aged 46 years": "Aged 46 years", + "Aged 47 years": "Aged 47 years", + "Aged 48 years": "Aged 48 years", + "Aged 49 years": "Aged 49 years", + "Aged 5 years": "Aged 5 years", + "Aged 50 years": "Aged 50 years", + "Aged 51 years": "Aged 51 years", + "Aged 52 years": "Aged 52 years", + "Aged 53 years": "Aged 53 years", + "Aged 54 years": "Aged 54 years", + "Aged 55 years": "Aged 55 years", + "Aged 56 years": "Aged 56 years", + "Aged 57 years": "Aged 57 years", + "Aged 58 years": "Aged 58 years", + "Aged 59 years": "Aged 59 years", + "Aged 6 years": "Aged 6 years", + "Aged 60 years": "Aged 60 years", + "Aged 61 years": "Aged 61 years", + "Aged 62 years": "Aged 62 years", + "Aged 63 years": "Aged 63 years", + "Aged 64 years": "Aged 64 years", + "Aged 65 years": "Aged 65 years", + "Aged 66 years": "Aged 66 years", + "Aged 67 years": "Aged 67 years", + "Aged 68 years": "Aged 68 years", + "Aged 69 years": "Aged 69 years", + "Aged 7 years": "Aged 7 years", + "Aged 70 years": "Aged 70 years", + "Aged 71 years": "Aged 71 years", + "Aged 72 years": "Aged 72 years", + "Aged 73 years": "Aged 73 years", + "Aged 74 years": "Aged 74 years", + "Aged 75 years": "Aged 75 years", + "Aged 76 years": "Aged 76 years", + "Aged 77 years": "Aged 77 years", + "Aged 78 years": "Aged 78 years", + "Aged 79 years": "Aged 79 years", + "Aged 8 years": "Aged 8 years", + "Aged 80 years": "Aged 80 years", + "Aged 81 years": "Aged 81 years", + "Aged 82 years": "Aged 82 years", + "Aged 83 years": "Aged 83 years", + "Aged 84 years": "Aged 84 years", + "Aged 85 years": "Aged 85 years", + "Aged 86 years": "Aged 86 years", + "Aged 87 years": "Aged 87 years", + "Aged 88 years": "Aged 88 years", + "Aged 89 years": "Aged 89 years", + "Aged 9 years": "Aged 9 years", + "Aged 90 years": "Aged 90 years", + "Aged 91 years": "Aged 91 years", + "Aged 92 years": "Aged 92 years", + "Aged 93 years": "Aged 93 years", + "Aged 94 years": "Aged 94 years", + "Aged 95 years": "Aged 95 years", + "Aged 96 years": "Aged 96 years", + "Aged 97 years": "Aged 97 years", + "Aged 98 years": "Aged 98 years", + "Aged 99 years": "Aged 99 years", + "Aged under 1 year": "Aged under 1 year", + "age_0": "Aged under 1 year", + "age_1": "Aged 1 year", + "age_10": "Aged 10 years", + "age_100": "Aged 100 years and over", + "age_11": "Aged 11 years", + "age_12": "Aged 12 years", + "age_13": "Aged 13 years", + "age_14": "Aged 14 years", + "age_15": "Aged 15 years", + "age_16": "Aged 16 years", + "age_17": "Aged 17 years", + "age_18": "Aged 18 years", + "age_19": "Aged 19 years", + "age_2": "Aged 2 years", + "age_20": "Aged 20 years", + "age_21": "Aged 21 years", + "age_22": "Aged 22 years", + "age_23": "Aged 23 years", + "age_24": "Aged 24 years", + "age_25": "Aged 25 years", + "age_26": "Aged 26 years", + "age_27": "Aged 27 years", + "age_28": "Aged 28 years", + "age_29": "Aged 29 years", + "age_3": "Aged 3 years", + "age_30": "Aged 30 years", + "age_31": "Aged 31 years", + "age_32": "Aged 32 years", + "age_33": "Aged 33 years", + "age_34": "Aged 34 years", + "age_35": "Aged 35 years", + "age_36": "Aged 36 years", + "age_37": "Aged 37 years", + "age_38": "Aged 38 years", + "age_39": "Aged 39 years", + "age_4": "Aged 4 years", + "age_40": "Aged 40 years", + "age_41": "Aged 41 years", + "age_42": "Aged 42 years", + "age_43": "Aged 43 years", + "age_44": "Aged 44 years", + "age_45": "Aged 45 years", + "age_46": "Aged 46 years", + "age_47": "Aged 47 years", + "age_48": "Aged 48 years", + "age_49": "Aged 49 years", + "age_5": "Aged 5 years", + "age_50": "Aged 50 years", + "age_51": "Aged 51 years", + "age_52": "Aged 52 years", + "age_53": "Aged 53 years", + "age_54": "Aged 54 years", + "age_55": "Aged 55 years", + "age_56": "Aged 56 years", + "age_57": "Aged 57 years", + "age_58": "Aged 58 years", + "age_59": "Aged 59 years", + "age_6": "Aged 6 years", + "age_60": "Aged 60 years", + "age_61": "Aged 61 years", + "age_62": "Aged 62 years", + "age_63": "Aged 63 years", + "age_64": "Aged 64 years", + "age_65": "Aged 65 years", + "age_66": "Aged 66 years", + "age_67": "Aged 67 years", + "age_68": "Aged 68 years", + "age_69": "Aged 69 years", + "age_7": "Aged 7 years", + "age_70": "Aged 70 years", + "age_71": "Aged 71 years", + "age_72": "Aged 72 years", + "age_73": "Aged 73 years", + "age_74": "Aged 74 years", + "age_75": "Aged 75 years", + "age_76": "Aged 76 years", + "age_77": "Aged 77 years", + "age_78": "Aged 78 years", + "age_79": "Aged 79 years", + "age_8": "Aged 8 years", + "age_80": "Aged 80 years", + "age_81": "Aged 81 years", + "age_82": "Aged 82 years", + "age_83": "Aged 83 years", + "age_84": "Aged 84 years", + "age_85": "Aged 85 years", + "age_86": "Aged 86 years", + "age_87": "Aged 87 years", + "age_88": "Aged 88 years", + "age_89": "Aged 89 years", + "age_9": "Aged 9 years", + "age_90": "Aged 90 years", + "age_91": "Aged 91 years", + "age_92": "Aged 92 years", + "age_93": "Aged 93 years", + "age_94": "Aged 94 years", + "age_95": "Aged 95 years", + "age_96": "Aged 96 years", + "age_97": "Aged 97 years", + "age_98": "Aged 98 years", + "age_99": "Aged 99 years" + }, + "salary_sacrifice_threshold_position": { + "all": "All threshold positions" + }, + "scheme_type": { + "Defined benefit": "Defined benefit", + "Defined contribution": "Defined contribution", + "all": "Total" + }, + "school_membership": { + "isc": "ISC member schools" + }, + "scotgov.bus_scope": { + "scotland": "Scotland" + }, + "scotgov.funding_component": { + "all_government_support": "All government support", + "concessionary_fares": "Concessionary fares", + "local_authority_bus_support": "Local authority bus support", + "network_support_grant": "Network Support Grant" + }, + "scotgov.geography_row": { + "scotland": "Scotland" + }, + "scotgov.journey_category": { + "all_passenger_journeys": "All passenger journeys", + "concessionary_passenger_journeys": "Concessionary passenger journeys" + }, + "seasonal_adjustment": { + "actual": "Actual (not seasonally adjusted)" + }, + "sector": { + "Private": "Private sector", + "Public": "Public sector", + "S13": "S13", + "all": "All sectors" + }, + "sector_scheme": { + "Personal or private sector occupational scheme": "Personal or private sector occupational scheme", + "Public sector occupational scheme": "Public sector occupational scheme", + "all": "Total" + }, + "service": { + "metro_glider": "Metro / Glider" + }, + "sex": { + "Female": "Female", + "Male": "Male", + "all": "All", + "female": "Female", + "male": "Male" + }, + "sic2007_section": { + "A": "Agriculture, Forestry and Fishing", + "B": "Mining and Quarrying", + "C": "Manufacturing", + "D": "Electricity, Gas, Steam and Air Conditioning Supply", + "E": "Water supply; sewerage, waste management and remediation activities", + "F": "Construction", + "G": "Wholesale and retail trade; repair of motor vehicles and motorcycles", + "H": "Transportation and storage", + "I": "Accommodation and food service activities", + "J": "Information and communication", + "K": "Financial and insurance activities", + "L": "Real estate activities", + "M": "Professional, scientific and technical activities", + "N": "Administrative and support service activities", + "O": "Public administration and defence; compulsory social security", + "P": "Education", + "Q": "Human health and social work activities", + "R": "Arts, entertainment and recreation", + "S": "Other service activities", + "all": "All industries" + }, + "sic2007_summary_category": { + "all": "All industries", + "index_of_production": "All Index of Production industries (SIC 2007 sections B to E)", + "service_industries": "All service industries (SIC 2007 sections G to U)" + }, + "slc.repayment_line": { + "he_repayments": "Higher education borrower repayments" + }, + "slc.repayment_plan": { + "net_repayments": "Net repayments posted during the financial year" + }, + "soc2020_major_group": { + "1": "Managers, directors and senior officials", + "2": "Professional occupations", + "3": "Associate professional and technical occupations", + "4": "Administrative and secretarial occupations", + "5": "Skilled trades occupations", + "6": "Caring, leisure and other service occupations", + "7": "Sales and customer service occupations", + "8": "Process, plant and machine operatives", + "9": "Elementary occupations" + }, + "spdeps": { + "SPR": "SPR" + }, + "spfunc": { + "DIS": "DIS", + "EXCL": "EXCL", + "FAM": "FAM", + "HOU": "HOU", + "OLD": "OLD", + "SICK": "SICK", + "SRV": "SRV", + "TOTAL": "TOTAL", + "UNE": "UNE", + "disability": "Disability", + "family_children": "Family and children", + "housing": "Housing", + "old_age": "Old age", + "sickness_health_care": "Sickness and health care", + "social_exclusion_nec": "Social exclusion not elsewhere classified", + "survivors": "Survivors", + "total": "Total social protection benefits", + "unemployment": "Unemployment" + }, + "statistic": { + "estimate": "Estimate", + "margin_of_error": "Margin of error", + "mean": "Mean", + "median": "Median" + }, + "tariff_type": { + "all": "All tariffs", + "fixed": "Fixed tariffs", + "variable": "Variable tariffs" + }, + "tax_rate": { + "Additional Rate": "Additional Rate", + "Basic Rate": "Basic Rate", + "Higher Rate": "Higher Rate", + "Main Rate": "Main Rate", + "all": "Total" + }, + "taxpayer_type": { + "all": "All", + "individuals": "Individuals", + "trusts": "Trusts" + }, + "temperature_adjustment": { + "actual_temperature": "Actual temperature", + "as_reported": "As reported", + "weather_corrected": "Weather corrected" + }, + "tenure": { + "all_dwellings": "All dwellings", + "council_or_housing_association": "Council or Housing Association", + "owner_occupied": "Owner-occupied", + "privately_rented": "Privately rented" + }, + "time": { + "2022": "2022", + "2023": "2023", + "2024": "2024", + "2025": "2025" + }, + "total_income_lower_bound": { + "100000": "100000", + "1000000": "1000000", + "12570": "12570", + "15000": "15000", + "150000": "150000", + "20000": "20000", + "200000": "200000", + "30000": "30000", + "300000": "300000", + "40000": "40000", + "50000": "50000", + "500000": "500000", + "70000": "70000" + }, + "total_income_upper_bound": { + "100000": "100000", + "1000000": "1000000", + "15000": "15000", + "150000": "150000", + "20000": "20000", + "200000": "200000", + "30000": "30000", + "300000": "300000", + "40000": "40000", + "50000": "50000", + "500000": "500000", + "70000": "70000" + }, + "type_of_pension_credit": { + "Both Guarantee and Savings Credit": "Both Guarantee and Savings Credit", + "Guarantee Credit only": "Guarantee Credit only", + "Savings Credit only": "Savings Credit only", + "all": "Total" + }, + "uk.firm.employment_band": { + "0_4": "0_4", + "100_249": "100_249", + "10_19": "10_19", + "20_49": "20_49", + "250_plus": "250_plus", + "50_99": "50_99", + "5_9": "5_9" + }, + "uk.firm.sic_code": { + "00001": "1", + "00002": "2", + "00003": "3", + "00005": "5", + "00006": "6", + "00007": "7", + "00008": "8", + "00009": "9", + "00010": "10", + "00011": "11", + "00012": "12", + "00013": "13", + "00014": "14", + "00015": "15", + "00016": "16", + "00017": "17", + "00018": "18", + "00019": "19", + "00020": "20", + "00021": "21", + "00022": "22", + "00023": "23", + "00024": "24", + "00025": "25", + "00026": "26", + "00027": "27", + "00028": "28", + "00029": "29", + "00030": "30", + "00031": "31", + "00032": "32", + "00033": "33", + "00035": "35", + "00036": "36", + "00037": "37", + "00038": "38", + "00039": "39", + "00041": "41", + "00042": "42", + "00043": "43", + "00045": "45", + "00046": "46", + "00047": "47", + "00049": "49", + "00050": "50", + "00051": "51", + "00052": "52", + "00053": "53", + "00055": "55", + "00056": "56", + "00058": "58", + "00059": "59", + "00060": "60", + "00061": "61", + "00062": "62", + "00063": "63", + "00064": "64", + "00065": "65", + "00066": "66", + "00068": "68", + "00069": "69", + "00070": "70", + "00071": "71", + "00072": "72", + "00073": "73", + "00074": "74", + "00075": "75", + "00077": "77", + "00078": "78", + "00079": "79", + "00080": "80", + "00081": "81", + "00082": "82", + "00084": "84", + "00085": "85", + "00086": "86", + "00087": "87", + "00088": "88", + "00090": "90", + "00091": "91", + "00092": "92", + "00093": "93", + "00094": "94", + "00095": "95", + "00096": "96", + "00097": "97", + "00098": "98", + "00099": "99" + }, + "uk.firm.turnover_band": { + "0_49k": "0_49k", + "1000_4999k": "1000_4999k", + "100_249k": "100_249k", + "250_499k": "250_499k", + "5000k_plus": "5000k_plus", + "500_999k": "500_999k", + "50_99k": "50_99k" + }, + "uk.firm.vat_registered": { + "true": "True" + }, + "unit": { + "MIO_EUR": "MIO_EUR" + }, + "us:statutes/26/62#adjusted_gross_income": { + "100k_to_200k": "$100,000 under $200,000", + "10k_to_11k": "$10,000 under $11,000", + "10k_to_15k": "$10,000 under $15,000", + "10k_to_25k": "$10,000 under $25,000", + "10m_plus": "$10,000,000 or more", + "11k_to_12k": "$11,000 under $12,000", + "12k_to_13k": "$12,000 under $13,000", + "13k_to_14k": "$13,000 under $14,000", + "14k_to_15k": "$14,000 under $15,000", + "15k_to_16k": "$15,000 under $16,000", + "15k_to_20k": "$15,000 under $20,000", + "16k_to_17k": "$16,000 under $17,000", + "17k_to_18k": "$17,000 under $18,000", + "18k_to_19k": "$18,000 under $19,000", + "19k_to_20k": "$19,000 under $20,000", + "1_5m_to_2m": "$1,500,000 under $2,000,000", + "1_to_10k": "$1 under $10,000", + "1_to_1k": "$1 under $1,000", + "1_to_5k": "$1 under $5,000", + "1k_to_2k": "$1,000 under $2,000", + "1m_plus": "$1,000,000 or more", + "1m_to_1_5m": "$1,000,000 under $1,500,000", + "200k_to_500k": "$200,000 under $500,000", + "20k_to_25k": "$20,000 under $25,000", + "25k_to_30k": "$25,000 under $30,000", + "25k_to_50k": "$25,000 under $50,000", + "2k_to_3k": "$2,000 under $3,000", + "2m_to_5m": "$2,000,000 under $5,000,000", + "30k_to_35k": "$30,000 under $35,000", + "30k_to_40k": "$30,000 under $40,000", + "35k_to_40k": "$35,000 under $40,000", + "3k_to_4k": "$3,000 under $4,000", + "40k_to_45k": "$40,000 under $45,000", + "40k_to_50k": "$40,000 under $50,000", + "45k_to_50k": "$45,000 under $50,000", + "4k_to_5k": "$4,000 under $5,000", + "500k_to_1m": "$500,000 under $1,000,000", + "50k_plus": "$50,000 and over", + "50k_to_75k": "$50,000 under $75,000", + "5k_to_10k": "$5,000 under $10,000", + "5k_to_6k": "$5,000 under $6,000", + "5m_to_10m": "$5,000,000 under $10,000,000", + "6k_to_7k": "$6,000 under $7,000", + "75k_to_100k": "$75,000 under $100,000", + "7k_to_8k": "$7,000 under $8,000", + "8k_to_9k": "$8,000 under $9,000", + "9k_to_10k": "$9,000 under $10,000", + "all": "All returns, total", + "total": "Total", + "under_1": "No adjusted gross income" + }, + "usda_snap.state_or_territory": { + "ak": "Alaska", + "al": "Alabama", + "ar": "Arkansas", + "az": "Arizona", + "ca": "California", + "co": "Colorado", + "ct": "Connecticut", + "dc": "District of Columbia", + "de": "Delaware", + "fl": "Florida", + "ga": "Georgia", + "gu": "Guam", + "hi": "Hawaii", + "ia": "Iowa", + "id": "Idaho", + "il": "Illinois", + "in": "Indiana", + "ks": "Kansas", + "ky": "Kentucky", + "la": "Louisiana", + "ma": "Massachusetts", + "md": "Maryland", + "me": "Maine", + "mi": "Michigan", + "mn": "Minnesota", + "mo": "Missouri", + "ms": "Mississippi", + "mt": "Montana", + "nc": "North Carolina", + "nd": "North Dakota", + "ne": "Nebraska", + "nh": "New Hampshire", + "nj": "New Jersey", + "nm": "New Mexico", + "nv": "Nevada", + "ny": "New York", + "oh": "Ohio", + "ok": "Oklahoma", + "or": "Oregon", + "pa": "Pennsylvania", + "ri": "Rhode Island", + "sc": "South Carolina", + "sd": "South Dakota", + "tn": "Tennessee", + "tx": "Texas", + "ut": "Utah", + "va": "Virginia", + "vi": "Virgin Islands", + "vt": "Vermont", + "wa": "Washington", + "wi": "Wisconsin", + "wv": "West Virginia", + "wy": "Wyoming" + }, + "use_frequency_band": { + "3 or more times a week (%)": "3 or more times a week", + "Less than once a year or never (%)": "Less than once a year or never", + "Once or twice a month (%)": "Once or twice a month", + "Once or twice a week (%)": "Once or twice a week", + "Once or twice a year (%)": "Once or twice a year" + }, + "vat_treatment": { + "including_vat": "Including VAT" + }, + "weekly_earnings_band": { + "Less than £100": "Less than £100", + "Over £600": "Over £600", + "all": "All weekly earnings", + "£100 to £200": "£100 to £200", + "£200 to £300": "£200 to £300", + "£300 to £400": "£300 to £400", + "£400 to £500": "£400 to £500", + "£500 to £600": "£500 to £600" + }, + "welshgov.geography_row": { + "wales": "Wales" + } + } +} diff --git a/chronicle/epoch.py b/chronicle/epoch.py index 5db6d259..f6549d0f 100644 --- a/chronicle/epoch.py +++ b/chronicle/epoch.py @@ -164,18 +164,21 @@ def key_for_epoch(self, key: str, epoch: Epoch) -> str: # The consumer-fact row contracts Chronicle has emitted, oldest first. Each is a # superset of the one before it, so a row restamped with a later id stays valid: # v2 (chronicle#261) is v1 plus optional dimension and value labels, v3 -# (chronicle#266) is v2 plus the publisher's name for the fact's geography, and -# v4 (chronicle#281) is v3 with that name resolved to one spelling per -# identifier where Chronicle's register carries it, the publisher's own text -# moving to an optional geography.publisher_name. The pair above is the Ledger -# rename table, not this contract history, so only v1 and v2 name a naming -# epoch. The row contract and the hash-key domains move independently: +# (chronicle#266) is v2 plus the publisher's name for the fact's geography, v4 +# (chronicle#281) is v3 with that name resolved to one spelling per identifier +# where Chronicle's register carries it, the publisher's own text moving to an +# optional geography.publisher_name, and v5 (chronicle#376) is v4 with one +# label per dimension value where Chronicle's register lists it, the package's +# own wording moving to an optional package_dimension_value_labels. The pair +# above is the Ledger rename table, not this contract history, so only v1 and +# v2 name a naming epoch. The row contract and the hash-key domains move independently: # EMIT_EPOCH still keeps every key Ledger-named. CONSUMER_FACT_ROW_CONTRACTS: tuple[str, ...] = ( SCHEMA_IDS["consumer_fact"].ledger, SCHEMA_IDS["consumer_fact"].chronicle, "chronicle.consumer_fact.v3", "chronicle.consumer_fact.v4", + "chronicle.consumer_fact.v5", ) CONSUMER_FACT_EMIT_SCHEMA_VERSION = CONSUMER_FACT_ROW_CONTRACTS[-1] diff --git a/chronicle/fixtures/consumer_facts.jsonl b/chronicle/fixtures/consumer_facts.jsonl index 315cb9dd..b9ce5b65 100644 --- a/chronicle/fixtures/consumer_facts.jsonl +++ b/chronicle/fixtures/consumer_facts.jsonl @@ -1,3 +1,3 @@ -{"aggregate_fact_key": "ledger.aggregate_fact.v2:13153fb8dfd73fa12d5715e9", "aggregation": {"method": "sum"}, "assertion": "observation", "dimension_labels": {"filing_status": "Filing status", "income_range": "Income range", "us:statutes/26/62#adjusted_gross_income": "Adjusted gross income"}, "dimension_set_key": "ledger.dimension_set.v2:a55266d8b1d53a8a7e49927d", "dimension_value_labels": {"filing_status": {"all": "All filing statuses"}, "income_range": {"all": "All income ranges"}, "us:statutes/26/62#adjusted_gross_income": {"all": "All returns"}}, "dimensions": {"filing_status": "all", "income_range": "all"}, "entity": {"name": "tax_unit", "role": "filing_unit"}, "geography": {"id": "0100000US", "level": "country", "name": "United States", "vintage": "2020_census"}, "label": "United States 2023 tax year count irs soi individual income tax returns for tax unit (filing status=all, income range=all) [irs_soi Publication 1304 Table 1.1 23in11si.xls tax_year_2023]", "layout": {"groupby_dimension": "us:statutes/26/62#adjusted_gross_income", "groupby_dimension_label": "Adjusted gross income", "groupby_ordinal": 0, "groupby_value_id": "all", "groupby_value_label": "All returns", "measure_id": "return_count", "measure_label": "Number of returns", "measure_ordinal": 0, "record_set_id": "irs_soi.ty2023.table_1_1", "record_set_spec_hash": "a1ecc4d67a3d281548a4660e", "record_set_spec_id": "irs_soi.table_1_1.v1", "source_column_id": "return_count", "source_row_id": "all", "table_record_kind": "total"}, "legacy_fact_key": "ledger.fact.v1:079f0697e3b090abf422781b", "lineage": {"source_record_id": "irs_soi.ty2023.table_1_1.all.return_count", "source_cell_keys": ["ledger.source_cell.v1:82f39b2a5aeab53c1b717928"], "source_row_keys": []}, "observed_measure": {"source_concept": "irs_soi.individual_income_tax_returns", "source_measure_id": "return_count", "source_name": "irs_soi", "source_table": "Publication 1304 Table 1.1", "unit": "count"}, "observed_measure_key": "ledger.observed_measure.v2:bc96277bae6ef31da4a5794c", "period": {"type": "tax_year", "value": 2023}, "provenance_class": "administrative", "schema_version": "chronicle.consumer_fact.v4", "semantic_fact_key": "ledger.semantic_fact.v2:1ae4c4f93f554ec7ca14d2ad", "source": {"extracted_at": "2026-05-04", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/irs_soi/soi-table-1-1/2023/842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17/23in11si.xls", "raw_r2_uri": "r2://ledger-raw/raw/irs_soi/soi-table-1-1/2023/842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17/23in11si.xls", "source_file": "23in11si.xls", "source_name": "irs_soi", "source_sha256": "842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17", "source_size_bytes": 54272, "source_table": "Publication 1304 Table 1.1", "url": "https://www.irs.gov/pub/irs-soi/23in11si.xls", "vintage": "tax_year_2023"}, "source_release_key": "ledger.source_release.v2:e418de50f65dc3f88fbcdd6c", "source_series_key": "ledger.source_series.v2:ac7ef40c4f9adbd84a82f24c", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:18df86d027cde55a3f217b77", "universe_constraints": {"domain": "all_individual_income_tax_returns"}, "value": 160602107, "value_type": "integer"} -{"aggregate_fact_key": "ledger.aggregate_fact.v2:36ce90001adb50e8e9758e4f", "aggregation": {"method": "sum"}, "assertion": "observation", "concept_alignment": {"authority": "ledger-us", "canonical_concept": "us:statutes/26/62#adjusted_gross_income", "concept_alignment_key": "ledger.concept_alignment.v2:2e0ac323f1b261710e4397a1", "evidence_notes": "IRS SOI Table 1.1 reports adjusted gross income for individual income tax returns; IRC section 62 defines adjusted gross income. This Ledger assertion treats the SOI AGI column as exactly adopting that legal concept for the tax-year source record.", "evidence_url": "https://uscode.house.gov/view.xhtml?req=(title:26%20section:62%20edition:prelim)", "legal_vintage": "tax_year_2023", "relation": "exact", "source_concept": "irs_soi.adjusted_gross_income"}, "dimension_labels": {"filing_status": "Filing status", "income_range": "Income range", "us:statutes/26/62#adjusted_gross_income": "Adjusted gross income"}, "dimension_set_key": "ledger.dimension_set.v2:a55266d8b1d53a8a7e49927d", "dimension_value_labels": {"filing_status": {"all": "All filing statuses"}, "income_range": {"all": "All income ranges"}, "us:statutes/26/62#adjusted_gross_income": {"all": "All returns"}}, "dimensions": {"filing_status": "all", "income_range": "all"}, "entity": {"name": "tax_unit", "role": "filing_unit"}, "geography": {"id": "0100000US", "level": "country", "name": "United States", "vintage": "2020_census"}, "label": "United States 2023 tax year sum us:statutes/26/62#adjusted gross income for tax unit (filing status=all, income range=all) [irs_soi Publication 1304 Table 1.1 23in11si.xls tax_year_2023]", "layout": {"groupby_dimension": "us:statutes/26/62#adjusted_gross_income", "groupby_dimension_label": "Adjusted gross income", "groupby_ordinal": 0, "groupby_value_id": "all", "groupby_value_label": "All returns", "measure_id": "adjusted_gross_income", "measure_label": "Adjusted gross income", "measure_ordinal": 1, "record_set_id": "irs_soi.ty2023.table_1_1", "record_set_spec_hash": "a1ecc4d67a3d281548a4660e", "record_set_spec_id": "irs_soi.table_1_1.v1", "source_column_id": "adjusted_gross_income", "source_row_id": "all", "table_record_kind": "total"}, "legacy_fact_key": "ledger.fact.v1:7f8e9d3c64fec2670b571c3b", "lineage": {"source_record_id": "irs_soi.ty2023.table_1_1.all.adjusted_gross_income", "source_cell_keys": ["ledger.source_cell.v1:c3d349e26856fb6224303675"], "source_row_keys": []}, "observed_measure": {"source_concept": "irs_soi.adjusted_gross_income", "source_measure_id": "adjusted_gross_income", "source_name": "irs_soi", "source_table": "Publication 1304 Table 1.1", "unit": "usd"}, "observed_measure_key": "ledger.observed_measure.v2:ac9c3cef252ef7ead0066cb1", "period": {"type": "tax_year", "value": 2023}, "provenance_class": "administrative", "schema_version": "chronicle.consumer_fact.v4", "semantic_fact_key": "ledger.semantic_fact.v2:b83082b8e69c1ddc6fdebed2", "source": {"extracted_at": "2026-05-04", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/irs_soi/soi-table-1-1/2023/842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17/23in11si.xls", "raw_r2_uri": "r2://ledger-raw/raw/irs_soi/soi-table-1-1/2023/842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17/23in11si.xls", "source_file": "23in11si.xls", "source_name": "irs_soi", "source_sha256": "842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17", "source_size_bytes": 54272, "source_table": "Publication 1304 Table 1.1", "url": "https://www.irs.gov/pub/irs-soi/23in11si.xls", "vintage": "tax_year_2023"}, "source_release_key": "ledger.source_release.v2:e418de50f65dc3f88fbcdd6c", "source_series_key": "ledger.source_series.v2:ac7ef40c4f9adbd84a82f24c", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:18df86d027cde55a3f217b77", "universe_constraints": {"domain": "all_individual_income_tax_returns"}, "value": 15286017359000, "value_type": "integer"} -{"aggregate_fact_key": "ledger.aggregate_fact.v2:0fa0e8c17cfe0ebd844c4f95", "aggregation": {"method": "sum"}, "assertion": "observation", "dimension_labels": {"filing_status": "Filing status", "income_range": "Income range", "us:statutes/26/62#adjusted_gross_income": "Adjusted gross income"}, "dimension_set_key": "ledger.dimension_set.v2:a55266d8b1d53a8a7e49927d", "dimension_value_labels": {"filing_status": {"all": "All filing statuses"}, "income_range": {"all": "All income ranges"}, "us:statutes/26/62#adjusted_gross_income": {"all": "All returns"}}, "dimensions": {"filing_status": "all", "income_range": "all"}, "entity": {"name": "tax_unit", "role": "filing_unit"}, "geography": {"id": "0100000US", "level": "country", "name": "United States", "vintage": "2020_census"}, "label": "United States 2023 tax year sum irs soi total income tax for tax unit (filing status=all, income range=all) [irs_soi Publication 1304 Table 1.1 23in11si.xls tax_year_2023]", "layout": {"groupby_dimension": "us:statutes/26/62#adjusted_gross_income", "groupby_dimension_label": "Adjusted gross income", "groupby_ordinal": 0, "groupby_value_id": "all", "groupby_value_label": "All returns", "measure_id": "total_income_tax", "measure_label": "Total income tax", "measure_ordinal": 2, "record_set_id": "irs_soi.ty2023.table_1_1", "record_set_spec_hash": "a1ecc4d67a3d281548a4660e", "record_set_spec_id": "irs_soi.table_1_1.v1", "source_column_id": "total_income_tax", "source_row_id": "all", "table_record_kind": "total"}, "legacy_fact_key": "ledger.fact.v1:ec48b42ac43674a2a2206b8b", "lineage": {"source_record_id": "irs_soi.ty2023.table_1_1.all.total_income_tax", "source_cell_keys": ["ledger.source_cell.v1:f38c48e6e2f23204eb997143"], "source_row_keys": []}, "observed_measure": {"source_concept": "irs_soi.total_income_tax", "source_measure_id": "total_income_tax", "source_name": "irs_soi", "source_table": "Publication 1304 Table 1.1", "unit": "usd"}, "observed_measure_key": "ledger.observed_measure.v2:c11ff13c2dfe8af0795a1194", "period": {"type": "tax_year", "value": 2023}, "provenance_class": "administrative", "schema_version": "chronicle.consumer_fact.v4", "semantic_fact_key": "ledger.semantic_fact.v2:f8b2801687c0ba560054ed36", "source": {"extracted_at": "2026-05-04", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/irs_soi/soi-table-1-1/2023/842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17/23in11si.xls", "raw_r2_uri": "r2://ledger-raw/raw/irs_soi/soi-table-1-1/2023/842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17/23in11si.xls", "source_file": "23in11si.xls", "source_name": "irs_soi", "source_sha256": "842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17", "source_size_bytes": 54272, "source_table": "Publication 1304 Table 1.1", "url": "https://www.irs.gov/pub/irs-soi/23in11si.xls", "vintage": "tax_year_2023"}, "source_release_key": "ledger.source_release.v2:e418de50f65dc3f88fbcdd6c", "source_series_key": "ledger.source_series.v2:ac7ef40c4f9adbd84a82f24c", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:18df86d027cde55a3f217b77", "universe_constraints": {"domain": "all_individual_income_tax_returns"}, "value": 2147909818000, "value_type": "integer"} +{"aggregate_fact_key": "ledger.aggregate_fact.v2:13153fb8dfd73fa12d5715e9", "aggregation": {"method": "sum"}, "assertion": "observation", "dimension_labels": {"filing_status": "Filing status", "income_range": "Income range", "us:statutes/26/62#adjusted_gross_income": "Adjusted gross income"}, "dimension_set_key": "ledger.dimension_set.v2:a55266d8b1d53a8a7e49927d", "dimension_value_labels": {"filing_status": {"all": "All filing statuses"}, "income_range": {"all": "All income ranges"}, "us:statutes/26/62#adjusted_gross_income": {"all": "All returns, total"}}, "dimensions": {"filing_status": "all", "income_range": "all"}, "entity": {"name": "tax_unit", "role": "filing_unit"}, "geography": {"id": "0100000US", "level": "country", "name": "United States", "vintage": "2020_census"}, "label": "United States 2023 tax year count irs soi individual income tax returns for tax unit (filing status=all, income range=all) [irs_soi Publication 1304 Table 1.1 23in11si.xls tax_year_2023]", "layout": {"groupby_dimension": "us:statutes/26/62#adjusted_gross_income", "groupby_dimension_label": "Adjusted gross income", "groupby_ordinal": 0, "groupby_value_id": "all", "groupby_value_label": "All returns, total", "measure_id": "return_count", "measure_label": "Number of returns", "measure_ordinal": 0, "record_set_id": "irs_soi.ty2023.table_1_1", "record_set_spec_hash": "a1ecc4d67a3d281548a4660e", "record_set_spec_id": "irs_soi.table_1_1.v1", "source_column_id": "return_count", "source_row_id": "all", "table_record_kind": "total"}, "legacy_fact_key": "ledger.fact.v1:079f0697e3b090abf422781b", "lineage": {"source_record_id": "irs_soi.ty2023.table_1_1.all.return_count", "source_cell_keys": ["ledger.source_cell.v1:82f39b2a5aeab53c1b717928"], "source_row_keys": []}, "observed_measure": {"source_concept": "irs_soi.individual_income_tax_returns", "source_measure_id": "return_count", "source_name": "irs_soi", "source_table": "Publication 1304 Table 1.1", "unit": "count"}, "observed_measure_key": "ledger.observed_measure.v2:bc96277bae6ef31da4a5794c", "period": {"type": "tax_year", "value": 2023}, "provenance_class": "administrative", "package_dimension_value_labels": {"us:statutes/26/62#adjusted_gross_income": {"all": "All returns"}}, "schema_version": "chronicle.consumer_fact.v5", "semantic_fact_key": "ledger.semantic_fact.v2:1ae4c4f93f554ec7ca14d2ad", "source": {"extracted_at": "2026-05-04", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/irs_soi/soi-table-1-1/2023/842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17/23in11si.xls", "raw_r2_uri": "r2://ledger-raw/raw/irs_soi/soi-table-1-1/2023/842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17/23in11si.xls", "source_file": "23in11si.xls", "source_name": "irs_soi", "source_sha256": "842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17", "source_size_bytes": 54272, "source_table": "Publication 1304 Table 1.1", "url": "https://www.irs.gov/pub/irs-soi/23in11si.xls", "vintage": "tax_year_2023"}, "source_release_key": "ledger.source_release.v2:e418de50f65dc3f88fbcdd6c", "source_series_key": "ledger.source_series.v2:ac7ef40c4f9adbd84a82f24c", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:18df86d027cde55a3f217b77", "universe_constraints": {"domain": "all_individual_income_tax_returns"}, "value": 160602107, "value_type": "integer"} +{"aggregate_fact_key": "ledger.aggregate_fact.v2:36ce90001adb50e8e9758e4f", "aggregation": {"method": "sum"}, "assertion": "observation", "concept_alignment": {"authority": "ledger-us", "canonical_concept": "us:statutes/26/62#adjusted_gross_income", "concept_alignment_key": "ledger.concept_alignment.v2:2e0ac323f1b261710e4397a1", "evidence_notes": "IRS SOI Table 1.1 reports adjusted gross income for individual income tax returns; IRC section 62 defines adjusted gross income. This Ledger assertion treats the SOI AGI column as exactly adopting that legal concept for the tax-year source record.", "evidence_url": "https://uscode.house.gov/view.xhtml?req=(title:26%20section:62%20edition:prelim)", "legal_vintage": "tax_year_2023", "relation": "exact", "source_concept": "irs_soi.adjusted_gross_income"}, "dimension_labels": {"filing_status": "Filing status", "income_range": "Income range", "us:statutes/26/62#adjusted_gross_income": "Adjusted gross income"}, "dimension_set_key": "ledger.dimension_set.v2:a55266d8b1d53a8a7e49927d", "dimension_value_labels": {"filing_status": {"all": "All filing statuses"}, "income_range": {"all": "All income ranges"}, "us:statutes/26/62#adjusted_gross_income": {"all": "All returns, total"}}, "dimensions": {"filing_status": "all", "income_range": "all"}, "entity": {"name": "tax_unit", "role": "filing_unit"}, "geography": {"id": "0100000US", "level": "country", "name": "United States", "vintage": "2020_census"}, "label": "United States 2023 tax year sum us:statutes/26/62#adjusted gross income for tax unit (filing status=all, income range=all) [irs_soi Publication 1304 Table 1.1 23in11si.xls tax_year_2023]", "layout": {"groupby_dimension": "us:statutes/26/62#adjusted_gross_income", "groupby_dimension_label": "Adjusted gross income", "groupby_ordinal": 0, "groupby_value_id": "all", "groupby_value_label": "All returns, total", "measure_id": "adjusted_gross_income", "measure_label": "Adjusted gross income", "measure_ordinal": 1, "record_set_id": "irs_soi.ty2023.table_1_1", "record_set_spec_hash": "a1ecc4d67a3d281548a4660e", "record_set_spec_id": "irs_soi.table_1_1.v1", "source_column_id": "adjusted_gross_income", "source_row_id": "all", "table_record_kind": "total"}, "legacy_fact_key": "ledger.fact.v1:7f8e9d3c64fec2670b571c3b", "lineage": {"source_record_id": "irs_soi.ty2023.table_1_1.all.adjusted_gross_income", "source_cell_keys": ["ledger.source_cell.v1:c3d349e26856fb6224303675"], "source_row_keys": []}, "observed_measure": {"source_concept": "irs_soi.adjusted_gross_income", "source_measure_id": "adjusted_gross_income", "source_name": "irs_soi", "source_table": "Publication 1304 Table 1.1", "unit": "usd"}, "observed_measure_key": "ledger.observed_measure.v2:ac9c3cef252ef7ead0066cb1", "period": {"type": "tax_year", "value": 2023}, "provenance_class": "administrative", "package_dimension_value_labels": {"us:statutes/26/62#adjusted_gross_income": {"all": "All returns"}}, "schema_version": "chronicle.consumer_fact.v5", "semantic_fact_key": "ledger.semantic_fact.v2:b83082b8e69c1ddc6fdebed2", "source": {"extracted_at": "2026-05-04", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/irs_soi/soi-table-1-1/2023/842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17/23in11si.xls", "raw_r2_uri": "r2://ledger-raw/raw/irs_soi/soi-table-1-1/2023/842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17/23in11si.xls", "source_file": "23in11si.xls", "source_name": "irs_soi", "source_sha256": "842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17", "source_size_bytes": 54272, "source_table": "Publication 1304 Table 1.1", "url": "https://www.irs.gov/pub/irs-soi/23in11si.xls", "vintage": "tax_year_2023"}, "source_release_key": "ledger.source_release.v2:e418de50f65dc3f88fbcdd6c", "source_series_key": "ledger.source_series.v2:ac7ef40c4f9adbd84a82f24c", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:18df86d027cde55a3f217b77", "universe_constraints": {"domain": "all_individual_income_tax_returns"}, "value": 15286017359000, "value_type": "integer"} +{"aggregate_fact_key": "ledger.aggregate_fact.v2:0fa0e8c17cfe0ebd844c4f95", "aggregation": {"method": "sum"}, "assertion": "observation", "dimension_labels": {"filing_status": "Filing status", "income_range": "Income range", "us:statutes/26/62#adjusted_gross_income": "Adjusted gross income"}, "dimension_set_key": "ledger.dimension_set.v2:a55266d8b1d53a8a7e49927d", "dimension_value_labels": {"filing_status": {"all": "All filing statuses"}, "income_range": {"all": "All income ranges"}, "us:statutes/26/62#adjusted_gross_income": {"all": "All returns, total"}}, "dimensions": {"filing_status": "all", "income_range": "all"}, "entity": {"name": "tax_unit", "role": "filing_unit"}, "geography": {"id": "0100000US", "level": "country", "name": "United States", "vintage": "2020_census"}, "label": "United States 2023 tax year sum irs soi total income tax for tax unit (filing status=all, income range=all) [irs_soi Publication 1304 Table 1.1 23in11si.xls tax_year_2023]", "layout": {"groupby_dimension": "us:statutes/26/62#adjusted_gross_income", "groupby_dimension_label": "Adjusted gross income", "groupby_ordinal": 0, "groupby_value_id": "all", "groupby_value_label": "All returns, total", "measure_id": "total_income_tax", "measure_label": "Total income tax", "measure_ordinal": 2, "record_set_id": "irs_soi.ty2023.table_1_1", "record_set_spec_hash": "a1ecc4d67a3d281548a4660e", "record_set_spec_id": "irs_soi.table_1_1.v1", "source_column_id": "total_income_tax", "source_row_id": "all", "table_record_kind": "total"}, "legacy_fact_key": "ledger.fact.v1:ec48b42ac43674a2a2206b8b", "lineage": {"source_record_id": "irs_soi.ty2023.table_1_1.all.total_income_tax", "source_cell_keys": ["ledger.source_cell.v1:f38c48e6e2f23204eb997143"], "source_row_keys": []}, "observed_measure": {"source_concept": "irs_soi.total_income_tax", "source_measure_id": "total_income_tax", "source_name": "irs_soi", "source_table": "Publication 1304 Table 1.1", "unit": "usd"}, "observed_measure_key": "ledger.observed_measure.v2:c11ff13c2dfe8af0795a1194", "period": {"type": "tax_year", "value": 2023}, "provenance_class": "administrative", "package_dimension_value_labels": {"us:statutes/26/62#adjusted_gross_income": {"all": "All returns"}}, "schema_version": "chronicle.consumer_fact.v5", "semantic_fact_key": "ledger.semantic_fact.v2:f8b2801687c0ba560054ed36", "source": {"extracted_at": "2026-05-04", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/irs_soi/soi-table-1-1/2023/842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17/23in11si.xls", "raw_r2_uri": "r2://ledger-raw/raw/irs_soi/soi-table-1-1/2023/842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17/23in11si.xls", "source_file": "23in11si.xls", "source_name": "irs_soi", "source_sha256": "842da11fe09123796c861e919d16011ef161338de1c172d39064bdfa666aca17", "source_size_bytes": 54272, "source_table": "Publication 1304 Table 1.1", "url": "https://www.irs.gov/pub/irs-soi/23in11si.xls", "vintage": "tax_year_2023"}, "source_release_key": "ledger.source_release.v2:e418de50f65dc3f88fbcdd6c", "source_series_key": "ledger.source_series.v2:ac7ef40c4f9adbd84a82f24c", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:18df86d027cde55a3f217b77", "universe_constraints": {"domain": "all_individual_income_tax_returns"}, "value": 2147909818000, "value_type": "integer"} diff --git a/chronicle/source_package.py b/chronicle/source_package.py index 73f568e2..860aaf86 100644 --- a/chronicle/source_package.py +++ b/chronicle/source_package.py @@ -10,6 +10,7 @@ from pathlib import Path import re import time +from collections.abc import Mapping, Sequence from typing import Any from urllib.parse import unquote, urlparse from zipfile import ZipFile @@ -32,7 +33,15 @@ AggregateFact, build_label, ) -from chronicle.dimension_labels import label_facts, unused_label_declarations +from chronicle.dimension_labels import ( + REGISTER_DISPLAY_PATH, + canonical_value_label, + declared_value_label_issues, + dimension_value_id, + in_package_value_label_remedy, + label_facts, + unused_label_declarations, +) from chronicle.epoch import SCHEMA_IDS, schema_id from chronicle.sources.cells import ( SourceArtifactMetadata, @@ -2477,6 +2486,103 @@ def try_load_source_package(source: str | Path) -> SourcePackage | None: return None +def _row_value_label_issues( + record_sets: Sequence[SourceRecordSetSpec], + declared_value_labels: Mapping[str, Mapping[str, str]], + *, + package_path: Path | None = None, +) -> list[SourcePackageIssue]: + """Refuse a groupby value the package's rows label two ways (chronicle#376). + + Each row's ``label:`` becomes its facts' value label unless Chronicle's + register lists the value or the package declares one label for it in + ``dimension_value_labels``; the rows' wording is then kept as the + package's own, in ``package_dimension_value_labels``. Otherwise rows + that word one value differently would give its facts two labels, which + ``build-bundle`` refuses. This finds it from the package file alone, at + any build year. + """ + + labels_by_value: dict[tuple[str, str], set[str]] = {} + record_sets_by_value: dict[tuple[str, str], list[str]] = {} + for record_set in record_sets: + groupby = (record_set.groupby_dimension or "").strip() + if not groupby: + continue + for row in record_set.rows: + label = (row.label or "").strip() + if not label: + continue + value_id = dimension_value_id(row.value_id) + if canonical_value_label(groupby, value_id) or ( + declared_value_labels.get(groupby, {}).get(value_id) + ): + continue + labels_by_value.setdefault((groupby, value_id), set()).add(label) + record_sets_by_value.setdefault((groupby, value_id), []).append( + record_set.record_set_id + ) + where = f" in {_display_package_path(package_path)}" if package_path else "" + return [ + SourcePackageIssue( + code="conflicting_value_label", + message=( + f"Dimension {dimension_id!r} value {value_id!r} is labelled " + f"{sorted(labels)!r} by the rows of this package{where}. " + f"{in_package_value_label_remedy(dimension_id, value_id)}" + ), + record_set_id=record_sets_by_value[(dimension_id, value_id)][0], + row_id=value_id, + ) + for (dimension_id, value_id), labels in sorted(labels_by_value.items()) + if len(labels) > 1 + ] + + +def _declared_value_label_register_issues( + declared_value_labels: Mapping[str, Mapping[str, Any]], + *, + package_path: Path | None = None, +) -> list[SourcePackageIssue]: + """Refuse a declaration that Chronicle's register contradicts (chronicle#376). + + Every fact takes the register's label for a value it lists, so a package + declaration with other text would never reach a fact and would mislead + whoever reads the package file. The register is the one source of those + labels; the package's rows keep their own wording. + """ + + where = f" in {_display_package_path(package_path)}" if package_path else "" + return [ + SourcePackageIssue( + code="declared_value_label_differs_from_register", + message=( + f"dimension_value_labels.{dimension_id}.{value_id} declares " + f"{declared!r}{where}, but Chronicle's register " + f"({REGISTER_DISPLAY_PATH}) labels this value {canonical!r}, " + "and every fact takes the register's label (chronicle#376). " + f"Change the declaration to {canonical!r}." + ), + row_id=value_id, + ) + for dimension_id, value_id, declared, canonical in ( + declared_value_label_issues(declared_value_labels) + ) + ] + + +def _display_package_path(package_path: str | Path) -> str: + """Return a package file's path relative to the repository when it can.""" + + path = Path(package_path) + if path.is_dir(): + path = path / "source_package.yaml" + try: + return str(path.resolve().relative_to(Path(__file__).resolve().parents[1])) + except ValueError: + return str(path) + + def validate_source_package( source: str | Path, *, @@ -2577,6 +2683,19 @@ def validate_source_package( source_record_ids.setdefault(spec.source_record_id, []).append(spec_index) counts["source_record_count"] += 1 + errors.extend( + _row_value_label_issues( + record_sets, + package.dimension_value_labels or {}, + package_path=package.package_path, + ) + ) + errors.extend( + _declared_value_label_register_issues( + package.dimension_value_labels or {}, + package_path=package.package_path, + ) + ) for record_set_id, indices in record_set_ids.items(): if len(indices) > 1: errors.append( diff --git a/chronicle/sources/census_acs5_county.py b/chronicle/sources/census_acs5_county.py index 2ddb2c42..6a76d792 100644 --- a/chronicle/sources/census_acs5_county.py +++ b/chronicle/sources/census_acs5_county.py @@ -17,6 +17,7 @@ from openpyxl.utils import get_column_letter import yaml +from chronicle.dimension_labels import canonical_value_label from chronicle.epoch import schema_id from chronicle.yaml_io import safe_load @@ -391,8 +392,13 @@ def build_package(table: str, root: Path = ROOT) -> dict[str, Any]: "B19001": "Income range", "B19051": "Earnings status", }[table] + # A value Chronicle's label register lists is declared with the + # register's label (chronicle#376): B19001's "Total" is income_range + # all, which the IRS SOI packages call "All income ranges". Census's + # own text stays in the measure labels and the source cells. values[category_dimension] = { - category: label for _, category, label in _categories(table) + category: canonical_value_label(category_dimension, category) or label + for _, category, label in _categories(table) } payload = { "schema_version": schema_id("source_package"), diff --git a/chronicle/store.py b/chronicle/store.py index b62e5349..9feb3e07 100644 --- a/chronicle/store.py +++ b/chronicle/store.py @@ -92,6 +92,12 @@ def fact_from_mapping(payload: dict[str, Any]) -> AggregateFact: "dimension_value_labels", {} ).items() }, + package_dimension_value_labels={ + dimension_id: dict(value_labels) + for dimension_id, value_labels in payload.get( + "package_dimension_value_labels", {} + ).items() + }, ) @@ -101,7 +107,11 @@ def fact_to_mapping(fact: AggregateFact) -> dict[str, Any]: if isinstance(fact.value, Decimal): payload["value"] = str(fact.value) payload["value_type"] = "decimal" - for label_field in ("dimension_labels", "dimension_value_labels"): + for label_field in ( + "dimension_labels", + "dimension_value_labels", + "package_dimension_value_labels", + ): if not payload[label_field]: payload.pop(label_field) payload["measure"] = { diff --git a/chronicle/suite.py b/chronicle/suite.py index ded968fb..7bcad55b 100644 --- a/chronicle/suite.py +++ b/chronicle/suite.py @@ -615,6 +615,58 @@ def _canonicalize_lineage_key(domain_name: str, key: Any) -> str: return key +_VALUE_LABEL_CONFLICT_CODES = frozenset( + {"conflicting_dimension_value_label", "conflicting_groupby_value_label"} +) + + +def _value_label_acceptance_issues( + facts: Sequence[AggregateFact], +) -> list[AgentAcceptanceIssue]: + """Refuse a value this package's facts label two ways (chronicle#376). + + The facts already carry the label Chronicle's register gives every value + it lists, so this finds a value the register does not list whose rows, + source text or declarations word it two ways, before ``build-bundle`` + would refuse it. + """ + + # Imported here: chronicle.dimension_labels imports chronicle.suite's + # source-row helpers lazily, and the suite imports the package loader. + from chronicle.dimension_labels import dimension_label_issues + + rows = [] + for fact in facts: + layout = fact.layout + rows.append( + { + "aggregate_fact_key": fact.source_record_id, + "dimensions": { + key: value + for key, value in fact.filters.items() + if value is not None + }, + "dimension_labels": fact.dimension_labels, + "dimension_value_labels": fact.dimension_value_labels, + "layout": ( + { + "groupby_dimension": layout.groupby_dimension, + "groupby_dimension_label": layout.groupby_dimension_label, + "groupby_value_id": layout.groupby_value_id, + "groupby_value_label": layout.groupby_value_label, + } + if layout + else {} + ), + } + ) + return [ + AgentAcceptanceIssue(code="conflicting_value_label", message=issue.message) + for issue in dimension_label_issues(rows) + if issue.code in _VALUE_LABEL_CONFLICT_CODES + ] + + def build_agent_acceptance_report( facts: list[AggregateFact], rows: list[SourceRow], @@ -863,6 +915,7 @@ def build_agent_acceptance_report( ) ) + errors.extend(_value_label_acceptance_issues(facts)) checks = { "stage_reports_valid": stage_reports_valid, "raw_artifacts_have_r2": raw_r2_link_count == len(artifacts) diff --git a/docs/agent-source-package-harness.md b/docs/agent-source-package-harness.md index 0414958d..261c1dd5 100644 --- a/docs/agent-source-package-harness.md +++ b/docs/agent-source-package-harness.md @@ -869,9 +869,74 @@ dimension_value_labels: A groupby axis whose rows cross several fields takes the label of its leading field, the one its id names; the crossed fields carry their own labels as dimensions of the same fact. A declaration wins over every recovered label. `build-bundle` reports an error for any package fact with an unlabelled or doubly labelled dimension or value, and for a dimension id two packages label differently (chronicle#265 — the rule -covers every country, since a consumer reads one artifact); publisher row labels -that differ across one groupby value's rows are a warning, since Chronicle keeps -them as published. `build_facts` refuses a declaration no fact uses. +covers every country, since a consumer reads one artifact). `build_facts` +refuses a declaration no fact uses. + +One dimension value carries one label (chronicle#376). Microcosm copies labels +into every target and merges packages built for different years into one feed, +so a value must not depend on which packages one build compares. Chronicle's +register, `chronicle/dimension_values/canonical_labels.json`, gives one label to +every value that two or more packages emit, and to every value its packages word +more than one way. When a package is built, at any year, each value the +register lists takes the register's label in `dimension_value_labels` and, for +the groupby value, `layout.groupby_value_label`; the package's own wording (the +row's `label:`, else its declaration, else its source-row text) is kept in +`package_dimension_value_labels` where it differs. That field holds the +package's wording, not necessarily the publisher's, and nothing checks it +against the publisher's file. The guards compare a row's `expected_row_header` +and `expected_column_header`, which are fields separate from its `label:`, with +the source cells (a row's `label:` is compared with the row-header cell only +when the row sets no `expected_row_header`). So a row's `label:` is the +publisher's text only where it equals the text a guard compares: the IRS +filing-season week-47 table heads its below-$1 column "No adjusted gross income +and deficit", the rows' `label:` and `expected_column_header` both say so, and +their facts carry the register's "No adjusted gross income" with the IRS text +beside it. Elsewhere the package's wording is often Chronicle's: a parser's +constant (Census B01001's "Female 20 years"), a value id in an extract Chronicle +prepared (Statbel's "65_plus"), or a package author's phrase (Eurostat's "First +income decile cut-point", whose guard checks the code `D1`). The publisher's +cells stay reachable through each fact's lineage. + +A value the register does not list is one only one package emits, so its +package's label is its one label. A value labelled two ways is an error, with no +list of exceptions: + +- inside one package, `validate-package` reports `conflicting_value_label` for + a groupby value whose rows word it two ways, `build-suite` reports the same + for any value its facts label two ways, and `build-bundle` reports + `conflicting_groupby_value_label` or `conflicting_dimension_value_label`; + declare one label for the value in the package's `dimension_value_labels`; +- across packages, `build-bundle` reports + `conflicting_value_label_across_packages`; add the value to the register with + one label. + +A package may not declare a label in `dimension_value_labels` for a value the +register lists unless it is the register's label: `validate-package` reports +`declared_value_label_differs_from_register`, so the register is the one source +of those labels. + +A new package that emits a value another package already emits should check the +register: the value is either listed, and takes the listed label, or needs an +entry. To choose a register label for a value its packages word differently, +take the wording most packages use, ties going to the national statistics +office's wording, without footnote markers or words that name the measure, and +keep each package's text in its rows. Where every wording names the measure +rather than the value, no package's text can be the label, and the maintainer +gives the value Chronicle's own wording: HMRC's salary sacrifice package words +`salary_sacrifice_threshold_position=all` "Employees using salary sacrifice to +make pension contributions" and "National Insurance contributions forgone +through salary sacrifice for pensions", and the register calls it "All threshold +positions". A register label is display text, not a source value, so such a +label invents no fact; the packages' texts stay in their rows and in +`package_dimension_value_labels`. The register is generated by +`scripts/build_dimension_value_register.py`, which holds the chosen labels; +add a chosen label there, rerun it, and commit both files. Its `--static-check` +mode compares the register with the package files without building them (every +value two packages' files name must be listed, every listed value must be named +by a package file, and no declaration may contradict the register), and +`tests/test_dimension_value_register.py` runs it in CI. The script without +`--static-check` builds every default-bundle package at its build year; with +`--check` it fails if the register differs from what those builds give. Every fact also carries the publisher's name for its geography (chronicle#266), taken from the record set's or the row's `geography_name`. `build-bundle` @@ -881,8 +946,9 @@ catalog only for identifiers it already knows, and an identifier is not a name. A country-level geography may stay unnamed, and no name is ever invented from the code. Where two packages name one area differently — the IRS truncates county names to twenty characters, and ONS writes "Yorkshire and The Humber" -where HMRC writes "the" — Chronicle keeps each publisher's text and warns, the -same way it does for a groupby value's row labels. +where HMRC writes "the" — Chronicle's UK register gives one name where it +carries the identifier (chronicle#281), and the bundle warns about the areas it +does not carry yet. ### Pinned artifacts and year labels diff --git a/docs/data-sources/uk-gambling-participation-gsgb-2025.md b/docs/data-sources/uk-gambling-participation-gsgb-2025.md index 97c8ab7f..26707c51 100644 --- a/docs/data-sources/uk-gambling-participation-gsgb-2025.md +++ b/docs/data-sources/uk-gambling-participation-gsgb-2025.md @@ -109,7 +109,9 @@ The values: markers dropped. - B.9's row 6 reads "Tickets National Lottery draws bought in person", where B.10's reads "Tickets for National Lottery draws bought in person". - - Both are kept, so the bundle reports a groupby-label warning for that row. + - Both are kept in the rows. Chronicle's label register gives the value B.10's + wording, and B.9's facts keep their row's text in + `package_dimension_value_labels` (chronicle#376). - B.2 and B.4's rows are named by area, on a `gambling_commission.gsgb_area` axis. - **Left out:** - weighted bases; diff --git a/docs/schemas/consumer_fact.v5.schema.json b/docs/schemas/consumer_fact.v5.schema.json new file mode 100644 index 00000000..59ff1389 --- /dev/null +++ b/docs/schemas/consumer_fact.v5.schema.json @@ -0,0 +1,502 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://policyengine.org/chronicle/schemas/consumer_fact.v5.schema.json", + "title": "Chronicle consumer fact contract row", + "description": "The v4 contract row with one label per dimension value (chronicle#376). Where Chronicle's register of dimension value labels carries a value, dimension_value_labels and layout.groupby_value_label carry the register's label, and package_dimension_value_labels carries the source package's own wording of that value when it differs, which is not checked against the publisher's file and may be text Chronicle wrote; elsewhere the labels are the package's, as in v4. Both stay display metadata: neither enters a fact key, and a v4 row restamped with this schema_version is a valid v5 row.", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "aggregate_fact_key", + "semantic_fact_key", + "legacy_fact_key", + "source_release_key", + "source_series_key", + "observed_measure_key", + "dimension_set_key", + "universe_constraint_set_key", + "value", + "value_type", + "assertion", + "provenance_class", + "period", + "geography", + "entity", + "aggregation", + "observed_measure", + "dimensions", + "universe_constraints", + "source", + "lineage" + ], + "allOf": [ + { + "if": { + "properties": { + "provenance_class": { + "const": "survey_aggregate" + } + }, + "required": [ + "provenance_class" + ] + }, + "then": { + "required": [ + "survey_instrument" + ] + }, + "else": { + "not": { + "required": [ + "survey_instrument" + ] + } + } + } + ], + "properties": { + "schema_version": { + "const": "chronicle.consumer_fact.v5" + }, + "aggregate_fact_key": { + "type": "string", + "pattern": "^ledger\\.aggregate_fact\\.v2:[0-9a-f]{24}$" + }, + "semantic_fact_key": { + "type": "string", + "pattern": "^ledger\\.semantic_fact\\.v2:[0-9a-f]{24}$" + }, + "legacy_fact_key": { + "type": "string", + "pattern": "^ledger\\.fact\\.v1:[0-9a-f]{24}$" + }, + "source_release_key": { + "type": "string", + "pattern": "^ledger\\.source_release\\.v2:[0-9a-f]{24}$" + }, + "source_series_key": { + "type": "string", + "pattern": "^ledger\\.source_series\\.v2:[0-9a-f]{24}$" + }, + "observed_measure_key": { + "type": "string", + "pattern": "^ledger\\.observed_measure\\.v2:[0-9a-f]{24}$" + }, + "dimension_set_key": { + "type": "string", + "pattern": "^ledger\\.dimension_set\\.v2:[0-9a-f]{24}$" + }, + "universe_constraint_set_key": { + "type": "string", + "pattern": "^ledger\\.universe_constraint_set\\.v2:[0-9a-f]{24}$" + }, + "value": { + "type": [ + "integer", + "number", + "string", + "boolean" + ] + }, + "value_type": { + "enum": [ + "integer", + "number", + "decimal", + "string", + "boolean" + ] + }, + "period": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "description": "Publisher-asserted period kind; the ledger.core.ALLOWED_PERIOD_TYPES vocabulary: calendar_year, tax_year, fiscal_year, academic_year, gas_year, month, quarter, week. Split-label years store the opening year of the publisher's label (UK FY2024-25 -> fiscal_year 2024; AY 2024/25 -> academic_year 2024). gas_year keeps DESNZ's year label: the opening year from 2016 (mid-May 2024 to mid-May 2025 -> gas_year 2024) and the closing year of the October-to-September years to 2015. Publishers labelling a fiscal year with a single year keep that label year (US federal FY2024 -> 2024). Quarter values use YYYY-QN and ISO week values use YYYY-Www, with exact dates in period_coverage." + }, + "value": { + "type": [ + "integer", + "string" + ] + } + } + }, + "geography": { + "type": "object", + "additionalProperties": false, + "required": [ + "level", + "id" + ], + "properties": { + "level": { + "type": "string" + }, + "id": { + "type": "string" + }, + "vintage": { + "type": "string" + }, + "name": { + "$ref": "#/$defs/label", + "description": "The name for this geography: Chronicle's register name where it carries the identifier, otherwise the publisher's own text; absent when neither states a name." + }, + "publisher_name": { + "$ref": "#/$defs/label", + "description": "The publisher's own name for this geography, present only where it differs from the register name carried in 'name'." + } + } + }, + "entity": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "role": { + "type": "string" + } + } + }, + "aggregation": { + "type": "object", + "additionalProperties": false, + "required": [ + "method" + ], + "properties": { + "method": { + "type": "string" + }, + "denominator": { + "type": "string" + } + } + }, + "observed_measure": { + "type": "object", + "additionalProperties": false, + "required": [ + "source_name", + "source_table", + "source_measure_id", + "source_concept", + "unit" + ], + "properties": { + "source_name": { + "type": "string" + }, + "source_table": { + "type": "string" + }, + "source_measure_id": { + "type": "string" + }, + "source_concept": { + "type": "string" + }, + "unit": { + "type": "string" + } + } + }, + "dimensions": { + "type": "object", + "additionalProperties": { + "type": [ + "integer", + "number", + "string", + "boolean" + ] + } + }, + "dimension_labels": { + "type": "object", + "description": "Label for each dimension id: every key of dimensions and, when layout.groupby_dimension is set, that id.", + "additionalProperties": { + "$ref": "#/$defs/label" + } + }, + "dimension_value_labels": { + "type": "object", + "description": "Label for each dimension value, keyed dimension id then value id: the label in Chronicle's register of dimension value labels when it carries the value, otherwise the source package's label. A value id is the value's string form: booleans lower-cased (true, false), integers, numbers and strings as Python str() writes them, lists and mappings JSON-serialised with sorted keys and no spaces. Covers every dimensions entry and, when layout.groupby_dimension is set, layout.groupby_value_id, whose label layout.groupby_value_label repeats.", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/label" + } + } + }, + "package_dimension_value_labels": { + "type": "object", + "description": "The source package's own wording of a dimension value, present only where it differs from the label this row carries for that value: the package row's label, else the package's dimension_value_labels declaration, else the text in the matching column of the parsed source row. This text is not checked against the publisher's file. It may be the publisher's wording (for example a row label that the row's guard compares with a header cell) or text Chronicle wrote (a parser's constant, a value id in an extract Chronicle prepared, or a package author's phrase); the publisher's own cells are reached through lineage.source_cell_keys. Keyed dimension id then value id like dimension_value_labels; the groupby value of a groupby axis that is also a filter with a different value is keyed by layout.groupby_value_id and differs from layout.groupby_value_label.", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/label" + } + } + }, + "universe_constraints": { + "type": "object", + "additionalProperties": false, + "required": [ + "domain" + ], + "properties": { + "domain": { + "type": "string" + }, + "constraints": { + "type": "array", + "items": { + "$ref": "#/$defs/constraint" + } + } + } + }, + "source": { + "type": "object", + "additionalProperties": true, + "required": [ + "source_name", + "source_table", + "source_file", + "vintage", + "extracted_at", + "extraction_method", + "source_sha256", + "source_size_bytes", + "raw_r2_uri" + ], + "properties": { + "source_name": { + "type": "string" + }, + "source_table": { + "type": "string" + }, + "source_file": { + "type": "string" + }, + "url": { + "type": "string" + }, + "vintage": { + "type": "string" + }, + "extracted_at": { + "type": "string" + }, + "extraction_method": { + "type": "string" + }, + "method_notes": { + "type": "string" + }, + "source_sha256": { + "type": "string" + }, + "source_size_bytes": { + "type": "integer" + }, + "raw_r2_bucket": { + "type": "string" + }, + "raw_r2_key": { + "type": "string" + }, + "raw_r2_uri": { + "type": "string" + } + } + }, + "lineage": { + "type": "object", + "additionalProperties": false, + "required": [ + "source_record_id", + "source_cell_keys" + ], + "properties": { + "source_record_id": { + "type": "string" + }, + "source_cell_keys": { + "type": "array", + "items": { + "type": "string" + } + }, + "source_row_keys": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "layout": { + "type": "object", + "additionalProperties": true, + "properties": { + "groupby_dimension_label": { + "$ref": "#/$defs/label", + "description": "Label of layout.groupby_dimension; equals dimension_labels for that id." + } + } + }, + "label": { + "type": "string" + }, + "concept_alignment": { + "type": "object", + "additionalProperties": false, + "required": [ + "concept_alignment_key", + "source_concept", + "canonical_concept", + "relation", + "authority" + ], + "properties": { + "concept_alignment_key": { + "type": "string", + "pattern": "^ledger\\.concept_alignment\\.v2:[0-9a-f]{24}$" + }, + "source_concept": { + "type": "string" + }, + "canonical_concept": { + "type": "string" + }, + "relation": { + "type": "string" + }, + "authority": { + "type": "string" + }, + "evidence_url": { + "type": "string" + }, + "evidence_notes": { + "type": "string" + }, + "legal_vintage": { + "type": "string" + } + } + }, + "assertion": { + "type": "string", + "enum": [ + "observation", + "source_projection" + ], + "description": "Who asserted the value: a publisher-measured outcome (observation) or the publisher's own forward-looking estimate (source_projection). PolicyEngine-computed values are never consumer facts." + }, + "provenance_class": { + "type": "string", + "enum": [ + "administrative", + "census", + "survey_aggregate", + "model_output" + ], + "description": "Publisher measurement basis. Consumers can gate calibration inputs on this required, closed classification." + }, + "survey_instrument": { + "type": "string", + "pattern": ".*\\S.*", + "description": "Survey name required exactly when provenance_class is survey_aggregate." + }, + "period_coverage": { + "type": "object", + "additionalProperties": false, + "description": "Non-identity provenance for the fact's reference period: coverage dates, basis, the publisher's period label, and accounting basis.", + "properties": { + "start_date": { + "type": "string" + }, + "end_date": { + "type": "string" + }, + "basis": { + "type": "string", + "enum": [ + "calendar", + "tax", + "fiscal", + "survey_reference", + "projection_horizon" + ] + }, + "source_period_label": { + "type": "string" + }, + "accounting_basis": { + "type": "string", + "enum": [ + "cash", + "accrual" + ] + }, + "notes": { + "type": "string" + } + } + } + }, + "$defs": { + "label": { + "type": "string", + "pattern": ".*\\S.*" + }, + "constraint": { + "type": "object", + "additionalProperties": false, + "required": [ + "variable", + "operator", + "value", + "role" + ], + "properties": { + "variable": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "value": { + "type": [ + "integer", + "number", + "string", + "boolean" + ] + }, + "unit": { + "type": "string" + }, + "role": { + "type": "string" + } + } + } + } +} diff --git a/packages/census/acs5_b19001_county_2024/source_package.yaml b/packages/census/acs5_b19001_county_2024/source_package.yaml index a68eb7d9..1918b5b6 100644 --- a/packages/census/acs5_b19001_county_2024/source_package.yaml +++ b/packages/census/acs5_b19001_county_2024/source_package.yaml @@ -13,7 +13,7 @@ dimension_value_labels: estimate: Estimate margin_of_error: Margin of error income_range: - all: Total + all: All income ranges under_10000: Less than $10,000 10000_to_14999: $10,000 to $14,999 15000_to_19999: $15,000 to $19,999 diff --git a/packages/census/pep_2024_national_age_sex/source_package.yaml b/packages/census/pep_2024_national_age_sex/source_package.yaml index 7feccc87..bf93cdc1 100644 --- a/packages/census/pep_2024_national_age_sex/source_package.yaml +++ b/packages/census/pep_2024_national_age_sex/source_package.yaml @@ -843,8 +843,10 @@ record_sets: end: 84 label: single-year age sequence table_record_kind: detail + # The file has numeric age codes only (85 to 100 summed here), so the label + # is Chronicle's: the one its register gives age 85_plus (chronicle#376). - value_id: 85_plus - label: Age 85 and over + label: Age 85 plus ordinal: 18 row_number: 88 row_end_number: 103 diff --git a/packages/dft/nts0601_age_mode_trips_2025/source_package.yaml b/packages/dft/nts0601_age_mode_trips_2025/source_package.yaml index 1f48ee09..0002cce2 100644 --- a/packages/dft/nts0601_age_mode_trips_2025/source_package.yaml +++ b/packages/dft/nts0601_age_mode_trips_2025/source_package.yaml @@ -24,8 +24,10 @@ dimension_value_labels: '0 to 16': 'Age 0 to 16' '17 to 20': 'Age 17 to 20' '21 to 29': 'Age 21 to 29' - '30 to 39': 'Age 30 to 39' - '40 to 49': 'Age 40 to 49' + # Chronicle's register gives these two labels, DfT's own row headers, + # because ONS ASHE packages emit the same values (chronicle#376). + '30 to 39': '30 to 39' + '40 to 49': '40 to 49' '50 to 59': 'Age 50 to 59' '60 to 69': 'Age 60 to 69' '70 and over': 'Age 70 and over' diff --git a/packages/hmrc/salary_sacrifice_reform_2029_headcounts/source_package.yaml b/packages/hmrc/salary_sacrifice_reform_2029_headcounts/source_package.yaml index 75ad3c05..5f1b343d 100644 --- a/packages/hmrc/salary_sacrifice_reform_2029_headcounts/source_package.yaml +++ b/packages/hmrc/salary_sacrifice_reform_2029_headcounts/source_package.yaml @@ -41,7 +41,12 @@ dimension_labels: 'hmrc.salary_sacrifice_employer_arrangement': 'Employer salary sacrifice arrangement for pension contributions' dimension_value_labels: 'salary_sacrifice_threshold_position': - 'all': 'Employees using salary sacrifice to make pension contributions' + # Chronicle's register gives this label, its own wording (chronicle#376): + # the rows' texts for this value, "Employees using salary sacrifice to make + # pension contributions" and "National Insurance contributions forgone + # through salary sacrifice for pensions", name the measure, and they stay + # in the rows. + 'all': 'All threshold positions' 'within_2000': 'Employees fully protected by the GBP 2,000 threshold' 'salary_sacrifice_employer_arrangement': 'operates': 'Operates salary sacrifice arrangements for pension contributions' diff --git a/packages/irs_soi/filing_season_week47_2024/source_package.yaml b/packages/irs_soi/filing_season_week47_2024/source_package.yaml index 1910f20e..8d101291 100644 --- a/packages/irs_soi/filing_season_week47_2024/source_package.yaml +++ b/packages/irs_soi/filing_season_week47_2024/source_package.yaml @@ -145,6 +145,12 @@ record_sets: domain: all_individual_income_tax_returns groupby_dimension: us:statutes/26/62#adjusted_gross_income rows: + # The label is the IRS's column header, which the guard below checks. + # It is the class every other IRS SOI package calls "No adjusted gross + # income": adjusted gross income below $1, deficits included (column C's + # AGI is -$120.2 billion, and the 16 columns add up to all returns). + # Facts take Chronicle's register label for under_1 and keep this text + # in package_dimension_value_labels (chronicle#376). - value_id: under_1 label: No adjusted gross income and deficit ordinal: 0 @@ -411,6 +417,7 @@ record_sets: domain: all_individual_income_tax_returns groupby_dimension: us:statutes/26/62#adjusted_gross_income rows: + # The IRS's column header, as in the count record set above. - value_id: under_1 label: No adjusted gross income and deficit ordinal: 0 diff --git a/packages/irs_soi/historic_table_2/source_package.yaml b/packages/irs_soi/historic_table_2/source_package.yaml index bfb5cfe8..59fb1459 100644 --- a/packages/irs_soi/historic_table_2/source_package.yaml +++ b/packages/irs_soi/historic_table_2/source_package.yaml @@ -72,8 +72,11 @@ record_sets: domain: all_individual_income_tax_returns groupby_dimension: us:statutes/26/62#adjusted_gross_income rows: + # The CSV has no text for AGI_STUB 0 (the IRS guide calls it "No AGI + # Stub"), so the label is Chronicle's: the one its register gives + # adjusted gross income all (chronicle#376). - value_id: all - label: All returns + label: All returns, total ordinal: 0 row_number: 2 expected_row_header_column: B diff --git a/packages/nisra/mye_2025_lgd_single_year_age/source_package.yaml b/packages/nisra/mye_2025_lgd_single_year_age/source_package.yaml index 46927307..7cd66a76 100644 --- a/packages/nisra/mye_2025_lgd_single_year_age/source_package.yaml +++ b/packages/nisra/mye_2025_lgd_single_year_age/source_package.yaml @@ -7,8 +7,10 @@ dimension_labels: age: Age dimension_value_labels: sex: - female: Females - male: Males + # Chronicle's register gives these labels (chronicle#376); NISRA's own + # "Females" and "Males" stay in the source rows. + female: Female + male: Male age: 90_plus: 90 and over artifact: diff --git a/packages/nrs/mye_2025_council_area/source_package.yaml b/packages/nrs/mye_2025_council_area/source_package.yaml index 1e13d0bf..e2eb496c 100644 --- a/packages/nrs/mye_2025_council_area/source_package.yaml +++ b/packages/nrs/mye_2025_council_area/source_package.yaml @@ -7,8 +7,10 @@ dimension_labels: sex: Sex dimension_value_labels: sex: - female: Females - male: Males + # Chronicle's register gives these labels (chronicle#376); NRS's own + # "Females" and "Males" are still compared by the guard cells below. + female: Female + male: Male age: 90_plus: 90 and over artifact: diff --git a/packages/nrs/pcon24_population_by_age_2024_revised_2026/source_package.yaml b/packages/nrs/pcon24_population_by_age_2024_revised_2026/source_package.yaml index 62ece4f6..ab01fa76 100644 --- a/packages/nrs/pcon24_population_by_age_2024_revised_2026/source_package.yaml +++ b/packages/nrs/pcon24_population_by_age_2024_revised_2026/source_package.yaml @@ -7,8 +7,10 @@ dimension_labels: sex: Sex dimension_value_labels: sex: - female: Females - male: Males + # Chronicle's register gives these labels (chronicle#376); NRS's own + # "Females" and "Males" are still compared by the guard cells below. + female: Female + male: Male age: 90_plus: 90 and over artifact: diff --git a/packages/ons/hpssa_pcon24_year_ending_march_2026/source_package.yaml b/packages/ons/hpssa_pcon24_year_ending_march_2026/source_package.yaml index e41df0a7..947bf9d0 100644 --- a/packages/ons/hpssa_pcon24_year_ending_march_2026/source_package.yaml +++ b/packages/ons/hpssa_pcon24_year_ending_march_2026/source_package.yaml @@ -35,9 +35,10 @@ dimension_labels: property_type: Property Type dimension_value_labels: property_type: - detached: Detached houses - semi_detached: Semi-detached houses - terraced: Terraced houses + # Chronicle's register gives these three labels (chronicle#376). + detached: Detached + semi_detached: Semi detached + terraced: Terraced flat_maisonette: Flats/maisonettes artifact: source_name: ons diff --git a/packages/ons/pipr_rents_by_area_august_2026/source_package.yaml b/packages/ons/pipr_rents_by_area_august_2026/source_package.yaml index ee43fd0c..116ba328 100644 --- a/packages/ons/pipr_rents_by_area_august_2026/source_package.yaml +++ b/packages/ons/pipr_rents_by_area_august_2026/source_package.yaml @@ -13,9 +13,11 @@ dimension_value_labels: three bed: three bed four or more bed: four or more bed property_type: - detached: detached + # Chronicle's register gives detached and terraced their labels + # (chronicle#376). + detached: Detached semidetached: semidetached - terraced: terraced + terraced: Terraced flat maisonette: flat maisonette artifact: source_name: ons diff --git a/policyengine_chronicle/consumer.py b/policyengine_chronicle/consumer.py index 2e94e762..786c9658 100644 --- a/policyengine_chronicle/consumer.py +++ b/policyengine_chronicle/consumer.py @@ -284,7 +284,13 @@ def _geography_key_payload(row: dict[str, Any]) -> Any: def _recompute_aggregate_fact_key(row: dict[str, Any]) -> str: - """Recompute the aggregate fact key from the row's content.""" + """Recompute the aggregate fact key from the row's content. + + Labels are display metadata and never enter the payload: + ``dimension_labels``, ``dimension_value_labels``, ``layout`` and the v5 + ``package_dimension_value_labels`` (chronicle#376) are not read here, and + the geography's display names are dropped by :func:`_geography_key_payload`. + """ declared_key = row.get("aggregate_fact_key") epoch = HASH_DOMAINS["aggregate_fact"].infer_key_epoch(declared_key) assertion = row.get("assertion") diff --git a/policyengine_chronicle/schema.py b/policyengine_chronicle/schema.py index 70c62933..c6506e13 100644 --- a/policyengine_chronicle/schema.py +++ b/policyengine_chronicle/schema.py @@ -9,7 +9,9 @@ (chronicle#266), for ``chronicle.consumer_fact.v3`` rows, and the ``consumer_fact.v4`` schema, v3 with one name per geography identifier and the publisher's own text beside it (chronicle#281), for -``chronicle.consumer_fact.v4`` rows. The packaged schema +``chronicle.consumer_fact.v4`` rows, and the ``consumer_fact.v5`` schema, v4 +with one label per dimension value and the package's own wording beside it +(chronicle#376), for ``chronicle.consumer_fact.v5`` rows. The packaged schema bytes are the single source of truth: each artifact manifest records the sha256 of the schema its rows use, and a load rejects any manifest that claims a different one. @@ -40,6 +42,7 @@ SCHEMA_IDS["consumer_fact"].chronicle: "consumer_fact.v2.schema.json", "chronicle.consumer_fact.v3": "consumer_fact.v3.schema.json", "chronicle.consumer_fact.v4": "consumer_fact.v4.schema.json", + "chronicle.consumer_fact.v5": "consumer_fact.v5.schema.json", } ) diff --git a/policyengine_chronicle/schemas/consumer_fact.v5.schema.json b/policyengine_chronicle/schemas/consumer_fact.v5.schema.json new file mode 100644 index 00000000..59ff1389 --- /dev/null +++ b/policyengine_chronicle/schemas/consumer_fact.v5.schema.json @@ -0,0 +1,502 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://policyengine.org/chronicle/schemas/consumer_fact.v5.schema.json", + "title": "Chronicle consumer fact contract row", + "description": "The v4 contract row with one label per dimension value (chronicle#376). Where Chronicle's register of dimension value labels carries a value, dimension_value_labels and layout.groupby_value_label carry the register's label, and package_dimension_value_labels carries the source package's own wording of that value when it differs, which is not checked against the publisher's file and may be text Chronicle wrote; elsewhere the labels are the package's, as in v4. Both stay display metadata: neither enters a fact key, and a v4 row restamped with this schema_version is a valid v5 row.", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "aggregate_fact_key", + "semantic_fact_key", + "legacy_fact_key", + "source_release_key", + "source_series_key", + "observed_measure_key", + "dimension_set_key", + "universe_constraint_set_key", + "value", + "value_type", + "assertion", + "provenance_class", + "period", + "geography", + "entity", + "aggregation", + "observed_measure", + "dimensions", + "universe_constraints", + "source", + "lineage" + ], + "allOf": [ + { + "if": { + "properties": { + "provenance_class": { + "const": "survey_aggregate" + } + }, + "required": [ + "provenance_class" + ] + }, + "then": { + "required": [ + "survey_instrument" + ] + }, + "else": { + "not": { + "required": [ + "survey_instrument" + ] + } + } + } + ], + "properties": { + "schema_version": { + "const": "chronicle.consumer_fact.v5" + }, + "aggregate_fact_key": { + "type": "string", + "pattern": "^ledger\\.aggregate_fact\\.v2:[0-9a-f]{24}$" + }, + "semantic_fact_key": { + "type": "string", + "pattern": "^ledger\\.semantic_fact\\.v2:[0-9a-f]{24}$" + }, + "legacy_fact_key": { + "type": "string", + "pattern": "^ledger\\.fact\\.v1:[0-9a-f]{24}$" + }, + "source_release_key": { + "type": "string", + "pattern": "^ledger\\.source_release\\.v2:[0-9a-f]{24}$" + }, + "source_series_key": { + "type": "string", + "pattern": "^ledger\\.source_series\\.v2:[0-9a-f]{24}$" + }, + "observed_measure_key": { + "type": "string", + "pattern": "^ledger\\.observed_measure\\.v2:[0-9a-f]{24}$" + }, + "dimension_set_key": { + "type": "string", + "pattern": "^ledger\\.dimension_set\\.v2:[0-9a-f]{24}$" + }, + "universe_constraint_set_key": { + "type": "string", + "pattern": "^ledger\\.universe_constraint_set\\.v2:[0-9a-f]{24}$" + }, + "value": { + "type": [ + "integer", + "number", + "string", + "boolean" + ] + }, + "value_type": { + "enum": [ + "integer", + "number", + "decimal", + "string", + "boolean" + ] + }, + "period": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "description": "Publisher-asserted period kind; the ledger.core.ALLOWED_PERIOD_TYPES vocabulary: calendar_year, tax_year, fiscal_year, academic_year, gas_year, month, quarter, week. Split-label years store the opening year of the publisher's label (UK FY2024-25 -> fiscal_year 2024; AY 2024/25 -> academic_year 2024). gas_year keeps DESNZ's year label: the opening year from 2016 (mid-May 2024 to mid-May 2025 -> gas_year 2024) and the closing year of the October-to-September years to 2015. Publishers labelling a fiscal year with a single year keep that label year (US federal FY2024 -> 2024). Quarter values use YYYY-QN and ISO week values use YYYY-Www, with exact dates in period_coverage." + }, + "value": { + "type": [ + "integer", + "string" + ] + } + } + }, + "geography": { + "type": "object", + "additionalProperties": false, + "required": [ + "level", + "id" + ], + "properties": { + "level": { + "type": "string" + }, + "id": { + "type": "string" + }, + "vintage": { + "type": "string" + }, + "name": { + "$ref": "#/$defs/label", + "description": "The name for this geography: Chronicle's register name where it carries the identifier, otherwise the publisher's own text; absent when neither states a name." + }, + "publisher_name": { + "$ref": "#/$defs/label", + "description": "The publisher's own name for this geography, present only where it differs from the register name carried in 'name'." + } + } + }, + "entity": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "role": { + "type": "string" + } + } + }, + "aggregation": { + "type": "object", + "additionalProperties": false, + "required": [ + "method" + ], + "properties": { + "method": { + "type": "string" + }, + "denominator": { + "type": "string" + } + } + }, + "observed_measure": { + "type": "object", + "additionalProperties": false, + "required": [ + "source_name", + "source_table", + "source_measure_id", + "source_concept", + "unit" + ], + "properties": { + "source_name": { + "type": "string" + }, + "source_table": { + "type": "string" + }, + "source_measure_id": { + "type": "string" + }, + "source_concept": { + "type": "string" + }, + "unit": { + "type": "string" + } + } + }, + "dimensions": { + "type": "object", + "additionalProperties": { + "type": [ + "integer", + "number", + "string", + "boolean" + ] + } + }, + "dimension_labels": { + "type": "object", + "description": "Label for each dimension id: every key of dimensions and, when layout.groupby_dimension is set, that id.", + "additionalProperties": { + "$ref": "#/$defs/label" + } + }, + "dimension_value_labels": { + "type": "object", + "description": "Label for each dimension value, keyed dimension id then value id: the label in Chronicle's register of dimension value labels when it carries the value, otherwise the source package's label. A value id is the value's string form: booleans lower-cased (true, false), integers, numbers and strings as Python str() writes them, lists and mappings JSON-serialised with sorted keys and no spaces. Covers every dimensions entry and, when layout.groupby_dimension is set, layout.groupby_value_id, whose label layout.groupby_value_label repeats.", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/label" + } + } + }, + "package_dimension_value_labels": { + "type": "object", + "description": "The source package's own wording of a dimension value, present only where it differs from the label this row carries for that value: the package row's label, else the package's dimension_value_labels declaration, else the text in the matching column of the parsed source row. This text is not checked against the publisher's file. It may be the publisher's wording (for example a row label that the row's guard compares with a header cell) or text Chronicle wrote (a parser's constant, a value id in an extract Chronicle prepared, or a package author's phrase); the publisher's own cells are reached through lineage.source_cell_keys. Keyed dimension id then value id like dimension_value_labels; the groupby value of a groupby axis that is also a filter with a different value is keyed by layout.groupby_value_id and differs from layout.groupby_value_label.", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/label" + } + } + }, + "universe_constraints": { + "type": "object", + "additionalProperties": false, + "required": [ + "domain" + ], + "properties": { + "domain": { + "type": "string" + }, + "constraints": { + "type": "array", + "items": { + "$ref": "#/$defs/constraint" + } + } + } + }, + "source": { + "type": "object", + "additionalProperties": true, + "required": [ + "source_name", + "source_table", + "source_file", + "vintage", + "extracted_at", + "extraction_method", + "source_sha256", + "source_size_bytes", + "raw_r2_uri" + ], + "properties": { + "source_name": { + "type": "string" + }, + "source_table": { + "type": "string" + }, + "source_file": { + "type": "string" + }, + "url": { + "type": "string" + }, + "vintage": { + "type": "string" + }, + "extracted_at": { + "type": "string" + }, + "extraction_method": { + "type": "string" + }, + "method_notes": { + "type": "string" + }, + "source_sha256": { + "type": "string" + }, + "source_size_bytes": { + "type": "integer" + }, + "raw_r2_bucket": { + "type": "string" + }, + "raw_r2_key": { + "type": "string" + }, + "raw_r2_uri": { + "type": "string" + } + } + }, + "lineage": { + "type": "object", + "additionalProperties": false, + "required": [ + "source_record_id", + "source_cell_keys" + ], + "properties": { + "source_record_id": { + "type": "string" + }, + "source_cell_keys": { + "type": "array", + "items": { + "type": "string" + } + }, + "source_row_keys": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "layout": { + "type": "object", + "additionalProperties": true, + "properties": { + "groupby_dimension_label": { + "$ref": "#/$defs/label", + "description": "Label of layout.groupby_dimension; equals dimension_labels for that id." + } + } + }, + "label": { + "type": "string" + }, + "concept_alignment": { + "type": "object", + "additionalProperties": false, + "required": [ + "concept_alignment_key", + "source_concept", + "canonical_concept", + "relation", + "authority" + ], + "properties": { + "concept_alignment_key": { + "type": "string", + "pattern": "^ledger\\.concept_alignment\\.v2:[0-9a-f]{24}$" + }, + "source_concept": { + "type": "string" + }, + "canonical_concept": { + "type": "string" + }, + "relation": { + "type": "string" + }, + "authority": { + "type": "string" + }, + "evidence_url": { + "type": "string" + }, + "evidence_notes": { + "type": "string" + }, + "legal_vintage": { + "type": "string" + } + } + }, + "assertion": { + "type": "string", + "enum": [ + "observation", + "source_projection" + ], + "description": "Who asserted the value: a publisher-measured outcome (observation) or the publisher's own forward-looking estimate (source_projection). PolicyEngine-computed values are never consumer facts." + }, + "provenance_class": { + "type": "string", + "enum": [ + "administrative", + "census", + "survey_aggregate", + "model_output" + ], + "description": "Publisher measurement basis. Consumers can gate calibration inputs on this required, closed classification." + }, + "survey_instrument": { + "type": "string", + "pattern": ".*\\S.*", + "description": "Survey name required exactly when provenance_class is survey_aggregate." + }, + "period_coverage": { + "type": "object", + "additionalProperties": false, + "description": "Non-identity provenance for the fact's reference period: coverage dates, basis, the publisher's period label, and accounting basis.", + "properties": { + "start_date": { + "type": "string" + }, + "end_date": { + "type": "string" + }, + "basis": { + "type": "string", + "enum": [ + "calendar", + "tax", + "fiscal", + "survey_reference", + "projection_horizon" + ] + }, + "source_period_label": { + "type": "string" + }, + "accounting_basis": { + "type": "string", + "enum": [ + "cash", + "accrual" + ] + }, + "notes": { + "type": "string" + } + } + } + }, + "$defs": { + "label": { + "type": "string", + "pattern": ".*\\S.*" + }, + "constraint": { + "type": "object", + "additionalProperties": false, + "required": [ + "variable", + "operator", + "value", + "role" + ], + "properties": { + "variable": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "value": { + "type": [ + "integer", + "number", + "string", + "boolean" + ] + }, + "unit": { + "type": "string" + }, + "role": { + "type": "string" + } + } + } + } +} diff --git a/scripts/build_dimension_value_register.py b/scripts/build_dimension_value_register.py new file mode 100644 index 00000000..26f9735f --- /dev/null +++ b/scripts/build_dimension_value_register.py @@ -0,0 +1,500 @@ +"""Build and check Chronicle's register of dimension value labels (chronicle#376). + +``chronicle/dimension_values/canonical_labels.json`` gives one label to every +(dimension id, value id) that two or more default-bundle packages emit, and to +every value its packages word more than one way. Each fact a package builds +takes the register's label for a value it lists, so a consumer that merges +packages built for different years sees one label per value. + +The register is Chronicle's display text, not a publisher's file. A value with +one wording keeps it. A value worded more than one way takes the label in +``CHOSEN_LABELS`` below, chosen by the rule in +``docs/agent-source-package-harness.md`` (the wording most packages use, a tie +going to the national statistics office's wording) or by the maintainer. + +Usage: + + # Rebuild every default-bundle package at its build year and rewrite the + # register (slow: every package is built). + uv run python scripts/build_dimension_value_register.py + + # The same, but fail instead of writing when the register differs. + uv run python scripts/build_dimension_value_register.py --check + + # Read already-built packages (directories of /consumer_facts.jsonl, + # as build-suite writes them) instead of building them. + uv run python scripts/build_dimension_value_register.py \\ + --from-consumer-facts BUILDS_DIR [BUILDS_DIR ...] [--check] + + # Compare the register with the package files only, without building: + # every value two packages' files name must be listed, every listed value + # must be named by some package file, and no package may declare a label + # the register contradicts. Runs in CI through + # tests/test_dimension_value_register.py. + uv run python scripts/build_dimension_value_register.py --static-check + +The static check reads groupby rows' value ids, filters and declarations from +each package file compiled at its build year. It cannot see a value a package +only takes from its source rows at build time, so the full ``--check`` is the +complete comparison. +""" + +from __future__ import annotations + +import argparse +import json +import sys +from collections import defaultdict +from collections.abc import Iterable, Mapping +from pathlib import Path +from typing import Any + +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + +from chronicle.dimension_labels import ( # noqa: E402 + REGISTER_DISPLAY_PATH, + REGISTER_PATH, + dimension_value_id, +) + +SCRIPT_DISPLAY_PATH = "scripts/build_dimension_value_register.py" +SCHEMA_VERSION = "chronicle.dimension_value_labels.v1" +#: The Chronicle commit whose package builds the register was generated from. +BUILT_AT_CHRONICLE_COMMIT = "dece5e9" +DEFAULT_BUILD_YEAR = 2023 +#: Default-bundle packages that do not build at DEFAULT_BUILD_YEAR. +BUILD_YEARS = { + "census-acs-s0101-congressional-district-age-2024": 2024, + "census-acs-s0101-national-age-2024": 2024, + "census-acs-s0101-state-age-2024": 2024, + "census-acs-s1501-state-attainment-2024": 2024, + "census-acs-s2201-congressional-district-snap-2024": 2024, + "census-acs5-b01003-county-2024": 2024, + "census-acs5-b11001-county-2024": 2024, + "census-acs5-b19001-county-2024": 2024, + "census-acs5-b19013-county-2024": 2024, + "census-acs5-b19025-county-2024": 2024, + "census-acs5-b19051-county-2024": 2024, + "census-acs5-b19061-county-2024": 2024, + "cms-aca-effectuated-enrollment-2022": 2022, + "cms-aca-oep-state-level": 2024, + "cms-aca-oep-state-level-2022": 2022, + "cms-aca-oep-state-level-2025": 2025, + "ed-fsa-dl-portfolio-by-repayment-plan-fy2026-q3": 2026, + "ed-fsa-portfolio-by-age-fy2026-q2": 2026, + "ed-fsa-portfolio-by-debt-size-fy2026-q2": 2026, + "ed-fsa-portfolio-by-loan-type-fy2026-q3": 2026, + "ed-fsa-portfolio-by-location-fy2026-q2": 2026, + "ed-fsa-portfolio-summary-fy2026-q3": 2026, + "jct-obbba-revenue-estimates-2025": 2026, + "jct-tax-expenditures-2024": 2024, +} + +AGI = "us:statutes/26/62#adjusted_gross_income" +#: The label of each value its packages word more than one way. The three US +#: labels are the maintainer's choice; the other 40 were proposed in +#: chronicle#377 and approved on 2026-10-21, coicop_02 with ONS's overview +#: wording after review. The maintainer chose four more on 2026-10-26, for +#: values the packages merged from main word two ways: freq=A, GSGB's +#: national_lottery_draws_in_person, income_range=all and +#: salary_sacrifice_threshold_position=all. +CHOSEN_LABELS: dict[tuple[str, str], str] = { + (AGI, "under_1"): "No adjusted gross income", + (AGI, "all"): "All returns, total", + ("age", "85_plus"): "Age 85 plus", + ("age", "age_20"): "Age 20", + ("age", "age_21"): "Age 21", + ("age", "age_25_to_29"): "Age 25 to 29", + ("age", "age_30_to_34"): "Age 30 to 34", + ("age", "age_35_to_39"): "Age 35 to 39", + ("age", "age_40_to_44"): "Age 40 to 44", + ("age_band", "30 to 39"): "30 to 39", + ("age_band", "40 to 49"): "40 to 49", + ( + "early_year_award_line", + "new_returning_total_returning_31_33_35", + ): "Total returning [31][33][35]", + # Eurostat's exchange-rate dataset's JSON-stat category label; the older + # Eurostat packages carry the bare code "A". + ("freq", "A"): "Annual", + # B.10's wording; B.9 writes "Tickets National Lottery draws bought in + # person" for the same row. + ( + "gambling_commission.gsgb_activity", + "national_lottery_draws_in_person", + ): "Tickets for National Lottery draws bought in person", + ("groeipakket.component", "pleegzorgtoeslag"): "Foster care supplement", + ("groeipakket.component", "sociale_toeslag"): "Social supplement", + ("groeipakket.component", "wezentoeslag"): "Orphan supplement", + ("groeipakket.component", "zorgtoeslag"): "Care supplement", + ( + "household_type", + "couple_3_plus_children_households", + ): "3 or more dependent children", + ( + "ons.household_type", + "couple_3_plus_children_households", + ): "3 or more dependent children", + # The IRS SOI packages' wording; Census B19001 writes "Total". + ("income_range", "all"): "All income ranges", + ("measure", "country_total"): "Country total", + ( + "na_item", + "belgium_household_disposable_income_gross", + ): "Disposable income, gross (B.6G)", + ("na_item", "belgium_household_mixed_income_gross"): "Mixed income, gross (B.3G)", + ( + "na_item", + "belgium_household_operating_surplus_gross", + ): "Operating surplus, gross (B.2G)", + # ONS's detailed-worksheet wording without its footnote marker, except + # where noted. + ("ons.coicop", "coicop_01"): "Food and non-alcoholic beverages", + # ONS's overview (0CN) wording: the total, CDID ADFL, includes narcotics + # (ADFL = ADFM + ADFN + MNC2), which the 02CN column header leaves out. + ("ons.coicop", "coicop_02"): "Alcohol, tobacco and narcotics", + ("ons.coicop", "coicop_04"): "Housing, water, electricity, gas and other fuel", + # The overview (0CN) wording; 05CN abbreviates it. + ( + "ons.coicop", + "coicop_05", + ): "Furnishings, household equipment and routine maintenance of the house", + # The overview (0CN) wording; 11CN writes "Restaurant and hotels". + ("ons.coicop", "coicop_11"): "Restaurants and hotels", + ("ons.coicop", "coicop_12"): "Miscellaneous goods and services", + ("person.age_band", "65_plus"): "65+", + ("property_type", "detached"): "Detached", + ("property_type", "semi_detached"): "Semi detached", + ("property_type", "terraced"): "Terraced", + ("quant_inc", "d1"): "First income decile", + ("quant_inc", "d2"): "Second income decile", + ("quant_inc", "d3"): "Third income decile", + ("quant_inc", "d4"): "Fourth income decile", + ("quant_inc", "d5"): "Fifth income decile", + ("quant_inc", "d6"): "Sixth income decile", + ("quant_inc", "d7"): "Seventh income decile", + ("quant_inc", "d8"): "Eighth income decile", + ("quant_inc", "d9"): "Ninth income decile", + # Chronicle's own wording. HMRC's salary sacrifice package words this value + # "Employees using salary sacrifice to make pension contributions" and + # "National Insurance contributions forgone through salary sacrifice for + # pensions": each names the measure, not the threshold position. + ("salary_sacrifice_threshold_position", "all"): "All threshold positions", + ("sex", "female"): "Female", + ("sex", "male"): "Male", +} + +DESCRIPTION = ( + "One label per dimension value (chronicle#376). Every fact built from a " + "source package carries the label listed here for a value in " + "dimension_value_labels and, for its groupby value, " + "layout.groupby_value_label; the package's own wording, where it differs, " + "is kept in package_dimension_value_labels. A value enters this register " + "when two or more packages emit it or when its packages word it more than " + "one way. These are Chronicle's display labels, not a publisher's file: a " + "value with one wording keeps it, and a value worded more than one way " + "takes the label chosen in scripts/build_dimension_value_register.py. A " + "package may not declare a different label for a listed value. A value no " + "entry covers takes its package's label, and build-bundle refuses it if " + "two packages label it differently." +) + +ValueKey = tuple[str, str] +#: (dimension id, value id) -> wording -> package id -> fact count. +Wordings = dict[ValueKey, dict[str, dict[str, int]]] + + +def build_year(package_id: str) -> int: + """Return the year the register builds *package_id* at.""" + + return BUILD_YEARS.get(package_id, DEFAULT_BUILD_YEAR) + + +def wordings_by_value( + rows_by_package: Mapping[str, Iterable[Mapping[str, Any]]], +) -> Wordings: + """Count each package's own wording of each value in its consumer rows. + + A row built before the register carries its package's wording as the + label; a row built after carries the register's label, with the package's + wording in ``package_dimension_value_labels`` where it differs. A value id + equal to the row's geography id names the area, not a dimension value. + """ + + found: Wordings = defaultdict(lambda: defaultdict(lambda: defaultdict(int))) + for package_id, rows in rows_by_package.items(): + for row in rows: + geography_id = str((row.get("geography") or {}).get("id") or "").casefold() + package_wording = row.get("package_dimension_value_labels") or {} + seen: set[tuple[str, str, str]] = set() + for dimension_id, value_labels in ( + row.get("dimension_value_labels") or {} + ).items(): + for value_id, label in value_labels.items(): + wording = (package_wording.get(dimension_id) or {}).get( + value_id, label + ) + seen.add((dimension_id, str(value_id), str(wording).strip())) + layout = row.get("layout") or {} + groupby = layout.get("groupby_dimension") + if groupby and layout.get("groupby_value_id") is not None: + value_id = dimension_value_id(layout["groupby_value_id"]) + wording = (package_wording.get(groupby) or {}).get( + value_id, layout.get("groupby_value_label") or "" + ) + seen.add((groupby, value_id, str(wording).strip())) + for dimension_id, value_id, wording in seen: + if not wording or value_id.casefold() == geography_id: + continue + found[(dimension_id, value_id)][wording][package_id] += 1 + return { + key: {wording: dict(packages) for wording, packages in wordings.items()} + for key, wordings in found.items() + } + + +def register_labels( + wordings: Wordings, + *, + chosen: Mapping[ValueKey, str] = CHOSEN_LABELS, +) -> dict[str, dict[str, str]]: + """Return the register's labels for the package wordings counted.""" + + labels: dict[str, dict[str, str]] = defaultdict(dict) + unresolved = [] + for (dimension_id, value_id), by_wording in sorted(wordings.items()): + packages = {package for counts in by_wording.values() for package in counts} + if len(packages) < 2 and len(by_wording) < 2: + continue + if (dimension_id, value_id) in chosen: + label = chosen[(dimension_id, value_id)] + elif len(by_wording) == 1: + label = next(iter(by_wording)) + else: + unresolved.append(f"{dimension_id}={value_id}: {sorted(by_wording)}") + continue + labels[dimension_id][value_id] = label + if unresolved: + raise SystemExit( + "Values worded more than one way need a label in CHOSEN_LABELS " + f"({SCRIPT_DISPLAY_PATH}), chosen by the rule in " + "docs/agent-source-package-harness.md:\n " + "\n ".join(unresolved) + ) + return { + dimension_id: dict(sorted(values.items())) + for dimension_id, values in sorted(labels.items()) + } + + +def register_payload(labels: Mapping[str, Mapping[str, str]]) -> dict[str, Any]: + """Return the register file's content for *labels*.""" + + return { + "schema_version": SCHEMA_VERSION, + "description": DESCRIPTION, + "sources": { + "script": SCRIPT_DISPLAY_PATH, + "packages": "chronicle.bundle.DEFAULT_BUNDLE_SOURCES", + "built_at_chronicle_commit": BUILT_AT_CHRONICLE_COMMIT, + "default_build_year": DEFAULT_BUILD_YEAR, + "build_years": dict(sorted(BUILD_YEARS.items())), + "chosen_labels": sorted( + f"{dimension_id}={value_id}" for dimension_id, value_id in CHOSEN_LABELS + ), + }, + "labels": { + dimension_id: dict(sorted(values.items())) + for dimension_id, values in sorted(labels.items()) + }, + } + + +def register_text(labels: Mapping[str, Mapping[str, str]]) -> str: + return json.dumps(register_payload(labels), indent=2, ensure_ascii=False) + "\n" + + +def _stored_rows(builds_dirs: Iterable[Path]) -> dict[str, list[dict[str, Any]]]: + rows_by_package: dict[str, list[dict[str, Any]]] = {} + for builds_dir in builds_dirs: + for package_dir in sorted(Path(builds_dir).iterdir()): + facts_path = package_dir / "consumer_facts.jsonl" + if not facts_path.is_file(): + continue + with facts_path.open(encoding="utf-8") as stream: + rows_by_package[package_dir.name] = [ + json.loads(line) for line in stream if line.strip() + ] + return rows_by_package + + +def _built_rows() -> dict[str, list[dict[str, Any]]]: + from chronicle.bundle import DEFAULT_BUNDLE_SOURCES + from chronicle.consumer_contract import consumer_fact_rows + from chronicle.source_package import load_source_package + + rows_by_package = {} + for source in DEFAULT_BUNDLE_SOURCES: + package = load_source_package(source) + year = build_year(package.package_id) + facts = package.build_facts(year, cells=package.build_source_cells(year)) + rows_by_package[package.package_id] = consumer_fact_rows(facts) + print(f"built {package.package_id} at {year}", file=sys.stderr) + return rows_by_package + + +# The static check: package files only. + + +def static_package_values() -> tuple[ + dict[ValueKey, set[str]], dict[tuple[str, str, str], str] +]: + """Return the values each package file names, and its declarations. + + Each default-bundle package is compiled at its build year without reading + its source file. A value is a groupby row's value id or a filter value + (record set, row or measure), skipping a value equal to the row's + geography id; declarations are the package's ``dimension_value_labels``. + """ + + from chronicle.bundle import DEFAULT_BUNDLE_SOURCES + from chronicle.source_package import load_source_package + + emitters: dict[ValueKey, set[str]] = defaultdict(set) + declarations: dict[tuple[str, str, str], str] = {} + for source in DEFAULT_BUNDLE_SOURCES: + package = load_source_package(source) + package_id = package.package_id + record_sets = package._compile_record_set_specs(build_year(package_id)) + for record_set in record_sets: + groupby = (record_set.groupby_dimension or "").strip() + for row in record_set.rows: + geography_id = str( + row.geography_id or record_set.geography_id or "" + ).casefold() + named = [] + if groupby and row.value_id is not None: + named.append((groupby, row.value_id)) + named.extend((record_set.shared_filters or {}).items()) + named.extend((row.filters or {}).items()) + for measure in record_set.measures: + named.extend((measure.filters or {}).items()) + for dimension_id, value in named: + if value is None: + continue + value_id = dimension_value_id(value) + if value_id.casefold() == geography_id: + continue + emitters[(str(dimension_id), value_id)].add(package_id) + for dimension_id, value_labels in ( + package.dimension_value_labels or {} + ).items(): + for value_id, label in (value_labels or {}).items(): + emitters[(str(dimension_id), str(value_id))].add(package_id) + declarations[(package_id, str(dimension_id), str(value_id))] = str( + label + ).strip() + return dict(emitters), declarations + + +def register_problems( + *, + register: Mapping[str, Mapping[str, str]], + emitters: Mapping[ValueKey, set[str]], + declarations: Mapping[tuple[str, str, str], str], +) -> list[str]: + """Compare the register with the values and declarations package files name.""" + + listed = { + (dimension_id, value_id) + for dimension_id, values in register.items() + for value_id in values + } + problems = [] + for (dimension_id, value_id), packages in sorted(emitters.items()): + if len(packages) >= 2 and (dimension_id, value_id) not in listed: + problems.append( + f"{dimension_id}={value_id} is emitted by {len(packages)} packages " + f"({', '.join(sorted(packages))}) but the register does not list " + f"it; add it to {REGISTER_DISPLAY_PATH} with one label." + ) + for dimension_id, value_id in sorted(listed - set(emitters)): + problems.append( + f"{dimension_id}={value_id} is in the register but no package emits " + f"it; remove it from {REGISTER_DISPLAY_PATH}." + ) + for (package_id, dimension_id, value_id), declared in sorted(declarations.items()): + canonical = register.get(dimension_id, {}).get(value_id) + if canonical is not None and declared != canonical: + problems.append( + f"{package_id} declares dimension_value_labels.{dimension_id}." + f"{value_id} {declared!r}, but the register labels it " + f"{canonical!r}; change the declaration to {canonical!r}." + ) + return problems + + +def committed_register() -> dict[str, dict[str, str]]: + return json.loads(REGISTER_PATH.read_text(encoding="utf-8"))["labels"] + + +def static_check_problems() -> list[str]: + """Run the static check against the committed register.""" + + emitters, declarations = static_package_values() + return register_problems( + register=committed_register(), + emitters=emitters, + declarations=declarations, + ) + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser(description=__doc__.split("\n\n", 1)[0]) + parser.add_argument("--check", action="store_true") + parser.add_argument("--static-check", action="store_true") + parser.add_argument("--from-consumer-facts", nargs="+", type=Path) + parser.add_argument("--output", type=Path, default=REGISTER_PATH) + arguments = parser.parse_args(argv) + + if arguments.static_check: + problems = static_check_problems() + for problem in problems: + print(problem, file=sys.stderr) + print( + f"static check: {len(problems)} problem(s) in {REGISTER_DISPLAY_PATH}", + file=sys.stderr, + ) + return 1 if problems else 0 + + rows_by_package = ( + _stored_rows(arguments.from_consumer_facts) + if arguments.from_consumer_facts + else _built_rows() + ) + text = register_text(register_labels(wordings_by_value(rows_by_package))) + if arguments.check: + current = REGISTER_PATH.read_text(encoding="utf-8") + if current != text: + print( + f"{REGISTER_DISPLAY_PATH} differs from the register the packages " + f"give; rerun {SCRIPT_DISPLAY_PATH} without --check and review " + "the change.", + file=sys.stderr, + ) + return 1 + print(f"{REGISTER_DISPLAY_PATH} matches the packages.", file=sys.stderr) + return 0 + arguments.output.write_text(text, encoding="utf-8") + labels = json.loads(text)["labels"] + print( + f"wrote {sum(len(values) for values in labels.values())} values in " + f"{len(labels)} dimensions to {arguments.output}", + file=sys.stderr, + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/build_uk_excise_packages.py b/scripts/build_uk_excise_packages.py index 0175e1d3..a4ebb368 100644 --- a/scripts/build_uk_excise_packages.py +++ b/scripts/build_uk_excise_packages.py @@ -3668,8 +3668,9 @@ def build_gambling_commission() -> None: ), ] # Row labels are each table's own text (whitespace collapsed, footnote marker dropped), -# so B.9 row 6's wording differs from B.10's and the bundle reports that row's two -# labels as a groupby-label warning, as it does for any label kept as published. +# so B.9 row 6's wording differs from B.10's. Chronicle's label register gives the +# value B.10's wording, and B.9's facts keep their row's text as the package's wording +# (chronicle#376). GSGB_ACTIVITY_VARIANTS = { "Tickets National Lottery draws bought in person": ( "Tickets for National Lottery draws bought in person" diff --git a/tests/test_chronicle_bundle.py b/tests/test_chronicle_bundle.py index 91781067..47707b83 100644 --- a/tests/test_chronicle_bundle.py +++ b/tests/test_chronicle_bundle.py @@ -627,7 +627,13 @@ def test_build_bundle_writes_merged_consumer_contract(tmp_path): # prints it, where the older Eurostat packages carry the bare code 'A'. # GSGB 2025 adds one: B.9 writes "Tickets National Lottery draws bought in # person" where B.10 writes "Tickets for ...", both kept as published. - "warning_count": 133, + # chronicle#376 removes 41: every dimension value two packages emit + # takes its label from chronicle/dimension_values/canonical_labels.json, + # so the 17 values two packages labelled differently and the 24 values + # one package's rows labelled two ways now carry one label each (freq=A + # 'Annual', and B.10's wording for GSGB's row), and a value labelled + # two ways is an error rather than a warning. + "warning_count": 92, } row_count = 0 provenance_classes = set() @@ -2484,8 +2490,6 @@ def test_build_bundle_writes_merged_consumer_contract(tmp_path): assert len(coverage["duplicates"]["semantic_fact_keys"]) == 2324 assert Counter(warning["code"] for warning in summary["warnings"]) == { "conflicting_geography_name_across_packages": 91, - "conflicting_groupby_value_label": 24, - "conflicting_value_label_across_packages": 17, "duplicate_semantic_fact_key": 1, } assert [ @@ -2525,29 +2529,19 @@ def test_build_bundle_writes_merged_consumer_contract(tmp_path): for warning in geography_names if warning["key"].startswith("local_authority:") ) == ["local_authority:nz-ta-018", "local_authority:nz-ta-027"] - assert sorted( - warning["key"] - for warning in summary["warnings"] - if warning["code"] == "conflicting_value_label_across_packages" - ) == [ - "age=85_plus", - "age=age_20", - "age=age_21", - "age_band=30 to 39", - "age_band=40 to 49", - "freq=A", - "household_type=couple_3_plus_children_households", - "measure=country_total", - "ons.household_type=couple_3_plus_children_households", - "person.age_band=65_plus", - "property_type=detached", - "property_type=semi_detached", - "property_type=terraced", - "sex=female", - "sex=male", - "us:statutes/26/62#adjusted_gross_income=all", - "us:statutes/26/62#adjusted_gross_income=under_1", - ] + # One label per dimension value (chronicle#376): nothing about value labels + # is left as a warning, and the bundle reports no value label error. + assert [ + issue["key"] + for issue in (*summary["errors"], *summary["warnings"]) + if issue["code"] + in { + "conflicting_value_label", + "conflicting_value_label_across_packages", + "conflicting_groupby_value_label", + "conflicting_dimension_value_label", + } + ] == [] # E12000003 is the case chronicle#281 was opened on: six packages wrote # "Yorkshire and The Humber" and five "Yorkshire and the Humber". The # register carries the identifier, so the export names it once and the diff --git a/tests/test_chronicle_consumer.py b/tests/test_chronicle_consumer.py index fc4cecac..3ae89044 100644 --- a/tests/test_chronicle_consumer.py +++ b/tests/test_chronicle_consumer.py @@ -131,7 +131,7 @@ def test_artifact_build_load_round_trip_is_facts_only(tmp_path): } assert manifest == { "schema_version": "policyengine_ledger.consumer_artifact.v2", - "consumer_fact_schema_versions": ["chronicle.consumer_fact.v4"], + "consumer_fact_schema_versions": ["chronicle.consumer_fact.v5"], "consumer_fact_schema_sha256": CONSUMER_FACT_SCHEMA_SHA256, "fact_row_count": 2, "facts_sha256": hashlib.sha256( @@ -140,7 +140,7 @@ def test_artifact_build_load_round_trip_is_facts_only(tmp_path): } assert ( CONSUMER_FACT_SCHEMA_SHA256 - == (CONSUMER_FACT_SCHEMA_SHA256_BY_VERSION["chronicle.consumer_fact.v4"]) + == (CONSUMER_FACT_SCHEMA_SHA256_BY_VERSION["chronicle.consumer_fact.v5"]) ) assert {path.name for path in out_dir.iterdir()} == { "consumer_facts.jsonl", @@ -258,14 +258,14 @@ def test_mixed_epoch_rows_are_emitted_ledger_keyed_in_one_artifact(tmp_path): artifact = load_consumer_artifact(out_dir) assert artifact.manifest["consumer_fact_schema_versions"] == [ - "chronicle.consumer_fact.v4" + "chronicle.consumer_fact.v5" ] assert len(artifact.rows) == 2 validator = Draft202012Validator(consumer_fact_schema()) for line in (out_dir / "consumer_facts.jsonl").read_text().splitlines(): row = json.loads(line) validator.validate(row) - assert row["schema_version"] == "chronicle.consumer_fact.v4" + assert row["schema_version"] == "chronicle.consumer_fact.v5" for field_name in _KEY_FIELDS: assert row[field_name].startswith("ledger.") assert all( @@ -400,6 +400,7 @@ def test_artifact_load_unknown_row_schema_names_both_accepted_forms(tmp_path): assert "chronicle.consumer_fact.v2" in message assert "chronicle.consumer_fact.v3" in message assert "chronicle.consumer_fact.v4" in message + assert "chronicle.consumer_fact.v5" in message def test_artifact_load_rejects_declared_row_schema_drift(tmp_path): diff --git a/tests/test_chronicle_consumer_contract.py b/tests/test_chronicle_consumer_contract.py index ba47ffe3..7943746a 100644 --- a/tests/test_chronicle_consumer_contract.py +++ b/tests/test_chronicle_consumer_contract.py @@ -44,7 +44,7 @@ ) CONSUMER_FACT_SCHEMA_PATH = ( - Path(__file__).parents[1] / "docs" / "schemas" / "consumer_fact.v4.schema.json" + Path(__file__).parents[1] / "docs" / "schemas" / "consumer_fact.v5.schema.json" ) CONSUMER_FACT_SAMPLE_PATH = ( Path(__file__).parents[1] / "chronicle" / "fixtures" / "consumer_facts.jsonl" @@ -331,7 +331,7 @@ def test_write_consumer_facts_jsonl_accepts_the_ledger_epoch_string(tmp_path): [_soi_agi_fact()], facts_path, emit_epoch="ledger" ) - assert report.schema_version == "chronicle.consumer_fact.v4" + assert report.schema_version == "chronicle.consumer_fact.v5" assert facts_path.exists() diff --git a/tests/test_chronicle_core.py b/tests/test_chronicle_core.py index 6d3fc6f9..53692820 100644 --- a/tests/test_chronicle_core.py +++ b/tests/test_chronicle_core.py @@ -470,11 +470,13 @@ def test_frozen_fixture_bytes_are_unchanged(): # chronicle#266 re-pinned this from cc18841e… when the rows began # carrying the publisher's geography name, chronicle#265 again # because the sample's own package now declares its dimension - # labels, and chronicle#281 again for the v4 contract. Only the - # schema_version moved that last time: the three rows are IRS SOI - # and the geography register is UK-only. The keys and values in - # them are unchanged throughout. - "d02308d049edcd0e60b29d590211456c6427a505e1acf50f1ae71bbcd2962a8c" + # labels, chronicle#281 again for the v4 contract, and chronicle#376 + # for v5: Table 1.1's "All returns" row now exports the register's + # "All returns, total" and keeps the package's row label in + # package_dimension_value_labels (a name chronicle#377's review + # gave the field). The keys and values in them are unchanged + # throughout. + "450a22c689b7a086cfc03522aa4492d491efc6875a4661dbd851a2015506897a" ), fixture_root / "source_cells" / "soi_table_1_1_2023_cells.jsonl": ( "615639f21ee63e54595c677e24c3eddff484c00a795a2f91b45a8575f021c7e2" diff --git a/tests/test_chronicle_uk_national_2025.py b/tests/test_chronicle_uk_national_2025.py index 1989d86a..6cf0903b 100644 --- a/tests/test_chronicle_uk_national_2025.py +++ b/tests/test_chronicle_uk_national_2025.py @@ -224,21 +224,30 @@ def test_slc_returning_support_keeps_both_publisher_footnote_spellings(facts_for line = "new_returning_total_returning_31_33_35" returning = {f.aggregation.method: f for f in facts if f.filters[axis] == line} # Table 7C(ii)!B75 and B111 contain different literal footnote spellings. - labels = { + # Both facts carry the one label Chronicle's register gives the value, and + # the row whose spelling differs keeps it as the package's own wording + # (chronicle#376). + publisher_spellings = { "sum": "Total returning [31][33][35]", "mean": "Total returning [31[[33][35]", } - assert set(returning) == set(labels) - for method, label in labels.items(): + assert set(returning) == set(publisher_spellings) + for method, spelling in publisher_spellings.items(): fact = returning[method] - assert fact.layout.groupby_value_label == label - assert fact.dimension_value_labels[axis][line] == label + assert fact.layout.groupby_value_label == "Total returning [31][33][35]" + assert fact.dimension_value_labels[axis][line] == ( + "Total returning [31][33][35]" + ) + assert ( + fact.package_dimension_value_labels.get(axis, {}).get( + line, "Total returning [31][33][35]" + ) + == spelling + ) errors, warnings = _dimension_label_reports(alias, consumer_fact_rows(facts)) assert not errors, [error.to_dict() for error in errors] - assert [(warning.code, warning.key) for warning in warnings] == [ - ("conflicting_groupby_value_label", f"{axis}={line}") - ] + assert warnings == [] def test_public_sector_employment_keeps_four_published_quarters(facts_for): diff --git a/tests/test_dimension_value_register.py b/tests/test_dimension_value_register.py new file mode 100644 index 00000000..fbe67461 --- /dev/null +++ b/tests/test_dimension_value_register.py @@ -0,0 +1,173 @@ +"""The script that builds and checks Chronicle's dimension value register. + +``chronicle/dimension_values/canonical_labels.json`` gives one label to every +dimension value two or more packages emit, and to every value its packages +word more than one way (chronicle#376). The chronicle#377 reviews found that +the script which generated it was not committed and that nothing checked the +register against the packages, so a value two packages start sharing could +reach a feed with two labels. ``scripts/build_dimension_value_register.py`` +regenerates the register from built packages, and its ``--static-check`` reads +only the package files: every value two packages' files name must be listed, +every listed value must be named by some package file, and no package may +declare a label that differs from the register's. +""" + +from __future__ import annotations + +import importlib +import json +import sys +from pathlib import Path + +import pytest + +ROOT = Path(__file__).resolve().parents[1] +_REGISTER = ROOT / "chronicle" / "dimension_values" / "canonical_labels.json" + + +def _script(): + scripts = str(ROOT / "scripts") + if scripts not in sys.path: + sys.path.insert(0, scripts) + return importlib.import_module("build_dimension_value_register") + + +def test_the_static_check_passes_on_the_repository(): + assert _script().static_check_problems() == [] + + +def test_the_static_check_reports_a_shared_value_the_register_does_not_list(): + problems = _script().register_problems( + register={"sex": {"female": "Female"}}, + emitters={ + ("sex", "female"): {"ons-a", "nrs-b"}, + ("filing_status", "single"): {"soi-a", "soi-b"}, + }, + declarations={}, + ) + + assert problems == [ + "filing_status=single is emitted by 2 packages (soi-a, soi-b) but the " + "register does not list it; add it to " + "chronicle/dimension_values/canonical_labels.json with one label." + ] + + +def test_the_static_check_reports_a_listed_value_no_package_emits(): + problems = _script().register_problems( + register={"sex": {"female": "Female", "unknown": "Unknown"}}, + emitters={("sex", "female"): {"ons-a", "nrs-b"}}, + declarations={}, + ) + + assert problems == [ + "sex=unknown is in the register but no package emits it; remove it " + "from chronicle/dimension_values/canonical_labels.json." + ] + + +def test_the_static_check_reports_a_declaration_the_register_contradicts(): + problems = _script().register_problems( + register={"sex": {"female": "Female"}}, + emitters={("sex", "female"): {"ons-a", "nrs-b"}}, + declarations={("nrs-b", "sex", "female"): "Females"}, + ) + + assert problems == [ + "nrs-b declares dimension_value_labels.sex.female 'Females', but the " + "register labels it 'Female'; change the declaration to 'Female'." + ] + + +def test_the_register_is_built_from_each_packages_own_wording(): + script = _script() + rows_by_package = { + "pkg-a": [ + { + "geography": {"id": "UK"}, + "dimension_value_labels": {"sex": {"female": "Female"}}, + "layout": {}, + } + ], + "pkg-b": [ + { + "geography": {"id": "UK"}, + # Built after the register: the label is the register's, the + # package's wording is kept beside it. + "dimension_value_labels": {"sex": {"female": "Female"}}, + "package_dimension_value_labels": {"sex": {"female": "Females"}}, + "layout": {}, + }, + { + "geography": {"id": "UK"}, + "dimension_value_labels": {"region": {"uk": "UK"}}, + "layout": { + "groupby_dimension": "line", + "groupby_value_id": "total", + "groupby_value_label": "Total", + }, + }, + ], + } + + wordings = script.wordings_by_value(rows_by_package) + labels = script.register_labels(wordings, chosen={("sex", "female"): "Female"}) + + assert wordings[("sex", "female")] == { + "Female": {"pkg-a": 1}, + "Females": {"pkg-b": 1}, + } + # The region value equals the row's geography id, so it is not a value. + assert ("region", "uk") not in wordings + assert labels == {"sex": {"female": "Female"}} + with pytest.raises(SystemExit, match="sex=female"): + script.register_labels(wordings, chosen={}) + + +def test_the_chosen_labels_are_the_registers_labels(): + script = _script() + register = json.loads(_REGISTER.read_text(encoding="utf-8"))["labels"] + + assert len(script.CHOSEN_LABELS) == 47 + for (dimension_id, value_id), label in script.CHOSEN_LABELS.items(): + assert register[dimension_id][value_id] == label + + +def test_the_register_records_what_it_was_built_from(): + payload = json.loads(_REGISTER.read_text(encoding="utf-8")) + sources = payload["sources"] + + assert sources["script"] == "scripts/build_dimension_value_register.py" + assert sources["packages"] == "chronicle.bundle.DEFAULT_BUNDLE_SOURCES" + assert sources["built_at_chronicle_commit"].startswith("dece5e9") + assert sources["default_build_year"] == 2023 + assert sources["build_years"] == { + "census-acs-s0101-congressional-district-age-2024": 2024, + "census-acs-s0101-national-age-2024": 2024, + "census-acs-s0101-state-age-2024": 2024, + "census-acs-s1501-state-attainment-2024": 2024, + "census-acs-s2201-congressional-district-snap-2024": 2024, + "census-acs5-b01003-county-2024": 2024, + "census-acs5-b11001-county-2024": 2024, + "census-acs5-b19001-county-2024": 2024, + "census-acs5-b19013-county-2024": 2024, + "census-acs5-b19025-county-2024": 2024, + "census-acs5-b19051-county-2024": 2024, + "census-acs5-b19061-county-2024": 2024, + "cms-aca-effectuated-enrollment-2022": 2022, + "cms-aca-oep-state-level": 2024, + "cms-aca-oep-state-level-2022": 2022, + "cms-aca-oep-state-level-2025": 2025, + "ed-fsa-dl-portfolio-by-repayment-plan-fy2026-q3": 2026, + "ed-fsa-portfolio-by-age-fy2026-q2": 2026, + "ed-fsa-portfolio-by-debt-size-fy2026-q2": 2026, + "ed-fsa-portfolio-by-loan-type-fy2026-q3": 2026, + "ed-fsa-portfolio-by-location-fy2026-q2": 2026, + "ed-fsa-portfolio-summary-fy2026-q3": 2026, + "jct-obbba-revenue-estimates-2025": 2026, + "jct-tax-expenditures-2024": 2024, + } + assert sorted(sources["chosen_labels"]) == sorted( + f"{dimension_id}={value_id}" + for dimension_id, value_id in _script().CHOSEN_LABELS + ) diff --git a/tests/test_etl_eurostat.py b/tests/test_etl_eurostat.py index 2c46fa89..569950a0 100644 --- a/tests/test_etl_eurostat.py +++ b/tests/test_etl_eurostat.py @@ -62,7 +62,28 @@ # constraints happened to carry. With the three label fields stripped, these # facts still hash to the pre-label 9db298bc... and 51768608... : only the # labels moved. +# chronicle#376 adds AggregateFact.package_dimension_value_labels. It is an +# empty mapping on every fact of these two packages; with that key removed, +# the facts still hash to the digests before it (below): only the empty +# field moved. PRIOR_VINTAGE_FACT_DIGESTS = { + "eurostat-gov-10a-taxag": ( + "c2e3256a6550d6864c60843591c2c5755d816aa23b97aeea8b051b6ac5b8d39a" + ), + "eurostat-spr-exp-func": ( + "f9a785e52cd2c1df0e3e97828da34a3a15348f7bc89d106e948eccff11e53d61" + ), +} +#: The digests before freq=A took the register's label "Annual" (chronicle#376). +FACT_DIGESTS_BEFORE_ANNUAL = { + "eurostat-gov-10a-taxag": ( + "516a28c598db59fa4aafd0abef2fd3339a22495e3f2143a0b137e7290672f9d5" + ), + "eurostat-spr-exp-func": ( + "e0231b789fb8142751a78aeeac09548f3dd6dba86d2031abf160b8fe63cd101b" + ), +} +FACT_DIGESTS_BEFORE_PACKAGE_WORDING = { "eurostat-gov-10a-taxag": ( "89b50ea09e046680f1acd6f3a5e7778a249a0e671a31dfe74b5245a12c31fb8a" ), @@ -421,16 +442,35 @@ def test_eurostat_production_values_match_publisher_bytes(): assert isinstance(be_disability[0].value, int) +def _fact_payload_digest(fact_payloads): + return hashlib.sha256( + json.dumps(fact_payloads, sort_keys=True, separators=(",", ":")).encode() + ).hexdigest() + + @pytest.mark.parametrize("alias", PRIOR_VINTAGE_FACT_DIGESTS) def test_eurostat_prior_vintage_facts_remain_byte_stable(alias): - facts = _package_outputs(alias)[3] - canonical = json.dumps( - [asdict(fact) for fact in facts], - sort_keys=True, - separators=(",", ":"), - ).encode() - - assert hashlib.sha256(canonical).hexdigest() == PRIOR_VINTAGE_FACT_DIGESTS[alias] + fact_payloads = [asdict(fact) for fact in _package_outputs(alias)[3]] + + assert _fact_payload_digest(fact_payloads) == PRIOR_VINTAGE_FACT_DIGESTS[alias] + # Only labels moved the bytes (chronicle#376). Every fact's freq=A takes the + # register's "Annual", with the package's own "A" beside it. + assert all( + payload["dimension_value_labels"]["freq"] == {"A": "Annual"} + and payload["package_dimension_value_labels"] == {"freq": {"A": "A"}} + for payload in fact_payloads + ) + for payload in fact_payloads: + payload["dimension_value_labels"]["freq"] = {"A": "A"} + payload["package_dimension_value_labels"] = {} + assert _fact_payload_digest(fact_payloads) == FACT_DIGESTS_BEFORE_ANNUAL[alias] + # Before that, only the new, empty package-wording field had moved them. + for payload in fact_payloads: + del payload["package_dimension_value_labels"] + assert ( + _fact_payload_digest(fact_payloads) + == FACT_DIGESTS_BEFORE_PACKAGE_WORDING[alias] + ) def test_eurostat_2025_tax_vintage_adds_only_new_coordinates(): diff --git a/tests/test_issue_261_dimension_labels.py b/tests/test_issue_261_dimension_labels.py index 5e17fd93..3666d05b 100644 --- a/tests/test_issue_261_dimension_labels.py +++ b/tests/test_issue_261_dimension_labels.py @@ -242,22 +242,24 @@ def test_constraint_labels_that_disagree_label_nothing(): def test_the_groupby_row_label_labels_a_filter_on_the_same_axis(): + # A value Chronicle's register does not list (chronicle#376), so the row + # label is its label. [labelled] = label_facts( [ _fact( { - "household_income_band": "gbp15_000_gbp19_999", - "region": "gbp15_000_gbp19_999", + "household_income_band": "gbp15_000_gbp19_998", + "region": "gbp15_000_gbp19_998", }, groupby="desnz.need.household_income_band", - value_id="gbp15_000_gbp19_999", - value_label="£15,000 to £19,999 ", + value_id="gbp15_000_gbp19_998", + value_label="£15,000 to £19,998 ", ) ] ) assert labelled.dimension_value_labels["household_income_band"] == { - "gbp15_000_gbp19_999": "£15,000 to £19,999" + "gbp15_000_gbp19_998": "£15,000 to £19,998" } assert "region" not in labelled.dimension_value_labels @@ -328,7 +330,7 @@ def test_labels_never_move_a_fact_key_or_value(): **plain["layout"], "groupby_dimension_label": "Carer Entitlement", } - assert rich["schema_version"] == "chronicle.consumer_fact.v4" + assert rich["schema_version"] == "chronicle.consumer_fact.v5" validate_consumer_fact_row(rich, 1, "labelled.jsonl") @@ -430,12 +432,15 @@ def test_bundle_requires_labels_for_uk_packages_only(): UK_BUNDLE_SOURCES[0], [unlabelled, _row(), drifting] ) + # Row labels that drift across one groupby value are refused too: a value + # carries one label (chronicle#376). assert {error.code for error in errors} == { "missing_dimension_label", "missing_dimension_value_label", + "conflicting_groupby_value_label", } - assert [warning.code for warning in warnings] == ["conflicting_groupby_value_label"] - assert all(issue.source == UK_BUNDLE_SOURCES[0] for issue in errors + warnings) + assert warnings == [] + assert all(issue.source == UK_BUNDLE_SOURCES[0] for issue in errors) def test_one_uk_dimension_id_needs_one_label_across_packages(): @@ -531,9 +536,9 @@ def test_build_bundle_reports_an_unlabelled_uk_package(tmp_path, monkeypatch): ) assert not report.valid - assert {issue.code for issue in report.errors} == { - "missing_dimension_label", - "missing_dimension_value_label", - } + # The package's values are ones other ISC packages emit too, so they take + # the labels Chronicle's register gives them (chronicle#376); its + # dimension ids still need the declarations this copy dropped. + assert {issue.code for issue in report.errors} == {"missing_dimension_label"} assert {issue.source for issue in report.errors} == {str(package_dir)} assert "isc.census_line" in {issue.key for issue in report.errors} diff --git a/tests/test_issue_265_non_uk_labels.py b/tests/test_issue_265_non_uk_labels.py index 8a75f2b7..2b96bf98 100644 --- a/tests/test_issue_265_non_uk_labels.py +++ b/tests/test_issue_265_non_uk_labels.py @@ -20,7 +20,6 @@ from chronicle.bundle import ( UK_BUNDLE_SOURCES, _cross_package_dimension_label_errors, - _cross_package_value_label_warnings, _dimension_label_reports, _value_labels, ) @@ -151,23 +150,28 @@ def test_the_packages_microcosm_targets_outside_the_uk_declare_their_labels(): } -def test_a_value_two_packages_word_differently_is_a_warning(): - warnings = _cross_package_value_label_warnings( - { - ("income_range", "under_1"): { - "No adjusted gross income": ["soi-table-1-1"], - "No adjusted gross income and deficit": [ - "soi-filing-season-week47-2024-eitc-total" - ], - }, - ("filing_status", "all"): {"All filing statuses": ["soi-table-1-1"]}, - } - ) +def test_a_value_two_packages_word_differently_is_an_error(): + """One value id carries one label across packages (chronicle#376). - assert [(warning.code, warning.key) for warning in warnings] == [ + There is no list of accepted wordings: the remedy is one register entry, + which test_issue_376_one_label_per_value.py covers. + """ + labels_by_value = { + ("income_range", "under_1"): { + "No adjusted gross income": ["soi-table-1-1"], + "No adjusted gross income and deficit": [ + "soi-filing-season-week47-2024-eitc-total" + ], + }, + ("filing_status", "all"): {"All filing statuses": ["soi-table-1-1"]}, + } + + errors = bundle._cross_package_value_label_errors(labels_by_value) + + assert [(error.code, error.key) for error in errors] == [ ("conflicting_value_label_across_packages", "income_range=under_1") ] - assert "'No adjusted gross income' in ['soi-table-1-1']" in warnings[0].message + assert "'No adjusted gross income' in ['soi-table-1-1']" in errors[0].message def test_an_area_name_is_left_to_the_geography_warning(): @@ -190,7 +194,7 @@ def test_an_area_name_is_left_to_the_geography_warning(): def test_one_package_disagreeing_with_itself_is_left_to_its_own_report(): """The package-level check owns single-source drift; this one would repeat it.""" - warnings = _cross_package_value_label_warnings( + errors = bundle._cross_package_value_label_errors( { ("groeipakket.component", "sociale_toeslag"): { "Social supplement child caseload": [ @@ -203,4 +207,4 @@ def test_one_package_disagreeing_with_itself_is_left_to_its_own_report(): } ) - assert warnings == [] + assert errors == [] diff --git a/tests/test_issue_376_one_label_per_value.py b/tests/test_issue_376_one_label_per_value.py new file mode 100644 index 00000000..53350149 --- /dev/null +++ b/tests/test_issue_376_one_label_per_value.py @@ -0,0 +1,827 @@ +"""One Chronicle-declared label per dimension value (chronicle#376). + +Microcosm copies every fact's dimension and value labels into the targets it +compiles, and the calibration-diagnostics dashboard refuses a release whose +targets label one value two ways. IRS SOI's filing-season week-47 package +labelled ``under_1`` of the adjusted-gross-income dimension "No adjusted gross +income and deficit", the IRS's column header, while every other IRS SOI package +writes "No adjusted gross income", and US release +``populace-us-2024-0fb05b6-4b57d15a287c-20260930T150401Z`` carried both. The +bundle check only compared packages built for one year, and Microcosm merges +packages built for different years into one feed. + +Each (dimension id, value id) that more than one package emits now has one +label in Chronicle's register, ``chronicle/dimension_values/canonical_labels.json``. +Every fact takes that label when it is built, at any build year, in +``dimension_value_labels`` and ``layout.groupby_value_label``. A package's own +wording, where it differs, is kept in ``package_dimension_value_labels`` +(``chronicle.consumer_fact.v5``). That wording is the package's, not +necessarily the publisher's: often it is text Chronicle wrote, so the field +says so and nothing presents it as the publisher's text. A +value no register entry covers takes its package's label, and two labels for it +are an error wherever Chronicle can see both: inside one package in +``validate-package``, ``build-suite`` and ``build-bundle``, and across packages +in ``build-bundle``. There is no list of accepted exceptions. +""" + +from __future__ import annotations + +import hashlib +import json +from pathlib import Path + +import openpyxl +import pytest +import yaml + +from chronicle import bundle, dimension_labels +from chronicle.consumer_contract import consumer_fact_rows, write_consumer_facts_jsonl +from chronicle.source_package import ( + SOURCE_PACKAGE_ALIASES, + load_source_package, + validate_source_package, +) +from chronicle.suite import build_source_suite +from policyengine_chronicle.consumer import ( + build_consumer_artifact, + load_consumer_artifact, +) + +ADJUSTED_GROSS_INCOME = "us:statutes/26/62#adjusted_gross_income" +WEEK47 = "soi-filing-season-week47-2024-eitc-total" +IRS_SOI_LABEL = "No adjusted gross income" +WEEK47_WORDING = "No adjusted gross income and deficit" +WEEK47_COLUMN_HEADER = "No adjusted gross\nincome and deficit" +FILING_SEASON_LINE = "irs_soi.filing_season_line" +_PACKAGES = Path(__file__).parents[1] / "packages" +_REGISTER = ( + Path(__file__).parents[1] + / "chronicle" + / "dimension_values" + / "canonical_labels.json" +) +_REGISTER_PATH_TEXT = "chronicle/dimension_values/canonical_labels.json" +_HARNESS_DOC = Path(__file__).parents[1] / "docs" / "agent-source-package-harness.md" +_ONS_CONSUMER_TRENDS = ( + Path(__file__).parents[1] + / "db" + / "data" + / "ons" + / "consumer_trends_current_price_2026" + / "cpnsa.xlsx" +) + + +def _week47_facts(): + package = load_source_package(WEEK47) + return package.build_facts(2024, cells=package.build_source_cells(2024)) + + +def _below_one_dollar(facts): + return [ + fact + for fact in facts + if fact.layout.groupby_dimension == ADJUSTED_GROSS_INCOME + and fact.layout.groupby_value_id == "under_1" + ] + + +def _package_rows(source: str, year: int) -> list[dict]: + package = load_source_package(source) + facts = package.build_facts(year, cells=package.build_source_cells(year)) + return consumer_fact_rows(facts) + + +def _week47_copy_with_drifting_line_label(tmp_path: Path) -> Path: + """A copy of week 47 whose EITC amount row names its line differently.""" + source = _PACKAGES / SOURCE_PACKAGE_ALIASES[WEEK47] / "source_package.yaml" + package_dir = tmp_path / "week47_drift" + package_dir.mkdir() + payload = yaml.safe_load(source.read_text()) + amount = next( + record_set + for record_set in payload["record_sets"] + if record_set["record_set_id"].endswith("eitc_all_returns.amount") + ) + amount["rows"][0]["label"] = "Earned income credit amount" + (package_dir / "source_package.yaml").write_text( + yaml.safe_dump(payload, sort_keys=False, allow_unicode=True) + ) + return package_dir + + +# The register and the three US labels the maintainer chose. + + +def test_the_register_holds_the_three_chosen_us_labels(): + assert ( + dimension_labels.canonical_value_label(ADJUSTED_GROSS_INCOME, "under_1") + == "No adjusted gross income" + ) + assert ( + dimension_labels.canonical_value_label(ADJUSTED_GROSS_INCOME, "all") + == "All returns, total" + ) + assert dimension_labels.canonical_value_label("age", "85_plus") == "Age 85 plus" + + +def test_the_register_holds_the_four_labels_chosen_after_merging_main(): + """The maintainer's 2026-10-26 choices for values main's packages word two ways.""" + assert dimension_labels.canonical_value_label("freq", "A") == "Annual" + assert ( + dimension_labels.canonical_value_label("income_range", "all") + == "All income ranges" + ) + assert ( + dimension_labels.canonical_value_label( + "gambling_commission.gsgb_activity", "national_lottery_draws_in_person" + ) + == "Tickets for National Lottery draws bought in person" + ) + assert ( + dimension_labels.canonical_value_label( + "salary_sacrifice_threshold_position", "all" + ) + == "All threshold positions" + ) + + +def test_a_chronicle_written_label_keeps_the_rows_text_beside_it(): + """salary_sacrifice_threshold_position=all: both row texts name the measure.""" + package = load_source_package("hmrc-salary-sacrifice-reform-2029-headcounts") + facts = package.build_facts(2023, cells=package.build_source_cells(2023)) + all_positions = [ + fact + for fact in facts + if fact.filters.get("salary_sacrifice_threshold_position") == "all" + ] + + assert all_positions + assert { + fact.dimension_value_labels["salary_sacrifice_threshold_position"]["all"] + for fact in all_positions + } == {"All threshold positions"} + # Each row keeps its own text: the headcount row as its groupby label, the + # forgone National Insurance rows also as the package's wording of the value. + assert {fact.layout.groupby_value_label for fact in all_positions} == { + "Employees using salary sacrifice to make pension contributions", + "National Insurance contributions forgone through salary sacrifice for " + "pensions", + } + assert { + fact.package_dimension_value_labels.get( + "salary_sacrifice_threshold_position", {} + ).get("all") + for fact in all_positions + } == { + None, + "National Insurance contributions forgone through salary sacrifice for " + "pensions", + } + + +def test_the_register_is_one_file_with_one_label_per_value(): + payload = json.loads(_REGISTER.read_text(encoding="utf-8")) + + assert payload["schema_version"] == "chronicle.dimension_value_labels.v1" + assert payload["labels"] + for dimension_id, value_labels in payload["labels"].items(): + assert dimension_id.strip() == dimension_id and dimension_id + for value_id, label in value_labels.items(): + assert isinstance(label, str) and label.strip() == label and label, ( + dimension_id, + value_id, + ) + assert dimension_labels.REGISTER_PATH == _REGISTER + + +def test_there_is_no_list_of_accepted_label_variants(): + assert not hasattr(dimension_labels, "REVIEWED_VALUE_LABEL_VARIANTS") + assert not hasattr(dimension_labels, "is_reviewed_value_label_variant") + assert not hasattr(bundle, "_cross_package_value_label_warnings") + + +# The week-47 package: the register's label, and the IRS wording beside it. + + +def test_week47_facts_carry_the_register_label_and_keep_the_irs_wording(): + below_one_dollar = _below_one_dollar(_week47_facts()) + + assert len(below_one_dollar) == 2 + for fact in below_one_dollar: + assert fact.dimension_value_labels[ADJUSTED_GROSS_INCOME] == { + "under_1": IRS_SOI_LABEL + } + assert fact.layout.groupby_value_label == IRS_SOI_LABEL + assert fact.package_dimension_value_labels == { + ADJUSTED_GROSS_INCOME: {"under_1": WEEK47_WORDING} + } + assert [ + (constraint.variable, constraint.operator, constraint.value) + for constraint in fact.constraints + ] == [(ADJUSTED_GROSS_INCOME, "<", 1)] + + for row in consumer_fact_rows(below_one_dollar): + assert row["schema_version"] == "chronicle.consumer_fact.v5" + assert row["dimension_value_labels"][ADJUSTED_GROSS_INCOME] == { + "under_1": IRS_SOI_LABEL + } + assert row["layout"]["groupby_value_label"] == IRS_SOI_LABEL + assert row["package_dimension_value_labels"] == { + ADJUSTED_GROSS_INCOME: {"under_1": WEEK47_WORDING} + } + + +def test_week47_rows_keep_the_irs_wording_checked_against_its_column(): + """The package's row label is the IRS's text, which its column guard checks.""" + package_yaml = _PACKAGES / SOURCE_PACKAGE_ALIASES[WEEK47] / "source_package.yaml" + package = yaml.safe_load(package_yaml.read_text()) + rows = [ + row + for record_set in package["record_sets"] + if record_set["groupby_dimension"] == ADJUSTED_GROSS_INCOME + for row in record_set["rows"] + if row["value_id"] == "under_1" + ] + + assert [(row["label"], row["expected_column_header"]) for row in rows] == [ + (WEEK47_WORDING, WEEK47_COLUMN_HEADER), + (WEEK47_WORDING, WEEK47_COLUMN_HEADER), + ] + + +def test_week47_fact_keys_and_record_set_hashes_are_unchanged(): + """Labels are display metadata: no key moves, and the row text is main's.""" + rows = sorted( + consumer_fact_rows(_week47_facts()), + key=lambda row: row["lineage"]["source_record_id"], + ) + key_fields = [ + [ + row["lineage"]["source_record_id"], + row["aggregate_fact_key"], + row["semantic_fact_key"], + row["legacy_fact_key"], + row["dimension_set_key"], + ] + for row in rows + ] + + assert len(rows) == 34 + # The 34 facts' keys as built on main at aa288c3. + assert ( + hashlib.sha256(json.dumps(key_fields).encode()).hexdigest() + == "ddbdbaca7cbfe0f0a035db899d944e60cf2f1077a89339d3bc54564dbbea28ee" + ) + assert { + row["lineage"]["source_record_id"].rsplit(".", 1)[-1]: row["layout"][ + "record_set_spec_hash" + ] + for row in rows + if row["layout"].get("groupby_value_id") == "under_1" + } == { + "total_earned_income_credit_returns": "5baf962c82f213018a03f6c3", + "total_earned_income_credit_amount": "164f9b82a4305158d1a57b85", + } + + +def test_a_row_with_the_publisher_wording_loads_with_its_fact_key(tmp_path): + """The validator's recomputed key ignores the new display field (cf. #284).""" + facts = _below_one_dollar(_week47_facts()) + facts_path = tmp_path / "consumer_facts.jsonl" + write_consumer_facts_jsonl(facts, facts_path) + + build_consumer_artifact(tmp_path / "artifact", facts_path=facts_path) + artifact = load_consumer_artifact(tmp_path / "artifact") + + assert artifact.manifest["consumer_fact_schema_versions"] == [ + "chronicle.consumer_fact.v5" + ] + assert sorted(row["aggregate_fact_key"] for row in artifact.rows) == [ + "ledger.aggregate_fact.v2:d7be16a1db07493be1500058", + "ledger.aggregate_fact.v2:fba2311e623134c71d8c78cd", + ] + assert all( + row["package_dimension_value_labels"] + == {ADJUSTED_GROSS_INCOME: {"under_1": WEEK47_WORDING}} + for row in artifact.rows + ) + + +# One label at every build year. + + +def test_a_value_carries_one_label_across_packages_built_at_different_years(): + """Microcosm merges packages built for different years into one feed. + + Week 47 builds only at 2024 and Publication 1304 Table 1.4 at 2023; ACS + S0101 builds only at 2024 and the B01001 female table only at 2023. No + single-year bundle holds both packages of either pair, so the facts must + agree on their own. + """ + labels_by_value: dict[tuple[str, str], dict[str, list[str]]] = {} + for source, year in ( + (WEEK47, 2024), + ("soi-table-1-4", 2023), + ("census-acs-s0101-national-age-2024", 2024), + ("census-b01001-female-age-2023", 2023), + ): + for value, labels in bundle._value_labels(_package_rows(source, year)).items(): + for label in labels: + labels_by_value.setdefault(value, {}).setdefault(label, []).append( + source + ) + + assert bundle._cross_package_value_label_errors(labels_by_value) == [] + assert labels_by_value[(ADJUSTED_GROSS_INCOME, "under_1")] == { + IRS_SOI_LABEL: [WEEK47, "soi-table-1-4"] + } + for value_id in ("age_25_to_29", "age_30_to_34", "age_35_to_39", "age_40_to_44"): + assert list(labels_by_value[("age", value_id)]) == [ + dimension_labels.canonical_value_label("age", value_id) + ] + + +def test_a_value_two_packages_label_differently_is_refused_with_its_remedy(): + labels_by_value = { + ("filing_status", "head_of_household"): { + "Head of household": ["soi-table-1-2"], + "Heads of household": ["a-new-package"], + }, + # A registered value is refused too if two labels reach the bundle: + # nothing is an accepted exception. + ("sex", "male"): {"Male": ["ons-a"], "Males": ["nrs-b"]}, + ("filing_status", "all"): {"All filing statuses": ["soi-table-1-1"]}, + } + + errors = bundle._cross_package_value_label_errors(labels_by_value) + + assert [(error.code, error.key) for error in errors] == [ + ( + "conflicting_value_label_across_packages", + "filing_status=head_of_household", + ), + ("conflicting_value_label_across_packages", "sex=male"), + ] + unlisted, listed = errors[0].message, errors[1].message + assert "'Heads of household' in ['a-new-package']" in unlisted + # Two packages emit it, so only a register entry can apply, and the + # message says how to choose its label. + assert f"Add it to {_REGISTER_PATH_TEXT}" in unlisted + assert "the wording most of these packages use" in unlisted + assert "national statistics office" in unlisted + assert "scripts/build_dimension_value_register.py --static-check" in unlisted + # Two packages word it differently, so the script that regenerates the + # register needs the chosen label too, or it no longer reproduces the + # register (chronicle#377 re-check, N2). + assert ( + "add that label to CHOSEN_LABELS in scripts/build_dimension_value_register.py" + ) in unlisted + assert "dimension_value_labels" not in unlisted.replace( + "package_dimension_value_labels", "" + ) + # A listed value already has its label: the message names it. + assert "Chronicle's register labels this value 'Male'" in listed + assert "rebuild" in listed + assert "Add it to" not in listed + assert "CHOSEN_LABELS" not in listed + + +# One label inside one package, refused as early as validate-package. + + +def test_validate_package_refuses_a_value_one_package_labels_two_ways(tmp_path): + package_dir = _week47_copy_with_drifting_line_label(tmp_path) + + report = validate_source_package(package_dir, year=2024) + + issues = [ + issue for issue in report.errors if issue.code == "conflicting_value_label" + ] + assert len(issues) == 1 + message = issues[0].message + assert f"{FILING_SEASON_LINE!r} value 'earned_income_credit'" in message + assert "'Earned income credit'" in message + assert "'Earned income credit amount'" in message + # One package emits it and the register does not list it: the one remedy + # is a declaration in this package. + assert "Declare one label for it in this package's dimension_value_labels" in ( + message + ) + assert _REGISTER_PATH_TEXT not in message + + +def test_build_suite_refuses_a_value_one_package_labels_two_ways(tmp_path): + package_dir = _week47_copy_with_drifting_line_label(tmp_path) + + report = build_source_suite(package_dir, tmp_path / "suite", year=2024) + + assert not report.valid + assert [ + issue.code + for issue in report.agent_acceptance.errors + if issue.code == "conflicting_value_label" + ] == ["conflicting_value_label"] + + +def test_a_package_declaration_settles_its_own_value_and_keeps_the_rows(tmp_path): + """A value only one package emits needs no register entry: it declares one.""" + package_dir = _week47_copy_with_drifting_line_label(tmp_path) + package_yaml = package_dir / "source_package.yaml" + payload = yaml.safe_load(package_yaml.read_text()) + payload["dimension_value_labels"][FILING_SEASON_LINE] = { + "earned_income_credit": "Earned income credit" + } + package_yaml.write_text(yaml.safe_dump(payload, sort_keys=False)) + + assert [ + issue.code + for issue in validate_source_package(package_dir, year=2024).errors + if issue.code == "conflicting_value_label" + ] == [] + package = load_source_package(package_dir) + facts = package.build_facts(2024, cells=package.build_source_cells(2024)) + amount = next( + fact + for fact in facts + if fact.source_record_id.endswith( + "eitc_all_returns.earned_income_credit.total_earned_income_credit_amount" + ) + ) + assert amount.layout.groupby_value_label == "Earned income credit" + assert amount.package_dimension_value_labels == { + FILING_SEASON_LINE: {"earned_income_credit": "Earned income credit amount"} + } + + +def test_the_bundle_refuses_a_value_one_package_labels_two_ways(): + rows = [ + { + "aggregate_fact_key": f"ledger.aggregate_fact.v2:{label}", + "dimensions": {}, + "dimension_labels": {FILING_SEASON_LINE: "Filing season line"}, + "dimension_value_labels": { + FILING_SEASON_LINE: {"earned_income_credit": label} + }, + "layout": { + "groupby_dimension": FILING_SEASON_LINE, + "groupby_dimension_label": "Filing season line", + "groupby_value_id": "earned_income_credit", + "groupby_value_label": label, + }, + } + for label in ("Earned income credit", "Earned income credit amount") + ] + + errors, warnings = bundle._dimension_label_reports(WEEK47, rows) + + assert [(error.code, error.key) for error in errors] == [ + ( + "conflicting_groupby_value_label", + f"{FILING_SEASON_LINE}=earned_income_credit", + ) + ] + assert "Declare one label for it in this package's dimension_value_labels" in ( + errors[0].message + ) + assert _REGISTER_PATH_TEXT not in errors[0].message + assert warnings == [] + + +def test_a_listed_value_labelled_two_ways_in_old_rows_names_the_register_label(): + """Rows built before the register (or by hand) can still disagree.""" + rows = [ + { + "aggregate_fact_key": f"ledger.aggregate_fact.v2:{label}", + "dimensions": {"sex": "male"}, + "dimension_labels": {"sex": "Sex"}, + "dimension_value_labels": {"sex": {"male": label}}, + "layout": {}, + } + for label in ("Male", "Males") + ] + + errors, _warnings = bundle._dimension_label_reports("nrs-a", rows) + + assert [(error.code, error.key) for error in errors] == [ + ("conflicting_dimension_value_label", "sex=male") + ] + assert "Chronicle's register labels this value 'Male'" in errors[0].message + assert "Declare one label" not in errors[0].message + + +# A package declaration cannot contradict the register (chronicle#377 review). + + +def test_validate_package_refuses_a_declaration_the_register_contradicts(tmp_path): + package_dir = _week47_copy_with_drifting_line_label(tmp_path) + package_yaml = package_dir / "source_package.yaml" + payload = yaml.safe_load(package_yaml.read_text()) + payload["dimension_value_labels"][ADJUSTED_GROSS_INCOME] = { + "under_1": WEEK47_WORDING + } + package_yaml.write_text(yaml.safe_dump(payload, sort_keys=False)) + + issues = [ + issue + for issue in validate_source_package(package_dir, year=2024).errors + if issue.code == "declared_value_label_differs_from_register" + ] + + assert len(issues) == 1 + message = issues[0].message + assert ( + f"dimension_value_labels.{ADJUSTED_GROSS_INCOME}.under_1 declares " + f"{WEEK47_WORDING!r}" + ) in message + assert f"labels this value {IRS_SOI_LABEL!r}" in message + assert _REGISTER_PATH_TEXT in message + assert f"Change the declaration to {IRS_SOI_LABEL!r}" in message + assert str(package_yaml) in message or "source_package.yaml" in message + + +@pytest.mark.parametrize( + ("package_dir", "dimension_id", "value_id", "register_label"), + [ + ("nrs/mye_2025_council_area", "sex", "female", "Female"), + ("nrs/mye_2025_council_area", "sex", "male", "Male"), + ("nisra/mye_2025_lgd_single_year_age", "sex", "female", "Female"), + ("nisra/mye_2025_lgd_single_year_age", "sex", "male", "Male"), + ("nrs/pcon24_population_by_age_2024_revised_2026", "sex", "female", "Female"), + ("nrs/pcon24_population_by_age_2024_revised_2026", "sex", "male", "Male"), + ( + "ons/hpssa_pcon24_year_ending_march_2026", + "property_type", + "detached", + "Detached", + ), + ( + "ons/hpssa_pcon24_year_ending_march_2026", + "property_type", + "semi_detached", + "Semi detached", + ), + ( + "ons/hpssa_pcon24_year_ending_march_2026", + "property_type", + "terraced", + "Terraced", + ), + ("ons/pipr_rents_by_area_august_2026", "property_type", "detached", "Detached"), + ("ons/pipr_rents_by_area_august_2026", "property_type", "terraced", "Terraced"), + ("dft/nts0601_age_mode_trips_2025", "age_band", "30 to 39", "30 to 39"), + ("dft/nts0601_age_mode_trips_2025", "age_band", "40 to 49", "40 to 49"), + ], +) +def test_the_declarations_the_register_overrode_now_agree_with_it( + package_dir, dimension_id, value_id, register_label +): + """The 13 declarations the register silently overrode at e29da32.""" + payload = yaml.safe_load( + (_PACKAGES / package_dir / "source_package.yaml").read_text() + ) + + assert dimension_labels.canonical_value_label(dimension_id, value_id) == ( + register_label + ) + assert payload["dimension_value_labels"][dimension_id][value_id] == register_label + + +# The package's own wording: a field that says what it holds. + +# Each wording is text Chronicle wrote, not the publisher's (the chronicle#377 +# source-fidelity, contract and boundary reviews): a curated extract's value +# id, a parser's constant, or a package author's phrase. Each must be kept in a +# field that names it as the package's wording and says it is unchecked. +_CHRONICLE_WRITTEN_WORDINGS = [ + # The Statbel ZIP has single-year CD_AGE only; "65_plus" is the curated + # CSV's value id. + ( + "statbel-population-structure-2025", + 2025, + "person.age_band", + "65_plus", + "65_plus", + ), + # The B01001 JSON holds variable codes and numbers; the text is + # B01001_FEMALE_AGE_COLUMNS and the parser's sex column. + ("census-b01001-female-age-2023", 2023, "age", "age_20", "Female 20 years"), + ("census-b01001-female-age-2023", 2023, "sex", "female", "female"), + # Eurostat calls D1 "First decile"; the guard checks the code D1. + ( + "eurostat-ilc-di01", + 2023, + "quant_inc", + "d1", + "First income decile cut-point", + ), + # The four Belgian country-total rows: guards check Chronicle identifiers. + ( + "spf-finances-pit-2023", + 2023, + "measure", + "country_total", + "Belgium PIT federal and local tax before withholding", + ), + ( + "onem-rva-unemployment-2024", + 2023, + "measure", + "country_total", + "Complete unemployment benefit recipients", + ), + ( + "nbb-national-accounts-household-disposable-income-2024", + 2023, + "measure", + "country_total", + "Household disposable income gross", + ), + ( + "onss-contributions-2024", + 2023, + "measure", + "country_total", + "Worker-borne personal social security contributions", + ), + # The guard checks the code B2G in column D. + ( + "eurostat-nasa-10-nf-tr", + 2023, + "na_item", + "belgium_household_operating_surplus_gross", + "Operating surplus, gross (B.2G), paid-direction cell", + ), + # The guard checks the code sociale_toeslag. + ( + "opgroeien-groeipakket-caseload-2025", + 2023, + "groeipakket.component", + "sociale_toeslag", + "Social supplement child caseload", + ), +] + + +@pytest.mark.parametrize( + ("source", "year", "dimension_id", "value_id", "wording"), + _CHRONICLE_WRITTEN_WORDINGS, +) +def test_text_chronicle_wrote_is_kept_as_the_packages_wording_not_the_publishers( + source, year, dimension_id, value_id, wording +): + package = load_source_package(source) + facts = package.build_facts(year, cells=package.build_source_cells(year)) + rows = consumer_fact_rows(facts) + description = json.loads( + ( + Path(__file__).parents[1] + / "docs" + / "schemas" + / "consumer_fact.v5.schema.json" + ).read_text() + )["properties"]["package_dimension_value_labels"]["description"] + + wordings = { + fact.package_dimension_value_labels.get(dimension_id, {}).get(value_id) + for fact in facts + } + assert wording in wordings + assert all("publisher_dimension_value_labels" not in row for row in rows) + assert any( + (row.get("package_dimension_value_labels") or {}) + .get(dimension_id, {}) + .get(value_id) + == wording + for row in rows + ) + assert "text Chronicle wrote" in description + + +def test_nts0601_age_bands_now_carry_dfts_header_and_no_package_wording(): + """NTS0601's "Age 30 to 39" came from its declaration, now the register's. + + DfT's row header, which the guard checks, is "30 to 39"; the declaration + "Age 30 to 39" was Chronicle's text in the field at e29da32. + """ + package = load_source_package("dft-nts0601-age-mode-trips-2025") + facts = package.build_facts(2023, cells=package.build_source_cells(2023)) + banded = [ + fact + for fact in facts + if fact.filters.get("age_band") in {"30 to 39", "40 to 49"} + ] + + assert len(banded) == 18 + for fact in banded: + value_id = fact.filters["age_band"] + assert fact.dimension_value_labels["age_band"] == {value_id: value_id} + assert "age_band" not in fact.package_dimension_value_labels + + +def test_a_groupby_value_whose_axis_is_also_a_filter_is_keyed_by_its_row_value(): + """Eurostat ilc_di01: quant_inc is the filter D1 and the groupby row d1.""" + package = load_source_package("eurostat-ilc-di01") + facts = package.build_facts(2023, cells=package.build_source_cells(2023)) + fact = next( + fact + for fact in facts + if fact.layout.groupby_value_id == "d1" and fact.filters["statinfo"] == "SHARE" + ) + + assert fact.filters["quant_inc"] == "D1" + assert fact.layout.groupby_value_label == "First income decile" + # freq=A takes the register's "Annual"; the package's "A" is kept beside it. + assert fact.package_dimension_value_labels == { + "freq": {"A": "A"}, + "quant_inc": {"d1": "First income decile share"}, + } + + +def test_the_harness_doc_says_which_fields_the_guards_check(): + text = " ".join(_HARNESS_DOC.read_text(encoding="utf-8").split()) + + assert "a row's `label:` stays the publisher's text" not in text + assert "package_dimension_value_labels" in text + assert "publisher_dimension_value_labels" not in text + assert ( + "The guards compare a row's `expected_row_header` and " + "`expected_column_header`, which are fields separate from its `label:`" + ) in text + + +def test_the_label_module_does_not_call_package_wording_the_publishers(): + """The label-source list names the package's row label and source-row text. + + A row's ``label:`` and the text Chronicle's parser reads into a source row + are the package's wording, which nothing checks against the publisher's + file (chronicle#377 re-check, N3). + """ + docstring = " ".join(dimension_labels.__doc__.split()) + + assert "publisher row label" not in docstring + assert "the publisher's text in the matching column" not in docstring + assert ( + "the package's row label for the fact (``layout.groupby_value_label``" + ) in docstring + + +def test_the_bundle_label_report_does_not_call_package_wording_the_publishers(): + """``build-bundle``'s label report names row labels as the package's. + + The labels that can differ across one groupby value's rows are the + record-set rows' ``label:`` values, package text that nothing checks + against the publisher's file (chronicle#377 fix-round review, F1). + """ + docstring = " ".join(bundle._dimension_label_reports.__doc__.split()) + + assert "publisher row label" not in docstring + assert "the package's row labels" in docstring + + +# ONS COICOP 02: the total includes narcotics (chronicle#377 review). + + +def test_coicop_02_takes_the_ons_wording_that_names_narcotics(): + assert ( + dimension_labels.canonical_value_label("ons.coicop", "coicop_02") + == "Alcohol, tobacco and narcotics" + ) + + +def test_the_ons_coicop_02_total_includes_narcotics(): + """ADFL = ADFM (alcoholic beverages) + ADFN (tobacco) + MNC2 (narcotics).""" + workbook = openpyxl.load_workbook( + _ONS_CONSUMER_TRENDS, read_only=True, data_only=True + ) + sheet_rows = list(workbook["02CN"].iter_rows(values_only=True)) + workbook.close() + cdid_row = next(row for row in sheet_rows if row[0] == "CDID identifier code") + column_by_cdid = {cdid: index for index, cdid in enumerate(cdid_row) if cdid} + annual = [ + row for row in sheet_rows if isinstance(row[0], int) and 1997 <= row[0] <= 2100 + ] + + assert len(annual) >= 29 + for row in annual: + parts = [row[column_by_cdid[cdid]] for cdid in ("ADFM", "ADFN", "MNC2")] + assert abs(row[column_by_cdid["ADFL"]] - sum(parts)) < 0.5, row[0] + + +def test_irs_soi_packages_label_the_band_below_one_dollar_one_way(tmp_path): + report = bundle.build_bundle( + tmp_path / "bundle", + year=2023, + sources=[ + WEEK47, + "soi-historic-table-2", + "soi-table-2-5-eitc-agi-children-2023", + ], + ) + + assert report.valid, [issue.to_dict() for issue in report.errors] + assert [ + issue.to_dict() + for issue in (*report.errors, *report.warnings) + if issue.key == f"{ADJUSTED_GROSS_INCOME}=under_1" + ] == [] diff --git a/tests/test_policyengine_chronicle_schema.py b/tests/test_policyengine_chronicle_schema.py index 1e15afa2..45c60684 100644 --- a/tests/test_policyengine_chronicle_schema.py +++ b/tests/test_policyengine_chronicle_schema.py @@ -31,11 +31,13 @@ _V2 = SCHEMA_IDS["consumer_fact"].chronicle _V3 = "chronicle.consumer_fact.v3" _V4 = "chronicle.consumer_fact.v4" +_V5 = "chronicle.consumer_fact.v5" _SCHEMA_FILES = { _V1: "consumer_fact.v1.schema.json", _V2: "consumer_fact.v2.schema.json", _V3: "consumer_fact.v3.schema.json", _V4: "consumer_fact.v4.schema.json", + _V5: "consumer_fact.v5.schema.json", } _FROZEN_SCHEMA_SHA256 = { _V1: "72ad3149564f8aab3e9bb6de5ea25950c8e19a3e8402e2cdcfc52d250bc8ee82", @@ -43,6 +45,8 @@ _V3: "bdb51e2a8115634633ba7448c4005930fd9c0bfbade5e1b079b6bc24da485d3d", # chronicle#356 adds gas_year to period.type's vocabulary description. _V4: "d953306d6f01fbc64db4372d0262d3012ee590269f8a25b276b18dca0626c6a0", + # chronicle#376: v4 plus the source package's own wording of a value. + _V5: "acd33a091cd8d192be5d264e3e94c13e00afb6fd1972e57d4576ac55a54f6970", } _TOP_LEVEL_KEY_DOMAINS = { @@ -88,11 +92,13 @@ def _chronicle_epoch_row(row): def _v2_row(index=0): """A fixture row restated as a ``chronicle.consumer_fact.v2`` row. - v2 carries the labels and knows nothing of the publisher's geography name. + v2 carries the labels and knows nothing of the publisher's geography name + or of a package's own value wording (v5). """ row = _fixture_row(index) row["schema_version"] = _V2 row.get("geography", {}).pop("name", None) + row.pop("package_dimension_value_labels", None) return row @@ -106,7 +112,7 @@ def _v1_row(index=0): return row -@pytest.mark.parametrize("schema_version", [_V1, _V2, _V3, _V4]) +@pytest.mark.parametrize("schema_version", [_V1, _V2, _V3, _V4, _V5]) def test_packaged_schema_is_byte_identical_to_docs_schema(schema_version): filename = _SCHEMA_FILES[schema_version] docs_bytes = (_REPO_ROOT / "docs" / "schemas" / filename).read_bytes() @@ -125,11 +131,58 @@ def test_packaged_schema_is_byte_identical_to_docs_schema(schema_version): ) -def test_emitted_schema_is_the_v4_contract(): - assert CONSUMER_FACT_SCHEMA_SHA256 == _FROZEN_SCHEMA_SHA256[_V4] +def test_emitted_schema_is_the_v5_contract(): + assert CONSUMER_FACT_SCHEMA_SHA256 == _FROZEN_SCHEMA_SHA256[_V5] assert dict(CONSUMER_FACT_SCHEMA_SHA256_BY_VERSION) == _FROZEN_SCHEMA_SHA256 - assert consumer_fact_schema() == consumer_fact_schema(_V4) - assert tuple(CONSUMER_FACT_ROW_CONTRACTS) == (_V1, _V2, _V3, _V4) + assert consumer_fact_schema() == consumer_fact_schema(_V5) + assert tuple(CONSUMER_FACT_ROW_CONTRACTS) == (_V1, _V2, _V3, _V4, _V5) + + +def test_v5_schema_is_v4_plus_the_packages_own_value_wording(): + v4 = copy.deepcopy(consumer_fact_schema(_V4)) + v5 = copy.deepcopy(consumer_fact_schema(_V5)) + + assert v5["properties"]["schema_version"] == {"const": _V5} + assert v5["required"] == v4["required"] + assert set(v5["properties"]) - set(v4["properties"]) == { + "package_dimension_value_labels" + } + package_wording = v5["properties"]["package_dimension_value_labels"] + assert package_wording["type"] == "object" + assert package_wording["additionalProperties"] == { + "type": "object", + "additionalProperties": {"$ref": "#/$defs/label"}, + } + for schema in (v4, v5): + for key in ("$id", "title", "description"): + schema.pop(key, None) + schema["properties"].pop("schema_version") + schema["properties"].pop("package_dimension_value_labels", None) + schema["properties"]["dimension_value_labels"].pop("description") + assert v5 == v4 + + +def test_v5_describes_the_package_wording_as_unchecked_text_chronicle_may_write(): + """The field holds a package's own wording, which is often Chronicle's text. + + Statbel's "65_plus", Census B01001's "Female 20 years" and "female", + Eurostat's "First income decile cut-point" and the Belgian country-total + phrases are text Chronicle wrote (the chronicle#377 source-fidelity + review), so the contract must not call the field the publisher's text. + """ + v5_text = (_REPO_ROOT / "docs" / "schemas" / _SCHEMA_FILES[_V5]).read_text() + description = consumer_fact_schema(_V5)["properties"][ + "package_dimension_value_labels" + ]["description"] + + assert "publisher_dimension_value_labels" not in v5_text + assert "the publisher's row or column text" not in v5_text + assert "not checked against the publisher's file" in description + assert "text Chronicle wrote" in description + assert "lineage.source_cell_keys" in description + # A groupby value whose axis is also a filter with another value (Eurostat + # quant_inc: filter D1, row d1) is keyed by its groupby value id. + assert "layout.groupby_value_id" in description def test_v4_schema_is_v3_plus_the_publishers_own_geography_name(): @@ -200,12 +253,12 @@ def test_valid_fixture_rows_pass_validation(): ] assert len(rows) == 3 - assert {row["schema_version"] for row in rows} == {_V4} + assert {row["schema_version"] for row in rows} == {_V5} for line_number, row in enumerate(rows, start=1): validate_consumer_fact_row(row, line_number, _SAMPLE_PATH) -@pytest.mark.parametrize("schema_version", [_V2, _V3, _V4]) +@pytest.mark.parametrize("schema_version", [_V2, _V3, _V4, _V5]) def test_a_v1_row_validates_as_v1_and_restamped_under_each_successor(schema_version): row = _v1_row() @@ -263,8 +316,8 @@ def test_all_chronicle_epoch_identifiers_pass_without_mutating_row(): assert row == original normalized = normalize_consumer_fact_row_epochs(row, 2, _SAMPLE_PATH) # The row contract is not an epoch alias: a row keeps the contract it - # declares, here the v4 one the fixture was published under. - assert normalized["schema_version"] == _V4 + # declares, here the v5 one the fixture was published under. + assert normalized["schema_version"] == _V5 for field_name, domain_name in _TOP_LEVEL_KEY_DOMAINS.items(): assert normalized[field_name].startswith(HASH_DOMAINS[domain_name].ledger + ":") assert normalized["concept_alignment"]["concept_alignment_key"].startswith( diff --git a/tests/test_source_gambling_commission_gsgb_2025.py b/tests/test_source_gambling_commission_gsgb_2025.py index 62f48fc9..5a310c03 100644 --- a/tests/test_source_gambling_commission_gsgb_2025.py +++ b/tests/test_source_gambling_commission_gsgb_2025.py @@ -126,11 +126,30 @@ def test_facts_are_valid_labelled_and_unique(facts): assert len(facts) == 1024 assert validate_facts(facts).valid assert validate_consumer_fact_contract(facts).valid - # B.9 and B.10 word row 6 differently, and both labels are kept as published. + # B.9 and B.10 word row 6 differently. Chronicle's label register gives the + # value B.10's wording (chronicle#376), and B.9's facts keep their row's + # text as the package's wording. issues = dimension_label_issues(consumer_fact_rows(facts)) - assert [(issue.code, issue.value_id) for issue in issues] == [ - ("conflicting_groupby_value_label", "national_lottery_draws_in_person") + assert [(issue.code, issue.value_id) for issue in issues] == [] + in_person = [ + fact + for fact in facts + if fact.layout.groupby_value_id == "national_lottery_draws_in_person" ] + assert {fact.layout.groupby_value_label for fact in in_person} == { + "Tickets for National Lottery draws bought in person" + } + assert { + fact.filters["source_sheet"]: ( + fact.package_dimension_value_labels.get( + "gambling_commission.gsgb_activity", {} + ).get("national_lottery_draws_in_person") + ) + for fact in in_person + } == { + "Table B.9": "Tickets National Lottery draws bought in person", + "Table B.10": None, + } assert max(Counter(build_semantic_fact_key(f) for f in facts).values()) == 1 assert Counter(f.filters["source_sheet"] for f in facts) == { "Table B.1": 72,