#149: shared airports + airport_points layer — one MVT source for is/se/pl/fi #154

Merged
art merged 15 commits from issue-149-shared-airports into main 2026-08-17 22:08:30 +00:00
Owner

#149: shared airports + airport_points layer — one MVT source for is/se/pl/fi

Closes #149


The shared layer

airports and the derived airport_points are now shared layers in the
unification sense: contracts in conf/common.yaml shared_layers:, one
country-partitioned table map_<layer>_<z>_<cc> per country, one MVT function
(zxy_map_airports / zxy_map_airport_points) on the map source. All four
countries build a partition; the style draws every country's airports from the one
map tile route.

The contract (airports: stop_z 10, maxz 13, filter_only; airport_points:
stop_z 8, maxz 13, filter_only) is one attribute set all four countries already
fill: geom, name, airport_class. The class ladders collapse to the same 1/2
(Áætlunarvöllur / iata presence / TYPLOTNISKA 'port lotniczy' / register
LENTOASEMA → 1, everything else → 2) and the zoom floors matched before this PR,
so no country changed its data — only the table it lands in. Iceland renamed its
nafnfitju column to name to meet the contract.

The derivation reads the country's own partition: each airport_points
query sources map_airports_13_<cc> (partition-pruned), with the existing
layers: [airports] DAG edge keeping airports first (R140).

