diff --git a/assets/scss/common/_custom.scss b/assets/scss/common/_custom.scss index 24f706a..3be82c1 100644 --- a/assets/scss/common/_custom.scss +++ b/assets/scss/common/_custom.scss @@ -341,13 +341,54 @@ $feature-gap: 1.25rem; // smudges in the land. // // The cost is contrast, and it is worth stating plainly: 2.2:1 against the white -// keyline that rings each dot, 1.9:1 against the land. WCAG 2.1 asks 3:1 of a +// keyline that rings each dot, 1.9:1 against the land — 1.1:1 where the dot stands +// on a shaded country, which is where most of them stand. WCAG 2.1 asks 3:1 of a // graphic needed to understand the content, and this no longer meets it. What makes // that a considered trade rather than an oversight is that nothing here is only on // the map: every city is named in the card that opens on its dot, along with the // people who are there, and the region shares are the text list beside it. Going // back to 72% (#E47351) restores 3.1:1 on the keyline. +// +// The keyline is what keeps the dots countable over the shade, and it gains what the +// fill loses: white on a shaded country is 1.97:1 against 1.18:1 on bare land. That +// trade is why the shade can be as dark as it is — see $map-region. $map-land: #e9edf2; +// The countries somebody is in, filled whole. The land's own colour a step darker +// rather than a colour of its own, which is what this started as — the mark's hue at +// 35%, and the trouble was never the strength but that half the land ended up in the +// accent family. North America, China, India and Australia are all shaded, so the +// largest warm shapes on the map were the ones carrying the vaguest information: a +// country is where somebody is *somewhere* in, and the dots are where they actually +// are. A darker neutral says which countries without spending the accent on them, so +// the dots stay the only colour the map has. +// +// #b0bac6 is a slate: the land's own hue (213) at 16% saturation against its 26%, and +// 73% lightness against its 93%. Every number here was set by rendering the +// alternatives and looking at them, and the two dead ends are worth keeping: +// +// #c8d4e3 — the land's hue and saturation at 84% — was too blue and too close. Blue at +// full saturation is the one hue a map already spends on something else, so the shaded +// countries read as a second sea rather than as land with somebody in it, and at 84% +// they were a 1.28:1 step off the land besides. +// +// #bcc0c4 — a near-neutral grey at 6% saturation — went too far the other way. A grey +// that has no hue at all sits over a land that has one, and the shapes read as a +// desaturated patch of the map rather than as a tone of it: muddy, and nothing to do +// with contrast, which was fine. +// +// So: keep the land's hue, drop most of its saturation, and take the lightness down +// until the shade is unmistakable — a 1.67:1 step against the land. The floor is the +// small countries, because Romania, Italy, Ireland and Cyprus are a few pixels of +// coastline at this width and at 86% they did not read at all, which loses the shade +// exactly where it is the only thing saying anybody is there. The ceiling is where the +// shades stop being marks on one landmass and become a silhouette of their own over +// it — around 70%, where the United States and Brazil start to outweigh the dots +// standing on them. +// +// Flat and opaque rather than a tint: the shades are one per country and never +// overlap, so there is nothing for an alpha to buy — and an alpha over the land is +// this colour anyway, computed at render time instead of being chosen. +$map-region: #b0bac6; $map-mark: mix($primary, #fff, 52%); // City labels and the legend's figures. Lighter than the body ink, which made both // heavier than the map they annotate. Safe at this lightness only because each is @@ -374,15 +415,21 @@ $map-pulse-alpha: 0.18; align-items: center; // Room for a card to open into rather than separation, which is what this is for at // every other width. Stacked on a phone the map is shorter than the cards standing on - // it: 109px tall at 320px wide, where Shanghai's six faces make a 221px card. A card + // it: 109px tall at 320px wide, where Shanghai's seven faces make a 249px card. A card // is centred on its dot, so one in the lower half of a map that short hangs past its - // bottom edge — Shanghai's by 42px, which over a 2rem gap laid the card's bottom edge + // bottom edge — Shanghai's by 56px, which over a 2rem gap laid the card's bottom edge // and its shadow across the legend's "Asia" row. // - // 3.5rem clears it: at 320px the widest card the data makes stops 9px above the - // legend's box and 14px above the first row's text. The separation the two elements - // actually want is the 2rem below. - gap: 3.5rem; + // 4.5rem clears it: at 320px the tallest card stops 9px above the legend's box and + // 14px above the first row's text. The separation the two elements actually want is + // the 2rem below. + // + // It is measured against the data, so it is worth knowing what moves it: every face + // the tallest card gains is 12px more overhang here (3.5rem was enough for six of + // them), and the list stops at ten and an "and N more" line, which would want 7rem. + // A gap that big under a 109px map is spacing that reads as a mistake, so if the map + // ever needs it, the card is what should give — not this. + gap: 4.5rem; } // From `sm` up the container has a fixed width, so the map stops shrinking: it is 175px @@ -524,6 +571,32 @@ $map-pulse-alpha: 0.18; fill: $map-land; } +// Every country a contributor is in, filled over the land. See `$map-region` for why +// it is a darker neutral and not a tint of the mark's colour. +.worldmap-country { + fill: $map-region; + // A hairline of page background around each country, which is the same device the + // dots use and it is here for the same reason: without it, neighbours that both + // have contributors fuse into one shape. The United States and Canada became a + // single mass from the Arctic to Mexico, China and India one from the Pacific to + // the Arabian Sea, and eight European countries one blob — a map that said "this + // continent" where the data says which countries. + // + // The stroke straddles the outline, so half of it lands outside: on the sea, where + // it is the same white and invisible, and on an unshaded neighbour, where it is a + // barely-there 1.18:1 lightening of the land. Only where two shades meet do both + // halves paint, and that is the one place a seam is wanted. + // + // 0.8 units against the dots' 2.5. This is a border and not a keyline: at 2.5 the + // seams read as white rivers between countries, and Italy — 15 units of coastline — + // loses a fifth of its area to its own outline. + stroke: var(--bs-body-bg, #fff); + stroke-width: 0.8; + // The pointer belongs to the hover target in the html layer above, as it does for + // the dots — a shade is not a bigger hit area, it is a bigger mark. + pointer-events: none; +} + .worldmap-dot { fill: $map-mark; // A hairline of page background around each mark. Guangzhou and Shenzhen are diff --git a/data/contributors.json b/data/contributors.json index 43c9966..c7cfb0b 100644 --- a/data/contributors.json +++ b/data/contributors.json @@ -1,7 +1,7 @@ { "generated": "2026-09-11", - "total": 56, - "located": 37, + "total": 75, + "located": 48, "places": [ { "label": "Shanghai, China", @@ -14,7 +14,7 @@ "dy": 5, "anchor": "start" }, - "count": 6, + "count": 7, "people": [ { "login": "cr7258", @@ -36,6 +36,10 @@ "login": "rudeigerc", "avatar": "https://avatars.githubusercontent.com/u/18243819?v=4&s=64" }, + { + "login": "windsonsea", + "avatar": "https://avatars.githubusercontent.com/u/79828097?v=4&s=64" + }, { "login": "caozhuozi", "avatar": "https://avatars.githubusercontent.com/u/68834160?v=4&s=64" @@ -50,9 +54,9 @@ "lng": -122.42, "short": "San Francisco", "offset": { - "dx": 0, - "dy": -14, - "anchor": "start" + "dx": -11, + "dy": 4, + "anchor": "end" }, "count": 3, "people": [ @@ -72,50 +76,74 @@ "more": 0 }, { - "label": "India", - "country": "India", - "lat": 22, - "lng": 79, + "label": "United States", + "country": "United States", + "lat": 39.5, + "lng": -98.35, "countryOnly": true, - "short": "India", + "short": "United States", + "offset": { + "dx": -11, + "dy": -8, + "anchor": "end" + }, + "count": 2, + "people": [ + { + "login": "awdemos", + "avatar": "https://avatars.githubusercontent.com/u/159745380?v=4&s=64" + }, + { + "login": "twinsgeeks", + "avatar": "https://avatars.githubusercontent.com/u/261838102?v=4&s=64" + } + ], + "more": 0 + }, + { + "label": "Barcelona, Spain", + "country": "Spain", + "lat": 41.39, + "lng": 2.17, + "short": "Barcelona", "offset": { "dx": 0, - "dy": 23, - "anchor": "middle" + "dy": 22, + "anchor": "start" }, "count": 2, "people": [ { - "login": "SanjanShiv", - "avatar": "https://avatars.githubusercontent.com/u/90202905?v=4&s=64" + "login": "guillemwilly", + "avatar": "https://avatars.githubusercontent.com/u/161842218?v=4&s=64" }, { - "login": "VedantMadane", - "avatar": "https://avatars.githubusercontent.com/u/6527493?v=4&s=64" + "login": "vgmartinez", + "avatar": "https://avatars.githubusercontent.com/u/10614247?v=4&s=64" } ], "more": 0 }, { - "label": "Guangzhou, China", - "country": "China", - "lat": 23.13, - "lng": 113.26, - "short": "Guangzhou", + "label": "London, UK", + "country": "United Kingdom", + "lat": 51.51, + "lng": -0.13, + "short": "London", "offset": { - "dx": -9, - "dy": 20, - "anchor": "end" + "dx": 0, + "dy": -28, + "anchor": "middle" }, "count": 2, "people": [ { - "login": "kenwoodjw", - "avatar": "https://avatars.githubusercontent.com/u/10386710?v=4&s=64" + "login": "jaedmunt", + "avatar": "https://avatars.githubusercontent.com/u/76647805?v=4&s=64" }, { - "login": "Whitea029", - "avatar": "https://avatars.githubusercontent.com/u/145814986?v=4&s=64" + "login": "metrofun", + "avatar": "https://avatars.githubusercontent.com/u/946519?v=4&s=64" } ], "more": 0 @@ -144,6 +172,30 @@ ], "more": 0 }, + { + "label": "Guangzhou, China", + "country": "China", + "lat": 23.13, + "lng": 113.26, + "short": "Guangzhou", + "offset": { + "dx": -9, + "dy": 20, + "anchor": "end" + }, + "count": 2, + "people": [ + { + "login": "kenwoodjw", + "avatar": "https://avatars.githubusercontent.com/u/10386710?v=4&s=64" + }, + { + "login": "Whitea029", + "avatar": "https://avatars.githubusercontent.com/u/145814986?v=4&s=64" + } + ], + "more": 0 + }, { "label": "Shenzhen, China", "country": "China", @@ -169,42 +221,47 @@ "more": 0 }, { - "label": "South Africa", - "country": "South Africa", - "lat": -29, - "lng": 24.7, + "label": "India", + "country": "India", + "lat": 22, + "lng": 79, "countryOnly": true, - "short": "South Africa", + "short": "India", "offset": { - "dx": 11, + "dx": -11, "dy": 4, - "anchor": "start" + "anchor": "end" }, - "count": 1, + "count": 2, "people": [ { - "login": "AbdulDavids", - "avatar": "https://avatars.githubusercontent.com/u/125186956?v=4&s=64" + "login": "SanjanShiv", + "avatar": "https://avatars.githubusercontent.com/u/90202905?v=4&s=64" + }, + { + "login": "VedantMadane", + "avatar": "https://avatars.githubusercontent.com/u/6527493?v=4&s=64" } ], "more": 0 }, { - "label": "Paris, France", - "country": "France", - "lat": 48.86, - "lng": 2.35, - "short": "Paris", + "label": "South Africa", + "country": "South Africa", + "lat": -29, + "lng": 24.7, + "countryOnly": true, + "short": "South Africa", "offset": { - "dx": 17, - "dy": 28, + "dx": 11, + "dy": 4, "anchor": "start" }, "count": 1, "people": [ { - "login": "ThibautMelen", - "avatar": "https://avatars.githubusercontent.com/u/20891897?v=4&s=64" + "login": "AbdulDavids", + "avatar": "https://avatars.githubusercontent.com/u/125186956?v=4&s=64" } ], "more": 0 @@ -249,6 +306,27 @@ ], "more": 0 }, + { + "label": "Romania", + "country": "Romania", + "lat": 45.9, + "lng": 25, + "countryOnly": true, + "short": "Romania", + "offset": { + "dx": 11, + "dy": 4, + "anchor": "start" + }, + "count": 1, + "people": [ + { + "login": "damienen", + "avatar": "https://avatars.githubusercontent.com/u/44813558?v=4&s=64" + } + ], + "more": 0 + }, { "label": "Toronto, Canada", "country": "Canada", @@ -276,9 +354,9 @@ "lng": -6.26, "short": "Dublin", "offset": { - "dx": 0, - "dy": -11, - "anchor": "middle" + "dx": -11, + "dy": 4, + "anchor": "end" }, "count": 1, "people": [ @@ -309,6 +387,26 @@ ], "more": 0 }, + { + "label": "Kuala Lumpur, Malaysia", + "country": "Malaysia", + "lat": 3.14, + "lng": 101.69, + "short": "Kuala Lumpur", + "offset": { + "dx": 11, + "dy": 4, + "anchor": "start" + }, + "count": 1, + "people": [ + { + "login": "heiwen", + "avatar": "https://avatars.githubusercontent.com/u/3409733?v=4&s=64" + } + ], + "more": 0 + }, { "label": "Cambridge, UK", "country": "United Kingdom", @@ -316,8 +414,8 @@ "lng": 0.12, "short": "Cambridge", "offset": { - "dx": -8, - "dy": 19, + "dx": -11, + "dy": 15, "anchor": "end" }, "count": 1, @@ -390,6 +488,67 @@ ], "more": 0 }, + { + "label": "Limassol, Cyprus", + "country": "Cyprus", + "lat": 34.71, + "lng": 33.02, + "short": "Limassol", + "offset": { + "dx": 11, + "dy": 4, + "anchor": "start" + }, + "count": 1, + "people": [ + { + "login": "nadyyym", + "avatar": "https://avatars.githubusercontent.com/u/96404149?v=4&s=64" + } + ], + "more": 0 + }, + { + "label": "Italy", + "country": "Italy", + "lat": 42.8, + "lng": 12.6, + "countryOnly": true, + "short": "Italy", + "offset": { + "dx": 11, + "dy": 9, + "anchor": "start" + }, + "count": 1, + "people": [ + { + "login": "nicoloboschi", + "avatar": "https://avatars.githubusercontent.com/u/23314389?v=4&s=64" + } + ], + "more": 0 + }, + { + "label": "Bengaluru, India", + "country": "India", + "lat": 12.97, + "lng": 77.59, + "short": "Bengaluru", + "offset": { + "dx": 0, + "dy": 19, + "anchor": "middle" + }, + "count": 1, + "people": [ + { + "login": "pranshuchittora", + "avatar": "https://avatars.githubusercontent.com/u/32242596?v=4&s=64" + } + ], + "more": 0 + }, { "label": "Melbourne, Australia", "country": "Australia", @@ -417,9 +576,9 @@ "lng": -87.63, "short": "Chicago", "offset": { - "dx": 8, - "dy": 19, - "anchor": "start" + "dx": 0, + "dy": -17, + "anchor": "middle" }, "count": 1, "people": [ @@ -450,6 +609,26 @@ ], "more": 0 }, + { + "label": "Cleveland, USA", + "country": "United States", + "lat": 41.5, + "lng": -81.69, + "short": "Cleveland", + "offset": { + "dx": 11, + "dy": 12, + "anchor": "start" + }, + "count": 1, + "people": [ + { + "login": "santoshkumarradha", + "avatar": "https://avatars.githubusercontent.com/u/29346072?v=4&s=64" + } + ], + "more": 0 + }, { "label": "Minsk, Belarus", "country": "Belarus", @@ -470,6 +649,26 @@ ], "more": 0 }, + { + "label": "Paris, France", + "country": "France", + "lat": 48.86, + "lng": 2.35, + "short": "Paris", + "offset": { + "dx": 11, + "dy": 8, + "anchor": "start" + }, + "count": 1, + "people": [ + { + "login": "ThibautMelen", + "avatar": "https://avatars.githubusercontent.com/u/20891897?v=4&s=64" + } + ], + "more": 0 + }, { "label": "Palo Alto, USA", "country": "United States", @@ -491,84 +690,84 @@ "more": 0 }, { - "label": "Barcelona, Spain", - "country": "Spain", - "lat": 41.39, - "lng": 2.17, - "short": "Barcelona", + "label": "Amsterdam, Netherlands", + "country": "Netherlands", + "lat": 52.37, + "lng": 4.9, + "short": "Amsterdam", "offset": { - "dx": 0, - "dy": 22, + "dx": 11, + "dy": -25, "anchor": "start" }, "count": 1, "people": [ { - "login": "vgmartinez", - "avatar": "https://avatars.githubusercontent.com/u/10614247?v=4&s=64" + "login": "vivekchand", + "avatar": "https://avatars.githubusercontent.com/u/987905?v=4&s=64" } ], "more": 0 }, { - "label": "Amsterdam, Netherlands", - "country": "Netherlands", - "lat": 52.37, - "lng": 4.9, - "short": "Amsterdam", + "label": "Tampa, USA", + "country": "United States", + "lat": 27.95, + "lng": -82.46, + "short": "Tampa", "offset": { - "dx": 12, - "dy": 23, + "dx": 11, + "dy": 4, "anchor": "start" }, "count": 1, "people": [ { - "login": "vivekchand", - "avatar": "https://avatars.githubusercontent.com/u/987905?v=4&s=64" + "login": "zwright8", + "avatar": "https://avatars.githubusercontent.com/u/24713584?v=4&s=64" } ], "more": 0 } ], - "cities": 21, - "countryCount": 16, + "cities": 27, + "countryCount": 20, "regions": [ { "name": "Asia", - "count": 15, - "percent": 27 + "count": 19, + "percent": 25 }, { - "name": "North America", - "count": 9, + "name": "Europe", + "count": 12, "percent": 16 }, { - "name": "Europe", - "count": 7, - "percent": 12 + "name": "North America", + "count": 11, + "percent": 15 }, { "name": "Oceania", "count": 3, - "percent": 5 + "percent": 4 }, { "name": "South America", "count": 2, - "percent": 4 + "percent": 3 }, { "name": "Africa", "count": 1, - "percent": 2 + "percent": 1 }, { "name": "Others", - "count": 19, + "count": 27, "note": "Contributors whose GitHub profile does not say where they are.", - "percent": 34 + "percent": 36 } ] } diff --git a/data/worldmap.json b/data/worldmap.json index b987d25..19218e3 100644 --- a/data/worldmap.json +++ b/data/worldmap.json @@ -1,9 +1,64 @@ { - "source": "https://cdn.jsdelivr.net/npm/world-atlas@2/land-110m.json", + "source": "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json", "license": "Natural Earth, public domain", "width": 1000, "height": 394.4, "k": 2.7777777777777777, "latTop": 84, - "land": "M312 383l3 2 4 0-1 2-3 0-1-1-1 1-2 1-3-1-2 0-3-1-4-1-3-2-3-3 2 1 4 2 3 1 2-2 1-2 2-1 2 1 1 1ZM337 375l3 2-5 1-1-1-3 2-1-2 3-1 3 0ZM695 371l-4 1 0-2 0-1 2 0 3 1ZM904 347l3 1 1-1 2 0 2 0 0 3-1 3-3 2-2-1-2-2 0-2-2-2 0-2ZM981 347l0 1 2-1 1 1 0 1-1 2-2 2-1 1 1 1-2 0-3 1 0 2-2 3-2 1-2 1-2 0-2-1-3 0 0-1 1-2 4-3 1-1 2-1 3-1 1-2 2-2 1 0 0-2 2-1ZM985 334l2 3 0-2 1 1 1 2 2 1 2 0 1-1 2 0-1 3-1 1-2 0 0 2-2 2-1 2-2 1-2-1 2-2-1-2-3-1 0-1 2-1 0-2 0-2-1-2-1-1-2-3-1-2 1 0 1 2 2 0ZM964 295l-1 1-1-1-2-1-2-2-2-2 2 0 2 1 3 3ZM995 281l1 3-2 0-1 0-1-1 2-1 1 0ZM0 279l0-1 0 1ZM1000 279l-2 1-2 1 0-1 1-1 3-1 0 1ZM966 279l-2-1 0-1ZM964 275l1 2-2 0 0-3ZM639 271l0 3 1 2 0 1-1-1 0 3-1 1-1 3-1 3-1 4-2 6-1 3-1 4-2 0-3 1-1 0-3-1 0-2-1-2-1-2 0-2 1-2 1-1 1-3 1-2-1-1-1-2 0-2 1-2 0-2 2 0 1 0 1-1 2 0 1-1 3-2 0-2 0-1 1 1 2-2 0-2 1-1 1 1 0 1ZM899 272l1 2 2-1 0 1 2 1 0 1 0 3 1 1 1 3 0 1 1 2 3 1 2 2 1 1 2 2 1 3 1 0 1 1 1 3 2 1 1 1 3 3 0 2 0 1 0 2 2 2-1 3 0 1-1 3 0 1 0 2-2 3-2 1-1 2-1 2 0 2-1 1-1 2 0 2-2 2-3 0-3 1-1 2-2 1-2-1-2-1 1-1-2 0-2 2-2-1-2 0-2 0-2-1-2-2-1-2 0-1-2-1-2-1 1-1-1-2-1 2-3 0 2-1 0-2 1-1 0-2-2 2-2 1-1 2-2-1 0-1-2-2-2-1-3-3-2 0-2-1-5 0-4 1-3 1-3 0-3 1-2 1 0 1-2 1-2 1-2 0-2-1-2 1-2 0-2 1-2 1-1 1-2 0-2 0-3-2-1-1 0-1 1-1 0-1 1-2-1-2-1-3-1-1 1-2-2-2-1-2 0-2-2-2 0-1 1 1-1-2 1 0 1 1 0-1-1-2-1-2 0-2 1-2 0-1 1-2 0 2 1-2 3-1 1-1 2-1 1 0 3-1 2 0 1-1 2 0 3-1 1-1 1-2 2-1 0-1 0-2 2-2 1 2 1 0-1-2 1-1 1 1 0-2 2-2 1-1 1 0 1-1 2-1 1 0 2 1 2 2 1 0 2 0-1-2 2-2 1-1 1-2 2-1 1 1 2-1 0-1-2-1 2-1 1 1 2 1 2 1 3 0 1 0 1 0 2 1 0 1-1 1-1 1-1 2-1 1 3 3 2 0 1 1 2 2 2 1 3 2 2-1 1-2 0-1 1-2 1-2-1-1 0-3 0-2 1-1 0-2 1-1 1-2 1 1 0 2 1 2 1 1 0 2ZM950 262l-1 1-1-1 2 0ZM835 262l-1 0-4-2 3-1 2 1 0 1ZM947 261l-1 0-2 0 0-2 1 0 1 1ZM949 260l-2-2-1-2 2 3ZM846 261l-3 1 0-1 1-2 3-1 3-1 2 0 2 0-1 0-3 2-3 0ZM827 256l1 1 2-1 1 2-3 0-2 0-2 0 1-1 2 0ZM841 256l0 1-4 1-4 0 0-1 2-1 2 1 2 0ZM944 256l-2 0-1-1-2-1 2 0 2 2ZM938 254l-2-1-1-1 1 1ZM802 252l5 0 1-1 5 2 1 1 4 1 3 2-3 1-3-1-2 0-3-1-3 0-3-1-2 0-1 0-5-1-1-1-2-1 2-2 3 0 2 1 1 0ZM874 251l-1 1 0-2 1-2 0 1ZM933 252l-2-1-1-1-1-2 2 1 1 2 1 0ZM922 249l-1 0-2 1-2 1-1 0-2-1-2-1 3 0 1 0 1-2 0 2 2-1 2-1 0-2 2 0 0 2ZM853 243l-1 1-1-1-1-1 3 0ZM862 242l1 2-2-1-2 0-2 0-2 0 1-2 3 0ZM925 246l-1-1-1-1-1-1-1-1-2-1 2 0 2 1 1 2 1 0ZM873 237l0 4 3 2 3-3 3-2 2 0 3 1 2 1 3 1 4 1 6 2 2 1 1 2 1 2 4 1 1 2-3 0 1 2 2 2 2 3 2 0 0 1 2 0 2 2-2 1-3-1-3-1-2-1-2-2-1-2-4-1-2 0-2 1 0 2-2 1-1 0-3 0-3-3-3 0-4 1 1-3 2 0-1-3-1-3-5-2-3 0-4-3-1 2-1 0 0-1 0-1-2-2 3-1 2 0-5-1-1-1-2-1-1-1 3-1 2-1 4 1ZM848 229l-2 3-2 1-3-1-5 0-2 1-1 2 3 2 1-1 6-1-1 1-1 0-1 2-2 1 2 3 2 4 0 2-1 1-1-1 1-2-3 1 0-2-2-2 0-2-2 0 0 4 1 4-2 0-1-1 0-2 0-3-1 0-1-2 1-2 0-2 2-4 0-1 3-2 2 1 3 0 4 0 2-2ZM857 230l0 3-1-1-1 2 2 1-2-1-1-3 0-3 1-1 1 2 1 0ZM794 250l-3 0-2-3-4-2-1-2-2-2-2-2-2-4-2-2-1-3-1-2-3-1-1-3-2-1-3-3 0-2 1 0 5 1 2 2 2 2 2 2 3 3 2 0 3 1 1 3 2 1-1 2 2 1 1 0 0 2 1 2 2 0 2 2-1 3ZM827 228l4 3-4 0-1 2 0 3-2 1 0 3-1 4-4 1-1-2-2 0-1-1-4 1-1-1-2 0-2-1 0-3-2-1-1-2 0-3 0-2 2-2 2 1 2-1 0-2 2-1 3 0 2-2 1-2 1-1 3-2 2-2 1-2 1 0 2 1 0 2 2 0 2 1 0 1-2 1 0 1-2 1-1 2 2 3ZM851 210l0 2 0 1 0 3-1-3-2 1 1 3-1 1-3-2-1-2 1-1-2-1-1 1-1 0-2 1 1-3 2-1 1-1 1 1 2 0 1-2 2 0-1-2 3 2 0 1ZM726 216l-3 1-1-2-1-4 2-5 2 2 1 2 1 2 0 3ZM331 205l-3 1 1-1 0-2 1 0 1 0ZM844 205l-1 1 0 1-3-1 1-1 1-2 1 0 0 2 2-3ZM829 207l-4 3 2-2 2-2 2-1 1-3 0 2-1 2ZM839 200l1 1 2 0 0 1-1 1-2 1 0-1 0-1ZM849 200l0 3-2-1 1 3-1 0 0-2-2-2 2 1 0-1-2-3 3 1ZM838 197l-1 2-1-1-2-2 3 0ZM837 182l2 1 1 0-1 1 1 2 0 2-2 1 0 2 0 3 2 0 1 0 3 1 0 2 1 2-3-2-1-1 0 1-2-2-3 0-1 0 0-1 0-2 0 1-1-1-1-1 0-3 1 1 0-5 1-2ZM318 183l-3 0-2 0 0-1 3 0 1 0ZM286 184l-2 0-2-1 2-1 2 0 2 1 0 1ZM298 178l3 1 2-1 2 1 1 1 2 0 1 1 1 1-1 1-1-1-1 0-2 1-1 0-1 0-1 1-1-1-2 0-1 0-2 0-1 0-2-1 3 0 2 0 1-1-1-1 0-1-2 0 1-1ZM806 181l-2 2-2-1 0-2 1-2 3-1 2 1 0 1-1 1ZM68 180l-1 0-1-1 1-2 1 1 2 1-1 1ZM66 176l-1 0 2 0ZM65 175l-2 0 0-1ZM62 174l-1 0 0-1ZM57 172l-1 0 1 0ZM279 170l1 1 2 0 4 2 1 1 3 1 2 1 2 1-2 1-2 0-2 0-4 0 2-1-1-1-2 0-2-3-1 0-3 0-4-1 0-2-3 0-2 2-1 0-2 1-1 0 1-1 1-1 1-1 2-1 2 0 3 0 2 0ZM285 167l-2-1-1-1 1-2 2 3ZM837 170l-2 2-1-2 0-2 1-3 2-2 2 1-1 2ZM284 159l-3 1 0-1 1 0 2 0ZM286 159l0 2-1-1-1-1 0-1ZM874 138l-1 3-1-1-2 1-1 1-1 0 0-2 1-1 2 0 1-1ZM596 134l-2 1-2 2-2 0 0-1 1 0 3-1ZM566 134l1 1 3 0 2 0 1 0-4 1-4-1ZM543 127l-1 2 0 3-2-1-2-1-3-1 0-2 3 1 3-1ZM526 119l1 2 0 4-1-1-2 1-1 0 0-4 0-1 1 0ZM892 130l-1 2 0 2-1 2-4 1-5 0-4 3-2-1 0-2-5 1-3 1-3 0 3 2-2 5-2 1-1-1 0-2-1-1-2-2 3-1 2-2 2-1 2-2 6-1 3 1 3-5 2 1 4-3 1-1 2-3 0-3 1-2 3-1 1 4 0 2-2 3ZM527 116l-1 2-2 0 0-2 0-1 2-1ZM900 111l2 0 2-1 0 3-4 1-2 3-5-2-1 3-3 0-1-3 2-2 3 0 1-4 0-2 4 3ZM323 104l2 0 3 0-2 1-1 1-3-2 0-1ZM328 97l-1 0-4-1-2-1 4 0 3 1ZM157 99l-1 0-5-1-3-2-4-2-1-1 3 0 2 0 3 1 2 2 3 1ZM344 93l-2 2 2-1 2 1 1 1 2 0 2 1 0 2 2-1 0 2 1 1-1 3-2 0-1-1 0-2-4 2-2 0 2-1-2-1-3 0-6 0 2-2-2 0 3-2 3-5 1-1 3-1 1 0 0 1ZM131 83l3 0-1 3 3 2-1 0-2-1-1-1-2-1 0-1 0-1ZM899 92l3 5-4-1-2 4 3 3 0 2-2-2-2 3-1-3 0-2 0-3 1-2 0-4-2-3 1-4 2-1-1-1 1-1 1 2 1 3 0 3ZM481 88l-5 2-4-1 3-3-2-2 4-3 2-1 2 0 3 2-1 2 0 2ZM535 79l-1 2-3-1-1-2 4-1ZM75 75l-3 1-1-1-1-1 3-1 1-1 2 0 1 1ZM492 70l-3 3 3 0 3 0-1 2-3 3 3 0 3 4 2 0 2 3 0 1 4 1-1 2-1 0 1 2-2 1-4 0-5 1-1 0-2 1-3-1-2 2-1-1 4-3 3-1-5 0-1-1 3-1-1-1 0-2 4 0 1-2-2-1-3-1 0-2-3 1 0-3-1-1 1-3 2-3 2 1ZM40 67l-2 0-1 0-2-1 3 0 2 0ZM280 61l-1 1-1 0-1-1 1-1 1 0ZM273 59l-4 2-2 0 2-2 4 0ZM23 56l2 1 1-1 3 1 2 1-2 0-2 0-1-1-3 0ZM263 51l1 1 1 0 2 0 3 1 3 1 0 2 3-1 1 1-2 1-4 0-2-2-3 2-4 1-1-1-3 0 2-2 0-2 1-2ZM460 49l-1 2 3 1-3 3-8 1-3 1-3 0-8-1 3-2-7-1 5 0-6-2 2-2 5 0 4 2 4-2 4 1 4-1ZM289 47l-3 0-1-1 2-2 2 0 2 0 0 2ZM0 42l7 2 7 3 0 1 2 1-1-2 8 0 5 3-3 1-4 1 0 2-1 1-3 0-2-1-4-1 0-1-3-1-3 1-2-1 1-1-4 0 2 2-2 1 0-11ZM1000 42l0 11-4 1-3 0 2 1 2 3 1 0 1 2-6 0-8 2-3 0-4 2-4 2-1 1-4-2-7 2-1-1-3 1-4 0-1 2-3 3 0 1 3 0 0 4-3 0-1 3 1 1-5 1 0 4-5 0 0 3-4 3-2-2-1-4-1-7 1-3 2-2 1-1 4-1 5-3 5-3 5-3 2-3-4 0-1 2-7 3-2-3-8 1-7 4 3 2-7 1-4 0 0-2-4 0-3 1-9 0-9 0-9 6-11 6 5 1 1 1 3 1 2-1 3 0 4 3 0 2-2 3-1 3-1 5-4 4-1 2-4 3-4 3-1 2-4 1-2 0-2-1-3 2-2 1-1 1-1 3-1 0-2 2-2 0-1 1 0 1 3 2 2 3 1 2 0 3-1 2-3 0-2 2-3 0 0-2 1-2-2-3 2 0-2-3-1 0-1 1-2-2 1-1 1-2-2-1-1-1-4 1-2 2-3 0 2-1-1-1 2-2-1-1-3 1-3 2-1 1-3 0-2 2 2 2 2 0 0 1 3 1 3-2 2 1 2 0 0 2-4 1-1 1-3 1-1 2 3 2 1 3 2 2 2 2 0 2-2 1 1 2 1 0 0 3-1 2-2 0-2 3-2 4-2 3-4 3-4 2-3 0-2 2-2 0-4 1-3 1-1 3-2 0 0-2 0-1-4-1-1 0-4 3-2 2 0 2 2 3 2 4 3 2 1 2 2 5-1 5-2 2-3 2-2 2-4 2-1-1 1-2-2-2-3 0-1-2-1-3-3-1-2 0 0-2-2 0 0 3-2 4-1 3 1 2 1 0 2 2 0 3 2 1 1 1 2 1 2 2 1 2 0 2 0 1 1 3 2 3-2 1-3-2-3-2-1-2-1-2-1-2-1-1 1-2-1-2-1-1-1-1-1-2-1-1-1 2 0-2 0-2 1-2-1-2 1-2-1-2 1-3-1-2-1-3-1-3-1-3-2 2-3 2-2-1-1 0 1-4-1-2-2-3 0-1-1-1-2-2-1-2 0-1-1-1-1-2-3 0 1 1-1 2-1-1-2 0-1 0 0 1-2 0-3 1 0 2-2 1-4 2-3 3-2 2-3 2 0 1-1 1-3 1-1 0-1 2 1 4 0 2-1 3 0 5-2 0-1 2-2 2 0 1-2 1-2-2-2-4-1-3-1-1-1-3-1-4 0-1-3-4-1-5-1-4 0-3 0-3-4 2-2-1-4-3 1-1 0-1-4-2-2-1 0-2-3-2-5 0-4 0-4 1-5-1-3-1-4 0-1-4-1 0-2 0-3 2-3-1-3-2-3-1-2-3-2-3-1 0-2-1-1 1-2 0 1 1 0 3 2 2 1 1 2 2 0 1 1 2 1 2 0-1 1-2 1 1 0 1 0 2 0 1 3 0 2 0 2 0 2-2 2-1 2-2 1-1 0 1 0 3 1 2 1 1 2 0 2 1 1 1 2 2-1 2-1 2-2 2-1-1-1 3 1 1-2 1-2 1 0 1-2 1-1 0 0 1-2 1-1 0-2 1-1 0-2 1-1 1-3 2-4 1-3 2-1 1-2 1-2 0-3 0-1 1-1 1-1 0-3 0-1-1 0-2-1-3-1-1 1-1 0-2-1-1-1-2-1-1-1-3-1-2-2-2-1 0-2-3-1-2 1-1-2-3-1-2-2 0-1-2 0-2-2-2-2-3-1-2-2 0 1-1 0-2-1 3-1 1-2 0-1-2-2-4 1 4 2 2 2 5 1 1 1 2 2 3 0 2 3 3 1 3 0 3 1 4 1 0 2 1 1 4 1 2 2 1 3 3 2 2 1 1 3 2 0 2-1 1 1 0 1 2 2 1 1 0 3 0 3-1 2-1 1 0 3 0 2-1 2 0 1-1 1 0 0 2 0 2-1 1-1 3-1 3-2 3-2 5-2 3-4 3-2 3-5 2-2 3-3 3-1 1-2 2-1 1-1 0-1 2 0 2-1 1-1 1-1 4 0 1 2 1-1 3 0 2 1 2 1 2 1 1 0 1 0 3 1 2 0 5 0 1-1 2-1 2-1 2-3 1-3 1-3 3-1 1-2 2-1 0-1 2 2 2 0 2 1 3-1 2 0 1-1 1-2 1-3 2-2 1 1 1 0 2-1 2 0 2-1 1-1 2-2 1-1 2-2 2-3 3-2 1-2 2-3 1-1 0-2 0-1 1-3-1-2 1-1-1-3 1-3 1-1 1-2 0-1-1-2-1 0-2-1-2 1-3-2-2-2-3-2-3-2-2-1-2 0-3-1-2-1-4 0-4 0-1-1-1-2-3-1-3-1-2-2-2 0-3-1-1 1-3 1-2 0-2 1-2 0-1 2-2 1-1 0-2 0-2-2-3 0-1 1-2-1-3-1-1-1-2 0-2-1-2-2-3-3-2-2-3-2-3 1-1 1-2 0-2 1-4 0-2-1-2-1-1-1-1 0-1-3 1-1 0-1 1-3-1-1-1-1-2-2-2-2 0-3 0-2 0-2 1-4 1-2 1-2 1-3-1-1 0-2 0-2 0-3 0-2 1-3 1-1 0-3-1-3-2-2-2-2-2-3-1-1-1 0-1-1-2-1-2-1-1-1-1-1-1-1-1-2-1-1-1 0-1-1-1-1-2 1-1-2-3-1-1 1 0 2-2 0-1 0-2 1-1 0-3 0-3 0-1 0-1-1-2-1-1 0-1 0-1 1-1 1-2 1-3 1-1 2-2 0-2 1-2 2-1 2-2 1-2 3 0 2-2 1 0 2-3 0-3 1-3 0-1 2-2 3-1 2-1 2-3 1-2 2 0 1 1 3 0 3 1 1 0 3-2 3 0 1-2 3 0 5-1 4 0 2 0 2-1 3 0 1 1 2 0 3-1 2 0 0 1 3-1-2 2 0 1 1 4-2 1 1 1 1 1 1 1 1 0 3 1 1 0 3 0 3 2 2 2 2 1 4 1 3 1 1 0 2-2-1-2 1-1 2-2 2 0 4 1 1 1 1 0 3 1 5 1 2 0 3 1 1 1 2-1 2-1 2 0 2 0 1 1 3 0 2 0 1 0 1-1 1-2 0-2 2-3 1-2 0-2 0-1-1-1 1-1-1 0-3-1-1 2-5 0-2-1-3-1-1 2-2 0-2-2-3 1-2-3-2-2 1-2-1-1 3-3 4 0 1-2 6 0 3-2 3 0 5 0 5 2 4 1 3-1 2 0 3-1 1-1-1-2-1-1-2 0-1-1-4-3-3-1-2-1 2-1 2-2-1-1 4-1-3-1-2 1-2 1-2 0-3 1 0 2 2 0 2 0-3 2-4 1-1 0 0-2-3-1 3-1-5-1 0-1-3 0-1 1-2 3-1 1-2 3-1 1-1 2 1 2 0 1 3 1-4 0-1 1-3 2-1-1-1-1-2 0-3 0 2 2-2 0-1 0-2-1 0 2 2 1-1 1 1 1 2 1 0 2-3-1 1 1-2 1 1 2-2 0-2-1-1-2 0-2-1-1-2-2-1-2-1 0 0-2 0-2 0-1-2-1-1-1-2-1-2-1-3-1-2-2-1-1-1-1-1 1-1-2-1-1-3 1 0 2 1 2 3 1 1 3 3 2 2 0 0 1 3 1 2 1 2 1 0 2-2-2-2 0-1 2 2 1-1 1-1 0-1 3-1 0 0-2 0-3-1-1-1 0-1-1-2-1-1-1-2 0-2-2-3-1-2-2-1-3-1 0-2-1-2 0-1 2-1 0-3 2-5-1-4 1-1 1 0 2-2 2-4 0-2 3-1 2 1 2-1 1-1 2-2 0-2 2-3 1-3-1-2 1-1 1-1 0-1-1-1-1-3-1-1 1-1 0-2 0 1-2-1-2-1 0 0-1 0-2 1-1 0-1 1-2 0-1-1-2 0-2-1-1 4-2 3 0 4 0 3 1 2 0 5 0 1-2 1-5-3-3-2-2-4-1-1-2 4-1 5 1-1-3 2 1 7-2 1-2 2-1 2 0 2-1 2-4 4-1 2 0 3-1 2-1 0-1 0-1-1-2-1-3 2-1 2 0 3-2 0 1 0 2 1 1 0 1-3 1 1 2 0 1 2 0 3 1 2-1 3 1 1 1 2-1 4-1 4-1 3 0 3 1 0-1 4-1-1-2 1-2 1-2 3-1 2 2 2 0 1-2 0-2-1 1-2-1 0-2 3-1 4 0 3 0 3 0 3-1-3-2-5 0-5 2-4 0-2-1-3-1 1-3-2-3 2-1 2-2 7-3 2-1-1-1-4-1-4 1-3 2 0 1-4 3-5 2-2 4 2 2 2 1-2 4-3 0-1 5-2 2-3 0-2 2-3 1-1-3-2-3-2-4-2-2-6 3-3 1-4-1-1-3-1-7 2-2 8-2 5-3 5-4 7-5 5-2 7-4 6-1 5 0 4-2 5 0 5 0 9 2-4 0 3 2 3-1 5 2 7 0 11 4 2 1 0 2-3 1-4 1-13-2-2 0 5 2 0 4 4 1 2 1 0-1-2-2 2-1 7 2 2-1-2-2 7-2 2 0 3 1 2-2-3-2 2-1-2-2 7 1 2 1-3 1 0 1 2 1 4 0 1-2 6-2 9-2 2 0-2 2 3 0 2-1 5 0 4-1 4 2 3-2-3-2 1-1 8 1 4 1 10 3 2-1-3-2-3-1 1-1-2-2 5-3 2-3 2-1 8 1 0 2-2 2 1 1 1 2 0 4 3 1-2 2-5 4 3 1 1-1 3-1 1-2 2-1-1-1 1-2-3-1-1-1 3-3-4-2 5-2-1-2 2 0 1 2-1 2 3 1-1-2 4-1 6-1 5 2-2-2 0-3 4-1 7 0 6 0-2-1 3-2 3 0 6-2 7 0 8-1 3 0 6-1 5 0 1-1 2-1 7-1 5 0-4 1 6 1 1 1 2-1 9 0 6 2 2 1-1 1-3 1-7 1-2 1 3 1 4 0 3 0 1 2 2-1 4-1 9 1 1 1 11 1 0-2 6 0 5 0 4 1 1 2-1 1 3 3 5 1 2-3 5 1 5-1 5 1 2-1 5 1-2-3 3-1 25 2 3 1 7 3 11-1 6 0 2 2 0 2 3 0 4 0 5 0 5 0 5 0 5 3 3-1-2-2 1-1 9 0 6 0 8 2ZM636 119l2 2 1 0-1 1-1 2-1 2 0 1 1 2 2 1 2 1 4 0 5 0-1-3 1-3-2-1 0-2-2 0 1-2 3 0 2 0-2-2-1-2-2 1 0 2-1-2 0-2-3-1-2-3-1-1 2 0 1-2 2-1 2 1 1-3-1-2-2 0-3 0-3 1-3 0-1 2-3 1-2 2 2 3 0 2 3 3ZM234 41l-1 1-4-1-2 1-4-1 2-1 2-2 3 1 2 1 1 0ZM0 35l0 2 0-2ZM1000 35l0 2-3 0-1-1ZM0 35l3 0 4 0-3 1-4 1ZM1000 35l0 2ZM248 40l0 3 4-2 4 2-1 2 2 2 3-2 2-3 0-3 4 0 4 1 4 1 0 2-2 1 2 2 0 1-6 2-3 0-3-1-1 2-3 2-1 1-3 2-4 0-2 2 0 1-3 1-4 2-3 3-1 2 0 4 4 0 1 3 2 2 4-1 5 1 2 1 2 2 4 1 3 1 4 0 3 0 0 3 1 2 2 3 4 3 2-1 2-3-2-4-2-2 5-1 3-2 1-2 0-2-2-2-3-2 3-3-1-2-1-5 2 0 5 0 3 1 2-1 2 1 4 1 1 2 5 0 0 2 1 4 2 0 2 2 4-2 3-3 2-1 2 2 3 4 3 3-1 2 4 1 3 2 4 1 2 1 1 2 2 0 1 1 0 3-2 2-2 0-4 1-4 3-4 0-6 0-5 0-2 0-3 2-3 1-4 4-4 2 3 0 4-4 6-2 4 0 3 1-3 2 1 3 1 2 4 1 4 0 3-3 0 2 2 1-4 2-6 1-2 1-4 2-2 0 0-2 5-2-4 0-3 0-3 2-3 1-3 1-1 2-1 2 1 1 1 0 0-1 1 2-2 0-2 0-2 1-1 0-1 0-3 1 4-1-3 1-2 0 0 3-2 2-2-1 1 1 1 2-1 1-2 2 1-2-2-1 0-2-1 1 1 2-2-1 2 1 0 3 1 1 1 3-2 2-3 0-2 2-1 0-2 1-3 3-2 1-1 2 0 2 0 2 1 2 1 2 0 1 2 4 0 2-1 1 0 1-2 0-1-1-1-1-1-2-2-2 0-1 0-2 0-2-3-2-1 0-2 1-2-1-2-1-3 0-3 0-2 0-1 1 1 1-2 1-2 0-3-1-2 0-2 0-2 0-2 0-3 3-2 1-2 1 0 1 0 2 0 2-1 3 0 2-1 4 0 1 1 2 0 1 1 2 2 2 1 2 1 1 3 1 1 1 2-1 2 0 2-1 2 0 2-1 1-2 0-2 2-2 3 0 3 0 1-1 1 2-2 2 0 2 0 1-1 3-1-1 0 1 0 1 0 2 0 1-1 1 0 2 1 0 2-1 2 1 1-1 1 0 2 0 1 0 1 0 1 1 2 1 1 1 0 2-1 2 0 1 0 2-1 1 0 2 1 1 0 1 1 2 2 1 1 1 1 0 1 1 1 0 1-1 2-1 2 0 2 0 1 1 2 1 2 0 2-2 1 0 0-3 2-1 2-1 2 0 2-1 1-1 2-1 1 1 0 1-2 1 1 1 0 1-1 2 1 2 1 0 1-2-1-3 3-1 0-2 2 2 2 0 1 1 3 1 3 0 2 1 2 0 1-1 4 0 3 0-2 0 1 2 2 0 2 1 0 2 2 0 1 1 2 1 2 2 0 1 1 0 1 2 1 1 4 0 2 0 3 0 3 1 3 3 1 1 1 1 2 5 1 1 0 1-2 3 6 1 0 3 2-2 4 1 4 2 2 1-1 2 3-1 6 1 4 0 4 3 4 3 2 1 2 0 1 1 1 3 1 2-2 4-1 2-4 4-2 3-2 3-1 2 0 5-1 4 0 2-1 1 0 4-3 3-1 3-2 1-1 2-3 0-4 1-2 1-3 1-3 2-3 3 0 2 0 2 0 3-1 1-2 2-3 4-2 3-2 1-1 3-2 1-1 2-4 1-2 0-1 0-3-1-2 0-1-1 0 1 3 2 0 2 1 1 0 2-2 3-5 2-5 0-3 0 0 2 0 2 0 1-1 1-3 1-3-1-1 0 1 3 1 1 2-1 1 2-3 0-2 2 0 3-1 1-3 0-2 2-1 2 3 2 3 1-1 2-4 2-1 3-3 1-1 1 1 3 2 2-1 0-3 0-1 0-3 1 0 3-1 0-4-1-3-2-3-1-1-2 1-2-2-2 0-4 1-3 3-2-4-1 3-3 0-4 4 1 1-6-2-1-1 4-1-1 0-4 1-5 2-2-1-2 0-3 1-1 1-4 2-4 2-5-1-4 1-2-1-3 2-4 1-5 0-6 1-6 0-5 0-4-3-1-1-1-5-3-5-3-2-2-1-2-2-5-3-5-3-5-1-2-1-2-2-1-2-2 1-1-1-3 1-1 2-2 1-2 0-1-1 1-2-1 0-4 2-2 1-2 0-1 1 0 2-2 1-1-1-1 1-1 2 0 1-2 1-1-1-1 0-2 0-2 0-3-1-2-2-2 0-2-2-1-1 1-2 1 1 2-1 1-2 0 0-1-1 0-1-1-1 0-2-1-2 0 0-1-1-1-1-1-1-1-1 1-2-1 0-2-1-1 0-1-1-1-2-2-2-2 1-1-1 1-2 0-1-1-1 0-1 0-3-1-1 0-2-1-1-1-3-3-2-1-2-1-2 1-2 1-1 0-2-1-2 0-3-2-2 0-3-1-2-2-3-1-2 0-2-2-3-1-1-2-1-1 1-1 1-2-1-1-1-2-1-1-2-3-3-2-1-2-2-1-1-2-1-1-2-1 0-2-2 0-1-2-2-1-1-3-1-2 0-1-2-1-3-1 0 1 0 1 0 3 1 1 2 2 2 1 1 2 1 2 2 1 1 3 1 1 0 1 1 2 1 0 1 1 1 1-1 2-1-2-2-1-2-2-2 0 0-2 0-2-1-1-2-1-1 0-2-1-2-2 2 0 1-1 0-1-2-2-2-1-1-2-1-1-1-3-1-2-1-1-2-2-1 0-2-1-1-1-2 0-1-2-3-3-2-4-2-2-2-2 0-2-2-2 1-2 0-2-1-2 1-3 1-5-1-4-1-2 0-2 4 1 1 3 1-4-1-2-6-3-2-1-5-1-2-2 1-2-4-1 0-2-4-2 0-2-1-1-3-1 0-2-4-2-1-3-3 0-5 0-3-1-6-3-2-1-5-1-4 1-5-2-4-1-3 1 1 2-2 0-3 0-2 1-3 1-1-2 1-2 3-1-4 1-2 1-4 2 2 2-2 2-3 1-3 1-1 1-4 1-1 2-3 1-2 0-3 1-3 0-2 1-5 1 3-2 3 0 3-2 3 0 1-1 4-2 3-2 0-2 2-1-3 1-3 0-2-1-1-1-3 1-2 0 0-1 0-1-1-1-4 0-2-1-2-1 0-1-2-1 1-2 2-2 1-1 2 0 2 0 2-1 2 0 2-1 0-1-2-1 2-1-1 0-3 1-3 0-4 0-4 0-1-1-4-2 4-1 6-2 2 0 0 2 6 0-2-2-4-1-2-1-2-2-4-1 1-1 5 0 4-1 0-2 3-1 3 0 5-2 3 1 4-2 4 1 2 1 2-1 4 1 4 1 3-1 6 1 5 1 2 0 4-1 4 1 3 1 6 0 4 2 3 0 2-1 4-1 4 0 4-1 4-1 2 2 2-1 1-1 2 0 5 2 3-2 1 3 3-1 1-1 4 0 4 2 6 1 4 0 3 0 4 1-4 2 5 0 7 0 3-1 3 2 3-1-3-1 2-1 3 0 2-1 2 1 3 1 3 0 5 1 4 0 5 0-1-2 3 0 4 1 0 2 2-2 2 0 1-3-3-1-3-1 0-3 4-2 3 0 3 1 4 3-3 2ZM183 30l-2 2 7-1 4 1 3-1 2 1 2 2 2-1-2-3 2 0 3 0 3 1 2 3 1 2 4 2 6 1-1 1-4 0 1 1-1 1-5 0-4-1-4 0-5 1-8 1-4 0-1-1-4-1-3 0-3-2 2 0 4-1 4 0 4 0-6-1-6 0-4 0-1-1 6-1-4 0-5 0 3-3 2-1 7-1ZM210 29l-3 2-4-2 5 0ZM288 30l-3 1-3 0-3 0-4-1 0-1 2-1 6 1ZM260 30l2 2 2-2 7-2 5 3 0 2 5-1 3-1 6 2 4 1 0 1 5 0 3 1 7 1 2 2 3 2-5 1 6 2 5 1 4 2 4 1-1 2-5 3-3-1-4-3-4 0 0 2 3 1 3 2 2 0 1 3-1 2-3-1-7-2 4 3 3 1-7 0-6-1-4-2-3-2-4-1-8 1-2-1 2-2 5 0 6 0 0-3 3-3-1-1-1-1-4-1-6-1 2-1-3-1-2-1-2-1-2 1-5 1-10-1-6-1-4 0-3-1 3-1-4-1-1-2 3-3 2-1 8-1ZM221 28l4 1 5-1-2 3 4 1-1 2-4 1-3 0-2-1-7-2 6-1-3-1ZM899 30l-4 0-6 0 2-2 4 0 4 1ZM241 31l-3 2-3 0-2-2 0-2 2-1 2-1 6 0 6 1-5 3ZM165 35l-7 1-1-1-7-1 3-4 3-1-3-2 9 0 4 0 7 0 3 1 3 1-3 1-7 2-4 2ZM919 25l-4 1-4 0-5-1 6-1ZM240 25l-2 1-4 0-3-1 2-1 4-1 2 1ZM903 23l-2 2-10 0-5 1-6-2 2-2 4 0 7 0ZM226 20l3 2 0 1-2 2-4 0-3 0 0-2-5 0 0-2 3 0 4-1 4 1ZM199 22l2 1 2-1 3 0 0 2-1 1-10 0-7 2-4 0 5-2-12 0-4-1 4-2 2-1 8 1 5 1 5 1-4-3 3-1 2 0ZM660 37l-2 0-9 0-1-1-5-1 0-2 3 0 0-2 5-2-2-1 6-2 0-1 6-2 9-1 9-1 5-1 5 0 2 1-2 1-9 1-9 1-9 3-4 3-4 2 1 3ZM237 19l3 1 6 0 2 1-1 1 3 1 2 0 4 0 4 1 4-1 6 0 5 0 3 1 0 1-1 1-5 1-3-1-8 1-6 0-4-1-8-1-1-1 0-1-3-2-6 0-3-1 1-1ZM177 18l0 2-2 1-3 0-5 1-4 1-4-1 4-2 6-2 4 0ZM239 18l-1 0-5 0 5-1 2 1ZM194 18l-5 0-4-1 2 0 4-1 4 1ZM569 17l-7 1-4 0 1-1-1-1 6-1 1 1ZM195 15l-3 1-5 0 3-2 2 0ZM234 17l-4 0-3-1-1-1 0-1 4 0 1 1 4 1ZM222 16l1 1-4 0-5-1-6 0 3-1-4-1 0-1 5 0 8 1ZM792 16l-16 1 5-4 3 0 2 0 7 2ZM551 12l9 2-7 1-2 2-2 1-1 2-4 0-6-2 3-1-4 0-6-3-2-2 8-1 1 1 4 0 1-1 4 0ZM571 10l5 1-4 1-8 1-8-1-5-1-3-1 9-1 4 1 3-1ZM642 10l-4 0-2 0-4 1-3-1 2 0-6-1 5 0 4 0 2 0 3 0 4 0ZM778 14l-6 1-8-1-5-1-2-2-4-1 7-2 6 0 6 1 6 3ZM258 12l4 1-4 1-5 2-5 0-6 0-3-1 0-1 2-1-5 0-3-1-2-1 2-2 2 0 3-1-1 0 6 0 4 1 5 1 4 0ZM310 2l7 1 6 0 5 1-7 2-6 0-3 1 6 0-6 2-5 0-5 3-5 0-2 1-9 0 4 0-2 1 3 1-3 1-4 1-2 1-4 1 6 0-8 3-7-1-8 0-4 0-6 0 0-1 5-1-1-2 2 0 7 1-4-2-4 0 2-1 5-1-3-2-1-2 7 1 2 0 5-1-7 0-9 0-5-1-3-1-3-1 4-2 3 0 5 0 5-1 3 0 3 1 2-2 4 0 5-1 8 0 2 1 8-1 6 0ZM425 1l17 3-5 1-11 0-15 0 2 0 10 0 8 1 5-1 3 1-3 2 7-1 13-1 9 0 1 2-11 2-2 0-9 1 7 0-3 2-3 2 0 3 4 1-5 1-4 0 5 2 1 2-3 1 3 2-6 0 3 1-5 2-3 0 3 2 0 1-5-1-2 0 4 1 4 2 1 2-5 1-3-1-3-2 1 2-3 1 7 0 4 1-8 2-7 2-8 1-3 0-3 1-4 3-6 2-2 0-4 1-4 1-2 1 0 2-1 2-5 2 1 2-1 3-1 2-4 1-5-3-5 0-3-1-2-3-4-3-2-2 0-3-4-2 1-2-2-1 3-4 4-1 1-1 1-2-3 1-2 0-2 1-4-1 0-2 1-1 3 0 5 0-5-1-2-1-3 0-2-1 3-2-2-1-2-2-3-3-4-1 0-1-7-2-6 0-8 0-6 0-4-1-4-2 7 0 6-1-12 0-7-1 1-2 10-1 10-1 2-1-8-1 2-1 10-2 4-1-1-1 7-1 8 0 9 0 3 1 7-2 7 1 4 1 5 0-6-1 0-1 9-2 10 0 4-1 10 0Z" + "land": "M995 282l1 0 0 2-2 0-1 0-1-1 2-1ZM0 278l0 1 0-1ZM1000 278l0 1-2 1-2 1 0-1 1-1 3-1ZM609 246l-1 4 0 1 2 1-1 3 0 2 1 2 1 2 1 1 0 1 0 3 1 2 0 5 0 1-1 2-1 2-1 2-3 1-3 1-3 3-1 1-2 2-1 0-1 2 2 2 0 2 1 3-1 2 0 1-1 1-2 1-3 2-2 1 1 1 0 2-1 2 0 2-1 1-1 2-2 1-1 2-2 2-3 3-2 1-2 2-3 1-1 0-2 0-1 1-3-1-2 1-1-1-3 1-3 1-1 1-2 0-1-1-2-1 0-2-1-2 1-3-2-2-2-3-2-3-2-2-1-2 0-3-1-2-1-4 0-4 0-1-1-1-2-3-1-3-1-2-2-2 0-3-1-1 1-3 1-2 0-2 1-2 0-1 2-2 1-1 0-2 0-2-2-3 0-1 1-2-1-3-1-1-1-2 0-2-1-2-2-3-3-2-2-3-2-3 1-1 1-2 0-2 1-4 0-2-1-2-1-1-1-1 0-1-3 1-1 0-1 1-3-1-1-1-1-2-2-2-2 0-3 0-2 0-2 1-4 1-2 1-2 1-3-1-1 0-2 0-2 0-3 0-2 1-3 1-1 0-3-1-3-2-2-2-2-2-3-1-1-1 0-1-1-2-1-2-1-1-1-1-1-1-1-1-2-1-1-1 0-1-1-1-1-2 1-1-2-3-1-1 1 0 2-2 0-1 0-2 1-1 0-3 0-3 0-1 0-1-1-2-1-1 0-1 0-1 1-1 1-2 1-3 1-1 2-2 0-2 1-2 2-1 2-2 1-2 3 0 2-2 1 0 2-3 0-3 1-3 0-1 2-2 3-1 2-1 2-3 1-2 2 0 1 1 3 0 3 1 1 0 3-2 3 0 1-2 3 0 5-1 4 0 2 0 2-1 3 0 1 1 2 0 3-1 2 0 0 1 3-1-2 2 0 1 1 4-2 1 1 1 1 1 1 1 1 0 3 1 1 0 3 0 3 2 2 2 2 1 4 1 3 1 1 0 2-2-1-2 1-1 2-2 2 0 4 1 1 1 1 0 3 1 5 1 2 0 3 1 1 1 2-1 2-1 2 0 2 0 1 1 3 0 2 0 1 0 1-1 1-2 0-2 2-3 1-2 0-2 0-1-1-1 1-1-1 0-3-1-1 2-5 0-2-1-3-1-1 2-2 0-2-2-3 1-2-3-2-2 1-2-1-1 3-3 4 0 1-2 6 0 3-2 3 0 5 0 5 2 4 1 3-1 2 0 3-1 1-1-1-2-1-1-2 0-1-1-4-3-3-1-2-1 2-1 2-2-1-1 4-1-3-1-2 1-2 1-2 0-3 1 0 1 2 1 2 0-3 2-4 1-1 0 0-2-3-1 3-1-5-1 0-1-3 0-1 1-2 3-1 1-2 3-1 1-1 2 1 2 0 1 3 1-4 0-1 1-3 2-1-1-1-1-2 0-3 0 2 2-2 0-1 0-2-1 0 2 2 1-1 1 1 1 2 1 0 2-3-1 1 1-2 1 1 2-2 0-2-1-1-2 0-2-1-1-2-2-1-2-1 0 0-2 0-2 0-1-2-1-1-1-2-1-2-1-3-1-2-2-1-1-1-1-1 1-1-2-1-1-3 1 0 2 1 2 3 1 1 3 3 2 2 0 0 1 3 1 2 1 2 1 0 2-2-2-2 0-1 2 2 1-1 1-1 0-1 3-1 0 0-2 0-3-1-1-1 0-1-1-2-1-1-1-2 0-2-2-3-1-2-2-1-3-1 0-2-1-2 0-1 2-1 0-3 2-5-1-4 1-1 1 0 2-2 2-4 0-2 3-1 2 1 2-1 1-1 2-2 0-2 2-3 1-3-1-2 1-1 1-1 0-1-1-1-1-3-1-1 1-1 0-2 0 1-2-1-2-1 0 0-1 0-2 1-1 0-1 1-2 0-1-1-2 0-2-1-1 4-2 3 0 4 0 3 1 2 0 5 0 1-2 1-5-3-3-2-2-4-1-1-2 4-1 5 1-1-3 2 1 7-2 1-2 2-1 2 0 2-1 2-4 4-1 2 0 3-1 2-1 0-1 0-1-1-2-1-3 2-1 2 0 3-2 0 1 0 2 1 1 0 1-3 1 1 2 0 1 2 0 3 1 2-1 3 1 1 1 2-1 4-1 4-1 3 0 3 1 0-1 4-1-1-2 1-2 1-2 3-1 2 2 2 0 1-2 0-2-1 1-2-1 0-2 3-1 4 0 3 0 3 0 3-1-3-2-5 0-5 2-4 0-2-1-3-1 1-3-2-3 2-1 2-2 7-3 2-1-1-1-4-1-4 1-3 2 0 1-4 3-5 2-2 4 2 2 2 1-2 4-3 0-1 5-2 2-3 0-2 2-3 1-1-3-2-3-2-4-2-2-6 3-3 1-4-1-1-3-1-7 2-2 8-2 5-3 5-4 7-5 5-2 7-4 6-1 5 0 4-2 5 0 5 0 9 2-4 0 3 2 3-1 5 2 7 0 11 4 2 1 0 2-3 1-4 1-13-2-2 0 5 2 0 2 0 2 4 1 2 1 0-1-2-2 2-1 7 2 2-1-2-2 7-2 2 0 3 1 2-2-3-2 2-1-2-2 7 1 2 1-3 1 0 1 2 1 4 0 1-2 6-2 9-2 2 0-2 2 3 0 2-1 5 0 4-1 4 2 3-2-3-2 1-1 8 1 4 1 10 3 2-1-3-2-3-1 1-1-2-2 5-3 2-3 2-1 8 1 0 2-2 2 1 1 1 2 0 4 3 1-2 2-5 4 3 1 1-1 3-1 1-2 2-1-1-1 1-2-3-1-1-1 3-3-4-2 5-2-1-2 2 0 1 2-1 2 3 1-1-2 4-1 6-1 5 2-2-2 0-3 4-1 7 0 6 0-2-1 3-2 3 0 6-2 7 0 8-1 3 0 6-1 5 0 1-1 2-1 7-1 5 0-4 1 6 1 1 1 2-1 9 0 6 2 2 1-1 1-3 1-7 1-2 1 3 1 4 0 3 0 1 2 2-1 4-1 9 1 1 1 11 1 0-2 6 0 5 0 4 1 1 2-1 1 3 3 5 1 2-3 5 1 5-1 5 1 2-1 5 1-2-3 3-1 25 2 3 1 7 3 11-1 6 0 2 2 0 2 3 0 4 0 5 0 5 0 5 0 5 3 3-1-2-2 1-1 9 0 6 0 8 2 4 1 0 11-4 1-3 0 2 1 2 3 1 0 1 2-6 0-8 2-3 0-4 2-4 2-1 1-4-2-7 2-1-1-3 1-4 0-1 2-3 3 0 1 3 0 0 4-3 0-1 3 1 1-5 1 0 4-5 0 0 3-4 3-2-2-1-4-1-7 1-3 2-2 1-1 4-1 5-3 5-3 5-3 2-3-4 0-1 2-7 3-2-3-8 1-7 4 3 2-7 1-4 0 0-2-4 0-3 1-9 0-9 0-9 6-11 6 5 1 1 1 3 1 2-1 3 0 4 3 0 2-2 3-1 3-1 5-4 4-1 2-4 3-4 3-1 2-4 1-2 0-2-1-3 2-2 1-1 1-1 3-1 0-2 2-2 0-1 1 0 1 3 2 2 3 1 2 0 3-1 2-3 0-2 2-3 0 0-2 1-2-2-3 2 0-2-3-1 0-1 1-2-2 1-1 1-2-2-1-1-1-4 1-2 2-3 0 2-1-1-1 2-2-1-1-3 1-3 2-1 1-3 0-2 2 2 2 2 0 0 1 3 1 3-2 2 1 2 0 0 2-4 1-1 1-3 1-1 2 3 2 1 3 2 2 2 2 0 2-2 1 1 2 1 0 0 3-1 2-2 0-2 3-2 4-2 3-4 3-4 2-3 0-2 2-2 0-4 1-3 1-1 3-2 0 0-2 0-1-4-1-1 0-4 3-2 2 0 2 2 3 2 4 3 2 1 2 2 5-1 5-2 2-3 2-2 2-4 2-1-1 1-2-2-2-3 0-1-2-1-3-3-1-2 0 0-2-2 0 0 3-2 4-1 3 1 2 1 0 2 2 0 3 2 1 1 1 2 1 2 2 1 2 0 2 0 1 1 3 2 3-2 1-3-2-3-2-1-2-1-2-1-2-1-1 1-2-1-2-1-1-1-1-1-2-1-1-1 2 0-2 0-2 1-2-1-2 1-2-1-2 1-3-1-2-1-3-1-3-1-3-2 2-3 2-2-1-1 0 1-4-1-2-2-3 0-1-1-1-2-2-1-2 0-1-1-1-1-2-3 0 1 1-1 2-1-1-2 0-1 0 0 1-2 0-3 1 0 2-2 1-4 2-3 3-2 2-3 2 0 1-1 1-3 1-1 0-1 2 1 4 0 2-1 3 0 5-2 0-1 2-2 2 0 1-2 1-2-2-2-4-1-3-1-1-1-3-1-4 0-1-3-4-1-5-1-4 0-3 0-3-4 2-2-1-4-3 1-1 0-1-4-2-2-1 0-2-3-2-5 0-4 0-4 1-5-1-3-1-4 0-1-4-1 0-2 0-3 2-3-1-3-2-3-1-2-3-2-3-1 0-2-1-1 1-2 0 1 1 0 3 2 2 1 1 2 2 0 1 1 2 1 2 0-1 1-2 1 1 0 1 0 2 0 1 3 0 2 0 2 0 2-2 2-1 2-2 1-1 0 1 0 3 1 2 1 1 2 0 2 1 1 1 2 2-1 2-1 2-2 2-1-1-1 3 1 1-2 1-2 1 0 1-2 1-1 0 0 1-2 1-1 0-2 1-1 0-2 1-1 1-3 2-4 1-3 2-1 1-2 1-2 0-3 0-1 1-1 1-1 0-3 0-1-1 0-2-1-3-1-1 1-1 0-2-1-1-1-2-1-1-1-3-1-2-2-2-1 0-2-3-1-2 1-1-2-3-1-2-2 0-1-2 0-2-2-2-2-3-1-2-2 0 1-1 0-2-1 3-1 1-2 0-1-2-2-4 1 4 2 2 2 5 1 1 1 2 2 3 0 2 3 3 1 3 0 3 1 4 1 0 2 1 1 4 1 2 2 1 3 3 2 2 1 1 3 2 0 2-1 1 1 0 1 2 2 1 1 0 3 0 3-1 2-1 1 0 3 0 2-1 2 0 1-1 1 0 0 2 0 2-1 1-1 3-1 3-2 3-2 5-2 3-4 3-2 3-5 2-2 3-3 3-1 1-2 2-1 1-1 0-1 2 0 2-1 1ZM0 42l7 2 7 3 0 1 2 1-1-2 8 0 5 3-3 1-4 1 0 2-1 1-3 0-2-1-4-1 0-1-3-1-3 1-2-1 1-1-4 0 2 2-2 1ZM636 127l1 2 2 1 2 1 4 0 5 0-1-3 1-3-2-1 0-2-2 0 1-2 3 0 2 0-2-2-1-2-2 1 0 2-1-2 0-2-3-1-2-3-1-1 2 0 1-2 2-1 2 1 1-3-1-2-2 0-3 0-3 1-3 0-1 2-3 1-2 2 2 3 0 2 3 3 1 2 2 2 1 0-1 1-1 2-1 2ZM108 40l6 0 4 2 3 0 2-1 4-1 4 0 4-1 4-1 2 2 2-1 1-1 2 0 5 2 3-2 1 3 3-1 1-1 4 0 4 2 6 1 4 0 3 0 4 1-4 2 5 0 7 0 3-1 3 2 3-1-3-1 2-1 3 0 2-1 2 1 3 1 3 0 5 1 4 0 5 0-1-2 3 0 4 1 0 2 2-2 2 0 1-3-3-1-3-1 0-3 4-2 3 0 3 1 4 3-3 2 5 0 0 3 4-2 4 2-1 2 2 2 3-2 2-3 0-3 4 0 4 1 4 1 0 2-2 1 2 2 0 1-6 2-3 0-3-1-1 2-3 2-1 1-3 2-4 0-2 2 0 1-3 1-4 2-3 3-1 2 0 4 4 0 1 3 2 2 4-1 5 1 2 1 2 2 4 1 3 1 4 0 3 0 0 3 1 2 2 3 4 3 2-1 2-3-2-4-2-2 5-1 3-2 1-2 0-2-2-2-3-2 3-3-1-2-1-5 2 0 5 0 3 1 2-1 2 1 4 1 1 2 5 0 0 2 1 4 2 0 2 2 4-2 3-3 2-1 2 2 3 4 3 3-1 2 4 1 3 2 4 1 2 1 1 2 2 0 1 1 0 3-2 2-2 0-4 1-4 3-4 0-6 0-5 0-2 0-3 2-3 1-4 4-4 2 3 0 4-4 6-2 4 0 3 1-3 2 1 3 1 2 4 1 4 0 3-3 0 2 2 1-4 2-6 1-2 1-4 2-2 0 0-2 5-2-4 0-3 0-3 2-3 1-3 1-1 2-1 2 1 1 1 0 0-1 1 2-2 0-2 0-2 1-1 0-1 0-3 1 4-1-3 1-2 0 0 3-2 2-2-1 1 1 1 2-1 1-2 2 1-2-2-1 0-2-1 1 1 2-2-1 2 1 0 3 1 1 1 3-2 2-3 0-2 2-1 0-2 1-3 3-2 1-1 2 0 2 0 2 1 2 1 2 0 1 2 4 0 2-1 1 0 1-2 0-1-1-1-1-1-2-2-2 0-1 0-2 0-2-3-2-1 0-2 1-2-1-2-1-3 0-3 0-2 0-1 1 1 1-2 1-2 0-3-1-2 0-2 0-2 0-2 0-3 3-2 1-2 1 0 1 0 2 0 2-1 3 0 2-1 4 0 1 1 2 0 1 1 2 2 2 1 2 1 1 3 1 1 1 2-1 2 0 2-1 2 0 2-1 1-2 0-2 2-2 3 0 3 0 1-1 1 2-2 2 0 2 0 1-1 3-1-1 0 1 0 1 0 2 0 1-1 1 0 2 1 0 2-1 2 1 1-1 1 0 2 0 1 0 1 0 1 1 2 1 1 1 0 2-1 2 0 1 0 2-1 1 0 2 1 1 0 1 1 2 2 1 1 1 1 0 1 1 1 0 1-1 2-1 2 0 2 0 1 1 2 1 2 0 2-2 1 0 0-3 2-1 2-1 2 0 2-1 1-1 2-1 1 1 0 1-2 1 1 1 0 1-1 2 1 2 1 0 1-2-1-3 3-1 0-2 2 2 2 0 1 1 3 1 3 0 2 1 2 0 1-1 4 0 3 0-2 0 1 2 2 0 2 1 0 2 2 0 1 1 2 1 2 2 0 1 1 0 1 2 1 1 4 0 2 0 3 0 3 1 3 3 1 1 1 1 2 5 1 1 0 1-2 3 6 1 0 3 2-2 4 1 4 2 2 1-1 2 3-1 6 1 4 0 4 3 4 3 2 1 2 0 1 1 1 3 1 2-2 4-1 2-4 4-2 3-2 3-1 2 0 5-1 4 0 2-1 1 0 4-3 3-1 3-2 1-1 2-3 0-4 1-2 1-3 1-3 2-3 3 0 2 0 2 0 3-1 1-2 2-3 4-2 3-2 1-1 3-2 1-1 2-4 1-2 0-1 0-3-1-2 0-1-1 0 1 3 2 0 2 1 1 0 2-2 3-5 2-5 0-3 0 0 2 0 2 0 1-1 1-3 1-3-1-1 0 1 3 1 1 2-1 1 2-3 0-2 2 0 3-1 1-3 0-2 2-1 2 3 2 3 1-1 2-4 2-1 3-3 1-1 1 1 3 2 2-1 0-3 0-1 0-3 1 0 3-1 0-4-1-3-2-3-1-1-2 1-2-2-2 0-4 1-3 3-2-4-1 3-3 0-4 4 1 1-6-2-1-1 4-1-1 0-4 1-5 2-2-1-2 0-3 1-1 1-4 2-4 2-5-1-4 1-2-1-3 2-4 1-5 0-6 1-6 0-5 0-4-3-1-1-1-5-3-5-3-2-2-1-2-2-5-3-5-3-5-1-2-1-2-2-1-2-2 1-1-1-3 1-1 2-2 1-2 0-1-1 1-2-1 0-4 2-2 1-2 0-1 1 0 2-2 1-1-1-1 1-1 2 0 1-2 1-1-1-1 0-2 0-2 0-3-1-2-2-2 0-2-2-1-1 1-2 1 1 2-1 1-2 0 0-1-1 0-1-1-1 0-2-1-2 0 0-1-1-1-1-1-1-1-1 1-2-1 0-2-1-1 0-1-1-1-2-2-2-2 1-1-1 1-2 0-1-1-1 0-1 0-3-1-1 0-2-1-1-1-3-3-2-1-2-1-2 1-2 1-1 0-2-1-2 0-3-2-2 0-3-1-2-2-3-1-2 0-2-2-3-1-1-2-1-1 1-1 1-2-1-1-1-2-1-1-2-3-3-2-1-2-2-1-1-2-1-1-2-1 0-2-2 0-1-2-2-1-1-3-1-2 0-1-2-1-3-1 0 1 0 1 0 3 1 1 2 2 2 1 1 2 1 2 2 1 1 3 1 1 0 1 1 2 1 0 1 1 1 1-1 2-1-2-2-1-2-2-2 0 0-2 0-2-1-1-2-1-1 0-2-1-2-2 2 0 1-1 0-1-2-2-2-1-1-2-1-1-1-3-1-2-1-1-2-2-1 0-2-1-1-1-2 0-1-2-3-3-2-4-2-2-2-2 0-2-2-2 1-2 0-2-1-2 1-3 1-3 0-2-1-4-1-2 0-2 4 1 1 3 1-3-1-3-6-3-2-1-5-1-2-2 1-2-4-1 0-2-4-2 0-2-1-1-3-1 0-2-4-2-1-3-3 0-5 0-3-1-6-3-2-1-5-1-4 1-5-2-4-1-3 1 1 2-2 0-3 0-2 1-3 1-1-2 1-2 3-1-4 1-2 1-4 2 2 2-2 2-3 1-3 1-1 1-4 1-1 2-3 1-2 0-3 1-3 0-2 1-5 1 3-2 3 0 3-2 3 0 1-1 4-2 3-2 0-2 2-1-3 1-3 0-2-1-1-1-3 1-2 0 0-1 0-1-1-1-4 0-2-1-2-1 0-1-2-1 1-2 2-2 1-1 2 0 2 0 2-1 2 0 2-1 0-1-2-1 2-1-1 0-3 1-3 0-4 0-4 0-1-1-4-2 4-1 6-2 2 0 0 2 6 0-2-2-4-1-2-1-2-2-4-1 1-1 5 0 4-1 0-2 3-1 3 0 5-2 3 1 4-2 4 1 2 1 2-1 4 1 4 1 3-1 6 1 5 1 2 0 4-1 4 1ZM267 60l2-1 4 0-4 2-2 0ZM278 31l-3-1 0-1 2-1 6 1 5 1-3 1-3 0-3 0ZM277 61l1-1 1 0 0 2-1 0-1-1ZM240 25l-2 1-4 0-3-1 2-1 4-1 2 1ZM239 18l-1 0-5 0 5-1 2 1ZM231 15l4 1-1 1-4 0-3-1-1-1 0-1 4 0ZM255 27l-4-1-8-1-1-1 0-1-3-2-6 0-3-1 1-1 6 0 3 1 6 0 2 1-1 1 3 1 2 0 4 0 4 1 4-1 6 0 5 0 3 1 0 1-1 1-5 1-3-1-8 1ZM191 16l4 1-6 1-4-1 2 0ZM192 14l3 1-3 1-5 0 3-2ZM346 91l-2 2-2 2 2-1 2 1 1 1 2 0 2 1 0 2 2-1 0 2 1 1-1 3-2 0-1-1 0-2-4 2-2 0 2-1-2-1-3 0-6 0 2-2-2 0 3-2 3-5 1-1 3-1 1 0ZM267 52l3 1 3 1 0 2 3-1 1 1-2 1-4 0-2-2-3 2-4 1-1-1-3 0 2-2 0-2 1-2 2 0 1 1 1 0ZM281 32l3-1 6 2 4 1 0 1 5 0 3 1 7 1 2 2 3 2-5 1 6 2 5 1 4 2 4 1-1 2-5 3-3-1-4-3-4 0 0 2 3 1 3 2 2 0 1 3-1 2-3-1-7-2 4 3 3 1-7 0-6-1-4-2-3-2-4-1-8 1-2-1 2-2 5 0 6 0 0-3 3-3-1-1-1-1-4-1-6-1 2-1-3-1-2-1-2-1-2 1-5 1-10-1-6-1-4 0-3-1 3-1-4-1-1-2 3-3 2-1 8-1-2 2 2 2 2-2 7-2 5 3 0 2ZM237 27l6 0 6 1-5 3-3 0-3 2-3 0-2-2 0-2 2-1ZM159 22l4-2 6-2 4 0 4 0 0 2-2 1-3 0-5 1-4 1ZM131 83l3 0-1 3 3 2-1 0-2-1-1-1-2-1 0-1 0-1ZM207 13l5 0 8 1 2 2 1 1-4 0-5-1-6 0 3-1-4-1ZM157 99l-1 0-5-1-3-2-4-2-1-1 3 0 2 0 3 1 2 2 3 1ZM162 27l4 0 7 0 3 1 3 1-3 1-7 2-4 2 0 1-7 1-1-1-7-1 1-1 2-3 3-1-3-2ZM201 23l2-1 3 0 0 2-1 1-10 0-7 2-4 0 5-2-12 0-4-1 4-2 2-1 8 1 5 1 5 1-4-3 3-1 2 0 1 2ZM204 30l3 1 2 3 1 2 4 2 6 1-1 1-4 0 1 1-1 1-5 0-4-1-4 0-5 1-7 1-5 0-1-1-4-1-3 0-3-2 2 0 4-1 4 0 4 0-6-1-6 0-4 0-1-1 6-1-4 0-5 0 3-3 2-1 7-1 3 0-2 2 7-1 4 1 3-1 2 1 2 2 2-1-2-3 2 0ZM221 31l-3-1 3-2 4 1 5-1-2 3 4 1-1 2-4 1-3 0-2-1-7-2 0-1ZM204 29l4 0 2 0-3 2-4-2ZM226 20l3 2 0 1-2 2-4 0-3 0 0-2-5 0 0-2 3 0 4-1 4 1ZM233 9l2 0 3-1-1 0 6 0 4 1 5 1 4 0 2 2 4 1-4 1-5 2-5 0-6 0-3-1 0-1 2-1-5 0-3-1-2-1ZM246 6l4-1 3 0 5 0 5-1 3 0 3 1 2-2 4 0 5-1 8 0 2 1 8-1 6 0 6 0 7 1 6 0 5 1-7 2-6 0-3 1 6 0-6 2-5 0-5 3-5 0-2 1-9 0 4 0-2 1 3 1-3 1-4 1-2 1-4 1 6 0-8 3-7-1-8 0-4 0-6 0 0-1 5-1-1-2 2 0 7 1-4-2-4 0 2-1 5-1-3-2-1-2 7 1 2 0 5-1-7 0-9 0-5-1-3-1-3-1ZM291 46l-2 1-3 0-1-1 2-2 2 0 2 0 0 2ZM233 40l1 1-1 1-4-1-2 1-4-1 2-1 2-2 3 1 2 1ZM321 95l4 0 3 1-1 1-4-1ZM322 103l1 1 2 0 3 0-2 1-1 1-3-2-1 0ZM68 178l2 1-1 1-1 1-1-1-1-1 1-2ZM67 176l-1 0-1-1 1 0ZM65 175l-2 0 0-1ZM61 173l1 1-1 0-1-1ZM57 172l-1 0 1 0ZM38 66l2 0 0 1-2 0-1 0-2-1ZM74 72l2 0 1 1-2 2-3 1-1-1-1-1 3-1ZM23 56l2 1 1-1 3 1 2 1-2 0-2 0-1-1-3 0ZM892 241l4 1 6 2 2 1 1 2 1 2 4 1 1 2-3 0 1 2 2 2 2 3 2 0 0 1 2 0 2 2-2 1-3-1-3-1-2-1-2-2-1-2-4-1-2 0-2 1 0 2-2 1-1 0-3 0-3-3-3 0-4 1 1-3 2 0-1-3-1-3-5-2-3 0-4-3-1 2-1 0 0-1 0-1-2-2 3-1 2 0-5-1-1-1-2-1-1-1 3-1 2-1 4 1 1 2 0 4 3 2 3-3 3-2 2 0 3 1 2 1ZM924 244l1 0 0 2-1-1-1-1-1-1-1-1-2-1 2 0 2 1ZM920 250l-1 0-2 1-1 0-2-1-2-1 3 0 1 0 1-2 0 2 2-1 2-1 0-2 2 0 0 2-1 2-1 0ZM930 248l2 3 1 0-1 2-1-2-1-1-1-2 1-1ZM847 259l-1 2-3 1 0-1 1-2 3-1 3-1 2 0 2 0-1 0-3 2ZM873 252l0-2 1-2 0 3ZM821 218l2-2 1-2 1 0 2 1 0 2 2 0 2 1 0 1-2 1 0 1-2 1-1 2 2 3-1 1 4 3-4 0-1 2 0 3-2 1 0 3-1 4-4 1-1-2-2 0-1-1-4 1-1-1-2 0-2-1 0-3-2-1-1-2 0-3 0-2 2-2 2 1 2-1 0-2 2-1 3 0 2-2 1-2 1-1ZM859 241l3 1 1 2-2-1-2 0-2 0-2 0 1-2ZM852 244l-1-1-1-1 3 0 0 1ZM855 227l1 2 1 0 0 1 0 3-1-1-1 2 2 1-2-1-1-3 0-3ZM841 231l4 0 2-2-1 3-2 1-3-1-5 0-2 1-1 2 3 2 1-1 6-1-1 1-1 0-1 2-2 1 2 3 2 4 0 2-1 1-1-1 1-2-3 1 0-2-2-2 0-2-2 0 0 4 1 4-2 0-1-1 0-2 0-3-1 0-1-2 1-2 0-2 2-4 0-1 3-2 2 1ZM834 262l-4-2 3-1 2 1 0 2ZM837 257l2 0 2-1 0 1-4 1-4 0 0-1 2-1ZM828 257l2-1 1 2-3 0-2 0-2 0 1-1 2 0 0-1ZM801 251l6 1 1-1 5 2 1 1 4 1 3 2-3 1-3-1-2 0-3-1-3 0-3-1-2 0-1 0-5-1-1-1-2-1 2-2 3 0 2 1ZM790 236l0 2 1 2 2 0 2 2-1 3 0 5-3 0-2-3-4-2-1-2-2-2-2-2-2-4-2-2-1-3-1-2-3-1-1-3-2-1-3-3 0-2 1 0 5 1 2 2 2 2 2 2 3 3 2 0 3 1 1 3 2 1-1 2 2 1ZM309 380l1 1 2 2 3 2 4 0-1 2-3 0-1-1-1 1-2 1-2 0-1-1-2 0-3-1-4-1-3-2-3-3 2 1 4 2 3 1 2-2 1-2 2-1ZM301 183l-2 0-1 0-2 0-1 0-2-1 3 0 2 0 1-1-1-1 0-1-2 0 2-1 3 1 2-1 2 1 1 1 2 0 1 1 1 1-1 1-1-1-1 0-2 1-1 0-1 0-1 1-1 0ZM760 8l6 0 6 1 6 3 0 2-6 1-8-1-5-1-2-2-4-1ZM786 13l7 2-1 1-16 1 5-4 3 0ZM886 22l7 0 10 1-2 2-10 0-5 1-6-2 2-2ZM912 24l7 1-4 1-4 0-5-1 1-1ZM889 30l2-2 4 0 4 1-4 1-6 0ZM625 9l5 0 4 0 2 0 3 0 4 0-1 1-4 0-2 0-4 1-3-1 2 0ZM649 28l6-2 0-1 6-2 9-1 9-1 5-1 5 0 2 1-2 1-9 1-9 1-9 3-4 3-4 2 1 3 5 2-2 0-9 0-1-1-5-1 0-2 3 0 0-2 5-2ZM897 84l1 3 0 3 1 2 3 5-4-1-2 4 3 3 0 2-2-2-2 3-1-3 0-2 0-3 1-2 0-4-2-3 1-4 2-1-1-1 1-1ZM0 35l3 0 4 0-3 1-4 1 0-2ZM1000 35l0 2-3 0-1-1ZM281 159l1 0 2 0-3 1ZM284 158l2 1 0 2-1-1-1-1ZM283 163l2 3 0 1-2-1-1-1ZM330 377l3-1 3 0 1-1 3 2-5 1-1-1-3 2ZM542 12l1-1 4 0 4 1 9 2-7 1-2 2-2 1-1 2-4 0-6-2 3-1-4 0-6-3-2-2 8-1 1 1ZM576 11l-4 1-8 1-8-1-5-1-3-1 9-1 4 1 3-1 7 1ZM569 17l-7 1-4 0 1-1-1-1 6-1 1 1ZM370 4l9-2 10 0 4-1 10 0 22 0 17 3-5 1-11 0-15 0 2 0 10 0 8 1 5-1 3 1-3 2 7-1 13-1 9 0 1 2-11 2-2 0-9 1 7 0-3 2-3 2 0 3 4 1-5 1-4 0 5 2 1 2-3 1 3 2-6 0 3 1-5 2-3 0 3 2 0 1-5-1-2 0 4 1 4 2 1 2-5 1-3-1-3-2 1 2-3 1 7 0 4 1-8 2-7 2-8 1-3 0-3 1-4 3-6 2-2 0-4 1-4 1-2 1 0 2-1 2-5 2 1 2-1 3-1 2-4 1-5-3-5 0-3-1-2-3-4-3-2-2 0-3-4-2 1-2-2-1 3-4 4-1 1-1 1-2-3 1-2 0-2 1-4-1 0-2 1-1 3 0 5 0-5-1-2-1-3 0-2-1 3-2-2-1-2-2-3-3-4-1 0-1-7-2-6 0-8 0-6 0-4-1-4-2 7 0 6-1-12 0-7-1 1-2 10-1 10-1 2-1-8-1 2-1 10-2 4-1-1-1 7-1 8 0 9 0 3 1 7-2 7 1 4 1 5 0-6-1ZM691 368l2 1 3 1-1 1-4 1 0-2 0-1ZM524 115l2-1 1 2-1 2-2 0 0-2ZM316 182l1 0 0 1-2 0-2 0 0-1 1 0ZM285 182l1 0 2 1-2 1-2 0-2-1 2-1ZM271 169l3 0 2 0 3 1 1 1 2 0 4 2 1 1 3 1 2 1 2 1-2 1-2 0-2 0-4 0 2-1-1-1-2 0-2-3-1 0-3 0-4-1 0-2-3 0-2 2-1 0-2 1-1 0 1-1 1-1 1-1 2-1 2 0ZM638 268l0 1 1 2 0 3 1 2 0 1-1-1 0 3-1 1-1 3-1 3-1 4-2 6-1 3-1 4-2 0-3 1-1 0-3-1 0-2-1-2-1-2 0-2 1-2 1-1 1-3 1-2-1-1-1-2 0-2 1-2 0-2 2 0 1 0 1-1 2 0 1-1 3-2 0-2 0-1 1 1 2-2 0-2 1-1ZM964 277l2 2-2-1ZM963 277l0-3 1 1 1 2-1 0ZM573 135l-4 1-4-1 1-1 1 1 3 0 2 0 0 1ZM483 84l0 2-2 2-5 2-4-1 3-3-2-2 4-3 2-1 2 0 3 2ZM960 292l3 2 1 1-1 1-1-1-2-1-2-2-2-2 2 0 2 1ZM950 262l-1 1-1-1 2 0ZM949 260l-2-2-1-2 2 3ZM947 261l-1 0-2 0 0-2 1 0 1 1ZM943 256l1 1-2-1-1-1-2-1 2 0ZM936 253l2 1-2-1-1-1ZM991 345l-1 1-1 2-2 1-2-1 2-2-1-2-3-1 0-1 2-1 0-2 0-2-1-2-1-1-2-3-1-2 1 0 1 2 2 0 1 3 2 3 0-2 1 1 1 2 2 1 2 0 1-1 2 0-1 3-1 1-2 0 0 2ZM971 354l3-1 1-2 2-2 1 0 0-2 2-1 1 1 0 1 2-1 1 1 0 1-1 2-2 2-1 1 1 1-2 0-3 1 0 2-2 3-2 1-2 1-2 0-2-1-3 0 0-1 1-2 4-3 1-1ZM910 347l2 0 0 3-1 3-3 2-2-1-2-2 0-2-2-2 0-2 2 1 3 1 1-1ZM850 323l-3 1-2 1 0 1-2 1-2 1-2 0-2-1-2 1-2 0-2 1-2 1-1 1-2 0-2 0-3-2-1-1 0-1 1-1 0-1 1-2-1-2-1-3-1-1 1-2-2-2-1-2 0-2-2-2 0-1 1 1-1-2 1 0 1 1 0-1-1-2-1-2 0-2 1-2 0-1 1-2 0 2 1-2 3-1 1-1 2-1 1 0 3-1 2 0 1-1 2 0 3-1 1-1 1-2 2-1 0-1 0-2 2-2 1 2 1 0-1-2 1-1 1 1 0-2 2-2 1-1 1 0 1-1 2-1 1 0 2 1 2 2 1 0 2 0-1-2 2-2 1-1 1-2 2-1 1 1 2-1 0-1-2-1 2-1 1 1 2 1 2 1 3 0 1 0 1 0 2 1 0 1-1 1-1 1-1 2-1 1 3 3 2 0 1 1 2 2 2 1 3 2 2-1 1-2 0-1 1-2 1-2-1-1 0-3 0-2 1-1 0-2 1-1 1-2 1 1 0 2 1 2 1 1 0 2 0 1 1 2 2-1 0 1 2 1 0 1 0 3 1 1 1 3 0 1 1 2 3 1 2 2 1 1 2 2 1 3 1 0 1 1 1 3 2 1 1 1 3 3 0 2 0 1 0 2 2 2-1 3 0 1-1 3 0 1 0 2-2 3-2 1-1 2-1 2 0 2-1 1-1 2 0 2-2 2-3 0-3 1-1 2-2 1-2-1-2-1 1-1-2 0-2 2-2-1-2 0-2 0-2-1-2-2-1-2 0-1-2-1-2-1 1-1-1-2-1 2-3 0 2-1 0-2 1-1 0-2-2 2-2 1-1 2-2-1 0-1-2-2-2-1-3-3-2 0-2-1-5 0-4 1-3 1ZM727 212l0 3-1 1-3 1-1-2-1-4 2-5 2 2 1 2ZM804 183l-2-1 0-2 1-2 3-1 2 1 0 1-1 1-1 1ZM838 166l-1 4-2 2-1-2 0-2 1-3 2-2 2 1ZM541 127l2 0-1 2 0 3-2-1-2-1-3-1 0-2 3 1ZM524 120l2-1 1 2 0 4-1-1-2 1-1 0 0-4 0-1ZM534 77l1 2-1 2-3-1-1-2ZM491 85l1-2-2-1-3-1 0-2-3 1 0-3-1-1 1-3 2-3 2 1 4-1-3 3 3 0 3 0-1 2-3 3 3 0 3 4 2 0 2 3 0 1 4 1-1 2-1 0 1 2-2 1-4 0-5 1-1 0-2 1-3-1-2 2-1-1 4-3 3-1-5 0-1-1 3-1-1-1 0-2ZM460 49l-1 2 3 1-3 3-8 1-3 1-3 0-8-1 3-2-7-1 5 0-6-2 2-2 5 0 4 2 4-2 4 1 4-1ZM836 198l-2-2 3 0 1 1-1 2ZM841 206l1-3 1 0 0 2 2-3-1 3-1 1 0 1-3-1ZM851 210l0 2 0 1 0 3-1-3-2 1 1 3-1 1-3-2-1-2 1-1-2-1-1 1-1 0-2 1 1-3 2-1 1-1 1 1 2 0 1-2 2 0-1-2 3 2 0 1ZM829 207l-4 3 2-2 2-2 2-1 1-3 0 2-1 2ZM840 183l-1 1 1 2 0 2-2 1 0 2 0 3 2 0 1 0 3 1 0 2 1 2-3-2-1-1 0 1-2-2-3 0-1 0 0-1 0-2 0 1-1-1-1-1 0-3 1 1 0-5 1-2 2 0 2 1 1-1ZM839 202l0-2 1 1 2 0 0 1-1 1-2 1 0-1ZM849 200l0 3-2-1 1 3-1 0 0-2-2-2 2 1 0-1-2-3 3 1ZM894 124l-2 3 0 3-1 2 0 2-1 2-4 1-5 0-4 3-2-1 0-2-5 1-3 1-3 0 3 2-2 5-2 1-1-1 0-2-1-1-2-2 3-1 2-2 2-1 2-2 6-1 3 1 3-5 2 1 4-3 1-1 2-3 0-3 1-2 3-1 1 4ZM902 111l2-1 0 3-4 1-2 3-5-2-1 3-3 0-1-3 2-2 3 0 1-4 0-2 4 3 2 1ZM868 140l1-1 2 0 1-1 2 0-1 3-1-1-2 1-1 1-1 0ZM591 136l3-1 2-1-2 1-2 2-2 0 0-1ZM329 203l1 0 1 2-3 1 1-1Z", + "countries": { + "Argentina": "M309 380l1 1 2 2 3 2 4 0-1 2-3 0-1-1-2 0-3 0ZM340 317l-1 2-1 3 1 3-1 3 0 1 3 2 0 2 1 1 0 2-2 3-5 2-5 0-3 0 0 2 0 2 0 1-1 1-3 1-3-1-1 0 1 3 1 1 2-1 1 2-3 0-2 2 0 3-1 1-3 0-2 2-1 2 3 2 3 1-1 2-4 2-1 3-3 1-1 1 1 3 2 2-1 0-3-1-7 0-1-2 0-2-2 0-1-1 0-3 2-1 1-2 0-1 1-2 1-4 0-2 1 0 0-1-1-1 0-1-1-1 0-3 1-1-1-3 1-3 1-3 1-1-1-2 0-3 3-2-1-2 2-3 0-2-2-6 2-2 0-3 1-3 1-2 2-2-1-1 1-6 3-1 1-3 2-3 4 1 1 2 1-3 3 1 6 5 2 0 4 2 3 1 0 1-3 5 3 0 3 1 2-1 3-2 0-2 2-1 1 2 0 2-2 2-2 1-3 2Z", + "Australia": "M910 347l2 0 0 3-1 3-3 2-2-1-2-2 0-2-2-2 0-2 2 1 3 1 1-1ZM850 323l-3 1-2 1 0 1-2 1-2 1-2 0-2-1-2 1-2 0-2 1-2 1-1 1-2 0-2 0-3-2-1-1 0-1 1-1 0-1 1-2-1-2-1-3-1-1 1-2-2-2-1-2 0-2-2-2 0-1 1 1-1-2 1 0 1 1 0-1-1-2-1-2 0-2 1-2 0-1 1-2 0 2 1-2 3-1 1-1 2-1 1 0 3-1 2 0 1-1 2 0 3-1 1-1 1-2 2-1 0-1 0-2 2-2 1 2 1 0-1-2 1-1 1 1 0-2 2-2 1-1 1 0 1-1 2-1 1 0 2 1 2 2 1 0 2 0-1-2 2-2 1-1 1-2 2-1 1 1 2-1 0-1-2-1 2-1 1 1 2 1 2 1 3 0 1 0 1 0 2 1 0 1-1 1-1 1-1 2-1 1 3 3 2 0 1 1 2 2 2 1 3 2 2-1 1-2 0-1 1-2 1-2-1-1 0-3 0-2 1-1 0-2 1-1 1-2 1 1 0 2 1 2 1 1 0 2 0 1 1 2 2-1 0 1 2 1 0 1 0 3 1 1 1 3 0 1 1 2 3 1 2 2 1 1 2 2 1 3 1 0 1 1 1 3 2 1 1 1 3 3 0 2 0 1 0 2 2 2-1 3 0 1-1 3 0 1 0 2-2 3-2 1-1 2-1 2 0 2-1 1-1 2 0 2-2 2-3 0-3 1-1 2-2 1-2-1-2-1 1-1-2 0-2 2-2-1-2 0-2 0-2-1-2-2-1-2 0-1-2-1-2-1 1-1-1-2-1 2-3 0 2-1 0-2 1-1 0-2-2 2-2 1-1 2-2-1 0-1-2-2-2-1-3-3-2 0-2-1-5 0-4 1-3 1Z", + "Austria": "M547 100l0 1-2 0 0 2-3 1-1 0-3 0-4-1-3 0-2 0-1 0-2-1 1-1 2 1 3-1 2 0 1 0 1 0 0-2 1 0 1-1 2 0 1-1 4 1 1 0 1 0 0 1Z", + "Bangladesh": "M757 172l0 2 0 2-1-2 0-1-1-1-1-2-3 0 1 1-1 2-1-1-2 0-1 0 0-2-1-2 0-2-1-1 0-1 2-1-2-1 1-2 2 1 2 0 0 2 2 1 3-1 2 1-2 2-1 0-1 2 2 1 0-1 1 0Z", + "Belarus": "M578 77l3 1 2 0 3 1 0 1 1 3 1 0 2 1 0 2-3 0 1 1 0 2-2 0-1 2-1 0-3 0-2-1-1 0-2 0-3-1-3 0-2 0-1 1-2 0 0-1-1-1 2-1 0-1-1-1 0-1 3 0 3-1 1-2 2-1 0-1 1-1Z", + "Belgium": "M517 92l0 2-1 2-3-2-1 1-2-2-1-1-2 0 2-1 2 0 3-1 2 2Z", + "Brazil": "M352 327l-1-1 1-2-1-2-3-1-2-2-1 0-3-2-2 0 4-4 3-2 2-1 2-2 0-2-1-2-2 1 1-2 0-1 0-2-1 0-1 0-1 0 0-1 0-3-3-1-1 0-3 0 0-4-1-2 1-2 1-1 0-2 0-2-2-1 0-1 0-1-5-1-1-3 1-1-1-2-2-1-1 0-2-1-1-1-2-1-3 0-3-3 1-1-1-1 1-3-4 1-2 1-2 1-2 1-2 0-2 0-1 0 0-4-2 1-3 0-1-1-1 0 0-2-1-1-2-3 1-1 2-1 0-2 1-2 3-2 2 0 3-1 1-7 0-2 0-1-1-1 0-2 1-1-1-1 0-1 5 0 2 0 1 1 2 1 2 0 3-1 1-1 0-1 2-1-3-1 0-1 0-2-1-1 3 0 2 1 3-1 3-1 1-1 1-1 0 2 2 1-2 4 1 1 0 1 2 2 1 0 2-1 1 0 2-1 2 0 0-1 2 0 1-1 2 1 1 0 1 0 2 0 1-1 1-2 2-2 1 1 2 5 1 1 0 1-2 3 6 1 0 3 2-2 4 1 4 2 2 1-1 2 3-1 6 1 4 0 4 3 4 3 2 1 2 0 1 1 1 3 1 2-2 4-1 2-4 4-2 3-2 3-1 2 0 5-1 4 0 2-1 1 0 4-3 3-1 3-2 1-1 2-3 0-4 1-2 1-3 1-3 2-3 3 0 2 0 2 0 3-1 1-2 2-3 4-2 3-2 1-1 3Z", + "Canada": "M159 97l-6-3-2-1-5-1-2-2 1-2-4-1 0-2-4-2 0-2 2-1 0-2-5-2-3-3-1-2-3-1-2-1-1-2-3 1-3 2-2-2-2-1-3-1-3 0 0-16 0-10 6 0 4 2 3 0 2-1 4-1 4 0 4-1 4-1 2 2 2-1 1-1 2 0 5 2 3-2 1 3 3-1 1-1 4 0 4 2 6 1 4 0 3 0 4 1-4 2 5 0 7 0 3-1 3 2 3-1-3-1 2-1 3 0 2-1 2 1 3 1 3 0 5 1 4 0 5 0-1-2 3 0 4 1 0 2 2-2 2 0 1-3-3-1-3-1 0-3 4-2 3 0 3 1 4 3-3 2 5 0 0 3 4-2 4 2-1 2 2 2 3-2 2-3 0-3 4 0 4 1 4 1 0 2-2 1 2 2 0 1-6 2-3 0-3-1-1 2-3 2-1 1-3 2-4 0-2 2 0 1-3 1-4 2-3 3-1 2 0 4 4 0 1 3 2 2 4-1 5 1 2 1 2 2 4 1 3 1 4 0 3 0 0 3 1 2 2 3 4 3 2-1 2-3-2-4-2-2 5-1 3-2 1-2 0-2-2-2-3-2 3-3-1-2-1-5 2 0 5 0 3 1 2-1 2 1 4 1 1 2 5 0 0 2 1 4 2 0 2 2 4-2 3-3 2-1 2 2 3 4 3 3-1 2 4 1 3 2 4 1 2 1 1 2 2 0 1 1 0 3-2 2-2 0-4 1-4 3-4 0-6 0-5 0-2 0-3 2-3 1-4 4-4 2 3 0 4-4 6-2 4 0 3 1-3 2 1 3 1 2 4 1 4 0 3-3 0 2 2 1-4 2-6 1-2 1-4 2-2 0 0-2 5-2-4 0-3 0-2-2 0-3-2-1-1 0-3 2-1 2-1 1-1 0-2 1-5 0-4 0-1 1-3 2-1 1-3 0-3 0-1 1 1 1-4 2-3 0-3 2-2-1 1-2 1-1 1-2-1-2 0-3-3-1-2-1-1-1-1-1-2-1-2-1-3-1-2-1-3 1-4-1-3 1-2-1-3-1-2 0-1-2-1 1-6 0-10 0-9 0-8 0-9 0-8 0-8 0-3 0-8 0ZM267 60l2-1 4 0-4 2-2 0ZM278 31l-3-1 0-1 2-1 6 1 5 1-3 1-3 0-3 0ZM277 61l1-1 1 0 0 2-1 0-1-1ZM240 25l-2 1-4 0-3-1 2-1 4-1 2 1ZM239 18l-1 0-5 0 5-1 2 1ZM231 15l4 1-1 1-4 0-3-1-1-1 0-1 4 0ZM255 27l-4-1-8-1-1-1 0-1-3-2-6 0-3-1 1-1 6 0 3 1 6 0 2 1-1 1 3 1 2 0 4 0 4 1 4-1 6 0 5 0 3 1 0 1-1 1-5 1-3-1-8 1ZM191 16l4 1-6 1-4-1 2 0ZM192 14l3 1-3 1-5 0 3-2ZM346 91l-2 2-2 2 2-1 2 1 1 1 2 0 2 1 0 2 2-1 0 2 1 1-1 3-2 0-1-1 0-2-4 2-2 0 2-1-2-1-3 0-6 0 2-2-2 0 3-2 3-5 1-1 3-1 1 0ZM267 52l3 1 3 1 0 2 3-1 1 1-2 1-4 0-2-2-3 2-4 1-1-1-3 0 2-2 0-2 1-2 2 0 1 1 1 0ZM281 32l3-1 6 2 4 1 0 1 5 0 3 1 7 1 2 2 3 2-5 1 6 2 5 1 4 2 4 1-1 2-5 3-3-1-4-3-4 0 0 2 3 1 3 2 2 0 1 3-1 2-3-1-7-2 4 3 3 1-7 0-6-1-4-2-3-2-4-1-8 1-2-1 2-2 5 0 6 0 0-3 3-3-1-1-1-1-4-1-6-1 2-1-3-1-2-1-2-1-2 1-5 1-10-1-6-1-4 0-3-1 3-1-4-1-1-2 3-3 2-1 8-1-2 2 2 2 2-2 7-2 5 3 0 2ZM237 27l6 0 6 1-5 3-3 0-3 2-3 0-2-2 0-2 2-1ZM159 22l4-2 6-2 4 0 4 0 0 2-2 1-3 0-5 1-4 1ZM131 83l3 0-1 3 3 2-1 0-2-1-1-1-2-1 0-1 0-1ZM207 13l5 0 8 1 2 2 1 1-4 0-5-1-6 0 3-1-4-1ZM157 99l-1 0-5-1-3-2-4-2-1-1 3 0 2 0 3 1 2 2 3 1ZM162 27l4 0 7 0 3 1 3 1-3 1-7 2-4 2 0 1-7 1-1-1-7-1 1-1 2-3 3-1-3-2ZM201 23l2-1 3 0 0 2-1 1-10 0-7 2-4 0 5-2-12 0-4-1 4-2 2-1 8 1 5 1 5 1-4-3 3-1 2 0 1 2ZM204 30l3 1 2 3 1 2 4 2 6 1-1 1-4 0 1 1-1 1-5 0-4-1-4 0-5 1-7 1-5 0-1-1-4-1-3 0-3-2 2 0 4-1 4 0 4 0-6-1-6 0-4 0-1-1 6-1-4 0-5 0 3-3 2-1 7-1 3 0-2 2 7-1 4 1 3-1 2 1 2 2 2-1-2-3 2 0ZM221 31l-3-1 3-2 4 1 5-1-2 3 4 1-1 2-4 1-3 0-2-1-7-2 0-1ZM204 29l4 0 2 0-3 2-4-2ZM226 20l3 2 0 1-2 2-4 0-3 0 0-2-5 0 0-2 3 0 4-1 4 1ZM233 9l2 0 3-1-1 0 6 0 4 1 5 1 4 0 2 2 4 1-4 1-5 2-5 0-6 0-3-1 0-1 2-1-5 0-3-1-2-1ZM246 6l4-1 3 0 5 0 5-1 3 0 3 1 2-2 4 0 5-1 8 0 2 1 8-1 6 0 6 0 7 1 6 0 5 1-7 2-6 0-3 1 6 0-6 2-5 0-5 3-5 0-2 1-9 0 4 0-2 1 3 1-3 1-4 1-2 1-4 1 6 0-8 3-7-1-8 0-4 0-6 0 0-1 5-1-1-2 2 0 7 1-4-2-4 0 2-1 5-1-3-2-1-2 7 1 2 0 5-1-7 0-9 0-5-1-3-1-3-1ZM291 46l-2 1-3 0-1-1 2-2 2 0 2 0 0 2ZM233 40l1 1-1 1-4-1-2 1-4-1 2-1 2-2 3 1 2 1ZM321 95l4 0 3 1-1 1-4-1ZM322 103l1 1 2 0 3 0-2 1-1 1-3-2-1 0Z", + "Chile": "M309 380l0 6 3 0 2 0-1 1-2 1-2 0-1-1-2 0-3-1-4-1-3-2-3-3 2 1 4 2 3 1 2-2 1-2 2-1ZM307 282l1 2 0 2 2 1-1 3 2 3 1 4 2-1-1 4-3 1 0 5 0 2-2 2-1 2-1 3 0 3-2 2 1 5 1 3-2 3 1 2-3 2 0 3 1 2-1 1-1 3-1 3 1 3-1 1 0 3 1 1 0 1 1 1 0 1-1 0 0 2-1 4-1 2 0 1-1 2-2 1 0 3 1 1 2 0 0 2 1 2 7 0 3 1-3 0-1 0-3 1 0 3-1 0-4-1-3-2-3-1-1-2 1-2-2-2 0-4 1-3 3-2-4-1 3-3 0-4 4 1 1-6-2-1-1 4-1-1 0-4 1-5 2-2-1-2 0-3 1-1 1-4 2-4 2-5-1-4 1-2-1-3 2-4 1-5 0-6 1-6 0-5 0-4 1 0Z", + "China": "M804 183l-2-1 0-2 1-2 3-1 2 1 0 1-1 1-1 1ZM723 116l0-2 2-1-3-4 6-2 1 0 2-5 6 1 1-1 0-3 3-1 2-1 1-1 0 2 3 2 4 1 2 2-1 3 1 2 3 0 4 0 3 2 2 0 1 3 2 2 3 0 5 0 4 0 3 0 4 2 3 0 2 1 3-2 4-1 4 0 4-1 2-1 2-1-2-2 2-2 1 0 3 1 3-2 4-1 2-2 2 0 4-1 2 1-2-3-2-1-2 1-3-1-1 1-1-1 2-3 1-2 3 1 4-2 0-1 3-3 1-1 0-2-1 0 2-2 4 0 3 0 4 1 3 1 2 2 1 2 1 1 1 3 4 1 4 2 1 3 4 0 2-2 5 0-1 2-1 1-1 3-2 3-4-1-2 1 1 3-1 3-1 0 0 2-2-2-1 1-4 2 0 1-2 0-2-1-1 2-4 2-2 1-4 1-2 2-3 0 2-1-1-1 2-2-1-1-3 1-3 2-1 1-3 0-2 2 2 2 2 0 0 1 3 1 3-2 2 1 2 0 0 2-4 1-1 1-3 1-1 2 3 2 1 3 2 2 2 2 0 2-2 1 1 2 1 0 0 3-1 2-2 0-2 3-2 4-2 3-4 3-4 2-3 0-2 2-2 0-4 1-3 1-1 3-2 0 0-2 0-1-4-1-1 0-3 0-1-1 0-2-2 0-1-2-3 2-2 0-3 0-1 1-2 0 1 4-2-1 0-1-2 0-1 0-2-1 0-2-1-1-1-3-3 1 0-3 3-3 0-2 0-2-1-1-1-1-2 0-3-1 1-1-1-1-2 1-2-1-4 2-2 2-2 0-2-1-1 0-2 0-1 0-2 3-1-3-1 1-3 0-4-1-2-1-2-1-1-1-2-1-2-1-3-1-1 0-4-1-2-2-1-3 2 0 0-1-1-2 0-2-3-3-4-1-1-3-2-1-1-2 0-1-2-1-1-2 0-1 3-2 2 0 3 0 1-2 3 0 1-1 5-2Z", + "Colombia": "M314 230l-1-1-2 0-5 0 0 1 2 1 0 1-2 0 0 2 1 1 0 1 0 2-1 7-2-1 1-3-2-1-1 0-1-1-2 1-2 0-2-3-1-1-1-1-2-2-2 0-1-1-3 0-1-1-3-2 1-1-1-1 1-1 2 0 1-2 1-1-1-1 0-2 0-2 0-3-1-2 0-1 1-1 0-1 2-1 2-2 1 0 0-3 2-1 2-1 2 0 2-1 1-1 2-1 1 1-2 1-1 1-1 1-1 1 0 2-1 2 2 0 0 1 1 2 0 1 1 2 4 0 1 0 2 2 1 0 2 0 2 0 0 2 0 3 0 2 1 1-1 1 1 1 0 1Z", + "Cyprus": "M591 136l1 0 2 0-2 1-2 0 0-1Z", + "Czechia": "M542 91l1 1 2 1 1 1 3-1 2 1 1 2-1 0-1 1-1 1-1 0-2 0-1 0-3-1-2 1-2 0-2-2-1 0-1-1 2-2 1-1 2 0 1 0Z", + "Denmark": "M528 81l-2 0-2 0-1-2-1-3 2-1 2 0 3-2 0 1 0 2 1 1 0 1-3 1ZM534 77l1 2-1 2-3-1-1-2Z", + "Egypt": "M602 172l-11 0-10 0-12 0 0-10 0-10 0-2 0-2 0-1 1-1 4 0 2 0 3 1 1 1 2-1 2-1 2 0 2 0 1 1 3 0 2 0 1 0 2 4-1 2 0 2-1 1-2 0-1-2-2-4 1 4 2 2 2 5 1 1 1 2 2 3 0 2 3 3Z", + "Finland": "M579 41l0 2 4 2-2 2 3 4-2 2 3 2-2 2 5 2-2 1-2 2-6 3-5 0-5 2-4 0-2-1-3-1 1-3-2-3 2-1 2-2 7-3 2-1-1-1-4-1-1-1 0-4-4-2-4-2 2 0 3 1 4 0 3 1 2-2 2-2 4-1 4 2Z", + "France": "M357 222l-2 2-1 2-1 1-1 1-1-1-2 0 0-1 0-2 1-1-1-1 0-2 1-3 3 1 3 3ZM517 96l1 1 4 0-1 2 0 2-2 0-2 3 0 1 1-1 1 2 1 1-1 3 2 1 0 1-3 2-5-1-4 1-1 1-3 1-3-2-1 1-5-1-1-1 1-2 1-5-3-3-2-2-4-1-1-2 4-1 5 1-1-3 2 1 7-2 1-2 2-1 2 1 1 1 2 2 1-1 3 2ZM524 115l2-1 1 2-1 2-2 0 0-2Z", + "Germany": "M539 84l1 1 0 2 1 2 1 2-2 1-1 0-2 0-1 1-2 1 1 2 1 0 2 2-1 1-1 0 0 2-1 0-1 0-2 0-3 0-2 0-3-1-3 1 0-2 1-2-4 0-1-1 0-1 0-3 0-3 1 0 1-1 1-2 0-2 2 0 2-1 0-1 0-1 2 0 2 0 0 1 2 0 3 1 2-1 3 1Z", + "Greece": "M573 135l-4 1-4-1 1-1 1 1 3 0 2 0 0 1ZM564 119l2 0 2-1 2 1 3 0 0-2 1 1-1 2-2 0-2 0-3 0 2 2-2 0-1 0-2-1 0 2 2 1-1 1 1 1 2 1 0 2-3-1 1 1-2 1 1 2-2 0-2-1-1-2 0-2-1-1-2-2 1-2 1-1 2-1 1-1 2 0Z", + "Hungary": "M561 99l2 1-2 1-1 2-2 2-2 0-2 0-2 1-1 0-2 0-2-2-2-1 1-2 1 0 0-1 2 0 1 1 2-1 1 0 2-1 1 0 2-1 3 1Z", + "India": "M770 155l1 1-1 2-2 0-4 2 0 1-1 2 0 2-2 2-2-1 0 3 0 2-2 1-1-4-1 1-2-1 1-2 1 0 2-2-2-1-3 1-2-1 0-2-2 0-2-1-1 2 2 1-2 1 0 1 1 1 0 2 1 2 0 2 0 1-2 0-3 1 0 2-2 1-4 2-3 3-2 2-3 2 0 1-1 1-3 1-1 0-1 2 1 4 0 2-1 3 0 5-2 0-1 2-2 2 0 1-2 1-2-2-2-4-1-3-1-1-1-3-1-4 0-1-3-4-1-5-1-4 0-3 0-3-4 2-2-1-4-3 1-1 0-1-4-2 2-2 6 0 0-3-2-1 0-2-2-2 3-2 3 0 3-3 2-3 3-3 0-2 2-1-2-2-1-2-1-2 1-1 4 0 4 0 2-2 3 3 0 2 1 2 0 1-2 0 1 3 2 2 4 1-1 2-2 2 3 1 3 2 3 1 4 1 2 1 2 0 3 1 3 0 0-1 0-2 0-1 1-1 1 3 2 1 2 0 2 0 3 0 0-2-1-1 2 0 2-2 4-2 2 1 2-1 1 1-1 1Z", + "Indonesia": "M892 241l0 9 0 9-3-3-3 0-4 1 1-3 2 0-1-3-1-3-5-2-3 0-4-3-1 2-1 0 0-1 0-1-2-2 3-1 2 0-5-1-1-1-2-1-1-1 3-1 2-1 4 1 1 2 0 4 3 2 3-3 3-2 2 0 3 1 2 1ZM847 258l0 1-1 2-3 1 0-1 1-2ZM873 252l0-2 1-2 0 3ZM827 222l-1 2 2 3-1 1 4 3-4 0-1 2 0 3-2 1 0 3-1 4-4 1-1-2-2 0-1-1-4 1-1-1-2 0-2-1 0-3-2-1-1-2 0-3 0-2 2-2 0 2 2 1 2 0 2 0 1-2 1 0 3 1 2-1 2-4 1 0 1-4 3 0ZM859 241l3 1 1 2-2-1-2 0-2 0-2 0 1-2ZM852 244l-1-1-1-1 3 0 0 1ZM855 227l1 2 1 0 0 1 0 3-1-1-1 2 2 1-2-1-1-3 0-3ZM841 231l4 0 2-2-1 3-2 1-3-1-5 0-2 1-1 2 3 2 1-1 6-1-1 1-1 0-1 2-2 1 2 3 2 4 0 2-1 1-1-1 1-2-3 1 0-2-2-2 0-2-2 0 0 4 1 4-2 0-1-1 0-2 0-3-1 0-1-2 1-2 0-2 2-4 0-1 3-2 2 1ZM834 262l-4-2 3-1 2 1 0 2ZM837 257l2 0 2-1 0 1-4 1-4 0 0-1 2-1ZM828 257l2-1 1 2-3 0-2 0-2 0 1-1 2 0 0-1ZM801 251l6 1 1-1 5 2 1 1 4 1 3 2-3 1-3-1-2 0-3-1-3 0-3-1-2 0-1 0-5-1-1-1-2-1 2-2 3 0 2 1ZM790 236l0 2 1 2 2 0 2 2-1 3 0 5-3 0-2-3-4-2-1-2-2-2-2-2-2-4-2-2-1-3-1-2-3-1-1-3-2-1-3-3 0-2 1 0 5 1 2 2 2 2 2 2 3 3 2 0 3 1 1 3 2 1-1 2 2 1Z", + "Ireland": "M483 84l0 2-2 2-5 2-4-1 3-3-2-2 4-3 2-1 1 2-1 1 2 0Z", + "Israel": "M599 142l-1 1-1 2 0 1 1 0 0 1-1 4-2-4 1-1 1-2 0-2 2-1 1 0 0 1-1 0Z", + "Italy": "M529 103l2 0 3-1 4 2 0 2 1 1-2-1-3 1 0 2 1 2 3 1 1 3 3 2 2 0 0 1 3 1 2 1 2 1 0 2-2-2-2 0-1 2 2 1-1 1-1 0-1 3-1 0 0-2 0-3-1-1-1 0-1-1-2-1-1-1-2 0-2-2-3-1-2-2-1-3-1 0-2-1-2 0-1 2-1 0 0-1-2-1 0-2 0-2 1 0 2 0 1-1 2 0 1-1 2 1 1-1ZM541 127l2 0-1 2 0 3-2-1-2-1-3-1 0-2 3 1ZM524 120l2-1 1 2 0 4-1-1-2 1-1 0 0-4 0-1Z", + "Japan": "M894 124l-2 3 0 3-1 2 0 2-1 2-4 1-5 0-4 3-2-1 0-2-5 1-3 1-3 0 3 2-2 5-2 1-1-1 0-2-1-1-2-2 3-1 2-2 2-1 2-2 6-1 3 1 3-5 2 1 4-3 1-1 2-3 0-3 1-2 3-1 1 4ZM902 111l2-1 0 3-4 1-2 3-5-2-1 3-3 0-1-3 2-2 3 0 1-4 0-2 4 3 2 1ZM868 140l1-1 2 0 1-1 2 0-1 3-1-1-2 1-1 1-1 0Z", + "Kenya": "M609 246l-4-2 0-2-10-6-1-3 1-1 1-2 1-2-1-3 0-2-2-1 2-2 2-2 1 1 0 1 3 1 4 2 1 0 3 1 1-1 2-1 1 0 2 0-2 4 0 10 2 2-2 1-1 1-1 0-1 2 0 2-1 1Z", + "Malaysia": "M778 215l3 1 0 2 2-1 1-1 2 2 1 2 0 2 0 1 1 3 2 3-2 1-3-2-3-2-1-2-1-2-1-2-1-1 1-2ZM827 222l-2-1-3 0-1 4-1 0-2 4-2 1-3-1-1 0-1 2-2 0-2 0-2-1 0-2 2 1 2-1 0-2 2-1 3 0 2-2 1-2 1 1 2-1 1-1 0-2 2-2 1-2 1 0 2 1 0 2 2 0 2 1 0 1-2 1 0 1Z", + "Mexico": "M175 143l3 0 3-1 4 2 7 2 5 0 2 0 0-1 5 0 1 1 2 1 1 1 1 2 1 1 1 1 3 1 1-2 3 0 2 1 1 2 1 1 2 2 0 2 1 1 2 1 2 1 1-1-1 3 0 2-1 4 0 1 1 2 0 1 1 2 2 2 1 2 1 1 3 1 1 1 2-1 2 0 2-1 2 0 2-1 1-2 0-2 2-2 3 0 3 0 1-1 1 2-2 2 0 2 0 1-1 3-1-1-2 2-3 0-3 0 0 1-1 0 1 1 1 1 1 2-4 0-1 2 0 1-3-2-2-1-2-1-2 1-2 1-1 0-2-1-2 0-3-2-2 0-3-1-2-2-3-1-2 0-2-2-3-1-1-2-1-1 1-1 1-2-1-1-1-2-1-1-2-3-3-2-1-2-2-1-1-2-1-1-2-1 0-2-2 0-1-2-2-1-1-3-1-2 0-1-2-1-3-1 0 1 0 1 0 3 1 1 2 2 2 1 1 2 1 2 2 1 1 3 1 1 0 1 1 2 1 0 1 1 1 1-1 2-1-2-2-1-2-2-2 0 0-2 0-2-1-1-2-1-1 0-2-1-2-2 2 0 1-1 0-1-2-2-2-1-1-2-1-1-1-3Z", + "Morocco": "M494 136l1 1 0 2 1 3 0 2-3 0-2 1-1 0 0 3-3 1-2 1-2 1-3 0-4 2 0 4 0 1-2 0-2 1-1-1-3 1-1 2-2 4-4 3-1 3-1 2 0 1-6 0 0-1 1-1 1-2 1-3 1-1 2-2 0-2 1-2 2-1 2-2 1-2 3 0 2-2 1 0 2-3 0-3 1-3 0-1 2-2 3-1 2-1 2-3 1-2 2 0 1 1 3 0 3 1Z", + "Netherlands": "M519 85l0 3-1 1-1 0 0 3-1 0-2-2-3 1-2 0 2-1 2-4 4-1Z", + "New Zealand": "M991 345l-1 1-1 2-2 1-2-1 2-2-1-2-3-1 0-1 2-1 0-2 0-2-1-2-1-1-2-3-1-2 1 0 1 2 2 0 1 3 2 3 0-2 1 1 1 2 2 1 2 0 1-1 2 0-1 3-1 1-2 0 0 2ZM971 354l3-1 1-2 2-2 1 0 0-2 2-1 1 1 0 1 2-1 1 1 0 1-1 2-2 2-1 1 1 1-2 0-3 1 0 2-2 3-2 1-2 1-2 0-2-1-3 0 0-1 1-2 4-3 1-1Z", + "Nigeria": "M507 216l1-5 0-1 0-2 2-3 1-1-1-2 0-4 1-1 0-1 4-1 3 1 1 1 1 0 2-1 3 2 1 0 2-2 2 1 2-1 2 1 2-1 3 3 1 1 0 1-2 2-1 2 0 2-2 2-1 1 0 2-1 1 0 1-2 1-2-1-1 0-2 1-2 3 0 2-3 1-1 0-1 1-3-1-1-1-1-2-2-2-2 0Z", + "Norway": "M542 12l1-1 4 0 4 1 9 2-7 1-2 2-2 1-1 2-4 0-6-2 3-1-4 0-6-3-2-2 8-1 1 1ZM586 40l-4 1-3 0 2-1-4-2-4 1-2 2-2 2-3-1-4 0-3-1-2 0-1 0-1 2-5 0-1 1-2 0-2 2-3 3-4 4 1 1-1 1-3 0-2 3 0 4 2 1-1 3-2 2-1 2-2-2-6 3-3 1-4-1-1-3-1-7 2-2 8-2 5-3 5-4 7-5 5-2 7-4 6-1 5 0 4-2 5 0 5 0 9 2-4 0ZM576 11l-4 1-8 1-8-1-5-1-3-1 9-1 4 1 3-1 7 1ZM569 17l-7 1-4 0 1-1-1-1 6-1 1 1Z", + "Pakistan": "M716 135l-2 2-4 0-4 0-1 1 1 2 1 2 2 2-2 1 0 2-3 3-2 3-3 3-3 0-3 2 2 2 0 2 2 1 0 3-6 0-2 2-2-1 0-2-3-2-5 0-4 0-4 1 1-4 4-1 0-1-2-1 0-2-2-1-2-2-1-2 5 2 3-1 1 1 3-1 3-1 0-2 2-2 2 0 2-1 1 0 2 0-1-2 2-2 1 0-1-2 3 0 1-1 0-1 1-1 0-2-1-1 2-1 3-1 3 0 1-1 2 0 2 1 1 3Z", + "Peru": "M306 245l-3 0-2 1-3 2-1 1 0 3-2 1 0 1 1 3 1 1 0 2 1 0 1 1 3 0 2-1 0 4 1 0 2 0 2 4 0 3-1 2-1 2 1 1 0 3-1 3-1 2-1 0-3-1-1-1-5-3-5-3-2-2-1-2-2-5-3-5-3-5-1-2-1-2-2-1-2-2 1-1-1-3 1-1 2-2 0 1 0 2 1-1 1 1 1 1 2-1 0-2 2-2 3-1 3-3 1-2 0-2 2 1 1 1 1 1 2 3 2 0 2-1 1 1 1 0 2 1-1 3Z", + "Poland": "M565 84l0 1 1 1 0 1-2 1 1 1 0 1 2 2-2 2-2 2 0 1-3-1-2 0-1 0-2 1-1-1-1 0-2-2-2 0-2-1-2 0-2-1-1-1-1-1-1-3-1-1 0-2 2-1 4-1 4-1 3 0 3 1 3 0 5 0 2 1Z", + "Portugal": "M475 117l1-1 1 0 1 1 1 0 2 0 1 1-1 1 0 2-1 2-1 0 1 2 0 2 0 1-1 1-1 2-1 0-2 0 1-2-1-2-1 0 0-1 0-2 1-1 0-1 1-2 0-1-1-1Z", + "Romania": "M578 107l2 0 1 0 1 1-1 1-2 3-1 0-2-1-4 0-1 1-4 0-2-1-1 1-1-2-1-1-2 0 0-1-2-1-2-2 2 0 2-2 1-2 2-1 1 0 2 0 2 0 1 1 3-1 2-1 2 1 1 2 1 1 0 2 0 1Z", + "Russia": "M760 8l6 0 6 1 6 3 0 2-6 1-8-1-5-1-2-2-4-1ZM786 13l7 2-1 1-16 1 5-4 3 0ZM886 22l7 0 10 1-2 2-10 0-5 1-6-2 2-2ZM912 24l7 1-4 1-4 0-5-1 1-1ZM889 30l2-2 4 0 4 1-4 1-6 0ZM625 9l5 0 4 0 2 0 3 0 4 0-1 1-4 0-2 0-4 1-3-1 2 0ZM563 82l-5 0-3 0 0-1 4-1 3 1 1 0 0 1ZM649 28l6-2 0-1 6-2 9-1 9-1 5-1 5 0 2 1-2 1-9 1-9 1-9 3-4 3-4 2 1 3 5 2-2 0-9 0-1-1-5-1 0-2 3 0 0-2 5-2ZM897 84l1 3 0 3 1 2 3 5-4-1-2 4 3 3 0 2-2-2-2 3-1-3 0-2 0-3 1-2 0-4-2-3 1-4 2-1-1-1 1-1ZM863 116l0-2 1 0 1-3-1-3 2-1 4 1 2-3 1-3 1-1 1-2-5 0-2 2-4 0-1-3-4-2-4-1-1-3-1-1-1-2-2-2-3-1-4-1-3 0-4 0-2 2 1 0 0 2-1 1-3 3 0 1-4 2-3-1-3 0-2-1-1 0-4 2-4 0-3 1-3-1-3 0-1-1-3-1-3-1-3 1-3 0-4-1 0-2-4-1-2 0-3-1-3 3 1 1-3 2-4 0-3-1-1-1-3 0-3-1-4 2-5 2-3 0-1 1-2-2-3 0-2-1-2 0-1-2-1-1-4 1-4-1-2 1-6-7-3-2 1-1-7 3-3 0 0-2-3-1-3 1-1-3-5-1-3 2-7 1-1 0-10 1-2 1 2 2-2 1-2 2 4 2-1 1-4 0-4-1-4 1-3 1-4-1-6-2-4 0-6 3 0 2-3-2-2 3-1 3 2 2 2 0 2 2 0 1 1 0-1 2-3 1-2 2 2 3 0 2 3 3-2 1-1 1-2-2-3-1-1-1-2 0-2 0-4-2-4 0-3-1-4-2-3-1-2-1 2-1 2-2-1-1 4-1-3-1 0-1 2-1 2 0 0-2 1-2-4-1-1 0-2-2-2 1-4-1-1-2-2 0 1-1-2-2-3 0-2 1-1 0 0-2-1-1 3 0 1-1-3-1-1-1-2-2 1-2-3-1-1 1-4-2-1-1 0-2-1 0 1-1-1-3 2-1 3-2-3-2 6-3 2-2 2-1-5-2 2-2-3-2 2-2-3-4 2-2-4-2 0-2 3 0 4-1 3-1 5 2 7 0 11 4 2 1 0 2-3 1-4 1-13-2-2 0 5 2 0 2 0 2 4 1 2 1 0-1-2-2 2-1 7 2 2-1-2-2 7-2 2 0 3 1 2-2-3-2 2-1-2-2 7 1 2 1-3 1 0 1 2 1 4 0 1-2 6-2 9-2 2 0-2 2 3 0 2-1 5 0 4-1 4 2 3-2-3-2 1-1 8 1 4 1 10 3 2-1-3-2-3-1 1-1-2-2 5-3 2-3 2-1 8 1 0 2-2 2 1 1 1 2 0 4 3 1-2 2-5 4 3 1 1-1 3-1 1-2 2-1-1-1 1-2-3-1-1-1 3-3-4-2 5-2-1-2 2 0 1 2-1 2 3 1-1-2 4-1 6-1 5 2-2-2 0-3 4-1 7 0 6 0-2-1 3-2 3 0 6-2 7 0 8-1 3 0 6-1 5 0 1-1 2-1 7-1 5 0-4 1 6 1 1 1 2-1 9 0 6 2 2 1-1 1-3 1-7 1-2 1 3 1 4 0 3 0 1 2 2-1 4-1 9 1 1 1 11 1 0-2 6 0 5 0 4 1 1 2-1 1 3 3 5 1 2-3 5 1 5-1 5 1 2-1 5 1-2-3 3-1 25 2 3 1 7 3 11-1 6 0 2 2 0 2 3 0 4 0 5 0 5 0 5 0 5 3 3-1-2-2 1-1 9 0 6 0 8 2 4 1 0 11-4 1-3 0 2 1 2 3 1 0 1 2-6 0-8 2-3 0-4 2-4 2-1 1-4-2-7 2-1-1-3 1-4 0-1 2-3 3 0 1 3 0 0 4-3 0-1 3 1 1-5 1 0 4-5 0 0 3-4 3-2-2-1-4-1-7 1-3 2-2 1-1 4-1 5-3 5-3 5-3 2-3-4 0-1 2-7 3-2-3-8 1-7 4 3 2-7 1-4 0 0-2-4 0-3 1-9 0-9 0-9 6-11 6 5 1 1 1 3 1 2-1 3 0 4 3 0 2-2 3-1 3-1 5-4 4-1 2-4 3-4 3-1 2-4 1-2 0-2-1-3 2ZM0 42l7 2 7 3 0 1 2 1-1-2 8 0 5 3-3 1-4 1 0 2-1 1-3 0-2-1-4-1 0-1-3-1-3 1-2-1 1-1-4 0 2 2-2 1ZM0 35l3 0 4 0-3 1-4 1 0-2ZM1000 35l0 2-3 0-1-1ZM593 106l3 0 1 0 2 1 2 0-3 2-4 1-1 0 0-2-3-1 3-1Z", + "South Africa": "M545 313l2-2 1 1 0 1 2 0 1 1 2 0 2-2 0-10 3 3-1 2 3 1 1-2 2 0 0-2 2 0 1 0 1 1 3 0 1-1 1-2 2 0 0-1 1-2 3-2 4-2 1 0 1 0 3 0 1 4 1 2-1 3-1 1-1 1-1 1 2 2 2 0 0-1 2 0-1 2 0 2-1 1-1 2-2 1-1 2-2 2-3 3-2 1-2 2-3 1-1 0-2 0-1 1-3-1-2 1-1-1-3 1-3 1-1 1-2 0-1-1-2-1 0-2-1-2 1-3-2-2-2-3ZM580 314l-1-1-1 0-2 2-1 1 2 2 2-1 1 0 1-2Z", + "South Korea": "M850 128l2 0 1-1 2 0 1 0 3 2 1 2 0 3-1 2-3 0-2 2-3 0 0-2 1-2-2-3 2 0Z", + "Spain": "M479 130l1-2 0-1 0-2-1-2 1 0 0-1 1-3 1-1-1-1-1 0-2 0-1-1-1 0-1 1 0-2-1-1 4-2 3 0 4 0 3 1 2 0 5 0 1 1 5 1 1-1 3 2 3-1 0 2-2 2-4 0-2 3-1 2 1 2-1 1-1 2-2 0-2 2-3 1-3-1-2 1-1 1-1 0-1-1-1-1Z", + "Sweden": "M531 70l1-2 2-2 1-3-2-1 0-4 2-3 3 0 1-1-1-1 4-4 3-3 2-2 2 0 1-1 5 0 1-2 1 0 4 2 4 2 0 4 1 1-4 1-3 2 0 1-4 3-5 2-2 4 2 2 2 1-2 4-3 0-1 5-2 2-3 0-2 2-3 1-1-3-2-3Z", + "Switzerland": "M527 101l-1 1 2 1 1 0 0 1-1 1-2-1-1 1-1 1-2 0-2 0-1 0-1-2-1 1 0-1 2-2 1 0 3-1 1-1Z", + "Taiwan": "M838 166l-1 4-2 2-1-2 0-2 1-3 2-2 2 1Z", + "Thailand": "M792 194l-2-1-4 1-2 2 1 3-3-1-2 0 0-2-2 0 0 3-2 4-1 3 1 2 1 0 2 2 0 3 2 1 1 1 2 1-1 1-2 1 0-2-3-1-1-1-1-1-1-2-1-1-1 2 0-2 0-2 1-2 1-3 2-3-1-2 0-2-1-1-2-2 0-2 2-3-1-1-2-2-2-3 2 0 1-3 2-1 2-1 1 0 1 0 0 2 2 0 0 3 0 3 3-2 2 0 3 0 2 2 0 3 2 2 0 2Z", + "Turkey": "M624 130l-1 1-4-2-1 1-4 0-1 0-3 1-3 0-1 0-3 1-1 1-2 1-1-1 1-1-1 0-3-1-1 2-5 0-2-1-3-1-1 2-2 0-2-2-3 1-2-3-2-2 1-2-1-1 3-3 4 0 1-2 6 0 3-2 3 0 5 0 5 2 4 1 3-1 2 0 3-1 3 0 3 1 0 3 2 0 1 1-1 1 0 3 0 1ZM573 117l2-1 3 1 0 1 3 1-4 0-1 1-3 2-1-1 2-3Z", + "Ukraine": "M588 89l1 0 2-1 3 0 2 2-1 1 2 0 1 1 4 2 2-1 2 2 1 0 4 1-1 2 1 1-3 1-2 1 0 1-2 1-2 1-2 0-3 1 0 1-1 0-2-1-2 0-4 0 0-1-3 0-1 1-2 3-1-1-1 0-2 0 2-1 0-2 3 1-1-2 0-1-1-1-1-1-2 0-2-1-1 0-2 0-3 1-2 0-2 0-2 0-1 0-2-1 1-1 1-1 0-1 2-2 1-1-1-3 2 0 1-1 2 0 3 0 3 1 2 0 1 0 2 0 3 1 1 0 0-2 1 0Z", + "United Arab Emirates": "M643 166l3 0 2 0 2 0 2-2 2-1 2-2 1 3-2 0 0 2-1 2-1 1 0 1-9-1-1-2Z", + "United Kingdom": "M483 84l-2-1-2 0 1-1-1-2 2 0 3 2ZM491 85l1-2-2-1-3-1 0-2-3 1 0-3-1-1 1-3 2-3 2 1 4-1-3 3 3 0 3 0-1 2-3 3 3 0 3 4 2 0 2 3 0 1 4 1-1 2-1 0 1 2-2 1-4 0-5 1-1 0-2 1-3-1-2 2-1-1 4-3 3-1-5 0-1-1 3-1-1-1 0-2Z", + "United States": "M159 97l8 0 8 0 3 0 8 0 8 0 9 0 8 0 9 0 10 0 6 0 0-1 1 2 3 0 3 1 2 1 3-1 3 1 4-1 2 1 3 1 2 1 2 1 1 1 1 0 1 1 1 1 3 1 0 3 1 2-1 2-1 1-1 2 1 1 4-2 3 0 4-2 0-1 3-1 3 0 1-1 3-2 1-1 4 0 5 0 2-1 1 0 1-1 1-2 2-2 2 0 2 1 0 3 2 2-3 2-3 1-3 1-1 2-1 2 1 1 1 0 0-1 1 2-2 0-2 0-2 1-1 0-1 0-3 1 4-1-3 1-2 0 0 3-2 2-2-1 1 1 1 2-1 1-2 2 1-2-2-1 0-2-1 1 1 2-2-1 2 1 0 3 1 1 1 3-2 2-3 0-2 2-1 0-2 1-3 3-2 1-1 2 0 2 0 2 1 2 1 2 0 1 2 4 0 2-1 1 0 1-2 0-1-1-1-1-1-2-2-2 0-1 0-2 0-2-3-2-1 0-2 1-2-1-2-1-3 0-3 0-2 0-1 1 1 1-2 1-2 0-3-1-2 0-2 0-2 0-2 0-3 3-2 1-2 1 0 1 0 2 0 2-1 1-2-1-2-1-1-1 0-2-2-2-1-1-1-2-2-1-3 0-1 2-3-1-1-1-1-1-1-2-1-1-2-1-1-1-5 0 0 1-2 0-5 0-7-2-4-1-3 0-3 0-1-1-2-2-1 0-2-1-1-1-2 0-1-2-3-3-2-4-2-2-2-2 0-2-2-2 1-2 0-2-1-2 1-3 1-3 0-2-1-4-1-2 0-2 4 1 1 3 1-3ZM68 178l2 1-1 1-1 1-1-1-1-1 1-2ZM67 176l-1 0-1-1 1 0ZM65 175l-2 0 0-1ZM61 173l1 1-1 0-1-1ZM57 172l-1 0 1 0ZM38 66l2 0 0 1-2 0-1 0-2-1ZM74 72l2 0 1 1-2 2-3 1-1-1-1-1 3-1ZM108 40l0 10 0 16 3 0 3 1 2 1 2 2 3-2 3-1 1 2 2 1 3 1 1 2 3 3 5 2 0 2-2 1-1-1-3-1 0-2-4-2-1-3-3 0-5 0-3-1-6-3-2-1-5-1-4 1-5-2-4-1-3 1 1 2-2 0-3 0-2 1-3 1-1-2 1-2 3-1-4 1-2 1-4 2 2 2-2 2-3 1-3 1-1 1-4 1-1 2-3 1-2 0-3 1-3 0-2 1-5 1 3-2 3 0 3-2 3 0 1-1 4-2 3-2 0-2 2-1-3 1-3 0-2-1-1-1-3 1-2 0 0-1 0-1-1-1-4 0-2-1-2-1 0-1-2-1 1-2 2-2 1-1 2 0 2 0 2-1 2 0 2-1 0-1-2-1 2-1-1 0-3 1-3 0-4 0-4 0-1-1-4-2 4-1 6-2 2 0 0 2 6 0-2-2-4-1-2-1-2-2-4-1 1-1 5 0 4-1 0-2 3-1 3 0 5-2 3 1 4-2 4 1 2 1 2-1 4 1 4 1 3-1 6 1 5 1 2 0 4-1 4 1ZM23 56l2 1 1-1 3 1 2 1-2 0-2 0-1-1-3 0Z", + "Vietnam": "M790 204l2-1 3 0-1-2 5-2 0-3-1-2 1-3-1-2-2-2-2-2-2-4-3-1 2-2-1-2-3 0-2-3-1-2 1-1 3 0 2 0 3-2 1 2 2 0 0 2 1 1 3 0-4 3-2 2 0 2 2 3 2 4 3 2 1 2 2 5-1 5-2 2-3 2-2 2-4 2-1-1 1-2Z" + } } diff --git a/hugo_stats.json b/hugo_stats.json index 93df9d8..796a58d 100644 --- a/hugo_stats.json +++ b/hugo_stats.json @@ -183,6 +183,7 @@ "worldmap-city-head", "worldmap-city-login", "worldmap-city-people", + "worldmap-country", "worldmap-dot", "worldmap-hit", "worldmap-hit-left", diff --git a/layouts/_default/home.html b/layouts/_default/home.html index 5bc5158..58a6261 100644 --- a/layouts/_default/home.html +++ b/layouts/_default/home.html @@ -45,7 +45,48 @@

