diff --git a/.cursor/rules/projects/nucleos-eleitorais.mdc b/.cursor/rules/projects/nucleos-eleitorais.mdc
index 7e4eb6a0..9ea2f67b 100644
--- a/.cursor/rules/projects/nucleos-eleitorais.mdc
+++ b/.cursor/rules/projects/nucleos-eleitorais.mdc
@@ -7,6 +7,7 @@ alwaysApply: false
## Status
+- **B8+ entregue em código (2026-07-27):** os quatro débitos do `/simplify` do B8 F2, e o achado central mudou de dono. **F1 — a alavanca não era a que o plano dizia.** O plano tratava "escala de chão" como algo implementado via dígitos de quantização; medindo o re-snap do artefato commitado para grades mais grossas, quantização sozinha quase não corta: ~12 m → 8.990 pontos (99% do original), ~25 m → 8.164, ~50 m → 6.219, e **mesmo na grade da malha estadual (~103 m) → 3.849 pontos, ainda 203/feature** — ~9× o irmão. Quem manda é o **limiar absoluto de Visvalingam**, que o plano citava entre parênteses. Então a política nasceu invertida: o peso absoluto **em m² de chão** é a política, os dígitos são derivados do bbox de cada topologia. `scripts/lib/topology.mjs` (**primeiro módulo de `scripts/lib/` — o B5 F2 pousa nele, não abre um segundo**) expõe `SIMPLIFY_TOLERANCE_M2` por malha, `GROUND_GRID_METRES = 102.82`, `simplifyToGroundScale`, `quantizeToGroundGrid` e `describeGroundScale`; `SIMPLIFY_QUANTILE`/`QUANTIZE_DIGITS` morreram nos dois scripts. Resultado medido: as zonas caíram de **9.120 → 574 pontos de arco (480 → 30,2/feature) e 72.310 → 7.687 bytes**; `bahia-municipalities` saiu **byte-idêntico** (a política foi semeada no valor histórico dele); territórios mudou **1 byte** (a grade passou de 102,730 para 102,822 m ao ser derivada do bbox em vez de um `1e4` fixo). **Três fatos para ninguém re-derivar:** (1) tolerância é **por malha de propósito** — a municipal (1,78 km²) chega a 17,9 pontos/feature nas zonas, mas come **5% da área de terra de Salvador (306 → 291 km²)**, que é justamente a grandeza com que o int prova que nenhum bairro foi descartado nem duplicado; as zonas ficaram em 0,06 km² e os territórios em 13,6 km² (dissolve da malha municipal, já vêm generalizados); (2) **a ordem importa** — quantizar antes de simplificar colapsa vértices em duplicatas e o `merge` posterior produz anéis quebrados (medido: Salvador dissolvendo para 24 km² em vez de 307); (3) a área das zonas pós-corte é **306,3 km²** (era ~324), dentro da janela de 280–360 km² que o int já tinha. `MAX_TOPO_BYTES` ficou e ganhou ao lado **`MAX_POINTS_PER_FEATURE = 60`** — bytes só pegam malha que ninguém simplificou (as zonas viviam a 10% do teto de bytes com 22× a densidade do irmão — 26× é a razão do passo de grade, não da densidade). `zoneNumber` saiu do artefato e do tipo. **F2:** `featureMapKey` passou a rodar sobre features **reais** das três malhas, cada uma no laço que já a varre inteira — 417 `codarea`, 27 `code`, 19 `slug` (a zona responde slug mesmo carregando o `ibgeCode` da cidade); a primeira escrita asseria a cidade dentro do laço das zonas, e o `/simplify` mostrou que isso era **uma** feature municipal asserida 19 vezes (as 19 ZE compartilham o código de Salvador) enquanto 416 municípios e 27 TIs nunca passavam por `featureMapKey`; o caso de precedência do unit usava `{ municipalitySlug, codarea }`, forma que **nenhuma malha produz** — caiu, e o comentário passou a declarar o invariante real: as três propriedades de chave são **mutuamente exclusivas**, e `ibgeCode` na malha de zonas deliberadamente não é chave. **F3:** `.catch()` na metade das zonas — e a precisão que o plano deixava otimista: como o bundle é keyed por slug, **Salvador não volta a pintar agregada**, volta como polígono sem dado e sem interação (não está em `scopedKeys`); a memoização da rejeição fica (é o estado de falha acionável do B14) e `status === 'error'` segue reservado à malha municipal. A ressalva de aproximação saiu do gate `!comparisonActive` e virou `
` condicionado a `bundle.hasZoneMunicipalities` — campo novo do contrato, derivado de `kind === 'zona'` no loader. O `/simplify` rejeitou as duas alternativas: um `isZoneMapKey` no cliente (segunda codificação da regra de `mapKeyForMunicipality`, em espaço negativo) e `zoneBreakdown.length > 0` (recria o acoplamento que o fill-in da lista de zonas vai deletar); com o campo próprio, o fill-in só apaga o `
` + `zoneBreakdown`. **F4:** `getTerritoryFeature`/`getMunicipalityZoneFeature` deletados; `MunicipalityMapNavigation` colapsado em `string | undefined` e `MunicipalitiesByMapKey` em `Record` (com o tipo morreram o helper, o `useMemo` que só existia porque ele alocava por chamada, o `| null` do `MapFeatureReadout` e **435 strings no payload RSC de toda visita ao Início**); `polygonRingsOf` exportado; helpers de geometria retipados em `PolygonalFeature` (o requisito real, em vez de `BahiaGeometryFeature` que arrasta `GeoJsonProperties`, ou seja `any`), mais `BahiaFeature
` e `BahiaMeshFeature`. **Um item do plano foi rejeitado por medição:** `city`/`zoneNumber` de `MunicipalityZoneNeighborhoodEntry` **ficam** — nenhum runtime os lê, mas os dois entram nas linhas hasheadas por `canonicalEvidenceRows` e são colunas do fixture de proveniência da RA 02/2017 (transcrição **independente** da resolução), então deletar enfraqueceria a verificação por ganho zero; só o `zoneNumber` do **artefato** saiu. Sem migration, collection, action ou `Consent`; e2e segue 436 paths / 435 interativos. Gate completo rodado bare contra o banco local (as falhas de e2e encontradas foram reproduzidas em árvore limpa — flakiness pré-existente já no ledger); Aikido **0 findings** nos arquivos editados (desta vez o scanner rodou; o exit code 2 do B8 F2 não se repetiu para o SAST). Plano as-built: [`escala-dry-pos-b8f2.md`](../../../docs/plans/escala-dry-pos-b8f2.md).
- **`users.roles` entregue em código (2026-07-27):** campo `roles` (`admin` | `editor`) em `users` — migration `20260727_032523_add_users_roles` (enum + tabela `users_roles` + backfill `admin` nas rows existentes). `isPayloadAdmin` exige papel `admin` (falha fechado se ausente/vazio); `hasPayloadPanelAccess` / `canManagePublishedContent` liberam editor em `/admin` + `post`/`tag`/`media`; `petition`/PII/campanha seguem admin-only; `canReadMunicipality` nega ator `users` sem admin (antes devolvia `Where` vazio e o editor via Municípios no sidebar). Unificação `users`+`campaignUser` **rejeitada** nesta sessão (25 FKs, isolamento estrutural→dado, janela de congelamento) — gatilho: Fase 2 white-label ou dor real de duas contas. Plano: [`roles-admin-payload.md`](../../../docs/plans/roles-admin-payload.md).
- **B8 F2 entregue em código (2026-07-26):** as 19 ZE de Salvador ganharam polígono próprio e o coroplético deixou de ser keyed por `codarea`. Antes, Salvador era **um** polígono carregando os votos da cidade inteira, então o mapa não respondia "qual pedaço de Salvador está fraco / é meu" — a única visão por zona era a lista textual do `zoneBreakdown`. **Fase 0 (prep S1+S3):** `municipalityZoneNeighborhoods` passou a autorar só `{ municipalitySlug, source, neighborhoods }` e hidrata `city`/`zoneNumber` de `getMunicipalityCatalogEntry` no `entry()` (slug desconhecido ou não-`zona` falha no import); int novo de ordem de slugs vs catálogo. S2 (gerar TS do JSON) segue cortado — a curadoria ficou no script, não no catálogo. **Fase 1–2 (artefato):** `scripts/build-municipality-zone-geometries.mjs` (`pnpm build:municipality-zone-geometries`, `--report` só reconcilia) baixa/cacheia `BA_bairros_CD2022.zip` do geoftp do IBGE, parseia com **`shpjs`** (devDependency nova — reprojeta o SIRGAS 2000, o IBGE não publica GeoJSON de bairro), filtra `CD_MUN === '2927408'` (**170 polígonos**) e dissolve por zona pela RA 02/2017 do TRE-BA → `src/lib/geometries/bahia-municipality-zones.topo.json` (**72.310 bytes**, ~20 KB gzip, 19 features keyed por `municipalitySlug`), com submódulo `bahiaMunicipalityZoneGeometries.ts` + `loadMunicipalityZoneGeometryModule()` no padrão memoizado de B5 F1. **Reconciliação = 3 tabelas curadas no cabeçalho do script, não regex mais esperta:** `IBGE_TO_TRE_NEIGHBORHOOD` (7 aliases — compostos "Beiru/Tancredo Neves", CAB, ilhas), `TRE_NEIGHBORHOODS_MERGED_INTO` (Jardim Cruzeiro dentro de Vila Ruy Barbosa; o build **recusa** um merge que atravesse zonas) e `SPLIT_NEIGHBORHOOD_ZONES` (Periperi, que a resolução corta na Rua das Pedrinhas, vai **inteiro** para a ZE 17 — o bairro é o átomo geométrico). Atribuição em dois passes: nome da resolução, depois **maior fronteira compartilhada** para os 5 bairros que a RA nunca nomeia (Ilha Amarela, Dois de Julho, Chame-Chame, Horto Florestal, Mirantes de Periperi) — a regra foi **validada** contra os 4 que a resolução nomeia sob outro rótulo e reproduz a zona oficial nos 4. O build morre se sobrar polígono órfão ou bairro TRE sem polígono (hoje 170/170 → 19/19). **Fase 3 (re-keying):** map key = `kind === 'zona' ? slug : ibgeCode` (`mapKeyForMunicipality` + `buildMunicipalitiesByMapKey` em `municipalityMapNavigation.ts`); o bundle inteiro re-keyed (`territorialClassByMapKey`, `projectedValidVotesByMapKey`, `municipalitiesByMapKey`, `valuesByYear`, `values2026ByScenario`, `validVotesByYear`, `diffByYear`); os rollups pararam de acumular com `+=` porque cada map key agora é 1:1; `computeAggregateTerritorialClass` deu lugar a `computeMunicipalityTerritorialClass` (um slug por chave); `resolveMunicipalityMapNavigation` virou 1:1 e o ramo `kind: 'zones'` morreu junto com o scroll-anchor e a copy "toque de novo" do readout. **`competitiveRank` continua por cidade** (o artefato TSE só tem `federalRankByIbgeCode`): as 19 zonas dividem a posição da cidade, o que a legenda já afirmava — int novo pina que as 19 têm **uma** posição só. Per-ZE segue fora (gatilho: produto pedir posição dentro da zona). `buildMunicipalitiesByIbgeCode` sobrevive intacto — o href de lista do B14 ✓ é por cidade. **Fase 4 (mapa):** `BahiaMap` monta a camada de município a partir de **duas** malhas via `loadLayerFeatures`, e o polígono municipal de Salvador fica desenhado **por baixo** como base sem dado e sem pointer (`baseKeys`), para que um sliver de desacordo entre duas malhas simplificadas independentemente não abra buraco no contorno do estado; `keyPropertyForMode`/`featureKeyFromProperties` deram lugar a `featureMapKey` (`municipalitySlug ?? codarea ?? code` — as três nunca coexistem, então o argumento de modo sumiu); `fitMapToHighlights` passou a medir os **paths desenhados** (`pathByKeyRef`) em vez do módulo de geometria, que já não sabe sozinho de qual malha veio a chave, e `geometryModuleRef` foi apagado. Copy do painel: a linha morta "Zonas não têm polígono oficial — Salvador e **Camaçari** aparecem agregadas" (Camaçari saiu do modelo de zona na M1) virou o disclaimer de aproximação. **Dois fatos medidos, para ninguém re-derivar:** o polígono municipal de Salvador tem **~690 km²** e a soma das 19 zonas **~324 km²** — a diferença é a água da baía que os limites municipais encerram e a malha de bairros não desenha, então o int de área compara contra a área de **terra** (280–360 km²) e não contra o município; e centróide-dentro-de-outra-zona **não** é teste de sobreposição válido aqui, porque a ZE 16 é concava e envolve a ZE 14 (o centróide da 16 cai na 14) — a garantia de não-sobreposição é estrutural (cada bairro é atribuído a exatamente uma zona) mais a soma de áreas. Testes: int de contrato (19 features, slugs == catálogo, budget 600 KB, centróide de cada zona dentro do polígono municipal), unit de `featureMapKey`, e2e `campaignZoneMap.e2e.spec.ts` (436 paths / 435 interativos — o único não-interativo é a base de Salvador — readout "Salvador — ZE N" e clique abrindo `/campanha/municipios/salvador-ze-N`). **`/simplify`:** comentário de `NearbyMunicipalityResolution.zoneCity` que dizia "sem polígonos de zona (B8 F2)" corrigido (os polígonos passaram a existir nesta entrega; o card **deliberadamente** continua na lista filtrada — débito aberto, não efeito colateral); duas asserções do int de bairros que viraram tautologia com a hidratação da Fase 0 (comparavam `city`/`zoneNumber` com o catálogo de onde foram copiados) removidas, apontando para o teste de fixture que checa contra a transcrição independente; e o script parou de re-indexar geometrias simplificadas por **nome** de bairro (o irmão `build-bahia-geometries.mjs` usa `codarea`, único por construção) — hoje são 170 nomes distintos em 170 polígonos, mas um nome repetido em malha futura colapsaria dois polígonos silenciosamente num artefato commitado; passou a haver `id` próprio, e o rebuild saiu **byte-idêntico** (sha256 `1dd0d629…`). Sem migration, sem collection, sem action, sem Consent. **Gate:** tsc/lint/format/knip/`check:cycles`/unit+int/e2e/build rodados; **Aikido não fechou** — o scanner MCP responde Opengrep exit code 2 em **qualquer** entrada (inclusive um arquivo-probe trivial de uma linha), então os "4 findings" que ele reportou são artefato da execução quebrada e não achados atribuíveis; o feed do Aikido não tem nada deste repo. SCA do `shpjs` também pendente. **Relatórios do `/simplify` chegaram depois do merge** e o que sobrou virou o fill-in **B8+** ([`escala-dry-pos-b8f2.md`](../../../docs/plans/escala-dry-pos-b8f2.md)), aberto por uma medição que contradiz a intuição de "malha pequena, artefato pequeno": as 19 zonas têm **9.120** pontos de arco contra **9.139** da malha de **todos** os 417 municípios da Bahia (480 vs 22 pontos/feature; Salvador é um `Polygon` de **35** pontos na malha municipal). A causa não é a malha de bairros ser detalhada — é que `QUANTIZE_DIGITS = 1e4` e `SIMPLIFY_QUANTILE = 0.35` foram copiados verbatim do script irmão e **os dois são relativos à própria topologia**: a quantização é uma grade sobre o bbox do arquivo, e o de Salvador é ~26× mais estreito, o que dá **~3,9 m** de resolução contra ~103 m no estado, num mapa que para em `maxZoom: 10`. Consequência para quem for consertar: o que deve ficar compartilhado entre os dois scripts é a **escala de chão**, não a contagem de dígitos — extrair as constantes como estão (o que o revisor de reuse pediu, sem essa medição) cimentaria o defeito e lhe daria autoridade de política. Os outros três: nada roda `featureMapKey` sobre um feature **real** fora do e2e, então as três escritas da map key podem divergir e pintar cinza sem erro em lugar nenhum; o `Promise.all` das duas malhas somado à memoização da rejeição fez de um chunk de 19 polígonos um ponto único de falha do mapa inteiro (antes a malha municipal sozinha bastava); e a ressalva "é aproximado, não é o limite oficial do TSE" está pendurada na condição de render da **lista** (`!comparisonActive`), então desaparece no modo comparação enquanto a malha aproximada continua pintada. Plano: [`poligonos-pracas-zona.md`](../../../docs/plans/poligonos-pracas-zona.md).
- **B39–B42 registrados (2026-07-26, lote roadmap-items):** sessão "Lembrar de mim" (**B39**, ~0,5d, não cortável — default hoje 2 h); login biométrico WebAuthn (**B40**, soft B39, cortável); scroll horizontal + sticky coluna Município (**B41**, espelha TerritoryList/B21); polimento mobile lista municípios (**B42** — Drawer Tendência/Assessores no padrão B26 + card compacto). Planos: `lembrar-de-mim-sessao-campanha.md`, `login-biometrico-campanha.md`, `scroll-horizontal-lista-municipios.md`, `polimento-mobile-lista-municipios.md`. Dedup do lote: drawers + card mobile mesclados em B42; auth fatiado B39/B40.
diff --git a/AGENTS.md b/AGENTS.md
index 1628142b..fda6eb7e 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -74,6 +74,8 @@ Backlog consolidado (bloqueadores, site, campanha, white-label): [`docs/roadmap.
**Recently resolved (2026-07-26):** **B8 F2** Polígonos dos Municípios-zona de Salvador (ZE 1–19) — Salvador used to be **one** polygon carrying the whole city's votes, so the choropleth could not answer "which piece of Salvador is weak, or mine"; the only per-zone view was the textual `zoneBreakdown`. Two halves shipped. **(1) The mesh:** a new committed artifact `src/lib/geometries/bahia-municipality-zones.topo.json` (72,310 bytes, ~20 KB gzip, 19 features keyed by `municipalitySlug`) built by `pnpm build:municipality-zone-geometries` — see "Campaign map geometries" for the source, the parser and the three curated reconciliation tables. The interesting part is not the dissolve, it is that **the curation lives in the script, declared line by line with its evidence, and the build fails closed**: an orphan polygon or a TRE neighbourhood with no polygon aborts it, so "170/170 → 19/19" is a tested invariant. Periperi, which the resolution splits mid-street between two ZE, goes **whole** to ZE 17 — the neighbourhood is the smallest geometry available and cutting a polygon from a prose description of a street was the rabbit hole the plan already refused. The 5 polygons the resolution never names are assigned by **longest shared boundary**, and that rule was _validated_ against the 4 it names under another label before being trusted. **(2) The key:** the choropleth is no longer keyed by `codarea` but by a **map key** (`mapKeyForMunicipality`: slug for `kind === 'zona'`, `ibgeCode` otherwise) — see the "Map" bullet in the Município model for the contract, the non-interactive Salvador base and the per-city rank limitation. Because each map key now maps to exactly one catalog entry, the rollups stopped accumulating with `+=` and `computeAggregateTerritorialClass` gave way to `computeMunicipalityTerritorialClass`; `resolveMunicipalityMapNavigation` became 1:1, and with it the `kind: 'zones'` branch, its "toque de novo" readout copy and the panel's scroll-anchor all died. `buildMunicipalitiesByIbgeCode` survives untouched: B14's list href is per city on purpose. **Two measurements, so nobody re-derives them:** Salvador's municipal polygon is **~690 km²** against **~324 km²** for the 19 zones summed — the difference is the bay water the municipal limit encloses and a neighbourhood mesh never draws, which is why the int test asserts a **land**-area range instead of a ratio against the município (the first version demanded ≥95% and was comparing land to land+water); and centroid-inside-another-zone is **not** a valid overlap check here, because ZE 16 is concave and wraps ZE 14, so 16's centroid legitimately falls in 14 — non-overlap is guaranteed structurally at build time plus the area sum. New e2e `campaignZoneMap.e2e.spec.ts` pins 436 paths / 435 interactive (the one non-interactive path is Salvador's base) and that a zone opens `/campanha/municipios/salvador-ze-N`. No migration, no collection, no server action, no `Consent`. **Open debts with triggers (in the plan, not silent):** the B14 "Onde estou" card still routes Salvador to the filtered list even though resolving the exact ZE is now possible, and per-ZE competitive rank needs a new dimension in the TSE artifact. Plano: [`docs/plans/poligonos-pracas-zona.md`](docs/plans/poligonos-pracas-zona.md).
+**Recently resolved (2026-07-27):** **B8+** Escala e DRY pós-B8 F2 — the four `/simplify` debts of the ZE polygons, and the headline finding changed owner. The plan called the target "ground resolution implemented via quantization digits"; measuring the committed artifact re-snapped to coarser grids showed quantization alone barely cuts (~25 m → 90% of the original vertices, and **even on the state mesh's ~103 m grid the zones stayed at 203 points/feature**, ~9× the sibling). The lever is the **absolute Visvalingam threshold**, so the policy was inverted: absolute weight in **m² of ground** is the policy, digits are derived per topology. See the ground-scale policy bullet under "Campaign map geometries" for the numbers that matter; the outcome is the zone mesh at **574 arc points / 30.2 per feature / 7,687 bytes** (from 9,120 / 480 / 72,310), `bahia-municipalities` **byte-identical**, and `bahia-identity-territories` off by one byte because its grid is now derived from its bbox (102.730 → 102.822 m). `zoneNumber` left the artifact and the type. The other three phases: `featureMapKey` is now exercised on real features of all three committed meshes, each inside the loop that already sweeps it whole (417 `codarea` + 27 `code` + 19 `slug`) — the `/simplify` caught the first version asserting the city inside the zone loop, which covered **one** municipal feature nineteen times because the 19 ZE share Salvador's code — and the synthetic precedence test died (the invariant is real — see the Map bullet); a zone-chunk failure degrades instead of killing the map (with the reason logged, since a ChunkLoadError and a corrupt artifact are not the same event), and the approximation caveat left the `!comparisonActive` gate for a paragraph conditioned on the new bundle field `hasZoneMunicipalities`, published by the loader from `kind === 'zona'` — the `/simplify` rejected deriving it on the client from the key's shape (a second encoding of `mapKeyForMunicipality`, in negative space) and rejected gating on `zoneBreakdown`, which the zone-list fill-in deletes; and the delivery's orphans are gone — two accessors deleted, `MunicipalityMapNavigation` collapsed to `string | undefined`, `MunicipalitiesByMapKey` to `Record` (435 dead strings out of every Início RSC payload), `polygonRingsOf` exported, geometry helpers retyped on `PolygonalFeature`. **One planned deletion was rejected by measurement:** `city`/`zoneNumber` on `MunicipalityZoneNeighborhoodEntry` **stay** — no runtime reads them, but both feed the rows hashed by `canonicalEvidenceRows` and are columns of the RA 02/2017 provenance fixture (an independent transcription), so deleting them would weaken the verification for nothing. No migration, collection, action or `Consent`; e2e still 436 paths / 435 interactive. Plano: [`docs/plans/escala-dry-pos-b8f2.md`](docs/plans/escala-dry-pos-b8f2.md).
+
**Recently resolved (2026-07-26):** **E12** Camada TI — extends the E17/B21 rollup (`territoryOverview.ts` + `loadTerritoryOverview.ts`) with E8 goal coverage (`central`), MAUP-safe regional capture (aggregate ratio Σ own votes ÷ Σ field ceiling — never the mean of municipal ratios; median, min–max, named critical municipality and beacon), and aggregated territorial class via `computeAggregateTerritorialClass` (same rule as B13 for TI groups). Staff surface: three new columns on `/campanha/territorios` (Cobertura, Captura, Classe) with B22 header descriptions and sorts `cobertura`/`captura`/`classe`; municipality detail gets intra-TI benchmark T4 on `MunicipalityGoalAccountCard` (`territoryIntraCaptureBenchmark.ts` — Salvador zone slugs compare among the 19 zones, other Metropolitano peers among RMS municipalities). Two E18 concepts (`captura-regional`, `benchmark-intra-ti`). v1 cuts kept: no `?group=territorio` on the municipality list, no TI map mode. No migration. Plano: [`docs/plans/camada-territorios-identidade.md`](docs/plans/camada-territorios-identidade.md).
**Recently resolved (2026-07-26):** **B24** Auto-save + justificativa no popover de Tendência — `MunicipalityListTrendControl` grava sozinho via `POST /campanha/municipios/political-trend` (status ~150 ms, nota 600 ms, flush blur/fechamento), `Textarea` de justificativa no Popover, sem `revalidatePath` da lista; `/editar` mantém submit explícito. Plano: [`docs/plans/autosave-tendencia-lista-municipios.md`](docs/plans/autosave-tendencia-lista-municipios.md).
@@ -159,7 +161,7 @@ The internal `/campanha` area is gated by its own authentication, deliberately k
- **Vote pledge asymmetry:** staff declare `declaredVotes` and record `estimatedVotes` (pessimistic/central/optimistic); leaders never see estimates. Aggregates use `estimated[S] ?? declared`, default `central` (`src/utilities/votePledgeData.ts`).
- **Demandas:** staff-only create/read (`canCreateCampaignDemand`); optional `leadership` provenance selected by staff. Escalated decisions: coordinator **or** candidate.
- **Dobradinhas:** `stateDeputy` entity + `municipality.stateDeputies` / `leadership.stateDeputies` hasMany; UI at `/campanha/dobradinhas`.
-- **Map:** staff dashboard (`/campanha`) loads `MunicipalityMapPanel`; `/campanha/municipios` is list/overview only. **Keyed by "map key", not `ibgeCode`** (B8 F2, 2026-07-26): `mapKeyForMunicipality` returns the `municipalitySlug` for `kind === 'zona'` and the `ibgeCode` otherwise, so each of Salvador's 19 ZE is painted, hovered and opened on its own from `bahia-municipality-zones.topo.json`. Every bundle field follows that key (`municipalitiesByMapKey`, `territorialClassByMapKey`, `projectedValidVotesByMapKey`, `valuesByYear`, …) and each key maps to exactly one catalog entry, so rollups assign instead of accumulating. Salvador's **municipal** polygon is still drawn, underneath, as a non-interactive base with no data (`baseKeys` in `BahiaMap`) — two independently simplified meshes do not close on the same coastline, and deleting it opened a gap in the state outline; being out of the key index, it cannot double-count or steal a hover. Feature→key resolution is `featureMapKey` (`municipalitySlug ?? codarea ?? code`). **`competitiveRank` is still per city:** the TSE artifact only carries `federalRankByIbgeCode`, so all 19 zones share the city's placement — which is what the legend already claims, and an int test pins it. Scales (B13): **quantis** (default), **padrão próprio (LQ)**, **posição no município**, **% dos válidos** (B11) and **Total (votos)**. The three relative ones are **discrete classes, never a continuous ramp** — the pure math lives in `src/lib/mapScaleClasses.ts` (quantiles degrade to 3 classes below 10 municípios and the legend says so; LQ is cut on the E10 anchors in `src/lib/territorialClassAnchors.ts`). Diverging red×blue stays exclusive to the compare mode, where it means "Solla × adversário" — do not reuse it for LQ. Quantiles are computed over the **user's access scope**, so an advisor sees his portfolio classed against itself. Rank is unavailable in 2026 (TSE data) and LQ in 2026 reuses the 2022 statewide standard, the same precedent `percentValid` set. An optional proportional-symbol layer sizes bubbles by projected valid votes (area ∝ value) and colours them by the E10 class. A class label never renders alone: the readout always spells out the reason.
+- **Map:** staff dashboard (`/campanha`) loads `MunicipalityMapPanel`; `/campanha/municipios` is list/overview only. **Keyed by "map key", not `ibgeCode`** (B8 F2, 2026-07-26): `mapKeyForMunicipality` returns the `municipalitySlug` for `kind === 'zona'` and the `ibgeCode` otherwise, so each of Salvador's 19 ZE is painted, hovered and opened on its own from `bahia-municipality-zones.topo.json`. Every bundle field follows that key (`municipalitiesByMapKey`, `territorialClassByMapKey`, `projectedValidVotesByMapKey`, `valuesByYear`, …) and each key maps to exactly one catalog entry, so rollups assign instead of accumulating. Salvador's **municipal** polygon is still drawn, underneath, as a non-interactive base with no data (`baseKeys` in `BahiaMap`) — two independently simplified meshes do not close on the same coastline, and deleting it opened a gap in the state outline; being out of the key index, it cannot double-count or steal a hover. Feature→key resolution is `featureMapKey` (`municipalitySlug ?? codarea ?? code`) — the three are **mutually exclusive** on the committed meshes, so it is a lookup over distinct names and not a precedence rule; the zone mesh also carries the city's `ibgeCode`, which is deliberately **not** a key property because all 19 zones share it. Since B8+ that contract is exercised on **real features of all three meshes** in `tests/int/bahiaGeometries.int.spec.ts` — over the full 417 / 27 / 19, not on hand-written literals and not on one city feature repeated per zone — and a failure of the zone chunk **degrades instead of killing the map**: `loadLayerFeatures` catches it and paints the state without the ZE (Salvador falls back to its non-interactive base polygon, not to an aggregated one — the bundle is keyed by slug), while `status === 'error'` stays reserved for the municipal mesh. **`competitiveRank` is still per city:** the TSE artifact only carries `federalRankByIbgeCode`, so all 19 zones share the city's placement — which is what the legend already claims, and an int test pins it. Scales (B13): **quantis** (default), **padrão próprio (LQ)**, **posição no município**, **% dos válidos** (B11) and **Total (votos)**. The three relative ones are **discrete classes, never a continuous ramp** — the pure math lives in `src/lib/mapScaleClasses.ts` (quantiles degrade to 3 classes below 10 municípios and the legend says so; LQ is cut on the E10 anchors in `src/lib/territorialClassAnchors.ts`). Diverging red×blue stays exclusive to the compare mode, where it means "Solla × adversário" — do not reuse it for LQ. Quantiles are computed over the **user's access scope**, so an advisor sees his portfolio classed against itself. Rank is unavailable in 2026 (TSE data) and LQ in 2026 reuses the 2022 statewide standard, the same precedent `percentValid` set. An optional proportional-symbol layer sizes bubbles by projected valid votes (area ∝ value) and colours them by the E10 class. A class label never renders alone: the readout always spells out the reason.
- **URLs:** `/campanha/municipios[/slug]`, `/campanha/dobradinhas`, `/campanha/liderancas[/id]`, `/campanha/organizacoes[/slug]`, `/campanha/demandas[/slug]`, `/campanha/atividades[/slug]`, `/campanha/apoiadores`, `/campanha/assessores` (coordinator/candidate), `/campanha/conceitos` (staff glossary), `/campanha/perfil`.
## Campaign supporters (C2)
@@ -186,9 +188,10 @@ Mobilization events / agenda backing the campaign's field operations (roadmap it
Static Bahia map foundation for future Leaflet surfaces (roadmap B2; UI is B3). No migration, collection, Consent, or server action — same static-data pattern as `bahiaTerritories` / `bahiaTseZones`.
-- **Artifacts (committed):** `src/lib/geometries/bahia-municipalities.topo.json` (~132 KB; Topology object `municipalities`, 417 features, `properties: { codarea, name }`), `src/lib/geometries/bahia-identity-territories.topo.json` (~15 KB; object `territories`, 27 features, `properties: { code, name }`) and — since B8 F2 (2026-07-26) — `src/lib/geometries/bahia-municipality-zones.topo.json` (~72 KB; object `municipalityZones`, **19** features, `properties: { municipalitySlug, name, zoneNumber, ibgeCode }`), the Salvador ZE mesh. Soft size budget in tests: ≤ ~600 KB each.
+- **Artifacts (committed):** `src/lib/geometries/bahia-municipalities.topo.json` (~132 KB; Topology object `municipalities`, 417 features, `properties: { codarea, name }`), `src/lib/geometries/bahia-identity-territories.topo.json` (~15 KB; object `territories`, 27 features, `properties: { code, name }`) and — since B8 F2 (2026-07-26) — `src/lib/geometries/bahia-municipality-zones.topo.json` (**~7.7 KB** since B8+ recalibrated it; object `municipalityZones`, **19** features, `properties: { municipalitySlug, name, ibgeCode }`), the Salvador ZE mesh.
+- **Ground-scale policy (B8+, 2026-07-27):** how much detail a committed mesh keeps is declared **in ground units** in `scripts/lib/topology.mjs` (the first module in `scripts/lib/` — **B5 F2** lands there rather than opening a second one), and both build scripts consume it. Two knobs, both meaningless as raw numbers: `topojson-simplify` can pick its Visvalingam threshold as a **quantile of the mesh's own triangles**, and `quantize(topo, n)` lays an `n`-step grid across **the topology's own bbox** — so the `0.35` and `1e4` copied verbatim between the two scripts cut Salvador at ~0.6 m² and ~3.9 m while cutting Bahia at ~1.78 km² and ~103 m. The zone mesh shipped at **480 points/feature against the state mesh's 21.9** because of it. Now `SIMPLIFY_TOLERANCE_M2` states a tolerance per mesh in **square metres of ground** (with the density it buys measured in the comment) and quantization digits are derived per topology from `GROUND_GRID_METRES`. Two things not to re-derive: quantization alone barely helps (even on the state grid the zones stayed at 203 points/feature — the absolute weight is the lever), and **simplify before quantize**, because quantizing a dense mesh to a ~100 m grid collapses vertices into duplicates and a later `merge` produces broken rings (measured: Salvador dissolving to 24 km² instead of 307). Tolerances differ per mesh on purpose: the municipal tolerance reaches 17.9 points/feature on the zones but sheds 5% of Salvador's land area (306 → 291 km²), which is the quantity the int spec uses to prove no neighbourhood was dropped or double-counted. Guard: `MAX_POINTS_PER_FEATURE = 60` in `tests/int/bahiaGeometries.int.spec.ts`, next to the byte budget (soft, ≤ ~600 KB each) — bytes only catch a mesh nobody simplified at all.
- **Code table:** `src/lib/bahiaMunicipalityCodes.ts` — canonical municipality name → IBGE 7-digit `codarea`, plus `codeForMunicipality` / `municipalityForCode`. Fixture `tests/fixtures/bahia-municipality-codes.official.json` + int tests for bijection/coverage.
-- **Runtime helpers:** `src/lib/bahiaGeometries.ts` — `getMunicipalityFeature` / `getTerritoryFeature` / `getMunicipalityZoneFeature`, typed topologies, feature arrays. TopoJSON→GeoJSON decode is LAZY (dynamic import via `loadMunicipalityGeometryModule` / `loadMunicipalityZoneGeometryModule`; B5 F1 done) — the default `/campanha` server graph never pays it. Shared feature types live in `bahiaGeometriesTypes.ts`; geometry math that must accept any of the three meshes (point-in-polygon, centroid) takes `BahiaGeometryFeature`.
+- **Runtime helpers:** `src/lib/bahiaGeometries.ts` — typed topologies, feature arrays and `getMunicipalityFeature` (the territory and zone accessors were deleted by B8+: only the int specs used them, and a `Map` built in one line is what a spec wants). TopoJSON→GeoJSON decode is LAZY (dynamic import via `loadMunicipalityGeometryModule` / `loadMunicipalityZoneGeometryModule`; B5 F1 done) — the default `/campanha` server graph never pays it. Shared feature types live in `bahiaGeometriesTypes.ts`: `BahiaFeature
` is the one spelling of `Feature`, `BahiaMeshFeature` is what the map layer receives from any of the three meshes, and geometry math (point-in-polygon, centroid, area, bounds — all built on the exported `polygonRingsOf`) takes **`PolygonalFeature`**, which declares the actual requirement instead of dragging `GeoJsonProperties` (i.e. `any`) through the signature.
- **Territory polygons:** dissolved from IBGE municipality meshes via `bahiaIdentityTerritoryRecords` (`topojson` `merge`), not the IDE Bahia shapefile (IDE remains provenance/validation reference only).
- **Rebuild (Salvador zones):** `pnpm build:municipality-zone-geometries` (`scripts/build-municipality-zone-geometries.mjs`; `--report` reconciles without writing) downloads IBGE `BA_bairros_CD2022.zip` from geoftp, parses the shapefile with **`shpjs`** (devDependency — that cut is SHP-only, SIRGAS 2000), keeps `CD_MUN === '2927408'` (170 polygons) and dissolves neighbourhood→zone against **TRE-BA RA 02/2017** (`municipalityZoneNeighborhoods.ts`). Reconciliation is **curated data in the script header**, not cleverer matching: an alias table, a table for TRE neighbourhoods with no polygon of their own (the build refuses a merge that would cross zones), and a table for the one neighbourhood the resolution splits mid-street (it goes whole to one ZE — the neighbourhood is the atom). The 5 polygons the resolution never names are assigned by **longest shared boundary**, a rule validated against the 4 it names under another label. The build fails on an orphan polygon or a TRE neighbourhood with no polygon, so 170/170 → 19/19 is an invariant, not a hope. Same cache dir and the same "**does not touch the database**" guarantee as the sibling below.
- **Rebuild:** `pnpm build:geometries` (`scripts/build-bahia-geometries.mjs`) downloads IBGE Malhas (qualidade intermediaria) + Localidades, reconciles names with `canonicalizeMunicipalityName`, simplifies/quantizes, emits the artifacts above. Cache under `data/geometries/` (gitignored; override with `GEOMETRIES_CACHE_DIR`). **Does not touch the database** — no `assertLocalDatabase` / no Neon risk. Not part of `pnpm build` or `pnpm dev`. Details: `docs/plans/mapa-bahia-geometrias.md`. Scale/DRY follow-ups from `/simplify`: `docs/plans/escala-dry-pos-b2.md` (B5).
diff --git a/docs/plans/escala-dry-pos-b8f2.md b/docs/plans/escala-dry-pos-b8f2.md
index 429d4f60..8eb3b090 100644
--- a/docs/plans/escala-dry-pos-b8f2.md
+++ b/docs/plans/escala-dry-pos-b8f2.md
@@ -1,12 +1,54 @@
# Escala e DRY pós-B8 F2 (polígonos das ZE de Salvador)
-Status: rascunho
-Atualizado em: 2026-07-26
-Item do roadmap: [docs/roadmap.md](../roadmap.md) (Fill-ins abertos, **B8+**, fill-in de engenharia)
+Status: **entregue 2026-07-27** (as quatro fases; ver "Como foi entregue")
+Atualizado em: 2026-07-27
+Item do roadmap: [docs/roadmap.md](../roadmap.md) (**B8+ ✓**, fill-in de engenharia)
Impeccable: A — N/A (nenhuma superfície nova; F3 muda um parágrafo de copy e um estado de falha, o resto preserva o comportamento visível do B8 F2)
Appetite: ~0,75–1 dia eng; quatro fases independentes, nenhuma com migration, collection ou `Consent`; só F1 reescreve o artefato commitado
Responsável: —
+## Como foi entregue (as-built, 2026-07-27)
+
+As quatro fases entraram numa sessão, F1 primeiro. Duas correções ao plano vieram de medição, não de preferência, e estão registradas abaixo porque mudam o que a próxima pessoa deve acreditar.
+
+### F1 — a alavanca era o peso absoluto, não os dígitos
+
+O plano tratava o alvo como resolução de chão **implementada via dígitos de quantização**. Medindo o re-snap do artefato commitado para grades mais grossas, quantização sozinha quase não corta: ~12 m → 8.990 pontos (99% do original), ~25 m → 8.164 (90%), ~50 m → 6.219 (68%), e mesmo **na grade da malha estadual (~103 m) → 3.849 pontos, ainda 203/feature** — ~9× a densidade do irmão. A alavanca dominante é o limiar absoluto de Visvalingam, que o plano mencionava entre parênteses. A política inverteu a ordem: **o peso absoluto (em m² de chão) é a política; os dígitos são derivados do bbox de cada topologia por consistência.**
+
+`scripts/lib/topology.mjs` (primeiro módulo de `scripts/lib/` — **B5 F2** deve pousar nele, não abrir um segundo) declara `SIMPLIFY_TOLERANCE_M2` por malha, `GROUND_GRID_METRES = 102.82`, `simplifyToGroundScale`, `quantizeToGroundGrid` e `describeGroundScale`. `SIMPLIFY_QUANTILE` e `QUANTIZE_DIGITS` saíram dos dois scripts.
+
+| artefato | antes | depois |
+| ------------------------------ | --------------------------------- | -------------------------------------------- |
+| `bahia-municipalities` | 132.162 B · 9.139 pts · 21,9/ft | **byte-idêntico** (política semeada nele) |
+| `bahia-identity-territories` | 14.862 B · 1.210 pts · 44,8/ft | 14.861 B · 1.210 pts · 44,8/ft (−1 B) |
+| **`bahia-municipality-zones`** | **72.310 B · 9.120 pts · 480/ft** | **7.687 B · 574 pts · 30,2/ft** (−89% bytes) |
+
+Três coisas que a implementação aprendeu e deixou no comentário do módulo, para ninguém re-derivar:
+
+- **Tolerâncias são por malha de propósito**, agora lado a lado em unidades de chão. A tolerância municipal (1,78 km²) até chega a 17,9 pontos/feature nas zonas, mas come **5% da área de Salvador (306 → 291 km²)** — e a soma de áreas é justamente a asserção que prova que nenhum bairro foi descartado nem contado duas vezes. As zonas ficaram em 0,06 km²; os territórios em 13,6 km² (são dissolve da malha municipal, então já vêm generalizados).
+- **A ordem importa:** quantizar antes de simplificar colapsa vértices em duplicatas e o `merge` posterior produz anéis quebrados — medido: Salvador dissolveu para 24 km² em vez de 307.
+- O 1 byte dos territórios é a grade indo de 102,730 m para 102,822 m: os dígitos passaram a ser derivados do bbox para a grade pedida em vez de um `1e4` fixo.
+
+A área das zonas saiu em **306,3 km²** (era ~324), dentro da janela de 280–360 km² que o int já asseverava — medida, não presumida, como o plano exigia. O tripwire de bytes ficou e ganhou ao lado `MAX_POINTS_PER_FEATURE = 60`, a grandeza que a política controla. `zoneNumber` saiu do artefato e do tipo.
+
+### F2 — o invariante valia; caiu o teste sintético
+
+`featureMapKey` agora roda sobre features **reais** das três malhas commitadas, cada uma no laço que já as varre por inteiro: 417 municípios respondem `codarea`, 27 TIs respondem `code`, 19 zonas respondem `slug` **mesmo carregando o `ibgeCode` da cidade**. A primeira escrita asseria a cidade dentro do laço das zonas, e o `/simplify` pegou o furo: as 19 entradas compartilham o código de Salvador, então aquilo era uma feature municipal asserida 19 vezes enquanto 416 municípios e os 27 territórios nunca passavam por `featureMapKey`. O caso de precedência pinado no unit usava a forma `{ municipalitySlug, codarea }`, que nenhuma malha produz: caiu, e o comentário passou a declarar o invariante real (as três propriedades de chave são mutuamente exclusivas; `ibgeCode` na malha de zonas deliberadamente não é chave, porque as 19 o compartilham). Sem resolvedor único, como travado.
+
+### F3 — degrada e admite a aproximação em todo modo
+
+`loadLayerFeatures` faz `.catch()` na metade das zonas e segue com a malha municipal. A precisão que o plano deixava otimista: como o bundle é keyed por slug, **Salvador não volta a pintar agregada** — volta como polígono sem dado e sem interação, porque não está em `scopedKeys`. A memoização da rejeição fica (é o que dá ao B14 um estado de falha acionável) e `status === 'error'` segue reservado à falha da malha municipal. A ressalva de aproximação saiu do gate `!comparisonActive` e passou a ser um `
` condicionado a **haver ZE no escopo**. A primeira escrita derivava isso no cliente com um `isZoneMapKey` (um município é keyed por 7 dígitos; uma zona, pelo slug) e o `/simplify` a **rejeitou**: era uma segunda codificação da regra de `mapKeyForMunicipality`, agora em espaço negativo (qualquer chave sem 7 dígitos responde "zona"), e o servidor já conhece a resposta por `kind`. O gate é `bundle.hasZoneMunicipalities`, campo próprio do contrato preenchido no mesmo passe que monta `zoneBreakdown` — e **não** `zoneBreakdown.length > 0`, que recriaria justamente o acoplamento que o fill-in [remover-lista-zonas-mapa-inicio.md](remover-lista-zonas-mapa-inicio.md) vai deletar; assim ele só apaga o `
` + o campo do bundle.
+
+### F4 — deletado, colapsado e **um item rejeitado**
+
+Saíram `getTerritoryFeature` e `getMunicipalityZoneFeature` (os int specs montam o índice em uma linha). `MunicipalityMapNavigation` virou `string | undefined` e `MunicipalitiesByMapKey` virou `Record` — com o tipo, morreram o helper, o `useMemo` que só existia porque o helper alocava por chamada, o `| null` do `MapFeatureReadout` e 435 strings no payload RSC de toda visita ao Início. `polygonRingsOf` foi exportado (3º call site) e os helpers de geometria passaram a declarar o requisito real com `PolygonalFeature`, mais `BahiaFeature
` para as quatro grafias de `Feature` e `BahiaMeshFeature` para o que a camada do mapa recebe. As limpezas do script entraram (chave por alias num `Map` acima do passe 1, `polygonCount` sem branches inalcançáveis, `[await shp(buffer)].flat()`, o `url` que ninguém desestrutura, `push` em vez de copiar o array).
+
+**Rejeitado por medição, contra o plano:** deletar `city`/`zoneNumber` de `MunicipalityZoneNeighborhoodEntry`. É verdade que nenhum runtime os lê, mas os dois entram nas linhas hasheadas por `canonicalEvidenceRows` e são colunas do fixture de proveniência da RA 02/2017 — uma transcrição **independente** da resolução. Deletar enfraqueceria a verificação ou forçaria regerar um fixture de proveniência por ganho zero. **Ficaram**, e com eles o filtro `entry.city === 'Salvador'` no int. Só o `zoneNumber` do **artefato TopoJSON** saiu (F1 reescreveu o arquivo).
+
+### O que continua verdade
+
+Sem migration, collection, server action ou `Consent`. Contrato de URL, escalas e catálogo TRE inalterados. O e2e segue em 436 paths / 435 interativos (o não-interativo é a base municipal de Salvador). Os dois débitos de produto do B8 F2 (rank por ZE, ZE exata no "Onde estou") continuam abertos com gatilho no [plano do B8](poligonos-pracas-zona.md), e a decisão sobre o modo `territory` morto do `loadLayerFeatures` continua pertencendo ao **E12**.
+
## Dados → decisão → apresentação
- **Vou apresentar dados?** Não (N/A) — o lote é custo, coerência e honestidade de dados já entregues pelo B8 F2. F3 muda **um parágrafo** (a ressalva de aproximação, que hoje desaparece no modo comparação enquanto a malha aproximada continua pintada), não a métrica nem a forma.
@@ -46,10 +88,10 @@ A comparação que fecha o caso: **Salvador é um `Polygon` de 35 pontos na malh
- **A ressalva de aproximação pertence à malha, não à lista.** O parágrafo "é aproximado, não é o limite oficial do TSE" estava dentro do gate `bundle.zoneBreakdown.length > 0 && !comparisonActive`, mas o mapa divergente da comparação pinta Salvador zona por zona a partir da **mesma** malha aproximada. A ressalva foi pendurada na condição de render da lista em vez de na presença da malha na tela — e o rabbit hole que o próprio plano do B8 nomeia é "tratar polígono derivado como limite oficial". **Rejeitado:** duplicar a frase nos dois braços (duas cópias da mesma afirmação jurídica divergem na primeira revisão de copy). **Atualização 2026-07-26:** o fill-in [remover-lista-zonas-mapa-inicio.md](remover-lista-zonas-mapa-inicio.md) remove a lista `zoneBreakdown` inteira (pedido de produto pós-B8 F2). F3 **não** presupõe o `
`: quem landar primeiro coloca a ressalva atrelada ao escopo com ZE / presença da malha; o outro só ajusta.
- **i18n e naming** seguem o AGENTS.md: identificadores em inglês, strings visíveis em pt-BR.
-## Questões em aberto
+## Questões em aberto (resolvidas na entrega)
-- **Qual resolução de chão para as duas malhas?** **Opções:** (a) ~100 m nas duas, igualando a malha municipal de hoje (`QUANTIZE_DIGITS ≈ 380` nas zonas); (b) ~25 m nas zonas, aceitando nitidez até ~zoom 14 (`≈ 1500`), e 100 m no estado; (c) ~25 m nas duas (encarece a malha estadual, que é a que todo mundo baixa). **Recomendação:** (b) — o zoom útil de uma ZE é maior que o de um município do interior, e mesmo assim corta a densidade atual várias vezes; (a) é o corte máximo e vale se a medição pós-mudança mostrar que 1500 ainda dobra a camada.
-- **Deletar os dois acessores órfãos ou declará-los contrato do módulo?** **Opções:** (a) deletar `getMunicipalityZoneFeature` e `getTerritoryFeature`, com os specs montando o índice em uma linha; (b) manter e documentar como contrato uniforme dos três módulos de malha. **Recomendação:** (a) — o `getTerritoryFeature` perdeu o último consumidor de produção **neste commit** (quando `fitMapToHighlights` parou de consultar os módulos de geometria) e o knip não vê nenhum dos dois porque specs são entry points; a regra do repo é deletar o que a mudança orfanou. Se o produto quiser o contrato uniforme, ele volta de graça no 4º mesh.
+- **Qual resolução de chão para as duas malhas?** ~~Opções (a) ~100 m nas duas · (b) ~25 m nas zonas · (c) ~25 m nas duas.~~ **Resolvido: (a), ~100 m nas duas** (decisão do usuário na sessão de implementação), e a pergunta estava mal-posta: a **grade** é a mesma nas três malhas, mas o que controla densidade é a **tolerância de simplificação**, que é por malha. Ver "Como foi entregue → F1" — a tolerância municipal aplicada às zonas custaria 5% da área de Salvador, então elas têm a própria, declarada em m² ao lado das irmãs.
+- **Deletar os dois acessores órfãos ou declará-los contrato do módulo?** **Resolvido: (a), deletados.** Os int specs montam o índice em uma linha. Se o produto quiser o contrato uniforme, ele volta de graça no 4º mesh.
## Abordagem proposta
diff --git a/docs/plans/municipio-mais-proximo.md b/docs/plans/municipio-mais-proximo.md
index a23f1aab..7d3a5a10 100644
--- a/docs/plans/municipio-mais-proximo.md
+++ b/docs/plans/municipio-mais-proximo.md
@@ -138,7 +138,7 @@ Componentes:
- **Atalho também na lista `/campanha/municipios`.** Revisitar quando: evidência de uso no Início (campo pede o mesmo atalho na lista).
- **Lembrar última sugestão em `sessionStorage` para paint imediato.** Revisitar quando: critique acusar flash/vazio perceptível no card. _(Não acusou: o chunk de geometria costuma estar resolvido antes do fix chegar.)_
- **Atalho geo também para `leader`.** Permanece fora: liderança não sai do `LeaderContactsPanel`.
-- **Reusar `resolveMunicipalityMapNavigation` no branch `none|navigate|zones`.** Revisitar quando: um 3º chamador precisar do `zoneCount`/da entrada casada. Hoje a união existente descarta justamente o que o card precisa, então reusar significa alargar um contrato de que duas superfícies do mapa dependem para servir um caller — mais caro que as ~18 linhas duplicadas.
+- **Reusar a navegação do mapa no branch `inScope|zoneCity|outOfScope`.** Revisitar quando: um 3º chamador precisar do `zoneCount`/da entrada casada. Encerrado como reuso possível pelo **B8+** F4: `resolveMunicipalityMapNavigation` e sua união de estados morreram — o mapa lê `municipalitiesByMapKey[key]` direto, um `Record` que não carrega nada do que este card precisa.
- **Helper compartilhado para flags de sessão (`sessionStorage`).** Revisitar quando: nascer a 3ª flag. Hoje são duas (`campaignGeolocation` e `InstallPwaToast`) e elas **discordam de propósito** no fallback de leitura — em modo privado o geo suprime o prompt automático e o toast continua aparecendo —, o que é a maior parte do que o helper faria.
## Referências
diff --git a/docs/roadmap.md b/docs/roadmap.md
index 40a70971..571f7915 100644
--- a/docs/roadmap.md
+++ b/docs/roadmap.md
@@ -1,6 +1,6 @@
# Roadmap — Teqo
-Atualizado em: 2026-07-27 (**`users.roles` ✓** — `admin`\|`editor` em `users`, migration `20260727_032523_add_users_roles`, editor publica `post`/`tag`/`media`; unificação com `campaignUser` rejeitada · [plano](plans/roles-admin-payload.md); 2026-07-26 (**fill-in** remover lista "Municípios por zona eleitoral" do Início — pós-B8 F2 ✓ os polígonos tornam a lista textual redundante; dropar UI + `zoneBreakdown` do bundle; ressalva de aproximação fica na malha · [plano](plans/remover-lista-zonas-mapa-inicio.md); **B8 F2 ✓** polígonos das 19 ZE de Salvador — artefato `bahia-municipality-zones.topo.json` (72 KB) por dissolve bairro→zona do `BA_bairros_CD2022` do IBGE contra a RA 02/2017 do TRE-BA, com curadoria explícita e um passe de maior fronteira compartilhada validado; o coroplético passou a ser keyed por **map key** (`slug` na zona, `ibgeCode` no resto) e o polígono municipal de Salvador ficou como base sem interação por baixo, porque duas malhas simplificadas independentemente não fecham na mesma costa; `competitiveRank` segue por cidade (o artefato TSE só tem `federalRankByIbgeCode`) com int pinando o fato; desambiguar a ZE no card "Onde estou" do B14 ✓ virou débito com gatilho, não dependência — [plano](plans/poligonos-pracas-zona.md); **B8+** novo fill-in de engenharia com os quatro débitos do `/simplify` do B8 F2, cujos relatórios chegaram depois do merge — a malha de 19 zonas ficou com a mesma contagem de vértices da malha dos 417 municípios (as duas constantes de simplificação são relativas ao bbox e foram copiadas verbatim, o que vale ~3,9 m de grade em Salvador contra ~103 m no estado), a regra da map key está em três formas sem nenhum teste ligando artefato → `featureMapKey` → catálogo, uma falha de chunk nas zonas passou a derrubar o mapa inteiro, a ressalva de aproximação desaparece no modo comparação, e `getTerritoryFeature` perdeu o último consumidor de produção neste commit · [plano](plans/escala-dry-pos-b8f2.md); **B39–B42** registrados: sessão "Lembrar de mim" + login biométrico WebAuthn + scroll horizontal/sticky na lista de municípios + polimento mobile da mesma lista — [B39](plans/lembrar-de-mim-sessao-campanha.md), [B40](plans/login-biometrico-campanha.md), [B41](plans/scroll-horizontal-lista-municipios.md), [B42](plans/polimento-mobile-lista-municipios.md); **E12 ✓** camada TI — rollups MAUP, colunas Cobertura/Captura/Classe em `/campanha/territorios`, benchmark intra-TI no `MunicipalityGoalAccountCard`; [plano](plans/camada-territorios-identidade.md); **B36 ✓** coluna "Lideranças" em `/campanha/dobradinhas` — chips + Popover+Command + delta reuse da mutação B31; `LeadershipStateDeputyRelationCell` compartilhada (`direction`/`measureOverflow`); columns factory (não Context); casca `dobradinhas/formActions.ts`; `loadLeadershipOptions` + `leaderships[]` no row; [plano](plans/chips-liderancas-lista-dobradinhas.md); **B30 ✓** convite de completar cadastro por WhatsApp na lista de lideranças — `LeadershipInviteRowAction` (`UserPlusIcon`) na coluna `actions` ao lado do contato do B28 ✓; Popover two-step reusa `createCampaignInvite`/`autopreenchimento`; disable por `normalizeBrazilianPhone`; [plano](plans/convite-whatsapp-lista-liderancas.md); **B31 ✓** coluna de dobradinhas na lista de lideranças entregue — chips clicáveis → `/campanha/dobradinhas/` em `/campanha/liderancas`, edição por Popover+`Command` (mecânica do **B27 ✓**) com escrita por **server action direta do cliente** (`useTransition`, padrão do B19 ✓) em vez do endpoint JSON do B27, porque aqui há derivados a revalidar (`leadershipCount`, a ficha do deputado); `setLeadershipStateDeputyMembership(Record)` em transação + lock `leadership-state-deputies:{id}` + `revalidatePath`; helper puro `nextStateDeputyIdsAfterMembership` espelha `nextAdvisorIdsAfterMembership`; catálogo entregue uma vez por tabela via `leadershipColumns(stateDeputyOptions)` (columns factory, mesmo precedente de `municipalityListColumns`) em vez de Context; é o **2º call site** do padrão Popover+Command+chips — extração para `shared/` continua esperando o 3º (B34/B36/B37, que agora consomem a mutação/lock em vez de correr para desenhá-los); [plano](plans/dobradinhas-lista-liderancas.md); **fill-in ✓** limitar pan/zoom do mapa à Bahia — `BahiaMap` com `maxBounds`/`maxBoundsViscosity: 1` sobre `BAHIA_BOUNDS.pad(0.1)` e `minZoom` via `getBoundsZoom` com o mesmo padding 16px do `fitBounds`, recalculado no `ResizeObserver` existente; único arquivo; [plano](plans/limitar-mapa-a-bahia.md); (**B14 ✓** município mais próximo entregue — card cliente "Onde estou" no Início staff resolvendo **point-in-polygon** sobre o chunk de geometria que o mapa do dashboard já carrega (a premissa "polígonos explodem o bundle" do plano de 24/07 caiu na medição: 41 KB gzip já estão no browser, então o artefato de centroides e seu script saíram de escopo), com fallback nomeando onde o assessor está e o município mais próximo **da carteira** dentro de 150 km; a posição nunca sai do aparelho (sem action, sem `Consent`); First Load JS de `/campanha` 265 → 268 kB depois de mover o href das zonas de Salvador para o servidor (`zoneCityHrefs`) — importar `buildMunicipalityListHref` no cliente custava **21 kB** por um link, porque arrasta `bahiaTerritories` + `municipalityCatalog`; [plano](plans/municipio-mais-proximo.md); ~~**B38**~~ ✓ sidebar recolhido em tablet entregue — offcanvas + trigger md+ + cookie/matchMedia; [plano](plans/sidebar-recolhido-tablet.md); **B33+** novo fill-in de engenharia registrado no fechamento do B33 — `StateDeputyFilters` é o 3º call site do scaffold de navegação/debounce que `TerritoryFilters`/`MunicipalityFilters` já tinham, achado do `/simplify` rodada 2, [plano](plans/escala-dry-pos-b33.md); **B28 ✓** e-mail + celular na lista de lideranças entregue — colunas E-mail/Celular com copy-on-click + coluna de Ações com WhatsApp, no padrão de `/campanha/assessores` (B19 ✓); `shared/CampaignCopyableCell` nasce compartilhado já no 2º call site (`AdvisorsTable` migrado no mesmo PR), `whatsAppHrefForPhone` promovido a `lib/phone.ts`, `loadLeadershipDetail` deduplicado; [plano](plans/email-celular-lista-liderancas.md); **B24 ✓** auto-save + justificativa no popover de Tendência de `/campanha/municipios` — sem botão "Salvar", `POST /campanha/municipios/political-trend`, [plano](plans/autosave-tendencia-lista-municipios.md); **B13 ✓** escala relativa no mapa do Início entregue — quantis como novo default, padrão próprio/LQ nas âncoras do E10 e posição no município a partir do **artefato TSE v3** (`federalRankByIbgeCode`), mais bolhas opcionais por válidos projetados coloridas pela classe; `computeAggregateTerritorialClass` nasce aqui e o **E12** deve herdá-lo em vez de escrever um rollup próprio; `TERRITORIAL_CLASS_ANCHORS` mudou de casa para `src/lib/territorialClassAnchors.ts`; [plano](plans/escala-relativa-mapa.md); **B13+** novo fill-in de engenharia com os quatro débitos do `/simplify` do B13 — teste de concordância entre as duas escritas do LQ (mapa cliente × classificador server-only, a rede de segurança do **E15**), escopo geográfico declarado no readout (posição é da cidade inteira, classe é do escopo do usuário), uma varredura da fatia TSE por ano no script de agregados em vez de três, e a tupla no `competitiveRankByYear` que corta ~metade dos ~63,6 KB somados ao payload RSC · [plano](plans/escala-dry-pos-b13.md); **débito de teste** afinado no ledger ([TECH-DEBT.md](TECH-DEBT.md), P3 → P2): `campaignMunicipalities`/`campaign-pwa` são flaky com 2 workers **em `main`** também — clique no checkbox de consentimento antes da hidratação e regex de fixture em que "Conde" casa com "Condeúba"; **B27 ✓** combobox + chips + auto-save no popover de Assessores de `/campanha/municipios` entregue — a checkbox list + botão "Salvar assessores" virou chips removíveis + `Command` com gravação por delta, `nextAdvisorIdsAfterMembership` movido para `src/lib/`, endpoint `POST /campanha/municipios/advisors` espelho do `expected-votes/`, [plano](plans/combobox-assessores-lista-municipios.md); **B23 ✓** tooltip de conteúdo nas células das listas entregue — a mecânica genérica (`cellTooltip`, `CampaignCellTooltip`, `CampaignHoverTooltip` em `shared/`) já tinha saído de graça no E10 ✓; este item fechou `openOnTouch`/`disabled` no primitivo (mais um terceiro comportamento do `/simplify`: `content` falsy renderiza o trigger sem wrapper) e os dois consumidores de `/campanha/municipios` (nomes de assessores + justificativa da tendência), [plano](plans/tooltip-celulas-listas.md); **B22 ✓** explicação por coluna no header das listas entregue — `description?: ReactNode` em `CampaignTableHead`/`MunicipalitySortableHead` (rename de `tooltip`, sublinhado pontilhado), `campaignConceptOneLiner` como fonte única para colunas cobertas pelo E18 ✓, `municipalityColumnDescriptions` cobrindo as 11 colunas de `/campanha/municipios`; sem migration/action, [plano](plans/explicacao-colunas-header-listas.md); 2026-07-25: **E10 ✓** classificação territorial relativa entregue — Reduto/Expansão/Manutenção/Marginal/Sem base sobre o artefato TSE, coluna+sort+filtro na lista, badge no card do E8 e na capa do dossiê, e o seam genérico `cellTooltip` da `CampaignTable` (núcleo do B23) com `CampaignHoverTooltip` promovido para `shared/`; **B13** liberado; **E10+** novo fill-in de engenharia com os quatro débitos do `/simplify` do E10 — a lista lendo `municipality` duas vezes por request (o que **dispara o "Adiado com gatilho" do A11**: `classe` é o 4º path derivado no loader), memo de processo dos potenciais por município, `TooltipProvider` único no layout e os multi-filtros do mobile saindo das definitions · [plano](plans/escala-dry-pos-e10.md); **C8 F4b** novo fill-in — o guard de `formActions` só vê arquivos chamados exatamente `formActions.ts`, achado do `/simplify` do C13; **B26 ✓** registrar sinal na célula "Último sinal" — [plano](plans/registrar-sinal-lista-municipios.md); **C13 ✓** "Plano de Ação" → **"Atividade"** renomeado em toda a vertical — collection `activity`, rota `/campanha/atividades`, sidebar "Atividades", migration data-preserving escrita à mão (4 tabelas, 3 enums, 2 colunas, 39 índices, 14 FKs, 2 sequences + os 8 índices fósseis `%plaza%` da remodelagem) e guard de vocabulário table-driven varrendo `src`+`tests`+`scripts`; [plano](plans/renomear-plano-acao-para-atividade.md); **B37** chips editáveis de municípios na lista de dobradinhas — coluna "Municípios" de `/campanha/dobradinhas` troca o número morto (`municipalityCount`) por chips com link (município) / território (`MapPinIcon`) e o mesmo Popover+combobox do **B34** (busca por município/TI/ZE, lote de território/zona), mas escrevendo do lado invertido (`municipality.stateDeputies`, sem piso mínimo, lock por município em vez de por dobradinha, sem `assertMunicipalitiesWithinScope` porque `canUpdateMunicipality` já escopa o assessor); reaproveita/promove a mesma lib do B19/B34 (quem chegar primeiro faz a renomeação); mesmo conflito registrado com o pedido literal (toggle "Editar" de tabela inteira) que B28/B31/B32/B34/B36 já resolveram na direção do Popover por célula — decisão marcada como _proposta, a validar com produto_; sem migration, [plano](plans/chips-municipios-lista-dobradinhas.md); **B36** coluna "Lideranças" em `/campanha/dobradinhas` com a mesma UI/mecânica da coluna "Municípios" de `/campanha/assessores` (B19 ✓) — chips + Popover + `Command` + auto-save por delta + "Ver mais…" (clamp de 3 linhas por `ResizeObserver`, necessário aqui porque um deputado popular pode acumular muito mais lideranças do que uma liderança acumula dobradinhas); pedido explícito de não duplicar lógica — reusa **sem alteração** a mutação/schema/lock que o **B31** desenha para o lado inverso da mesma relação `leadership.stateDeputies`, promovendo a célula desse item para um componente compartilhado bidirecional (`LeadershipStateDeputyRelationCell`) em vez de um segundo componente-irmão; corrida de extração com o B31 (quem entrar primeiro paga a peça compartilhada); sem migration, [plano](plans/chips-liderancas-lista-dobradinhas.md); **B34** chips editáveis de municípios na lista de lideranças — coluna "Municípios" de `/campanha/liderancas` ganha chips com link (município) / território (`MapPinIcon`), edição por **Popover disparado por célula** com chips removíveis + combobox `Command` (busca por município/TI/ZE, lote de território/zona), gravação **por delta** direto em `leadership.municipalities` com lock `leadership-municipalities:{id}` (piso de 1 e teto de 30 respeitados) e `revalidatePath` (`liderancas`, `liderancas/[id]`, `municipios/[slug]` dos tocados); promove a lógica pura de `advisorMunicipalityPortfolio.ts`/`loadAdvisorMunicipalityIndex` (**B19 ✓**) para nomes neutros, sem portar a UI com `ResizeObserver`; **conflito registrado com o pedido literal** (pede um toggle "Editar" de tabela inteira, que B28/B31/B32 já travaram como anti-goal nesta mesma tabela — este plano segue o precedente e marca a decisão como _proposta, a validar com produto_); sem migration, [plano](plans/chips-municipios-lista-liderancas.md); ~~**B33**~~ ✓ ordenação e filtro no header da lista de dobradinhas (entregue 2026-07-26) — `?sort=`/`?dir=` por Nome/Partido + Popover multi-seleção de Partido com "Sem partido", consumindo o chrome compartilhado do **B21 ✓** (a corrida de ordem de chegada com B29 foi encerrada); paridade mobile (`StateDeputyFilters`) entrou por decisão desta sessão; ordem dos nulos de `party` pinada por int test; contagens derivadas (`municipalityCount`/`leadershipCount`) seguem sem sort/filtro, como travado, [plano](plans/ordenacao-filtros-lista-dobradinhas.md); **B32** editar Status de apoio na célula da lista de lideranças — clicar na célula abre um Popover com select de `supportStatus`, gravando sozinho por endpoint JSON dedicado (`POST /campanha/liderancas/support-status`, espelho do `expected-votes/`), **sem** o toggle "Editar" de tabela inteira (pedido explícito de produto, mesmo anti-goal do B28/B31); fecha o "Adiado com gatilho" que o próprio B29 já havia registrado para este caso; extrai `isSameOriginRequest` (2º endpoint) e as mensagens seguras do form action da ficha para módulos compartilhados; sem migration, [plano](plans/autosave-status-lista-liderancas.md); **B31** coluna de dobradinhas na lista de lideranças — chips com link + adicionar/remover na própria linha, com busca e gravação automática, na paridade pedida com a coluna "Municípios" de `/campanha/assessores` (B19 ✓) — paridade **da coluna**, não do modo "Editar" de tabela inteira (anti-goal do princípio 3 e do B28); escrita **por delta** com lock (`leadership-state-deputies:{id}`) em vez de replace do array, e `revalidatePath` porque `/campanha/dobradinhas` tem contagens derivadas; sem migration, [plano](plans/dobradinhas-lista-liderancas.md); **B30 ✓** convite de completar cadastro por WhatsApp na lista de lideranças — `LeadershipInviteRowAction` na coluna `actions` (entregue 2026-07-26), [plano](plans/convite-whatsapp-lista-liderancas.md); **B29** ordenação e filtro no header da lista de lideranças — leva B15 ✓/B16 ✓ para `/campanha/liderancas` (sort/filtro na URL, popover no header, colunas "Setor" e "Última atualização"), ordenação por nome via join `contact.name` (sem desnormalizar), e é o **3º call site** que dispara a extração do par head/filtro para `shared/` (municípios migrado junto; B21 fecha seu adiado), [plano](plans/ordenacao-filtros-lista-liderancas.md); ~~**B28**~~ ✓ e-mail + celular na lista de `/campanha/liderancas` (entregue 2026-07-26) — colunas E-mail/Celular com copy-on-click + coluna de Ações com WhatsApp como em `/campanha/assessores` (B19 ✓); `CampaignCopyableCell` nasce compartilhado já no 2º call site (`AdvisorsTable` migrado no mesmo PR), `whatsAppHrefForPhone` promovido a `lib/phone.ts`; edição in-list adiada; sem migration, [plano](plans/email-celular-lista-liderancas.md); ~~**B27**~~ ✓ combobox + chips + auto-save no popover de Assessores de `/campanha/municipios` (entregue 2026-07-26), [plano](plans/combobox-assessores-lista-municipios.md); ~~**B26**~~ ✓ registrar sinal na célula "Último sinal" (entregue 2026-07-25), [plano](plans/registrar-sinal-lista-municipios.md); **fill-in** renomear coluna "Cobertura da meta" → "Cobertura" em `/campanha/municipios` — header curto (padrão A11); glossário/KPI strips intactos; B16 ✓ liberou o nome ao remover "Assessoria", [plano](plans/renomear-coluna-cobertura-meta.md); ~~**B25**~~ ✓ link do território na lista de municípios (entregue 2026-07-26) — coluna "Território" + card mobile → `/campanha/territorios#ti-`; `territoryAnchor.ts` + `TerritoryLink`; seam `rowId` em `CampaignTable`; [plano](plans/link-territorio-lista-municipios.md); ~~**B24**~~ ✓ auto-save + justificativa editável no popover de Tendência de `/campanha/municipios` (entregue 2026-07-26), [plano](plans/autosave-tendencia-lista-municipios.md); **fill-in** remover coluna "Tipo" de `/campanha/municipios` — município e ZE tratados iguais na coordenação; filtro por Salvador cobre as zonas; drop também do filtro/sort/`?kind=` na URL da lista, schema `kind` intacto, [plano](plans/remover-coluna-tipo-municipios.md); ~~**B23**~~ ✓ tooltip de conteúdo nas células das listas (entregue 2026-07-26), [plano](plans/tooltip-celulas-listas.md); **fill-in** opções selecionadas no topo nos Popovers de filtro do header — helper puro reutilizável pelas demais listas, [plano](plans/selecionados-no-topo-filtros-header.md); ~~**B22**~~ ✓ explicação por coluna no header das listas (entregue 2026-07-26), [plano](plans/explicacao-colunas-header-listas.md); **B21** página própria dos Territórios de Identidade — rota `/campanha/territorios` com overview + tabela no sistema de listas (sort/filtro no header), sem migration, [plano](plans/pagina-territorios-identidade.md); **B20 ✓** Municípios prioritários no Início entregue 2026-07-25 — atalho ranqueado por déficit + markup sem bullets, [plano](plans/municipios-prioritarios-inicio.md); **Pass 2 ✓** consolidação de engenharia — listas genéricas/B16+ absorvido/B17-B18 triviais/E10 limpo/C8 F4 ✓/D3 consent WhatsApp; **B16 ✓**; **E16 ✓**; **E9 ✓**; **E18 ✓**; **B19 ✓**; **E8 ✓**; C12 ✓; B18; B17; A11 ✓; B15 ✓; E4R ✓; E17 ✓; B14 ✓; janela 1: smoke, R6)Registro canônico dos **próximos** planos e débitos. Histórico de entregas: resumo abaixo + planos em [`docs/plans/`](plans/) + notebook [`.cursor/rules/projects/nucleos-eleitorais.mdc`](../.cursor/rules/projects/nucleos-eleitorais.mdc).
+Atualizado em: 2026-07-27 (**B8+ ✓** escala e DRY pós-B8 F2 — a política de escala de chão das malhas commitadas virou código nomeado (`scripts/lib/topology.mjs`, tolerância de Visvalingam em m² e dígitos de quantização derivados do bbox de cada topologia), e com ela a malha das ZE caiu de 480 para **30,2 pontos/feature** (72.310 → 7.687 bytes) sem que `bahia-municipalities` mudasse um byte; a auditoria corrigiu a alavanca do plano (quantização sozinha quase não corta — o peso absoluto manda) e **rejeitou** um item do F4 por medição (`city`/`zoneNumber` de `MunicipalityZoneNeighborhoodEntry` são evidência de proveniência hasheada, não código morto); `MAX_POINTS_PER_FEATURE = 60` é o novo tripwire, `featureMapKey` passou a ser exercido sobre features reais das três malhas (417 `codarea`, 27 `code`, 19 `slug`), o mapa **degrada** em vez de morrer quando o chunk das zonas falha, e a ressalva de aproximação saiu do gate de comparação · [plano](plans/escala-dry-pos-b8f2.md); **`users.roles` ✓** — `admin`\|`editor` em `users`, migration `20260727_032523_add_users_roles`, editor publica `post`/`tag`/`media`; unificação com `campaignUser` rejeitada · [plano](plans/roles-admin-payload.md); 2026-07-26 (**fill-in** remover lista "Municípios por zona eleitoral" do Início — pós-B8 F2 ✓ os polígonos tornam a lista textual redundante; dropar UI + `zoneBreakdown` do bundle; ressalva de aproximação fica na malha · [plano](plans/remover-lista-zonas-mapa-inicio.md); **B8 F2 ✓** polígonos das 19 ZE de Salvador — artefato `bahia-municipality-zones.topo.json` (72 KB) por dissolve bairro→zona do `BA_bairros_CD2022` do IBGE contra a RA 02/2017 do TRE-BA, com curadoria explícita e um passe de maior fronteira compartilhada validado; o coroplético passou a ser keyed por **map key** (`slug` na zona, `ibgeCode` no resto) e o polígono municipal de Salvador ficou como base sem interação por baixo, porque duas malhas simplificadas independentemente não fecham na mesma costa; `competitiveRank` segue por cidade (o artefato TSE só tem `federalRankByIbgeCode`) com int pinando o fato; desambiguar a ZE no card "Onde estou" do B14 ✓ virou débito com gatilho, não dependência — [plano](plans/poligonos-pracas-zona.md); **B8+** novo fill-in de engenharia com os quatro débitos do `/simplify` do B8 F2, cujos relatórios chegaram depois do merge — a malha de 19 zonas ficou com a mesma contagem de vértices da malha dos 417 municípios (as duas constantes de simplificação são relativas ao bbox e foram copiadas verbatim, o que vale ~3,9 m de grade em Salvador contra ~103 m no estado), a regra da map key está em três formas sem nenhum teste ligando artefato → `featureMapKey` → catálogo, uma falha de chunk nas zonas passou a derrubar o mapa inteiro, a ressalva de aproximação desaparece no modo comparação, e `getTerritoryFeature` perdeu o último consumidor de produção neste commit · [plano](plans/escala-dry-pos-b8f2.md); **B39–B42** registrados: sessão "Lembrar de mim" + login biométrico WebAuthn + scroll horizontal/sticky na lista de municípios + polimento mobile da mesma lista — [B39](plans/lembrar-de-mim-sessao-campanha.md), [B40](plans/login-biometrico-campanha.md), [B41](plans/scroll-horizontal-lista-municipios.md), [B42](plans/polimento-mobile-lista-municipios.md); **E12 ✓** camada TI — rollups MAUP, colunas Cobertura/Captura/Classe em `/campanha/territorios`, benchmark intra-TI no `MunicipalityGoalAccountCard`; [plano](plans/camada-territorios-identidade.md); **B36 ✓** coluna "Lideranças" em `/campanha/dobradinhas` — chips + Popover+Command + delta reuse da mutação B31; `LeadershipStateDeputyRelationCell` compartilhada (`direction`/`measureOverflow`); columns factory (não Context); casca `dobradinhas/formActions.ts`; `loadLeadershipOptions` + `leaderships[]` no row; [plano](plans/chips-liderancas-lista-dobradinhas.md); **B30 ✓** convite de completar cadastro por WhatsApp na lista de lideranças — `LeadershipInviteRowAction` (`UserPlusIcon`) na coluna `actions` ao lado do contato do B28 ✓; Popover two-step reusa `createCampaignInvite`/`autopreenchimento`; disable por `normalizeBrazilianPhone`; [plano](plans/convite-whatsapp-lista-liderancas.md); **B31 ✓** coluna de dobradinhas na lista de lideranças entregue — chips clicáveis → `/campanha/dobradinhas/` em `/campanha/liderancas`, edição por Popover+`Command` (mecânica do **B27 ✓**) com escrita por **server action direta do cliente** (`useTransition`, padrão do B19 ✓) em vez do endpoint JSON do B27, porque aqui há derivados a revalidar (`leadershipCount`, a ficha do deputado); `setLeadershipStateDeputyMembership(Record)` em transação + lock `leadership-state-deputies:{id}` + `revalidatePath`; helper puro `nextStateDeputyIdsAfterMembership` espelha `nextAdvisorIdsAfterMembership`; catálogo entregue uma vez por tabela via `leadershipColumns(stateDeputyOptions)` (columns factory, mesmo precedente de `municipalityListColumns`) em vez de Context; é o **2º call site** do padrão Popover+Command+chips — extração para `shared/` continua esperando o 3º (B34/B36/B37, que agora consomem a mutação/lock em vez de correr para desenhá-los); [plano](plans/dobradinhas-lista-liderancas.md); **fill-in ✓** limitar pan/zoom do mapa à Bahia — `BahiaMap` com `maxBounds`/`maxBoundsViscosity: 1` sobre `BAHIA_BOUNDS.pad(0.1)` e `minZoom` via `getBoundsZoom` com o mesmo padding 16px do `fitBounds`, recalculado no `ResizeObserver` existente; único arquivo; [plano](plans/limitar-mapa-a-bahia.md); (**B14 ✓** município mais próximo entregue — card cliente "Onde estou" no Início staff resolvendo **point-in-polygon** sobre o chunk de geometria que o mapa do dashboard já carrega (a premissa "polígonos explodem o bundle" do plano de 24/07 caiu na medição: 41 KB gzip já estão no browser, então o artefato de centroides e seu script saíram de escopo), com fallback nomeando onde o assessor está e o município mais próximo **da carteira** dentro de 150 km; a posição nunca sai do aparelho (sem action, sem `Consent`); First Load JS de `/campanha` 265 → 268 kB depois de mover o href das zonas de Salvador para o servidor (`zoneCityHrefs`) — importar `buildMunicipalityListHref` no cliente custava **21 kB** por um link, porque arrasta `bahiaTerritories` + `municipalityCatalog`; [plano](plans/municipio-mais-proximo.md); ~~**B38**~~ ✓ sidebar recolhido em tablet entregue — offcanvas + trigger md+ + cookie/matchMedia; [plano](plans/sidebar-recolhido-tablet.md); **B33+** novo fill-in de engenharia registrado no fechamento do B33 — `StateDeputyFilters` é o 3º call site do scaffold de navegação/debounce que `TerritoryFilters`/`MunicipalityFilters` já tinham, achado do `/simplify` rodada 2, [plano](plans/escala-dry-pos-b33.md); **B28 ✓** e-mail + celular na lista de lideranças entregue — colunas E-mail/Celular com copy-on-click + coluna de Ações com WhatsApp, no padrão de `/campanha/assessores` (B19 ✓); `shared/CampaignCopyableCell` nasce compartilhado já no 2º call site (`AdvisorsTable` migrado no mesmo PR), `whatsAppHrefForPhone` promovido a `lib/phone.ts`, `loadLeadershipDetail` deduplicado; [plano](plans/email-celular-lista-liderancas.md); **B24 ✓** auto-save + justificativa no popover de Tendência de `/campanha/municipios` — sem botão "Salvar", `POST /campanha/municipios/political-trend`, [plano](plans/autosave-tendencia-lista-municipios.md); **B13 ✓** escala relativa no mapa do Início entregue — quantis como novo default, padrão próprio/LQ nas âncoras do E10 e posição no município a partir do **artefato TSE v3** (`federalRankByIbgeCode`), mais bolhas opcionais por válidos projetados coloridas pela classe; `computeAggregateTerritorialClass` nasce aqui e o **E12** deve herdá-lo em vez de escrever um rollup próprio; `TERRITORIAL_CLASS_ANCHORS` mudou de casa para `src/lib/territorialClassAnchors.ts`; [plano](plans/escala-relativa-mapa.md); **B13+** novo fill-in de engenharia com os quatro débitos do `/simplify` do B13 — teste de concordância entre as duas escritas do LQ (mapa cliente × classificador server-only, a rede de segurança do **E15**), escopo geográfico declarado no readout (posição é da cidade inteira, classe é do escopo do usuário), uma varredura da fatia TSE por ano no script de agregados em vez de três, e a tupla no `competitiveRankByYear` que corta ~metade dos ~63,6 KB somados ao payload RSC · [plano](plans/escala-dry-pos-b13.md); **débito de teste** afinado no ledger ([TECH-DEBT.md](TECH-DEBT.md), P3 → P2): `campaignMunicipalities`/`campaign-pwa` são flaky com 2 workers **em `main`** também — clique no checkbox de consentimento antes da hidratação e regex de fixture em que "Conde" casa com "Condeúba"; **B27 ✓** combobox + chips + auto-save no popover de Assessores de `/campanha/municipios` entregue — a checkbox list + botão "Salvar assessores" virou chips removíveis + `Command` com gravação por delta, `nextAdvisorIdsAfterMembership` movido para `src/lib/`, endpoint `POST /campanha/municipios/advisors` espelho do `expected-votes/`, [plano](plans/combobox-assessores-lista-municipios.md); **B23 ✓** tooltip de conteúdo nas células das listas entregue — a mecânica genérica (`cellTooltip`, `CampaignCellTooltip`, `CampaignHoverTooltip` em `shared/`) já tinha saído de graça no E10 ✓; este item fechou `openOnTouch`/`disabled` no primitivo (mais um terceiro comportamento do `/simplify`: `content` falsy renderiza o trigger sem wrapper) e os dois consumidores de `/campanha/municipios` (nomes de assessores + justificativa da tendência), [plano](plans/tooltip-celulas-listas.md); **B22 ✓** explicação por coluna no header das listas entregue — `description?: ReactNode` em `CampaignTableHead`/`MunicipalitySortableHead` (rename de `tooltip`, sublinhado pontilhado), `campaignConceptOneLiner` como fonte única para colunas cobertas pelo E18 ✓, `municipalityColumnDescriptions` cobrindo as 11 colunas de `/campanha/municipios`; sem migration/action, [plano](plans/explicacao-colunas-header-listas.md); 2026-07-25: **E10 ✓** classificação territorial relativa entregue — Reduto/Expansão/Manutenção/Marginal/Sem base sobre o artefato TSE, coluna+sort+filtro na lista, badge no card do E8 e na capa do dossiê, e o seam genérico `cellTooltip` da `CampaignTable` (núcleo do B23) com `CampaignHoverTooltip` promovido para `shared/`; **B13** liberado; **E10+** novo fill-in de engenharia com os quatro débitos do `/simplify` do E10 — a lista lendo `municipality` duas vezes por request (o que **dispara o "Adiado com gatilho" do A11**: `classe` é o 4º path derivado no loader), memo de processo dos potenciais por município, `TooltipProvider` único no layout e os multi-filtros do mobile saindo das definitions · [plano](plans/escala-dry-pos-e10.md); **C8 F4b** novo fill-in — o guard de `formActions` só vê arquivos chamados exatamente `formActions.ts`, achado do `/simplify` do C13; **B26 ✓** registrar sinal na célula "Último sinal" — [plano](plans/registrar-sinal-lista-municipios.md); **C13 ✓** "Plano de Ação" → **"Atividade"** renomeado em toda a vertical — collection `activity`, rota `/campanha/atividades`, sidebar "Atividades", migration data-preserving escrita à mão (4 tabelas, 3 enums, 2 colunas, 39 índices, 14 FKs, 2 sequences + os 8 índices fósseis `%plaza%` da remodelagem) e guard de vocabulário table-driven varrendo `src`+`tests`+`scripts`; [plano](plans/renomear-plano-acao-para-atividade.md); **B37** chips editáveis de municípios na lista de dobradinhas — coluna "Municípios" de `/campanha/dobradinhas` troca o número morto (`municipalityCount`) por chips com link (município) / território (`MapPinIcon`) e o mesmo Popover+combobox do **B34** (busca por município/TI/ZE, lote de território/zona), mas escrevendo do lado invertido (`municipality.stateDeputies`, sem piso mínimo, lock por município em vez de por dobradinha, sem `assertMunicipalitiesWithinScope` porque `canUpdateMunicipality` já escopa o assessor); reaproveita/promove a mesma lib do B19/B34 (quem chegar primeiro faz a renomeação); mesmo conflito registrado com o pedido literal (toggle "Editar" de tabela inteira) que B28/B31/B32/B34/B36 já resolveram na direção do Popover por célula — decisão marcada como _proposta, a validar com produto_; sem migration, [plano](plans/chips-municipios-lista-dobradinhas.md); **B36** coluna "Lideranças" em `/campanha/dobradinhas` com a mesma UI/mecânica da coluna "Municípios" de `/campanha/assessores` (B19 ✓) — chips + Popover + `Command` + auto-save por delta + "Ver mais…" (clamp de 3 linhas por `ResizeObserver`, necessário aqui porque um deputado popular pode acumular muito mais lideranças do que uma liderança acumula dobradinhas); pedido explícito de não duplicar lógica — reusa **sem alteração** a mutação/schema/lock que o **B31** desenha para o lado inverso da mesma relação `leadership.stateDeputies`, promovendo a célula desse item para um componente compartilhado bidirecional (`LeadershipStateDeputyRelationCell`) em vez de um segundo componente-irmão; corrida de extração com o B31 (quem entrar primeiro paga a peça compartilhada); sem migration, [plano](plans/chips-liderancas-lista-dobradinhas.md); **B34** chips editáveis de municípios na lista de lideranças — coluna "Municípios" de `/campanha/liderancas` ganha chips com link (município) / território (`MapPinIcon`), edição por **Popover disparado por célula** com chips removíveis + combobox `Command` (busca por município/TI/ZE, lote de território/zona), gravação **por delta** direto em `leadership.municipalities` com lock `leadership-municipalities:{id}` (piso de 1 e teto de 30 respeitados) e `revalidatePath` (`liderancas`, `liderancas/[id]`, `municipios/[slug]` dos tocados); promove a lógica pura de `advisorMunicipalityPortfolio.ts`/`loadAdvisorMunicipalityIndex` (**B19 ✓**) para nomes neutros, sem portar a UI com `ResizeObserver`; **conflito registrado com o pedido literal** (pede um toggle "Editar" de tabela inteira, que B28/B31/B32 já travaram como anti-goal nesta mesma tabela — este plano segue o precedente e marca a decisão como _proposta, a validar com produto_); sem migration, [plano](plans/chips-municipios-lista-liderancas.md); ~~**B33**~~ ✓ ordenação e filtro no header da lista de dobradinhas (entregue 2026-07-26) — `?sort=`/`?dir=` por Nome/Partido + Popover multi-seleção de Partido com "Sem partido", consumindo o chrome compartilhado do **B21 ✓** (a corrida de ordem de chegada com B29 foi encerrada); paridade mobile (`StateDeputyFilters`) entrou por decisão desta sessão; ordem dos nulos de `party` pinada por int test; contagens derivadas (`municipalityCount`/`leadershipCount`) seguem sem sort/filtro, como travado, [plano](plans/ordenacao-filtros-lista-dobradinhas.md); **B32** editar Status de apoio na célula da lista de lideranças — clicar na célula abre um Popover com select de `supportStatus`, gravando sozinho por endpoint JSON dedicado (`POST /campanha/liderancas/support-status`, espelho do `expected-votes/`), **sem** o toggle "Editar" de tabela inteira (pedido explícito de produto, mesmo anti-goal do B28/B31); fecha o "Adiado com gatilho" que o próprio B29 já havia registrado para este caso; extrai `isSameOriginRequest` (2º endpoint) e as mensagens seguras do form action da ficha para módulos compartilhados; sem migration, [plano](plans/autosave-status-lista-liderancas.md); **B31** coluna de dobradinhas na lista de lideranças — chips com link + adicionar/remover na própria linha, com busca e gravação automática, na paridade pedida com a coluna "Municípios" de `/campanha/assessores` (B19 ✓) — paridade **da coluna**, não do modo "Editar" de tabela inteira (anti-goal do princípio 3 e do B28); escrita **por delta** com lock (`leadership-state-deputies:{id}`) em vez de replace do array, e `revalidatePath` porque `/campanha/dobradinhas` tem contagens derivadas; sem migration, [plano](plans/dobradinhas-lista-liderancas.md); **B30 ✓** convite de completar cadastro por WhatsApp na lista de lideranças — `LeadershipInviteRowAction` na coluna `actions` (entregue 2026-07-26), [plano](plans/convite-whatsapp-lista-liderancas.md); **B29** ordenação e filtro no header da lista de lideranças — leva B15 ✓/B16 ✓ para `/campanha/liderancas` (sort/filtro na URL, popover no header, colunas "Setor" e "Última atualização"), ordenação por nome via join `contact.name` (sem desnormalizar), e é o **3º call site** que dispara a extração do par head/filtro para `shared/` (municípios migrado junto; B21 fecha seu adiado), [plano](plans/ordenacao-filtros-lista-liderancas.md); ~~**B28**~~ ✓ e-mail + celular na lista de `/campanha/liderancas` (entregue 2026-07-26) — colunas E-mail/Celular com copy-on-click + coluna de Ações com WhatsApp como em `/campanha/assessores` (B19 ✓); `CampaignCopyableCell` nasce compartilhado já no 2º call site (`AdvisorsTable` migrado no mesmo PR), `whatsAppHrefForPhone` promovido a `lib/phone.ts`; edição in-list adiada; sem migration, [plano](plans/email-celular-lista-liderancas.md); ~~**B27**~~ ✓ combobox + chips + auto-save no popover de Assessores de `/campanha/municipios` (entregue 2026-07-26), [plano](plans/combobox-assessores-lista-municipios.md); ~~**B26**~~ ✓ registrar sinal na célula "Último sinal" (entregue 2026-07-25), [plano](plans/registrar-sinal-lista-municipios.md); **fill-in** renomear coluna "Cobertura da meta" → "Cobertura" em `/campanha/municipios` — header curto (padrão A11); glossário/KPI strips intactos; B16 ✓ liberou o nome ao remover "Assessoria", [plano](plans/renomear-coluna-cobertura-meta.md); ~~**B25**~~ ✓ link do território na lista de municípios (entregue 2026-07-26) — coluna "Território" + card mobile → `/campanha/territorios#ti-`; `territoryAnchor.ts` + `TerritoryLink`; seam `rowId` em `CampaignTable`; [plano](plans/link-territorio-lista-municipios.md); ~~**B24**~~ ✓ auto-save + justificativa editável no popover de Tendência de `/campanha/municipios` (entregue 2026-07-26), [plano](plans/autosave-tendencia-lista-municipios.md); **fill-in** remover coluna "Tipo" de `/campanha/municipios` — município e ZE tratados iguais na coordenação; filtro por Salvador cobre as zonas; drop também do filtro/sort/`?kind=` na URL da lista, schema `kind` intacto, [plano](plans/remover-coluna-tipo-municipios.md); ~~**B23**~~ ✓ tooltip de conteúdo nas células das listas (entregue 2026-07-26), [plano](plans/tooltip-celulas-listas.md); **fill-in** opções selecionadas no topo nos Popovers de filtro do header — helper puro reutilizável pelas demais listas, [plano](plans/selecionados-no-topo-filtros-header.md); ~~**B22**~~ ✓ explicação por coluna no header das listas (entregue 2026-07-26), [plano](plans/explicacao-colunas-header-listas.md); **B21** página própria dos Territórios de Identidade — rota `/campanha/territorios` com overview + tabela no sistema de listas (sort/filtro no header), sem migration, [plano](plans/pagina-territorios-identidade.md); **B20 ✓** Municípios prioritários no Início entregue 2026-07-25 — atalho ranqueado por déficit + markup sem bullets, [plano](plans/municipios-prioritarios-inicio.md); **Pass 2 ✓** consolidação de engenharia — listas genéricas/B16+ absorvido/B17-B18 triviais/E10 limpo/C8 F4 ✓/D3 consent WhatsApp; **B16 ✓**; **E16 ✓**; **E9 ✓**; **E18 ✓**; **B19 ✓**; **E8 ✓**; C12 ✓; B18; B17; A11 ✓; B15 ✓; E4R ✓; E17 ✓; B14 ✓; janela 1: smoke, R6)Registro canônico dos **próximos** planos e débitos. Histórico de entregas: resumo abaixo + planos em [`docs/plans/`](plans/) + notebook [`.cursor/rules/projects/nucleos-eleitorais.mdc`](../.cursor/rules/projects/nucleos-eleitorais.mdc).
## Âncoras do calendário eleitoral 2026 (Res. TSE 23.760/2026)
@@ -130,14 +130,14 @@ O discovery literatura→persona→entrevista ([relatório aprovado](research/re
- ~~**Limitar o mapa da Bahia a pan/zoom dentro do estado**~~ — **✓ (entregue 2026-07-26)** `BahiaMap` trava pan com `maxBounds` (`BAHIA_BOUNDS.pad(0.1)`) + `maxBoundsViscosity: 1` e zoom-out com `minZoom` via `getBoundsZoom(BAHIA_BOUNDS, false, L.point(16, 16))` recalculado no `ResizeObserver` existente; único arquivo tocado; sem migration/props · [plano](plans/limitar-mapa-a-bahia.md)
- **Renomear coluna Cobertura da meta → Cobertura** em `/campanha/municipios` — pedido de produto (2026-07-25): header curto na fila (padrão A11 `2022`); definição no hover (**B22**) / glossário (**E18 ✓**). Só lista (header + card mobile + label de sort `deficit`); strips/card/conceitos mantêm o nome longo da métrica. Soft: **B16 ✓** (saiu "Assessoria", liberou o nome) · ~0,25d · Impeccable B · cortável · [plano](plans/renomear-coluna-cobertura-meta.md)
- **Remover coluna Tipo** em `/campanha/municipios` — pedido de produto (2026-07-25): a coluna "Tipo" (Município × Zona eleitoral) não informa a coordenação (ambos tratados iguais); filtrar ZE = filtrar Salvador (19 slugs). Remove coluna + filtro/sort UI + param `?kind=` do contrato URL da lista; **schema/catálogo `kind` intacto** (mapa, B8, dossiê) · ~0,25–0,5d · Impeccable B · soft: B15 ✓/B16 ✓ (header); B17 ganha uma coluna a menos · cortável · [plano](plans/remover-coluna-tipo-municipios.md)
-- **Remover lista "Municípios por zona eleitoral" do Início** — pedido de produto (2026-07-26): com **B8 F2 ✓** cada ZE de Salvador tem polígono próprio no mapa; a lista de 19 linhas sob o painel (`zoneBreakdown`) é densidade morta. Remove o bloco em `MunicipalityMapPanel` + o campo do bundle; mantém a ressalva de aproximação atrelada à malha (coordena **B8+** F3) · ~0,25–0,5d · Impeccable B · dura: B8 F2 ✓ · soft: B8+ · cortável · [plano](plans/remover-lista-zonas-mapa-inicio.md)
+- **Remover lista "Municípios por zona eleitoral" do Início** — pedido de produto (2026-07-26): com **B8 F2 ✓** cada ZE de Salvador tem polígono próprio no mapa; a lista de 19 linhas sob o painel (`zoneBreakdown`) é densidade morta. Remove o bloco em `MunicipalityMapPanel` + o campo do bundle; mantém a ressalva de aproximação atrelada à malha — **B8+** F3 ✓ já a moveu para fora do gate da lista, condicionada a `bundle.hasZoneMunicipalities` (campo próprio, que sobrevive ao drop de `zoneBreakdown`), então resta apagar o `
` + o campo do bundle · ~0,25d · Impeccable B · dura: B8 F2 ✓ · cortável · [plano](plans/remover-lista-zonas-mapa-inicio.md)
- **Ícone de prioridade na lista** em `/campanha/municipios` — trocar Badge “Prioritária” por ícone Flag + tooltip “Município prioritário” (hover) na coluna do nome · ~0,25d · Impeccable B · [plano](plans/icone-prioridade-lista-municipios.md)
- **Selecionados no topo nos filtros do header** em `/campanha/municipios` — nos Popovers de filtro (B16 ✓) as opções já marcadas sobem para o topo (ordem congelada enquanto o Popover está aberto; divisor de hairline), para desmarcar sem caçar a checkbox entre 27 territórios / 435 municípios; a regra sai como **helper puro em `src/lib/`** (`orderFilterOptionsSelectedFirst`), consumido pelo Popover desktop e pelo select mobile e pronto para **B21**/E12 — sem extrair o head genérico (gatilho do B21 segue sendo o 3º call site; **B22** promove o tooltip pelo mesmo critério de "peça compartilhada sem head genérico") · ~0,25–0,5d · Impeccable B · soft: B16 ✓ / B21 / B22 · [plano](plans/selecionados-no-topo-filtros-header.md)
- **Cenário junto aos filtros** em `/campanha/municipios` — mover `VoteEstimateScenarioField` para a fileira/barra slim de `MunicipalityFilters` (com **B16**, a barra deixa de carregar os selects de coluna); overview só consome o contexto · ~0,25–0,5d · Impeccable B · soft: B16 · [plano](plans/cenario-junto-filtros-municipios.md)
- ~~**B16+** escala/DRY pós-B16~~ — **absorvido pelo Pass 2 W1-D1 (2026-07-25)**: `useOptimistic`, facet por slugs, hrefs via serializador canônico, facets no mesmo `Promise.all` · [plano](plans/escala-dry-pos-b16.md)
- **E10+** escala/DRY pós-E10 — quatro fases do `/simplify` da classificação territorial: **F1** a lista lê `municipality` 2× por request (`listQuery` + `loadMunicipalityScope`, mesmo `where`, select superset) — **fecha o "Adiado com gatilho" do A11**, cujo gatilho ("3º path derivado no loader") disparou com `classe` sendo o 4º (`votos`, `deficit`, `frescor`); **F2** `computeAllMunicipalityPotentials()` recomputa 435 linhas puras do artefato por request (memo de processo, como `bahiaElectionAggregates`/`municipalityVoteRank`); **F3** um `TooltipProvider` por tooltip (~30 na lista) anula o agrupamento de delay do Radix — hoist para o layout de `(app)`; **F4** os 4 multi-filtros do mobile saem da mesma `municipalityFilterDefinitions` que os single-select vizinhos já usam · ~0,75–1d eng · Impeccable A · sem migration · cortável · [plano](plans/escala-dry-pos-e10.md)
- **B13+** escala/DRY pós-B13 — quatro fases do `/simplify` da escala relativa no mapa, as duas primeiras de **coerência** e não de custo: **F1** a razão do LQ é escrita duas vezes (painel cliente `:210` × classificador `server-only` `:108`, separação **deliberada** — o classificador arrasta o artefato de 600 KB) sem nenhum teste travando a concordância, que é a rede de segurança do **E15**; **F2** no readout do mapa a posição vale para a cidade inteira enquanto a classe é calculada sobre o escopo do usuário, então dois assessores veem classes diferentes para o mesmo polígono de Salvador — declarar a geografia, sem mudar o cálculo; **F3** `pnpm build:election-aggregates` varre a mesma fatia estadual do TSE 3× por ano (~225k docs extras) porque `loadFederalVotesByCityZoneAndCandidate` só precisa de `party` no `select` para ser superconjunto estrito dos outros dois; **F4** `competitiveRankByYear` soma ~57 dos ~63,6 KB que o B13 pôs no payload RSC, pagos mesmo por quem nunca abre a escala — tupla `[rank, candidates]` corta ~metade e responde ao "profiling antes de agir" que o ledger pediu em 2026-07-23 · ~0,5–0,75d eng · Impeccable A · sem migration · cortável · [plano](plans/escala-dry-pos-b13.md)
-- **B8+** escala/DRY pós-B8 F2 — quatro fases do `/simplify` dos polígonos das ZE, aberta pelo único achado **medido e já commitado**: a malha das 19 zonas tem 9.120 pontos de arco contra 9.139 da malha de **todos** os 417 municípios da Bahia (480 vs 22 pontos/feature), porque `QUANTIZE_DIGITS = 1e4` e `SIMPLIFY_QUANTILE = 0.35` foram copiados verbatim do script irmão e **os dois são relativos à própria topologia** — o bbox de Salvador é ~26× mais estreito, então a mesma "grade de 10⁴" vale ~3,9 m no chão contra ~103 m no estado (Salvador é um `Polygon` de 35 pontos na malha municipal); **F1** calibra as duas malhas pela mesma escala de **chão** — e é a escala, não a contagem de dígitos, que fica compartilhada entre os scripts, porque extrair as constantes como estão cimentaria o defeito — trocando o tripwire de bytes (`MAX_TOPO_BYTES`, calibrado para malha estadual) por um de pontos/feature; **F2** fecha o buraco de teste da **map key**, escrita em três formas (`mapKeyForMunicipality` sobre o catálogo × `featureMapKey` sobre propriedades GeoJSON × a identidade `baseKeys` do `BahiaMap`) que, se discordarem, pintam cinza **sem erro em lugar nenhum** — hoje nada roda `featureMapKey` sobre um feature real fora do e2e; **F3** para de derrubar o mapa inteiro quando o chunk das zonas falha (`Promise.all` + memoização da rejeição = ponto único de falha novo, quando antes a malha municipal sozinha bastava) e tira a ressalva "é aproximado, não é o limite oficial do TSE" de dentro do gate `!comparisonActive`, onde ela desaparece enquanto a malha aproximada continua pintada; **F4** deleta o que a entrega orfanou e o knip não vê (`getTerritoryFeature` perdeu o último consumidor de produção **neste commit**), colapsa a união de navegação de 3 estados num `string | undefined` e tira 435 strings mortas (`name`) do payload RSC do Início · ~0,75–1d eng · Impeccable A · sem migration (F1 reescreve o artefato commitado) · cortável · [plano](plans/escala-dry-pos-b8f2.md)
+- ~~**B8+** escala/DRY pós-B8 F2~~ — **✓ (entregue 2026-07-27)** as quatro fases do `/simplify` dos polígonos das ZE. **F1:** a política de escala de chão nasceu em `scripts/lib/topology.mjs` (primeiro módulo de `scripts/lib/` — **B5 F2** pousa nele) declarando tolerância de Visvalingam em **m² de chão** e derivando os dígitos de quantização do bbox de cada topologia; `SIMPLIFY_QUANTILE`/`QUANTIZE_DIGITS` morreram nos dois scripts. A auditoria corrigiu a alavanca do plano: quantização sozinha quase não corta (mesmo na grade estadual as zonas ficariam em 203 pontos/feature), o peso absoluto é que manda — as zonas caíram de **9.120 → 574 pontos de arco (480 → 30,2/feature) e 72.310 → 7.687 bytes**, `bahia-municipalities` saiu **byte-idêntico** e territórios mudou 1 byte (grade 102,730 → 102,822 m). Tolerância própria por malha, com o número medido no comentário: a tolerância municipal chegaria a 17,9/feature nas zonas mas comeria 5% da área de Salvador (306 → 291 km²), que é justamente a grandeza que prova que nenhum bairro sumiu. `MAX_TOPO_BYTES` ganhou ao lado `MAX_POINTS_PER_FEATURE = 60`. **F2:** `featureMapKey` passou a ser exercido sobre features **reais** das três malhas, cada uma no laço que já a varre inteira (417 `codarea` + 27 `code` + 19 `slug`) — o `/simplify` corrigiu a primeira escrita, que asseria a cidade dentro do laço das zonas e portanto cobria **uma** feature municipal 19 vezes; o teste de precedência sintético caiu e o comentário passou a declarar o invariante real (as três propriedades de chave são mutuamente exclusivas; `ibgeCode` na zona deliberadamente não é chave). **F3:** `.catch()` na metade das zonas — o mapa segue sem elas (com o motivo logado), com Salvador como polígono sem dado nem interação — e a ressalva de aproximação saiu do gate `!comparisonActive` para um `
` condicionado a `bundle.hasZoneMunicipalities`, campo novo publicado pelo loader a partir de `kind === 'zona'`: o `/simplify` **rejeitou** o predicado `isZoneMapKey` que lia isso da forma da chave (7 dígitos ⇒ município), porque era uma segunda codificação da regra de `mapKeyForMunicipality`, e gatear em `zoneBreakdown` recriaria o acoplamento que o fill-in da lista vai deletar. **F4:** dois acessores órfãos deletados, a união de navegação de 3 estados colapsada em `string | undefined`, `MunicipalitiesByMapKey` virou `Record` (435 strings fora do payload RSC do Início), `polygonRingsOf` exportado e os helpers de geometria retipados em `PolygonalFeature`/`BahiaFeature
`/`BahiaMeshFeature`. **Um item do plano foi rejeitado por medição:** `city`/`zoneNumber` de `MunicipalityZoneNeighborhoodEntry` **ficam** — entram nas linhas hasheadas por `canonicalEvidenceRows` e são colunas do fixture de proveniência da RA 02/2017, então não são código morto (só o `zoneNumber` do **artefato** TopoJSON saiu) · sem migration · [plano](plans/escala-dry-pos-b8f2.md)
- **E12+** escala/DRY pós-E12 — duas fases condicionais do `/simplify` da camada TI: **F1** extrair peers/sub-linhas do Metropolitano para `lib/` quando surgir 4º call site ou regra mais rica (hoje constantes + benchmark intra-TI compartilham `territoryOverview.ts`); **F2** memo de peer-group no benchmark T4 só com evidência de duplicação no detalhe · ~0,25–0,5d eng · Impeccable A · sem migration · cortável · [plano](plans/escala-dry-pos-e12.md)
- **O0+** escala/DRY pós-Onda 0 · [plano](plans/escala-dry-pos-onda0.md)
- **RS+** auth read leve + shells de senha · [plano](plans/escala-dry-pos-reset-senha-perfil.md)
diff --git a/scripts/build-bahia-geometries.mjs b/scripts/build-bahia-geometries.mjs
index f39adfc1..b2c570c7 100644
--- a/scripts/build-bahia-geometries.mjs
+++ b/scripts/build-bahia-geometries.mjs
@@ -26,9 +26,14 @@ import { access, mkdir, readFile, writeFile } from 'node:fs/promises'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
-import { merge, quantize } from 'topojson-client'
+import { merge } from 'topojson-client'
import { topology } from 'topojson-server'
-import { presimplify, quantile, simplify } from 'topojson-simplify'
+
+import {
+ describeGroundScale,
+ SIMPLIFY_TOLERANCE_M2,
+ simplifyToGroundScale,
+} from './lib/topology.mjs'
const { canonicalizeMunicipalityName, UnknownMunicipalityError } =
await import('../src/lib/electionResults.ts')
@@ -51,11 +56,6 @@ const SOURCES = {
},
}
-/** Quantile of triangle area kept after presimplify (higher = more detail). */
-const SIMPLIFY_QUANTILE = 0.35
-/** Quantization precision for the final topology. */
-const QUANTIZE_DIGITS = 1e4
-
const die = (message) => {
console.error(`\n[build:geometries] ${message}\n`)
process.exit(1)
@@ -93,13 +93,6 @@ const writeJson = async (relativePath, value) => {
console.log(`[build:geometries] wrote ${relativePath} (${Buffer.byteLength(body)} bytes)`)
}
-const simplifyTopology = (topo) => {
- let next = presimplify(topo)
- const minWeight = quantile(next, SIMPLIFY_QUANTILE)
- next = simplify(next, minWeight)
- return quantize(next, QUANTIZE_DIGITS)
-}
-
const buildMunicipalityCodesModule = (entries, provenance) => {
const lines = entries
.map(([name, code]) => ` ${JSON.stringify(name)}: ${JSON.stringify(code)},`)
@@ -209,7 +202,11 @@ const main = async () => {
let municipalityTopo = topology({
municipalities: { type: 'FeatureCollection', features: municipalityFeatures },
})
- municipalityTopo = simplifyTopology(municipalityTopo)
+ municipalityTopo = simplifyToGroundScale(
+ municipalityTopo,
+ SIMPLIFY_TOLERANCE_M2.bahiaMunicipalities,
+ )
+ console.log(`[build:geometries] ${describeGroundScale(municipalityTopo)}`)
const geometriesByCodarea = new Map(
municipalityTopo.objects.municipalities.geometries.map((geometry) => [
@@ -236,7 +233,11 @@ const main = async () => {
let territoryTopo = topology({
territories: { type: 'FeatureCollection', features: territoryFeatures },
})
- territoryTopo = simplifyTopology(territoryTopo)
+ territoryTopo = simplifyToGroundScale(
+ territoryTopo,
+ SIMPLIFY_TOLERANCE_M2.bahiaIdentityTerritories,
+ )
+ console.log(`[build:geometries] ${describeGroundScale(territoryTopo)}`)
const accessed = new Date().toISOString().slice(0, 10)
const provenance = {
diff --git a/scripts/build-municipality-zone-geometries.mjs b/scripts/build-municipality-zone-geometries.mjs
index 3710ca0b..d55e90df 100644
--- a/scripts/build-municipality-zone-geometries.mjs
+++ b/scripts/build-municipality-zone-geometries.mjs
@@ -30,9 +30,15 @@ import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import shp from 'shpjs'
-import { merge, quantize } from 'topojson-client'
+import { merge } from 'topojson-client'
import { topology } from 'topojson-server'
-import { presimplify, quantile, simplify } from 'topojson-simplify'
+
+import {
+ describeGroundScale,
+ quantizeToGroundGrid,
+ SIMPLIFY_TOLERANCE_M2,
+ simplifyToGroundScale,
+} from './lib/topology.mjs'
const { municipalityCatalog } = await import('../src/lib/municipalityCatalog.ts')
const { municipalityZoneNeighborhoods } =
@@ -49,11 +55,6 @@ const SOURCE = {
const OUTPUT_PATH = 'src/lib/geometries/bahia-municipality-zones.topo.json'
-/** Quantile of triangle area kept after presimplify (higher = more detail). */
-const SIMPLIFY_QUANTILE = 0.35
-/** Quantization precision for the final topology. */
-const QUANTIZE_DIGITS = 1e4
-
/**
* Same neighborhood, different name in the two sources — IBGE composites
* ("Beiru / Tancredo Neves") and spellings the accent folding cannot reach.
@@ -116,7 +117,7 @@ const ensureCachedBinary = async ({ key, url, ext }) => {
await access(path)
log(`cache hit ${path}`)
const buffer = await readFile(path)
- return { url, hash: sha256(buffer), buffer }
+ return { hash: sha256(buffer), buffer }
} catch (error) {
if (error?.code !== 'ENOENT') throw error
}
@@ -125,7 +126,7 @@ const ensureCachedBinary = async ({ key, url, ext }) => {
const hash = sha256(buffer)
await writeFile(path, buffer)
log(`saved ${path} (${buffer.length} bytes, sha256=${hash})`)
- return { url, hash, buffer }
+ return { hash, buffer }
}
const writeJson = async (relativePath, value) => {
@@ -136,13 +137,6 @@ const writeJson = async (relativePath, value) => {
log(`wrote ${relativePath} (${Buffer.byteLength(body)} bytes)`)
}
-const simplifyTopology = (topo) => {
- let next = presimplify(topo)
- const minWeight = quantile(next, SIMPLIFY_QUANTILE)
- next = simplify(next, minWeight)
- return quantize(next, QUANTIZE_DIGITS)
-}
-
/** Accent-folded, punctuation-free key; parentheses (the TRE's split notes) drop. */
const normalizeNeighborhood = (name) =>
name
@@ -153,9 +147,6 @@ const normalizeNeighborhood = (name) =>
.replace(/[^A-Z0-9]+/g, ' ')
.trim()
-const polygonCount = (geometry) =>
- geometry?.type === 'MultiPolygon' ? geometry.coordinates.length : geometry ? 1 : 0
-
const arcIndexes = (arcs, into = new Set()) => {
for (const item of arcs) {
if (Array.isArray(item)) arcIndexes(item, into)
@@ -270,12 +261,22 @@ const main = async () => {
})
const geometries = neighborhoodTopology.objects.neighborhoods.geometries
+ // The TRE key each polygon resolves to once aliases are applied. Resolved once
+ // because the assignment pass and the coverage check below used to derive it
+ // separately with the same fallback: the `die` guard is built on the second, so
+ // a divergence between the two would let it pass over a wrong assignment.
+ const treKeyByGeometry = new Map(
+ geometries.map((geometry) => {
+ const key = normalizeNeighborhood(geometry.properties.name)
+ return [geometry, aliasTargets.get(key) ?? key]
+ }),
+ )
+
// Pass 1 — the resolution's own names.
const zoneSlugByGeometry = new Map()
const unnamed = []
for (const geometry of geometries) {
- const key = normalizeNeighborhood(geometry.properties.name)
- const slug = zoneSlugByNeighborhood.get(aliasTargets.get(key) ?? key)
+ const slug = zoneSlugByNeighborhood.get(treKeyByGeometry.get(geometry))
if (slug) zoneSlugByGeometry.set(geometry, slug)
else unnamed.push(geometry)
}
@@ -300,12 +301,7 @@ const main = async () => {
)
}
- const coveredKeys = new Set(
- geometries.map((geometry) => {
- const key = normalizeNeighborhood(geometry.properties.name)
- return aliasTargets.get(key) ?? key
- }),
- )
+ const coveredKeys = new Set(treKeyByGeometry.values())
for (const hostName of Object.values(TRE_NEIGHBORHOODS_MERGED_INTO)) {
if (!coveredKeys.has(normalizeNeighborhood(hostName))) continue
for (const [treName, host] of Object.entries(TRE_NEIGHBORHOODS_MERGED_INTO)) {
@@ -320,7 +316,9 @@ const main = async () => {
const geometriesByZone = new Map()
for (const [geometry, slug] of zoneSlugByGeometry) {
- geometriesByZone.set(slug, [...(geometriesByZone.get(slug) ?? []), geometry])
+ const bucket = geometriesByZone.get(slug)
+ if (bucket) bucket.push(geometry)
+ else geometriesByZone.set(slug, [geometry])
}
log(
`assigned ${zoneSlugByGeometry.size}/${geometries.length} polygons to ${geometriesByZone.size}/${zoneEntries.length} zones`,
@@ -353,7 +351,10 @@ const main = async () => {
// Simplification keeps geometry order and properties, so the zone buckets
// above still address the right shapes.
- const simplified = simplifyTopology(neighborhoodTopology)
+ const simplified = simplifyToGroundScale(
+ neighborhoodTopology,
+ SIMPLIFY_TOLERANCE_M2.bahiaMunicipalityZones,
+ )
const simplifiedById = new Map(
simplified.objects.neighborhoods.geometries.map((geometry) => [
geometry.properties.id,
@@ -379,7 +380,6 @@ const main = async () => {
properties: {
municipalitySlug: entry.slug,
name: entry.name,
- zoneNumber: entry.zoneNumber,
ibgeCode: entry.ibgeCode,
},
geometry,
@@ -388,16 +388,15 @@ const main = async () => {
// Already simplified above — the final pass only quantizes, so the artifact
// stores short integers instead of the floats `merge` hands back.
- await writeJson(
- OUTPUT_PATH,
- quantize(
- topology({ municipalityZones: { type: 'FeatureCollection', features: zoneFeatures } }),
- QUANTIZE_DIGITS,
- ),
+ const zoneTopology = quantizeToGroundGrid(
+ topology({ municipalityZones: { type: 'FeatureCollection', features: zoneFeatures } }),
)
+ log(describeGroundScale(zoneTopology))
+ await writeJson(OUTPUT_PATH, zoneTopology)
for (const feature of zoneFeatures) {
- const pieces = polygonCount(feature.geometry)
+ // `merge` always hands back a MultiPolygon, so this is the piece count.
+ const pieces = feature.geometry.coordinates.length
log(
`${feature.properties.municipalitySlug}: ${
geometriesByZone.get(feature.properties.municipalitySlug).length
diff --git a/scripts/lib/topology.mjs b/scripts/lib/topology.mjs
new file mode 100644
index 00000000..4664a2b0
--- /dev/null
+++ b/scripts/lib/topology.mjs
@@ -0,0 +1,123 @@
+/**
+ * Ground-scale policy shared by the committed Bahia TopoJSON meshes.
+ *
+ * Every mesh in `src/lib/geometries/` is simplified and quantized before it is
+ * committed, and the two knobs that control that only mean something in ground
+ * units:
+ *
+ * - **Simplification tolerance** — Visvalingam drops a vertex whose effective
+ * triangle is smaller than a threshold in square degrees. `topojson-simplify`
+ * can pick that threshold as a *quantile* of the topology's own triangles,
+ * which is what both build scripts used to do with a copied `0.35`. A quantile
+ * is relative to the mesh: the same `0.35` cut Salvador's 19 neighbourhood-
+ * derived zones at ~0.6 m² while it cut the 417 municipalities at ~1.78 km².
+ * This is the dominant lever, and it is why the zone mesh shipped at 480 points
+ * per feature against the state mesh's 21.9.
+ * - **Quantization digits** — `topojson-client`'s `quantize(topo, n)` lays an
+ * `n`-step grid across *the topology's own bbox*, so a copied `1e4` means
+ * ~103 m across Bahia and ~3.9 m across Salvador: a 26× finer grid step nobody
+ * asked for. Measured, it is the minor knob — putting the zones on the state's
+ * ~103 m grid alone took them from 480 points per feature to 203, and only the
+ * absolute tolerance below reached 30.2.
+ *
+ * So the policy is declared here in ground units and the bbox-relative numbers
+ * are derived per topology. Tolerances are per mesh *on purpose* — a tolerance
+ * is a statement about the size of the shapes being drawn, and a Salvador zone
+ * (~16 km²) is three orders of magnitude smaller than a Bahia municipality
+ * (~1,340 km²) — but they now sit side by side in ground units, so divergence
+ * is a visible decision instead of an accident of a copied constant.
+ */
+
+import { quantize } from 'topojson-client'
+import { presimplify, simplify } from 'topojson-simplify'
+
+/**
+ * Metres per degree at the equator. Bahia spans ~9°–18° S, where a degree of
+ * longitude is 5–8% shorter, so every metre here is a nominal metre — good
+ * enough to size a tolerance, not a distance measurement.
+ */
+const METRES_PER_DEGREE = 111_320
+
+const SQUARE_METRES_PER_SQUARE_DEGREE = METRES_PER_DEGREE * METRES_PER_DEGREE
+
+/**
+ * Ground resolution of the committed meshes. Chosen as the step the state mesh
+ * has always had (`1e4` digits over its 9.2357° bbox), so honoring the policy
+ * leaves `bahia-municipalities.topo.json` byte-identical.
+ */
+const GROUND_GRID_METRES = 102.82
+
+/**
+ * Simplification tolerance per mesh, as the ground area of the smallest
+ * triangle kept. Each value is followed by the density it buys, measured — the
+ * tripwire in `tests/int/bahiaGeometries.int.spec.ts` asserts points per
+ * feature, so a mesh that silently goes back to a relative cut fails there.
+ */
+export const SIMPLIFY_TOLERANCE_M2 = {
+ /** 1.78 km² → 21.9 points/feature. The state mesh's historical cut. */
+ bahiaMunicipalities: 1_776_383,
+ /** 13.6 km² → 44.8 points/feature. Dissolved from the mesh above, so these
+ * outlines already carry the municipal cut and anything at or below it is
+ * close to a no-op; 13.6 km² is a deliberate step coarser, sized to shapes
+ * ~15× larger. */
+ bahiaIdentityTerritories: 13_591_527,
+ /** 0.06 km² → 30.2 points/feature. Sized to Salvador's zones rather than to
+ * Bahia's municipalities: the municipal tolerance does reach 17.9
+ * points/feature here, but it also sheds 5% of the city's land area
+ * (306 → 291 km²), which is the quantity the int spec uses to prove no
+ * neighbourhood was dropped or double-counted. */
+ bahiaMunicipalityZones: 60_000,
+}
+
+/**
+ * Quantization digits that lay `GROUND_GRID_METRES` across this topology's own
+ * bbox. `quantize` derives its scale from `n - 1` steps, so the requested step
+ * is honored to within one grid cell.
+ *
+ * `quantize` applies that single digit count to BOTH axes, so the step is only
+ * exact on the axis it is derived from — longitude here — and latitude follows
+ * the bbox aspect ratio: measured, 102.8×109.2 m for the two statewide meshes
+ * and 102.9×80.1 m for Salvador's. Anchoring on X is what keeps
+ * `bahia-municipalities.topo.json` byte-identical to its pre-policy build;
+ * making both axes exact would mean passing an explicit `{scale, translate}`
+ * transform and rewriting all three artifacts. `describeGroundScale` prints
+ * both steps, so the asymmetry is visible in every build log.
+ */
+const quantizeDigitsFor = (topo, gridMetres) => {
+ const [minX, , maxX] = topo.bbox
+ return Math.round((maxX - minX) / (gridMetres / METRES_PER_DEGREE)) + 1
+}
+
+/**
+ * Simplify to a ground tolerance and quantize to the shared ground grid.
+ *
+ * Order matters: quantizing a dense mesh to a ~100 m grid before simplifying it
+ * collapses vertices into duplicates, and a later `merge` of such a topology
+ * produces broken rings (measured: Salvador's 307 km² dissolved to 24 km²).
+ */
+export const simplifyToGroundScale = (topo, toleranceM2) => {
+ const minWeight = toleranceM2 / SQUARE_METRES_PER_SQUARE_DEGREE
+ return quantizeToGroundGrid(simplify(presimplify(topo), minWeight))
+}
+
+/** Quantize an already-simplified topology to the shared ground grid. */
+export const quantizeToGroundGrid = (topo) =>
+ quantize(topo, quantizeDigitsFor(topo, GROUND_GRID_METRES))
+
+/**
+ * One line describing what a topology actually landed on, so a rebuild reports
+ * the ground scale instead of leaving it to be re-derived from the artifact.
+ * Every topology here holds exactly one object (the int spec pins that), so the
+ * name is read off it rather than passed in twice.
+ */
+export const describeGroundScale = (topo) => {
+ const [name, object] = Object.entries(topo.objects)[0]
+ const arcPoints = topo.arcs.reduce((total, arc) => total + arc.length, 0)
+ const features = object.geometries.length
+ const stepMetres = topo.transform.scale.map((scale) => scale * METRES_PER_DEGREE)
+ return (
+ `${name}: ${features} features, ${arcPoints} arc points ` +
+ `(${(arcPoints / features).toFixed(1)}/feature), ` +
+ `grid ${stepMetres.map((step) => step.toFixed(1)).join('×')} m`
+ )
+}
diff --git a/src/components/campaign/map/BahiaMap.tsx b/src/components/campaign/map/BahiaMap.tsx
index 80e77c8e..3280d950 100644
--- a/src/components/campaign/map/BahiaMap.tsx
+++ b/src/components/campaign/map/BahiaMap.tsx
@@ -12,7 +12,7 @@ import {
loadMunicipalityZoneGeometryModule,
loadTerritoryGeometryModule,
} from '@/lib/bahiaGeometries'
-import type { BahiaGeometryFeature } from '@/lib/bahiaGeometriesTypes'
+import type { BahiaMeshFeature } from '@/lib/bahiaGeometriesTypes'
import {
bubbleRadius,
buildHighlightSet,
@@ -61,6 +61,13 @@ const applyBahiaMinZoom = (map: L.Map) => {
map.setMinZoom(zoom)
}
+/**
+ * `territory` has no caller today — B21 moved the Identity Territories to their
+ * own page and `MunicipalityMapPanel` hardcodes `municipality`. It is kept
+ * because E12 registered the TI map mode as a trigger, not because something
+ * still reads it; `bahiaTerritoryGeometries` and its ~15 KB artifact are alive
+ * only through that decision and the int spec.
+ */
export type BahiaMapMode = 'municipality' | 'territory'
/**
@@ -72,7 +79,7 @@ export type BahiaMapMode = 'municipality' | 'territory'
*/
const loadLayerFeatures = async (
mode: BahiaMapMode,
-): Promise<{ features: BahiaGeometryFeature[]; baseKeys: Set }> => {
+): Promise<{ features: BahiaMeshFeature[]; baseKeys: Set }> => {
if (mode === 'territory') {
const { features } = await loadTerritoryGeometryModule()
return { features: [...features], baseKeys: new Set() }
@@ -80,12 +87,24 @@ const loadLayerFeatures = async (
const [municipalities, zones] = await Promise.all([
loadMunicipalityGeometryModule(),
- loadMunicipalityZoneGeometryModule(),
+ // B8+ F3 — the state mesh is the map; the zone mesh is a detail on top of it.
+ // If it fails to arrive, Salvador falls back to the base polygon it already
+ // has underneath: drawn, but with no value and no pointer, since the bundle
+ // is keyed by zone slug and the city code is not a scoped key. Every other
+ // município keeps working instead of the whole panel erroring out. A network
+ // ChunkLoadError is the expected failure and needs no report; a decode error
+ // or a renamed topology object is a bug, so the reason is logged either way.
+ loadMunicipalityZoneGeometryModule().catch((error: unknown) => {
+ console.error('[map] malha das zonas indisponível; Bahia sem as ZE de Salvador', error)
+ return null
+ }),
])
+ const zoneFeatures = zones?.features ?? []
+
return {
- features: [...municipalities.features, ...zones.features],
- baseKeys: new Set(zones.features.map((zone) => zone.properties.ibgeCode)),
+ features: [...municipalities.features, ...zoneFeatures],
+ baseKeys: new Set(zoneFeatures.map((zone) => zone.properties.ibgeCode)),
}
}
diff --git a/src/components/campaign/map/MapFeatureReadout.tsx b/src/components/campaign/map/MapFeatureReadout.tsx
index ef8309ab..24bf89ff 100644
--- a/src/components/campaign/map/MapFeatureReadout.tsx
+++ b/src/components/campaign/map/MapFeatureReadout.tsx
@@ -4,7 +4,6 @@ import type { BahiaMapFeatureInfo } from '@/components/campaign/map/BahiaMap'
import { Button } from '@/components/ui/button'
import { formatElectionNumber } from '@/lib/electionFormat'
import type { MunicipalityMapScaleMode } from '@/utilities/municipalityMapContract'
-import type { MunicipalityMapNavigation } from '@/utilities/municipalityMapNavigation'
type MapFeatureReadoutProps = {
feature: BahiaMapFeatureInfo | null
@@ -21,7 +20,8 @@ type MapFeatureReadoutProps = {
/** What the bubble encodes for THIS município — only while the layer is on. */
bubbleReading: string | null
comparisonActive: boolean
- navigation: MunicipalityMapNavigation | null
+ /** The município the painted feature opens, when it is one the actor can read. */
+ municipalitySlug: string | undefined
}
const percentFormatter = new Intl.NumberFormat('pt-BR', {
@@ -52,7 +52,7 @@ export const MapFeatureReadout = ({
relativeReading,
bubbleReading,
comparisonActive,
- navigation,
+ municipalitySlug,
}: MapFeatureReadoutProps) => {
if (!feature) {
return (
@@ -105,9 +105,9 @@ export const MapFeatureReadout = ({
{bubbleReading ?
{bubbleReading}
: null}
- {navigation?.kind === 'navigate' ? (
+ {municipalitySlug ? (
) : null}
diff --git a/src/components/campaign/map/MunicipalityMapPanel.tsx b/src/components/campaign/map/MunicipalityMapPanel.tsx
index 04e2cf04..77c43ed5 100644
--- a/src/components/campaign/map/MunicipalityMapPanel.tsx
+++ b/src/components/campaign/map/MunicipalityMapPanel.tsx
@@ -60,7 +60,6 @@ import {
type MunicipalityMapScaleMode,
type MunicipalityMapYear,
} from '@/utilities/municipalityMapContract'
-import { resolveMunicipalityMapNavigation } from '@/utilities/municipalityMapNavigation'
import type { MunicipalityTerritorialClass } from '@/utilities/municipalityTerritorialClass'
/** The legend's note doubles as the scale selector's description. */
@@ -590,15 +589,20 @@ export const MunicipalityMapPanel = ({
}
/>
- {/* zone breakdown below */}
+ {/* B8+ F3 — tied to the MESH, not to the list below: the comparison mode
+ paints Salvador from the same approximate polygons, so the caveat has
+ to survive with or without comparison. */}
+ {bundle.hasZoneMunicipalities ? (
+
+ Salvador é pintada zona por zona. O desenho vem dos bairros de cada circunscrição
+ (TRE-BA, RA nº 2/2017) sobre a malha do IBGE — é aproximado, não é o limite oficial do
+ TSE.
+
- Salvador é pintada zona por zona. O desenho vem dos bairros de cada circunscrição
- (TRE-BA, RA nº 2/2017) sobre a malha do IBGE — é aproximado, não é o limite oficial do
- TSE.
-
{bundle.zoneBreakdown.map((zone) => (
{
if (selectedKeyRef.current !== key) return
- const navigation = resolveMunicipalityMapNavigation(key, municipalitiesByMapKey)
- if (navigation.kind === 'navigate') {
- router.push(`/campanha/municipios/${navigation.slug}`)
- }
+ // Annotated because `noUncheckedIndexedAccess` is off: the index is
+ // genuinely partial — a painted key outside the actor's scope has no slug.
+ const slug: string | undefined = municipalitiesByMapKey[key]
+ if (slug) router.push(`/campanha/municipios/${slug}`)
},
[municipalitiesByMapKey, router],
)
@@ -693,13 +697,9 @@ const MunicipalityMapSelection = ({
const selectedRawMetricValue =
selectedFeature && selectedFeature.key in rawValues ? rawValues[selectedFeature.key] : undefined
- const selectedNavigation = useMemo(
- () =>
- selectedFeature
- ? resolveMunicipalityMapNavigation(selectedFeature.key, municipalitiesByMapKey)
- : null,
- [municipalitiesByMapKey, selectedFeature],
- )
+ const selectedSlug: string | undefined = selectedFeature
+ ? municipalitiesByMapKey[selectedFeature.key]
+ : undefined
return (
<>
@@ -728,7 +728,7 @@ const MunicipalityMapSelection = ({
relativeReading={selectedFeature ? relativeReadingFor(selectedFeature.key) : null}
bubbleReading={selectedFeature ? bubbleReadingFor(selectedFeature.key) : null}
comparisonActive={comparisonActive}
- navigation={selectedNavigation}
+ municipalitySlug={selectedSlug}
/>
>
)
diff --git a/src/lib/bahiaGeometriesTypes.ts b/src/lib/bahiaGeometriesTypes.ts
index 363d877d..6e601405 100644
--- a/src/lib/bahiaGeometriesTypes.ts
+++ b/src/lib/bahiaGeometriesTypes.ts
@@ -1,6 +1,9 @@
-import type { Feature, GeoJsonProperties, MultiPolygon, Polygon } from 'geojson'
+import type { Feature, MultiPolygon, Polygon } from 'geojson'
import type { GeometryCollection, Topology } from 'topojson-specification'
+/** Every committed mesh is polygonal; only the properties differ. */
+type BahiaFeature = Feature
+
type BahiaMunicipalityProperties = {
codarea: string
name: string
@@ -18,18 +21,27 @@ type BahiaTerritoryProperties = {
type MunicipalityZoneProperties = {
municipalitySlug: string
name: string
- zoneNumber: number
ibgeCode: string
}
-export type BahiaMunicipalityFeature = Feature
+export type BahiaMunicipalityFeature = BahiaFeature
-export type BahiaTerritoryFeature = Feature
+export type BahiaTerritoryFeature = BahiaFeature
-export type MunicipalityZoneFeature = Feature
+export type MunicipalityZoneFeature = BahiaFeature
-/** Any feature of the committed meshes — for helpers that only read coordinates. */
-export type BahiaGeometryFeature = Feature
+/** Any feature of the committed meshes, as the map layer receives them. */
+export type BahiaMeshFeature =
+ | BahiaMunicipalityFeature
+ | BahiaTerritoryFeature
+ | MunicipalityZoneFeature
+
+/**
+ * What the geometry helpers actually need — a polygonal geometry, nothing else.
+ * Declaring the requirement instead of a feature union keeps `GeoJsonProperties`
+ * (which is `any`) out of the signature of a helper that only reads coordinates.
+ */
+export type PolygonalFeature = { geometry: Polygon | MultiPolygon }
export type MunicipalityTopology = Topology<{
municipalities: GeometryCollection
@@ -52,11 +64,9 @@ export type MunicipalityGeometryModule = {
export type TerritoryGeometryModule = {
topology: TerritoryTopology
features: readonly BahiaTerritoryFeature[]
- getTerritoryFeature: (code: string) => BahiaTerritoryFeature | undefined
}
export type MunicipalityZoneGeometryModule = {
topology: MunicipalityZoneTopology
features: readonly MunicipalityZoneFeature[]
- getMunicipalityZoneFeature: (municipalitySlug: string) => MunicipalityZoneFeature | undefined
}
diff --git a/src/lib/bahiaMapStyle.ts b/src/lib/bahiaMapStyle.ts
index 9f72b66b..96bdfe77 100644
--- a/src/lib/bahiaMapStyle.ts
+++ b/src/lib/bahiaMapStyle.ts
@@ -12,7 +12,8 @@ export type ChoroplethValues = Record
export type BahiaMapFillMode = 'sequential' | 'diverging'
-/** Properties that carry a map key, most specific first (see `featureMapKey`). */
+/** The three names a map key can arrive under — mutually exclusive on the
+ * committed meshes, so the order is incidental (see `featureMapKey`). */
const MAP_KEY_PROPERTIES = ['municipalitySlug', 'codarea', 'code'] as const
/**
@@ -96,8 +97,12 @@ export const canonicalMapKeysKey = (keys: string[]): string =>
* The key a feature is painted and addressed by, whichever mesh it came from:
* a zone municipality carries `municipalitySlug` (B8 F2 — the whole city shares
* one codarea, so the code cannot identify it), a município `codarea`, an
- * identity territory `code`. The three never coexist on one feature, so no mode
- * argument is needed.
+ * identity territory `code`. Exactly one of the three is present on any feature
+ * of the committed meshes, so this is a lookup over mutually exclusive names and
+ * not a precedence rule — no mode argument is needed. The zone mesh does also
+ * carry the city's `ibgeCode`, which is deliberately not a key property: all 19
+ * zones share it. Pinned against the real meshes in
+ * `tests/int/bahiaGeometries.int.spec.ts`.
*/
export const featureMapKey = (
properties: Record | undefined | null,
diff --git a/src/lib/bahiaMunicipalityZoneGeometries.ts b/src/lib/bahiaMunicipalityZoneGeometries.ts
index dc236004..6390153c 100644
--- a/src/lib/bahiaMunicipalityZoneGeometries.ts
+++ b/src/lib/bahiaMunicipalityZoneGeometries.ts
@@ -12,12 +12,7 @@ const topology = municipalityZoneTopologyJson as unknown as MunicipalityZoneTopo
const municipalityZoneFeatures = feature(topology, topology.objects.municipalityZones)
.features as MunicipalityZoneFeature[]
-const zoneBySlug = new Map(
- municipalityZoneFeatures.map((entry) => [entry.properties.municipalitySlug, entry]),
-)
-
export const municipalityZoneGeometryModule: MunicipalityZoneGeometryModule = {
topology,
features: municipalityZoneFeatures,
- getMunicipalityZoneFeature: (municipalitySlug: string) => zoneBySlug.get(municipalitySlug),
}
diff --git a/src/lib/bahiaTerritoryGeometries.ts b/src/lib/bahiaTerritoryGeometries.ts
index a2aa1516..548f5f73 100644
--- a/src/lib/bahiaTerritoryGeometries.ts
+++ b/src/lib/bahiaTerritoryGeometries.ts
@@ -12,10 +12,7 @@ const topology = territoryTopologyJson as unknown as TerritoryTopology
const territoryFeatures = feature(topology, topology.objects.territories)
.features as BahiaTerritoryFeature[]
-const territoryByCode = new Map(territoryFeatures.map((entry) => [entry.properties.code, entry]))
-
export const territoryGeometryModule: TerritoryGeometryModule = {
topology,
features: territoryFeatures,
- getTerritoryFeature: (code: string) => territoryByCode.get(code),
}
diff --git a/src/lib/geometries/bahia-identity-territories.topo.json b/src/lib/geometries/bahia-identity-territories.topo.json
index c3b96ae2..2723eb2f 100644
--- a/src/lib/geometries/bahia-identity-territories.topo.json
+++ b/src/lib/geometries/bahia-identity-territories.topo.json
@@ -1 +1 @@
-{"type":"Topology","bbox":[-46.5768,-18.3372,-37.349412961296125,-8.5328],"transform":{"scale":[0.0009228309869690843,0.0009805380538053805],"translate":[-46.5768,-18.3372]},"objects":{"territories":{"type":"GeometryCollection","geometries":[{"type":"MultiPolygon","arcs":[[[0,1,2]]],"properties":{"code":"01","name":"Irecê"}},{"type":"MultiPolygon","arcs":[[[3,4,5,6,7,-2,8,9]]],"properties":{"code":"02","name":"Velho Chico"}},{"type":"MultiPolygon","arcs":[[[10,11,12,13,14,-3,-8,15,16]]],"properties":{"code":"03","name":"Chapada Diamantina"}},{"type":"MultiPolygon","arcs":[[[17,18,19,20,21,22]]],"properties":{"code":"04","name":"Sisal"}},{"type":"MultiPolygon","arcs":[[[23,24,25,26,27]]],"properties":{"code":"05","name":"Litoral Sul"}},{"type":"MultiPolygon","arcs":[[[28,-26,29,30,31,32]]],"properties":{"code":"06","name":"Baixo Sul"}},{"type":"MultiPolygon","arcs":[[[33,34]]],"properties":{"code":"07","name":"Extremo Sul"}},{"type":"MultiPolygon","arcs":[[[35,36,-28,37,38]]],"properties":{"code":"08","name":"Médio Sudoeste da Bahia"}},{"type":"MultiPolygon","arcs":[[[39,40,-12,41,-33]]],"properties":{"code":"09","name":"Vale do Jiquiriçá"}},{"type":"MultiPolygon","arcs":[[[-9,-1,-15,42,43,-18,44,45,46,47]]],"properties":{"code":"10","name":"Sertão do São Francisco"}},{"type":"MultiPolygon","arcs":[[[48,-10,-48,49]]],"properties":{"code":"11","name":"Bacia do Rio Grande"}},{"type":"MultiPolygon","arcs":[[[-16,-7,50]]],"properties":{"code":"12","name":"Bacia do Paramirim"}},{"type":"MultiPolygon","arcs":[[[51,-17,-51,-6,52,53]]],"properties":{"code":"13","name":"Sertão Produtivo"}},{"type":"MultiPolygon","arcs":[[[54,-13,-41,55,56,57]]],"properties":{"code":"14","name":"Piemonte do Paraguaçu"}},{"type":"MultiPolygon","arcs":[[[58,-20,59,60,-58]]],"properties":{"code":"15","name":"Bacia do Jacuípe"}},{"type":"MultiPolygon","arcs":[[[-43,-14,-55,-61,61]]],"properties":{"code":"16","name":"Piemonte da Diamantina"}},{"type":"MultiPolygon","arcs":[[[62,-45,-23,63,64]]],"properties":{"code":"17","name":"Semiárido Nordeste II"}},{"type":"MultiPolygon","arcs":[[[-64,-22,65,66,67]]],"properties":{"code":"18","name":"Litoral Norte e Agreste Baiano"}},{"type":"MultiPolygon","arcs":[[[-59,-57,68,69,-66,-21]]],"properties":{"code":"19","name":"Portal do Sertão"}},{"type":"MultiPolygon","arcs":[[[-54,70,-39,71]]],"properties":{"code":"20","name":"Sudoeste Baiano"}},{"type":"MultiPolygon","arcs":[[[-56,-40,-32,72,-69]]],"properties":{"code":"21","name":"Recôncavo"}},{"type":"MultiPolygon","arcs":[[[-11,-52,-72,-38,-27,-29,-42]]],"properties":{"code":"22","name":"Médio Rio de Contas"}},{"type":"MultiPolygon","arcs":[[[73,-4,-49]]],"properties":{"code":"23","name":"Bacia do Rio Corrente"}},{"type":"MultiPolygon","arcs":[[[-63,74,-46]]],"properties":{"code":"24","name":"Itaparica"}},{"type":"MultiPolygon","arcs":[[[-62,-60,-19,-44]]],"properties":{"code":"25","name":"Piemonte Norte do Itapicuru"}},{"type":"MultiPolygon","arcs":[[[-67,-70,-73,-31,75]]],"properties":{"code":"26","name":"Metropolitano de Salvador"}},{"type":"MultiPolygon","arcs":[[[76,-34,77,-24,-37]]],"properties":{"code":"27","name":"Costa do Descobrimento"}}]}},"arcs":[[[5325,7675],[-88,106],[-27,-15],[-159,81],[-90,1],[-72,114],[-29,151],[-46,38],[-28,89],[-266,74],[1,-69],[-59,-59],[-6,-73],[-114,-90],[-53,-100]],[[4289,7923],[-46,-20],[-45,-129],[-84,-105],[-89,7],[-136,-100],[-69,-99],[-48,-21],[-58,-140],[-54,-76],[29,-80],[-55,-57],[-45,-113],[225,-46],[58,-70],[75,-32],[15,50],[72,-33],[119,-95],[-30,-106],[78,-69],[34,10],[225,-101],[234,18],[170,-244],[-1,-106]],[[4863,6166],[53,0],[-18,72],[77,-72],[19,26],[-2,177],[23,71],[-82,132],[3,79],[152,-77],[463,-212],[107,-71],[-14,87],[-95,116],[99,274],[-76,67],[-133,78],[166,115],[52,222],[-13,87],[-74,123],[-2,46],[-110,10],[-30,65],[-79,48],[-24,46]],[[2870,6215],[134,-3],[82,-66],[47,-8],[-23,-53],[166,-139],[119,-45],[-100,-88],[-15,-254],[-47,-40],[-101,-8],[5,-186],[45,-70],[-57,15],[-178,-94],[-54,-172],[13,-43],[80,-17],[-121,-170],[129,-53],[-70,-37],[-27,-54],[-109,-33],[-67,-117],[-31,30],[-14,-72],[-95,60],[-39,-17],[-50,-90],[-111,-13],[-51,-38],[-15,-109],[31,-95]],[[2346,4136],[103,42],[82,0],[118,-42],[147,16],[59,-35],[114,-12],[58,-28],[-94,-177],[-14,-142],[185,-64]],[[3104,3694],[60,45],[27,101],[-92,185],[21,43],[133,66],[5,104],[123,16],[-34,77],[48,201],[75,-85],[107,-17],[160,13],[25,50],[89,12],[178,-101],[64,-19],[313,119],[-83,88],[-22,76],[-41,17],[-85,144],[15,101],[32,25]],[[4222,4955],[-95,75],[-14,42],[-142,70],[10,138],[-77,135],[1,77],[89,64],[14,168],[-11,187],[68,-29],[202,70]],[[4267,5952],[115,-47],[217,72],[29,74],[56,-4],[-17,99],[158,34],[38,-14]],[[4289,7923],[-716,338],[-114,-3]],[[3459,8258],[9,-212],[-1,-276],[-12,-143],[-174,-12],[-228,-40],[-90,61],[-63,-7],[-61,-73],[-75,-28],[109,-129],[69,-203],[49,-107],[50,-205],[100,-211],[18,-73],[-107,-141],[31,-45],[-69,-45],[-30,-58],[-70,-24],[-44,-72]],[[6129,4534],[45,48],[243,5]],[[6417,4587],[-50,39],[-25,112],[38,84],[-8,103],[-33,78],[-61,65],[69,131],[100,58],[46,-33],[80,39],[46,65],[57,26]],[[6676,5354],[-96,145],[-77,-59],[-85,2],[-143,-44],[-110,39],[-63,-33],[-39,127],[-42,-2],[57,125],[-43,176],[47,130],[-19,33],[-111,-5],[-133,-40],[52,121],[104,103],[86,23],[-71,83],[83,53],[85,-26],[23,30],[-39,67],[10,83],[-81,91],[97,134],[39,-19],[159,233]],[[6366,6924],[-175,136],[-90,132],[-203,134],[-115,8],[-84,74],[22,71],[69,48],[-60,48],[-150,44],[-54,113],[-102,0]],[[5424,7732],[-37,-55],[-62,-2]],[[4267,5952],[-18,-19],[31,-109],[47,-56],[109,-31],[37,25],[199,-40],[57,-199],[105,-107],[13,-108],[140,-111],[68,-23],[13,-41],[-51,-40],[-23,-188]],[[4994,4905],[118,-45],[105,-91],[56,-25],[150,-200],[14,-64],[71,28],[-55,158],[-29,5],[-40,99],[350,-23],[39,-36],[99,42],[56,52],[80,-1],[-3,-156],[124,-114]],[[8010,8241],[-55,64],[-147,22],[-167,-16],[-37,83],[-31,-19],[-161,62],[3,-25]],[[7415,8412],[-3,-143],[25,-92],[-19,-93],[-78,-16],[-130,-70],[-6,-47],[-97,-81],[24,-12],[-67,-230],[54,-60],[-18,-66],[46,-173]],[[7146,7329],[31,-6],[-2,-94],[102,-65],[14,-38],[99,-73],[63,23],[111,-135],[119,-71],[134,-47],[133,-129],[-44,-60],[-17,-162]],[[7889,6472],[132,10],[59,58],[47,98],[78,17],[75,-27],[22,-63],[43,79],[140,132],[79,0]],[[8564,6776],[-117,334],[9,9]],[[8456,7119],[160,174],[16,50],[57,10],[-38,142],[-80,91],[-47,9],[-70,118],[46,58],[-8,72],[-42,43],[-174,-19],[-12,-32],[-96,24],[-239,-48],[23,61],[89,63],[9,175],[-40,131]],[[7595,2615],[-5,-22],[113,-40],[75,40],[47,-56],[74,6],[53,48],[373,31]],[[8325,2622],[-45,103],[-18,200],[-42,185],[-7,307],[-22,65],[-11,143],[-30,16],[-7,145],[66,285],[21,48],[-10,99],[39,127],[28,173],[-25,35]],[[8262,4553],[-53,-64],[-4,-99],[24,-42],[-124,-38],[-50,20],[-220,-58],[-105,-53],[-1,-42],[-77,21]],[[7652,4198],[-65,-32],[144,-53],[-23,-36],[-93,-7],[-96,81],[-40,-25],[-23,-80]],[[7456,4046],[-40,-150],[19,-63],[-41,-167],[-28,1],[-19,-145],[65,-29],[13,-55],[-94,-5],[-107,-64],[68,-283],[41,-14],[21,-101],[-55,-60],[12,-50],[127,-35],[31,-50],[119,21],[53,-20],[-12,-140],[-34,-22]],[[7437,4693],[76,45],[97,-36],[26,-79],[-28,-34],[74,-44],[-45,-36],[54,-66],[-8,-141],[-31,-104]],[[8262,4553],[-50,128],[67,91],[49,18],[-46,79],[44,104],[-13,76],[-45,-13],[-22,59],[37,122],[147,86]],[[8430,5303],[-4,77],[54,97]],[[8480,5477],[-177,36],[34,-67],[-80,-66],[-213,22],[-52,-38]],[[7992,5364],[85,-32],[-99,0],[-96,-56],[143,-71],[-53,-6],[-13,-54],[-90,88],[-35,-46],[-99,14],[12,-59],[-47,-12],[7,-62],[-113,-112],[-64,-5],[-44,-56],[-63,35],[-94,-62],[108,-175]],[[8083,1473],[-53,-37],[-135,42],[-214,-41],[-26,89],[-77,-13],[-122,127],[-136,-36],[-74,39],[-258,48],[-8,-30],[-122,-7],[-64,19]],[[6794,1673],[-18,-107],[79,-30],[-34,-71],[-90,27],[-46,-25],[-79,22],[-68,-108],[-38,-170],[33,-137],[-66,-44],[10,-66],[126,-98],[26,-83],[49,-41],[76,-6],[77,-114],[64,-26],[43,-101],[-97,-72],[45,-59],[601,-364],[35,107],[156,239],[71,66],[171,72],[11,35],[130,138],[-42,64],[-17,188],[-28,113],[6,177],[33,50],[33,174],[37,50]],[[6368,2723],[81,-52],[70,-87],[105,49],[42,-51],[95,-19],[110,21],[82,-107],[81,12],[20,-64],[68,-43],[97,2]],[[7219,2384],[78,23],[-116,83],[43,29],[81,-17],[52,73],[169,70],[69,-30]],[[7456,4046],[-101,20],[-52,-95],[-70,8],[-115,-96],[-75,-8],[-96,60]],[[6947,3935],[-41,-78],[-19,-120],[-81,11],[-26,-83],[10,-99],[31,-15],[-89,-58],[-48,61],[-28,-68],[-126,-120],[-163,-40],[-128,-129],[-30,-68],[169,29],[92,-44],[126,4],[21,-21],[-33,-118],[22,-192],[-42,-84],[-127,-9],[-69,29]],[[7992,5364],[-49,-18],[-103,35],[-65,65],[-45,4],[-35,142]],[[7695,5592],[-175,-78],[-213,112],[-65,69],[-38,-65],[32,-59],[-97,-57],[-3,-33],[-83,-30],[-83,10],[-59,-68],[-132,9],[-19,-42],[-84,-6]],[[6417,4587],[162,-48],[71,22],[-86,77],[-20,62],[69,51],[7,-39],[191,16],[104,-9],[109,26],[8,45],[107,-1],[102,-55],[46,40],[6,-68],[83,-63],[61,50]],[[5424,7732],[-21,25],[216,169],[11,48],[-99,54],[102,49],[56,63],[53,9]],[[5742,8149],[145,126],[-30,27],[2,168],[-93,59],[21,49],[55,-30],[87,43],[23,-33],[94,61],[115,-28],[65,50],[204,-23],[152,-86],[98,-2],[104,67],[33,-39],[112,60],[303,107],[6,42],[65,-89],[108,-74],[-32,-71],[10,-105],[26,-16]],[[8010,8241],[116,-126],[213,112],[325,-35],[6,81],[-171,63],[23,38],[-100,118],[-124,51],[-14,88],[77,51],[-4,44],[85,35],[2,102]],[[8444,8863],[-83,16],[-113,-8],[-157,13],[-185,-9],[-85,20],[-93,107],[37,55],[3,96],[55,76],[-16,63],[23,70],[-62,25],[-65,160],[-25,143],[128,278],[18,16]],[[7824,9984],[-103,-16],[-176,-96],[-81,-4],[17,-126],[-125,-35],[-113,-10],[20,-110],[-88,-112],[-120,-17],[-69,-48],[-118,57],[-37,-29],[-40,-196],[-51,-104],[-66,25],[-54,-69],[-47,13],[-48,-51],[-73,-26],[-156,38],[32,111],[-21,22],[75,38],[22,121],[-167,81],[-32,128],[-76,121],[-109,-8],[-16,59],[-73,5],[-9,77],[-123,1],[-58,-32],[-111,29],[-47,-97],[-93,-75],[-38,-87],[-65,4],[-128,-57],[-10,-76],[-73,-61],[-41,-97],[-90,-37],[-56,31],[-140,-34],[-148,-4],[-84,-31],[-192,-182],[-105,-4],[-32,-41],[-104,-16],[-59,-66],[-54,0],[-9,60],[-52,-1],[-81,52],[-39,111],[-58,-13],[-131,36],[-134,-42],[-199,163],[-113,-57],[-126,-106],[-105,-38],[-72,-107],[12,-77],[62,-127],[143,-83],[-61,-71],[47,-79],[-28,-84],[-74,-1],[-27,-120],[-57,-59],[0,-54],[-85,-92]],[[2884,8102],[157,0],[48,37],[71,-18],[-4,49],[87,80],[216,8]],[[398,4968],[302,173],[113,44],[104,19],[132,50],[57,-7],[120,39],[37,-15],[234,45],[276,101],[166,36],[91,-85],[90,61],[0,43],[76,29],[225,-179],[39,93],[70,76],[4,69],[61,9],[32,102],[-122,145],[34,65],[-88,48],[-17,58],[19,163],[74,43],[177,12],[34,-20],[132,30]],[[2884,8102],[-1,-34],[-121,14],[2,-64],[-50,-107],[-73,-61],[-138,17],[-52,67],[-148,-50],[-53,-44],[-84,23],[-98,-61],[-13,-82],[-116,-42],[-22,-59],[-133,-64],[-165,92],[-177,17],[-25,47],[-97,45],[-29,82],[-56,37],[-11,108],[55,66],[-37,87],[-91,71],[-57,90],[0,63],[-39,33],[-94,-49],[-10,-105],[-30,-55],[-77,-11],[-24,-135],[-260,-147],[-74,-21],[-85,-181],[-59,-14],[-7,-126],[-80,-4],[-228,-330],[-27,-81],[49,-35],[8,-89],[92,-59],[96,16],[108,-32],[45,-49],[139,-40],[-128,-24],[-49,43],[-125,-27],[56,-55],[-71,-84],[49,-5],[-56,-95],[90,-72],[-135,-93],[55,-73],[-28,-73],[29,-61],[0,-118],[87,-31],[19,-139],[80,10],[-107,-73],[-11,-62],[42,-81],[-46,-81],[40,-21],[-50,-143],[130,9],[79,35],[2,-48],[-163,-61],[-58,-82],[37,-43],[-35,-113],[38,-65],[205,61],[38,-39],[-73,-82],[-117,-49],[37,-43]],[[4222,4955],[59,75],[84,-56],[93,21],[62,-143],[51,-48],[118,15],[34,-44],[79,-18],[-12,-53],[112,22],[36,80],[-3,63],[59,36]],[[6097,4519],[32,15]],[[3104,3694],[185,-65],[12,-37],[75,70],[162,78],[148,19],[178,-51],[79,-7],[35,-54],[164,-87],[147,-95]],[[4289,3465],[65,118],[-24,55],[31,157],[-26,9],[-3,160],[84,52],[118,-27],[45,-47],[15,-151],[74,-12],[121,35],[-23,85],[117,68],[151,29],[104,-47],[153,-11],[61,-34],[112,11],[-27,19],[-12,179],[63,136],[142,70],[14,-35],[-37,-127],[116,-18],[203,-91],[17,82],[92,78],[-14,144],[45,49],[-3,79],[34,39]],[[6725,6854],[-104,15],[-61,-30],[-7,54],[-76,26],[-111,5]],[[7695,5592],[-29,42],[6,75],[67,65],[20,61],[106,70]],[[7865,5905],[-81,44],[22,69],[-26,89],[-37,21]],[[7743,6128],[-115,-13],[-140,-68],[-78,-2],[-192,-101],[-157,171],[-56,12],[-31,85],[117,76],[-51,65],[-156,11],[-119,123],[64,70],[-97,81],[11,155],[-18,61]],[[7743,6128],[25,64],[73,70],[52,10],[48,82],[37,11],[-89,107]],[[7146,7329],[-9,-12]],[[7137,7317],[-93,-34],[-74,14],[65,-71],[-26,-53],[-86,-36],[-18,-44],[10,-120],[31,-22],[-65,-44],[-73,72],[-16,60],[-81,-71],[14,-114]],[[7137,7317],[-204,58],[-228,45],[44,99],[109,55],[7,65],[-254,85],[-8,81],[-71,-16],[-214,68],[-17,41],[-187,-13],[68,107],[-76,-9],[-28,59],[-151,-15],[-81,36],[-47,-23],[-57,109]],[[9228,8923],[-67,-33],[-38,-59],[-138,-13],[-25,30],[-60,-46],[-134,-6],[-67,27],[-255,40]],[[8456,7119],[164,-55],[-46,-21],[179,-61],[54,71],[82,170],[-77,87],[8,52],[125,47],[83,154],[38,-10]],[[9066,7553],[-38,110],[31,98],[189,27],[71,-58],[181,73],[-3,180],[-50,83],[22,48],[104,44],[-5,102],[-59,128],[21,70],[-47,7],[-96,106],[-97,29],[3,91],[-48,120],[39,49],[-56,63]],[[8564,6776],[143,-63],[-39,-47],[-29,-106],[-114,-57],[-15,-53],[72,-41],[-82,-105],[81,-38],[77,-1],[65,-83],[1,-143]],[[8724,6039],[151,-15],[-3,28],[126,127],[107,18],[34,-113],[73,-87],[38,-6],[104,88],[55,-32]],[[9409,6047],[135,173],[173,288],[105,219],[171,303],[-112,-81],[-130,-29],[-58,34],[-45,-51],[-31,29],[-122,27],[-37,74],[-95,20],[-75,138],[26,89],[-71,18],[-51,82],[20,24],[-146,149]],[[7865,5905],[100,1],[22,34],[143,11],[72,-68],[105,52],[79,4],[5,148],[99,-107],[93,-11],[13,-29]],[[8596,5940],[89,92],[39,7]],[[4289,3465],[198,-88],[-7,-36],[116,-18],[76,-47],[99,40],[96,-103],[98,28],[46,-17],[87,61],[76,16],[483,-408],[27,-249],[126,8],[78,-36],[69,53],[79,6],[47,67],[66,-44],[93,45],[53,-68],[73,48]],[[6947,3935],[-282,97],[-86,47],[123,55],[-199,106],[-318,151],[-66,50],[-22,78]],[[8480,5477],[47,67],[25,221],[-36,44],[33,91],[47,40]],[[398,4968],[-41,-57],[2,-57],[89,-26],[-101,-83],[36,-82],[-59,-26],[49,-59],[-35,-101],[48,-29],[-1,-134],[37,-47],[242,-134],[62,-72],[-27,-55],[-78,-17],[-16,-47],[47,-68],[-24,-66],[-5,-196],[-38,-81],[77,-92],[-9,-73],[-75,-83],[-4,-47],[-76,-41],[43,-62],[127,124],[96,-16],[65,47],[66,-10],[84,46],[115,135],[84,-16],[86,39],[222,182],[118,-9],[71,79],[176,84],[39,96],[83,21],[206,140],[84,13],[83,48]],[[9228,8923],[68,90],[-87,60],[-83,-3],[-94,123],[-83,186],[-9,61],[40,34],[-37,59],[-86,-48],[-108,56],[-9,58],[45,60],[-109,36],[-70,-159],[-42,15],[-35,112],[-109,76],[-158,-17],[-88,69],[-211,27],[-15,75],[-48,74],[-76,17]],[[8430,5303],[167,125],[189,0],[125,59],[119,107],[212,220],[167,233]],[[7219,2384],[-23,-25],[86,-91],[-28,-83],[-58,-50],[19,-41],[-115,-74],[-60,-110],[-25,28],[-73,-90],[13,-55],[-127,6],[-34,-126]],[[8083,1473],[-27,25],[3,117],[39,57],[45,267],[57,62],[-14,92],[80,132],[5,84],[99,228],[-45,85]]]}
+{"type":"Topology","bbox":[-46.5768,-18.3372,-37.349412961296125,-8.5328],"transform":{"scale":[0.000923662366236624,0.0009814214214214213],"translate":[-46.5768,-18.3372]},"objects":{"territories":{"type":"GeometryCollection","geometries":[{"type":"MultiPolygon","arcs":[[[0,1,2]]],"properties":{"code":"01","name":"Irecê"}},{"type":"MultiPolygon","arcs":[[[3,4,5,6,7,-2,8,9]]],"properties":{"code":"02","name":"Velho Chico"}},{"type":"MultiPolygon","arcs":[[[10,11,12,13,14,-3,-8,15,16]]],"properties":{"code":"03","name":"Chapada Diamantina"}},{"type":"MultiPolygon","arcs":[[[17,18,19,20,21,22]]],"properties":{"code":"04","name":"Sisal"}},{"type":"MultiPolygon","arcs":[[[23,24,25,26,27]]],"properties":{"code":"05","name":"Litoral Sul"}},{"type":"MultiPolygon","arcs":[[[28,-26,29,30,31,32]]],"properties":{"code":"06","name":"Baixo Sul"}},{"type":"MultiPolygon","arcs":[[[33,34]]],"properties":{"code":"07","name":"Extremo Sul"}},{"type":"MultiPolygon","arcs":[[[35,36,-28,37,38]]],"properties":{"code":"08","name":"Médio Sudoeste da Bahia"}},{"type":"MultiPolygon","arcs":[[[39,40,-12,41,-33]]],"properties":{"code":"09","name":"Vale do Jiquiriçá"}},{"type":"MultiPolygon","arcs":[[[-9,-1,-15,42,43,-18,44,45,46,47]]],"properties":{"code":"10","name":"Sertão do São Francisco"}},{"type":"MultiPolygon","arcs":[[[48,-10,-48,49]]],"properties":{"code":"11","name":"Bacia do Rio Grande"}},{"type":"MultiPolygon","arcs":[[[-16,-7,50]]],"properties":{"code":"12","name":"Bacia do Paramirim"}},{"type":"MultiPolygon","arcs":[[[51,-17,-51,-6,52,53]]],"properties":{"code":"13","name":"Sertão Produtivo"}},{"type":"MultiPolygon","arcs":[[[54,-13,-41,55,56,57]]],"properties":{"code":"14","name":"Piemonte do Paraguaçu"}},{"type":"MultiPolygon","arcs":[[[58,-20,59,60,-58]]],"properties":{"code":"15","name":"Bacia do Jacuípe"}},{"type":"MultiPolygon","arcs":[[[-43,-14,-55,-61,61]]],"properties":{"code":"16","name":"Piemonte da Diamantina"}},{"type":"MultiPolygon","arcs":[[[62,-45,-23,63,64]]],"properties":{"code":"17","name":"Semiárido Nordeste II"}},{"type":"MultiPolygon","arcs":[[[-64,-22,65,66,67]]],"properties":{"code":"18","name":"Litoral Norte e Agreste Baiano"}},{"type":"MultiPolygon","arcs":[[[-59,-57,68,69,-66,-21]]],"properties":{"code":"19","name":"Portal do Sertão"}},{"type":"MultiPolygon","arcs":[[[-54,70,-39,71]]],"properties":{"code":"20","name":"Sudoeste Baiano"}},{"type":"MultiPolygon","arcs":[[[-56,-40,-32,72,-69]]],"properties":{"code":"21","name":"Recôncavo"}},{"type":"MultiPolygon","arcs":[[[-11,-52,-72,-38,-27,-29,-42]]],"properties":{"code":"22","name":"Médio Rio de Contas"}},{"type":"MultiPolygon","arcs":[[[73,-4,-49]]],"properties":{"code":"23","name":"Bacia do Rio Corrente"}},{"type":"MultiPolygon","arcs":[[[-63,74,-46]]],"properties":{"code":"24","name":"Itaparica"}},{"type":"MultiPolygon","arcs":[[[-62,-60,-19,-44]]],"properties":{"code":"25","name":"Piemonte Norte do Itapicuru"}},{"type":"MultiPolygon","arcs":[[[-67,-70,-73,-31,75]]],"properties":{"code":"26","name":"Metropolitano de Salvador"}},{"type":"MultiPolygon","arcs":[[[76,-34,77,-24,-37]]],"properties":{"code":"27","name":"Costa do Descobrimento"}}]}},"arcs":[[[5320,7668],[-88,106],[-27,-15],[-159,81],[-89,1],[-72,114],[-29,151],[-46,38],[-28,89],[-266,74],[1,-69],[-59,-59],[-6,-73],[-114,-90],[-53,-100]],[[4285,7916],[-46,-20],[-45,-129],[-84,-105],[-89,7],[-136,-100],[-68,-99],[-48,-21],[-58,-140],[-54,-76],[29,-79],[-55,-57],[-45,-113],[225,-46],[58,-70],[74,-32],[15,50],[72,-33],[119,-95],[-30,-106],[78,-69],[34,10],[225,-101],[234,18],[170,-244],[-1,-106]],[[4859,6160],[53,0],[-18,72],[77,-72],[19,26],[-2,177],[22,71],[-81,132],[3,79],[151,-77],[463,-212],[107,-71],[-14,87],[-95,116],[99,274],[-76,67],[-133,78],[166,115],[52,221],[-13,87],[-74,123],[-2,46],[-110,10],[-30,65],[-79,48],[-24,46]],[[2867,6209],[134,-3],[82,-66],[47,-8],[-23,-52],[166,-139],[119,-45],[-100,-88],[-15,-254],[-47,-40],[-101,-8],[5,-186],[45,-70],[-57,15],[-178,-94],[-54,-172],[13,-42],[80,-17],[-121,-170],[129,-53],[-70,-37],[-27,-54],[-109,-33],[-66,-117],[-31,30],[-14,-72],[-95,60],[-39,-17],[-50,-90],[-111,-13],[-51,-38],[-15,-109],[31,-95]],[[2344,4132],[103,42],[82,0],[118,-42],[146,16],[59,-35],[114,-12],[58,-28],[-94,-177],[-14,-141],[185,-64]],[[3101,3691],[60,45],[27,101],[-92,184],[21,43],[133,66],[5,104],[123,16],[-34,77],[48,201],[75,-85],[107,-17],[160,13],[25,50],[89,12],[177,-101],[64,-19],[313,119],[-83,88],[-22,76],[-41,17],[-85,144],[15,101],[32,25]],[[4218,4951],[-95,74],[-14,42],[-142,70],[10,138],[-77,135],[1,77],[89,64],[14,168],[-11,187],[68,-29],[202,70]],[[4263,5947],[115,-47],[217,72],[29,74],[56,-4],[-17,98],[158,34],[38,-14]],[[4285,7916],[-715,338],[-114,-3]],[[3456,8251],[9,-212],[-1,-276],[-12,-143],[-174,-12],[-228,-40],[-90,61],[-63,-7],[-61,-73],[-74,-28],[108,-129],[69,-202],[49,-107],[50,-205],[100,-211],[18,-73],[-107,-141],[31,-45],[-69,-45],[-30,-58],[-70,-24],[-44,-72]],[[6123,4530],[45,48],[243,5]],[[6411,4583],[-50,39],[-25,112],[38,84],[-8,103],[-33,77],[-61,65],[69,131],[100,58],[46,-33],[80,39],[46,65],[57,26]],[[6670,5349],[-96,145],[-77,-59],[-85,2],[-143,-44],[-110,39],[-62,-33],[-39,127],[-42,-2],[57,125],[-43,176],[47,130],[-19,33],[-111,-5],[-133,-40],[52,121],[104,102],[86,23],[-71,83],[83,53],[84,-26],[23,30],[-39,67],[10,83],[-80,91],[96,134],[39,-19],[159,233]],[[6360,6918],[-175,136],[-89,132],[-203,133],[-115,8],[-84,74],[22,71],[69,48],[-60,48],[-150,44],[-54,113],[-102,0]],[[5419,7725],[-37,-55],[-62,-2]],[[4263,5947],[-18,-19],[31,-109],[47,-56],[109,-31],[37,25],[199,-40],[57,-199],[105,-107],[13,-108],[140,-111],[67,-23],[13,-41],[-51,-40],[-22,-187]],[[4990,4901],[117,-45],[105,-91],[56,-25],[150,-200],[14,-64],[71,28],[-55,158],[-29,5],[-40,99],[350,-23],[39,-36],[99,42],[56,52],[80,-1],[-3,-156],[123,-114]],[[8003,8234],[-55,64],[-147,22],[-167,-16],[-37,82],[-31,-19],[-161,62],[3,-25]],[[7408,8404],[-3,-142],[25,-92],[-19,-93],[-78,-16],[-129,-70],[-6,-47],[-97,-81],[24,-12],[-67,-230],[54,-60],[-18,-66],[46,-173]],[[7140,7322],[31,-6],[-2,-94],[101,-64],[14,-38],[99,-73],[63,23],[111,-135],[119,-71],[134,-47],[133,-129],[-44,-60],[-17,-162]],[[7882,6466],[132,10],[59,58],[47,98],[78,17],[75,-27],[22,-63],[42,79],[140,132],[79,0]],[[8556,6770],[-117,334],[9,9]],[[8448,7113],[160,173],[16,50],[57,10],[-38,142],[-80,91],[-47,9],[-70,118],[46,58],[-8,72],[-42,43],[-173,-19],[-12,-32],[-96,24],[-239,-48],[23,61],[89,63],[9,175],[-40,131]],[[7588,2613],[-5,-22],[113,-40],[75,40],[47,-56],[74,6],[53,48],[373,31]],[[8318,2620],[-45,103],[-18,199],[-42,185],[-7,307],[-22,65],[-11,143],[-30,16],[-7,145],[66,284],[21,48],[-10,99],[39,127],[28,173],[-25,35]],[[8255,4549],[-53,-64],[-4,-99],[24,-42],[-124,-38],[-50,20],[-220,-58],[-105,-53],[-1,-42],[-77,21]],[[7645,4194],[-65,-32],[144,-53],[-23,-36],[-93,-7],[-96,81],[-40,-25],[-23,-80]],[[7449,4042],[-40,-150],[19,-62],[-41,-167],[-28,1],[-19,-145],[65,-29],[13,-55],[-94,-5],[-107,-64],[68,-283],[41,-14],[21,-101],[-55,-60],[12,-50],[127,-35],[31,-49],[119,20],[53,-19],[-12,-140],[-34,-22]],[[7430,4689],[76,45],[97,-36],[26,-79],[-28,-34],[74,-44],[-45,-36],[54,-66],[-8,-141],[-31,-104]],[[8255,4549],[-50,128],[67,91],[49,18],[-46,79],[44,104],[-13,75],[-45,-13],[-22,59],[37,122],[146,86]],[[8422,5298],[-4,77],[54,97]],[[8472,5472],[-176,36],[33,-67],[-79,-66],[-213,22],[-52,-38]],[[7985,5359],[85,-32],[-99,0],[-96,-56],[143,-71],[-53,-6],[-13,-54],[-90,88],[-35,-46],[-99,14],[12,-59],[-47,-12],[7,-62],[-113,-111],[-64,-5],[-44,-56],[-63,35],[-94,-62],[108,-175]],[[8076,1472],[-53,-37],[-135,42],[-214,-41],[-26,89],[-77,-13],[-122,127],[-136,-36],[-74,39],[-257,47],[-8,-29],[-122,-7],[-64,18]],[[6788,1671],[-18,-106],[79,-30],[-34,-71],[-90,27],[-46,-25],[-79,22],[-68,-108],[-38,-170],[33,-137],[-66,-44],[10,-66],[126,-98],[26,-83],[49,-41],[76,-6],[77,-114],[64,-26],[43,-100],[-97,-72],[45,-59],[600,-364],[35,107],[156,239],[71,66],[171,72],[11,35],[130,137],[-42,64],[-17,188],[-28,113],[6,177],[33,50],[33,174],[37,50]],[[6362,2721],[81,-52],[70,-87],[105,49],[42,-51],[95,-19],[110,21],[82,-107],[81,12],[20,-64],[68,-43],[97,2]],[[7213,2382],[77,23],[-115,83],[42,29],[81,-17],[52,73],[169,70],[69,-30]],[[7449,4042],[-101,20],[-52,-95],[-70,8],[-114,-95],[-75,-8],[-96,59]],[[6941,3931],[-41,-77],[-19,-120],[-81,11],[-26,-83],[10,-99],[31,-15],[-89,-58],[-48,61],[-28,-68],[-126,-120],[-163,-40],[-128,-129],[-30,-68],[169,29],[92,-44],[126,4],[21,-21],[-33,-118],[22,-192],[-42,-83],[-127,-9],[-69,29]],[[7985,5359],[-49,-18],[-103,35],[-65,65],[-45,4],[-35,142]],[[7688,5587],[-175,-78],[-213,112],[-65,69],[-37,-65],[31,-59],[-96,-57],[-3,-33],[-83,-30],[-83,10],[-59,-68],[-132,9],[-19,-42],[-84,-6]],[[6411,4583],[162,-48],[71,22],[-86,77],[-20,62],[69,51],[7,-39],[191,16],[104,-9],[109,26],[8,45],[107,-1],[101,-55],[46,40],[6,-68],[83,-63],[61,50]],[[5419,7725],[-21,25],[216,169],[11,48],[-99,54],[102,49],[56,63],[53,9]],[[5737,8142],[145,126],[-30,27],[2,167],[-93,59],[21,49],[55,-30],[87,43],[23,-33],[94,61],[114,-28],[65,50],[204,-23],[152,-86],[98,-2],[104,67],[33,-39],[112,60],[302,107],[6,42],[65,-89],[108,-74],[-32,-71],[10,-105],[26,-16]],[[8003,8234],[116,-126],[212,112],[325,-35],[6,81],[-171,62],[23,38],[-100,118],[-123,51],[-14,88],[76,51],[-4,44],[85,35],[2,102]],[[8436,8855],[-83,16],[-112,-8],[-157,13],[-185,-9],[-85,20],[-93,107],[37,55],[3,96],[55,76],[-16,63],[23,70],[-62,25],[-65,159],[-25,143],[128,278],[18,16]],[[7817,9975],[-103,-16],[-176,-96],[-81,-4],[17,-126],[-125,-35],[-113,-10],[20,-110],[-87,-112],[-120,-17],[-69,-47],[-118,56],[-37,-28],[-40,-196],[-51,-104],[-66,25],[-54,-69],[-47,13],[-48,-51],[-73,-26],[-156,38],[32,111],[-21,22],[75,38],[22,121],[-167,81],[-32,127],[-76,121],[-108,-8],[-16,59],[-73,5],[-9,77],[-123,1],[-58,-32],[-111,29],[-47,-97],[-93,-75],[-38,-87],[-65,4],[-128,-57],[-10,-75],[-73,-61],[-41,-97],[-90,-37],[-55,31],[-140,-34],[-148,-4],[-84,-31],[-192,-182],[-105,-4],[-32,-41],[-104,-16],[-59,-66],[-54,0],[-9,60],[-52,-1],[-81,52],[-39,111],[-57,-13],[-131,36],[-134,-42],[-199,163],[-113,-57],[-126,-106],[-105,-38],[-72,-107],[12,-77],[62,-127],[143,-83],[-61,-71],[47,-79],[-28,-84],[-74,-1],[-27,-119],[-57,-59],[0,-54],[-85,-92]],[[2881,8095],[157,0],[48,37],[71,-18],[-4,49],[87,80],[216,8]],[[398,4964],[301,172],[113,44],[104,19],[132,50],[57,-7],[120,39],[37,-15],[234,45],[275,101],[166,36],[91,-85],[90,61],[0,43],[76,29],[225,-179],[39,93],[70,76],[4,69],[61,9],[32,102],[-122,145],[34,65],[-88,48],[-17,58],[19,162],[74,43],[177,12],[34,-20],[131,30]],[[2881,8095],[-1,-34],[-120,14],[2,-64],[-50,-107],[-73,-61],[-138,17],[-52,67],[-148,-50],[-53,-44],[-84,23],[-98,-61],[-13,-82],[-116,-42],[-22,-59],[-133,-64],[-164,92],[-177,17],[-25,47],[-97,45],[-29,82],[-56,37],[-11,108],[55,66],[-37,87],[-91,71],[-57,90],[0,62],[-39,33],[-94,-49],[-10,-104],[-30,-55],[-77,-11],[-24,-135],[-260,-147],[-73,-21],[-85,-181],[-59,-14],[-7,-126],[-80,-4],[-228,-329],[-27,-81],[49,-35],[8,-89],[92,-59],[96,16],[108,-32],[45,-49],[139,-40],[-128,-24],[-49,43],[-125,-27],[56,-55],[-71,-84],[49,-5],[-56,-95],[90,-72],[-135,-93],[55,-73],[-28,-73],[29,-61],[0,-117],[87,-31],[19,-139],[80,10],[-107,-73],[-11,-62],[42,-81],[-46,-81],[40,-21],[-50,-143],[130,9],[79,35],[2,-48],[-163,-61],[-58,-82],[37,-43],[-35,-113],[38,-65],[205,61],[38,-39],[-73,-82],[-117,-49],[37,-42]],[[4218,4951],[59,74],[84,-55],[93,21],[62,-143],[51,-48],[118,15],[34,-44],[79,-18],[-12,-53],[112,22],[36,80],[-3,63],[59,36]],[[6092,4515],[31,15]],[[3101,3691],[185,-65],[12,-37],[75,70],[162,78],[148,19],[178,-51],[78,-7],[35,-54],[164,-87],[147,-95]],[[4285,3462],[65,118],[-24,55],[31,157],[-26,9],[-3,159],[84,52],[118,-27],[45,-47],[15,-150],[74,-12],[121,35],[-23,84],[117,68],[150,29],[104,-47],[153,-11],[61,-34],[112,11],[-27,19],[-12,179],[63,136],[142,70],[14,-35],[-37,-127],[116,-18],[203,-91],[17,82],[92,78],[-14,144],[45,49],[-3,79],[34,39]],[[6719,6848],[-104,15],[-61,-30],[-7,54],[-76,26],[-111,5]],[[7688,5587],[-29,42],[6,75],[67,65],[20,61],[106,70]],[[7858,5900],[-81,44],[22,69],[-26,89],[-37,20]],[[7736,6122],[-115,-13],[-140,-67],[-78,-2],[-191,-101],[-157,170],[-56,12],[-31,85],[117,76],[-51,65],[-156,11],[-119,123],[64,70],[-97,81],[11,155],[-18,61]],[[7736,6122],[25,64],[73,70],[52,10],[48,82],[37,11],[-89,107]],[[7140,7322],[-9,-12]],[[7131,7310],[-93,-34],[-74,14],[65,-71],[-26,-52],[-86,-36],[-18,-44],[10,-120],[31,-22],[-65,-44],[-73,72],[-16,60],[-81,-71],[14,-114]],[[7131,7310],[-204,58],[-228,45],[44,99],[109,55],[7,65],[-254,85],[-8,81],[-71,-16],[-214,68],[-17,41],[-187,-13],[68,107],[-75,-9],[-28,59],[-151,-15],[-81,36],[-47,-23],[-57,109]],[[9220,8915],[-67,-33],[-38,-59],[-138,-13],[-25,30],[-60,-46],[-134,-6],[-67,27],[-255,40]],[[8448,7113],[164,-55],[-46,-21],[179,-61],[54,71],[82,169],[-77,87],[8,52],[125,47],[83,154],[38,-10]],[[9058,7546],[-38,110],[31,98],[189,27],[71,-58],[180,73],[-3,180],[-50,83],[22,48],[104,44],[-5,102],[-59,127],[21,70],[-47,7],[-95,106],[-97,29],[3,91],[-48,120],[39,49],[-56,63]],[[8556,6770],[143,-63],[-39,-47],[-29,-106],[-114,-57],[-15,-53],[72,-41],[-82,-105],[81,-38],[77,-1],[65,-83],[1,-142]],[[8716,6034],[151,-15],[-3,28],[126,126],[107,18],[34,-112],[73,-87],[38,-6],[104,88],[55,-32]],[[9401,6042],[134,172],[173,288],[105,219],[171,303],[-112,-81],[-130,-29],[-58,34],[-45,-51],[-31,29],[-122,27],[-37,74],[-94,20],[-75,138],[26,88],[-71,18],[-51,82],[20,24],[-146,149]],[[7858,5900],[100,1],[22,34],[143,11],[72,-68],[105,52],[78,4],[5,148],[99,-107],[93,-11],[13,-29]],[[8588,5935],[89,92],[39,7]],[[4285,3462],[198,-88],[-7,-36],[116,-18],[76,-47],[99,40],[96,-103],[98,28],[45,-17],[87,61],[76,16],[483,-408],[27,-248],[126,8],[78,-36],[69,53],[79,6],[47,67],[65,-44],[93,45],[53,-68],[73,48]],[[6941,3931],[-282,97],[-86,47],[123,55],[-199,106],[-318,151],[-66,50],[-21,78]],[[8472,5472],[47,67],[25,221],[-36,44],[33,91],[47,40]],[[398,4964],[-41,-57],[2,-57],[89,-26],[-101,-83],[36,-82],[-59,-26],[49,-59],[-35,-101],[48,-29],[-1,-134],[37,-47],[241,-134],[62,-72],[-27,-55],[-78,-17],[-16,-47],[47,-67],[-24,-66],[-5,-196],[-38,-81],[77,-92],[-9,-73],[-75,-83],[-4,-47],[-75,-41],[43,-62],[126,124],[96,-16],[65,47],[66,-10],[84,46],[115,135],[84,-16],[86,39],[222,182],[118,-9],[70,79],[176,84],[39,95],[83,21],[206,140],[84,13],[83,48]],[[9220,8915],[68,90],[-87,60],[-83,-3],[-94,123],[-83,186],[-9,61],[40,33],[-37,59],[-86,-48],[-108,56],[-9,58],[45,60],[-109,36],[-70,-159],[-42,15],[-35,112],[-109,76],[-157,-17],[-88,69],[-211,27],[-15,75],[-48,74],[-76,17]],[[8422,5298],[167,125],[189,0],[125,59],[119,107],[212,220],[167,233]],[[7213,2382],[-23,-25],[85,-91],[-28,-83],[-57,-50],[19,-41],[-115,-74],[-60,-110],[-25,28],[-73,-90],[13,-55],[-127,6],[-34,-126]],[[8076,1472],[-27,25],[3,117],[39,56],[45,267],[57,62],[-14,92],[80,132],[5,84],[98,228],[-44,85]]]}
diff --git a/src/lib/geometries/bahia-municipality-zones.topo.json b/src/lib/geometries/bahia-municipality-zones.topo.json
index de33847a..039460af 100644
--- a/src/lib/geometries/bahia-municipality-zones.topo.json
+++ b/src/lib/geometries/bahia-municipality-zones.topo.json
@@ -1 +1 @@
-{"type":"Topology","bbox":[-38.65748489999993,-13.017326199999957,-38.304332699999975,-12.742395399999964],"transform":{"scale":[0.000035318751875182926,0.000027495829582957576],"translate":[-38.65748489999993,-13.017326199999957]},"objects":{"municipalityZones":{"type":"GeometryCollection","geometries":[{"type":"MultiPolygon","arcs":[[[0,1,2,3]]],"properties":{"municipalitySlug":"salvador-ze-1","name":"Salvador — ZE 1","zoneNumber":1,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[4,5,6,-3]]],"properties":{"municipalitySlug":"salvador-ze-2","name":"Salvador — ZE 2","zoneNumber":2,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[7,8,9,10]]],"properties":{"municipalitySlug":"salvador-ze-3","name":"Salvador — ZE 3","zoneNumber":3,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[11,12,13]],[[14]],[[15]],[[16]],[[17]],[[18]],[[19]]],"properties":{"municipalitySlug":"salvador-ze-4","name":"Salvador — ZE 4","zoneNumber":4,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[20,21,22,23,24,25,26,-10]]],"properties":{"municipalitySlug":"salvador-ze-5","name":"Salvador — ZE 5","zoneNumber":5,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-2,27,28,29,-5]]],"properties":{"municipalitySlug":"salvador-ze-6","name":"Salvador — ZE 6","zoneNumber":6,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-27,-28,-1,30,31,-11]]],"properties":{"municipalitySlug":"salvador-ze-7","name":"Salvador — ZE 7","zoneNumber":7,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[32,33,34,35,-13,36]],[[37,38]]],"properties":{"municipalitySlug":"salvador-ze-8","name":"Salvador — ZE 8","zoneNumber":8,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[39,40,41]]],"properties":{"municipalitySlug":"salvador-ze-9","name":"Salvador — ZE 9","zoneNumber":9,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[42,43,-25,44,45,46,47]]],"properties":{"municipalitySlug":"salvador-ze-10","name":"Salvador — ZE 10","zoneNumber":10,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[48,-38,49,50,51,-22,52,-34]]],"properties":{"municipalitySlug":"salvador-ze-11","name":"Salvador — ZE 11","zoneNumber":11,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-47,53,54]]],"properties":{"municipalitySlug":"salvador-ze-12","name":"Salvador — ZE 12","zoneNumber":12,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[55,-6,-30,56,-43]]],"properties":{"municipalitySlug":"salvador-ze-13","name":"Salvador — ZE 13","zoneNumber":13,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-23,-52,57]]],"properties":{"municipalitySlug":"salvador-ze-14","name":"Salvador — ZE 14","zoneNumber":14,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[58,-40,59,60,-35,-53,-21,-9]]],"properties":{"municipalitySlug":"salvador-ze-15","name":"Salvador — ZE 15","zoneNumber":15,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-44,-57,-29,-26]],[[-58,-51,61,-45,-24]]],"properties":{"municipalitySlug":"salvador-ze-16","name":"Salvador — ZE 16","zoneNumber":16,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-14,-36,-61,62]]],"properties":{"municipalitySlug":"salvador-ze-17","name":"Salvador — ZE 17","zoneNumber":17,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-59,-8,-32,63,-41]]],"properties":{"municipalitySlug":"salvador-ze-18","name":"Salvador — ZE 18","zoneNumber":18,"ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-46,-62,-50,-39,-49,-33,64,-54]]],"properties":{"municipalitySlug":"salvador-ze-19","name":"Salvador — ZE 19","zoneNumber":19,"ibgeCode":"2927408"}}]}},"arcs":[[[3883,1288],[4,-5],[6,-9],[4,-3],[3,19],[35,57],[30,40],[10,16],[16,44],[5,16],[4,8],[8,-4],[0,-4],[3,1],[7,-11],[3,1],[5,-3],[4,2],[3,7],[4,3],[-4,11],[1,3],[17,21],[10,14],[9,24],[12,21],[13,20],[16,29],[4,5],[8,8],[3,-1],[9,13],[7,11],[5,6],[10,9],[9,7],[6,7],[3,0],[9,14],[8,5],[2,12],[5,11],[3,13],[2,1],[11,10],[-1,2],[6,8],[2,-1],[3,-5],[5,-5],[4,4],[6,10],[2,6],[4,-3],[-1,-9],[2,-4],[3,-2],[-1,-3],[6,-3],[3,4],[8,-1],[0,-3],[-7,-8],[-6,-9],[0,-8],[-6,-36],[-4,-38],[8,-51],[2,-15],[-2,-18],[-2,-7],[-4,-6],[-9,-9],[-47,-20],[-37,-15],[-9,-7],[-39,-44],[2,-17],[4,2],[1,-8],[4,0],[2,-30],[-22,-4],[3,-19],[-28,0],[0,-45],[1,-9],[8,-20],[-11,-11],[-11,-9],[-1,-11],[-3,-14],[-14,-17],[13,-20],[-11,-15],[-20,-27],[-5,-8],[-18,31],[0,-1],[-12,-27],[7,-7],[6,-9],[3,-9],[3,-15],[3,-17],[1,-22],[3,-10],[7,-10],[-13,-18],[-3,-6],[0,-9],[1,-4],[5,-6],[7,-2],[6,-6],[3,-9],[-2,-9],[-20,-24],[-8,-7],[-11,-3],[4,-17],[4,-9],[8,2],[5,3],[5,1],[3,4],[4,10],[12,16],[13,18],[4,14],[4,12],[3,5],[5,4],[8,8],[3,8],[0,10],[17,0],[16,0],[2,10],[3,6],[4,3],[6,2],[7,-1],[5,-2],[5,-4],[5,-6],[11,-25],[1,-8],[1,-13],[5,3],[7,4],[12,1],[17,-1],[14,1],[24,11],[7,5],[2,4],[3,10],[-1,21]],[[4242,1070],[6,-25],[4,-9],[9,-12],[6,-10],[6,-8],[7,-7],[4,-1]],[[4284,998],[-9,-18],[-11,-35],[-5,-19],[-2,-11],[0,-11],[2,-29],[-5,5],[-9,3],[-6,-1],[-6,-3],[-4,-4],[-6,-9],[-2,-9],[-10,-1],[-9,-2],[-10,-4],[-8,-5],[-8,-8],[-3,-5],[-12,-22],[-7,-10],[-5,-5],[-6,-4],[-10,-1],[-7,1],[-18,8],[-6,1],[-14,-1],[-22,-7],[-11,-1],[-9,1],[-6,1],[-9,3],[-7,2],[-12,5],[-10,9],[-11,9],[-3,-3],[14,-14],[4,-9],[1,-9],[-1,-9],[-5,-18],[-2,-3],[-5,-8],[-2,-6],[-20,-64],[-2,-11],[-1,-9],[3,-22],[-1,-4],[17,-4],[-2,-8],[-4,-17],[2,-6],[6,-5],[7,-1],[7,7],[3,9],[4,4],[-5,8],[8,8],[3,4],[3,14],[0,8],[3,10],[10,-3],[4,-6],[2,-6],[-1,-13],[1,0],[3,7],[3,4],[5,14],[6,3],[10,1],[5,4],[0,5],[4,23],[0,8],[9,3],[4,0],[-2,-16],[11,-2],[-3,-7],[1,-9],[5,-13],[7,-22],[0,-10],[1,-29],[1,-6],[3,-13],[4,-12],[-3,-12],[-21,-62],[1,-4],[5,-7],[-6,-7],[-13,-13],[-9,-3],[-7,0],[-7,-4],[-24,-23],[-8,-2],[-4,-6],[-2,1],[-1,-6],[0,-13],[-3,-25],[0,-3],[-7,4],[-1,2],[2,5],[-12,9],[2,9],[0,9],[-3,7],[2,5],[1,4],[-4,6],[7,1],[3,8],[4,7],[6,11],[1,6],[0,4],[-5,16],[-3,15],[-1,16],[-2,5],[-9,23],[-14,25],[-11,13],[-2,2],[1,9],[-5,6],[-5,-2],[-24,3],[-8,1],[-11,-2],[-12,-5],[-9,-4],[-8,-7],[-6,-6],[-9,-13],[-14,-17],[-29,-47],[-20,-29],[-7,-16],[-1,-4],[-1,-5],[0,-26],[5,-32],[2,0],[24,18],[10,0],[8,-1],[9,-5],[5,-5],[6,-9],[7,-15],[12,-18],[14,-24],[9,6],[6,2],[7,0],[0,-5],[2,-2],[0,-5],[-5,-8],[-3,-13],[0,-6],[3,-4],[15,-11],[3,-7],[3,-8],[0,-6],[4,-23]],[[3946,246],[-4,-1],[-3,2],[-7,-1],[-2,5],[-2,0],[-9,6],[-4,10],[-14,-2],[-6,-1],[-10,-6],[-8,-5],[-5,-1],[-6,-2],[-7,-5],[-12,-11],[-21,-8],[-14,-3],[-6,-2],[0,-3],[-5,-1],[-3,-5],[-3,0],[-8,-9],[-5,0],[1,10],[-6,-3],[-6,5],[0,3],[-5,-1],[0,9],[1,3],[-2,2],[2,12],[-1,10],[-15,8],[-20,4],[-6,3],[-12,-1],[-11,-1],[-12,2],[-19,0],[-16,-4],[-13,0],[-16,-3],[-18,-4],[-12,-1],[-9,-3],[-22,-1],[-10,-5],[-7,-9],[7,-4],[1,-4],[-5,-7],[-3,-2],[-3,-9],[-3,-4],[-5,-2],[-11,3],[-4,10],[3,4],[-3,0],[-3,-6],[-5,1],[-7,4],[6,6],[6,1],[4,3],[-1,3],[-11,-2],[-1,2],[-3,-1],[-6,3],[-4,-1],[-1,7],[7,1],[-2,5],[1,10],[8,11],[12,8],[-2,4],[4,1],[9,-1],[4,3],[0,3],[3,8],[1,6],[-1,4],[3,2],[0,6],[-2,8],[-10,1],[-5,5],[-2,5],[0,7],[-4,9],[-11,14],[-4,-1],[-3,1],[-1,2],[5,7],[2,4],[-2,11],[-4,1],[3,6],[2,1],[5,7],[7,4],[1,3],[-1,9],[-2,4],[-3,0],[-5,2],[3,13],[-3,3],[-1,-1],[-12,0],[0,4],[3,5],[5,2],[-1,6],[-8,-3],[-1,3],[-3,-1],[0,4],[-5,-1],[5,7],[0,7],[-4,2],[-3,0],[0,-6],[-3,-1],[-1,4],[3,8],[6,-1],[2,4],[-1,3],[5,1],[3,-4],[4,4],[-1,-8],[6,0],[5,5],[4,5],[4,10],[2,19],[1,14],[0,15],[-2,7],[-3,2],[0,6],[3,5],[0,4],[3,3],[-3,2],[0,3],[4,6],[-2,10],[4,8],[-3,2],[6,4],[0,6],[9,8],[5,-4],[0,-3],[4,-2],[7,1],[4,4],[8,3],[3,11],[3,3],[7,6],[6,1],[6,3],[15,15],[2,3],[7,16],[1,24],[0,11],[-3,8],[-2,4],[0,12],[0,7],[5,9],[-1,6],[-3,-1],[-1,5],[3,8],[2,12],[5,10],[9,12],[8,7],[4,7],[0,16],[1,4],[7,12],[-1,10],[1,4],[5,5],[12,12],[7,10],[5,10],[3,8],[-1,8],[1,3],[7,1],[4,3],[-3,3],[-5,1],[0,8],[5,8],[11,20],[7,10],[5,9],[8,9],[2,4],[0,13],[8,18],[4,7],[7,0],[2,6],[3,3],[2,5],[0,6],[3,9],[8,10],[2,2],[2,-4],[3,1],[0,3],[-3,5],[0,4],[3,5],[7,7],[2,11],[3,3],[5,5],[4,8],[10,10],[4,7],[4,17],[3,10],[5,11],[5,7],[5,9],[16,15],[4,3],[9,1],[4,3],[1,6],[-7,0],[0,4],[3,4],[2,7],[3,16],[6,13],[11,13],[6,7]],[[4284,998],[10,-4],[14,-4],[59,-16],[7,-2],[6,-4],[11,-9],[10,-13],[5,-11],[6,-19],[4,-11],[7,-7],[8,-5],[7,-1],[27,-1],[10,-2],[13,-9],[13,-12],[28,-30],[6,-9],[22,-26],[6,-9],[11,-11],[29,-18],[11,-5],[32,-20],[10,-7],[9,-8],[3,-4],[3,-6],[13,11],[25,11],[19,25],[22,-16],[10,-1],[1,28],[2,6],[4,2],[6,-1],[17,-7],[3,1],[4,7],[16,38],[7,-13],[1,-5],[-1,-4],[-5,-25],[-2,-3],[18,-1],[1,2],[4,2],[21,8],[8,-4],[3,-19],[21,-30],[5,-10],[1,11],[9,-7],[7,-2],[16,-11],[11,-12],[6,1],[5,-2],[4,-4],[3,2],[9,-19],[5,-14],[6,-32]],[[4976,628],[-11,-5],[-9,-6],[-6,-6],[-4,-6],[-5,-14],[-1,-9],[0,-9],[3,-37],[1,-24],[-1,-8],[-3,-7],[19,3],[2,3],[4,20],[2,7],[3,4],[10,7],[3,9],[6,3],[11,7],[19,6],[4,3],[29,28],[11,11],[11,8],[9,11],[7,4],[5,4],[0,-28],[-21,-38],[-1,-2],[-2,-56],[1,-3],[3,3],[-6,-9],[6,-16],[-1,-37],[13,-12],[5,-4],[3,-13],[3,-10],[5,-18],[1,-11],[6,-35],[6,-14],[5,-7],[9,-6],[2,-14],[-22,-2],[-7,-2],[-8,-4],[-34,-18],[-2,10],[-12,-1],[-8,3],[-9,7],[-7,9],[-13,11],[-4,5],[-9,15],[-10,10],[-8,4],[-14,0],[-6,2],[-9,5],[-3,3],[-6,7],[-4,3],[-12,45],[-9,-2],[2,-5],[-7,-4],[-5,3],[-4,0],[-27,-18],[-5,-4],[-28,3],[-4,-7],[1,-4],[15,-6],[8,-6],[3,8],[3,2],[7,-3],[13,-12],[13,-5],[8,-4],[2,-14],[-2,-13],[2,1],[2,-8],[2,-11],[4,-3],[10,-7],[6,1],[9,-9],[-2,10],[9,2],[7,7],[6,-3],[-1,-11],[4,-2],[4,-4],[3,4],[7,6],[3,-1],[0,-4],[4,-5],[3,-5],[4,-2],[4,-9],[6,-19],[0,-6],[-1,-12],[2,-3],[4,5],[7,-2],[1,-7],[-1,-5],[-19,-30],[-12,-9],[8,-3],[5,-4],[3,3],[13,4],[3,-6],[3,-1],[7,-13],[2,-8],[-2,-8],[11,-6],[6,-2],[6,0],[27,3],[24,4],[-5,40],[12,-1],[10,-7],[22,2],[8,-2],[5,7],[41,4],[5,16],[5,7],[7,3],[-1,10],[0,9],[3,3],[7,-22],[8,-10],[2,-13],[41,5],[0,16],[9,3],[26,23],[30,-35],[17,4],[-11,15],[-9,4],[-7,7],[3,4],[18,14],[6,5],[6,-10],[33,-54],[5,-2]],[[5398,193],[-10,-9],[-7,-10],[-5,-12],[-8,-12],[-5,-15],[-6,-22],[-7,-19],[-6,-5],[-24,10],[-17,3],[-8,-2],[-17,-11],[-6,4],[-10,8],[-33,12],[-14,3],[-13,-4],[-13,-3],[-12,-1],[-13,-2],[-12,0],[-9,-3],[-40,-14],[-18,-7],[-18,-8],[-12,-9],[0,-6],[-7,-7],[-18,-8],[-5,1],[-1,4],[-3,5],[-5,4],[1,4],[-3,4],[-5,4],[-10,2],[-3,-3],[-6,3],[-2,5],[-3,13],[-8,1],[-6,2],[-11,-2],[-6,-7],[-8,0],[-5,-4],[-14,-9],[-8,-7],[-5,3],[-7,-1],[-4,-3],[-3,-11],[-5,0],[-2,-2],[-1,-7],[-4,-3],[-9,4],[-2,4],[-8,2],[-4,-9],[-2,2],[-3,-11],[-2,-3],[-2,2],[-2,-1],[-2,-11],[-4,-4],[-4,1],[-4,-4],[-12,-11],[-4,-1],[-4,2],[-2,5],[-17,2],[-5,-1],[-3,-6],[-6,0],[-5,15],[-1,7],[3,5],[-3,5],[-4,1],[-1,5],[-2,19],[-1,18],[-3,4],[-4,-1],[-3,-4],[-6,1],[-2,4],[-5,5],[0,11],[0,19],[-5,3],[-10,10],[-9,8],[-6,4],[-5,-3],[-6,0],[-5,-3],[-6,-3],[-7,0],[-5,2],[-2,4],[3,8],[-7,3],[-4,-1],[-4,2],[1,11],[0,8],[6,10],[4,4],[-4,8],[-4,8],[-11,7],[-7,-1],[0,-3],[-9,0],[-4,-3],[-12,-1],[-3,-4],[-1,4],[-3,0],[-6,6],[-6,2],[-5,-4],[-4,0],[0,6],[-6,-5],[-4,0],[-6,-5],[-5,1],[-2,4],[-17,0],[-3,4],[-3,20],[-3,4],[-5,1],[-17,-8],[-1,-4],[0,-6],[2,-5],[-1,-5],[-12,-3],[-5,-1],[-13,-4],[-4,-2],[-5,0],[-11,-8],[-9,2],[-4,-2],[-1,-5],[-2,-2],[-7,-2],[-6,3],[-3,-5],[-7,-3],[-3,3],[-4,-1],[-9,8],[-1,5],[2,5],[-3,3],[-1,7],[-9,4],[-7,3],[-5,6],[-2,11],[-9,4],[-9,-1],[-11,-2],[-10,-4],[-14,-6],[-8,-5],[-14,-12],[-6,-3],[-3,2],[-5,-6],[0,-8],[-4,-6],[-6,-2],[-5,1],[-5,3],[0,7],[4,10],[-5,5],[-8,3],[-7,0],[-4,-2],[-2,-3],[-6,-7],[-11,-4],[-6,1],[-10,-7],[-8,6],[-6,8],[-9,5],[-3,6],[-7,4],[-3,6],[1,4],[-4,5],[-6,2],[-18,-1],[-14,-12],[0,-5],[-4,-8],[-4,-3],[0,-15],[1,-13],[-7,-1],[-2,-4],[-3,-1],[-1,6],[-2,4],[2,3],[-7,4],[0,4],[5,3],[1,9],[1,1],[-2,6],[-10,9],[-5,2],[-4,-2],[-4,-11],[-5,0],[-3,3],[-4,6],[0,3],[-9,-1],[-7,-4],[-3,2],[-2,8],[-4,0],[-1,-5],[-7,-5],[-3,-3],[-6,-2],[-16,10],[-3,13],[2,5],[-1,3],[-5,-3],[-5,1],[0,5],[3,6],[3,2],[-5,1],[-4,5],[-9,6],[-6,2],[-6,-1],[-4,-5],[0,-5],[-5,-3],[-4,0],[-4,4],[-1,-4],[-12,-3],[-4,3],[-9,-1],[-4,4],[-1,-1],[-2,-5],[-4,-3],[-4,0],[-6,3]],[[4583,1987],[1,4],[4,-1],[8,0],[9,5],[9,11],[2,5],[5,15],[3,2],[1,6],[5,-2],[0,-9],[-1,-14],[1,-7],[4,-10],[3,-3],[7,-4],[2,0],[17,7],[2,13],[15,-3],[5,31],[10,2],[7,19],[15,-3],[4,18],[9,-3],[15,-5],[-1,-4],[-5,-12],[-2,-3],[4,1],[1,-6],[11,12],[2,6],[7,25],[5,-3],[0,-11],[-2,-13],[-5,-7],[-16,-18],[2,-7],[19,26],[5,9],[1,7],[4,29],[1,8],[2,21],[-16,4],[5,4],[7,3],[3,-1],[1,8],[5,14],[10,20],[2,5],[-16,22],[2,2],[-16,19],[-10,7],[-4,2],[8,21],[5,-3],[14,-1],[3,-1],[7,-8],[0,-1],[14,18],[-15,10],[-9,8],[-3,4],[-2,7],[-2,3],[-1,6],[-7,1],[-9,3],[-12,-3],[-16,-3],[-13,-2],[-9,-1],[-16,1],[-24,2],[1,3],[-5,9],[-4,8],[0,13],[2,6],[1,8],[-1,15],[3,13],[19,32],[8,16],[1,4],[1,19],[-4,21],[-2,6],[23,8],[-7,28],[-5,25],[2,0],[12,7],[2,-6],[2,-22],[3,-19],[6,3],[15,-8],[11,-5],[14,-1],[22,3],[16,-3],[5,-3],[5,-1],[13,-8],[2,-1],[31,-4],[3,9],[-6,4],[-7,15],[8,7],[3,6],[2,7],[8,1],[0,8],[1,5],[0,6],[3,11],[2,-1],[4,12],[16,28],[8,10],[7,3],[4,0],[5,5],[7,4],[7,2],[-2,5],[9,4],[-7,23],[-12,44],[-11,24],[-13,28],[-4,5],[-6,5],[-11,8],[-16,6],[-7,4],[-4,5],[-5,8],[-5,8],[-4,11],[-5,19],[-5,10],[-5,3],[-7,2],[-11,-1],[-28,-5],[-13,-1],[-8,0]],[[4751,2814],[1,13],[3,11],[6,0],[10,5],[10,8],[8,7],[9,10],[4,2],[36,18],[5,3],[6,1],[24,9],[14,9],[4,5],[10,13],[18,15],[16,10],[13,14],[8,-14],[4,-10],[8,-14],[3,-4],[7,8],[2,4],[9,11],[4,-5],[10,-6],[10,-14],[11,-1],[9,3],[1,-9],[8,-19],[5,-5],[7,-2],[10,2],[7,-5],[7,-8],[3,-1],[7,1],[10,2],[22,-11],[-2,-8],[-7,-11],[0,-3],[4,-2],[8,-9],[9,-14],[3,-5],[-3,-3],[2,-5],[3,1],[5,-10],[8,3],[4,0],[12,-6],[5,2],[19,-15],[12,-6],[9,-1],[9,1],[1,-18],[5,1],[6,0],[8,-4],[8,-4],[7,-5],[-1,-1],[-11,-44],[10,-3],[-11,-9],[-7,-6],[-5,-10],[8,-5],[-2,-6],[2,-6],[-10,-3],[-5,13],[-9,-7],[-4,5],[-6,-2],[-5,3],[-14,-9],[-4,-6],[-1,-5],[3,-14],[-2,-13],[1,-1],[-2,-9],[-2,2],[-3,-5],[-8,-6],[-6,-6],[2,-10],[7,-3],[7,-11],[9,6],[0,-21],[4,-24],[0,-5],[-2,-8],[-3,1],[-2,-3],[-9,0],[-16,2],[-2,-14],[8,-6],[5,-3],[-3,-10],[5,-6],[11,-18],[-10,-9],[-16,-10],[-4,-2],[-8,-1],[-3,-2],[-6,-16],[3,-8],[-1,-8],[1,-6]],[[5138,2401],[-8,-2],[0,-3],[-1,-8],[11,-5],[11,-7],[11,-9],[0,-16],[1,-32],[0,-14],[-1,-13],[-1,-11],[-2,-8],[-15,-46],[-11,-33],[-30,-92],[-31,-96],[-3,-10],[-10,-18],[-9,-26],[-3,-14],[-5,-22],[-3,-15],[-13,-94],[-2,-19],[4,-29]],[[5028,1759],[-21,-1],[-10,1],[-33,7],[-16,3],[-45,10],[-87,19],[-16,4],[-13,6],[-54,31],[-29,17],[-8,2],[-10,2],[-18,0],[-2,14],[-4,12],[-6,-3],[-14,0],[-11,28],[-4,15],[7,5],[-3,9],[-4,0],[-4,19],[0,11],[7,-2],[4,-2],[6,-6],[-1,17],[-9,3],[-19,1],[-15,2],[-13,4]],[[5120,5863],[5,20],[5,10],[3,11],[3,4],[2,10],[4,8],[1,12],[5,19],[1,18],[0,8],[-3,9],[-2,7],[-2,21],[-2,8],[-4,6],[1,5],[-3,4],[0,16],[2,7],[2,6],[2,16],[3,12],[4,20],[4,25],[1,2],[18,-3],[15,-3],[11,-2],[2,2],[2,10],[1,6],[8,14],[5,13],[6,12],[1,6],[9,21],[2,2],[3,8],[8,14],[11,16],[-1,13],[0,10],[-1,2],[0,7],[-3,-5],[0,9],[3,7],[-3,2],[-6,-6],[-1,8],[2,2],[8,5],[-2,3],[-31,4],[-3,3],[12,-1],[3,6],[3,-2],[2,-5],[5,-1],[6,9],[2,10],[1,12],[-1,13],[-1,11],[-4,18],[-2,13],[-5,14],[-9,14],[-22,30],[-11,12],[-2,0],[-15,20],[-11,17],[-10,15],[-7,9],[-2,6],[0,3],[-6,2],[-4,3],[-10,14],[-3,7],[-8,16],[-7,10],[-6,7],[-9,12],[-7,7],[-8,12],[-13,13],[-6,7],[-16,15],[-12,10],[-9,9],[-11,9],[-26,18],[-18,12],[-9,5],[-8,4],[-11,8],[-4,1],[-6,-2],[-3,-2],[-2,-11],[-5,-6],[-6,-6],[-7,-8],[-5,-8],[-1,-3],[-3,-2],[-13,-1],[-1,-6],[-3,0],[-4,4],[-10,6],[-4,0],[-7,-7],[-8,-1],[-4,-4],[-4,0],[-6,6],[-12,1],[-6,6],[-2,6],[-5,2],[-3,5],[-1,14],[-3,5],[-3,-1],[-9,-5],[-1,4],[1,4],[-1,6],[-7,11],[-4,6],[-9,10],[-6,9],[-6,7],[-6,11],[1,7],[5,8],[-3,9],[1,3],[4,5],[7,3],[6,12],[1,4],[1,16],[-1,6],[1,9],[-1,11],[-4,13],[-1,11],[-1,2],[-7,26],[-2,16],[0,11],[1,33],[3,7],[5,-1],[6,1],[4,4],[2,7],[1,9],[4,25],[2,10],[1,10],[2,7],[5,0],[3,-2],[6,-1],[2,5],[0,5],[-2,5],[-6,4],[-7,10],[0,7],[1,7],[7,21],[6,11],[3,9],[3,12],[2,12],[3,25],[-1,15],[4,5],[-1,5],[-2,5],[1,7],[-1,3],[-5,7],[-1,9],[-5,12],[1,8],[1,7],[-1,12],[-3,10],[-6,15],[-1,5],[-6,14],[-3,12],[-10,21],[-9,15],[-9,15],[-10,14],[-5,6],[-13,13],[-8,6],[-12,6],[-11,5],[-6,6],[-6,7],[-8,7],[-16,12],[-8,5],[-20,6],[-9,2],[-11,0],[-9,-1],[-4,-2],[-6,-4],[-7,-7],[-8,-4],[-9,-6],[-8,-4],[-5,-4],[-2,5],[-7,2],[-12,0],[-4,-1],[-3,-3],[-1,1],[0,7],[-3,3],[-4,2],[-9,2],[-6,4],[-10,10],[-10,7],[-5,0],[-8,4],[-3,-2],[1,13],[-3,1],[0,-10],[-2,-1],[-4,4],[-3,13],[-3,5],[1,4],[4,0],[1,3],[-1,8],[-2,13],[0,6],[5,9],[-1,6],[-1,7],[2,9],[0,8],[-4,4],[-1,14],[-3,4],[0,7],[4,14],[-1,37],[1,21],[3,10],[2,11],[2,6],[6,27],[4,10],[5,20],[0,6],[-9,5],[-7,7],[-3,5],[-4,13],[0,8],[7,2],[5,3],[1,3],[-1,11],[0,11],[2,10],[-1,16],[0,12],[-2,9],[-4,21],[-1,13],[4,25],[-1,14],[2,9],[4,8],[2,6],[0,20],[0,17],[1,11],[0,10],[-3,13],[-4,10],[-12,25],[-2,6],[-1,18],[1,4],[7,11],[3,5],[2,9],[4,14],[-1,6],[-12,28],[-4,4],[-2,5],[-1,12],[4,16],[3,10],[10,24],[10,6],[8,1],[6,-1],[16,-7],[6,-4],[8,-7],[16,-20],[10,-6],[11,-9],[18,-8],[2,1],[11,-3],[6,-4],[2,-2],[1,-8],[1,-6],[0,-9],[7,-1],[-2,-20],[1,-2],[-7,-54],[-6,1],[1,-17],[-1,-20],[2,-3],[5,0],[7,13],[3,0],[1,-7],[2,0],[14,108],[4,0],[-14,-114],[1,-7],[39,-66],[1,-14],[-7,-5],[-27,-25],[-10,-10],[-4,-6],[3,-5],[6,3],[37,34],[6,6],[15,-8],[47,44],[46,43],[3,1],[0,2],[3,3],[-2,4],[-6,0],[-2,3],[-5,11],[1,9],[4,7],[3,2],[12,5],[9,6],[11,4],[15,1],[15,1],[5,2],[3,3],[5,9],[4,10],[3,11],[0,12],[4,10],[1,6],[-2,11],[-8,5],[4,5],[1,7],[2,2],[-1,3],[4,2],[2,5],[7,9],[8,7],[9,2],[3,2],[11,-2],[10,-3],[8,-1],[5,0],[15,6],[4,4],[9,5],[0,1],[6,4],[11,4],[12,2],[15,4],[4,5],[8,1],[13,8],[7,5],[3,0],[5,-3],[5,-1],[2,-3],[9,-5],[7,-1],[8,1],[14,6],[1,-3],[-7,-7],[-6,-4],[-4,-1],[0,-5],[-6,-8],[11,-4],[4,-1],[15,2],[6,3],[6,8],[8,29],[2,7],[1,10],[-5,15],[-3,4],[-6,3],[-5,10],[3,9],[1,6],[6,4],[10,1],[6,-2],[4,-5],[13,-32],[10,-2],[13,7],[1,2],[0,7],[1,4],[6,3],[9,-6],[3,-1],[3,-7],[4,-15],[2,-5],[4,-5],[3,-5],[5,-2],[9,5],[5,7],[7,3],[7,-2],[6,-3],[5,-10],[6,-7],[5,-18],[1,-5],[4,-7],[6,-6],[3,-7],[3,-5],[1,-11],[9,-21],[4,-5],[8,-8],[5,-2],[7,4],[9,9],[6,3],[4,0],[16,-9],[2,-9],[-3,-4],[-10,-7],[-6,-7],[-9,-11],[-6,-12],[-3,-9],[0,-11],[0,-13],[3,-8],[1,-4],[0,-5],[-1,-2],[-15,7],[-9,2],[-18,-1],[-4,1],[-6,7],[-5,4],[-2,3],[-5,12],[-2,7],[1,4],[-2,1],[0,6],[6,1],[7,3],[3,4],[0,10],[-2,3],[-7,7],[-5,4],[-10,0],[-2,1],[-7,0],[-2,-2],[-3,1],[-11,-2],[-9,6],[-3,1],[-10,1],[-2,-3],[-7,-3],[-4,2],[-7,-5],[-5,0],[-8,-4],[-6,-4],[-3,-4],[-12,-21],[-2,-7],[0,-5],[2,-5],[8,-9],[5,-9],[1,-4],[2,-11],[2,-4],[1,-8],[8,-19],[1,-10],[-2,-3],[-10,-5],[-7,-1],[-14,2],[-5,-1],[-12,-6],[-5,0],[1,-8],[2,-6],[5,-8],[11,-9],[17,-18],[9,-7],[13,-3],[14,2],[14,-1],[4,-2],[2,-3],[0,-5],[-3,-7],[1,-9],[-6,-10],[-4,-4],[-9,-5],[-2,-2],[-7,-12],[-6,-5],[-13,-9],[-7,-6],[-3,-4],[-4,-8],[-3,-10],[-6,-29],[-6,-17],[-4,-15],[-2,-18],[0,-22],[-2,-6],[1,-13],[0,-10],[6,-6],[2,-6],[5,-1],[5,-4],[3,3],[8,-1],[3,-6],[-1,-14],[-3,-12],[-1,-10],[0,-21],[-2,-11],[-3,-15],[-10,-25],[-7,-15],[-8,-14],[-3,-10],[-4,-5],[-6,-1],[-4,2],[-4,6],[-5,3],[-15,0],[-3,-2],[-1,-6],[-4,-9],[-4,-6],[-5,-1],[-3,-4],[-3,-6],[-3,-12],[-4,-10],[0,-7],[-2,-7],[-6,-10],[-9,-16],[-3,-10],[-4,-9],[-7,-8],[-8,-17],[-1,-12],[-5,-10],[-6,-4],[-6,-20],[-5,-15],[0,-10],[4,-4],[0,-10],[2,-9],[1,-12],[2,-8],[2,-13],[1,-10],[-1,-7],[-4,-9],[-5,-19],[-6,-4],[-3,-11],[2,-9],[5,-5],[5,-9],[1,-8],[2,-4],[14,-8],[6,-5],[5,4],[9,-2],[6,1],[7,8],[1,11],[3,4],[-2,4],[0,5],[4,6],[5,2],[1,4],[3,2],[7,0],[4,1],[4,5],[0,3],[3,4],[1,4],[3,2],[-1,7],[2,3],[4,15],[3,3],[6,10],[3,10],[0,10],[-2,2],[1,7],[-2,6],[-6,11],[-4,22],[1,14],[2,5],[-1,2],[2,12],[3,5],[3,1],[2,3],[4,3],[-3,8],[0,13],[3,5],[2,-1],[7,5],[8,0],[5,4],[2,5],[1,6],[2,4],[-1,3],[1,6],[4,5],[4,-2],[0,7],[1,4],[5,4],[-2,4],[3,8],[8,7],[1,5],[9,7],[3,4],[6,13],[7,9],[6,13],[8,9],[8,3],[4,-2],[5,-5],[9,-3],[12,-9],[9,-11],[4,-20],[1,-10],[0,-21],[3,-31],[0,-20],[3,-6],[-1,-4],[1,-8],[2,-3],[3,-6],[2,-10],[2,-8],[3,-15],[2,-6],[-1,-3],[6,-7],[6,-2],[5,-3],[5,-6],[6,-3],[4,1],[7,-5],[2,-3],[4,0],[8,-4],[5,1],[6,4],[5,8],[1,5],[5,8],[7,7],[10,1],[4,-2],[2,-6],[6,-9],[5,-12],[0,-9],[-2,-11],[-3,-5],[-4,-2],[-3,-6],[-5,-6],[-5,-2],[-6,0],[-14,0],[-3,-6],[8,-1],[10,-3],[2,-3],[10,-7],[12,-2],[14,0],[6,3],[4,5],[2,5],[6,0],[-1,5],[1,8],[3,7],[0,5],[1,6],[6,9],[2,7],[3,2],[5,8],[1,5],[10,13],[10,17],[2,1],[1,-5],[5,-10],[2,-12],[0,-7],[-3,-5],[-7,-8],[-7,-9],[-3,-8],[-2,-12],[1,-9],[2,-5],[4,-8],[7,-4],[1,-8],[-7,-9],[-3,-7],[2,-5],[9,-2],[8,-5],[0,-4],[-2,-4],[-10,-1],[-2,-1],[0,-8],[4,-3],[4,-5],[3,-9],[2,-5],[4,-5],[2,-4],[1,-12],[8,-14],[2,-14],[3,-6],[-1,-4],[-2,-5],[0,-3],[6,-4],[1,-4],[0,-26],[-3,-11],[0,-4],[4,-12],[-2,-9],[-2,-19],[2,-8],[4,-10],[3,-4],[11,-4],[3,-2],[11,-11],[1,-8],[-5,-21],[-1,-16],[-1,-17],[-3,-15],[-5,-15],[-5,-41],[-5,-19],[-1,-9],[2,-10],[6,-12],[1,-6],[-2,-13],[1,-5],[6,-10],[5,-1],[22,-4],[6,-3],[6,-5],[5,-9],[10,-10],[22,-9],[7,-5],[16,-7],[29,-10],[20,-6],[7,-2],[23,-13],[9,-9],[10,-13],[0,-12],[-2,-8],[-12,-30],[-10,-31],[-7,-48],[-2,-29],[1,-10],[2,-9],[6,-18],[3,-11],[11,-6],[12,-4],[15,2],[13,0],[10,-7],[5,-1],[7,1],[4,-1],[5,-6],[3,-5],[4,-8],[3,-15],[-1,-6],[-8,-11],[-11,-12],[-8,-11],[-1,-6],[0,-6],[3,-14],[5,-13],[3,-13],[5,-11],[3,-7],[6,-9],[9,-9],[7,-4],[10,-4],[3,-5],[15,-37],[4,-8],[14,-13],[12,-5],[16,-5],[9,-7],[5,-5],[5,-7],[14,-9],[7,11]],[[5872,6248],[3,-4],[9,-1],[3,-27],[-12,0],[-16,1],[-16,2],[-11,3],[-18,7],[-17,7],[-23,7],[-17,2],[-17,-1],[-23,-3],[-12,-1],[-7,2],[-5,-4],[3,-17],[2,0],[7,-33],[2,-14],[0,-13],[-1,-17],[-4,-28],[-2,-5],[-5,-33],[-5,-44],[-1,-8],[-2,-10],[-1,-6],[1,-21],[3,-21],[2,-12],[3,-9],[4,-10],[1,-6],[3,-6]],[[5703,5925],[-8,-2],[-8,-6],[-5,-11],[0,-7],[1,-4],[11,-16],[2,-7],[1,-11],[-3,-8],[0,-2],[-4,-9],[-10,-14],[-12,-13],[-5,-8],[2,-9],[2,-6],[2,-11],[-4,-12],[-1,-10],[2,-8],[4,-12],[0,-11],[-8,-27],[-2,-3],[-8,-12],[-14,-27],[-4,-10],[-14,-46],[-1,-17],[-1,-17],[-2,-12],[-7,-2],[-10,0],[-8,-5],[-5,-2],[-4,-3],[-9,0],[-8,-3],[-4,0],[-5,2],[-3,-4],[2,-2],[-1,-4],[-4,-2],[0,-10],[-8,-8],[-1,-2],[-6,-3],[-3,-4],[-10,-4],[-4,-1],[-13,-6],[-16,1],[-1,-1],[3,-6],[2,-7],[-4,-14],[-1,-1],[-3,-15],[-2,-2],[-3,-8],[-15,-14],[-3,-5],[-3,1],[-4,-4],[-6,0],[-5,5],[-3,5],[-1,4],[-10,10],[-5,2],[-6,-1],[-6,2],[-1,4],[-4,1],[-5,5],[0,5],[-4,0],[-2,14],[1,2],[-2,15],[-3,5],[2,9],[-3,8],[0,10],[-6,20],[-5,6],[-9,6],[-2,4],[0,5],[4,9],[0,4],[-2,9],[0,6],[1,4],[-14,3],[-2,10],[-6,3],[-10,1],[-7,16],[-5,5],[-12,8],[1,3],[9,14],[18,19],[6,9],[23,43],[4,6],[9,7],[12,2],[12,4],[10,25],[-34,9],[-44,8],[-19,3],[-32,2],[-27,4],[-1,15],[1,5],[-27,5],[-13,3],[-4,-10],[-3,-14],[-3,-2],[-6,1],[-19,0],[-2,-1],[-9,7],[1,18],[5,24],[2,4],[-16,-4],[-4,0],[-16,5],[-14,-1],[-9,3],[-8,4]],[[3539,8631],[4,11],[0,13],[-2,18],[-3,8],[-6,26],[-2,4],[-5,3],[1,3],[4,3],[-3,6],[0,3],[-4,-1],[-2,-4],[-6,1],[-6,4],[-2,7],[2,6],[5,3],[-2,6],[11,13],[6,12],[7,19],[1,14],[-2,17],[-2,14],[-3,10],[-4,15],[-2,5],[-17,25],[-7,12],[-12,21],[-8,10],[-5,6],[-14,13],[-13,9],[-28,18],[-16,10],[-33,22],[-43,22],[-22,13],[-24,19],[-23,20],[-18,21],[-12,18],[-5,12],[-8,26],[-14,40],[-20,35],[-25,30],[-4,8],[-2,10],[0,7],[3,12],[3,7],[10,14],[18,22],[15,18],[4,6],[4,8],[9,27],[1,8],[2,18],[1,35],[1,25],[1,9],[2,11],[5,19],[7,19],[7,12],[10,24],[6,16],[7,15],[8,15],[13,28],[4,10],[5,12],[11,19],[5,12],[4,16],[2,18],[1,13],[-2,7],[-7,9],[-1,7],[5,8],[11,4],[7,15],[3,3],[4,0],[4,-5],[5,-3],[10,-3],[7,2],[-10,0],[-8,2],[-5,5],[-1,2],[3,5],[11,14],[10,15],[5,10],[3,14],[2,23],[3,20],[5,21],[7,21],[6,10],[3,1],[4,-1],[8,-11],[7,-13],[5,-6],[8,1],[9,2],[20,12],[10,8],[23,15],[10,9],[7,6],[5,3],[9,2],[7,-1],[11,-9],[5,-3],[7,-6],[5,-6],[8,-3],[4,-13],[2,-2],[10,-8],[4,-2],[16,-6],[6,-4],[2,-9],[4,-10],[9,-18],[5,-9],[8,-6],[7,-5],[9,-4],[10,-2],[9,-5],[12,-11],[14,-14],[3,-4],[4,-15],[3,-7],[7,-8],[16,-23],[4,-8],[8,-8],[10,-9],[10,-5],[6,2],[10,-5],[9,-7],[4,-1],[6,-7],[6,-2],[4,0],[3,2],[10,10],[10,8],[1,3],[3,14],[3,-5],[0,-8],[-1,-7],[4,-5],[1,-8],[-1,-5],[7,7],[1,-1],[-1,-7],[1,-3],[8,-2],[21,22],[2,9],[7,4],[0,4],[-5,3],[-7,2],[-4,-2],[-10,-1],[-4,2],[0,4],[6,3],[6,2],[3,4],[3,2],[4,4],[6,1],[10,3],[4,0],[8,-4],[5,-6],[7,-5],[2,-4],[0,-4],[-3,-13],[-2,-10],[4,-13],[3,-1],[8,-12],[9,-15],[18,-15],[18,-19],[3,-6],[3,-11],[7,-9],[4,-9],[1,-5],[-2,-6],[-4,-9],[-1,-4],[0,-18],[0,-23],[1,-11],[0,-11],[-1,-6],[-5,-11],[-4,-2],[0,-7],[-2,-7],[1,-14],[-3,-13],[0,-6],[-2,-4],[-10,8],[-1,-2],[-5,2],[-3,-1],[-3,-4],[-1,-4],[-3,-4],[-16,-30],[-2,-8],[1,-12],[-3,-7],[2,-12],[5,-14],[1,-8],[-2,-4],[8,-13],[3,-10],[3,-9],[7,-44],[3,-10],[1,-8],[4,-9],[-3,-14],[-6,0],[-1,-6],[-4,-6],[7,-19],[0,-5],[-1,-5],[2,-11],[-3,-4],[1,-4],[-7,-10],[-2,-1],[-9,2],[-1,-1],[-2,-11],[0,-14],[1,-4],[6,-6],[4,-8],[1,-6],[1,-18],[-1,-10],[-5,-9],[1,-10],[-2,-9],[-6,-10],[-9,-9],[-3,-5],[-4,-14],[-1,-13],[1,-5],[0,-7],[11,-7],[0,-5],[-3,-2],[-1,-5],[3,-4],[2,-7],[7,-3],[1,-12],[-3,-12],[6,-10],[5,-9],[4,-15],[2,-9],[0,-8],[0,-12],[0,-19],[0,-6],[1,-3],[3,-4],[1,-20],[1,-5],[4,-12],[1,-7],[7,-14],[8,-21],[7,-13],[3,-3],[0,-3],[10,-16],[4,-9],[1,-7],[-1,-4],[3,-11],[2,-5],[-5,-14],[1,-6],[7,-7],[3,-10],[2,-1],[2,-5],[-4,-14],[1,-5],[4,-4],[3,-9],[3,-7],[0,-4],[-3,-9],[2,-5],[3,-4],[0,-2],[3,-4],[1,-10],[4,-1],[0,-6],[2,-5],[4,-15],[1,-5],[4,-3],[4,-19],[2,-5],[5,-8],[1,-14],[3,-1],[1,-6],[4,-24],[0,-5],[-2,-2],[-9,22],[-2,1],[-4,-2],[-11,-10],[-5,-5],[-8,-10],[-4,-3],[-4,-6],[-2,-7],[-6,-5],[0,-10],[4,-4],[4,-13],[3,-8],[-1,-10],[0,-24],[1,-22],[5,-14],[6,-2],[3,-5],[2,0],[2,4],[7,0],[-1,-8],[-5,-1],[-6,1],[0,3],[-3,-1],[0,5],[-4,1],[0,-2],[0,-11],[3,-5],[3,0],[2,-6],[-7,-7],[-5,-12],[0,-5],[2,-7],[0,-4],[3,-4],[1,-7],[3,-3],[1,-2],[-8,-9],[-7,-1],[1,-4],[-1,-6],[7,-6],[1,-3],[-8,-8],[-4,-1],[-3,8],[-5,5],[-1,-5],[1,-3],[-2,-1],[-3,0],[-6,5],[-4,-8],[0,3],[-5,-3],[-3,-9],[2,-3],[11,-11],[0,-3],[-3,-3],[-3,4],[-1,-2],[-3,0],[-3,-6],[-1,-8],[7,1],[4,-2],[2,-7],[-2,-6],[-3,0],[-6,11],[-4,2],[-4,-3],[2,-7],[-3,6],[-3,2],[-6,-2],[0,-6],[5,-6],[-4,-16],[7,-3],[3,-6],[3,0],[6,5],[2,-4],[-1,-7],[-4,-6],[-9,-14],[-10,-9],[-9,-4],[-12,-8],[-7,-11],[-8,-7],[-6,-9],[-13,-7],[-2,-2],[-13,-10],[-9,-13],[-4,-8],[-8,-1],[-3,-1],[-8,-9],[-1,-9],[2,-4],[-3,-8],[-6,-2],[-3,-6],[-3,-3],[-4,-8],[-7,0],[-3,-2],[-2,-8],[-4,-9],[0,-6],[3,-6],[1,-5],[-1,-5],[1,-8],[0,-4],[-5,0],[-5,11],[-2,11],[-8,2],[-1,5],[1,11],[0,3],[-4,1],[-6,-4],[-9,-3],[-5,-7],[-12,2],[-1,-1],[1,-5],[10,-4],[4,-6],[3,1],[3,4],[3,-2],[1,-5],[-3,-6],[-1,-9],[-4,-3],[-5,2],[1,8],[-2,5],[-7,4],[-2,-1],[0,-6],[-2,-6],[-2,-2],[-5,1],[-3,3],[-9,14],[-3,10],[-4,3],[-4,0],[-2,-4],[0,-10],[-3,-5],[-5,-3],[-3,-5],[-3,-1],[-2,4],[0,10],[-2,9],[-6,3],[-8,1],[-4,1],[-6,4],[-17,7],[-9,4],[-10,3],[-3,2],[-5,-3],[-4,3],[-2,-2],[-5,1],[-8,4],[-12,1],[-7,2],[-5,4],[-5,3],[-9,3],[-5,0],[-16,-2],[-3,-4],[-2,1],[1,5],[0,9],[-6,5],[-8,4],[-4,-1],[-5,-9],[-10,-7],[-8,1],[-5,-1],[-4,-5],[-6,-2],[-5,2],[-10,0],[-4,2],[-6,11],[-2,2],[-5,0],[-3,-5],[-7,-1],[-8,0],[-7,-1],[-7,1],[-11,7],[-3,4],[0,7],[0,7],[3,5],[7,10],[1,8],[-3,7],[2,9],[4,8],[5,3],[12,1],[3,4],[-2,9],[-5,3],[-2,12],[-1,2],[-5,-4],[-2,0],[-3,5],[1,6],[-3,0],[-3,-2],[-6,0],[-2,4],[0,9],[2,13],[2,7],[7,5],[7,0],[4,-2],[3,-9],[2,-1],[5,9],[1,6],[-1,7],[-3,2],[-6,2],[-10,1],[-7,3],[3,12],[2,1],[5,0],[1,2],[3,12],[6,5],[3,-2],[3,-6],[6,-1],[5,-4],[7,-1],[6,6],[5,8],[4,1],[2,5],[-2,0],[1,6],[5,4],[3,6],[10,8],[5,2],[-1,8],[-8,0],[-9,8],[-4,0],[0,6],[4,1],[1,2],[-4,4],[-2,0],[2,8],[4,2],[4,3],[1,4],[2,-1],[5,11],[-1,3],[-3,-1],[0,6],[2,2],[4,-4],[-3,5],[0,7],[-1,9],[4,0],[1,10],[-2,4],[-6,-2],[-2,5],[2,3],[-2,8],[-2,-5],[-2,7],[1,3],[-1,10],[0,9],[-8,20],[-3,4],[-4,8],[-2,-2],[-1,8],[-5,6],[0,4],[7,6],[3,-1],[3,4],[-1,7],[-9,6],[-3,7],[-2,-2],[-3,4],[3,7],[-1,4],[4,2],[3,-4],[0,5],[-3,1],[0,7],[-2,1],[-1,-7],[-3,5],[1,2],[-2,3],[1,3],[-1,3],[-3,0],[-2,14],[2,10],[4,2],[-1,4],[-1,1],[-3,10],[1,3],[-3,2],[-2,4],[-1,6],[-2,3],[2,7],[2,2],[4,6],[4,3],[1,5],[4,8],[0,9],[2,1],[-1,8],[3,5],[8,3],[5,-1],[4,0],[6,2],[5,-2],[7,6],[1,4],[6,1],[1,9],[3,7]],[[242,9213],[5,-10],[-1,-8],[3,-9],[0,-7],[1,-4],[5,-10],[2,-6],[-2,-9],[-3,-6],[-25,-22],[-7,-2],[-7,-6],[-5,1],[-2,6],[0,9],[5,9],[3,6],[0,31],[-7,18],[4,6],[-1,1],[3,8],[-5,2],[1,2],[4,-2],[8,7],[9,1],[5,0],[7,-6]],[[191,9241],[-1,-3],[-4,-2],[-8,-1],[-4,-1],[-3,-5],[-1,-4],[-6,-12],[-3,-1],[-3,-6],[0,-15],[-1,-11],[4,-5],[6,-11],[0,-15],[3,-6],[5,-3],[7,-7],[6,-2],[3,-4],[7,-3],[0,-5],[-5,3],[-5,-1],[-6,6],[-3,-1],[-5,-5],[-4,0],[-5,-3],[-9,3],[-5,0],[-1,4],[-7,0],[-6,4],[-6,3],[-8,0],[0,7],[-2,-4],[0,-4],[-7,-2],[-3,-2],[-10,0],[-2,-1],[-7,-8],[-6,-2],[-1,-9],[-9,-2],[-4,2],[3,5],[-2,4],[-4,-3],[-8,5],[3,8],[-2,6],[2,7],[4,0],[3,8],[-4,3],[-2,0],[-2,3],[-1,10],[1,5],[4,6],[7,4],[4,-1],[5,-9],[5,2],[-1,4],[3,5],[0,7],[2,12],[-4,7],[-5,3],[-4,5],[-4,9],[0,9],[7,18],[3,0],[4,-9],[6,13],[4,5],[3,5],[6,4],[3,0],[5,3],[4,12],[3,2],[4,6],[6,5],[4,19],[0,4],[-3,8],[-9,5],[0,8],[6,2],[11,1],[3,2],[13,2],[10,-2],[6,-6],[3,-5],[2,-8],[4,-6],[3,-9],[1,-6],[2,-5],[0,-17],[2,-3],[-3,-4],[0,-14],[2,-6],[6,-5],[-1,-3],[-4,-6]],[[342,8087],[-2,6],[-2,3],[-7,15],[-8,9],[-3,11],[2,7],[4,5],[6,5],[4,6],[0,8],[2,9],[10,14],[0,5],[4,5],[1,4],[-6,6],[0,22],[-2,16],[0,12],[3,2],[1,5],[-5,10],[-11,-4],[-6,3],[-4,11],[-4,15],[-3,23],[-3,10],[3,15],[-3,9],[-1,12],[-5,13],[-3,3],[-2,-2],[-4,3],[-1,4],[-10,17],[-5,5],[-3,8],[-6,6],[-2,11],[-6,7],[-3,8],[-6,7],[-5,2],[-3,-3],[-4,1],[-2,8],[1,5],[-1,12],[-2,10],[0,5],[-2,5],[-5,10],[-7,7],[-4,8],[-17,21],[-6,2],[-11,8],[-6,2],[-5,4],[-10,6],[-7,4],[-6,6],[-4,8],[-5,5],[-10,5],[-8,5],[-14,3],[-13,1],[-13,3],[-6,-2],[-4,2],[-4,-7],[-10,-7],[-8,1],[-4,5],[-2,10],[0,5],[-5,5],[-5,4],[-6,13],[-5,14],[-3,8],[-10,2],[-1,6],[6,1],[3,4],[-1,11],[-5,8],[-5,5],[-2,7],[-2,8],[2,12],[0,9],[-5,4],[-5,2],[3,7],[0,5],[2,8],[10,7],[3,5],[0,5],[-7,5],[3,3],[5,-1],[6,2],[-2,5],[1,2],[5,6],[2,-1],[1,4],[-5,5],[2,4],[5,-1],[5,2],[5,12],[9,3],[3,9],[6,5],[1,5],[6,5],[7,8],[5,12],[2,4],[1,9],[5,0],[-4,8],[8,6],[3,0],[2,4],[5,2],[7,6],[3,7],[2,-7],[-2,-14],[1,-6],[2,-5],[5,4],[-1,8],[3,16],[0,8],[9,0],[2,-4],[-3,-4],[-4,0],[0,-2],[4,-4],[-1,-7],[-3,-4],[1,-3],[3,5],[5,0],[0,3],[3,3],[4,0],[0,-4],[-3,-1],[0,-4],[7,-17],[0,-2],[5,-2],[1,4],[-4,7],[-2,7],[1,7],[7,-10],[2,2],[0,10],[1,3],[0,10],[-2,8],[1,4],[-5,17],[-6,4],[-1,3],[5,12],[1,5],[-2,13],[0,9],[4,5],[2,7],[1,9],[-2,6],[3,8],[4,3],[5,0],[1,2],[2,-4],[5,3],[1,6],[8,9],[6,2],[2,5],[5,-3],[3,-1],[5,1],[7,-4],[2,3],[2,-4],[6,3],[2,5],[5,8],[-2,20],[1,0],[3,-26],[2,-7],[1,4],[4,1],[7,17],[1,2],[3,2],[4,-3],[0,-6],[-4,2],[-4,-4],[0,-10],[-4,-11],[-9,-5],[-7,-2],[-18,-9],[-7,-13],[-5,-8],[2,-7],[2,-13],[0,-4],[2,-11],[-1,-12],[-1,-4],[3,-6],[-1,-3],[5,0],[3,3],[6,1],[3,-4],[0,-3],[9,-7],[1,-7],[-2,-2],[2,-3],[1,-4],[4,-6],[-2,-15],[0,-2],[7,8],[2,1],[5,-3],[1,6],[3,4],[6,-3],[4,5],[2,1],[2,-5],[5,2],[4,-4],[1,-3],[2,8],[0,9],[2,5],[4,4],[0,6],[4,7],[-4,14],[-3,13],[-6,6],[-3,0],[-7,5],[-2,5],[-2,6],[2,14],[4,3],[1,5],[10,7],[2,4],[6,1],[6,-1],[9,-5],[8,-1],[6,-5],[2,-3],[4,-2],[4,1],[8,-3],[7,-6],[3,-5],[-1,-9],[-2,-4],[-3,-2],[-2,-4],[3,-5],[6,0],[1,-4],[4,1],[5,-2],[1,-13],[4,4],[9,-6],[1,3],[6,-8],[6,9],[-1,5],[3,1],[1,10],[-3,5],[-1,5],[-1,12],[-1,7],[1,7],[3,2],[2,8],[-1,5],[7,4],[6,-1],[3,3],[9,-4],[5,1],[10,-1],[3,-3],[16,-4],[8,-5],[3,3],[0,6],[-3,5],[-4,0],[-6,3],[-7,9],[-2,0],[-4,6],[4,10],[3,10],[-2,3],[1,8],[-9,4],[-6,8],[0,5],[4,6],[5,13],[4,4],[-1,12],[1,7],[3,2],[9,0],[3,1],[2,-2],[6,2],[4,-5],[4,-1],[1,2],[7,2],[6,4],[6,-1],[2,4],[5,3],[1,3],[7,4],[8,2],[6,7],[2,0],[5,3],[4,-2],[1,-5],[-3,-4],[3,-17],[4,1],[1,-5],[-4,-1],[0,-9],[5,1],[3,-6],[3,-20],[-2,-11],[4,-19],[0,-7],[2,-3],[2,-8],[-3,-8],[6,-8],[3,-13],[0,-7],[4,-6],[3,-11],[4,-9],[0,-9],[2,3],[6,-10],[-4,-14],[2,-3],[3,1],[3,-5],[7,5],[2,-6],[2,-2],[-3,10],[0,3],[4,-3],[3,2],[10,-1],[-1,14],[-2,4],[2,3],[9,7],[6,4],[3,-1],[2,-3],[2,-6],[8,3],[-2,7],[0,8],[12,10],[4,-2],[1,6],[13,11],[6,10],[2,8],[4,3],[8,3],[5,6],[8,5],[4,1],[4,3],[5,5],[6,9],[3,2],[7,12],[2,8],[10,12],[5,2],[12,-3],[-1,4],[1,7],[3,5],[2,-2],[4,1],[0,5],[7,9],[2,9],[7,11],[2,6],[0,7],[2,3],[-2,8],[3,6],[2,12],[2,3],[4,1],[2,4],[-1,4],[-4,6],[-2,6],[6,10],[9,8],[4,5],[7,3],[3,10],[3,6],[6,8],[9,17],[8,13],[6,14],[5,4],[5,4],[4,9],[6,11],[4,9],[5,7],[8,22],[4,6],[5,10],[4,4],[1,3],[6,7],[3,12],[9,8],[6,-1],[0,-4],[4,3],[2,4],[6,2],[7,8],[9,3],[10,0],[2,5],[4,-1],[3,-20],[5,-3],[9,-11],[13,-9],[-1,-1],[7,-3],[18,-1],[5,2],[2,4],[-3,4],[6,1],[0,6],[1,10],[6,1],[5,-3],[3,2],[8,-3],[10,-1],[10,-5],[4,-2],[7,-5],[2,-4],[4,-11],[0,-10],[5,-9],[2,-5],[8,-8],[2,-4],[7,-6],[8,-16],[3,-12],[0,-6],[7,-13],[-1,-6],[-3,-5],[0,-8],[3,-5],[2,-10],[-5,-16],[0,-9],[2,-11],[-3,-5],[2,-5],[-4,-8],[2,-10],[5,-12],[0,-7],[3,-4],[0,-11],[-3,-1],[-1,-7],[0,-5],[-3,-10],[-1,0],[-2,-6],[0,-10],[-3,-9],[-6,-1],[-7,-12],[-5,-13],[-8,-14],[-4,-9],[-13,-22],[-4,-11],[-7,-15],[-7,-11],[-6,-17],[-1,-9],[1,-6],[-5,-18],[1,-9],[0,-8],[2,-7],[-2,-11],[2,-4],[57,31],[1,0],[-60,-34],[5,-13],[2,-1],[6,1],[1,-4],[7,-8],[5,-3],[1,1],[2,-7],[3,-4],[3,1],[-6,-14],[-3,-2],[-2,-8],[-1,-6],[-3,-14],[-5,-10],[-5,-15],[-1,-8],[-1,-2],[-5,-19],[-4,-16],[-2,-6],[0,-8],[-1,-10],[3,-12],[0,-18],[-2,-4],[1,-3],[-1,-11],[-4,-8],[-1,-16],[-8,-13],[-4,-13],[-3,-3],[-4,-5],[-1,-8],[-3,-4],[-4,-1],[0,-3],[-2,-11],[-2,-5],[-5,-7],[-5,-17],[-6,-16],[-4,-3],[0,-6],[-2,-4],[-1,-9],[-2,-7],[-1,-9],[-3,-22],[-1,-21],[-2,-7],[-1,-19],[-4,-9],[0,-6],[-3,-14],[1,-15],[4,-7],[10,-14],[3,-6],[0,-6],[3,-12],[-2,-10],[0,-7],[-11,-22],[-27,-16],[-5,-10],[-10,-42],[0,-5],[-4,-3],[-2,-8],[0,-5],[-1,-7],[-4,-3],[0,-5],[-3,-7],[-9,-7],[0,-3],[-5,-13],[-1,-6],[-3,-9],[-5,-7],[-11,-10],[-11,-12],[-4,-6],[-5,-13],[-2,-2],[-11,-7],[-4,-1],[0,-5],[-2,-13],[-5,-12],[-3,-14],[0,-10],[-3,-17],[0,-8],[2,-10],[3,-14],[4,-5],[5,6],[2,1],[2,-4],[0,-5],[-2,-4],[1,-3],[-2,-6],[2,-6],[0,-19],[-3,-14],[1,-7],[0,-8],[-3,-5],[0,-9],[-2,-13],[-5,-5],[0,-14],[-1,-5],[-3,-4],[-6,-13],[-10,-14],[-4,-7],[-3,-7],[-6,-8],[-8,-6],[-3,-6],[-4,-6],[-3,-1],[-3,-6],[-2,-8],[-10,-23],[-4,-21],[-1,-7],[-4,-8],[0,-13],[10,-14],[9,-8],[14,-4],[10,1],[5,-5],[2,-11],[-2,-1],[0,-9],[-1,-6],[-1,-12],[-4,-9],[-5,-8],[-2,-9],[-5,-4],[-2,-7],[-1,-15],[-2,-13],[-8,-13],[-7,-7],[-14,-12],[-13,-6],[-7,-7],[-18,-8],[-12,-6],[-10,-8],[-3,-5],[-6,-5],[-8,-3],[-8,-11],[-2,-4],[-5,-1],[-2,-4],[-5,-3],[-7,-9],[-5,-12],[-3,-10],[-3,-5],[-2,-8],[0,-10],[1,-3],[-2,-9],[-6,-10],[-7,-7],[-7,-3],[-2,-4],[-6,0],[-2,6],[-3,2],[-5,-3],[-4,4],[-9,-7],[1,-3],[1,-15],[0,-16],[-3,-6],[-7,-6],[-12,-2],[-2,2],[1,6],[-2,7],[-6,3],[-1,4],[-4,2],[-11,3],[-11,0],[-22,-4],[-5,-4],[-6,-1],[-9,-5],[-10,-9],[-10,-12],[-3,-6],[-20,-27],[-21,-23],[-4,-7],[-5,-4],[-3,-5],[-8,-2],[0,-4],[-3,0],[-1,4],[-13,20],[-3,4],[1,1],[15,-23],[4,2],[11,14],[3,2],[10,13],[3,1],[6,8],[5,4],[5,9],[7,8],[-7,36],[-8,40],[-5,32],[-12,23],[-6,12],[-4,9],[-3,17],[0,17],[3,16],[-3,16],[-4,11],[-10,15],[-17,16],[-24,24],[-12,9],[-30,11],[-10,1],[-6,5],[-5,7],[2,5],[0,14],[1,12],[-5,24],[-1,29],[-2,15],[-5,13],[-8,15],[0,5],[-4,-5],[-5,5],[8,10],[6,3],[3,6],[4,14],[9,23],[2,7],[0,20],[-3,10],[-1,8],[6,13],[1,9],[15,13],[10,4],[8,5],[1,9],[5,15],[12,15],[3,11],[-2,7],[0,10],[-1,6],[3,18],[-2,3],[-6,6],[4,10],[-2,7],[2,12],[-2,7]],[[344,9306],[-4,-12],[-2,-7],[-3,-5],[-4,-2],[-1,-3],[-6,-7],[3,-2],[1,-8],[0,-4],[-3,-9],[-1,-6],[-4,0],[-2,-4],[-4,0],[-1,3],[-5,2],[0,9],[3,10],[-4,10],[-11,19],[4,6],[6,-9],[3,0],[3,5],[3,0],[7,8],[2,4],[3,2],[9,0],[9,6],[-1,-6]],[[360,9359],[-4,5],[0,-4],[-4,-7],[-6,2],[-5,12],[1,-7],[0,-3],[-10,-8],[-2,-5],[-4,0],[-4,4],[-1,5],[0,7],[-1,8],[1,3],[6,-3],[6,4],[1,2],[4,1],[8,-2],[4,-2],[3,3],[5,1],[0,2],[6,5],[3,-2],[3,2],[11,1],[20,1],[9,0],[1,17],[1,3],[11,4],[0,-9],[-8,1],[-2,-17],[4,-2],[7,4],[-2,4],[4,4],[2,-3],[5,8],[3,1],[1,8],[3,5],[2,-1],[7,5],[1,3],[6,1],[0,6],[7,0],[1,-1],[6,-1],[0,-2],[6,0],[7,-7],[6,8],[5,8],[2,-1],[-1,6],[3,2],[1,5],[3,8],[-1,3],[2,11],[-6,24],[7,6],[12,-1],[0,18],[1,3],[0,-22],[7,-10],[2,-4],[2,0],[3,-9],[-1,-2],[2,-14],[0,-4],[2,-6],[-1,-2],[4,-10],[-3,-2],[5,-22],[-1,-4],[3,-4],[-1,-5],[3,0],[1,-5],[-4,0],[0,-11],[1,-1],[-2,-5],[-2,-10],[0,-8],[-4,-2],[0,-8],[-5,-2],[3,-5],[0,-3],[14,-15],[6,-4],[4,3],[4,-2],[7,4],[6,-1],[1,-2],[6,-3],[2,7],[2,3],[6,1],[3,-2],[3,-7],[2,-6],[-2,-20],[-2,-9],[-6,-11],[-1,-8],[3,-9],[-2,-5],[1,-7],[3,-5],[1,-6],[5,-16],[0,-10],[-1,-5],[-6,-16],[-4,-3],[-4,0],[-13,1],[-6,3],[-4,4],[2,5],[-7,7],[-4,0],[-10,7],[-13,6],[-7,0],[-6,4],[-2,-3],[-4,0],[-3,8],[-3,3],[3,19],[-6,-14],[-5,-1],[-3,3],[-1,8],[-3,-2],[-3,1],[-1,-3],[-3,2],[-1,5],[-5,5],[-2,-1],[3,-18],[2,-3],[-5,-3],[-1,-10],[-3,-3],[-2,6],[-4,10],[1,2],[-6,0],[-1,2],[3,6],[-3,3],[0,4],[-4,1],[-5,-2],[-3,-9],[-7,-2],[-3,-3],[-5,2],[-13,-9],[-7,-6],[-25,18],[8,14],[2,19],[11,1],[-1,20],[8,3],[-2,2],[-9,-4],[-2,5],[7,6],[-7,12],[-16,-10],[-5,-4],[-1,2],[5,3],[-1,3],[-4,-4],[-4,4],[5,4],[-1,3],[13,11],[-1,1],[-13,-11],[0,1],[13,11],[-4,10],[-7,8],[-4,-2],[-1,3],[-2,-3],[-3,3],[-3,6],[-3,0],[-4,4],[2,4]],[[5138,2401],[10,3],[8,1],[7,-3],[2,9],[3,7],[9,13],[7,11],[12,13],[3,5],[7,20],[8,31],[2,5],[11,32],[0,7],[6,8],[13,12],[9,9],[5,2],[9,9],[1,4],[3,22],[3,24],[6,-1],[5,3],[4,-5],[10,18],[1,-5],[8,2],[3,-20],[4,-12],[2,1],[6,-3],[10,0],[7,-2],[1,-2],[-7,-16],[0,-6],[18,-9],[6,-1],[11,13],[-1,5],[3,6],[4,10],[19,-11],[15,-9],[-7,-17],[-3,0],[-5,-12],[-2,-6],[-2,-11],[0,-15],[4,-6],[7,-2],[4,5],[3,7],[3,11],[4,4],[7,13],[5,-11],[5,6],[1,-4],[5,-9],[6,-5],[2,1],[9,-7],[6,-6],[2,-5],[0,-7],[5,-3],[2,-3],[2,-9],[3,-6],[3,-3],[3,-6],[0,-5],[3,-6],[0,-4],[4,-7],[2,-6],[2,-2],[22,0],[7,4],[7,8],[2,6],[2,15],[6,10],[-11,3],[-7,4],[-4,6],[-3,7],[-1,7],[2,7],[-4,19],[-3,8],[-22,23],[-6,7],[-6,13],[31,33],[-3,7],[-3,9],[0,9],[-3,15],[-1,4],[-4,21],[0,6],[-2,7],[-14,4],[-3,5],[-6,4],[-4,4],[-7,14],[-7,10],[-5,0],[-9,0],[-8,3],[-8,8],[-9,11],[-4,4],[-10,4],[-3,2],[-10,10],[-10,9],[-14,4],[-21,-1],[-4,-2],[-5,0],[-3,-4],[-3,-2],[0,-3],[-11,-6],[-2,5],[-1,6],[-8,5],[-8,9],[-4,11],[-4,6],[-1,10],[1,4],[0,8],[-2,14],[-2,9],[0,8],[3,9],[3,2],[7,2]],[[5294,2909],[6,-1],[-1,2],[16,14],[6,3],[13,1],[7,1],[7,7],[4,9],[3,14],[1,20],[3,20],[2,8],[1,4],[-4,4],[6,8],[7,5],[3,5],[2,10],[7,9],[4,3],[11,3],[4,3],[9,1],[-1,13],[3,8],[6,5],[8,6],[15,1],[9,5],[6,4],[4,-3],[2,-1],[5,6],[8,1],[15,-13],[3,-7],[3,-16],[-1,-13],[2,-9],[6,-1],[1,4],[4,0],[3,-2],[12,1],[4,-3],[4,0],[4,2],[5,5],[20,11],[6,8],[9,14],[5,13],[-1,1],[2,7],[5,11],[1,16],[-1,12],[-1,12],[8,21],[7,1],[2,8],[1,7],[3,11],[1,8],[5,19],[7,22],[-3,11],[9,28],[3,5],[6,4],[-7,3],[-7,6],[-3,4],[-6,12],[-14,24],[-7,18],[-1,6],[18,16],[5,3],[12,6],[6,2],[7,1],[18,0],[27,-3],[24,-3],[15,-2],[14,-4],[11,-12],[3,0],[25,-39],[6,5],[12,13],[10,8],[3,8],[4,4],[9,12],[7,10],[8,13],[9,19],[6,15],[7,7],[0,10],[1,2],[26,-13],[31,-17],[11,-12],[8,-13],[4,-12],[2,-11],[0,-6],[-3,-13],[-8,-21],[-4,-16],[-1,-12],[0,-7],[4,-16],[3,-10],[10,-13],[7,-6],[7,-4],[5,-1]],[[5959,3266],[4,-26],[1,-19],[-2,-8],[-4,-6],[-14,-9],[-4,-6],[-16,-23],[-2,-6],[2,-13],[3,-12],[0,-4],[-5,-13],[-7,-11],[-5,-5],[-7,-4],[-14,-14],[-14,5],[-5,0],[-16,-6],[-7,2],[-1,7],[-3,-1],[-4,-5],[-4,-3],[-10,-6],[-13,0],[-6,-7],[-2,-4],[-1,-11],[-7,-13],[-2,-9],[-5,-11],[-3,-8],[-7,-13],[-2,-1],[-7,-12],[-1,-4],[-2,-24],[1,-18],[2,-4],[3,-11],[-1,-5],[2,-5],[-1,-15],[-12,6],[-5,-9],[7,-10],[8,-19],[4,-5],[11,-22],[13,-17],[4,-7],[2,-13],[2,-14],[4,-5],[1,-4],[-13,-10],[3,-7],[7,-26],[-7,-6],[3,-10],[2,-8],[1,1],[2,-15],[-11,1],[-14,-2],[-11,-4],[-9,-7],[-5,-3],[-5,-5],[-2,-7],[-6,-14],[1,-8],[5,-10],[3,-4],[5,-4],[3,-5],[4,-9],[5,-5],[5,0],[5,-5],[14,-9],[-2,-11],[-3,-20],[3,-13],[3,-19],[-4,-3],[-2,-8],[-6,-6],[-12,-10],[-2,-6],[1,-7],[-1,-9],[-5,-8],[1,-12],[1,-7],[0,-15],[-2,-17],[-2,0],[2,-11],[-1,-8],[-2,-12],[0,-8],[-4,-10],[-5,-7],[1,-2],[0,-7],[1,-2],[9,-9],[8,-3],[5,0],[4,-1],[4,1],[10,-1],[-1,-12],[3,-9],[7,4],[0,-1],[8,-4],[2,2],[6,-1]],[[5822,2333],[0,-4],[3,-10],[-3,-1],[2,-13],[-4,-1],[-4,-8],[-1,-6],[-1,-10],[-4,0],[2,-9],[3,-5],[-2,-5],[6,-7],[6,-4],[18,21],[13,13],[1,4],[0,13],[-1,4],[0,7],[12,-2],[16,-10],[4,-5],[-1,-6],[-3,-22],[-1,-10],[1,-18],[-3,-12],[-8,-8],[-23,-19],[-4,-18],[-7,-21],[-21,-30],[-1,-1],[-10,13],[-6,-5],[0,-5],[15,-16],[12,-9],[11,-7],[7,-2],[-8,-26],[-5,-7],[0,-39],[-18,-29],[1,-2],[3,-10],[-1,-14],[2,-8],[3,-8],[6,-7],[5,-5],[10,-7],[15,-9],[10,-5],[21,-10],[13,-2],[8,0],[5,-3],[5,-4],[2,-10],[0,-16],[2,-17],[2,-7],[2,-14],[6,-14],[6,-10],[9,-8],[7,-5],[5,-1],[14,-8],[14,-5],[13,-7],[7,-1],[12,-8],[7,-6],[6,-8],[5,-11],[8,-14],[5,-6],[8,-19]],[[6061,1709],[-19,-14],[-96,-65],[-64,-42]],[[5882,1588],[-41,44],[-10,10],[-14,16],[-7,10],[-7,14],[-4,8],[-3,11],[-3,12],[-7,36],[-3,16],[-8,16],[-9,16],[-13,14],[-9,8],[-8,6],[-45,35],[-14,11],[-5,5],[-18,20],[-4,6],[-7,17],[-12,-3],[-2,8],[-12,-8],[-7,2],[0,-3],[-7,0],[-11,3],[-4,1],[-11,6],[-7,1],[-2,-1],[-7,2],[-22,1],[-5,24],[-26,15],[0,5],[-12,4],[-11,-17],[-17,-1],[-13,11],[4,-10],[-8,-6],[-15,-7],[-7,0],[-20,5],[-19,2],[-2,-2],[-22,-10],[-13,5],[-2,0],[-12,0],[-12,4],[-24,6],[-6,0],[-7,2],[-2,0],[-16,-10],[-3,-3],[-2,-6],[-3,-6],[-8,-17],[1,-18],[-2,0],[-1,-5],[-9,1],[-5,-4],[1,-7],[-3,-1],[-8,2],[-2,-2],[-13,-4],[-6,-4],[-5,-4],[-22,-23],[-11,-11],[-18,-14],[-7,-5],[-27,-16],[9,-23],[8,-21],[5,-17],[4,-16],[3,-19],[2,-13],[0,-22],[0,-11],[-2,-19],[-2,-14],[-5,-20],[-4,-12],[-8,-18],[-9,-16],[-5,-9]],[[5115,1551],[-2,8],[-2,20],[-4,26],[-7,23],[-6,16],[-10,22],[-15,25],[-7,10],[-9,14],[-20,32],[-5,12]],[[4242,1070],[-2,9],[-1,8],[0,7],[2,8],[4,9],[18,34],[9,12],[7,7],[6,4],[6,3],[5,-1],[18,-9],[9,-1],[7,1],[4,2],[9,8],[6,11],[2,15],[3,82],[0,6],[-1,16],[2,19],[3,17],[1,6],[15,27],[25,43],[5,7],[3,8],[5,13],[29,-19],[7,-6],[9,-11],[7,-11],[11,-17],[14,-10],[41,-8],[5,-2],[10,-4],[10,-7],[5,-5],[6,-8],[49,-71],[8,-7],[10,-4],[16,-5],[36,-9],[37,-20],[23,-12],[18,-2],[28,3],[8,2],[18,0],[16,-4],[21,-9],[11,-2],[13,0],[26,11],[34,28],[6,6],[8,11],[5,10],[3,10],[3,12],[8,36],[5,19],[4,12],[25,43],[10,15],[22,32],[11,15],[18,25],[38,56],[11,17]],[[5115,1551],[2,-13],[4,-16],[14,-32],[10,-12],[7,-9],[8,-6],[8,-4],[20,-8],[13,-5],[17,-5],[35,-9],[7,-1],[22,-9],[40,-18],[37,-16],[18,-10],[10,-5],[23,-16]],[[5410,1357],[10,-14],[3,-10],[1,-17],[0,-10],[-1,-10],[-8,-37],[-8,-30],[-3,-12],[-2,-13],[-3,-21],[-2,-32],[-2,-44],[-2,-10],[-6,-13],[-8,-9],[-3,-2],[-24,-14],[-38,-25],[-14,-6],[-19,-7],[-23,-5],[-13,-4],[-13,-7],[-5,-5],[-9,-10],[-53,-68],[-7,-10],[-4,-8],[-2,-11],[-1,-12],[0,-34],[1,-7],[0,-6],[-3,-15],[-6,-16],[-6,-8],[-14,-14],[-36,-33],[-21,-21],[-9,-15],[-18,-40],[-5,-11],[-7,-10],[-3,-4],[-12,-7],[-36,-12]],[[3883,1288],[10,11],[3,6],[0,5],[-2,7],[-7,1],[-79,77],[-1,7],[53,84],[2,-3],[-49,-80],[1,-5],[65,-67],[2,2],[7,12],[1,6],[13,21],[3,1],[5,0],[6,-6],[1,0],[19,30],[3,-1],[5,2],[11,6],[5,5],[5,6],[13,28],[5,13],[1,5],[-24,14],[3,9],[2,1],[6,-2],[23,35],[5,9],[-8,6],[-20,37],[-31,57],[-25,46],[-9,19],[-8,23],[-9,31],[-4,27],[-1,25],[1,-2],[1,-11],[3,-24],[2,-17],[8,-27],[11,-29],[8,-17],[39,-70],[35,-64],[47,60],[1,-5],[-3,-4],[6,-7],[6,7],[3,-1],[4,8],[-7,8],[-3,-3],[0,6],[5,7],[-2,6],[-28,35],[0,2],[79,98],[-1,3],[55,69],[8,17],[2,-1],[40,86],[53,117],[0,3],[-38,59],[-1,2],[33,116],[45,3],[2,2],[3,10],[7,9],[3,3],[6,-1],[4,9],[5,13],[1,11],[-1,1],[2,5],[1,-1],[6,9],[3,8],[4,8],[0,3],[-2,9],[-9,26],[-3,13],[-4,7],[1,6],[3,-1],[2,-2],[6,-20],[2,-3],[4,2],[-4,4],[9,2],[1,3],[-5,11],[3,3],[4,-14],[4,2],[0,20],[4,0],[2,-14],[2,-2],[6,16],[4,7],[8,20],[2,7],[2,21],[2,-1],[1,-12],[2,-5],[12,0],[4,2],[8,5],[2,10],[-2,7]],[[4413,2446],[13,0],[8,1],[-4,15],[-12,44],[1,3],[15,7],[23,11],[-2,4],[29,17],[11,9],[3,3],[5,13],[13,-10],[-4,-27],[-4,-4],[-14,-3],[7,-16],[7,-7],[3,-6],[-3,-10],[3,-2],[-7,-14],[-3,-9],[-7,-11],[-6,-10],[-5,-4],[-3,-1],[-9,-7],[-6,0],[-12,-11],[2,-11],[-2,-17],[-1,-7],[-6,-24],[-5,-27],[-3,-8],[-4,-6],[-3,-3],[-2,-4],[-1,-15],[3,-11],[0,-4],[-9,-42],[-2,-9],[-2,-9],[1,-4],[2,-2],[-1,-10],[14,-5],[9,0],[3,-3],[2,-5],[-6,-9],[-3,-7],[-4,-13],[-6,-12],[-1,-6],[-1,-7],[7,-18],[8,-5],[7,-3],[-2,-7],[17,-9],[15,-12],[6,-5],[19,-21],[7,-6],[13,-9],[14,-12],[7,-6],[9,-10],[10,-14],[12,-12],[7,-4],[0,-1]],[[7099,5230],[-13,-11],[-15,2],[-2,-2],[-5,-1],[-14,-13],[-12,-33],[-2,-18],[-4,-6],[-9,-4],[-4,-23],[1,-5],[-3,-7],[-2,-2],[-9,-3],[-13,-7],[-10,-6],[-7,-9],[-9,-6],[-4,-7],[-9,2],[-21,0],[-20,-3],[-8,-4],[-10,-10],[-5,-7],[-3,-8],[-3,-8],[0,-22],[-1,-11],[0,-4],[0,-19],[-2,-9],[-6,-16],[-13,-18],[-6,3],[-6,1],[-5,-1],[-51,-14]],[[6794,4921],[-18,8],[-25,13],[-19,16],[-22,21],[-22,17],[-18,8],[-16,3],[-23,2],[-22,0],[-52,-2],[-15,0],[-43,-8],[-22,-6],[-29,-5],[-4,2],[-14,1],[-3,-6],[-16,-15],[4,-7],[-2,-6],[-3,-18],[-5,-10],[-3,-5],[-5,10],[-4,3],[-6,2],[-5,9],[-3,2],[-14,-8],[-9,-6],[-6,4],[-1,-2],[-12,-22],[-10,-18],[-7,-12],[-18,-27],[-11,-14],[-14,-16],[-15,-15],[-26,-22],[-11,-9],[-28,-23],[-88,-70],[-40,-34],[-25,-25],[-11,-12],[-12,-14],[-16,-21],[-14,-21],[-20,-35],[-9,-17],[-14,-31],[-7,-15],[-16,-34],[-20,-39],[-20,-42],[-7,-14],[-14,-25],[-15,-25],[-28,-43],[-46,-70],[-19,-29],[-26,-41],[-28,-47],[-16,-32],[-12,-26],[-8,-22],[-22,-58],[-27,-75],[-19,-51],[-14,-30],[-9,-17],[-6,-10],[-15,-22],[-18,-25],[-34,-45],[-104,-139],[-7,-11],[-9,-17],[-4,-9],[-9,-22],[-3,-12],[-3,-14],[-2,-11],[-2,-19],[-1,-18],[0,-29],[0,-53],[0,-12],[-2,-15],[-3,-14],[-5,-15],[-6,-14],[-11,-17],[-19,-25],[-10,-14],[-6,-11],[-6,-13],[-4,2],[-4,-1],[-1,4],[2,5],[-4,-3],[-2,1]],[[5277,3147],[7,14],[5,4],[6,8],[2,3],[6,7],[-1,8],[-5,12],[-6,14],[-7,4],[-7,1],[-6,4],[-4,6],[-8,25],[-6,8],[-20,17],[-10,12],[-6,13],[-7,5],[-5,9],[-5,2],[-2,5],[-2,9],[-3,8],[2,4],[-1,3],[2,4],[0,10],[2,9],[7,12],[2,11],[7,19],[-1,2],[-4,3],[-4,5],[-2,5],[-1,7],[1,7],[-4,7],[2,9],[7,9],[4,3],[5,11],[0,7],[3,7],[2,7],[1,12],[1,1],[3,19],[14,-2],[11,5],[2,6],[-1,2],[6,22],[-4,10],[3,16],[4,8],[5,5],[5,9],[2,2],[-2,2],[-2,-3],[-8,-3],[-2,1],[-9,17],[-7,6],[-10,3]],[[5234,3644],[4,7],[-7,24],[1,17],[4,26],[0,19],[-1,23],[-3,13],[-9,22],[-5,8],[-3,10],[1,11],[7,23],[24,39],[6,11],[10,17],[-3,23],[6,16],[6,11],[4,2],[7,11],[5,5],[5,7],[6,23],[7,14],[0,3],[-2,14],[-6,18],[-4,19],[0,4],[4,11],[3,13],[5,18],[0,6],[0,15],[0,7],[-1,7],[1,4],[-6,0],[-8,5],[-11,1],[-1,-4],[-8,-4],[-11,-1],[-11,-1],[-10,2],[-7,-1],[-8,2],[6,21],[5,15],[4,14],[-4,20],[-3,1],[-1,7],[4,12],[16,18],[-1,9],[11,7],[9,8],[6,11],[5,8],[4,10],[9,1],[2,1],[12,-2],[3,1],[3,4],[0,4],[6,12],[2,8],[0,4],[4,16],[16,29],[4,6],[5,13],[6,9],[6,7],[9,7],[7,9],[0,5],[4,8],[5,5],[7,4],[11,-1],[5,-2],[7,2],[6,-1],[5,-3],[12,-14],[6,-5],[11,-7],[26,-13],[9,-2],[9,4],[2,5],[-1,14],[-6,8],[-2,5],[0,6],[-4,-8],[-5,-8],[-6,-4],[-5,0],[-13,2],[-4,3],[-4,7],[-1,11],[1,16],[-3,13],[0,11],[-2,6],[-4,5],[-7,4],[-3,3],[-8,1],[-10,0],[-4,3],[-2,6],[-1,14],[1,8],[6,24],[2,11],[0,6],[-4,7],[-21,21],[-5,9],[-4,10],[-12,38],[-4,10],[-6,7],[-8,3],[-18,6],[7,9],[3,18],[1,15],[3,24],[7,2],[4,7],[2,7],[2,3],[6,0],[4,3],[1,4],[-1,10],[1,6],[6,3],[3,3],[7,13],[8,27],[5,25],[4,15],[11,27],[6,27],[3,14],[11,45],[9,31],[7,22],[1,7],[-2,2],[3,19],[3,7],[5,17],[8,7],[18,11],[25,18],[19,12],[13,9],[2,-4],[6,2],[3,6],[10,15],[-3,5],[0,6],[12,0],[2,19],[-10,5],[3,11],[11,-2],[2,18],[-9,30],[8,34],[-2,2],[3,14],[-1,60],[16,6],[3,-2],[-4,-3],[-2,-5],[2,-6],[8,-1],[5,1],[4,-4],[6,3],[3,-2],[1,-9],[2,-12],[18,-14],[4,-8],[20,4],[7,22],[-2,44],[-3,18],[58,0],[0,4],[1,7],[5,9],[9,19],[5,17],[9,11],[1,3],[0,9],[6,15],[4,7],[5,15],[2,13],[1,19],[-1,15],[-4,15],[-4,10],[-15,19],[0,3],[5,7],[15,13],[4,10],[0,13],[-1,7],[-9,19],[-8,30],[-2,13],[0,13],[-3,19],[4,3],[1,1],[-2,8],[-2,2],[-8,18],[-8,20],[-6,12],[-14,26],[-16,31],[-5,11]],[[5872,6248],[73,106],[4,11],[0,7],[0,12],[3,6],[7,9],[9,10],[8,10],[6,3],[9,1],[11,8],[17,5],[17,0],[6,3],[9,2],[13,4],[7,4],[23,6],[14,3],[12,3],[8,2],[9,-5],[9,-12],[18,-32],[8,-9],[15,-19],[7,-5],[45,-42],[4,-3],[8,0],[7,-1],[6,-5],[11,-18],[4,-16],[4,-12],[6,-6],[3,-6],[4,-10],[2,-16],[2,-5],[7,-4],[15,2],[17,-3],[17,-11],[5,-7],[7,-14],[5,-4],[22,-11],[19,-4],[14,-1],[15,0],[7,-2],[15,-11],[3,-3],[17,-29],[5,-8],[3,-11],[2,-11],[-2,-39],[-2,-18],[-5,-19],[-9,-19],[-4,-11],[1,-17],[3,-15],[1,-18],[0,-15],[2,-9],[-1,-20],[-4,-15],[-4,-13],[-6,-15],[-2,-8],[-1,-8],[-1,-19],[-2,-20],[1,-10],[4,-12],[12,-10],[4,-1],[12,3],[29,18],[17,12],[26,11],[12,9],[13,5],[13,7],[15,12],[6,3],[13,4],[9,1],[4,-2],[7,-13],[5,-6],[18,-19],[9,-3],[11,-3],[3,-3],[2,-6],[0,-12],[-2,-20],[1,-8],[6,-16],[4,-8],[12,-20],[3,-8],[2,-7],[4,-6],[7,-2],[11,-1],[17,-11],[6,-2],[6,0],[11,-7],[6,-8],[12,-20],[5,-9],[-1,-18],[0,-11],[-6,-24],[-4,-16],[-2,-24],[5,-11],[3,-14],[2,-10],[3,-4],[9,-19],[13,-24],[6,-6],[14,-12],[7,-8],[9,-11],[12,-14],[4,-3],[12,-2],[9,1],[5,-1],[8,-4],[16,-9],[11,-5],[5,-4],[8,-8],[8,-10],[6,-6],[7,-4],[2,0],[10,-5],[14,-6],[10,-2],[4,-3],[9,-9],[7,-9],[7,-10],[1,-10],[2,-5],[6,-2],[6,-8],[8,-4],[8,-9],[8,-10],[4,-10],[4,-20],[2,-7],[3,-3]],[[6680,4159],[-5,15],[-4,18],[-4,31],[-6,21],[-5,8],[-10,13],[-6,5],[-9,4],[-14,2],[-27,0],[-19,2],[-30,4],[-12,1],[-16,4],[-27,11],[-11,7],[-26,15],[-8,3],[-7,-1],[-8,-2],[-5,-6],[-16,13],[0,2],[-7,1],[-2,3],[-4,8],[-6,10],[-1,3],[-2,10],[-2,6],[-2,19],[1,15],[10,32],[7,24],[4,8],[3,13],[2,15],[-1,4],[-5,17],[10,9],[3,9],[4,-4],[6,3],[-1,3],[-10,15],[-18,25],[-10,17],[-4,10],[6,8],[6,7],[11,5],[8,0],[26,-8],[8,0],[8,2],[4,3],[7,5],[-3,1],[-5,7],[-14,15],[-3,9],[0,14],[-1,8],[-4,13],[0,9],[-8,0],[6,3],[11,14],[6,8],[12,22],[2,7],[-4,4],[3,8],[0,8],[26,-8],[3,-3],[3,-9],[8,4],[9,3],[10,2],[11,1],[5,1],[5,6],[12,5],[1,5],[33,4],[8,6],[4,7],[7,8],[8,6],[12,2],[10,-3],[27,-14],[10,-3],[9,0],[4,1],[10,5],[5,5],[7,4],[6,2],[6,0],[7,-4],[11,-9],[26,-23],[8,-6],[8,-2],[9,1],[5,3]],[[6795,4773],[3,-4],[9,-37],[6,-10],[3,-9],[0,-18],[2,-5],[9,-12],[5,-13],[2,-11],[0,-12],[-6,-28],[-3,-5],[-5,-4],[-4,-6],[0,-3],[2,-6],[8,-2],[2,-3],[2,-11],[-2,-6],[-9,-11],[-4,-10],[-1,-6],[0,-6],[3,-8],[2,0],[8,5],[3,0],[4,-3],[5,2],[1,-3],[4,-1],[1,-3],[7,-5],[1,-4],[-1,-4],[1,-6],[-1,-3],[1,-11],[3,-6],[0,-3],[2,-5],[0,-5],[-5,-1],[-1,-6],[1,-7],[1,-8],[-1,-9],[-5,-24],[0,-3],[-2,-5],[11,-7],[6,-2],[6,0],[21,6],[9,3],[11,-1],[7,-3],[6,-5],[7,-9],[7,-11],[4,-12],[3,-11],[16,1],[4,-5],[10,-1],[10,1],[17,-3],[13,-6],[5,-5],[8,-4],[13,-3],[6,1],[10,3],[0,-9],[2,-7],[11,-24],[-2,-3],[3,-12],[-12,-4],[-8,2],[-2,-2],[-22,-8],[0,-7],[0,-5],[-4,-1],[-1,-10],[-6,-5],[-9,-6],[0,-4],[2,-12],[3,-21],[0,-9],[-2,-9],[-8,-10],[-7,-13],[-1,-8],[1,-5],[3,-7],[15,-13],[3,-7],[-1,-9],[-1,-4],[-4,-5],[0,-7],[1,-7],[4,-5],[0,-9],[-13,-7],[-3,-10],[-2,-5],[-4,-4],[-4,-2],[-1,-3],[0,-6],[-1,-3],[-7,-1],[-1,-3],[-12,1],[-8,-4],[-2,-3],[-4,-11],[-1,-9],[-2,-2],[-8,1],[-13,3],[-5,-3],[-2,-5],[-7,-8],[-16,-12],[-4,0],[-8,-8],[-6,9],[-9,9],[-7,4],[-10,9],[-26,17],[-15,8],[-17,16],[-8,7],[-13,16],[-18,21],[-18,17],[-6,7],[-14,11],[-13,13],[-14,20],[-12,8]],[[4814,3231],[10,-3],[11,-7],[1,0],[5,11],[10,24],[25,60],[28,67],[6,11],[8,8],[8,6],[23,15],[-5,-24],[-4,-11],[-7,-14],[-18,-28],[-1,-1],[-12,-23],[-7,-17],[-8,-23],[-15,-38],[-7,-15],[-9,-15],[-10,-16],[3,-3],[-2,-4],[6,-6],[3,2],[6,-4],[8,-6],[-1,-9],[-8,-18],[-9,-7],[-5,1],[-10,7],[-10,1],[-3,-3],[-9,-26],[-1,-5],[-6,-14],[-5,-13],[1,-10],[4,-8],[3,-4],[6,-2],[6,-5],[-3,-8],[7,-2],[7,1],[18,0],[0,-12],[1,-4],[-1,0],[-15,4],[-4,-3],[-2,-6],[-4,-4],[-6,-2],[-5,1],[-23,11],[-4,-1],[-4,3],[-2,-1],[-6,-16],[1,-3],[-3,-12],[-7,4],[-2,-2],[-6,-2],[-9,-16],[-11,-23],[-3,-6],[-1,1],[-8,-10],[-1,1],[-8,-11],[9,-9],[-3,-6],[-7,-4],[-13,-14],[-9,-18],[-8,-18],[-5,-14],[0,-11],[-5,-10],[12,-9],[11,-7],[7,-3],[8,-8]],[[4716,2813],[-1,-6],[-12,6],[-10,6],[-5,2],[-6,0],[-20,-13],[-21,-4],[-2,-2],[-26,-5],[9,7],[7,13],[4,12],[6,27],[5,13],[14,37],[9,18],[-2,2],[-8,4],[-10,11],[-9,8],[-11,10],[-62,-124],[-19,-34],[0,-4],[-35,19],[-8,-32],[-1,-13],[-12,-5],[11,-21],[-18,-11],[-10,12],[-4,-2],[-8,11],[-14,3],[1,7],[-30,49],[-6,10],[7,8],[-8,15],[-7,15],[-8,14],[-9,-9],[-22,36],[7,7],[4,-6],[9,3],[19,10],[3,-7],[12,9],[-8,21],[6,5],[2,-8],[6,-10],[11,-15],[10,13],[16,-17],[12,16],[19,23],[17,14],[10,9],[-15,18],[-12,-11],[-17,-18],[-8,11],[-4,15],[-7,20],[-12,22],[-9,18],[-13,25],[-7,9],[-15,21],[-9,11],[-19,27],[-19,26],[-10,13],[2,14],[8,37],[3,15],[8,44],[10,51],[4,23],[2,12],[-22,7],[-26,8],[-3,-5],[-5,-3],[-10,-3],[-6,-1],[-14,3],[0,-46],[0,-17],[2,-55],[0,-49],[0,-32],[2,-35],[1,-68],[3,-87],[3,-20],[-3,-16],[-5,15],[-3,4],[-4,2],[-6,1],[-7,-2],[1,-2],[-5,-5],[-4,-11],[0,-8],[-9,7],[-14,14],[-1,0],[-31,-30]],[[4215,2939],[-13,17],[-10,17],[-8,9],[-7,6],[-18,22],[-12,15],[-14,12],[-26,24],[-13,9],[-14,9],[-13,10],[-9,10],[-11,7],[-40,29],[-15,12],[-3,3],[-9,5],[-12,5],[-13,0],[-10,8],[-4,9],[-2,17],[-16,13],[-6,-1],[-3,-3],[-3,0],[-4,4],[-3,2],[-3,9],[1,10],[2,2],[0,6],[-4,4],[4,6],[4,-2],[3,-13],[5,-1],[3,0],[2,8],[-6,12],[1,6],[0,-5],[7,-13],[4,-2],[0,-2],[21,-9],[9,13],[1,5],[5,4],[15,23],[1,0],[12,-12],[6,-4],[1,-4],[4,0],[4,-4],[14,1],[5,1],[8,9],[8,12],[5,9],[4,11],[6,35],[-1,10],[4,25],[0,13],[3,14],[3,14],[2,12],[5,3],[2,10],[-1,6],[-2,4],[1,3],[11,0],[5,1],[5,4],[6,17],[4,6],[11,12],[9,7],[6,0],[12,-4],[7,2],[8,0],[10,-5],[17,-1],[24,-3],[7,-3],[5,0],[9,2],[31,11],[4,-4],[7,-3],[7,3],[4,0],[22,-3],[7,-3],[6,1],[6,2],[7,5],[18,15],[6,6],[11,13],[13,17],[26,40],[7,10],[3,9],[3,5],[8,7],[5,5],[13,21],[17,27],[8,19],[9,16],[3,-1],[8,16],[8,23],[4,13],[8,24],[4,13],[1,7],[3,16],[2,14],[5,22],[0,20],[0,15],[0,23],[1,12],[1,3],[4,5],[5,2],[4,0],[6,-2],[7,5],[21,7],[2,0],[6,-6],[10,6],[5,1],[5,-2],[7,0],[6,-13],[-3,-3],[0,-7],[-4,-9],[1,-16],[2,-18],[5,-3],[1,-3],[0,-10],[-3,-2],[-1,-5],[-2,-2],[9,-11],[2,3],[3,-2],[-1,-3],[5,-4],[8,-2],[11,1],[4,-3],[26,-1],[6,-3],[6,-7],[4,0],[3,-9],[-1,-8],[-2,0],[0,-4],[-4,-11],[3,2],[2,-4],[-6,-12],[-2,1],[-1,-5],[-8,-14],[-5,-6],[-6,-13],[-4,-1],[-4,-5],[-8,-15],[-6,-9],[-6,-19],[-7,-8],[6,-5],[-3,-7],[-1,-5],[7,-3],[0,-17],[3,-13],[0,-9],[0,-18],[-2,-10],[-2,-8],[-1,-11],[-3,-7],[-5,-5],[-5,-3],[-8,0],[-4,-4],[-7,-2],[-2,2],[-6,-2],[-1,-1],[-7,-3],[-5,7],[-8,-5],[-4,6],[-4,-2],[2,-5],[-2,-6],[4,-11],[-3,-2],[0,4],[-1,6],[-2,0],[-6,-6],[1,-12],[5,-5],[2,-5],[16,-24],[5,-9],[0,-7],[-9,-29],[-7,-4],[-9,-4],[-5,-4],[-2,-14],[2,-8],[-1,-10],[2,-18],[17,19],[14,10],[11,14],[8,12],[9,9],[8,0],[3,1],[10,1],[4,-4],[5,-12],[2,-7],[4,-8],[2,-10],[3,-12],[1,-7],[5,-17],[9,-14],[5,-16],[2,-11],[-3,-8],[1,-6],[1,-7],[2,-4],[6,-6],[11,-1],[22,6],[11,5],[2,2],[3,-2],[4,-5],[12,-9],[1,-6],[0,-9],[3,-3],[5,0],[2,-5],[4,0],[4,10],[5,5],[7,-3],[3,-6],[2,-14],[0,-11],[-3,-7],[-7,-8],[-5,-2],[-5,0],[-9,5],[-2,0],[-1,-4],[2,-16],[0,-8],[1,-12],[0,-6],[3,-13],[-5,-14],[-3,-11],[-5,-3],[-3,-6],[-2,-8],[-4,-6],[2,-3],[2,6],[9,11],[6,6],[8,6],[7,8],[4,11],[8,11],[1,5],[2,2],[1,4],[8,10],[3,10],[3,12],[5,5],[0,8],[4,0]],[[5979,650],[8,25],[1,13],[-1,6],[-3,5],[-4,3],[-9,-1],[-11,-6],[-3,-2],[-8,-10],[-7,-10],[-7,-5],[-13,-4],[-4,-1],[-5,1],[-6,5],[-7,9],[-16,30],[-5,10],[-9,20],[-5,13],[-9,29],[-7,16],[-1,8],[0,9],[1,4],[7,16],[10,19],[14,28],[11,24],[1,6],[0,12],[-2,17],[-2,8],[-3,15],[-1,13],[2,13],[7,27],[3,11],[5,14],[1,14],[0,16],[-1,18],[-1,5],[-8,18],[-5,8],[-4,5],[-9,9],[-4,3],[-9,9],[-7,12],[-4,22],[-1,12],[-2,10],[-4,9],[-7,11],[7,6],[4,7],[4,11],[5,14],[10,33],[4,14],[4,21],[0,14],[-3,14],[-4,7],[-5,7],[-16,15],[-10,7],[-21,17],[-33,26],[-14,11],[-20,16],[-6,8],[-6,17]],[[5736,1486],[25,18],[27,20],[38,25],[19,13],[37,26]],[[6061,1709],[63,45],[8,6],[47,37],[12,16],[35,48],[61,91],[56,84],[54,78],[14,22],[110,192],[13,21],[32,55],[37,64],[46,81],[48,82],[15,26],[23,39],[17,32],[5,9],[13,21],[10,14],[15,16],[15,13],[19,14],[21,10],[33,10],[58,12],[9,2],[23,4],[86,17],[25,5]],[[7084,2875],[138,27],[81,17],[6,1],[26,7],[18,9],[27,15],[23,16],[22,17],[51,55],[87,90],[111,118],[31,27],[14,12],[20,13],[27,13],[29,12],[21,6],[31,8],[15,4],[57,13],[76,18],[91,22],[79,18],[12,3]],[[8177,3416],[1,-20],[3,-41],[1,-14],[1,-7],[4,-7],[3,-2],[11,-7],[7,-8],[5,-18],[-2,-13],[-10,-28],[-4,-2],[-40,-39],[-5,-5],[-7,-15],[-1,-12],[2,-16],[0,-12],[-3,-11],[-4,-7],[-5,-6],[-21,-13],[-4,-4],[-1,-4],[0,-5],[1,-7],[6,-13],[7,-10],[0,-5],[-1,-11],[-3,-4],[-14,-15],[-11,-9],[-7,-2],[-18,1],[-24,21],[-6,-5],[-10,-19],[-9,-23],[-1,-6],[4,-14],[4,-5],[-2,-11],[-5,-23],[-13,-15],[-1,-6],[-5,-12],[-7,-14],[-6,-8],[-4,-8],[1,-9],[-5,-2],[-5,-9],[-7,-26],[-5,-19],[4,-10],[5,-3],[-1,-5],[4,-3],[-10,-35],[-9,-41],[-4,-15],[-4,-9],[-1,-7],[-6,-17],[-5,-15],[1,-3],[-5,-17],[0,-5],[6,-8],[8,-36],[0,-5],[19,3],[8,-4],[12,-9],[25,-20],[-8,-15],[3,-1],[10,-10],[6,-6],[3,-5],[10,-11],[8,-7],[8,-5],[19,7],[4,1],[7,-29],[-82,-30],[4,-18],[9,-39],[6,-15]],[[8016,2365],[-16,-9],[-15,-6],[-22,-12],[-12,-8],[-10,-11],[-4,-7],[-9,-7],[-7,-14],[-4,-10],[0,-9],[-2,-24],[-10,-7],[-9,-1],[-2,-7],[2,-9],[0,-11],[-7,-4],[-5,5],[-5,6],[-15,12],[-15,5],[-19,10],[-21,4],[-15,-3],[-39,-11],[-14,-6],[-10,1],[-17,-2],[-13,-7],[-15,-4],[-35,-19],[-33,-25],[-15,-10],[-10,-7],[-20,-12],[-33,-30],[-12,-14],[-15,-13],[-25,-18],[-37,-31],[-80,-54],[-30,-19],[-37,-35],[-18,-18],[-16,-16],[-17,-17],[-19,-19],[-13,-14],[-11,-16],[-8,-10],[-42,-29],[-13,-13],[-25,-21],[-15,-17],[-20,-14],[-34,-32],[-29,-21],[-31,-29],[-44,-37],[-42,-46],[-41,-31],[-22,-19],[-27,-18],[-9,-8],[-2,-2],[-42,-33],[-14,-12],[-8,-10],[-4,-1],[-2,-7],[-6,-7],[-3,2],[-5,0],[-2,-2],[-6,-1],[-4,-2],[-9,-2],[-2,2],[-9,3],[2,3],[-2,3],[-8,0],[-10,-4],[-17,-13],[-10,-10],[-16,-13],[-39,-37],[-16,-12],[-34,-31],[-40,-41],[-39,-46],[-43,-49],[-40,-41],[-31,-46],[-12,-18],[-13,-19],[-29,-34],[-15,-19],[-13,-18],[-18,-27],[-10,-17],[-23,-35],[-31,-52],[-16,-36],[-2,-4],[-18,-30],[2,-3],[0,-3],[-4,-7],[1,-8],[-1,-1],[1,-9],[-7,-2],[-6,4],[-3,-2],[5,-10],[-1,-6],[4,-6],[-5,-13],[0,-5],[5,-5],[-4,-5],[-5,0],[-7,-5],[-6,2],[-1,5],[-5,2],[-5,-1],[-4,-3],[-6,-1],[-7,-3],[-10,-7],[-5,2],[-7,-4],[-2,-5],[-4,-3],[-9,5],[-4,3],[-2,7],[-9,1],[-6,-2],[-7,-5],[-6,-6],[-7,-6],[-4,-6],[-6,-5],[-9,0],[-9,-4],[-3,1]],[[6794,4921],[4,-15],[4,-20],[1,-9],[1,-24],[0,-11],[0,-22],[2,-25],[-1,-7],[-5,-12],[-5,-3]],[[6680,4159],[8,-18],[4,-8],[7,-5],[6,-13],[7,-22],[2,-18],[0,-10],[-6,-35],[-13,-63],[-2,-10],[-6,-15],[-6,-11],[-28,-48],[-7,-18],[-12,-37],[-5,-14],[-7,-13],[-12,-16],[-9,-7],[-7,-5],[-13,-6],[-13,-4],[-9,-4],[-13,-9],[-7,-6],[-3,-3],[-15,-16],[-9,-7],[-9,-5],[-17,-7],[-18,-8],[-9,-7],[-5,-5],[-8,-10],[-8,-13]],[[6438,3663],[-4,-9],[-8,-21],[-6,-15],[-11,-29],[-9,-24],[-2,-7],[-5,-24],[-3,-12]],[[6390,3522],[-9,4],[-18,-2],[4,-14],[0,-3],[-5,-12],[-3,-5],[-4,-17],[-3,-6],[-8,-8],[-7,-4],[-9,-8],[-9,-4],[-8,16],[-7,10],[-5,2],[-10,-4],[-14,0],[-8,-3],[-7,1],[-5,3],[1,6],[-8,5],[-2,3],[-13,7],[-8,-2],[-5,-6],[-9,-8],[-11,-1],[-6,-2],[-8,-7],[-4,5],[-13,5],[-5,5],[-7,15],[-7,24],[-1,0],[-11,4],[-8,8],[-6,12],[-5,6],[-9,13],[-5,5],[-10,6],[-8,13],[-9,18],[-6,-33],[0,-13],[4,-27],[5,-7],[5,-2],[0,-9],[-1,-1],[5,-10],[-2,-10],[-9,-11],[-1,-11],[-7,-17],[-6,-9],[-10,-13],[-1,-7],[2,-8],[3,-11],[7,-17],[7,-22],[9,-25],[6,-27],[1,-15],[-8,-1],[-12,-4],[-12,-6],[-7,-5],[-17,-6],[-31,-6],[-11,-3],[-15,-2],[-9,0],[-8,2]],[[5294,2909],[3,7],[-4,7],[-11,1],[-10,3],[-10,11],[-2,11],[0,18],[2,10],[3,8],[13,32],[1,4],[-1,12],[-2,18],[-2,3],[2,10],[3,5],[-10,4],[-7,2],[-1,4],[1,7],[-1,0],[2,7],[3,15],[7,21],[1,5],[2,5],[1,8]],[[8177,3416],[16,4],[60,15],[95,21],[89,22],[46,11],[15,4],[-5,29],[8,42],[12,47],[3,15],[5,13],[7,6],[-3,5],[-5,-2],[-4,5],[-9,-4],[-8,-3],[-5,-3],[-2,-8],[-7,-5],[-3,12],[-18,20],[-16,13],[-2,8],[-5,3],[4,7],[-5,10],[-12,9],[-13,11],[-8,11],[-9,1],[-14,-2],[-8,-4],[-1,12],[7,25],[6,-2],[7,1],[5,3],[5,9],[2,8],[0,7],[-2,6],[-4,8],[-21,32],[-16,26],[-8,0],[-20,9],[-32,14],[-16,4],[-9,3],[-11,4],[-18,10],[-8,1],[-7,-1],[-9,-7],[-14,-19],[-3,-4],[-9,-6],[-19,-4],[-11,-2],[-8,-1],[-6,1],[-13,6],[-10,7],[-9,4],[-10,-1],[-11,-5],[-7,-1],[-9,1],[-7,3],[-24,11],[-14,5],[-10,6],[-21,9],[-9,5],[-9,7],[-5,6],[-8,16],[-1,11],[0,7],[3,13],[0,9],[0,5],[-6,11],[0,14],[-3,7],[-5,6],[-9,9],[-5,4],[-22,12],[-7,7],[-12,28],[-4,6],[-4,2],[-4,-1],[-2,-4],[0,-6],[3,-8],[1,-8],[-1,-5],[-3,-5],[-17,-15],[-6,-1],[-3,3],[-5,8],[-5,5],[-4,2],[-6,-1],[-6,-5],[-8,-13],[-16,-18],[-33,-35],[-9,-7],[-32,-16],[-7,-4],[-7,-9],[-5,-9],[-6,-14],[-4,-5],[-5,-1],[-8,2],[-6,4],[-7,7],[0,15],[-2,11],[0,7],[2,6],[0,1],[5,1],[5,10],[3,4],[7,4],[2,8],[6,7],[7,16],[0,3],[4,2],[3,17],[3,3],[0,2],[4,3],[2,6],[3,0],[8,7],[11,5],[11,4],[27,14],[17,6],[15,9],[12,8],[18,18],[3,5],[-1,11],[0,9],[1,0],[4,11],[11,9],[4,8],[0,11],[1,4],[6,-3],[13,-4],[4,0],[5,-2],[2,-11],[3,-5],[11,-1],[5,-4],[10,-3],[10,1],[7,0],[5,-3],[5,-7],[6,-3],[15,-4],[32,-15],[7,-2],[7,-1],[7,1],[30,6],[14,5],[6,3],[8,6],[5,1],[7,0],[8,6],[4,0],[12,-2],[18,-8],[9,-6],[9,0],[10,-8],[7,-2],[14,-5],[14,-8],[15,-4],[25,-11],[20,-7],[14,-8],[37,-15],[9,-3],[7,0],[40,-9],[22,2],[8,-1],[5,0],[6,-3],[2,0],[18,1],[48,4],[28,2],[0,-42],[9,3],[41,13],[4,3],[9,11],[-42,34],[-35,29],[-7,5],[-22,12],[-36,14],[-40,9],[-17,5],[-14,6],[-9,6],[-10,8],[-8,9],[-13,16],[-6,10],[-5,9],[-9,25],[-5,25],[-2,47],[0,19],[-2,114],[-1,63],[-1,62],[-2,93],[-1,63],[0,30],[-1,88],[-1,40],[-1,69],[4,176],[3,116],[0,3],[1,48],[1,5],[1,38],[-1,6],[3,92],[2,52],[2,77],[1,43],[2,71],[2,72],[1,12],[2,19],[3,15],[3,10],[17,47],[30,85],[4,13],[3,20],[-1,18],[-3,68],[-5,120],[-4,80],[-3,57],[-2,18],[-4,20],[-6,25],[-16,31],[-6,9],[57,71],[69,117],[45,75]],[[8507,6699],[65,-90],[36,-129],[3,-43],[25,-226],[8,-230],[-63,-301],[-5,-158],[-5,-190],[-9,-331],[2,-145],[6,-370],[-2,-25],[57,-45],[67,-54],[16,-12],[6,-5],[28,-23],[89,-70],[22,-26],[22,-37],[18,-40],[3,-10],[-7,-7],[6,-14],[5,-13],[37,-48],[13,-25],[-1,-3],[5,-7],[8,-6],[43,34],[19,93],[15,1],[5,1],[10,1],[0,-2],[37,-7],[2,0],[24,9],[32,-29],[31,21],[34,6],[7,35],[8,19],[22,27],[24,38],[22,24],[26,20],[26,40],[16,-12],[56,-99],[61,23],[73,0],[40,-64],[19,-14],[41,-29],[9,-76],[183,47],[12,-7],[9,-9],[77,20],[4,-3],[16,-95],[-3,-4],[-43,-12],[8,-16],[19,-43],[32,-49],[21,-33],[-9,-13],[-2,-7],[-13,-19],[-3,-7],[-6,-8],[-11,-11],[-10,-13],[-8,-12],[-8,-17],[-8,-10],[-9,-21],[-7,-10],[-5,-9],[-11,-22],[-5,-7],[-4,-7],[-11,-12],[-5,-4],[-7,-9],[-1,-5],[-8,-13],[-4,-5],[1,-2],[-4,-5],[-2,-7],[-3,-4],[-4,-9],[-7,-16],[-1,-4],[-4,-5],[-1,-6],[-5,-5],[-1,-6],[-4,0],[0,-6],[-4,-4],[-2,-5],[-3,-4],[-2,-5],[-3,0],[-1,-4],[-2,-1],[-1,-5],[-7,-8],[-9,-19],[-16,-29],[-2,-4],[-7,-12],[-7,-9],[-1,-3],[-7,-11],[-3,-4],[-3,-5],[-4,-6],[-14,-31],[-4,-17],[-4,-6],[-1,-5],[-4,-2],[0,-6],[-4,-7],[-7,-7],[-3,-4],[-13,-33],[-3,-1],[-7,-8],[-5,-11],[-4,-3],[-6,-8],[-5,-10],[-6,-10],[-3,-3],[-7,-11],[-2,-2],[0,-4],[-4,-1],[-8,-11],[-7,-7],[-8,-7],[-15,-15],[-6,-10],[-5,-5],[-10,-6],[-6,-7],[-9,-12],[-5,-8],[-6,-7],[-1,-4],[-14,-13],[-4,-2],[-3,-5],[-13,-11],[-4,-2],[-2,-3],[-4,-2],[-2,-4],[-4,-1],[-2,-5],[-4,-5],[-1,-3],[-9,-8],[-2,-4],[-13,-15],[-8,-15],[-8,-9],[-2,-4],[-6,-5],[-1,-3],[-9,-9],[-19,-26],[-6,-4],[-7,-10],[-5,-11],[-6,-10],[-2,-7],[-7,-11],[-9,-11],[-11,-10],[-6,-5],[-9,-9],[-4,-7],[-3,-10],[-1,-8],[-4,-7],[-3,-3],[-6,-5],[-12,-6],[-10,-13],[-14,-20],[-6,-7],[-10,-13],[-9,-10],[-6,-5],[-3,-6],[-4,-4],[-8,-18],[-9,-9],[-5,-10],[-3,-3],[-8,-6],[-5,-5],[0,-2],[-10,-19],[-9,-11],[-2,-6],[-6,-3],[-8,-7],[-4,-2],[-5,-10],[-6,-12],[-3,-1],[-7,-6],[-7,1],[-6,-3],[-2,3],[-5,1],[-9,0],[-5,-2],[-6,-7],[-7,-2],[-4,-3],[-11,-11],[-8,-1],[0,-4],[-4,0],[-1,-6],[-3,-1],[-7,-10],[-11,-11],[-9,-5],[-2,-4],[-6,-4],[-7,-6],[-12,-14],[-10,-15],[-5,-5],[-6,-7],[-8,-9],[-3,-4],[-3,-3],[-3,-6],[-2,-1],[-2,-5],[-2,-2],[-9,-13],[-3,-6],[-7,-9],[-2,-4],[-6,-6],[-4,-10],[-9,-8],[-2,-4],[-4,-3],[-3,-4],[-6,1],[-3,4],[-3,-3],[-12,-6],[-7,-6],[-12,-14],[-5,-2],[-4,-3],[-4,-7],[1,-7],[-2,1],[-4,-4],[-4,0],[-7,-4],[-6,0],[-3,-4],[-8,-1],[-2,-4],[-1,-9],[-3,0],[-4,3],[-11,-1],[-13,-11],[-4,-5],[-11,-15],[-8,-4],[-5,-5],[-2,-5],[-7,-5],[-6,1],[-3,-2],[-13,0],[-4,-1],[-8,-8],[-4,-7],[-1,-3],[-7,-7],[-1,-6],[-3,-1],[-4,-6],[-2,2],[-6,-2],[-8,-9],[3,-2],[-2,-4],[-7,-2],[-7,2],[-4,0],[-2,-4],[-5,2],[-1,-5],[-4,-3],[-5,-1],[-4,-5],[-6,-9],[-3,-10],[-3,-3],[-2,-7],[-5,-3],[-5,-4],[-10,-2],[-5,-3],[-13,0],[-2,-3],[0,4],[-10,0],[-6,4],[-5,0],[-6,-2],[-5,4],[-3,5],[-1,4],[-3,2],[-16,1],[-8,-6],[-9,1],[-7,4],[-7,0],[-11,6],[-13,3],[-24,2],[-5,2],[-13,20],[-14,22],[-20,24],[-22,16],[-6,-2],[-5,6],[0,6],[7,2],[0,5],[-3,7],[-3,-1],[-4,9],[-8,3],[-5,-1],[-1,-8],[-3,1],[-6,4],[1,4],[-4,12],[-3,4],[-5,14],[1,7],[0,4],[-3,5],[-4,1],[-6,0],[-3,7],[-1,9],[-3,2],[-3,-1],[-4,3],[-1,5],[-3,5],[-7,6],[-8,1],[-8,-2],[-8,-6],[-8,-10],[-11,0],[-11,4],[-23,-7],[-10,-4],[-10,-1],[-1,1],[-16,5],[-15,1],[-11,-2],[-13,-4],[-8,-2],[-22,-10],[-26,-8],[-25,-7],[-13,-10],[-2,-6],[-4,-1],[-2,-3],[-6,-1],[-7,6],[1,5],[2,0],[-4,5],[-5,1],[-8,-3]],[[5979,650],[-2,0],[-3,5],[-6,1],[-19,-27],[-11,-14],[-11,-17],[-14,-18],[-27,-37],[-2,-4],[4,-6],[0,-4],[-5,-3],[2,-2],[-6,-5],[-9,2],[-5,-4],[-2,-5],[3,-9],[0,-4],[-3,-5],[-5,-2],[-3,0],[-7,-5],[-4,-7],[-10,-4],[-5,-1],[-5,3],[-5,7],[-5,3],[-5,-2],[-5,-9],[-3,-8],[-6,-10],[-5,-10],[-10,-7],[-10,-7],[-6,-8],[-14,-27],[-9,-9],[-10,-5],[-17,3],[-9,1],[-6,-4],[-10,3],[-12,0],[-15,-2],[-11,-4],[-11,-2],[-11,-5],[-7,-5],[-15,-14],[-3,-9],[-7,-6],[-15,-20],[-9,-10],[-9,-14],[-9,-2],[-15,-8],[-8,-6],[-11,-4],[-27,-16],[-13,-10],[-6,-6],[-12,-11],[-17,-12],[-19,-12],[-13,-5],[-16,-13]],[[5410,1357],[8,13],[8,5],[20,5],[5,3],[49,44],[0,2],[20,19],[9,9],[8,12],[18,34],[6,8],[7,7],[6,6],[15,7],[18,0],[37,-5],[15,-3],[21,-3],[22,-5],[22,-7],[3,-3],[4,-6],[5,-13]],[[6390,3522],[-4,-18],[-1,-5],[-3,-14],[-6,-13],[-7,-12],[-10,-14],[-9,-15],[-8,-17],[-2,-7],[-4,-20],[-2,-24],[-1,-30],[-1,-19],[-1,-35],[1,-13],[2,-9],[6,-25],[27,9],[1,-8],[2,-4],[6,-4],[6,1],[18,6],[11,-28],[-23,-5],[8,-16],[-26,-15],[-23,-42],[-10,-23],[-6,-39],[-11,9],[-11,6],[-39,19],[-11,-18],[-1,-9],[-7,-23],[-6,-15],[-4,-12],[-4,-10],[-5,-10],[-6,-9],[-4,-1],[-4,7],[-3,-2],[-10,-2],[-5,-5],[-6,-13],[-5,-12],[5,-4],[9,-7],[15,-18],[12,-12],[10,-12],[15,-27],[4,-15],[4,-6],[22,-23],[7,-6],[6,-5],[9,-4],[12,-2],[9,1],[27,7],[13,1],[10,0],[6,-2],[11,-3],[-7,-19],[19,-28],[4,-8],[1,-5],[0,-9],[-2,-8],[-6,-8],[-4,-3],[-4,-5],[-6,2],[-10,0],[-10,-3],[-8,-1],[-8,-4],[-6,-7],[-7,-2],[-6,-6],[4,-10],[-22,-14],[-8,-2],[-5,-4],[0,-7],[-5,-5],[-2,-4],[2,-8],[-3,-7],[-5,6],[0,-6],[-4,-3],[-5,-13],[-3,-3],[-10,-8],[-1,-5],[-3,-6],[-4,-16],[-3,-7],[-13,-11],[-6,-6],[-4,-7],[-8,-9],[-8,-6],[-6,1],[-3,-1],[-2,-7],[0,-8],[1,-3],[-1,-6],[-3,-5],[-3,-9],[2,-11],[15,-9],[13,-6],[4,-5],[9,5],[5,10],[4,-22],[-7,-42],[0,-7],[-3,-16],[-1,-8],[-2,-13],[-4,-5],[-4,-4],[-2,-4],[0,-10],[-14,4],[-12,1],[-7,2],[-1,-9],[-8,-2],[-10,-1],[-9,1],[-10,4],[-6,1],[-8,6],[-12,3],[-3,0],[-6,-2],[-4,0],[-3,7],[-4,4],[-2,7],[-1,8],[-3,14],[-2,14],[3,4],[-2,2],[-11,-10],[-15,-20],[-2,-6],[-34,-43],[-14,-17],[-5,-6],[-14,-13],[-17,-23],[-27,18],[-20,10],[1,8],[-2,5],[-4,4],[4,6],[-4,5],[-8,10],[-9,12],[-5,7],[-3,4],[-2,14],[-5,3],[-4,-11],[-3,1],[-5,-4],[0,-13],[8,-7],[-4,-3],[-2,1],[-7,7],[-4,1],[-14,-1],[-1,3],[-5,1],[-6,-3],[-8,-7],[-8,-6],[-4,-1],[3,-7],[-4,-4],[-8,-12],[-3,-7],[-10,2]],[[4751,2814],[-8,0],[-7,3],[-8,1],[-6,0],[-6,-5]],[[4814,3231],[-5,4],[-2,6],[3,2],[2,5],[-2,8],[1,6],[-3,4],[-1,7],[0,10],[-5,7],[-5,0],[-11,-9],[-3,-2],[-8,-1],[-8,-2],[-11,6],[-5,5],[-5,8],[0,8],[4,7],[8,5],[8,10],[3,6],[-1,9],[-1,4],[-4,3],[-2,4],[0,-4],[-7,4],[-10,-2],[-8,1],[-8,4],[-4,6],[-5,17],[-6,10],[-7,14],[-9,7],[-3,1],[-11,7],[-9,4],[-3,4],[-1,8],[8,11],[8,9],[-2,1],[-4,-2],[-7,-7],[0,5],[6,7],[11,6],[-2,4],[-3,2],[6,1],[8,6],[-9,-3],[-1,2],[5,3],[10,9],[9,5],[2,3],[-3,5],[10,8],[-1,5],[34,29],[7,6],[5,-2],[3,-5],[10,-1],[4,2],[4,0],[24,-2],[10,-4],[39,-26],[6,-3],[8,2],[12,7],[13,10],[11,14],[2,3],[10,7],[4,4],[-5,2],[3,8],[6,3],[1,8],[3,2],[1,7],[-5,3],[-1,2],[3,13],[1,8],[-2,19],[-2,6],[-1,11],[3,8],[1,6],[-2,11],[0,13],[-2,10],[1,9],[-4,6],[1,13],[6,21],[1,5],[1,19],[4,9],[4,6],[9,11],[6,12],[2,11],[1,10],[3,10],[13,12],[3,6],[1,9],[0,10],[-3,9],[-4,10],[-3,7],[-1,17],[-3,10],[-7,10],[-18,15],[1,4],[3,0],[5,-4],[9,-2],[6,-3],[9,1],[4,3],[13,14],[8,12],[7,14],[8,17]],[[5015,4006],[18,-9],[33,-12],[8,-3],[-6,-25],[-21,-89],[-9,-38],[-4,-17],[-9,-38],[-3,-12],[-6,-26],[-7,-31],[-2,-26],[0,-21],[16,-3],[14,5],[4,2],[7,9],[6,3],[15,4],[4,-2],[4,-5],[1,-9],[-2,-19],[3,-7],[9,1],[14,0],[11,-3],[15,7],[9,4],[9,-2],[7,-1],[12,-10],[11,-1],[6,1],[13,9],[11,11],[3,2],[8,0],[4,-2],[8,-6],[2,-4],[3,1]],[[6438,3663],[12,-7],[8,-1],[7,0],[11,5],[13,6],[10,2],[4,-16],[61,-9],[14,-10],[1,-2],[24,-68],[-1,-5],[5,-5],[27,-8],[17,0],[26,-15],[10,-1],[5,3],[10,2],[11,-1],[8,-1],[11,5],[7,3],[11,3],[9,-1],[8,-5],[9,-9],[12,-12],[8,-10],[6,-10],[14,-29],[6,-12],[13,-26],[6,-13],[2,-8],[3,-17],[3,-7],[15,-10],[15,-8],[13,-10],[9,-8],[33,-42],[12,-14],[11,-16],[9,-13],[21,-20],[10,-8],[11,-18],[5,-12],[3,-11],[1,-10],[0,-13],[-2,-18],[-1,-16],[-3,-25],[-3,-28],[-3,-13],[-2,-15],[2,-8],[2,-7],[4,-7],[4,-3],[4,-3],[18,-5],[5,-2],[8,-8],[3,-11],[4,-7],[5,-6],[5,-4],[17,-6],[-6,-19],[-2,-15],[-1,-4],[-1,-10],[10,-56]],[[5015,4006],[0,2],[3,10],[2,4],[4,10],[6,5],[2,-4],[3,5],[4,2],[8,0],[1,-2],[5,1],[4,-4],[5,4],[4,10],[4,7],[-7,0],[3,3],[-13,20],[1,4],[-3,0],[-3,5],[-1,6],[-1,12],[2,18],[-2,1],[0,10],[0,13],[2,14],[4,5],[1,9],[3,3],[5,11],[8,13],[1,3],[-3,6],[1,3],[6,-2],[5,-8],[7,-7],[5,-5],[2,-9],[14,-10],[4,-2],[10,-1],[0,2],[-16,5],[-9,9],[-5,13],[3,20],[2,9],[-2,11],[-6,6],[-5,-2],[-1,-3],[-3,-2],[-5,3],[-6,11],[2,9],[6,10],[-5,3],[-22,-6],[-10,4],[-3,1],[-7,4],[-6,1],[-2,3],[-4,2],[-7,-2],[-10,-10],[-6,-10],[-5,-2],[0,-3],[-5,-5],[-9,-13],[-1,-4],[-2,-1],[-4,-10],[0,-4],[3,-6],[2,-3],[0,-7],[0,-11],[3,-8],[4,-1],[5,-8],[4,-14],[3,-2],[1,-4],[-2,-6],[-4,-8],[-3,-6],[-4,1],[0,-3],[-3,-5],[-5,-4],[-4,0],[-7,2],[-9,-2],[-9,-8],[-8,-4],[1,-2],[6,1],[0,-1],[-7,-11],[-7,-6],[-4,1],[-5,-1],[-5,-4],[-3,3],[-10,5],[-6,0],[-10,-3],[-15,-9],[-6,-2],[-5,0],[-1,-3],[-21,-7],[-8,-7],[-2,-3],[0,-7],[-2,-8],[0,-7],[8,0],[4,-7],[1,-7],[-3,-5],[-7,2],[-11,10],[-7,5],[-5,5],[-11,7],[-7,5],[-8,9],[-16,11],[-4,5],[-5,6],[-10,18],[-5,11],[-14,61],[-12,-3],[-3,15],[5,2],[-1,1],[-7,28],[0,2],[6,3],[-3,17],[-7,21],[0,8],[-4,13],[-4,20],[0,14],[-1,2],[2,15],[0,15],[1,8],[-3,5],[1,5],[3,5],[2,2],[4,5],[6,19],[0,9],[4,8],[2,11],[2,5],[4,17],[5,6],[5,19],[2,2],[6,16],[0,7],[3,9],[3,5],[1,8],[4,-1],[1,2],[3,9],[4,6],[5,15],[1,10],[4,15],[1,6],[4,12],[4,9],[3,13],[13,29],[11,21],[-2,2],[13,26],[1,4],[3,12],[2,11],[5,11],[3,12],[3,0],[5,36],[3,31],[2,27],[3,18],[4,7],[3,2],[4,-1],[7,1],[4,2],[7,8],[16,15],[11,12],[2,12],[2,8],[6,12],[4,11],[1,6],[4,9],[11,7],[9,10],[8,0],[9,4],[8,2],[13,6],[5,4],[11,8],[7,5],[14,20],[3,8],[6,11],[6,13],[6,20],[5,8],[3,9],[7,15],[4,12],[5,19],[4,24],[2,21],[1,15],[-1,30],[0,26],[-3,8],[1,9],[1,3],[1,11],[1,25],[0,4],[-3,6],[-1,5],[3,6],[3,8],[2,8],[0,11],[-1,19],[-3,21],[-5,13],[-4,4],[0,6],[3,7],[0,6],[-4,13],[-2,9],[-6,3],[-1,6],[0,6],[3,4],[-1,12],[-4,26],[0,7],[1,9],[1,12],[-2,11],[-4,23],[-4,32],[-10,38],[-5,32],[-3,12],[0,7],[1,16],[-3,2],[-5,-2],[-4,1],[-2,3],[-1,9],[-3,3],[-3,-7],[-1,1],[11,20],[3,8],[0,4],[-3,3],[3,4],[5,2],[2,-4],[3,2],[5,3],[12,-4],[11,1],[6,4],[9,14],[11,12],[2,4],[2,6],[6,2],[14,18],[9,15],[5,11],[4,11]],[[4413,2446],[-1,2],[-23,-1],[-5,2],[-9,1],[0,3],[4,1],[2,3],[-1,6],[-2,36],[-1,18],[-1,9],[0,7],[0,7],[0,8],[4,2],[3,-2],[-2,-4],[0,-8],[5,-4],[9,14],[-1,13],[-5,7],[2,12],[-7,27],[-9,29],[-13,42],[-17,42],[-14,37],[-13,23],[-16,25],[-21,36],[-6,9],[-10,18],[-3,12],[-3,6],[-18,20],[-11,14],[-10,15],[-5,6]],[[7099,5230],[5,0],[8,8],[4,5],[8,8],[2,3],[6,2],[8,3],[3,-2],[2,-7],[7,3],[5,-3],[10,0],[8,1],[33,11],[12,2],[3,7],[4,2],[-2,17],[1,11],[6,20],[3,6],[6,1],[8,-3],[2,2],[1,7],[-3,11],[-5,35],[-6,20],[0,13],[-1,5],[-4,5],[-6,1],[-1,3],[1,5],[3,3],[6,4],[12,11],[14,14],[12,17],[4,4],[10,6],[4,1],[8,6],[6,9],[3,8],[1,7],[-1,15],[-2,9],[-3,10],[-5,19],[-11,22],[-10,18],[-5,18],[-3,14],[1,7],[2,8],[9,11],[1,4],[7,9],[4,7],[2,8],[4,18],[2,3],[12,0],[8,-2],[12,0],[5,5],[5,1],[16,2],[5,2],[7,3],[8,5],[18,19],[22,35],[16,28],[12,14],[16,25],[18,26],[15,4],[16,-9],[18,-3],[16,2],[13,13],[10,27],[5,37],[-2,48],[-5,40],[-6,26],[-12,14],[-15,16],[-13,10],[-6,17],[-6,25],[-6,19],[-9,19],[-1,20],[2,29],[-3,23],[-2,23],[4,18],[12,16],[15,11],[53,62],[12,15],[8,18],[0,24],[-4,23],[8,31],[8,14],[5,20],[2,25],[1,29],[8,37],[11,21],[16,13],[15,8],[20,11],[21,16],[11,11],[6,17],[16,19],[23,17],[19,15],[13,19],[8,24],[0,39],[1,21],[7,19],[15,7],[14,6],[17,9],[10,14],[7,18],[7,30],[7,37],[0,18],[1,46],[11,-3],[14,1],[8,4],[11,-1],[11,-6],[18,-12],[14,-15],[42,-28],[10,-3],[25,-12],[26,-24],[8,-9],[7,-9],[2,-9],[4,-8],[6,-10],[12,-8],[8,-11],[7,-2],[16,6],[16,5],[21,10],[18,8],[16,3],[7,-3],[9,-8],[10,-12],[9,-15],[6,-6],[6,-5],[8,-4],[18,-13],[10,-11],[20,-19],[22,-16],[10,-8],[26,-31],[78,-42],[49,-58]]]}
+{"type":"Topology","bbox":[-38.65748489999993,-13.017326199999957,-38.304332699999975,-12.742395399999964],"transform":{"scale":[0.0009244821989527593,0.0007197141361256356],"translate":[-38.65748489999993,-13.017326199999957]},"objects":{"municipalityZones":{"type":"GeometryCollection","geometries":[{"type":"MultiPolygon","arcs":[[[0,1,2,3]]],"properties":{"municipalitySlug":"salvador-ze-1","name":"Salvador — ZE 1","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[4,5,6,-3]]],"properties":{"municipalitySlug":"salvador-ze-2","name":"Salvador — ZE 2","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[7,8,9,10,11]]],"properties":{"municipalitySlug":"salvador-ze-3","name":"Salvador — ZE 3","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[12,13,14]],[[15]],[[16]],[[17]],[[18]],[[19]],[[20]]],"properties":{"municipalitySlug":"salvador-ze-4","name":"Salvador — ZE 4","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[9,21,22,23,24,25,26,27,-11]]],"properties":{"municipalitySlug":"salvador-ze-5","name":"Salvador — ZE 5","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-2,28,29,30,31,32,-5]]],"properties":{"municipalitySlug":"salvador-ze-6","name":"Salvador — ZE 6","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-28,-29,-1,33,34,35,-12]]],"properties":{"municipalitySlug":"salvador-ze-7","name":"Salvador — ZE 7","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[36,37,38,39,-14,40]],[[41,42]]],"properties":{"municipalitySlug":"salvador-ze-8","name":"Salvador — ZE 8","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[43,44,45]]],"properties":{"municipalitySlug":"salvador-ze-9","name":"Salvador — ZE 9","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[46,47,-26,48,49,50,51]]],"properties":{"municipalitySlug":"salvador-ze-10","name":"Salvador — ZE 10","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[52,-42,53,54,55,-23,56,-38]]],"properties":{"municipalitySlug":"salvador-ze-11","name":"Salvador — ZE 11","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-51,57,58]]],"properties":{"municipalitySlug":"salvador-ze-12","name":"Salvador — ZE 12","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[59,-6,-33,31,-31,60,-47]]],"properties":{"municipalitySlug":"salvador-ze-13","name":"Salvador — ZE 13","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-24,-56,61]]],"properties":{"municipalitySlug":"salvador-ze-14","name":"Salvador — ZE 14","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[62,-44,63,64,-39,-57,-22,-9]]],"properties":{"municipalitySlug":"salvador-ze-15","name":"Salvador — ZE 15","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-48,-61,-30,-27]],[[-62,-55,65,-49,-25]]],"properties":{"municipalitySlug":"salvador-ze-16","name":"Salvador — ZE 16","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-15,-40,-65,66]]],"properties":{"municipalitySlug":"salvador-ze-17","name":"Salvador — ZE 17","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-63,-8,35,-35,67,-45]]],"properties":{"municipalitySlug":"salvador-ze-18","name":"Salvador — ZE 18","ibgeCode":"2927408"}},{"type":"MultiPolygon","arcs":[[[-50,-66,-54,-43,-53,-37,68,-58]]],"properties":{"municipalitySlug":"salvador-ze-19","name":"Salvador — ZE 19","ibgeCode":"2927408"}}]}},"arcs":[[[148,49],[1,0],[5,7],[7,11],[2,-1],[-1,-6],[-5,-6],[-1,-5],[-3,-9],[0,-4],[5,5],[4,0]],[[162,41],[2,-3]],[[164,38],[-1,-5],[-4,-2],[-6,0],[-1,0],[0,-7],[2,0],[2,-5],[-2,-2],[-3,6],[-3,0],[-3,-6],[1,-1],[5,-7]],[[151,9],[-17,1],[1,2],[0,11],[3,5],[6,13],[4,8]],[[164,38],[10,-7],[0,-1],[4,-2],[0,-1],[6,4],[2,-1],[4,-6]],[[190,24],[-1,-5],[6,5],[-1,-7],[2,-5],[-3,-1],[-7,4],[6,-6],[-2,-2],[2,-1],[9,2],[4,2],[1,-3]],[[206,7],[-2,-4],[-5,1],[-7,-2],[-2,2],[-6,-4],[-6,8],[-9,0],[-18,1]],[[175,76],[6,1],[1,2],[1,4],[0,2],[-5,3],[2,9],[4,-3],[5,6],[-4,6],[-3,1]],[[182,107],[7,6],[7,-3],[5,-5],[-3,-3],[-2,-10]],[[196,92],[0,0]],[[196,92],[1,-5],[-2,-7],[-3,-13]],[[192,67],[-1,0],[-1,0],[-9,3],[-3,1],[-3,5]],[[196,224],[1,11],[2,1],[1,9],[-5,7],[-7,6],[-4,-2],[-2,4],[2,16],[-3,8],[-3,3],[-7,1],[0,10],[0,19],[5,-3],[3,-9],[6,6],[1,4],[12,4],[4,-5],[-6,-2],[-1,-4],[1,-12],[-6,-13],[2,-7],[2,10],[4,5],[2,-8],[7,-4],[3,-10],[-1,-3],[0,-5],[8,-4],[-1,-8],[3,0],[0,-6],[5,-4]],[[224,239],[1,-2],[-7,1],[-1,-8],[1,-4]],[[218,226],[0,-2],[-3,-12],[-9,-3],[-3,7],[4,5],[-11,3]],[[135,330],[0,9],[-12,10],[-3,6],[7,16],[4,9],[4,2],[8,-9],[6,1],[4,-6],[-3,-8],[1,-5],[-1,-10],[5,-19],[-2,-3],[1,-8],[-8,-10],[-15,1],[1,8],[3,1],[-2,12],[2,3]],[[9,352],[0,0]],[[7,353],[-4,-5],[0,5],[4,4],[0,-4]],[[13,309],[-1,11],[-4,7],[-6,2],[-2,5],[6,11],[3,-5],[2,5],[3,-3],[3,2],[-1,5],[4,1],[1,-8],[7,6],[6,12],[7,-1],[2,-8],[-3,-7],[1,-4],[-4,-13],[0,-7],[-5,-9],[0,-9],[-3,-6],[1,-6],[-8,-8],[-5,-1],[-2,9],[-4,3],[-1,5],[3,11]],[[13,356],[0,0]],[[14,358],[6,4],[3,-11],[-8,2],[-1,5]],[[196,92],[7,10],[0,-1],[7,-7],[0,7],[-2,5],[-5,1],[-1,4]],[[202,111],[7,7],[3,-1],[3,9],[-1,3],[7,-1],[3,5],[2,-2],[2,-6]],[[228,125],[-3,-7],[-3,-1],[-2,-6],[2,-3],[-1,-12],[-1,-6],[2,-1]],[[222,89],[3,-4],[-2,-5],[0,-6],[9,-9]],[[232,65],[-7,-4]],[[225,61],[-5,8],[-4,4],[-6,2],[-6,-1],[-8,-5],[-1,-10]],[[195,59],[-3,8]],[[162,41],[4,4],[0,4],[1,2],[2,4],[5,-4],[3,-3],[9,-2],[4,5],[5,8]],[[195,59],[2,-3],[10,-4]],[[207,52],[-1,-11],[-6,-3],[-3,-6]],[[197,32],[0,0]],[[197,32],[-1,-2],[-6,-6]],[[148,49],[6,12],[0,2],[5,7],[4,8],[-2,3],[8,12]],[[169,93],[4,5],[-3,-7],[0,-10],[1,-1],[4,-4]],[[175,76],[0,0]],[[271,200],[-11,-12]],[[260,188],[-6,3],[-11,-2],[-3,-4],[-9,-8],[-10,-18],[-9,-17],[-6,-8],[-1,-6],[-3,-8]],[[202,120],[-1,3],[-3,5],[1,6],[2,4],[-1,1]],[[200,139],[-1,7],[2,5],[2,8],[-3,0],[0,3],[6,9],[2,0],[-4,9],[5,14],[4,6],[0,7],[3,-3],[5,9],[-1,8],[0,1],[-2,4]],[[224,239],[4,6],[6,2],[7,-9],[7,-5],[-1,-12],[7,3],[1,-2],[5,-6],[1,-7],[3,-2],[7,-7]],[[255,159],[0,2],[-8,3],[-2,1],[0,8],[2,9],[5,1],[8,-1]],[[260,182],[0,-6],[2,-5],[0,-3],[8,-4],[-2,-2],[0,-6],[-5,-4],[-8,7]],[[184,123],[4,5],[-4,-10],[1,-2],[-2,0],[-4,-7],[1,-2]],[[180,107],[-2,0],[0,5],[-1,1],[-5,-7],[-5,5],[2,1],[4,1],[-2,0],[-5,10],[1,5],[0,1],[-3,0],[1,-16],[-3,0],[-1,-1]],[[161,112],[-8,8],[-4,3],[6,3],[3,7],[9,1],[4,7],[2,8],[3,1],[3,-5],[-2,-9],[-3,-2],[0,-4],[3,1],[2,-5],[3,-2],[-1,-5],[3,4]],[[228,25],[-5,6],[2,8],[-2,8],[1,5],[-5,5]],[[219,57],[4,3],[2,1]],[[232,65],[2,2],[11,15],[5,8],[6,12],[2,2],[3,4],[5,1],[5,1]],[[271,110],[9,2],[6,4],[12,11],[2,1],[12,2]],[[312,130],[2,-4],[-7,-10],[0,-2],[-3,-9],[0,-7],[5,-4],[-3,-4]],[[306,90],[-5,-6],[-6,1],[-16,-11],[-1,-1],[-18,-16],[-10,-7],[-8,-9],[-6,-10],[-2,-5],[-6,-1]],[[260,188],[0,-6]],[[255,159],[0,-8],[-3,-7],[-6,-4]],[[246,140],[-2,-5]],[[244,135],[-3,-2],[-6,0],[-3,5],[1,-12],[-5,-1]],[[202,111],[-1,6],[1,3]],[[312,130],[13,3],[0,7],[-4,3],[-1,5],[-14,2],[-4,6],[-8,-6],[2,5],[5,4],[10,0],[7,-3],[10,-1],[-8,4],[-2,6],[-1,25],[0,11],[1,20],[2,9],[-2,16],[7,10]],[[325,256],[4,-8],[1,-19],[-2,-18],[-1,-20],[0,-21],[10,-8],[3,-5],[2,-4],[3,5],[7,0],[5,8],[3,-4],[5,1],[4,-7],[11,2],[-1,-5],[3,-5],[-13,-22],[-7,-8],[-13,-17],[-6,-5],[-2,-3],[-12,-9],[-6,1],[-6,8],[-11,-3]],[[228,25],[-9,-10],[-4,0],[-9,-8]],[[207,52],[6,6],[6,-1]],[[244,135],[0,-1],[-2,-17],[-2,1],[-4,-5],[5,-5],[3,0],[-7,-12],[1,-6],[-7,0],[-2,-2],[-3,4],[-4,-3]],[[182,107],[-2,0]],[[184,123],[-6,8],[4,5],[4,-2],[3,3],[-1,5],[4,11]],[[192,153],[2,-1],[-3,-12],[9,-1]],[[246,140],[5,-1],[2,-4],[6,-1],[7,-9],[5,-15]],[[192,153],[3,9],[-4,2],[0,-5],[-8,-4],[-4,10],[2,7],[6,16],[6,8],[1,9],[-2,13],[4,6]],[[169,93],[-2,9],[-4,7],[-2,3]],[[271,200],[1,1],[4,0],[0,7],[3,3],[-1,5],[3,3],[5,6],[2,0],[1,7],[-3,9],[4,4],[2,9],[5,5],[4,12],[10,-7],[3,1],[11,-9]]]}
diff --git a/src/lib/municipalityProximity.ts b/src/lib/municipalityProximity.ts
index 12bad87c..f1f0faa9 100644
--- a/src/lib/municipalityProximity.ts
+++ b/src/lib/municipalityProximity.ts
@@ -1,9 +1,9 @@
import type { Position } from 'geojson'
import type {
- BahiaGeometryFeature,
BahiaMunicipalityFeature,
MunicipalityGeometryModule,
+ PolygonalFeature,
} from '@/lib/bahiaGeometriesTypes'
import { oneDecimalFormatter } from '@/lib/electionFormat'
@@ -109,7 +109,8 @@ const isPointInRing = (point: GeoPoint, ring: readonly Position[]): boolean => {
return inside
}
-const polygonRingsOf = (feature: BahiaGeometryFeature): readonly Position[][][] =>
+/** Outer ring + holes per polygon, so callers stop re-writing the Polygon/MultiPolygon branch. */
+export const polygonRingsOf = (feature: PolygonalFeature): readonly Position[][][] =>
feature.geometry.type === 'Polygon'
? [feature.geometry.coordinates]
: feature.geometry.coordinates
@@ -118,7 +119,7 @@ const polygonRingsOf = (feature: BahiaGeometryFeature): readonly Position[][][]
* Holes and MultiPolygons do not occur in the committed mesh (417 plain
* Polygons), but a rebuild at finer quality would introduce them.
*/
-export const featureContainsPoint = (feature: BahiaGeometryFeature, point: GeoPoint): boolean =>
+export const featureContainsPoint = (feature: PolygonalFeature, point: GeoPoint): boolean =>
polygonRingsOf(feature).some(([outerRing, ...holes]) => {
if (!outerRing || !isPointInRing(point, outerRing)) return false
return !holes.some((hole) => isPointInRing(point, hole))
@@ -129,7 +130,7 @@ export const featureContainsPoint = (feature: BahiaGeometryFeature, point: GeoPo
* at Bahia's latitudes is far below the precision this feeds). Holes are
* ignored: they move the centre by less than the rounding of the label.
*/
-export const featureCentroid = (feature: BahiaGeometryFeature): GeoPoint => {
+export const featureCentroid = (feature: PolygonalFeature): GeoPoint => {
let weightedLng = 0
let weightedLat = 0
let totalArea = 0
diff --git a/src/utilities/municipalityMapContract.ts b/src/utilities/municipalityMapContract.ts
index ef009450..8389efcf 100644
--- a/src/utilities/municipalityMapContract.ts
+++ b/src/utilities/municipalityMapContract.ts
@@ -125,6 +125,16 @@ export type MunicipalityMapBundle = {
projectedValidVotesByMapKey: Record
/** map key → the municipality it opens on click. */
municipalitiesByMapKey: MunicipalitiesByMapKey
+ /**
+ * Whether the actor's scope includes a zone municipality, i.e. whether the
+ * approximate ZE mesh is painted at all — which is what the map's provenance
+ * caveat is about. Published rather than re-derived on the client so `kind`
+ * stays the single answer to "is this a zona": reading it off the key's shape
+ * would be a second encoding of the rule in `mapKeyForMunicipality`, and
+ * `zoneBreakdown` is scheduled for deletion by the fill-in that removes the
+ * textual zone list.
+ */
+ hasZoneMunicipalities: boolean
/** Zone municipalities in scope (Salvador) with per-year values. */
zoneBreakdown: MunicipalityZoneBreakdownRow[]
candidateName: string
diff --git a/src/utilities/municipalityMapData.ts b/src/utilities/municipalityMapData.ts
index 3ac9ccb1..937fef18 100644
--- a/src/utilities/municipalityMapData.ts
+++ b/src/utilities/municipalityMapData.ts
@@ -155,11 +155,9 @@ const buildMunicipalityMapBundleFromMunicipalities = async (
const territorialClassByMapKey: Record = {}
const projectedValidVotesByMapKey: Record = {}
- for (const [mapKey, entry] of Object.entries(municipalitiesByMapKey)) {
- territorialClassByMapKey[mapKey] = computeMunicipalityTerritorialClass(entry.slug).class
- projectedValidVotesByMapKey[mapKey] = projectedValidVotes(
- getMunicipalityFederalBaseline(entry.slug),
- )
+ for (const [mapKey, slug] of Object.entries(municipalitiesByMapKey)) {
+ territorialClassByMapKey[mapKey] = computeMunicipalityTerritorialClass(slug).class
+ projectedValidVotesByMapKey[mapKey] = projectedValidVotes(getMunicipalityFederalBaseline(slug))
}
const pledgeValuesByScenario = Object.fromEntries(
@@ -264,6 +262,7 @@ const buildMunicipalityMapBundleFromMunicipalities = async (
competitiveRankByYear,
projectedValidVotesByMapKey,
municipalitiesByMapKey,
+ hasZoneMunicipalities: municipalities.some((municipality) => municipality.kind === 'zona'),
zoneBreakdown,
candidateName: BASELINE_TICKET_2022.candidate.name,
comparison,
diff --git a/src/utilities/municipalityMapNavigation.ts b/src/utilities/municipalityMapNavigation.ts
index 53dad921..6c71d69d 100644
--- a/src/utilities/municipalityMapNavigation.ts
+++ b/src/utilities/municipalityMapNavigation.ts
@@ -9,13 +9,13 @@ type MunicipalityMapSlugEntry = {
export type MunicipalitiesByIbgeCode = Record
/**
- * Map key → the single unit it paints. Since B8 F2 the map draws one polygon per
- * catalog unit — zone municipalities by slug, everything else by IBGE codarea —
- * so this index is 1:1 where `MunicipalitiesByIbgeCode` is 1:N.
+ * Map key → the slug of the single unit it paints. Since B8 F2 the map draws one
+ * polygon per catalog unit — zone municipalities by slug, everything else by IBGE
+ * codarea — so this index is 1:1 where `MunicipalitiesByIbgeCode` is 1:N, and the
+ * name it used to carry alongside was 435 dead strings in the RSC payload of
+ * every visit to Início (the readout takes the name from the feature it painted).
*/
-export type MunicipalitiesByMapKey = Record
-
-export type MunicipalityMapNavigation = { kind: 'none' } | { kind: 'navigate'; slug: string }
+export type MunicipalitiesByMapKey = Record
/**
* What the choropleth paints a unit by: a zone municipality has no code of its
@@ -52,19 +52,8 @@ export const buildMunicipalitiesByMapKey = (
const byMapKey: MunicipalitiesByMapKey = {}
for (const municipality of municipalities) {
- byMapKey[mapKeyForMunicipality(municipality)] = {
- slug: municipality.slug,
- name: municipality.name,
- }
+ byMapKey[mapKeyForMunicipality(municipality)] = municipality.slug
}
return byMapKey
}
-
-export const resolveMunicipalityMapNavigation = (
- mapKey: string,
- municipalitiesByMapKey: MunicipalitiesByMapKey,
-): MunicipalityMapNavigation => {
- const entry = municipalitiesByMapKey[mapKey]
- return entry ? { kind: 'navigate', slug: entry.slug } : { kind: 'none' }
-}
diff --git a/tests/helpers/featureBounds.ts b/tests/helpers/featureBounds.ts
index 4587e4b9..328f5e3a 100644
--- a/tests/helpers/featureBounds.ts
+++ b/tests/helpers/featureBounds.ts
@@ -1,4 +1,5 @@
-import type { BahiaMunicipalityFeature } from '../../src/lib/bahiaGeometriesTypes.js'
+import type { PolygonalFeature } from '../../src/lib/bahiaGeometriesTypes.js'
+import { polygonRingsOf } from '../../src/lib/municipalityProximity.js'
export type FeatureBounds = {
west: number
@@ -7,17 +8,9 @@ export type FeatureBounds = {
north: number
}
-/**
- * Bounding box of every ring of a municipality feature. Type-only import on
- * purpose: this helper is shared by the vitest int suite and the Playwright e2e
- * suite, which resolve runtime modules differently.
- */
-export const featureBounds = (feature: BahiaMunicipalityFeature): FeatureBounds => {
- const rings =
- feature.geometry.type === 'Polygon'
- ? [feature.geometry.coordinates]
- : feature.geometry.coordinates
- const positions = rings.flat(2)
+/** Bounding box of every ring of a mesh feature. Shared by the int and e2e suites. */
+export const featureBounds = (feature: PolygonalFeature): FeatureBounds => {
+ const positions = polygonRingsOf(feature).flat(2)
const longitudes = positions.map(([lng]) => lng)
const latitudes = positions.map(([, lat]) => lat)
diff --git a/tests/int/bahiaGeometries.int.spec.ts b/tests/int/bahiaGeometries.int.spec.ts
index 87375554..107e79fc 100644
--- a/tests/int/bahiaGeometries.int.spec.ts
+++ b/tests/int/bahiaGeometries.int.spec.ts
@@ -5,15 +5,17 @@ import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import type { Position } from 'geojson'
+import type { GeometryCollection, Topology } from 'topojson-specification'
import { describe, expect, it } from 'vitest'
-import type { BahiaGeometryFeature } from '@/lib/bahiaGeometriesTypes'
+import type { PolygonalFeature } from '@/lib/bahiaGeometriesTypes'
import {
loadMunicipalityGeometryModule,
loadMunicipalityZoneGeometryModule,
loadTerritoryGeometryModule,
} from '@/lib/bahiaGeometries'
+import { featureMapKey } from '@/lib/bahiaMapStyle'
import { bahiaMunicipalityCodes } from '@/lib/bahiaMunicipalityCodes'
import { bahiaIdentityTerritoryRecords } from '@/lib/bahiaTerritories'
import { municipalityCatalog } from '@/lib/municipalityCatalog'
@@ -21,6 +23,7 @@ import {
featureCentroid,
featureContainsPoint,
findContainingMunicipality,
+ polygonRingsOf,
resolveNearbyMunicipality,
} from '@/lib/municipalityProximity'
@@ -29,6 +32,22 @@ import { featureBounds } from '../helpers/featureBounds'
/** Soft ceiling against accidental unsimplified meshes (plan target ≤ ~600 KB). */
const MAX_TOPO_BYTES = 600 * 1024
+/**
+ * B8+ — the grandeza the ground-scale policy in `scripts/lib/topology.mjs`
+ * actually controls. Bytes only catch a mesh nobody simplified at all: the zone
+ * mesh shipped at 480 points/feature, 22× the state mesh, while sitting at 10% of
+ * the byte budget, because a simplification tolerance copied as a *quantile* of
+ * each mesh's own triangles cut Salvador's zones at ~0.6 m² and Bahia's
+ * municipalities at ~1.78 km². A mesh that goes back to a relative cut fails here.
+ */
+const MAX_POINTS_PER_FEATURE = 60
+
+/** Arc points over features — sound because each mesh holds exactly one object. */
+const pointsPerFeature = (topology: Topology<{ [key: string]: GeometryCollection }>): number => {
+ const arcPoints = topology.arcs.reduce((total, arc) => total + arc.length, 0)
+ return arcPoints / Object.values(topology.objects)[0].geometries.length
+}
+
/** Square degrees → km² at Salvador's latitude — good to a few percent, which is all this needs. */
const SQUARE_DEGREE_KM2 = 110.57 * 108.5
@@ -43,13 +62,8 @@ const hasNonEmptyGeometry = (
}
/** Planar shoelace in square degrees — only ever compared against itself. */
-const featureArea = (feature: BahiaGeometryFeature): number => {
- const polygons =
- feature.geometry.type === 'Polygon'
- ? [feature.geometry.coordinates]
- : feature.geometry.coordinates
-
- return polygons.reduce((total, [outerRing, ...holes]) => {
+const featureArea = (feature: PolygonalFeature): number =>
+ polygonRingsOf(feature).reduce((total, [outerRing, ...holes]) => {
const ringArea = (ring: readonly Position[]): number => {
let sum = 0
for (
@@ -66,7 +80,6 @@ const featureArea = (feature: BahiaGeometryFeature): number => {
total + ringArea(outerRing) - holes.reduce((holeTotal, hole) => holeTotal + ringArea(hole), 0)
)
}, 0)
-}
describe('Bahia static geometries', () => {
it('keeps committed TopoJSON under the size budget', () => {
@@ -82,12 +95,25 @@ describe('Bahia static geometries', () => {
expect(municipalityBytes).toBeGreaterThan(10_000)
expect(territoryBytes).toBeGreaterThan(1_000)
- expect(zoneBytes).toBeGreaterThan(10_000)
+ expect(zoneBytes).toBeGreaterThan(1_000)
expect(municipalityBytes).toBeLessThanOrEqual(MAX_TOPO_BYTES)
expect(territoryBytes).toBeLessThanOrEqual(MAX_TOPO_BYTES)
expect(zoneBytes).toBeLessThanOrEqual(MAX_TOPO_BYTES)
})
+ it('cuts every mesh at the shared ground scale, not at its own bbox', async () => {
+ const [municipalityModule, territoryModule, zoneModule] = await Promise.all([
+ loadMunicipalityGeometryModule(),
+ loadTerritoryGeometryModule(),
+ loadMunicipalityZoneGeometryModule(),
+ ])
+
+ for (const { topology } of [municipalityModule, territoryModule, zoneModule]) {
+ const [objectName] = Object.keys(topology.objects)
+ expect(pointsPerFeature(topology), objectName).toBeLessThanOrEqual(MAX_POINTS_PER_FEATURE)
+ }
+ })
+
it('exposes 417 municipality features whose codarea set matches the code table', async () => {
const { topology, features, getMunicipalityFeature } = await loadMunicipalityGeometryModule()
@@ -102,6 +128,9 @@ describe('Bahia static geometries', () => {
expect(entry.properties.codarea).toMatch(/^29\d{5}$/)
expect(bahiaMunicipalityCodes[entry.properties.name]).toBe(entry.properties.codarea)
expect(hasNonEmptyGeometry(entry.geometry)).toBe(true)
+ // B8+ F2 — the map key every one of these is painted and hovered by,
+ // resolved from the real properties instead of a synthetic literal.
+ expect(featureMapKey(entry.properties), entry.properties.name).toBe(entry.properties.codarea)
}
expect(getMunicipalityFeature('2927408')?.properties.name).toBe('Salvador')
@@ -109,7 +138,7 @@ describe('Bahia static geometries', () => {
})
it('exposes 27 territory features whose codes match bahiaIdentityTerritoryRecords', async () => {
- const { topology, features, getTerritoryFeature } = await loadTerritoryGeometryModule()
+ const { topology, features } = await loadTerritoryGeometryModule()
expect(topology.objects.territories.geometries).toHaveLength(27)
expect(features).toHaveLength(27)
@@ -118,15 +147,19 @@ describe('Bahia static geometries', () => {
const recordCodes = bahiaIdentityTerritoryRecords.map((entry) => entry.code).sort()
expect(featureCodes).toEqual(recordCodes)
+ const territoryByCode = new Map(
+ features.map((entry) => [entry.properties.code, entry] as const),
+ )
+
for (const record of bahiaIdentityTerritoryRecords) {
- const featureEntry = getTerritoryFeature(record.code)
+ const featureEntry = territoryByCode.get(record.code)
expect(featureEntry, record.code).toBeDefined()
expect(featureEntry?.properties.name).toBe(record.name)
expect(hasNonEmptyGeometry(featureEntry?.geometry)).toBe(true)
+ expect(featureMapKey(featureEntry?.properties), record.code).toBe(record.code)
}
- expect(getTerritoryFeature('01')?.properties.name).toBe('Irecê')
- expect(getTerritoryFeature('99')).toBeUndefined()
+ expect(territoryByCode.get('01')?.properties.name).toBe('Irecê')
})
/**
@@ -139,23 +172,31 @@ describe('Bahia static geometries', () => {
const zoneCatalog = municipalityCatalog.filter((entry) => entry.kind === 'zona')
it('exposes one feature per zona municipality, keyed by catalog slug', async () => {
- const { topology, features, getMunicipalityZoneFeature } =
- await loadMunicipalityZoneGeometryModule()
+ const { topology, features } = await loadMunicipalityZoneGeometryModule()
expect(Object.keys(topology.objects)).toEqual(['municipalityZones'])
expect(topology.objects.municipalityZones.geometries).toHaveLength(zoneCatalog.length)
expect(features).toHaveLength(zoneCatalog.length)
+ const zoneBySlug = new Map(
+ features.map((zone) => [zone.properties.municipalitySlug, zone] as const),
+ )
+
for (const entry of zoneCatalog) {
- const zone = getMunicipalityZoneFeature(entry.slug)
+ const zone = zoneBySlug.get(entry.slug)
expect(zone, entry.slug).toBeDefined()
expect(zone?.properties.name).toBe(entry.name)
- expect(zone?.properties.zoneNumber).toBe(entry.zoneNumber)
expect(zone?.properties.ibgeCode).toBe(entry.ibgeCode)
expect(hasNonEmptyGeometry(zone?.geometry)).toBe(true)
+
+ // B8+ F2 — a zone answers its own slug even though it also carries the
+ // city's `ibgeCode`, which all 19 share and which is therefore not a key
+ // property. The municipal side of the contract is pinned over all 417
+ // features in the codarea test above.
+ expect(featureMapKey(zone?.properties), entry.slug).toBe(entry.slug)
}
- expect(getMunicipalityZoneFeature('feira-de-santana')).toBeUndefined()
+ expect(zoneBySlug.get('feira-de-santana')).toBeUndefined()
})
it('keeps every zone inside the municipality it decomposes', async () => {
diff --git a/tests/int/municipalityMapData.int.spec.ts b/tests/int/municipalityMapData.int.spec.ts
index 417d6496..7cd3810d 100644
--- a/tests/int/municipalityMapData.int.spec.ts
+++ b/tests/int/municipalityMapData.int.spec.ts
@@ -35,6 +35,7 @@ describe('loadMunicipalityMapBundle — list URL filters', () => {
expect(bundle).not.toBeNull()
expect(bundle!.zoneBreakdown).toHaveLength(ZONE_MUNICIPALITY_COUNT)
+ expect(bundle!.hasZoneMunicipalities).toBe(true)
const mapKeys = Object.keys(bundle!.valuesByYear['2022'] ?? {})
expect(mapKeys.length).toBeGreaterThan(0)
@@ -69,6 +70,8 @@ describe('loadMunicipalityMapBundle — list URL filters', () => {
expect(included!.zoneBreakdown.some((row) => row.slug === administered.slug)).toBe(
administered.kind === 'zona',
)
+ // The map's provenance caveat follows the actor's scope, not the list below it.
+ expect(included!.hasZoneMunicipalities).toBe(administered.kind === 'zona')
expect(Object.keys(included!.valuesByYear['2022'] ?? {})).toEqual([
administered.kind === 'zona' ? administered.slug : administered.ibgeCode,
])
diff --git a/tests/unit/bahiaMapStyle.unit.spec.ts b/tests/unit/bahiaMapStyle.unit.spec.ts
index e7cd68af..3ac69952 100644
--- a/tests/unit/bahiaMapStyle.unit.spec.ts
+++ b/tests/unit/bahiaMapStyle.unit.spec.ts
@@ -31,10 +31,10 @@ describe('bahiaMapStyle', () => {
})
describe('featureMapKey (B8 F2)', () => {
- it('keys a zone municipality by its catalog slug', () => {
- expect(
- featureMapKey({ municipalitySlug: 'salvador-ze-7', ibgeCode: '2927408', zoneNumber: 7 }),
- ).toBe('salvador-ze-7')
+ it('keys a zone municipality by its slug, never by the city code it also carries', () => {
+ expect(featureMapKey({ municipalitySlug: 'salvador-ze-7', ibgeCode: '2927408' })).toBe(
+ 'salvador-ze-7',
+ )
})
it('keys a município by codarea and an identity territory by code', () => {
@@ -44,12 +44,6 @@ describe('bahiaMapStyle', () => {
)
})
- it('prefers the slug when the zone mesh also carries the city code', () => {
- expect(featureMapKey({ municipalitySlug: 'salvador-ze-1', codarea: '2927408' })).toBe(
- 'salvador-ze-1',
- )
- })
-
it('returns undefined when no key property is usable', () => {
expect(featureMapKey(undefined)).toBeUndefined()
expect(featureMapKey({ name: 'Sem chave' })).toBeUndefined()
diff --git a/tests/unit/municipalityMapNavigation.unit.spec.ts b/tests/unit/municipalityMapNavigation.unit.spec.ts
index a3e84cac..4641f3a5 100644
--- a/tests/unit/municipalityMapNavigation.unit.spec.ts
+++ b/tests/unit/municipalityMapNavigation.unit.spec.ts
@@ -4,7 +4,6 @@ import {
buildMunicipalitiesByIbgeCode,
buildMunicipalitiesByMapKey,
mapKeyForMunicipality,
- resolveMunicipalityMapNavigation,
} from '@/utilities/municipalityMapNavigation'
const abaira = { slug: 'abaira', name: 'Abaíra', ibgeCode: '2900108', kind: 'municipio' } as const
@@ -40,31 +39,11 @@ describe('municipalityMapNavigation', () => {
it('gives every zone its own map key instead of pooling them under the city', () => {
const byMapKey = buildMunicipalitiesByMapKey([salvadorZe1, salvadorZe2, abaira])
- expect(Object.keys(byMapKey).sort()).toEqual(['2900108', 'salvador-ze-1', 'salvador-ze-2'])
+ expect(byMapKey).toEqual({
+ '2900108': 'abaira',
+ 'salvador-ze-1': 'salvador-ze-1',
+ 'salvador-ze-2': 'salvador-ze-2',
+ })
expect(byMapKey['2927408']).toBeUndefined()
- expect(byMapKey['salvador-ze-2']).toEqual({
- slug: 'salvador-ze-2',
- name: 'Salvador — ZE 2',
- })
- })
-
- it('resolveMunicipalityMapNavigation returns none for an unknown or empty key', () => {
- const byMapKey = buildMunicipalitiesByMapKey([abaira])
-
- expect(resolveMunicipalityMapNavigation('9999999', byMapKey)).toEqual({ kind: 'none' })
- expect(resolveMunicipalityMapNavigation('2900108', {})).toEqual({ kind: 'none' })
- })
-
- it('resolveMunicipalityMapNavigation opens the unit behind the key, zone included', () => {
- const byMapKey = buildMunicipalitiesByMapKey([abaira, salvadorZe1])
-
- expect(resolveMunicipalityMapNavigation('2900108', byMapKey)).toEqual({
- kind: 'navigate',
- slug: 'abaira',
- })
- expect(resolveMunicipalityMapNavigation('salvador-ze-1', byMapKey)).toEqual({
- kind: 'navigate',
- slug: 'salvador-ze-1',
- })
})
})