This carries the three per-country imports: the se (#146/#103), fi (#147/#110)
and pl (#153/#106) airports data now renders through the shared source. Those
issues stay open for their data review; this PR is only the unification fold.

Style and sources

  • airports + airport_labels now read the shared map source (airport_labels
    switched from nafnfitju to the contract's name field).
  • The per-country style layers (airports_se/fi/pl, airport_labels_se/fi/pl) and
    the per-country tile sources (se, fi, pl) that #103/#106/#110 added are
    deleted. conf/mapsrv.yaml sources are back to [map, is]; is keeps
    contours/buildings/peaks.
  • se/pl/fi configs now declare no source; their sources: blocks are empty
    (documented in-place).
  • Docs updated: docs/style.md (66 layers: 58 map + 7 is + background),
    docs/schema.md (shared/per-country lists), docs/country-requirements.md
    (R13 + layer inventory), docs/unification.md, docs/workstream-a.md.

Orphans — deliberate (issue #12 shape)

Nothing was DROPped. The old per-country tables (ismap_/se_/plmap_/fi_ airports +
airport_points) and their zxy_<cc>_airports[_points] functions remain in the DB as
inert #12 orphans — the project's established practice from past unifications. They
collide with nothing (different prefixes; mapsrv no longer declares those sources)
and are tracked by #12.

Verification (live DB)

Re-imported only the two layers per country (--layer airports,airport_points),
no fetches, no full imports:

  • Acceptance per country (run on every import + make acceptance):
    • ismap: 31 passed, 0 failed (incl. R119/R120 airports + airport_points on
      map_airports_*_is)
    • semap: 35 passed, 1 not run (the 100s-bucket test; airports R119/R120 PASS)
    • plmap: 34 passed, 0 failed (incl. R6/R119/R120)
    • fimap: 40 passed, 0 failed (incl. R6/R119/R120/R94)
    • world: 14 passed, 0 failed
    • Layer tallies, e.g. R119: no airports zoom table is empty (z10–z13) — PASS,
      R120: airports carry no NULL airport_class ... — PASS (per country), the
      Finland R94: no all-caps Finland airport labels ... — PASS, the Poland
      R6: the airport partition is populated (OT_KUKO_A) — PASS (airports=301).
  • tiles --check (R121 decoded-tile check) per config: all PASS; the shared
    layers' keys are exactly [name airport_class country] (contract attrs minus
    nothing, plus the partition key).
  • Decoded tiles through the live zxy_map at z13: Keflavík → airports 1 +
    airport_points 1 (name Keflavík, class 1); Arlanda → 1 (Arlanda flygplats, 1);
    Chopin → 1 + 1 (Lotnisko Chopina w Warszawie, 1); Helsinki-Vantaa → 32
    (Helsinki-vantaan lentoasema, class 1 among class-2 grounds).
  • Real-browser CDP render (scripts/cdp-map-check.mjs, no virtual time) at z13
    per country: Keflavík 8 airport polygons + label "Keflavík"; Arlanda 5 +
    "Arlanda flygplats"; Chopin 4 + "Lotnisko Chopina w Warszawie"; Helsinki-Vantaa
    72 + "Helsinki-vantaan lentoasema". Screenshots verified (local Qwen2.5-VL).
  • gl-style-validate clean (exit 0).
  • make test passes; config-check passes for all four configs + world.
#149: shared airports + airport_points layer — one MVT source for is/se/pl/fi Closes #149 --- ## The shared layer `airports` and the derived `airport_points` are now **shared layers** in the unification sense: contracts in `conf/common.yaml` `shared_layers:`, one country-partitioned table `map_<layer>_<z>_<cc>` per country, one MVT function (`zxy_map_airports` / `zxy_map_airport_points`) on the `map` source. All four countries build a partition; the style draws every country's airports from the one `map` tile route. **The contract** (`airports`: stop_z 10, maxz 13, filter_only; `airport_points`: stop_z 8, maxz 13, filter_only) is one attribute set all four countries already fill: `geom`, `name`, `airport_class`. The class ladders collapse to the same 1/2 (Áætlunarvöllur / iata presence / TYPLOTNISKA 'port lotniczy' / register LENTOASEMA → 1, everything else → 2) and the zoom floors matched before this PR, so no country changed its data — only the table it lands in. Iceland renamed its `nafnfitju` column to `name` to meet the contract. **The derivation** reads the country's *own* partition: each `airport_points` query sources `map_airports_13_<cc>` (partition-pruned), with the existing `layers: [airports]` DAG edge keeping airports first (R140). **This carries the three per-country imports**: the se (#146/#103), fi (#147/#110) and pl (#153/#106) airports data now renders through the shared source. Those issues stay open for their data review; this PR is only the unification fold. ## Style and sources - `airports` + `airport_labels` now read the shared `map` source (`airport_labels` switched from `nafnfitju` to the contract's `name` field). - The per-country style layers (`airports_se/fi/pl`, `airport_labels_se/fi/pl`) and the per-country tile sources (`se`, `fi`, `pl`) that #103/#106/#110 added are deleted. `conf/mapsrv.yaml` sources are back to `[map, is]`; `is` keeps contours/buildings/peaks. - `se`/`pl`/`fi` configs now declare no source; their `sources:` blocks are empty (documented in-place). - Docs updated: `docs/style.md` (66 layers: 58 map + 7 is + background), `docs/schema.md` (shared/per-country lists), `docs/country-requirements.md` (R13 + layer inventory), `docs/unification.md`, `docs/workstream-a.md`. ## Orphans — deliberate (issue #12 shape) Nothing was DROPped. The old per-country tables (`ismap_/se_/plmap_/fi_` airports + airport_points) and their `zxy_<cc>_airports[_points]` functions remain in the DB as inert #12 orphans — the project's established practice from past unifications. They collide with nothing (different prefixes; mapsrv no longer declares those sources) and are tracked by #12. ## Verification (live DB) Re-imported only the two layers per country (`--layer airports,airport_points`), no fetches, no full imports: - **Acceptance per country** (run on every import + `make acceptance`): - ismap: 31 passed, 0 failed (incl. R119/R120 airports + airport_points on `map_airports_*_is`) - semap: 35 passed, 1 not run (the 100s-bucket test; airports R119/R120 PASS) - plmap: 34 passed, 0 failed (incl. R6/R119/R120) - fimap: 40 passed, 0 failed (incl. R6/R119/R120/R94) - world: 14 passed, 0 failed - Layer tallies, e.g. `R119: no airports zoom table is empty (z10–z13) — PASS`, `R120: airports carry no NULL airport_class ... — PASS` (per country), the Finland `R94: no all-caps Finland airport labels ... — PASS`, the Poland `R6: the airport partition is populated (OT_KUKO_A) — PASS (airports=301)`. - **tiles --check** (R121 decoded-tile check) per config: all PASS; the shared layers' keys are exactly `[name airport_class country]` (contract attrs minus nothing, plus the partition key). - **Decoded tiles** through the live `zxy_map` at z13: Keflavík → `airports` 1 + `airport_points` 1 (name Keflavík, class 1); Arlanda → 1 (Arlanda flygplats, 1); Chopin → 1 + 1 (Lotnisko Chopina w Warszawie, 1); Helsinki-Vantaa → 32 (Helsinki-vantaan lentoasema, class 1 among class-2 grounds). - **Real-browser CDP render** (`scripts/cdp-map-check.mjs`, no virtual time) at z13 per country: Keflavík 8 airport polygons + label "Keflavík"; Arlanda 5 + "Arlanda flygplats"; Chopin 4 + "Lotnisko Chopina w Warszawie"; Helsinki-Vantaa 72 + "Helsinki-vantaan lentoasema". Screenshots verified (local Qwen2.5-VL). - **gl-style-validate** clean (exit 0). - `make test` passes; `config-check` passes for all four configs + world.
Sweden's first unshared layer since unification Phase 5: `airports` (runway
polygons) + the derived `airport_points` label layer, mirroring Iceland's
implementation (R140), from the already-negotiated topo10 Geotorget order (new
files: entry only — 11.4 MB zipped / 25.7 MB unzipped, recorded on first fetch,
R5).

Source: start_landningsbana (objekttypnr 2853, 206 runway polygons with
flygplatsstatus I drift/Nedlagd) joined to flygplatsomrade (objekttypnr 2854,
183 areas with iata/icao). Design, each decision measured against the live data:

- Nedlagd runways are dropped at import (190 of 206 kept) — the same closed-track
  decision the railways layer made; a decommissioned runway is not an airport.
- airport_class comes from the codes, not flygplatsstatus: Iceland's
  scheduled-vs-strip ladder has no Swedish vocabulary, so class 1 = iata present
  ("regular traffic only" per the source docs), class 2 = absent. 57/133 runways.
  The coarse-zoom label filter (z9, class 1, like Iceland) keeps the 42 scheduled
  airports on z8-z9.
- Names come from the Topo 10 text theme's ANLTX "X flygplats" labels (48 of 183
  areas carry one, always inside its area): neither anläggningsomrade table has a
  name, only codes, and a code is not a label. The join is the label inside the
  runway's own area — the uncapped nearest-label join this replaced labelled
  runways from another airport up to 300 km away, and the R120 acceptance test
  pins the structural guarantee.

Serving: semap.yaml regains a sources: block (se), mapsrv.yaml serves /tiles/se,
html/style.json declares the se source with airports_se + airport_labels_se copied
from Iceland's (nafnfitju -> name). Docs updated: country-sweden.md catalogue line
(issue #84), R13 in country-requirements.md, style.md layer count, unification.md.

Verified against the live DB: se_airports_* 190 rows at z10-z13; se_airport_points_*
42 at z8-z9 / 48 at z10-z13; new R119/R120 acceptance tests PASS; importer tiles
--check PASS for both layers at coarsest + finest zoom; decoded the z13 Arlanda
tile by hand (2 runways, name=Arlanda flygplats, class 1); real-browser CDP render
at z11-13 shows Arlanda/Landvetter/Sturup labels + runways; make acceptance-all:
ismap 31/31, semap 36/36, plmap 29/29, fimap 34/34, world 14/14; make build and
make test pass.
Poland's `airports` (+ derived `airport_points`, R140) from OT_KUKO_A, rodzaj
'lotnisko lub lądowisko' (KUKO02) — the R13 line for Poland, the same
runway-polygon shape Iceland's and Sweden's airports come from. The KUKO areas
are an overlay over the PTKM transport-surface coverage, so they draw as their
own layer on top of the transport fill rather than being carved into cover: the
carve is issue #118's declared overlay-carve staging kind (still open), and the
issue body offers the standalone option. airport_class comes from TYPLOTNISKA
('port lotniczy' → 1, else 2) — the lotnisko register tier a scheduled service
operates from; IDIATA was measured and rejected (registration numbers and wrong
codes, e.g. '4E' for Chopin). The name is the source's NAZWA.

R6 check first (issue step 1): three county packages inspected end to end (1465
Warszawa, 1206 krakowski, 1261 m. Kraków) confirmed the class in every delivery
and measured the ladder; the "PTKM cannot split airports out" note was about the
fetch list, not the database. BDOT10K_CLASSES gains OT_KUKO_A/P and the marker
widens to pt-sw-sk-oikm-oipr-skpp-kuk, so the 380 county zips re-pull on the next
make fetch-bdot10k (~25 GB, measured 65 MB avg per county zip; the old "~10 GB"
figure predates the SW*/SK*/OIKM/OIPR/SKPP/KU* widening).

Verified against the live DB on the three R6 counties (their KU* files are in the
shared data dir): make build/test green; config-check OK; make acceptance green
(pl: 34 tests, 33 passed, 0 failed, 1 skipped — R105 needs pl_kuko_p, which only
loads on a full import); five new acceptance tests (R6 population, R119 x2,
R120 x2) all PASS; tiles --check (R121) PASS for both new layers; style validates;
real-browser render over CDP shows the airports_pl fill and Chopin label at z11
and the class-1-only labels at z9. The national import awaits the widened fetch —
see run/issues/issue-106.md (blocked on the ~25 GB data re-pull per run rules).
Finland's airports from the already-fetched `lentokenttaalue` layer in MTK-muut
(835 grounds polygons, no fetch change). The `fi` tile source appears for the
first time — every Finland layer was shared until now — with the same pair that
brought `se` back in #103 and `pl` in #106.

The airports layer draws all 835 areas (runways + grounds, the whole-complex
shape Poland's KU* gives). kohdeluokka is the area-type ladder (32411/32412
paved/unpaved runways, 32415-32418 other airport / other air-traffic areas), but
it does not carry a scheduled/other tier — a paved runway is a kohdeluokka, not
a traffic class, and every named airport has exactly one runway area (measured;
Joensuu has both). The tier comes from the register's 32401 traffic-area names:
the survey prints its airports as LENTOASEMA and its airfields as LENTOKENTTÄ /
KEVYTLENTOPAIKKA — the Finnish analogue of Poland's port-lotniczy ladder — so
airport_class 1 = the register names it lentoasema (26 airports: all 21
scheduled-service airports plus Halli, Utti, Malmi, Mikkeli, Varkaus), else 2.

Names are the register join (R92): 32401 label within 500 units (the terminal
sits on a building footprint or a grounds hole — measured 0-127 m outside the
nearest area, so strict containment would leave Helsinki-Vantaa and the big
airports unnamed), Finnish preferred, biggest font first, longer name on a font
tie (Kokkola-Pietarsaari's KRUUNUPYYN LENTOASEMA ELI fragment loses to the full
name). The 32401 class also carries harbour names; the join filters the name
text to the airport vocabulary. 32401 joins the shared R94 casing pass so the
labels come out cased (one copy of the rule); the register has no cased twin for
the big airports, so the hyphenated genitives render first-letter-cased
(Helsinki-vantaan lentoasema) — the register's own convention, documented.
GENBÖLEN LENTOKENTTÄ is the one register name 13 km from any grounds (source
gap). airport_points derives per R140: one centroid per named airport, z9 keeps
class 1, 88 labels.

Importer fix this exposed: staging builds now end with ANALYZE. A query-kind
staging table reading a just-loaded load-kind table plans on no statistics
(autoanalyze fires a minute after a bulk load), and the planner's no-stats guess
for the fi_paikannimi_cased rebuild was a nested loop over the 1.17M-row
register — 551k x 308k lower() comparisons, an hour-long build vs ~5 s once
analyzed. This would have hit any full import-fi, not just this layer's rebuild.

Verification: make build/test; --layer import 22 s with all layer acceptance
tests green; make acceptance rc 0 across all configs (fimap 40/40); tile-check
R121 PASS on both layers; CDP render over Helsinki-Vantaa shows 77 polygons +
"Helsinki-vantaan lentoasema" at z10 and only class-1 labels at z8/z9, Qwen2.5-VL
corroborates. Acceptance tests added: R6 populated, R119 per-zoom, R120 no-NULL
class / no-invalid / class-1-exactly-lentoasema, R94 casing.
# Conflicts:
#	conf/mapsrv.yaml
#	docs/country-requirements.md
#	docs/style.md
#	docs/unification.md
#	html/style.json
# Conflicts:
#	conf/mapsrv.yaml
#	docs/style.md
#	html/style.json
airports and the derived airport_points are now shared layers: contracts in
conf/common.yaml shared_layers: (airports z10-13, airport_points z8-13, both
filter_only, attrs geom/name/airport_class), one country-partitioned table
map_<layer>_<z>_<cc> per country, one MVT function (zxy_map_airports /
zxy_map_airport_points) on the map source. All four countries already conformed
(class ladder 1/2, name, same zoom floors), so no country changed its data —
only the table it lands in. Iceland's airports renamed nafnfitju -> name to meet
the contract; each country's airport_points derivation now reads its own
map_airports_13_<cc> partition (R140, DAG keeps airports first).

This carries the three per-country imports (#146 se/#103, #147 fi/#110, #153
pl/#106): their data now renders through the shared source. Those issues stay
open for their data review; this PR is only the unification fold.

Style: airports + airport_labels read the shared map source; the per-country
style layers (airports_se/fi/pl, airport_labels_se/fi/pl) and per-country tile
sources (se, fi, pl) the three PRs added are deleted. conf/mapsrv.yaml sources
back to [map, is]; is keeps contours/buildings/peaks. se/pl/fi configs now
declare no source.

Nothing is DROPped: the old per-country tables and zxy_<cc>_* functions remain
as inert #12 orphans, per the project's established practice.

Verified live: per-country acceptance on the shared partitions (R6/R119/R120/R94
all PASS per country, world 14 PASS), tiles --check (R121 keys exactly
[name airport_class country]), decoded z13 tiles through zxy_map at Keflavík /
Arlanda / Chopin / Helsinki-Vantaa, real-browser CDP renders per country
(airport polygons + labels), gl-style-validate clean, make test + config-check
pass. Docs updated (style.md layer count 72->66, schema.md, requirements R13 +
inventory, unification, workstream-a).
Three review points, none of which changes Sweden's output (measured: 48 points,
42 class 1, before and after) — they make the derivation right for the sources
that will exercise it.

* `min(airport_class)`, not `max`. The ladder is 1 = scheduled, 2 = everything
  else, so max() demotes an airport to the tier of its weakest polygon. Sweden's
  class comes from the airport area and every runway of one airport agrees, but
  Poland's BDOT10k splits Wrocław-Strachowice and Lublin across a 'port lotniczy'
  and an 'inne lotnisko' polygon each, and max() drops both off the z9 filter.
  The aggregate has to be the one that survives a source disagreeing with itself.

* Group by (name, spatial cluster), the R91 idiom places uses, not by name alone.
  A name is the source's label, not an airport identity key. eps 5 000 web-
  Mercator units sits an order of magnitude above the widest legitimate multi-
  area airport (Arlanda's three areas, 2 684 units apart) and an order of
  magnitude below a real collision; measured over all four countries it splits
  exactly one group, in Poland.

* The unnamed areas do not "keep their runway polygons" below z10 — airports
  starts at z10, so they draw nothing at all at z8–z9. Ten of them carry an iata
  code (GVX, HLF, HUV, IDB, KSK, LDK, ORB, OSK, SOO, SQO), so the coarse-zoom set
  is the 42 labelled scheduled airports, not all 52. Recorded in the layer
  comment and docs/country-sweden.md; every major airport is labelled.
No change to Finland's output (measured: 88 points, 26 class 1, before and
after) — the derivation is made right for the sources that will exercise it,
and the comment that got the reasoning wrong is corrected.

* `min(airport_class)`, not `max`. The ladder is 1 = scheduled, 2 = everything
  else, so max() demotes an airport to the tier of its weakest polygon. The old
  comment claimed the derivation "takes max(airport_class), so the label tier
  comes out right" — that is not why it came out right. Finland's class is a
  pure function of `name` and the grouping is by name, so every row in a group
  already agrees and the aggregate cannot change the answer. Poland's BDOT10k
  does disagree with itself, and there max() drops Wrocław-Strachowice and
  Lublin off the z9 filter.

* Group by (name, spatial cluster), the R91 idiom places uses, not by name
  alone. eps 5 000 web-Mercator units; Finland's grounds areas touch (23 units
  apart at closest approach, the tightest of the four countries), so nothing
  splits here.
Two real defects and one piece of dead weight.

* Wrocław-Strachowice and Lublin were missing from z8–z9. The ladder runs
  1 = scheduled, 2 = everything else, so the *lowest* number is the best tier —
  but airport_points aggregated with max(), which takes the weakest polygon.
  BDOT10k splits both airports across a 'port lotniczy' area and an 'inne
  lotnisko lub lądowisko' area, so both came out class 2 and the style's z9
  airport_class = 1 filter dropped them: Poland drew 15 scheduled airports at
  coarse zoom where it has 17, missing the country's 5th-busiest. min() is what
  the filter is actually asking for.

  A new R120 test pins the ladder's meaning against the source rather than its
  range — every named 'port lotniczy' must have a class-1 point, a missing point
  failing too. Measured: 17 names, 0 demoted with min(), 2 with max(). The old
  R120 could not catch this; airport_class was never NULL and always in (1,2).

* 'Aeroklub Koszaliński' is two airfields 46 541 web-Mercator units apart, and
  NAZWA is sometimes the operator's name rather than the airport's, so grouping
  by name alone gave the pair one marker (area-weighted onto the larger field —
  the smaller one silently lost its label). Group by (name, spatial cluster)
  instead, the R91 idiom places uses, eps 5 000 units: an order of magnitude
  above the widest legitimate multi-area airport in any country (Arlanda's
  three areas at 2 684; Poland's own worst is Iwonicz at 48) and an order of
  magnitude below this collision. Measured over all four countries it splits
  exactly this one group — pl 139 names → 140 points, is/se/fi unchanged.

* pl_kuko_p was fetched, extracted, staged and covered by the R105 non-empty
  test, and read by nothing: airport_points derives its label point from the
  areas (R140), so the point class was never going to be reconciled with them.
  Dropped from BDOT10K_CLASSES, the staging block and R105. The marker keeps
  its -kuk suffix on purpose — narrowing the class set is always satisfiable
  from a disk holding the wider one, and renaming it would force the 25 GB
  re-pull that only widening needs. R105's "all 24" count was already stale at
  26 when the KU* pair landed; it is 25 now and says so.
; Conflicts:
;	conf/semap.yaml
; Conflicts:
;	conf/fimap.yaml
; Conflicts:
;	conf/plmap.yaml
The fold made airports shared but left four copies of its checks and four
copies of its derivation. Both are now one, and unifying the second is what
found the defect.

THE TESTS. R119 and the range half of R120 were pasted four times, each naming
its own partitions ('map_airports_10_is', …_se, …_pl, …_fi). Four copies drift,
and a fifth country gets them only if it remembers to paste them. They are now
two catalogue queries on each contract in conf/common.yaml — the pg_inherits
idiom country_borders already uses, covering whatever countries exist — plus a
per-country aggregate for the attribute checks. This is the split
docs/importer-cli.md already documents: "an invariant of the shared table,
across every country" belongs on the contract, "that country's own data" stays
with the country. Each country keeps exactly the claim that is its own:

  is  every runway is named (true of no other country's source)
  se  every name is the ANLTX label inside its own area
  pl  no invalid polygon; every 'port lotniczy' is class 1 in airport_points
  fi  no invalid polygon; class 1 is exactly the lentoasema-named areas; R94

THE DERIVATION. All four countries now run the identical airport_points query,
and writing it once exposed that max() over the class ladder was wrong: the
ladder is 1 = scheduled, 2 = everything else, so max() demotes an airport to the
tier of its weakest polygon. Poland's BDOT10k splits Wrocław-Strachowice and
Lublin across a 'port lotniczy' and an 'inne lotnisko' area each, so both were
class 2 and the z9 filter dropped them — 15 scheduled airports drawn at coarse
zoom where Poland has 17. Iceland, Sweden and Finland agreed by luck, not by
construction, and nothing compared the four queries until they had to become
one. The grouping gains a spatial cluster for the same reason (a name is a
label, not an identity key; 'Aeroklub Koszaliński' is two airfields 46 km
apart). The reasoning and the measurements live on the contract.

Verified on the live database: all four countries reimported, 165 acceptance
tests pass across the five configs, and the shared tiles still render for every
country at z8 with no null tiles. pl 139 → 140 points and 15 → 17 class 1;
is/se/fi unchanged at 67/13, 48/42, 88/26.
art merged commit 5724c49cca into main 2026-08-17 22:08:30 +00:00
art deleted branch issue-149-shared-airports 2026-08-17 22:08:30 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
art/ismap!154
No description provided.