Contributors

+ {{/* Every country anybody on the map is in, shaded whole. Two things + are being said at once and they are different claims: the shade + is the country somebody is in, the dot is the city they are in. + A country nobody named a city in — "United States" is 39.5N + 98.35W, a field in Kansas — gets only the shade, which is exactly + what was given: somewhere in here. Drawing that as a dot claimed + the precision of San Francisco 500 units away. + + One shade per country, not one per mark: China has four cities on + the map and the United States six marks, and painting the same + path four times would have stacked four alphas into a country + brighter than its own dots. + + Drawn before the marks and outside their groups, so every dot and + every label sits on top of every shade. Paths rather than a + wrapping `` for the same reason the pulse rhythms are keyed to + `worldmap-place`: `nth-of-type` counts elements of one type among + their siblings, and a group here would have shifted every mark's + bucket by one. + + Only the countries tools/worldmap.mjs has an outline for. It has + one for every country tools/locations.json can place anybody in + except Hong Kong and Singapore, which are smaller than the + dataset resolves — they are on the map as city dots, and the + `with` below is what lets them be. */}} + {{ $countries := slice -}} {{ range .places -}} + {{ $countries = $countries | append .country -}} + {{ end -}} + {{ range uniq $countries -}} + {{ with index $map.countries . -}} + + {{ end -}} + {{ end -}} + {{/* Every place except the country-level ones the shade above has + already accounted for — see partials/worldmap-marks.html for which + those are and what it costs. Ranged from the same partial as the + hover targets below and as the stylesheet that positions them, + because those rules are `nth-child` and the three lists have to + agree element for element. */}} + {{ $marks := partial "worldmap-marks.html" (dict "data" . "map" $map) -}} + {{ range $marks -}} {{/* Position and size, from the one place that computes them: the stylesheet generated in head/resource-hints.html has to put each card's hover target exactly on top of the dot drawn here, and @@ -119,7 +160,15 @@

Contributors

city — see the note there on why no automatic rule works once two of them are 2.6 units apart. Hidden on narrow screens by the stylesheet, where the map is too small to - carry text and the list below says the same thing. */}} + carry text and the list below says the same thing. + + Every mark drawn here is named, country-level ones included: + the countries that would have wanted their name left off, + because their cities were already naming the same shape, are + not marks any more (partials/worldmap-marks.html). What is + left of a country mark is South Africa, Romania, Italy and New + Zealand — the countries whose name is the only name on the map + for them. */}} {{ $short := .short -}} {{ with .offset -}} Contributors head/resource-hints.html, not in a `style` attribute here, which the site's own `style-src 'self'` refuses. That is also why the order of these divs matters: the generated rules address them by - `nth-child`, so this must stay a flat list in the order of - `.places`. + `nth-child`, so this must stay a flat list of exactly the marks + partials/worldmap-marks.html returns, in that order. This layer takes the pointer for the whole map, so it is also what replaced the dots' `` tooltips — the card names the city, @@ -157,7 +206,7 @@ <h2 class="feature-grid-title">Contributors</h2> hidden` until something in it has focus, and a hidden link is not focusable, so without a stop on the mark itself there is no way in. */}} <div class="worldmap-hits"> - {{ range .places -}} + {{ range $marks -}} {{ $pos := partial "worldmap-place.html" (dict "map" $map "place" .) -}} {{/* Which side the card opens on, decided here because no script measures it at runtime: everything east of the middle opens to diff --git a/layouts/partials/head/resource-hints.html b/layouts/partials/head/resource-hints.html index 5e97571..3c4f62e 100644 --- a/layouts/partials/head/resource-hints.html +++ b/layouts/partials/head/resource-hints.html @@ -24,10 +24,14 @@ assets/scss/common/_custom.scss. Positions and sizes come out of partials/worldmap-place.html, the same partial - the svg's dots are drawn from, because these two have to agree to the pixel. */}} + the svg's dots are drawn from, because these two have to agree to the pixel. The + list itself comes out of partials/worldmap-marks.html for the same reason, and it + is the stricter of the two requirements: these rules are `nth-child`, so this has + to be the same marks in the same order as the divs on the page, not merely the + same arithmetic. */}} {{ $map := site.Data.worldmap -}} {{ $rules := slice -}} -{{ range $i, $place := site.Data.contributors.places -}} +{{ range $i, $place := partial "worldmap-marks.html" (dict "data" site.Data.contributors "map" $map) -}} {{ $pos := partial "worldmap-place.html" (dict "map" $map "place" $place) -}} {{/* Percentages of the layer, which is the svg's own box — so the targets track the map through every width it renders at, exactly as the dots do. @@ -53,6 +57,22 @@ {{ $room := cond (gt $pos.x (mul 0.5 $map.width)) (sub $left (div $size 2.0)) (sub (sub 100.0 $left) (div $size 2.0)) -}} {{ $rules = $rules | append (printf ".worldmap-hit:nth-child(%d){left:%.3f%%;top:%.3f%%;width:%.3f%%;--map-room:%.3f}" (add $i 1) $left $top $size $room) -}} {{ end -}} -{{ $css := resources.FromString "css/worldmap-hits.css" (delimit $rules "\n") | resources.Minify | fingerprint -}} +{{/* The target path carries a hash of the rules, which is not decoration: it is what + keeps this stylesheet from going stale against the page it positions. + + `resources.FromString` is keyed on the path it is given, and Hugo caches generated + resources under `resources/_gen` between builds. With a fixed name, a build whose + rules had changed — a contributor added, a city resolved, a mark reordered — could + be handed the bytes of an earlier one, and the failure is silent and total: the + rules are `nth-child`, so a stylesheet written for a different number of marks, or + the same marks in a different order, positions every card on somebody else's dot. + London's dot opened Bengaluru's card, which is exactly how this was found. A path + that changes with the content cannot be answered from the cache at all. + + The `fingerprint` below still earns its place — it is what produces the integrity + hash the `style-src 'self'` policy is paired with, and the immutable URL — but it + runs after the fact and cannot fix a resource that was already the wrong one. */}} +{{ $body := delimit $rules "\n" -}} +{{ $css := resources.FromString (printf "css/worldmap-hits.%s.css" (hash.XxHash $body)) $body | resources.Minify | fingerprint -}} <link rel="stylesheet" href="{{ $css.RelPermalink }}" integrity="{{ $css.Data.Integrity }}"> {{ end -}} diff --git a/layouts/partials/worldmap-marks.html b/layouts/partials/worldmap-marks.html new file mode 100644 index 0000000..f06e7d9 --- /dev/null +++ b/layouts/partials/worldmap-marks.html @@ -0,0 +1,47 @@ +{{/* The marks the contributor map draws, which is not every place in + data/contributors.json. + + A country-level place — contributors who said "India" and no city — is dropped + where that country has cities on the map as well and an outline to shade. The + shade over India is already the claim those contributors support: somebody is + somewhere in this country. Drawing a second mark for it put a card on a field in + central India that opened next to Bengaluru's, saying "India" where the map had + just said Bengaluru, and there was nothing to point at it with in the first + place — a shade is not a hover target, so the mark was a card that only appeared + when the pointer crossed empty land. + + Stated plainly, because it is a real loss: those contributors are then nowhere on + the map by name. Four people today — two who gave "USA" and two who gave "India" — + are counted in the summary above it and in the region shares beside it, and + represented on the map by their country's shade and nothing else. What buys that + is that a centroid is not where they are: the alternative was a mark claiming a + place none of them named. + + Where the country has no cities — South Africa, Romania, Italy, New Zealand — the + place is kept and drawn like any other mark, dot and name both. And where it has + no outline to be shaded by, it is kept whatever else is true, so a country the + 110m dataset cannot draw still puts its people on the map: today that is Hong Kong + and Singapore, which only ever come through as cities anyway. + + One partial rather than the same test in three templates, and that is the point of + it. The svg's marks, the hover targets over them and the generated stylesheet that + positions those targets are three lists that have to be the same list in the same + order — the rules are `nth-child`, so a template that filtered differently from the + others would silently put every card on somebody else's dot. + + Called with `data` (site.Data.contributors) and `map` (site.Data.worldmap). */}} +{{ $data := .data -}} +{{ $map := .map -}} +{{ $withCities := slice -}} +{{ range $data.places -}} +{{ if not .countryOnly -}} +{{ $withCities = $withCities | append .country -}} +{{ end -}} +{{ end -}} +{{ $marks := slice -}} +{{ range $data.places -}} +{{ if not (and .countryOnly (and (in $withCities .country) (index $map.countries .country))) -}} +{{ $marks = $marks | append . -}} +{{ end -}} +{{ end -}} +{{ return $marks -}} diff --git a/tools/contributors.mjs b/tools/contributors.mjs index cfe90da..4380620 100644 --- a/tools/contributors.mjs +++ b/tools/contributors.mjs @@ -70,7 +70,11 @@ if (!token) { console.warn("warning: no GITHUB_TOKEN set, expect to be rate limited\n"); } -async function request(path) { +// `missing`: what to return for a 404 instead of stopping the run. Only the profile +// lookups pass it, and only because a login read out of a commit is a login as it was +// on the day of the commit — an account renamed or deleted since is a 404 and is not a +// reason to leave the whole map stale. +async function request(path, { missing } = {}) { const headers = { Accept: "application/vnd.github+json", "User-Agent": "inftyai-website", @@ -81,14 +85,16 @@ async function request(path) { path.startsWith("https://") ? path : `https://api.github.com/${path}`, { headers }, ); + if (response.status === 404 && missing !== undefined) return null; if (!response.ok) { exit(`GET ${path} responded ${response.status} ${response.statusText}`); } return response; } -async function github(path) { - return (await request(path)).json(); +async function github(path, options) { + const response = await request(path, options); + return response === null ? options.missing : response.json(); } // Every page, not just the first. A repository with more than one page of commits @@ -123,33 +129,108 @@ async function githubAll(path) { // The cost is pagination — about twenty requests across the seven projects instead of // seven — which is nothing against the hourly limit, and the per-contributor profile // lookups below already dwarf it. -const logins = new Set(); -// How much each person has done, for the panel the legend opens on hover. Both come -// out of the commit pages that are already being read for the headcount, so the -// ranking costs no extra requests — which is the only reason it is commit-based -// rather than something the API would have to be asked for separately. -const commitsBy = new Map(); -const reposBy = new Map(); +// +// Everyone with a commit, keyed by their login lowercased: GitHub logins are +// case-insensitive, and the same person arrives spelled two ways — `googs1025` from +// the API's author field and `CYJiang <86391540+googs1025@users.noreply.github.com>` +// from a co-author trailer. Keyed by the login itself, that was two contributors. +// +// How much each has done travels with them, for the order the cards list faces in. +// Both numbers come out of the commit pages that are already being read for the +// headcount, so the ranking costs no extra requests — which is the only reason it is +// commit-based rather than something the API would have to be asked for separately. +const contributors = new Map(); + +// A commit's `author` is the one person GitHub attributed it to. Where two people +// wrote it, the second is a `Co-authored-by:` trailer in the message and appears in no +// field of the API's response — so reading `author` alone silently dropped them. +// +// Not a corner case here. Every project added to Awesome-LLMOps arrives as a pull +// request that inftyai-agent squash-merges, which makes that machine account the +// author and the person who did the work the co-author. They were counted as nobody, +// while the same contribution to a repo whose merges a human presses counted as a +// contributor — and around twenty of the people already on the map are Awesome-LLMOps +// submitters, so the map was applying two rules to one kind of work. +const COAUTHOR = /^co-authored-by:\s*(.*?)\s*<([^>]+)>\s*$/gim; + +// The only address that names a GitHub account rather than a mailbox: +// `id+login@users.noreply.github.com`, or the older `login@…`. The login is taken from +// there and nowhere else — the display name beside it is free text, and guessing from +// it would be wrong in both directions: `Kerry He` is the account `kerry-he`, which +// looks guessable, and `Se7en <chengzw258@163.com>` is `cr7258`, which does not. A +// name that happens to be somebody else's login would credit a stranger. Unresolved +// trailers are reported at the end instead, and in practice they are people a +// noreply trailer or an ordinary commit elsewhere has already found. +// +// Loose about the login's own shape, because the profile lookup below is what decides +// whether an account exists. +const NOREPLY = /^(?:\d+\+)?([\w-]+)@users\.noreply\.github\.com$/i; + +// Co-authors that are not people and have no account to look for: the assistants that +// sign commits in these repositories. Skipped rather than reported, so the report of +// unresolved trailers stays a list of contributors to look into rather than one line +// of noise per model release. +const NOT_PEOPLE = new Set(["noreply@anthropic.com"]); + +// Trailers naming somebody no login could be read from, for the report at the end. +const unresolved = new Map(); + +// Adds one commit to somebody's total, and returns the spelling of their login that +// the rest of the run uses. Null for anyone who is not a person to count. +function credit(login, repo) { + const key = login.toLowerCase(); + // `[bot]` is the suffix GitHub gives every App's account, and EXCLUDE covers the + // machine accounts that are ordinary users as far as the API is concerned. + if (key.endsWith("[bot]") || EXCLUDE.has(key)) return null; + let entry = contributors.get(key); + if (!entry) { + entry = { login, commits: 0, repos: new Set() }; + contributors.set(key, entry); + } + entry.commits += 1; + entry.repos.add(repo); + return entry.login; +} + for (const repo of repos) { const commits = await githubAll(`repos/${repo}/commits?per_page=100`); const seen = new Set(); let unattributed = 0; - for (const { author } of commits) { - // No linked account: a commit whose author email belongs to no GitHub user. - // Nothing to look a location up for, so it can only be counted and reported. - if (!author) { - unattributed += 1; - continue; + for (const commit of commits) { + const { author } = commit; + // Everyone this commit is the work of: the author GitHub linked to an account, + // then every co-author a login can be read from. A Map keyed on the lowercased + // login, so that the common `Signed-off-by` plus `Co-authored-by` pair naming the + // author again is one commit for them rather than two. + const writers = new Map(); + const writer = (login) => { + if (!writers.has(login.toLowerCase())) + writers.set(login.toLowerCase(), login); + }; + // `type` is "Bot" for GitHub Apps. A missing author is a commit whose author + // email belongs to no GitHub user — there is nothing to look a location up for, + // and a co-author trailer may yet name somebody, so it is left to the count below. + if (author?.type === "User") writer(author.login); + for (const [, name, email] of commit.commit.message.matchAll(COAUTHOR)) { + if (NOT_PEOPLE.has(email.toLowerCase())) continue; + const login = NOREPLY.exec(email)?.[1]; + if (login) { + writer(login); + continue; + } + if (name.toLowerCase().endsWith("[bot]")) continue; + const trailer = `${name} <${email}>`; + unresolved.set(trailer, (unresolved.get(trailer) ?? 0) + 1); } - // `type` is "Bot" for GitHub Apps; EXCLUDE covers machine accounts that are - // ordinary users as far as the API is concerned. - if (author.type !== "User") continue; - if (EXCLUDE.has(author.login.toLowerCase())) continue; - seen.add(author.login); - logins.add(author.login); - commitsBy.set(author.login, (commitsBy.get(author.login) ?? 0) + 1); - if (!reposBy.has(author.login)) reposBy.set(author.login, new Set()); - reposBy.get(author.login).add(repo); + const credited = [...writers.values()] + .map((login) => credit(login, repo)) + .filter((login) => login !== null); + // A commit whose author email belongs to no GitHub user and whose trailers named + // nobody either: there is no account to look a location up for, so all it can be + // is counted and reported. A bot's commit is not this — it has an account, and + // that account is deliberately not a person. + if (!author && !credited.length) unattributed += 1; + for (const login of credited) seen.add(login); } console.log( `${repo}: ${seen.size} contributors across ${commits.length} commits` + @@ -179,8 +260,24 @@ let located = 0; // from this, matched back to its place below. const people = []; -for (const login of [...logins].sort()) { - const { location, avatar_url: avatar } = await github(`users/${login}`); +for (const [id, entry] of [...contributors].sort(([a], [b]) => + a.localeCompare(b), +)) { + const { login, commits, repos } = entry; + const profile = await github(`users/${login}`, { missing: null }); + + // A login is a login as it was on the day of the commit it was read from, and three + // of the ones in these repositories now 404: renamed or deleted since. Dropped + // rather than counted, because there is no profile to place them by and no avatar to + // show — all they could add is another line to the "Others" share. + if (profile === null) { + contributors.delete(id); + console.warn( + `warning: no account for ${login}, named in a commit — skipping`, + ); + continue; + } + const { location, avatar_url: avatar } = profile; // `place` stays null until one is matched, and a null is somebody no card will // ever list: no location, a location the table has not learned, and a known @@ -195,8 +292,8 @@ for (const login of [...logins].sort()) { // Only the ranking, and only until the sort below — neither number reaches // data/contributors.json. The card shows a face and a handle; a commit count // beside them invited a reading of the map as a scoreboard. - commits: commitsBy.get(login) ?? 0, - repos: reposBy.get(login)?.size ?? 0, + commits, + repos: repos.size, place: null, }; people.push(person); @@ -216,8 +313,8 @@ for (const login of [...logins].sort()) { if (place === null) continue; // The mark whose card will list them. The label, because that is what identifies - // one mark on the map — and note that it can be a country-level fallback, which - // may not survive the pruning below. + // one mark on the map — and it can be a country-level fallback, which is a mark + // like any other and gets a card like any other. person.place = place.label; const existing = places.get(place.label); @@ -237,29 +334,22 @@ for (const login of [...logins].sort()) { located += 1; } -// A country-level place is a fallback: it says "somewhere in this country", which -// is worth drawing only while nothing better is known about that country. Once a -// city there is on the map, the country's own mark goes — a blob over China beside -// five Chinese cities reads as a sixth city that nobody lives in. +// Every mark that was matched is drawn, country-level fallbacks included. // -// Snapshot first, because everyone a dropped mark stood for still belongs to a -// region: their country is known, only their position is not. Everything derived -// below counts `matched` rather than `places`, and that is what holds the -// percentages still while the map loses a mark. +// This used to prune them: a country mark said "somewhere in this country", and once +// a city there was on the map the country's own mark went, on the grounds that a blob +// over China beside five Chinese cities reads as a sixth city that nobody lives in. +// That is true of the blob and it was the wrong thing to weigh. The mark was not the +// only thing dropped — the people it stood for went with it, off the card that names +// them and into a region percentage, so writing "India" instead of "Bengaluru" was +// enough to be counted and not shown. The contributors are the baseline here: a mark +// exists to name whoever is under it, so no mark that has somebody under it is +// dropped for the drawing's sake. // -// Data-dependent, so it is reversible: if every contributor in a Chinese city left -// and only a bare "China" remained, the country mark would come back. That is the -// rule working, but it does mean the map can change shape from the contributor list -// alone, with no edit to this file. +// What is left of the blob problem is a label, and the label is the answer to it: +// "India" beside a dot in the middle of India is not a city, and the card it opens +// lists the people who wrote it that way. const matched = [...places.values()]; -const mappedCities = new Set( - matched.filter((place) => !place.countryOnly).map((place) => place.country), -); -for (const place of matched) { - if (place.countryOnly && mappedCities.has(place.country)) { - places.delete(place.label); - } -} // The summary beside the map is by region, not by city or country. Ten cities was // a longer list than the map has dots worth explaining, and five of them were @@ -329,22 +419,10 @@ for (const place of places.values()) { } } -// Everyone the table placed in a country whose fallback mark was then pruned: located, -// counted in their region's share, and on no dot — so no card lists them. Reported -// because it is otherwise invisible, and because the fix is a line in -// tools/locations.json for the city they are actually in. -const orphaned = people.filter( - (person) => person.place && !places.has(person.place), -); -if (orphaned.length) { - console.log( - `\n${orphaned.length} contributor(s) matched a country-level mark that a city has` + - ` since replaced, so no card lists them:`, - ); - for (const person of orphaned) { - console.log(` ${person.login} (${person.place})`); - } -} +// Nobody the table placed is off the map any more: the report that used to stand here +// listed the contributors whose country mark a city had replaced, and there is no +// longer such a thing. Every located person is on the mark their `place` names, which +// the check above proves mark by mark. // Shares of every contributor, as whole numbers that still add to 100. // @@ -392,7 +470,7 @@ const ranked = [...regionCounts] // `note` is the only explanation the row gets — a visible one was tried and cut. // It reaches the tooltip and the accessibility tree, and the label alone would // otherwise suggest these people are somewhere else rather than unstated. -const unlocated = logins.size - located; +const unlocated = contributors.size - located; if (unlocated > 0) { ranked.push({ name: "Others", @@ -403,18 +481,19 @@ if (unlocated > 0) { const shares = share( ranked.map((r) => r.count), - logins.size, + contributors.size, ); const output = { // Not rendered anywhere — it is here so that a reader of the file, or of a // diff, can tell how old the snapshot is without going through git log. generated: new Date().toISOString().slice(0, 10), - total: logins.size, + total: contributors.size, located, // One mark each on the map. Largest first, so the template draws the big dots // before the small ones and a city of one is never hidden underneath a city of - // six. Country-level fallbacks that have yielded to a city are already gone. + // six. A country-level fallback is one of these marks, drawn wherever somebody + // gave their country and no more than that. // // `people` is the card the mark opens: a handle and an avatar each, capped at ten // because the card is a panel floating over the map and a mark of thirty would cover @@ -438,10 +517,9 @@ const output = { // fallback is a mark too. Only used by the map's accessible name, which called // India a city before this existed. cities: matched.filter((place) => !place.countryOnly).length, - // How many countries the located contributors are in — from `matched`, so a - // country whose fallback mark was dropped still counts. Not shown, but it is - // what the map's accessible name says, being more use to a screen reader than - // "4 regions". + // How many countries the located contributors are in, which is fewer than there + // are marks: six of these are American. Not shown, but it is what the map's + // accessible name says, being more use to a screen reader than "4 regions". countryCount: new Set(matched.map((p) => p.country)).size, // Regions plus the "Others" remainder: one row each in the summary. `count` is // not rendered — `percent` is — but it stays so the file can be checked against @@ -504,6 +582,25 @@ if (unmatched.size) { } } +// Co-authors written with an ordinary email address, which names a mailbox and not an +// account. Reported rather than resolved, for the reasons NOREPLY carries: there is no +// rule that turns "Se7en <chengzw258@163.com>" into `cr7258`, and a guess from the name +// would sooner or later credit a stranger. +// +// Not a list of people missing from the map. Most of these are somebody an ordinary +// commit or a noreply trailer elsewhere has already found — the list is here so that +// one who is not can be noticed, and the answer to that is a commit of their own, not +// a table of email addresses to keep. +if (unresolved.size) { + console.log( + `\n${unresolved.size} co-author(s) named by email rather than by account, so not` + + ` counted from those commits (they may be counted from others):`, + ); + for (const [trailer, count] of [...unresolved].sort((a, b) => b[1] - a[1])) { + console.log(` ${trailer}${count > 1 ? ` (x${count})` : ""}`); + } +} + function exit(message) { console.error(`error: ${message}`); process.exit(1); diff --git a/tools/locations.json b/tools/locations.json index a2d0f26..0db9fc6 100644 --- a/tools/locations.json +++ b/tools/locations.json @@ -93,6 +93,12 @@ "lat": 1.35, "lng": 103.82 }, + "kuala lumpur": { + "label": "Kuala Lumpur, Malaysia", + "country": "Malaysia", + "lat": 3.14, + "lng": 101.69 + }, "bengaluru": { "label": "Bengaluru, India", "country": "India", @@ -165,6 +171,12 @@ "lat": 41.01, "lng": 28.98 }, + "limassol": { + "label": "Limassol, Cyprus", + "country": "Cyprus", + "lat": 34.71, + "lng": 33.02 + }, "london": { "label": "London, UK", "country": "United Kingdom", @@ -375,6 +387,12 @@ "lat": 41.88, "lng": -87.63 }, + "cleveland": { + "label": "Cleveland, USA", + "country": "United States", + "lat": 41.5, + "lng": -81.69 + }, "boston": { "label": "Boston, USA", "country": "United States", @@ -399,6 +417,12 @@ "lat": 33.75, "lng": -84.39 }, + "tampa": { + "label": "Tampa, USA", + "country": "United States", + "lat": 27.95, + "lng": -82.46 + }, "toronto": { "label": "Toronto, Canada", "country": "Canada", @@ -673,6 +697,13 @@ "lng": 19.4, "countryOnly": true }, + "romania": { + "label": "Romania", + "country": "Romania", + "lat": 45.9, + "lng": 25, + "countryOnly": true + }, "sweden": { "label": "Sweden", "country": "Sweden", @@ -792,9 +823,12 @@ "seoul, south korea": "seoul", "seoul, korea": "seoul", "korea": "south korea", + "kuala lumpur, malaysia": "kuala lumpur", + "kl": "kuala lumpur", "bangalore": "bengaluru", "bangalore, india": "bengaluru", "bengaluru, india": "bengaluru", + "bengaluru, in": "bengaluru", "mumbai, india": "mumbai", "delhi": "new delhi", "delhi, india": "new delhi", @@ -807,6 +841,7 @@ "dubai, uae": "dubai", "tel aviv, israel": "tel aviv", "istanbul, turkey": "istanbul", + "limassol, cyprus": "limassol", "london, uk": "london", "london, england": "london", "england": "united kingdom", @@ -855,6 +890,8 @@ "denver, co": "denver", "austin, tx": "austin", "chicago, il": "chicago", + "cleveland, oh": "cleveland", + "cleveland, ohio": "cleveland", "boston, ma": "boston", "cambridge, ma": "boston", "new york, ny": "new york", @@ -866,6 +903,8 @@ "washington, d.c.": "washington, dc", "dc": "washington, dc", "atlanta, ga": "atlanta", + "tampa, fl": "tampa", + "tampa, florida": "tampa", "toronto, canada": "toronto", "toronto, on": "toronto", "montreal, canada": "montreal", @@ -937,6 +976,7 @@ "Israel": "Asia", "Italy": "Europe", "Japan": "Asia", + "Malaysia": "Asia", "Kenya": "Africa", "Mexico": "North America", "Morocco": "Africa", @@ -959,6 +999,7 @@ "Taiwan": "Asia", "Thailand": "Asia", "Turkey": "Asia", + "Cyprus": "Asia", "Ukraine": "Europe", "United Arab Emirates": "Asia", "United Kingdom": "Europe", @@ -993,13 +1034,13 @@ "anchor": "end" }, "India": { - "dx": 0, - "dy": 23, - "anchor": "middle" + "dx": -11, + "dy": 4, + "anchor": "end" }, "Cambridge, UK": { - "dx": -8, - "dy": 19, + "dx": -11, + "dy": 15, "anchor": "end" }, "Berlin, Germany": { @@ -1012,15 +1053,10 @@ "dy": 4, "anchor": "end" }, - "New Zealand": { - "dx": -8, - "dy": 19, - "anchor": "end" - }, "Dublin, Ireland": { - "dx": 0, - "dy": -11, - "anchor": "middle" + "dx": -11, + "dy": 4, + "anchor": "end" }, "Palo Alto, USA": { "dx": -12, @@ -1028,8 +1064,8 @@ "anchor": "end" }, "Amsterdam, Netherlands": { - "dx": 12, - "dy": 23, + "dx": 11, + "dy": -25, "anchor": "start" }, "Barcelona, Spain": { @@ -1038,19 +1074,49 @@ "anchor": "start" }, "San Francisco, USA": { - "dx": 0, - "dy": -14, - "anchor": "start" + "dx": -11, + "dy": 4, + "anchor": "end" }, "Paris, France": { - "dx": 17, - "dy": 28, + "dx": 11, + "dy": 8, "anchor": "start" }, "Chicago, USA": { - "dx": 8, + "dx": 0, + "dy": -17, + "anchor": "middle" + }, + "London, UK": { + "dx": 0, + "dy": -28, + "anchor": "middle" + }, + "New Zealand": { + "dx": -8, "dy": 19, + "anchor": "end" + }, + "Italy": { + "dx": 11, + "dy": 9, "anchor": "start" + }, + "Bengaluru, India": { + "dx": 0, + "dy": 19, + "anchor": "middle" + }, + "Cleveland, USA": { + "dx": 11, + "dy": 12, + "anchor": "start" + }, + "United States": { + "dx": -11, + "dy": -8, + "anchor": "end" } } } diff --git a/tools/worldmap.mjs b/tools/worldmap.mjs index 119b8af..ac35c51 100644 --- a/tools/worldmap.mjs +++ b/tools/worldmap.mjs @@ -1,18 +1,26 @@ // Regenerates data/worldmap.json — the land silhouette the contributor map is -// drawn on. Run by `make worldmap`; the output is committed, so a normal build -// needs neither this script nor network access. +// drawn on, and the outline of each country a contributor can be placed in +// without a city. Run by `make worldmap`; the output is committed, so a normal +// build needs neither this script nor network access. // -// The source is Natural Earth's 110m land layer, as published in TopoJSON by +// The source is Natural Earth's 110m admin-0 layer, as published in TopoJSON by // world-atlas. TopoJSON is decoded here by hand rather than with topojson-client // + d3-geo, to keep tools/ dependency-free the way tools/og-shot.mjs is: the // whole job is a delta-decode and an equirectangular projection, which is less // code than the install would be. // -// Usage: node tools/worldmap.mjs [land-110m.json] +// countries-110m.json rather than land-110m.json, which is where this started and +// which draws the same coastline: this file carries a `land` object of its own +// *and* the per-country geometry, built from one shared set of arcs. Two files +// would have given the highlight a coastline simplified independently of the +// silhouette it is painted on, and disagreements of a pixel would show as a +// fringe of unshaded land along the coast of every highlighted country. +// +// Usage: node tools/worldmap.mjs [countries-110m.json] import { writeFile, readFile } from "node:fs/promises"; -const SOURCE = "https://cdn.jsdelivr.net/npm/world-atlas@2/land-110m.json"; +const SOURCE = "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json"; // Equirectangular, because the projection has to be reproduced in a Hugo // template to place the dots (see layouts/_default/home.html) and this is the @@ -185,8 +193,10 @@ function encode(points) { return `${out}Z`; } -const rings = []; -for (const geometry of topology.objects.land.geometries) { +// One geometry — a whole landmass, or one country — as the rings of it that fall +// on the map, projected and thinned. +function outline(geometry) { + const rings = []; const polygons = geometry.type === "MultiPolygon" ? geometry.arcs : [geometry.arcs]; for (const polygon of polygons) { @@ -226,11 +236,58 @@ for (const geometry of topology.objects.land.geometries) { } } } + return rings; } // One path for all of the land: it is filled with a single flat colour, so // splitting it per landmass would only add markup. -const d = rings.map(encode).join(""); +const land = topology.objects.land.geometries.flatMap(outline); +const d = land.map(encode).join(""); + +// Which countries get an outline: every country tools/locations.json can place +// anybody in, city or not, because the map shades the country a contributor is in +// as well as dotting the city (see layouts/_default/home.html). +// +// That list, and not the countries actually on the map today: +// data/contributors.json is regenerated on every contributor change, and this file +// would then have to be rebuilt over the network to catch up with it. Fifty-five +// outlines is some 20 KB of path data in a file nothing downloads; the page carries +// only the twenty of them that are used. +const places = JSON.parse( + await readFile("tools/locations.json", "utf8"), +).places; +const wanted = new Set( + Object.values(places) + .filter((place) => place && place.country) + .map((place) => place.country), +); + +// Natural Earth's own names, where they differ from the ones the site uses. Only +// one does today; the rest of the fifty-five match on the nose. +const NE_NAMES = { "United States": "United States of America" }; + +// The city-states, which 110m has no polygon for at all — one is 50 km across and +// the other 25, well under the pixel this dataset resolves. Listed rather than +// warned about: their contributors are on the map as city dots, a shade of a +// country that small would be invisible under its own dot, and a warning on every +// run for something that cannot be fixed is a warning nobody reads. +const NO_OUTLINE = new Set(["Hong Kong", "Singapore"]); + +const countries = {}; +for (const name of [...wanted].sort()) { + if (NO_OUTLINE.has(name)) continue; + const geometry = topology.objects.countries.geometries.find( + (candidate) => candidate.properties.name === (NE_NAMES[name] ?? name), + ); + if (!geometry) { + // Not fatal: the country goes unshaded and its cities are still dotted, so the + // map stays complete. A missing name is a typo in tools/locations.json or a + // rename upstream, and both want a person rather than a failed build. + console.error(`warning: no country named ${name} in the source`); + continue; + } + countries[name] = outline(geometry).map(encode).join(""); +} const output = { // Provenance, since the geometry is generated rather than authored. @@ -242,11 +299,14 @@ const output = { k: K, latTop: LAT_TOP, land: d, + countries, }; await writeFile("data/worldmap.json", JSON.stringify(output) + "\n"); +const shapes = Object.values(countries).join(""); console.log( - `data/worldmap.json: ${rings.length} rings, ${(d.length / 1024).toFixed(1)} KB of path data`, + `data/worldmap.json: ${land.length} rings, ${(d.length / 1024).toFixed(1)} KB of path data` + + `, plus ${Object.keys(countries).length} countries in ${(shapes.length / 1024).toFixed(1)} KB`, ); async function fetchOrDie(url) {