commit 150e0a00b586d9ef9a1641bc0faa882248d15923 Author: Finn Skov Henriksen Date: Fri Oct 2 21:39:38 2026 +0200 Add visitor registration app with SQLite, admin tools and Docker deployment diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..65aa9ab --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +.git +.env +.env.* +appsettings.Development.json +bin +obj +node_modules +data +*.db +*.db-shm +*.db-wal diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e75b5f2 --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +Database__Path=data/visitors.db +Admin__Username=admin +Admin__Password=change-me +APP_BIND=127.0.0.1 +APP_PORT=5187 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..d47619d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +*.pdf binary +*.png binary +*.jpg binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..319f549 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +bin/ +obj/ +node_modules/ +appsettings.Development.json +*.user +*.suo +data/ +*.db +*.db-shm +*.db-wal +.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a59456d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build +WORKDIR /src +COPY SkydesportensDag.csproj ./ +RUN dotnet restore --source https://api.nuget.org/v3/index.json +COPY Program.cs appsettings.json ./ +COPY wwwroot/ ./wwwroot/ +RUN dotnet publish --no-restore -c Release -o /out /p:UseAppHost=false + +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS final +WORKDIR /app +COPY --from=build /out/ ./ +RUN mkdir -p /app/data && chown app:app /app/data +ENV ASPNETCORE_ENVIRONMENT=Production +ENV ASPNETCORE_HTTP_PORTS=8080 +ENV Database__Path=/app/data/visitors.db +USER app +EXPOSE 8080 +ENTRYPOINT ["dotnet", "SkydesportensDag.dll"] diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..6062a8f --- /dev/null +++ b/Program.cs @@ -0,0 +1,249 @@ +using System.Net; +using System.Security.Claims; +using System.Text; +using System.Text.Encodings.Web; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Options; +using Microsoft.Data.Sqlite; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddAuthentication("Basic") + .AddScheme("Basic", null); +builder.Services.AddAuthorization(); +builder.Services.AddSingleton(); + +var app = builder.Build(); + +app.UseDefaultFiles(); +app.UseStaticFiles(); +app.UseAuthentication(); +app.UseAuthorization(); + +await app.Services.GetRequiredService().InitializeAsync(); + +app.MapPost("/api/visitors", async (VisitorInput input, Database database) => +{ + var errors = Validate(input); + if (errors.Count > 0) + { + return Results.ValidationProblem(errors); + } + + await using var connection = await database.OpenConnectionAsync(); + await using var command = connection.CreateCommand(); + command.CommandText = """ + insert into visitors (name, street_address, postal_code, city, birthday, email) + values ($name, $street, $postal, $city, $birthday, $email) + """; + command.Parameters.AddWithValue("$name", input.Name.Trim()); + command.Parameters.AddWithValue("$street", input.StreetAddress.Trim()); + command.Parameters.AddWithValue("$postal", input.PostalCode.Trim()); + command.Parameters.AddWithValue("$city", input.City.Trim()); + command.Parameters.AddWithValue("$birthday", DateOnly.Parse(input.Birthday).ToString("yyyy-MM-dd")); + command.Parameters.AddWithValue("$email", input.Email.Trim().ToLowerInvariant()); + await command.ExecuteNonQueryAsync(); + + return Results.Created("/api/visitors", null); +}); + +app.MapGet("/api/visitors", async (Database database) => +{ + var visitors = new List(); + await using var connection = await database.OpenConnectionAsync(); + await using var command = connection.CreateCommand(); + command.CommandText = """ + select id, name, street_address, postal_code, city, birthday, email, created_at + from visitors + order by created_at desc, id desc + """; + await using var reader = await command.ExecuteReaderAsync(); + + while (await reader.ReadAsync()) + { + visitors.Add(new VisitorListItem( + reader.GetInt64(0), + reader.GetString(1), + reader.GetString(2), + reader.GetString(3), + reader.GetString(4), + DateOnly.Parse(reader.GetString(5)), + reader.GetString(6), + DateTime.SpecifyKind(reader.GetDateTime(7), DateTimeKind.Utc) + )); + } + + return Results.Ok(visitors); +}).RequireAuthorization(); + +app.MapDelete("/api/visitors/{id:long}", async (long id, Database database) => +{ + await using var connection = await database.OpenConnectionAsync(); + await using var command = connection.CreateCommand(); + command.CommandText = "delete from visitors where id = $id"; + command.Parameters.AddWithValue("$id", id); + var deleted = await command.ExecuteNonQueryAsync(); + return deleted == 0 ? Results.NotFound() : Results.NoContent(); +}).RequireAuthorization(); + +app.MapGet("/admin", (IWebHostEnvironment environment) => + Results.File(Path.Combine(environment.WebRootPath, "admin.html"), "text/html")); + +app.MapFallbackToFile("index.html"); + +app.Run(); + +static Dictionary Validate(VisitorInput input) +{ + var errors = new Dictionary(); + + if (string.IsNullOrWhiteSpace(input.Name)) + { + errors["name"] = ["Navn mangler."]; + } + + if (string.IsNullOrWhiteSpace(input.StreetAddress)) + { + errors["streetAddress"] = ["Vejnavn og husnummer mangler."]; + } + + if (string.IsNullOrWhiteSpace(input.PostalCode) || input.PostalCode.Trim().Length != 4 || !input.PostalCode.All(char.IsDigit)) + { + errors["postalCode"] = ["Postnummer skal være 4 cifre."]; + } + + if (string.IsNullOrWhiteSpace(input.City)) + { + errors["city"] = ["Postby mangler."]; + } + + if (string.IsNullOrWhiteSpace(input.Birthday) || !DateOnly.TryParse(input.Birthday, out _)) + { + errors["birthday"] = ["Fødselsdag mangler eller er ugyldig."]; + } + + if (string.IsNullOrWhiteSpace(input.Email) || !input.Email.Contains('@') || !input.Email.Contains('.')) + { + errors["email"] = ["Email mangler eller er ugyldig."]; + } + + return errors; +} + +public sealed record VisitorInput(string Name, string StreetAddress, string PostalCode, string City, string Birthday, string Email); + +public sealed record VisitorListItem(long Id, string Name, string StreetAddress, string PostalCode, string City, DateOnly Birthday, string Email, DateTime CreatedAt); + +public sealed class Database +{ + private readonly string _connectionString; + + public Database(IConfiguration configuration, IWebHostEnvironment environment) + { + var path = configuration["Database:Path"] ?? "data/visitors.db"; + var fullPath = Path.GetFullPath(path, environment.ContentRootPath); + Directory.CreateDirectory(Path.GetDirectoryName(fullPath)!); + _connectionString = new SqliteConnectionStringBuilder { DataSource = fullPath }.ToString(); + } + + public async Task OpenConnectionAsync() + { + var connection = new SqliteConnection(_connectionString); + try + { + await connection.OpenAsync(); + return connection; + } + catch + { + await connection.DisposeAsync(); + throw; + } + } + + public async Task InitializeAsync() + { + await using var connection = await OpenConnectionAsync(); + await using var command = connection.CreateCommand(); + command.CommandText = """ + create table if not exists visitors ( + id integer primary key autoincrement, + name text not null, + street_address text not null, + postal_code text not null, + city text not null, + birthday text not null, + email text not null, + created_at text not null default (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) + ); + + create index if not exists visitors_created_at_idx on visitors (created_at desc); + """; + + await command.ExecuteNonQueryAsync(); + } +} + +public sealed class BasicAuthenticationHandler( + IOptionsMonitor options, + ILoggerFactory logger, + UrlEncoder encoder, + IConfiguration configuration) + : AuthenticationHandler(options, logger, encoder) +{ + protected override Task HandleAuthenticateAsync() + { + var expectedUser = configuration["Admin:Username"] ?? "admin"; + var expectedPassword = configuration["Admin:Password"]; + + if (string.IsNullOrWhiteSpace(expectedPassword)) + { + return Task.FromResult(AuthenticateResult.Fail("Admin:Password mangler.")); + } + + if (!Request.Headers.TryGetValue("Authorization", out var authorizationHeaders)) + { + return Task.FromResult(AuthenticateResult.NoResult()); + } + + var authorization = authorizationHeaders.ToString(); + if (!authorization.StartsWith("Basic ", StringComparison.OrdinalIgnoreCase)) + { + return Task.FromResult(AuthenticateResult.NoResult()); + } + + try + { + var encoded = authorization["Basic ".Length..].Trim(); + var decoded = Encoding.UTF8.GetString(Convert.FromBase64String(encoded)); + var separator = decoded.IndexOf(':'); + if (separator < 0) + { + return Task.FromResult(AuthenticateResult.Fail("Ugyldige credentials.")); + } + + var username = decoded[..separator]; + var password = decoded[(separator + 1)..]; + + if (username != expectedUser || password != expectedPassword) + { + return Task.FromResult(AuthenticateResult.Fail("Forkert login.")); + } + + var identity = new ClaimsIdentity([new Claim(ClaimTypes.Name, username)], Scheme.Name); + var principal = new ClaimsPrincipal(identity); + return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(principal, Scheme.Name))); + } + catch + { + return Task.FromResult(AuthenticateResult.Fail("Ugyldige credentials.")); + } + } + + protected override Task HandleChallengeAsync(AuthenticationProperties properties) + { + Response.Headers.WWWAuthenticate = "Basic realm=\"Skydesportens Dag\""; + Response.StatusCode = StatusCodes.Status401Unauthorized; + return Task.CompletedTask; + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..668571c --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +# Skydesportens Dag besøgsregistrering + +Lille standalone ASP.NET Core app til Vestfalster Skytteforening. + +## Funktioner + +- Offentlig registrering uden login på `/` +- Felter: navn, adresse, fødselsdag og email +- Postby udfyldes automatisk ved indtastning af et kendt dansk postnummer og kan redigeres manuelt +- Adminliste på `/admin` +- Sletning med bekræftelse på adminlisten +- CSV-download og udskrivning via browserens dialog (vælg Gem som PDF for PDF) +- Adminlisten bruger enkel HTTP Basic Auth via konfiguration +- Data gemmes lokalt i SQLite uden databaseserver eller databaselogin +- Frontend serveres direkte fra samme dotnet app + +## Opsætning + +1. Sæt adminlogin via environment variables eller user secrets (kun nødvendigt for adminlisten): + + ```powershell + $env:Admin__Username="admin" + $env:Admin__Password="change-me" + ``` + +2. Start appen: + + ```powershell + dotnet run + ``` + +Appen opretter selv databasefilen `data/visitors.db` og `visitors`-tabellen. Data bevares efter genstart. Stien regnes fra projektmappen og kan ændres med `Database__Path`. Der kræves ingen databaseopsætning. En eventuel gammel `ConnectionStrings__Default` bruges ikke længere. + +Tag backup af databasefilen, når appen er stoppet. Databasefiler er udeladt fra Git. Eksisterende data i PostgreSQL flyttes ikke automatisk. + +Appen kører typisk på den URL, `dotnet run` skriver i terminalen, fx `http://localhost:5000`. + +Postnummerlisten ligger lokalt i `wwwroot/postnumre.json`, så opslag virker uden internet. Data er hentet fra [GeoNames](https://download.geonames.org/export/zip/) den 2. oktober 2026 og bruges under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). Ukendte postnumre kan udfyldes manuelt. Opdater listen med `./scripts/update-postal-codes.ps1` (kræver internet). + +## Docker-server uden Git-runner + +Overfør `Dockerfile`, `compose.yaml`, `SkydesportensDag.csproj`, `Program.cs`, `appsettings.json`, `.dockerignore`, `.env.example` og mappen `wwwroot` til samme mappe på serveren med SCP/SFTP. Docker bygger appen på serveren; der kræves ingen .NET-installation eller Git-runner dér. + +På serveren: + +```sh +cp .env.example .env +chmod 600 .env +# Rediger .env og sæt Admin__Password samt ønsket port. +docker compose up -d --build +docker compose logs --tail=100 web +``` + +Appen lytter som standard på `127.0.0.1:5187` på serveren. En eksisterende reverse proxy kan sende trafik hertil; brug HTTPS ved adgang over internettet, da adminlogin bruger Basic Auth. Ved direkte adgang på det lokale netværk kan `APP_BIND` sættes til serverens LAN-adresse. En proxy i en anden container kræver tilpasning af Docker-netværket. + +Databasen oprettes i Docker-volumenet `visitors-data` og bevares ved genstart og nye builds. `docker compose down -v` sletter databasen. Lokale registreringer overføres ikke automatisk; aftal overførsel af databasefilen, hvis de skal med. + +Ved opdateringer overføres kodefilerne igen, og `docker compose up -d --build` køres. Bevar serverens `.env` og databasevolumen. Tag databasebackup, mens appen er stoppet. + +Adminlisten viser et interaktivt kort med antal deltagere pr. postnummer. Positioner fra GeoNames ligger i wwwroot/postnummer-positioner.json og opdateres sammen med postnummerlisten. Leaflet 1.9.4 ligger lokalt i wwwroot/vendor/leaflet med licens. Baggrundskort fra OpenStreetMap kræver internet; navne og adresser sendes ikke til korttjenesten. Kortet opdateres efter sletning og udelades fra listeudskrift. diff --git a/SkydesportensDag.csproj b/SkydesportensDag.csproj new file mode 100644 index 0000000..4aba3f9 --- /dev/null +++ b/SkydesportensDag.csproj @@ -0,0 +1,11 @@ + + + net10.0 + enable + enable + + + + + + diff --git a/appsettings.json b/appsettings.json new file mode 100644 index 0000000..76fdf1e --- /dev/null +++ b/appsettings.json @@ -0,0 +1,9 @@ +{ + "Database": { + "Path": "data/visitors.db" + }, + "Admin": { + "Username": "admin", + "Password": "" + } +} diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..583e7b4 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,15 @@ +services: + web: + build: . + restart: unless-stopped + ports: + - "${APP_BIND:-127.0.0.1}:${APP_PORT:-5187}:8080" + environment: + Admin__Username: "${Admin__Username:-admin}" + Admin__Password: "${Admin__Password:?Sæt Admin__Password i .env}" + Database__Path: /app/data/visitors.db + volumes: + - visitors-data:/app/data + +volumes: + visitors-data: diff --git a/output/pdf/skydedag-qr-plakat-preview.png b/output/pdf/skydedag-qr-plakat-preview.png new file mode 100644 index 0000000..429d264 Binary files /dev/null and b/output/pdf/skydedag-qr-plakat-preview.png differ diff --git a/output/pdf/skydedag-qr-plakat.pdf b/output/pdf/skydedag-qr-plakat.pdf new file mode 100644 index 0000000..a3181e7 Binary files /dev/null and b/output/pdf/skydedag-qr-plakat.pdf differ diff --git a/output/pdf/skydedag-qr.png b/output/pdf/skydedag-qr.png new file mode 100644 index 0000000..443bec0 Binary files /dev/null and b/output/pdf/skydedag-qr.png differ diff --git a/scripts/update-postal-codes.ps1 b/scripts/update-postal-codes.ps1 new file mode 100644 index 0000000..85ee1b9 --- /dev/null +++ b/scripts/update-postal-codes.ps1 @@ -0,0 +1,32 @@ +$ErrorActionPreference = 'Stop' +$archivePath = Join-Path ([System.IO.Path]::GetTempPath()) ('dk-postcodes-' + [guid]::NewGuid() + '.zip') +try { + Invoke-WebRequest 'https://download.geonames.org/export/zip/DK.zip' -OutFile $archivePath + Add-Type -AssemblyName System.IO.Compression.FileSystem + $archive = [System.IO.Compression.ZipFile]::OpenRead($archivePath) + try { + $reader = [System.IO.StreamReader]::new($archive.GetEntry('DK.txt').Open()) + try { $data = $reader.ReadToEnd() } finally { $reader.Dispose() } + } finally { $archive.Dispose() } + + $cities = [ordered]@{} + $locations = [ordered]@{} + foreach ($row in $data.Trim().Split("`n")) { + $fields = $row.TrimEnd("`r").Split("`t") + if ($fields[0] -ne 'DK' -or $fields[1] -notmatch '^\d{4}$' -or !$fields[2]) { + throw 'Ugyldig postnummerdata.' + } + if ($cities.Contains($fields[1]) -and $cities[$fields[1]] -ne $fields[2]) { + throw "Flere postbyer for postnummer $($fields[1])." + } + $cities[$fields[1]] = $fields[2] + $locations[$fields[1]] = @{ city = $fields[2]; lat = [double]::Parse($fields[9], [Globalization.CultureInfo]::InvariantCulture); lng = [double]::Parse($fields[10], [Globalization.CultureInfo]::InvariantCulture) } + } + if ($cities.Count -lt 1000) { throw 'Postnummerlisten er ufuldstændig.' } + $target = Join-Path $PSScriptRoot '../wwwroot/postnumre.json' + $cities | ConvertTo-Json -Depth 3 | Set-Content -LiteralPath $target -Encoding utf8 + $locations | ConvertTo-Json -Depth 3 | Set-Content -LiteralPath (Join-Path $PSScriptRoot '../wwwroot/postnummer-positioner.json') -Encoding utf8 + Write-Output "Gemt $($cities.Count) danske postnumre." +} finally { + if (Test-Path -LiteralPath $archivePath) { Remove-Item -LiteralPath $archivePath } +} diff --git a/skydedag-qr-plakat.pdf b/skydedag-qr-plakat.pdf new file mode 100644 index 0000000..a3181e7 Binary files /dev/null and b/skydedag-qr-plakat.pdf differ diff --git a/wwwroot/admin.html b/wwwroot/admin.html new file mode 100644 index 0000000..65224b2 --- /dev/null +++ b/wwwroot/admin.html @@ -0,0 +1,57 @@ + + + + + + Besøgende - Skydesportens Dag + + + + + +
+
+
+
+

Vestfalster Skytteforening

+

Besøgende

+
+ Henter... +
+
+ + +
+ +
+

Hvor kommer deltagerne fra?

+

Fordelt på postnumre. Klik på en cirkel for at se postby og antal.

+
+

Henter kort...

+
+
+ + + + + + + + + + + + + + + + +
NavnVejnavn og husnummerPostnummerPostbyFødselsdagEmailRegistreretHandling
Henter besøgende...
+
+
+
+ + + + + diff --git a/wwwroot/admin.js b/wwwroot/admin.js new file mode 100644 index 0000000..6fdcf41 --- /dev/null +++ b/wwwroot/admin.js @@ -0,0 +1,115 @@ +const tableBody = document.querySelector("#visitors"); +const count = document.querySelector("#count"); +const message = document.querySelector("#message"); +const csvButton = document.querySelector("#export-csv"); +const printButton = document.querySelector("#print-list"); +let visitors = []; + +function formatDateTime(value) { + return new Intl.DateTimeFormat("da-DK", { + dateStyle: "short", + timeStyle: "short" + }).format(new Date(value)); +} + +function showError(text) { + message.textContent = text; + message.className = "notice error"; + message.hidden = false; +} + +function escapeHtml(value) { + return String(value ?? "") + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll('"', """) + .replaceAll("'", "'"); +} + +async function loadVisitors() { + csvButton.disabled = true; + printButton.disabled = true; + try { + const response = await fetch("/api/visitors"); + if (!response.ok) { + showError("Listen kunne ikke hentes. Tjek admin-login og databaseforbindelse."); + count.textContent = "Fejl"; + return; + } + + visitors = await response.json(); + updateParticipantMap(visitors); + message.hidden = true; + csvButton.disabled = false; + printButton.disabled = false; + count.textContent = `${visitors.length} registreret`; + + if (visitors.length === 0) { + tableBody.innerHTML = 'Ingen besøgende registreret endnu.'; + return; + } + + tableBody.innerHTML = visitors.map((visitor) => ` + + ${escapeHtml(visitor.name)} + ${escapeHtml(visitor.streetAddress)} + ${escapeHtml(visitor.postalCode)} + ${escapeHtml(visitor.city)} + ${escapeHtml(visitor.birthday)} + ${escapeHtml(visitor.email)} + ${escapeHtml(formatDateTime(visitor.createdAt))} + + + `).join(""); + } catch { + showError("Der er ikke forbindelse til besøgslisten lige nu."); + count.textContent = "Fejl"; + } +} + +tableBody.addEventListener("click", async (event) => { + const button = event.target.closest("button[data-id]"); + if (!button || button.disabled) return; + const visitor = visitors.find((item) => String(item.id) === button.dataset.id); + if (!visitor || !window.confirm(`Slet registreringen for ${visitor.name}? Dette kan ikke fortrydes.`)) return; + button.disabled = true; + csvButton.disabled = true; + printButton.disabled = true; + try { + const response = await fetch(`/api/visitors/${visitor.id}`, { method: "DELETE" }); + if (!response.ok && response.status !== 404) throw new Error("Sletning mislykkedes."); + await loadVisitors(); + } catch { + showError("Registreringen kunne ikke slettes. Prøv igen."); + button.disabled = false; + csvButton.disabled = false; + printButton.disabled = false; + } +}); + +function csvCell(value) { + let text = String(value ?? ""); + // Prevent spreadsheet programs from evaluating visitor input as formulas. + if (/^[\s]*[=+@-]/.test(text)) text = "'" + text; + return `"${text.replaceAll('"', '""')}"`; +} + +csvButton.addEventListener("click", () => { + const rows = [ + ["Navn", "Vejnavn og husnummer", "Postnummer", "Postby", "Fødselsdag", "Email", "Registreret"], + ...visitors.map((visitor) => [visitor.name, visitor.streetAddress, visitor.postalCode, + visitor.city, visitor.birthday, visitor.email, formatDateTime(visitor.createdAt)]) + ]; + const csv = "\uFEFF" + rows.map((row) => row.map(csvCell).join(";")).join("\r\n") + "\r\n"; + const url = URL.createObjectURL(new Blob([csv], { type: "text/csv;charset=utf-8" })); + const link = document.createElement("a"); + link.href = url; + link.download = "skydesportens-dag-besogende.csv"; + link.click(); + setTimeout(() => URL.revokeObjectURL(url), 1000); +}); + +printButton.addEventListener("click", () => window.print()); + +loadVisitors(); diff --git a/wwwroot/app.js b/wwwroot/app.js new file mode 100644 index 0000000..29e3391 --- /dev/null +++ b/wwwroot/app.js @@ -0,0 +1,70 @@ +const form = document.querySelector("#registration-form"); +const message = document.querySelector("#message"); +const postalCodeInput = form.elements.postalCode; +const cityInput = form.elements.city; +const citySuggestions = document.querySelector("#city-suggestions"); +const postalCodes = fetch("/postnumre.json") + .then((response) => { + if (!response.ok) throw new Error("Postnummerlisten kunne ikke hentes."); + return response.json(); + }) + .catch(() => null); + +function showMessage(text, type) { + message.textContent = text; + message.className = `notice ${type}`; + message.hidden = false; +} + +form.addEventListener("submit", async (event) => { + event.preventDefault(); + + const payload = Object.fromEntries(new FormData(form).entries()); + const button = form.querySelector("button"); + button.disabled = true; + + try { + const response = await fetch("/api/visitors", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(payload) + }); + + if (!response.ok) { + showMessage("Registreringen kunne ikke gemmes. Tjek felterne og prøv igen.", "error"); + return; + } + + form.reset(); + citySuggestions.replaceChildren(); + showMessage("Tak, du er registreret.", "success"); + } catch { + showMessage("Der er ikke forbindelse til registreringen lige nu.", "error"); + } finally { + button.disabled = false; + } +}); + +async function updateCity() { + postalCodeInput.value = postalCodeInput.value.replace(/\D/g, "").slice(0, 4); + const postalCode = postalCodeInput.value; + citySuggestions.replaceChildren(); + cityInput.value = ""; + + if (postalCode.length !== 4) return; + + const cities = await postalCodes; + if (postalCodeInput.value !== postalCode || !cities) return; + + const city = cities[postalCode]; + if (!city) return; + + const option = document.createElement("option"); + option.value = city; + citySuggestions.append(option); + cityInput.value = city; +} + +postalCodeInput.addEventListener("input", updateCity); +postalCodeInput.addEventListener("change", updateCity); +if (postalCodeInput.value) updateCity(); diff --git a/wwwroot/favicon.svg b/wwwroot/favicon.svg new file mode 100644 index 0000000..1e91029 --- /dev/null +++ b/wwwroot/favicon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/wwwroot/index.html b/wwwroot/index.html new file mode 100644 index 0000000..2054abd --- /dev/null +++ b/wwwroot/index.html @@ -0,0 +1,45 @@ + + + + + + Skydesportens Dag - registrering + + + + +
+
+

Vestfalster Skytteforening

+

Skydesportens Dag

+

Registrer dig som besøgende. Oplysningerne bruges kun i forbindelse med arrangementet.

+ +
+ + +
+ + +
+ + + +
+
+
+ + + diff --git a/wwwroot/participant-map.js b/wwwroot/participant-map.js new file mode 100644 index 0000000..3f22a4d --- /dev/null +++ b/wwwroot/participant-map.js @@ -0,0 +1,58 @@ +const mapStatus = document.querySelector("#map-status"); +const postalLocations = fetch("/postnummer-positioner.json") + .then((response) => { + if (!response.ok) throw new Error("Postnummerpositioner mangler."); + return response.json(); + }).catch(() => null); +let participantMap; +let participantMarkers; +let mapRevision = 0; +let tileError = false; + +async function updateParticipantMap(visitors) { + const revision = ++mapRevision; + const locations = await postalLocations; + if (revision !== mapRevision) return; + if (!locations || typeof L === "undefined") { + mapStatus.textContent = "Kortet kunne ikke indlæses. Deltagerlisten kan stadig bruges."; + return; + } + if (!participantMap) { + participantMap = L.map("participant-map").setView([56.1, 10.5], 6); + L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", { + maxZoom: 18, + attribution: '© OpenStreetMap | Postbyer: GeoNames' + }).on("tileerror", () => { + if (!tileError) { + tileError = true; + mapStatus.textContent += " Baggrundskortet kunne ikke hentes; kontrollér internetforbindelsen."; + } + }).addTo(participantMap); + participantMarkers = L.layerGroup().addTo(participantMap); + } + participantMarkers.clearLayers(); + const groups = new Map(); + let missing = 0; + for (const visitor of visitors) { + const code = String(visitor.postalCode ?? "").trim(); + if (!locations[code]) { missing++; continue; } + groups.set(code, (groups.get(code) ?? 0) + 1); + } + const bounds = []; + for (const [code, total] of groups) { + const location = locations[code]; + const point = [location.lat, location.lng]; + bounds.push(point); + const popup = document.createElement("div"); + popup.textContent = `${code} ${location.city}: ${total} ${total === 1 ? "deltager" : "deltagere"}`; + L.circleMarker(point, { + radius: Math.min(32, 7 + Math.sqrt(total) * 3), + color: "#16472d", fillColor: "#1d5b39", fillOpacity: 0.65, weight: 2 + }).bindPopup(popup).bindTooltip(`${code}: ${total}`).addTo(participantMarkers); + } + if (bounds.length) participantMap.fitBounds(bounds, { padding: [35, 35], maxZoom: 11 }); + else participantMap.setView([56.1, 10.5], 6); + mapStatus.textContent = visitors.length === 0 ? "Ingen deltagere registreret endnu." : + `${visitors.length - missing} deltagere fra ${groups.size} postnumre vist.${missing ? ` ${missing} deltagere har et ukendt postnummer og vises ikke på kortet.` : ""}`; + if (tileError) mapStatus.textContent += " Baggrundskortet kunne ikke hentes; kontrollér internetforbindelsen."; +} diff --git a/wwwroot/postnummer-positioner.json b/wwwroot/postnummer-positioner.json new file mode 100644 index 0000000..ffede1e --- /dev/null +++ b/wwwroot/postnummer-positioner.json @@ -0,0 +1,5797 @@ +{ + "1050": { + "city": "København K", + "lat": 55.6806, + "lng": 12.5857 + }, + "1051": { + "city": "København K", + "lat": 55.68, + "lng": 12.5906 + }, + "1052": { + "city": "København K", + "lat": 55.6789, + "lng": 12.5901 + }, + "1053": { + "city": "København K", + "lat": 55.678, + "lng": 12.5907 + }, + "1054": { + "city": "København K", + "lat": 55.678, + "lng": 12.5888 + }, + "1055": { + "city": "København K", + "lat": 55.6781, + "lng": 12.5877 + }, + "1056": { + "city": "København K", + "lat": 55.6794, + "lng": 12.5883 + }, + "1057": { + "city": "København K", + "lat": 55.6784, + "lng": 12.5893 + }, + "1058": { + "city": "København K", + "lat": 55.6773, + "lng": 12.59 + }, + "1059": { + "city": "København K", + "lat": 55.6767, + "lng": 12.5869 + }, + "1060": { + "city": "København K", + "lat": 55.6778, + "lng": 12.5851 + }, + "1061": { + "city": "København K", + "lat": 55.6775, + "lng": 12.5813 + }, + "1062": { + "city": "København K", + "lat": 55.6775, + "lng": 12.582 + }, + "1063": { + "city": "København K", + "lat": 55.678, + "lng": 12.5838 + }, + "1064": { + "city": "København K", + "lat": 55.6784, + "lng": 12.5841 + }, + "1065": { + "city": "København K", + "lat": 55.678, + "lng": 12.5812 + }, + "1066": { + "city": "København K", + "lat": 55.6777, + "lng": 12.5822 + }, + "1067": { + "city": "København K", + "lat": 55.6787, + "lng": 12.5817 + }, + "1068": { + "city": "København K", + "lat": 55.6779, + "lng": 12.5828 + }, + "1069": { + "city": "København K", + "lat": 55.6785, + "lng": 12.5832 + }, + "1070": { + "city": "København K", + "lat": 55.6786, + "lng": 12.5835 + }, + "1071": { + "city": "København K", + "lat": 55.6781, + "lng": 12.5832 + }, + "1072": { + "city": "København K", + "lat": 55.6785, + "lng": 12.5807 + }, + "1073": { + "city": "København K", + "lat": 55.6788, + "lng": 12.5804 + }, + "1074": { + "city": "København K", + "lat": 55.6796, + "lng": 12.5836 + }, + "1100": { + "city": "København K", + "lat": 55.6798, + "lng": 12.5827 + }, + "1101": { + "city": "København K", + "lat": 55.6812, + "lng": 12.5826 + }, + "1102": { + "city": "København K", + "lat": 55.6808, + "lng": 12.5827 + }, + "1103": { + "city": "København K", + "lat": 55.6808, + "lng": 12.584 + }, + "1104": { + "city": "København K", + "lat": 55.6813, + "lng": 12.584 + }, + "1105": { + "city": "København K", + "lat": 55.6802, + "lng": 12.5821 + }, + "1106": { + "city": "København K", + "lat": 55.6804, + "lng": 12.5812 + }, + "1107": { + "city": "København K", + "lat": 55.6813, + "lng": 12.583 + }, + "1110": { + "city": "København K", + "lat": 55.6817, + "lng": 12.5823 + }, + "1111": { + "city": "København K", + "lat": 55.682, + "lng": 12.581 + }, + "1112": { + "city": "København K", + "lat": 55.6807, + "lng": 12.5801 + }, + "1113": { + "city": "København K", + "lat": 55.6801, + "lng": 12.58 + }, + "1114": { + "city": "København K", + "lat": 55.6807, + "lng": 12.5792 + }, + "1115": { + "city": "København K", + "lat": 55.681, + "lng": 12.5784 + }, + "1116": { + "city": "København K", + "lat": 55.6818, + "lng": 12.5796 + }, + "1117": { + "city": "København K", + "lat": 55.6814, + "lng": 12.5808 + }, + "1118": { + "city": "København K", + "lat": 55.6811, + "lng": 12.5807 + }, + "1119": { + "city": "København K", + "lat": 55.6825, + "lng": 12.5769 + }, + "1120": { + "city": "København K", + "lat": 55.6824, + "lng": 12.5786 + }, + "1121": { + "city": "København K", + "lat": 55.6828, + "lng": 12.5788 + }, + "1122": { + "city": "København K", + "lat": 55.6826, + "lng": 12.5797 + }, + "1123": { + "city": "København K", + "lat": 55.6835, + "lng": 12.5776 + }, + "1124": { + "city": "København K", + "lat": 55.6832, + "lng": 12.5762 + }, + "1125": { + "city": "København K", + "lat": 55.6823, + "lng": 12.5763 + }, + "1126": { + "city": "København K", + "lat": 55.6822, + "lng": 12.5752 + }, + "1127": { + "city": "København K", + "lat": 55.6829, + "lng": 12.5756 + }, + "1128": { + "city": "København K", + "lat": 55.6828, + "lng": 12.5746 + }, + "1129": { + "city": "København K", + "lat": 55.6831, + "lng": 12.5744 + }, + "1130": { + "city": "København K", + "lat": 55.6835, + "lng": 12.574 + }, + "1131": { + "city": "København K", + "lat": 55.6839, + "lng": 12.5739 + }, + "1150": { + "city": "København K", + "lat": 55.6806, + "lng": 12.5775 + }, + "1151": { + "city": "København K", + "lat": 55.6798, + "lng": 12.5773 + }, + "1152": { + "city": "København K", + "lat": 55.6804, + "lng": 12.5769 + }, + "1153": { + "city": "København K", + "lat": 55.6797, + "lng": 12.577 + }, + "1154": { + "city": "København K", + "lat": 55.6797, + "lng": 12.5759 + }, + "1155": { + "city": "København K", + "lat": 55.68, + "lng": 12.5754 + }, + "1156": { + "city": "København K", + "lat": 55.6795, + "lng": 12.5752 + }, + "1157": { + "city": "København K", + "lat": 55.6792, + "lng": 12.5753 + }, + "1158": { + "city": "København K", + "lat": 55.6786, + "lng": 12.5736 + }, + "1159": { + "city": "København K", + "lat": 55.6798, + "lng": 12.5747 + }, + "1160": { + "city": "København K", + "lat": 55.6788, + "lng": 12.578 + }, + "1161": { + "city": "København K", + "lat": 55.6786, + "lng": 12.575 + }, + "1162": { + "city": "København K", + "lat": 55.6789, + "lng": 12.5742 + }, + "1164": { + "city": "København K", + "lat": 55.6783, + "lng": 12.5735 + }, + "1165": { + "city": "København K", + "lat": 55.6809, + "lng": 12.5712 + }, + "1166": { + "city": "København K", + "lat": 55.6791, + "lng": 12.5731 + }, + "1167": { + "city": "København K", + "lat": 55.6791, + "lng": 12.5715 + }, + "1168": { + "city": "København K", + "lat": 55.6799, + "lng": 12.5722 + }, + "1169": { + "city": "København K", + "lat": 55.6806, + "lng": 12.5746 + }, + "1170": { + "city": "København K", + "lat": 55.6802, + "lng": 12.5747 + }, + "1171": { + "city": "København K", + "lat": 55.6814, + "lng": 12.5726 + }, + "1172": { + "city": "København K", + "lat": 55.6808, + "lng": 12.5734 + }, + "1173": { + "city": "København K", + "lat": 55.6817, + "lng": 12.574 + }, + "1174": { + "city": "København K", + "lat": 55.6823, + "lng": 12.5728 + }, + "1175": { + "city": "København K", + "lat": 55.6824, + "lng": 12.5738 + }, + "1200": { + "city": "København K", + "lat": 55.6784, + "lng": 12.58 + }, + "1201": { + "city": "København K", + "lat": 55.6781, + "lng": 12.5781 + }, + "1202": { + "city": "København K", + "lat": 55.6777, + "lng": 12.5784 + }, + "1203": { + "city": "København K", + "lat": 55.6764, + "lng": 12.5761 + }, + "1204": { + "city": "København K", + "lat": 55.6765, + "lng": 12.5755 + }, + "1205": { + "city": "København K", + "lat": 55.6771, + "lng": 12.5765 + }, + "1206": { + "city": "København K", + "lat": 55.6775, + "lng": 12.5771 + }, + "1207": { + "city": "København K", + "lat": 55.6781, + "lng": 12.5766 + }, + "1208": { + "city": "København K", + "lat": 55.6771, + "lng": 12.5753 + }, + "1209": { + "city": "København K", + "lat": 55.678, + "lng": 12.5753 + }, + "1210": { + "city": "København K", + "lat": 55.6775, + "lng": 12.575 + }, + "1211": { + "city": "København K", + "lat": 55.6776, + "lng": 12.5747 + }, + "1212": { + "city": "København K", + "lat": 55.6769, + "lng": 12.5789 + }, + "1213": { + "city": "København K", + "lat": 55.6764, + "lng": 12.5783 + }, + "1214": { + "city": "København K", + "lat": 55.6747, + "lng": 12.579 + }, + "1215": { + "city": "København K", + "lat": 55.6756, + "lng": 12.5846 + }, + "1216": { + "city": "København K", + "lat": 55.6752, + "lng": 12.584 + }, + "1218": { + "city": "København K", + "lat": 55.6757, + "lng": 12.5795 + }, + "1219": { + "city": "København K", + "lat": 55.6731, + "lng": 12.5818 + }, + "1220": { + "city": "København K", + "lat": 55.6742, + "lng": 12.5772 + }, + "1221": { + "city": "København K", + "lat": 55.6743, + "lng": 12.5845 + }, + "1250": { + "city": "København K", + "lat": 55.6815, + "lng": 12.5915 + }, + "1251": { + "city": "København K", + "lat": 55.6798, + "lng": 12.5935 + }, + "1252": { + "city": "København K", + "lat": 55.6813, + "lng": 12.5953 + }, + "1253": { + "city": "København K", + "lat": 55.6831, + "lng": 12.594 + }, + "1254": { + "city": "København K", + "lat": 55.6809, + "lng": 12.5901 + }, + "1255": { + "city": "København K", + "lat": 55.6811, + "lng": 12.5887 + }, + "1256": { + "city": "København K", + "lat": 55.6848, + "lng": 12.5936 + }, + "1257": { + "city": "København K", + "lat": 55.6842, + "lng": 12.5929 + }, + "1259": { + "city": "København K", + "lat": 55.69, + "lng": 12.5995 + }, + "1260": { + "city": "København K", + "lat": 55.6839, + "lng": 12.59 + }, + "1261": { + "city": "København K", + "lat": 55.6819, + "lng": 12.5869 + }, + "1263": { + "city": "København K", + "lat": 55.6875, + "lng": 12.5935 + }, + "1264": { + "city": "København K", + "lat": 55.685, + "lng": 12.5879 + }, + "1265": { + "city": "København K", + "lat": 55.6849, + "lng": 12.5902 + }, + "1266": { + "city": "København K", + "lat": 55.6878, + "lng": 12.5911 + }, + "1267": { + "city": "København K", + "lat": 55.6884, + "lng": 12.5907 + }, + "1268": { + "city": "København K", + "lat": 55.6888, + "lng": 12.5903 + }, + "1270": { + "city": "København K", + "lat": 55.689, + "lng": 12.591 + }, + "1271": { + "city": "København K", + "lat": 55.6892, + "lng": 12.5898 + }, + "1300": { + "city": "København K", + "lat": 55.685, + "lng": 12.5863 + }, + "1301": { + "city": "København K", + "lat": 55.6832, + "lng": 12.5856 + }, + "1302": { + "city": "København K", + "lat": 55.6839, + "lng": 12.5862 + }, + "1303": { + "city": "København K", + "lat": 55.686, + "lng": 12.5882 + }, + "1304": { + "city": "København K", + "lat": 55.6846, + "lng": 12.5843 + }, + "1306": { + "city": "København K", + "lat": 55.6857, + "lng": 12.5834 + }, + "1307": { + "city": "København K", + "lat": 55.6878, + "lng": 12.5789 + }, + "1308": { + "city": "København K", + "lat": 55.6866, + "lng": 12.5847 + }, + "1309": { + "city": "København K", + "lat": 55.6873, + "lng": 12.5836 + }, + "1310": { + "city": "København K", + "lat": 55.6864, + "lng": 12.5884 + }, + "1311": { + "city": "København K", + "lat": 55.6872, + "lng": 12.5868 + }, + "1312": { + "city": "København K", + "lat": 55.6875, + "lng": 12.5858 + }, + "1313": { + "city": "København K", + "lat": 55.6875, + "lng": 12.5871 + }, + "1314": { + "city": "København K", + "lat": 55.6878, + "lng": 12.5869 + }, + "1315": { + "city": "København K", + "lat": 55.6876, + "lng": 12.5879 + }, + "1316": { + "city": "København K", + "lat": 55.6881, + "lng": 12.583 + }, + "1317": { + "city": "København K", + "lat": 55.689, + "lng": 12.5829 + }, + "1318": { + "city": "København K", + "lat": 55.6885, + "lng": 12.5848 + }, + "1319": { + "city": "København K", + "lat": 55.6882, + "lng": 12.5872 + }, + "1320": { + "city": "København K", + "lat": 55.6886, + "lng": 12.5873 + }, + "1321": { + "city": "København K", + "lat": 55.6879, + "lng": 12.5894 + }, + "1322": { + "city": "København K", + "lat": 55.6889, + "lng": 12.5873 + }, + "1323": { + "city": "København K", + "lat": 55.6897, + "lng": 12.5857 + }, + "1324": { + "city": "København K", + "lat": 55.6891, + "lng": 12.588 + }, + "1325": { + "city": "København K", + "lat": 55.6895, + "lng": 12.5876 + }, + "1326": { + "city": "København K", + "lat": 55.6897, + "lng": 12.5879 + }, + "1327": { + "city": "København K", + "lat": 55.6902, + "lng": 12.5876 + }, + "1328": { + "city": "København K", + "lat": 55.6902, + "lng": 12.5882 + }, + "1329": { + "city": "København K", + "lat": 55.689, + "lng": 12.5851 + }, + "1350": { + "city": "København K", + "lat": 55.6885, + "lng": 12.5813 + }, + "1352": { + "city": "København K", + "lat": 55.6896, + "lng": 12.5726 + }, + "1353": { + "city": "København K", + "lat": 55.6879, + "lng": 12.572 + }, + "1354": { + "city": "København K", + "lat": 55.6893, + "lng": 12.5719 + }, + "1355": { + "city": "København K", + "lat": 55.6891, + "lng": 12.5713 + }, + "1356": { + "city": "København K", + "lat": 55.6869, + "lng": 12.5676 + }, + "1357": { + "city": "København K", + "lat": 55.6884, + "lng": 12.569 + }, + "1358": { + "city": "København K", + "lat": 55.6819, + "lng": 12.5701 + }, + "1359": { + "city": "København K", + "lat": 55.6833, + "lng": 12.5655 + }, + "1360": { + "city": "København K", + "lat": 55.6843, + "lng": 12.5698 + }, + "1361": { + "city": "København K", + "lat": 55.684, + "lng": 12.5706 + }, + "1362": { + "city": "København K", + "lat": 55.6843, + "lng": 12.5691 + }, + "1363": { + "city": "København K", + "lat": 55.6844, + "lng": 12.5671 + }, + "1364": { + "city": "København K", + "lat": 55.683, + "lng": 12.5662 + }, + "1365": { + "city": "København K", + "lat": 55.6821, + "lng": 12.5644 + }, + "1366": { + "city": "København K", + "lat": 55.6833, + "lng": 12.5649 + }, + "1367": { + "city": "København K", + "lat": 55.6831, + "lng": 12.5635 + }, + "1368": { + "city": "København K", + "lat": 55.6815, + "lng": 12.5632 + }, + "1369": { + "city": "København K", + "lat": 55.6808, + "lng": 12.5622 + }, + "1370": { + "city": "København K", + "lat": 55.6833, + "lng": 12.563 + }, + "1371": { + "city": "København K", + "lat": 55.686, + "lng": 12.5651 + }, + "1400": { + "city": "København K", + "lat": 55.6726, + "lng": 12.591 + }, + "1401": { + "city": "København K", + "lat": 55.6752, + "lng": 12.5922 + }, + "1402": { + "city": "København K", + "lat": 55.6724, + "lng": 12.5864 + }, + "1403": { + "city": "København K", + "lat": 55.6755, + "lng": 12.594 + }, + "1406": { + "city": "København K", + "lat": 55.6752, + "lng": 12.593 + }, + "1407": { + "city": "København K", + "lat": 55.6741, + "lng": 12.5946 + }, + "1408": { + "city": "København K", + "lat": 55.6733, + "lng": 12.5903 + }, + "1409": { + "city": "København K", + "lat": 55.6737, + "lng": 12.5877 + }, + "1410": { + "city": "København K", + "lat": 55.672, + "lng": 12.5911 + }, + "1411": { + "city": "København K", + "lat": 55.6704, + "lng": 12.5849 + }, + "1412": { + "city": "København K", + "lat": 55.6706, + "lng": 12.586 + }, + "1413": { + "city": "København K", + "lat": 55.6706, + "lng": 12.5866 + }, + "1414": { + "city": "København K", + "lat": 55.6729, + "lng": 12.5908 + }, + "1415": { + "city": "København K", + "lat": 55.6733, + "lng": 12.5929 + }, + "1416": { + "city": "København K", + "lat": 55.6731, + "lng": 12.5931 + }, + "1417": { + "city": "København K", + "lat": 55.6728, + "lng": 12.5924 + }, + "1418": { + "city": "København K", + "lat": 55.671, + "lng": 12.5908 + }, + "1419": { + "city": "København K", + "lat": 55.6705, + "lng": 12.5888 + }, + "1420": { + "city": "København K", + "lat": 55.6716, + "lng": 12.5912 + }, + "1421": { + "city": "København K", + "lat": 55.6703, + "lng": 12.5882 + }, + "1422": { + "city": "København K", + "lat": 55.6732, + "lng": 12.5956 + }, + "1423": { + "city": "København K", + "lat": 55.6707, + "lng": 12.5926 + }, + "1424": { + "city": "København K", + "lat": 55.6704, + "lng": 12.5917 + }, + "1425": { + "city": "København K", + "lat": 55.6718, + "lng": 12.5942 + }, + "1426": { + "city": "København K", + "lat": 55.6723, + "lng": 12.5969 + }, + "1427": { + "city": "København K", + "lat": 55.6751, + "lng": 12.597 + }, + "1428": { + "city": "København K", + "lat": 55.6758, + "lng": 12.5979 + }, + "1429": { + "city": "København K", + "lat": 55.6755, + "lng": 12.5986 + }, + "1430": { + "city": "København K", + "lat": 55.6764, + "lng": 12.5993 + }, + "1432": { + "city": "København K", + "lat": 55.6878, + "lng": 12.6129 + }, + "1433": { + "city": "København K", + "lat": 55.7119, + "lng": 12.6981 + }, + "1434": { + "city": "København K", + "lat": 55.6797, + "lng": 12.6028 + }, + "1435": { + "city": "København K", + "lat": 55.6806, + "lng": 12.6053 + }, + "1436": { + "city": "København K", + "lat": 55.6775, + "lng": 12.6034 + }, + "1437": { + "city": "København K", + "lat": 55.6801, + "lng": 12.6043 + }, + "1438": { + "city": "København K", + "lat": 55.6823, + "lng": 12.6021 + }, + "1439": { + "city": "København K", + "lat": 55.6865, + "lng": 12.6085 + }, + "1440": { + "city": "København K", + "lat": 55.6748, + "lng": 12.6034 + }, + "1441": { + "city": "København K", + "lat": 55.6769, + "lng": 12.6099 + }, + "1450": { + "city": "København K", + "lat": 55.6775, + "lng": 12.5734 + }, + "1451": { + "city": "København K", + "lat": 55.6801, + "lng": 12.5695 + }, + "1452": { + "city": "København K", + "lat": 55.6795, + "lng": 12.5684 + }, + "1453": { + "city": "København K", + "lat": 55.6791, + "lng": 12.5686 + }, + "1454": { + "city": "København K", + "lat": 55.6784, + "lng": 12.5694 + }, + "1455": { + "city": "København K", + "lat": 55.6785, + "lng": 12.5692 + }, + "1456": { + "city": "København K", + "lat": 55.6777, + "lng": 12.57 + }, + "1457": { + "city": "København K", + "lat": 55.6782, + "lng": 12.5719 + }, + "1458": { + "city": "København K", + "lat": 55.677, + "lng": 12.5714 + }, + "1459": { + "city": "København K", + "lat": 55.6772, + "lng": 12.5709 + }, + "1460": { + "city": "København K", + "lat": 55.6766, + "lng": 12.571 + }, + "1461": { + "city": "København K", + "lat": 55.6768, + "lng": 12.5728 + }, + "1462": { + "city": "København K", + "lat": 55.6763, + "lng": 12.5717 + }, + "1463": { + "city": "København K", + "lat": 55.6758, + "lng": 12.5723 + }, + "1464": { + "city": "København K", + "lat": 55.6765, + "lng": 12.5728 + }, + "1465": { + "city": "København K", + "lat": 55.6761, + "lng": 12.5735 + }, + "1466": { + "city": "København K", + "lat": 55.6768, + "lng": 12.5741 + }, + "1467": { + "city": "København K", + "lat": 55.6761, + "lng": 12.5741 + }, + "1468": { + "city": "København K", + "lat": 55.6755, + "lng": 12.5735 + }, + "1470": { + "city": "København K", + "lat": 55.6751, + "lng": 12.574 + }, + "1471": { + "city": "København K", + "lat": 55.6743, + "lng": 12.5756 + }, + "1472": { + "city": "København K", + "lat": 55.6737, + "lng": 12.5765 + }, + "1473": { + "city": "København K", + "lat": 55.6722, + "lng": 12.579 + }, + "1550": { + "city": "København V", + "lat": 55.6761, + "lng": 12.5695 + }, + "1551": { + "city": "København V", + "lat": 55.6788, + "lng": 12.566 + }, + "1552": { + "city": "København V", + "lat": 55.675, + "lng": 12.5724 + }, + "1553": { + "city": "København V", + "lat": 55.6744, + "lng": 12.5711 + }, + "1554": { + "city": "København V", + "lat": 55.6771, + "lng": 12.5654 + }, + "1555": { + "city": "København V", + "lat": 55.6746, + "lng": 12.5739 + }, + "1556": { + "city": "København V", + "lat": 55.6736, + "lng": 12.5735 + }, + "1557": { + "city": "København V", + "lat": 55.6731, + "lng": 12.5748 + }, + "1558": { + "city": "København V", + "lat": 55.672, + "lng": 12.577 + }, + "1559": { + "city": "København V", + "lat": 55.6716, + "lng": 12.5776 + }, + "1560": { + "city": "København V", + "lat": 55.6664, + "lng": 12.569 + }, + "1561": { + "city": "København V", + "lat": 55.6607, + "lng": 12.5628 + }, + "1562": { + "city": "København V", + "lat": 55.6705, + "lng": 12.5741 + }, + "1563": { + "city": "København V", + "lat": 55.6709, + "lng": 12.5741 + }, + "1564": { + "city": "København V", + "lat": 55.672, + "lng": 12.5755 + }, + "1567": { + "city": "København V", + "lat": 55.6703, + "lng": 12.5709 + }, + "1568": { + "city": "København V", + "lat": 55.67, + "lng": 12.5713 + }, + "1569": { + "city": "København V", + "lat": 55.6713, + "lng": 12.5708 + }, + "1570": { + "city": "København V", + "lat": 55.6735, + "lng": 12.5642 + }, + "1571": { + "city": "København V", + "lat": 55.6711, + "lng": 12.5728 + }, + "1572": { + "city": "København V", + "lat": 55.6716, + "lng": 12.5732 + }, + "1573": { + "city": "København V", + "lat": 55.6716, + "lng": 12.5745 + }, + "1574": { + "city": "København V", + "lat": 55.6718, + "lng": 12.5724 + }, + "1575": { + "city": "København V", + "lat": 55.6718, + "lng": 12.5709 + }, + "1576": { + "city": "København V", + "lat": 55.6712, + "lng": 12.57 + }, + "1577": { + "city": "København V", + "lat": 55.669, + "lng": 12.5663 + }, + "1600": { + "city": "København V", + "lat": 55.6801, + "lng": 12.5619 + }, + "1601": { + "city": "København V", + "lat": 55.6782, + "lng": 12.56 + }, + "1602": { + "city": "København V", + "lat": 55.6786, + "lng": 12.561 + }, + "1603": { + "city": "København V", + "lat": 55.6792, + "lng": 12.5623 + }, + "1604": { + "city": "København V", + "lat": 55.6777, + "lng": 12.5614 + }, + "1605": { + "city": "København V", + "lat": 55.6761, + "lng": 12.5607 + }, + "1606": { + "city": "København V", + "lat": 55.6772, + "lng": 12.5623 + }, + "1607": { + "city": "København V", + "lat": 55.6782, + "lng": 12.5634 + }, + "1608": { + "city": "København V", + "lat": 55.6761, + "lng": 12.5658 + }, + "1609": { + "city": "København V", + "lat": 55.6758, + "lng": 12.5648 + }, + "1610": { + "city": "København V", + "lat": 55.6739, + "lng": 12.5548 + }, + "1611": { + "city": "København V", + "lat": 55.676, + "lng": 12.5638 + }, + "1612": { + "city": "København V", + "lat": 55.6752, + "lng": 12.562 + }, + "1613": { + "city": "København V", + "lat": 55.6745, + "lng": 12.5617 + }, + "1614": { + "city": "København V", + "lat": 55.6739, + "lng": 12.5606 + }, + "1615": { + "city": "København V", + "lat": 55.6737, + "lng": 12.5591 + }, + "1616": { + "city": "København V", + "lat": 55.6732, + "lng": 12.557 + }, + "1617": { + "city": "København V", + "lat": 55.673, + "lng": 12.5545 + }, + "1618": { + "city": "København V", + "lat": 55.6736, + "lng": 12.551 + }, + "1619": { + "city": "København V", + "lat": 55.6737, + "lng": 12.5501 + }, + "1620": { + "city": "København V", + "lat": 55.6722, + "lng": 12.5507 + }, + "1621": { + "city": "København V", + "lat": 55.6729, + "lng": 12.548 + }, + "1622": { + "city": "København V", + "lat": 55.6724, + "lng": 12.5463 + }, + "1623": { + "city": "København V", + "lat": 55.6719, + "lng": 12.5453 + }, + "1624": { + "city": "København V", + "lat": 55.6721, + "lng": 12.546 + }, + "1631": { + "city": "København V", + "lat": 55.6827, + "lng": 12.5555 + }, + "1632": { + "city": "København V", + "lat": 55.6827, + "lng": 12.5549 + }, + "1633": { + "city": "København V", + "lat": 55.6823, + "lng": 12.5564 + }, + "1634": { + "city": "København V", + "lat": 55.6819, + "lng": 12.5558 + }, + "1635": { + "city": "København V", + "lat": 55.6829, + "lng": 12.5561 + }, + "1650": { + "city": "København V", + "lat": 55.6697, + "lng": 12.5549 + }, + "1651": { + "city": "København V", + "lat": 55.6722, + "lng": 12.5637 + }, + "1652": { + "city": "København V", + "lat": 55.6718, + "lng": 12.5626 + }, + "1653": { + "city": "København V", + "lat": 55.672, + "lng": 12.5612 + }, + "1654": { + "city": "København V", + "lat": 55.6715, + "lng": 12.5595 + }, + "1655": { + "city": "København V", + "lat": 55.6714, + "lng": 12.5581 + }, + "1656": { + "city": "København V", + "lat": 55.6711, + "lng": 12.5568 + }, + "1657": { + "city": "København V", + "lat": 55.6704, + "lng": 12.5558 + }, + "1658": { + "city": "København V", + "lat": 55.6704, + "lng": 12.5548 + }, + "1659": { + "city": "København V", + "lat": 55.6718, + "lng": 12.5545 + }, + "1660": { + "city": "København V", + "lat": 55.67, + "lng": 12.5528 + }, + "1661": { + "city": "København V", + "lat": 55.6714, + "lng": 12.5518 + }, + "1662": { + "city": "København V", + "lat": 55.6698, + "lng": 12.551 + }, + "1663": { + "city": "København V", + "lat": 55.6692, + "lng": 12.5499 + }, + "1664": { + "city": "København V", + "lat": 55.6719, + "lng": 12.5492 + }, + "1665": { + "city": "København V", + "lat": 55.6687, + "lng": 12.549 + }, + "1666": { + "city": "København V", + "lat": 55.6699, + "lng": 12.5485 + }, + "1667": { + "city": "København V", + "lat": 55.6691, + "lng": 12.547 + }, + "1668": { + "city": "København V", + "lat": 55.6684, + "lng": 12.548 + }, + "1669": { + "city": "København V", + "lat": 55.6672, + "lng": 12.5474 + }, + "1670": { + "city": "København V", + "lat": 55.667, + "lng": 12.546 + }, + "1671": { + "city": "København V", + "lat": 55.6667, + "lng": 12.5461 + }, + "1672": { + "city": "København V", + "lat": 55.6685, + "lng": 12.5464 + }, + "1673": { + "city": "København V", + "lat": 55.668, + "lng": 12.5465 + }, + "1674": { + "city": "København V", + "lat": 55.6685, + "lng": 12.5447 + }, + "1675": { + "city": "København V", + "lat": 55.6665, + "lng": 12.5468 + }, + "1676": { + "city": "København V", + "lat": 55.6662, + "lng": 12.5485 + }, + "1677": { + "city": "København V", + "lat": 55.666, + "lng": 12.5469 + }, + "1699": { + "city": "København V", + "lat": 55.6677, + "lng": 12.5619 + }, + "1700": { + "city": "København V", + "lat": 55.6695, + "lng": 12.5597 + }, + "1701": { + "city": "København V", + "lat": 55.6718, + "lng": 12.5633 + }, + "1702": { + "city": "København V", + "lat": 55.6713, + "lng": 12.5637 + }, + "1703": { + "city": "København V", + "lat": 55.6705, + "lng": 12.5629 + }, + "1704": { + "city": "København V", + "lat": 55.6711, + "lng": 12.567 + }, + "1705": { + "city": "København V", + "lat": 55.6647, + "lng": 12.5522 + }, + "1706": { + "city": "København V", + "lat": 55.6707, + "lng": 12.56 + }, + "1707": { + "city": "København V", + "lat": 55.6718, + "lng": 12.5607 + }, + "1708": { + "city": "København V", + "lat": 55.6696, + "lng": 12.5575 + }, + "1709": { + "city": "København V", + "lat": 55.6685, + "lng": 12.5543 + }, + "1710": { + "city": "København V", + "lat": 55.6703, + "lng": 12.5625 + }, + "1711": { + "city": "København V", + "lat": 55.6679, + "lng": 12.5596 + }, + "1712": { + "city": "København V", + "lat": 55.6683, + "lng": 12.5577 + }, + "1714": { + "city": "København V", + "lat": 55.6663, + "lng": 12.5586 + }, + "1715": { + "city": "København V", + "lat": 55.6686, + "lng": 12.5609 + }, + "1716": { + "city": "København V", + "lat": 55.6689, + "lng": 12.5588 + }, + "1717": { + "city": "København V", + "lat": 55.6667, + "lng": 12.5574 + }, + "1718": { + "city": "København V", + "lat": 55.6666, + "lng": 12.5561 + }, + "1719": { + "city": "København V", + "lat": 55.6663, + "lng": 12.5554 + }, + "1720": { + "city": "København V", + "lat": 55.6654, + "lng": 12.5481 + }, + "1721": { + "city": "København V", + "lat": 55.6663, + "lng": 12.5524 + }, + "1722": { + "city": "København V", + "lat": 55.666, + "lng": 12.5548 + }, + "1723": { + "city": "København V", + "lat": 55.6674, + "lng": 12.5524 + }, + "1724": { + "city": "København V", + "lat": 55.668, + "lng": 12.552 + }, + "1725": { + "city": "København V", + "lat": 55.6655, + "lng": 12.5542 + }, + "1726": { + "city": "København V", + "lat": 55.6654, + "lng": 12.5529 + }, + "1727": { + "city": "København V", + "lat": 55.6651, + "lng": 12.5517 + }, + "1728": { + "city": "København V", + "lat": 55.6648, + "lng": 12.5506 + }, + "1729": { + "city": "København V", + "lat": 55.6646, + "lng": 12.5492 + }, + "1730": { + "city": "København V", + "lat": 55.6644, + "lng": 12.5482 + }, + "1731": { + "city": "København V", + "lat": 55.6641, + "lng": 12.5468 + }, + "1732": { + "city": "København V", + "lat": 55.6639, + "lng": 12.5458 + }, + "1733": { + "city": "København V", + "lat": 55.6637, + "lng": 12.5443 + }, + "1734": { + "city": "København V", + "lat": 55.6652, + "lng": 12.5457 + }, + "1735": { + "city": "København V", + "lat": 55.665, + "lng": 12.5452 + }, + "1736": { + "city": "København V", + "lat": 55.6654, + "lng": 12.5441 + }, + "1737": { + "city": "København V", + "lat": 55.6648, + "lng": 12.5444 + }, + "1738": { + "city": "København V", + "lat": 55.6646, + "lng": 12.5437 + }, + "1739": { + "city": "København V", + "lat": 55.6644, + "lng": 12.543 + }, + "1749": { + "city": "København V", + "lat": 55.6696, + "lng": 12.5369 + }, + "1750": { + "city": "København V", + "lat": 55.6678, + "lng": 12.5397 + }, + "1751": { + "city": "København V", + "lat": 55.6703, + "lng": 12.5446 + }, + "1752": { + "city": "København V", + "lat": 55.6701, + "lng": 12.5432 + }, + "1753": { + "city": "København V", + "lat": 55.6696, + "lng": 12.5433 + }, + "1754": { + "city": "København V", + "lat": 55.6692, + "lng": 12.5441 + }, + "1755": { + "city": "København V", + "lat": 55.6696, + "lng": 12.5428 + }, + "1756": { + "city": "København V", + "lat": 55.6695, + "lng": 12.5418 + }, + "1757": { + "city": "København V", + "lat": 55.6691, + "lng": 12.5408 + }, + "1758": { + "city": "København V", + "lat": 55.6682, + "lng": 12.542 + }, + "1759": { + "city": "København V", + "lat": 55.6686, + "lng": 12.5435 + }, + "1760": { + "city": "København V", + "lat": 55.6657, + "lng": 12.5448 + }, + "1761": { + "city": "København V", + "lat": 55.6666, + "lng": 12.5401 + }, + "1762": { + "city": "København V", + "lat": 55.6651, + "lng": 12.5408 + }, + "1763": { + "city": "København V", + "lat": 55.6651, + "lng": 12.5417 + }, + "1764": { + "city": "København V", + "lat": 55.665, + "lng": 12.5408 + }, + "1765": { + "city": "København V", + "lat": 55.6643, + "lng": 12.5391 + }, + "1766": { + "city": "København V", + "lat": 55.6641, + "lng": 12.5407 + }, + "1770": { + "city": "København V", + "lat": 55.6686, + "lng": 12.538 + }, + "1771": { + "city": "København V", + "lat": 55.6685, + "lng": 12.5392 + }, + "1772": { + "city": "København V", + "lat": 55.6684, + "lng": 12.5386 + }, + "1773": { + "city": "København V", + "lat": 55.6682, + "lng": 12.538 + }, + "1774": { + "city": "København V", + "lat": 55.6678, + "lng": 12.5383 + }, + "1775": { + "city": "København V", + "lat": 55.6679, + "lng": 12.5368 + }, + "1777": { + "city": "København V", + "lat": 55.6675, + "lng": 12.5376 + }, + "1799": { + "city": "København V", + "lat": 55.6661, + "lng": 12.5347 + }, + "2100": { + "city": "København Ø", + "lat": 55.7072, + "lng": 12.572 + }, + "2150": { + "city": "Nordhavn", + "lat": 55.7119, + "lng": 12.5984 + }, + "2200": { + "city": "København N", + "lat": 55.6948, + "lng": 12.5503 + }, + "2300": { + "city": "København S", + "lat": 55.6511, + "lng": 12.603 + }, + "2400": { + "city": "København NV", + "lat": 55.7086, + "lng": 12.5263 + }, + "2450": { + "city": "København SV", + "lat": 55.6484, + "lng": 12.5359 + }, + "2500": { + "city": "Valby", + "lat": 55.661, + "lng": 12.5006 + }, + "2700": { + "city": "Brønshøj", + "lat": 55.7069, + "lng": 12.4845 + }, + "2720": { + "city": "Vanløse", + "lat": 55.6896, + "lng": 12.4869 + }, + "1800": { + "city": "Frederiksberg C", + "lat": 55.6707, + "lng": 12.5345 + }, + "1801": { + "city": "Frederiksberg C", + "lat": 55.6693, + "lng": 12.5342 + }, + "1802": { + "city": "Frederiksberg C", + "lat": 55.6698, + "lng": 12.534 + }, + "1803": { + "city": "Frederiksberg C", + "lat": 55.6701, + "lng": 12.5335 + }, + "1804": { + "city": "Frederiksberg C", + "lat": 55.6698, + "lng": 12.5322 + }, + "1805": { + "city": "Frederiksberg C", + "lat": 55.668, + "lng": 12.5313 + }, + "1806": { + "city": "Frederiksberg C", + "lat": 55.6722, + "lng": 12.5334 + }, + "1807": { + "city": "Frederiksberg C", + "lat": 55.6714, + "lng": 12.5333 + }, + "1808": { + "city": "Frederiksberg C", + "lat": 55.6715, + "lng": 12.5342 + }, + "1809": { + "city": "Frederiksberg C", + "lat": 55.6724, + "lng": 12.5358 + }, + "1810": { + "city": "Frederiksberg C", + "lat": 55.6719, + "lng": 12.5397 + }, + "1811": { + "city": "Frederiksberg C", + "lat": 55.673, + "lng": 12.5369 + }, + "1812": { + "city": "Frederiksberg C", + "lat": 55.6721, + "lng": 12.5375 + }, + "1813": { + "city": "Frederiksberg C", + "lat": 55.6722, + "lng": 12.5387 + }, + "1814": { + "city": "Frederiksberg C", + "lat": 55.6724, + "lng": 12.5412 + }, + "1815": { + "city": "Frederiksberg C", + "lat": 55.6728, + "lng": 12.5424 + }, + "1816": { + "city": "Frederiksberg C", + "lat": 55.6728, + "lng": 12.5435 + }, + "1817": { + "city": "Frederiksberg C", + "lat": 55.6722, + "lng": 12.543 + }, + "1818": { + "city": "Frederiksberg C", + "lat": 55.6727, + "lng": 12.5446 + }, + "1819": { + "city": "Frederiksberg C", + "lat": 55.6736, + "lng": 12.5496 + }, + "1820": { + "city": "Frederiksberg C", + "lat": 55.6739, + "lng": 12.5418 + }, + "1822": { + "city": "Frederiksberg C", + "lat": 55.6726, + "lng": 12.5458 + }, + "1823": { + "city": "Frederiksberg C", + "lat": 55.6729, + "lng": 12.5454 + }, + "1824": { + "city": "Frederiksberg C", + "lat": 55.6743, + "lng": 12.547 + }, + "1825": { + "city": "Frederiksberg C", + "lat": 55.6745, + "lng": 12.5456 + }, + "1826": { + "city": "Frederiksberg C", + "lat": 55.6748, + "lng": 12.5445 + }, + "1827": { + "city": "Frederiksberg C", + "lat": 55.6749, + "lng": 12.5433 + }, + "1828": { + "city": "Frederiksberg C", + "lat": 55.675, + "lng": 12.542 + }, + "1829": { + "city": "Frederiksberg C", + "lat": 55.6752, + "lng": 12.541 + }, + "1850": { + "city": "Frederiksberg C", + "lat": 55.6763, + "lng": 12.5424 + }, + "1851": { + "city": "Frederiksberg C", + "lat": 55.6755, + "lng": 12.5396 + }, + "1852": { + "city": "Frederiksberg C", + "lat": 55.6758, + "lng": 12.5382 + }, + "1853": { + "city": "Frederiksberg C", + "lat": 55.6754, + "lng": 12.5364 + }, + "1854": { + "city": "Frederiksberg C", + "lat": 55.6755, + "lng": 12.5346 + }, + "1855": { + "city": "Frederiksberg C", + "lat": 55.6762, + "lng": 12.5355 + }, + "1856": { + "city": "Frederiksberg C", + "lat": 55.6768, + "lng": 12.5371 + }, + "1857": { + "city": "Frederiksberg C", + "lat": 55.6771, + "lng": 12.5356 + }, + "1860": { + "city": "Frederiksberg C", + "lat": 55.6809, + "lng": 12.536 + }, + "1861": { + "city": "Frederiksberg C", + "lat": 55.6793, + "lng": 12.5351 + }, + "1862": { + "city": "Frederiksberg C", + "lat": 55.6795, + "lng": 12.536 + }, + "1863": { + "city": "Frederiksberg C", + "lat": 55.6798, + "lng": 12.5375 + }, + "1864": { + "city": "Frederiksberg C", + "lat": 55.6785, + "lng": 12.5383 + }, + "1865": { + "city": "Frederiksberg C", + "lat": 55.6789, + "lng": 12.5386 + }, + "1866": { + "city": "Frederiksberg C", + "lat": 55.6779, + "lng": 12.5382 + }, + "1867": { + "city": "Frederiksberg C", + "lat": 55.6786, + "lng": 12.54 + }, + "1868": { + "city": "Frederiksberg C", + "lat": 55.6775, + "lng": 12.5404 + }, + "1870": { + "city": "Frederiksberg C", + "lat": 55.6804, + "lng": 12.5417 + }, + "1871": { + "city": "Frederiksberg C", + "lat": 55.6812, + "lng": 12.545 + }, + "1872": { + "city": "Frederiksberg C", + "lat": 55.6803, + "lng": 12.5452 + }, + "1873": { + "city": "Frederiksberg C", + "lat": 55.68, + "lng": 12.5444 + }, + "1874": { + "city": "Frederiksberg C", + "lat": 55.6796, + "lng": 12.5465 + }, + "1875": { + "city": "Frederiksberg C", + "lat": 55.6789, + "lng": 12.5452 + }, + "1876": { + "city": "Frederiksberg C", + "lat": 55.678, + "lng": 12.5449 + }, + "1877": { + "city": "Frederiksberg C", + "lat": 55.677, + "lng": 12.5433 + }, + "1878": { + "city": "Frederiksberg C", + "lat": 55.6768, + "lng": 12.5446 + }, + "1879": { + "city": "Frederiksberg C", + "lat": 55.6802, + "lng": 12.5485 + }, + "1900": { + "city": "Frederiksberg C", + "lat": 55.6778, + "lng": 12.555 + }, + "1901": { + "city": "Frederiksberg C", + "lat": 55.6761, + "lng": 12.5464 + }, + "1902": { + "city": "Frederiksberg C", + "lat": 55.6774, + "lng": 12.5481 + }, + "1903": { + "city": "Frederiksberg C", + "lat": 55.677, + "lng": 12.5492 + }, + "1904": { + "city": "Frederiksberg C", + "lat": 55.6764, + "lng": 12.5503 + }, + "1905": { + "city": "Frederiksberg C", + "lat": 55.6757, + "lng": 12.5508 + }, + "1906": { + "city": "Frederiksberg C", + "lat": 55.6752, + "lng": 12.5515 + }, + "1908": { + "city": "Frederiksberg C", + "lat": 55.6748, + "lng": 12.5536 + }, + "1909": { + "city": "Frederiksberg C", + "lat": 55.6758, + "lng": 12.5525 + }, + "1910": { + "city": "Frederiksberg C", + "lat": 55.6794, + "lng": 12.551 + }, + "1911": { + "city": "Frederiksberg C", + "lat": 55.6781, + "lng": 12.5509 + }, + "1912": { + "city": "Frederiksberg C", + "lat": 55.679, + "lng": 12.5512 + }, + "1913": { + "city": "Frederiksberg C", + "lat": 55.6786, + "lng": 12.5524 + }, + "1914": { + "city": "Frederiksberg C", + "lat": 55.6781, + "lng": 12.5536 + }, + "1915": { + "city": "Frederiksberg C", + "lat": 55.6787, + "lng": 12.5531 + }, + "1916": { + "city": "Frederiksberg C", + "lat": 55.6776, + "lng": 12.5554 + }, + "1917": { + "city": "Frederiksberg C", + "lat": 55.6769, + "lng": 12.5552 + }, + "1920": { + "city": "Frederiksberg C", + "lat": 55.68, + "lng": 12.5516 + }, + "1921": { + "city": "Frederiksberg C", + "lat": 55.6799, + "lng": 12.5529 + }, + "1922": { + "city": "Frederiksberg C", + "lat": 55.6801, + "lng": 12.5534 + }, + "1923": { + "city": "Frederiksberg C", + "lat": 55.6811, + "lng": 12.5503 + }, + "1924": { + "city": "Frederiksberg C", + "lat": 55.6812, + "lng": 12.5514 + }, + "1925": { + "city": "Frederiksberg C", + "lat": 55.6808, + "lng": 12.5536 + }, + "1926": { + "city": "Frederiksberg C", + "lat": 55.6801, + "lng": 12.556 + }, + "1927": { + "city": "Frederiksberg C", + "lat": 55.6794, + "lng": 12.5557 + }, + "1928": { + "city": "Frederiksberg C", + "lat": 55.6788, + "lng": 12.5558 + }, + "1950": { + "city": "Frederiksberg C", + "lat": 55.6817, + "lng": 12.5371 + }, + "1951": { + "city": "Frederiksberg C", + "lat": 55.6821, + "lng": 12.5364 + }, + "1952": { + "city": "Frederiksberg C", + "lat": 55.6824, + "lng": 12.537 + }, + "1953": { + "city": "Frederiksberg C", + "lat": 55.6828, + "lng": 12.5377 + }, + "1954": { + "city": "Frederiksberg C", + "lat": 55.6839, + "lng": 12.5392 + }, + "1955": { + "city": "Frederiksberg C", + "lat": 55.6836, + "lng": 12.5403 + }, + "1956": { + "city": "Frederiksberg C", + "lat": 55.6835, + "lng": 12.5413 + }, + "1957": { + "city": "Frederiksberg C", + "lat": 55.6832, + "lng": 12.5421 + }, + "1958": { + "city": "Frederiksberg C", + "lat": 55.6848, + "lng": 12.5425 + }, + "1959": { + "city": "Frederiksberg C", + "lat": 55.6858, + "lng": 12.5413 + }, + "1960": { + "city": "Frederiksberg C", + "lat": 55.6847, + "lng": 12.5512 + }, + "1961": { + "city": "Frederiksberg C", + "lat": 55.6816, + "lng": 12.5471 + }, + "1962": { + "city": "Frederiksberg C", + "lat": 55.6824, + "lng": 12.5475 + }, + "1963": { + "city": "Frederiksberg C", + "lat": 55.6813, + "lng": 12.5481 + }, + "1964": { + "city": "Frederiksberg C", + "lat": 55.6842, + "lng": 12.548 + }, + "1965": { + "city": "Frederiksberg C", + "lat": 55.6833, + "lng": 12.5483 + }, + "1966": { + "city": "Frederiksberg C", + "lat": 55.6833, + "lng": 12.5508 + }, + "1967": { + "city": "Frederiksberg C", + "lat": 55.6843, + "lng": 12.5499 + }, + "1970": { + "city": "Frederiksberg C", + "lat": 55.6826, + "lng": 12.5499 + }, + "1971": { + "city": "Frederiksberg C", + "lat": 55.6841, + "lng": 12.5521 + }, + "1972": { + "city": "Frederiksberg C", + "lat": 55.6836, + "lng": 12.5526 + }, + "1973": { + "city": "Frederiksberg C", + "lat": 55.6835, + "lng": 12.5538 + }, + "1974": { + "city": "Frederiksberg C", + "lat": 55.6828, + "lng": 12.5543 + }, + "2000": { + "city": "Frederiksberg", + "lat": 55.6825, + "lng": 12.5179 + }, + "2740": { + "city": "Skovlunde", + "lat": 55.7154, + "lng": 12.3989 + }, + "2750": { + "city": "Ballerup", + "lat": 55.7333, + "lng": 12.3566 + }, + "2760": { + "city": "Måløv", + "lat": 55.7513, + "lng": 12.3197 + }, + "2605": { + "city": "Brøndby", + "lat": 55.6527, + "lng": 12.4132 + }, + "2660": { + "city": "Brøndby Strand", + "lat": 55.6227, + "lng": 12.417 + }, + "2791": { + "city": "Dragør", + "lat": 55.5882, + "lng": 12.6482 + }, + "2820": { + "city": "Gentofte", + "lat": 55.751, + "lng": 12.5302 + }, + "2870": { + "city": "Dyssegård", + "lat": 55.7328, + "lng": 12.5268 + }, + "2900": { + "city": "Hellerup", + "lat": 55.7344, + "lng": 12.5601 + }, + "2920": { + "city": "Charlottenlund", + "lat": 55.7582, + "lng": 12.573 + }, + "2930": { + "city": "Klampenborg", + "lat": 55.7701, + "lng": 12.5886 + }, + "2860": { + "city": "Søborg", + "lat": 55.7361, + "lng": 12.483 + }, + "2880": { + "city": "Bagsværd", + "lat": 55.7571, + "lng": 12.4558 + }, + "2600": { + "city": "Glostrup", + "lat": 55.6813, + "lng": 12.4039 + }, + "2730": { + "city": "Herlev", + "lat": 55.7338, + "lng": 12.4278 + }, + "2620": { + "city": "Albertslund", + "lat": 55.6671, + "lng": 12.349 + }, + "2650": { + "city": "Hvidovre", + "lat": 55.6367, + "lng": 12.4717 + }, + "2630": { + "city": "Taastrup", + "lat": 55.65, + "lng": 12.2904 + }, + "2640": { + "city": "Hedehusene", + "lat": 55.6508, + "lng": 12.1977 + }, + "2800": { + "city": "Kongens Lyngby", + "lat": 55.7801, + "lng": 12.5122 + }, + "2830": { + "city": "Virum", + "lat": 55.7912, + "lng": 12.4705 + }, + "2610": { + "city": "Rødovre", + "lat": 55.6889, + "lng": 12.451 + }, + "2635": { + "city": "Ishøj", + "lat": 55.6154, + "lng": 12.3395 + }, + "2770": { + "city": "Kastrup", + "lat": 55.6227, + "lng": 12.6094 + }, + "2625": { + "city": "Vallensbæk", + "lat": 55.6477, + "lng": 12.3623 + }, + "2665": { + "city": "Vallensbæk Strand", + "lat": 55.6218, + "lng": 12.3864 + }, + "3500": { + "city": "Værløse", + "lat": 55.7763, + "lng": 12.364 + }, + "3520": { + "city": "Farum", + "lat": 55.8171, + "lng": 12.3713 + }, + "3450": { + "city": "Allerød", + "lat": 55.8692, + "lng": 12.3484 + }, + "3540": { + "city": "Lynge", + "lat": 55.8379, + "lng": 12.2804 + }, + "2980": { + "city": "Kokkedal", + "lat": 55.9115, + "lng": 12.4889 + }, + "2990": { + "city": "Nivå", + "lat": 55.9374, + "lng": 12.5002 + }, + "3050": { + "city": "Humlebæk", + "lat": 55.9604, + "lng": 12.5221 + }, + "3480": { + "city": "Fredensborg", + "lat": 55.9727, + "lng": 12.4105 + }, + "3000": { + "city": "Helsingør", + "lat": 56.0337, + "lng": 12.5881 + }, + "3060": { + "city": "Espergærde", + "lat": 55.9917, + "lng": 12.5419 + }, + "3070": { + "city": "Snekkersten", + "lat": 56.0119, + "lng": 12.5766 + }, + "3080": { + "city": "Tikøb", + "lat": 56.029, + "lng": 12.4465 + }, + "3100": { + "city": "Hornbæk", + "lat": 56.084, + "lng": 12.4523 + }, + "3140": { + "city": "Ålsgårde", + "lat": 56.0774, + "lng": 12.5283 + }, + "3150": { + "city": "Hellebæk", + "lat": 56.0668, + "lng": 12.5577 + }, + "3490": { + "city": "Kvistgård", + "lat": 55.9961, + "lng": 12.501 + }, + "3320": { + "city": "Skævinge", + "lat": 55.9179, + "lng": 12.1528 + }, + "3330": { + "city": "Gørløse", + "lat": 55.8839, + "lng": 12.1997 + }, + "3400": { + "city": "Hillerød", + "lat": 55.9359, + "lng": 12.2918 + }, + "2960": { + "city": "Rungsted Kyst", + "lat": 55.8868, + "lng": 12.5306 + }, + "2970": { + "city": "Hørsholm", + "lat": 55.8892, + "lng": 12.4963 + }, + "2840": { + "city": "Holte", + "lat": 55.8192, + "lng": 12.4855 + }, + "2850": { + "city": "Nærum", + "lat": 55.8182, + "lng": 12.533 + }, + "2942": { + "city": "Skodsborg", + "lat": 55.8275, + "lng": 12.5719 + }, + "2950": { + "city": "Vedbæk", + "lat": 55.8461, + "lng": 12.5454 + }, + "3460": { + "city": "Birkerød", + "lat": 55.8423, + "lng": 12.4296 + }, + "2765": { + "city": "Smørum", + "lat": 55.7361, + "lng": 12.2977 + }, + "3650": { + "city": "Ølstykke", + "lat": 55.7836, + "lng": 12.1609 + }, + "3660": { + "city": "Stenløse", + "lat": 55.7772, + "lng": 12.2177 + }, + "3670": { + "city": "Veksø Sjælland", + "lat": 55.7576, + "lng": 12.2386 + }, + "3550": { + "city": "Slangerup", + "lat": 55.8462, + "lng": 12.1744 + }, + "3600": { + "city": "Frederikssund", + "lat": 55.8383, + "lng": 12.0732 + }, + "3630": { + "city": "Jægerspris", + "lat": 55.8631, + "lng": 11.96 + }, + "4050": { + "city": "Skibby", + "lat": 55.7585, + "lng": 11.9552 + }, + "3300": { + "city": "Frederiksværk", + "lat": 55.9787, + "lng": 12.0242 + }, + "3310": { + "city": "Ølsted", + "lat": 55.9124, + "lng": 12.0604 + }, + "3360": { + "city": "Liseleje", + "lat": 56.0078, + "lng": 11.9679 + }, + "3370": { + "city": "Melby", + "lat": 55.992, + "lng": 11.9718 + }, + "3390": { + "city": "Hundested", + "lat": 55.9662, + "lng": 11.8782 + }, + "3120": { + "city": "Dronningmølle", + "lat": 56.0969, + "lng": 12.3818 + }, + "3200": { + "city": "Helsinge", + "lat": 56.016, + "lng": 12.1849 + }, + "3210": { + "city": "Vejby", + "lat": 56.0804, + "lng": 12.1437 + }, + "3220": { + "city": "Tisvildeleje", + "lat": 56.0579, + "lng": 12.0915 + }, + "3230": { + "city": "Græsted", + "lat": 56.0765, + "lng": 12.2586 + }, + "3250": { + "city": "Gilleleje", + "lat": 56.116, + "lng": 12.2866 + }, + "3700": { + "city": "Rønne", + "lat": 55.1065, + "lng": 14.7247 + }, + "3720": { + "city": "Aakirkeby", + "lat": 55.053, + "lng": 14.9259 + }, + "3730": { + "city": "Nexø", + "lat": 55.0428, + "lng": 15.1073 + }, + "3740": { + "city": "Svaneke", + "lat": 55.1313, + "lng": 15.1295 + }, + "3751": { + "city": "Østermarie", + "lat": 55.1385, + "lng": 15.0191 + }, + "3760": { + "city": "Gudhjem", + "lat": 55.1964, + "lng": 14.9504 + }, + "3770": { + "city": "Allinge", + "lat": 55.2654, + "lng": 14.805 + }, + "3782": { + "city": "Klemensker", + "lat": 55.18, + "lng": 14.8112 + }, + "3790": { + "city": "Hasle", + "lat": 55.1928, + "lng": 14.7193 + }, + "8700": { + "city": "Horsens", + "lat": 55.8623, + "lng": 9.8468 + }, + "8732": { + "city": "Hovedgård", + "lat": 55.9484, + "lng": 9.9577 + }, + "8740": { + "city": "Brædstrup", + "lat": 55.9727, + "lng": 9.6192 + }, + "8751": { + "city": "Gedved", + "lat": 55.9319, + "lng": 9.8467 + }, + "8752": { + "city": "Østbirk", + "lat": 55.9699, + "lng": 9.7518 + }, + "8789": { + "city": "Endelave", + "lat": 55.755, + "lng": 10.284 + }, + "6933": { + "city": "Kibæk", + "lat": 56.0102, + "lng": 8.8682 + }, + "6973": { + "city": "Ørnhøj", + "lat": 56.1973, + "lng": 8.5671 + }, + "7270": { + "city": "Stakroge", + "lat": 55.8965, + "lng": 8.847 + }, + "7280": { + "city": "Sønder Felding", + "lat": 55.9411, + "lng": 8.7837 + }, + "7400": { + "city": "Herning", + "lat": 56.1331, + "lng": 8.9736 + }, + "7451": { + "city": "Sunds", + "lat": 56.2173, + "lng": 9.0229 + }, + "7480": { + "city": "Vildbjerg", + "lat": 56.1877, + "lng": 8.7674 + }, + "7490": { + "city": "Aulum", + "lat": 56.2731, + "lng": 8.8037 + }, + "7540": { + "city": "Haderup", + "lat": 56.3566, + "lng": 8.9744 + }, + "7550": { + "city": "Sørvad", + "lat": 56.2605, + "lng": 8.6559 + }, + "6990": { + "city": "Ulfborg", + "lat": 56.2967, + "lng": 8.2163 + }, + "7500": { + "city": "Holstebro", + "lat": 56.363, + "lng": 8.6301 + }, + "7570": { + "city": "Vemb", + "lat": 56.3474, + "lng": 8.3622 + }, + "7830": { + "city": "Vinderup", + "lat": 56.4743, + "lng": 8.7959 + }, + "7620": { + "city": "Lemvig", + "lat": 56.541, + "lng": 8.292 + }, + "7650": { + "city": "Bøvlingbjerg", + "lat": 56.4376, + "lng": 8.2097 + }, + "7660": { + "city": "Bækmarksbro", + "lat": 56.4146, + "lng": 8.3202 + }, + "7673": { + "city": "Harboøre", + "lat": 56.6012, + "lng": 8.1592 + }, + "7680": { + "city": "Thyborøn", + "lat": 56.6984, + "lng": 8.2122 + }, + "7560": { + "city": "Hjerm", + "lat": 56.4395, + "lng": 8.6457 + }, + "7600": { + "city": "Struer", + "lat": 56.4925, + "lng": 8.5722 + }, + "7790": { + "city": "Thyholm", + "lat": 56.6368, + "lng": 8.5454 + }, + "8400": { + "city": "Ebeltoft", + "lat": 56.2173, + "lng": 10.6747 + }, + "8410": { + "city": "Rønde", + "lat": 56.3108, + "lng": 10.4664 + }, + "8420": { + "city": "Knebel", + "lat": 56.1792, + "lng": 10.4728 + }, + "8444": { + "city": "Balle", + "lat": 56.3145, + "lng": 10.7922 + }, + "8543": { + "city": "Hornslet", + "lat": 56.3161, + "lng": 10.3114 + }, + "8544": { + "city": "Mørke", + "lat": 56.3521, + "lng": 10.3423 + }, + "8550": { + "city": "Ryomgård", + "lat": 56.3849, + "lng": 10.4826 + }, + "8560": { + "city": "Kolind", + "lat": 56.3532, + "lng": 10.5908 + }, + "8581": { + "city": "Nimtofte", + "lat": 56.4133, + "lng": 10.5803 + }, + "8500": { + "city": "Grenaa", + "lat": 56.4213, + "lng": 10.8743 + }, + "8570": { + "city": "Trustrup", + "lat": 56.3567, + "lng": 10.7585 + }, + "8585": { + "city": "Glesborg", + "lat": 56.5089, + "lng": 10.6657 + }, + "8586": { + "city": "Ørum Djurs", + "lat": 56.445, + "lng": 10.6601 + }, + "8592": { + "city": "Anholt", + "lat": 56.7066, + "lng": 11.5396 + }, + "8950": { + "city": "Ørsted", + "lat": 56.5294, + "lng": 10.3334 + }, + "8961": { + "city": "Allingåbro", + "lat": 56.4807, + "lng": 10.4173 + }, + "8963": { + "city": "Auning", + "lat": 56.4306, + "lng": 10.3752 + }, + "8370": { + "city": "Hadsten", + "lat": 56.3324, + "lng": 10.0663 + }, + "8382": { + "city": "Hinnerup", + "lat": 56.2595, + "lng": 10.0657 + }, + "8450": { + "city": "Hammel", + "lat": 56.2572, + "lng": 9.8651 + }, + "8472": { + "city": "Sporup", + "lat": 56.2128, + "lng": 9.8331 + }, + "8860": { + "city": "Ulstrup", + "lat": 56.3874, + "lng": 9.7928 + }, + "8881": { + "city": "Thorsø", + "lat": 56.3045, + "lng": 9.7856 + }, + "8300": { + "city": "Odder", + "lat": 55.9626, + "lng": 10.1795 + }, + "8350": { + "city": "Hundslund", + "lat": 55.913, + "lng": 10.0565 + }, + "8799": { + "city": "Tunø", + "lat": 55.9512, + "lng": 10.4371 + }, + "8870": { + "city": "Langå", + "lat": 56.4097, + "lng": 9.9173 + }, + "8900": { + "city": "Randers C", + "lat": 56.464, + "lng": 10.0341 + }, + "8920": { + "city": "Randers NV", + "lat": 56.4764, + "lng": 9.9773 + }, + "8930": { + "city": "Randers NØ", + "lat": 56.4835, + "lng": 10.0844 + }, + "8940": { + "city": "Randers SV", + "lat": 56.4358, + "lng": 10.0334 + }, + "8960": { + "city": "Randers SØ", + "lat": 56.4422, + "lng": 10.1127 + }, + "8970": { + "city": "Havndal", + "lat": 56.6359, + "lng": 10.2281 + }, + "8981": { + "city": "Spentrup", + "lat": 56.54, + "lng": 10.0408 + }, + "8983": { + "city": "Gjerlev J", + "lat": 56.5835, + "lng": 10.1393 + }, + "8990": { + "city": "Fårup", + "lat": 56.5456, + "lng": 9.879 + }, + "8600": { + "city": "Silkeborg", + "lat": 56.1726, + "lng": 9.5564 + }, + "8620": { + "city": "Kjellerup", + "lat": 56.286, + "lng": 9.4126 + }, + "8632": { + "city": "Lemming", + "lat": 56.2401, + "lng": 9.5379 + }, + "8641": { + "city": "Sorring", + "lat": 56.1772, + "lng": 9.7805 + }, + "8643": { + "city": "Ans By", + "lat": 56.2993, + "lng": 9.6023 + }, + "8653": { + "city": "Them", + "lat": 56.0898, + "lng": 9.5503 + }, + "8654": { + "city": "Bryrup", + "lat": 56.026, + "lng": 9.517 + }, + "8882": { + "city": "Fårvang", + "lat": 56.2703, + "lng": 9.7072 + }, + "8883": { + "city": "Gjern", + "lat": 56.2244, + "lng": 9.738 + }, + "8305": { + "city": "Samsø", + "lat": 55.8602, + "lng": 10.5856 + }, + "8362": { + "city": "Hørning", + "lat": 56.0848, + "lng": 10.0333 + }, + "8464": { + "city": "Galten", + "lat": 56.1563, + "lng": 9.9273 + }, + "8660": { + "city": "Skanderborg", + "lat": 56.0401, + "lng": 9.9302 + }, + "8670": { + "city": "Låsby", + "lat": 56.1514, + "lng": 9.8075 + }, + "8680": { + "city": "Ry", + "lat": 56.0885, + "lng": 9.759 + }, + "8000": { + "city": "Aarhus C", + "lat": 56.1535, + "lng": 10.2034 + }, + "8200": { + "city": "Aarhus N", + "lat": 56.1888, + "lng": 10.1901 + }, + "8210": { + "city": "Aarhus V", + "lat": 56.1712, + "lng": 10.1605 + }, + "8220": { + "city": "Brabrand", + "lat": 56.1578, + "lng": 10.1092 + }, + "8230": { + "city": "Åbyhøj", + "lat": 56.1526, + "lng": 10.1602 + }, + "8240": { + "city": "Risskov", + "lat": 56.1976, + "lng": 10.2292 + }, + "8250": { + "city": "Egå", + "lat": 56.2216, + "lng": 10.293 + }, + "8260": { + "city": "Viby J", + "lat": 56.1284, + "lng": 10.1421 + }, + "8270": { + "city": "Højbjerg", + "lat": 56.1119, + "lng": 10.1907 + }, + "8310": { + "city": "Tranbjerg J", + "lat": 56.0904, + "lng": 10.1318 + }, + "8320": { + "city": "Mårslet", + "lat": 56.0698, + "lng": 10.1619 + }, + "8330": { + "city": "Beder", + "lat": 56.0578, + "lng": 10.2156 + }, + "8340": { + "city": "Malling", + "lat": 56.036, + "lng": 10.2065 + }, + "8355": { + "city": "Solbjerg", + "lat": 56.0396, + "lng": 10.0881 + }, + "8361": { + "city": "Hasselager", + "lat": 56.1077, + "lng": 10.0882 + }, + "8380": { + "city": "Trige", + "lat": 56.2648, + "lng": 10.1466 + }, + "8381": { + "city": "Tilst", + "lat": 56.1859, + "lng": 10.1089 + }, + "8462": { + "city": "Harlev J", + "lat": 56.1449, + "lng": 9.9963 + }, + "8471": { + "city": "Sabro", + "lat": 56.2079, + "lng": 10.0395 + }, + "8520": { + "city": "Lystrup", + "lat": 56.2374, + "lng": 10.2318 + }, + "8530": { + "city": "Hjortshøj", + "lat": 56.2628, + "lng": 10.2499 + }, + "8541": { + "city": "Skødstrup", + "lat": 56.2658, + "lng": 10.3144 + }, + "7330": { + "city": "Brande", + "lat": 55.9339, + "lng": 9.11 + }, + "7361": { + "city": "Ejstrupholm", + "lat": 55.9894, + "lng": 9.2921 + }, + "7362": { + "city": "Hampen", + "lat": 56.0173, + "lng": 9.3582 + }, + "7430": { + "city": "Ikast", + "lat": 56.1334, + "lng": 9.1573 + }, + "7441": { + "city": "Bording", + "lat": 56.1509, + "lng": 9.2703 + }, + "7442": { + "city": "Engesvang", + "lat": 56.1689, + "lng": 9.3436 + }, + "8765": { + "city": "Klovborg", + "lat": 55.9306, + "lng": 9.4903 + }, + "8766": { + "city": "Nørre Snede", + "lat": 55.9653, + "lng": 9.3974 + }, + "6880": { + "city": "Tarm", + "lat": 55.8883, + "lng": 8.5146 + }, + "6893": { + "city": "Hemmet", + "lat": 55.8418, + "lng": 8.3124 + }, + "6900": { + "city": "Skjern", + "lat": 55.9668, + "lng": 8.4999 + }, + "6920": { + "city": "Videbæk", + "lat": 56.0762, + "lng": 8.6563 + }, + "6940": { + "city": "Lem St", + "lat": 56.0361, + "lng": 8.3917 + }, + "6950": { + "city": "Ringkøbing", + "lat": 56.1039, + "lng": 8.2118 + }, + "6960": { + "city": "Hvide Sande", + "lat": 55.9573, + "lng": 8.1433 + }, + "6971": { + "city": "Spjald", + "lat": 56.137, + "lng": 8.5018 + }, + "6980": { + "city": "Tim", + "lat": 56.1977, + "lng": 8.2896 + }, + "7130": { + "city": "Juelsminde", + "lat": 55.7519, + "lng": 9.9985 + }, + "7140": { + "city": "Stouby", + "lat": 55.7077, + "lng": 9.798 + }, + "7150": { + "city": "Barrit", + "lat": 55.7131, + "lng": 9.8894 + }, + "7160": { + "city": "Tørring", + "lat": 55.8592, + "lng": 9.504 + }, + "7171": { + "city": "Uldum", + "lat": 55.8443, + "lng": 9.591 + }, + "8721": { + "city": "Daugård", + "lat": 55.7314, + "lng": 9.7117 + }, + "8722": { + "city": "Hedensted", + "lat": 55.7692, + "lng": 9.7022 + }, + "8723": { + "city": "Løsning", + "lat": 55.8028, + "lng": 9.6973 + }, + "8762": { + "city": "Flemming", + "lat": 55.8706, + "lng": 9.6629 + }, + "8763": { + "city": "Rask Mølle", + "lat": 55.875, + "lng": 9.6114 + }, + "8781": { + "city": "Stenderup", + "lat": 55.7903, + "lng": 9.8068 + }, + "8783": { + "city": "Hornsyld", + "lat": 55.7627, + "lng": 9.8514 + }, + "7800": { + "city": "Skive", + "lat": 56.5678, + "lng": 9.0226 + }, + "7840": { + "city": "Højslev", + "lat": 56.5815, + "lng": 9.1723 + }, + "7860": { + "city": "Spøttrup", + "lat": 56.615, + "lng": 8.8218 + }, + "7870": { + "city": "Roslev", + "lat": 56.7234, + "lng": 8.9892 + }, + "7884": { + "city": "Fur", + "lat": 56.822, + "lng": 9.0224 + }, + "7470": { + "city": "Karup J", + "lat": 56.3262, + "lng": 9.2049 + }, + "7850": { + "city": "Stoholm Jyll", + "lat": 56.484, + "lng": 9.1354 + }, + "8800": { + "city": "Viborg", + "lat": 56.4451, + "lng": 9.3909 + }, + "8830": { + "city": "Tjele", + "lat": 56.502, + "lng": 9.6119 + }, + "8831": { + "city": "Løgstrup", + "lat": 56.519, + "lng": 9.3224 + }, + "8832": { + "city": "Skals", + "lat": 56.5807, + "lng": 9.3716 + }, + "8840": { + "city": "Rødkærsbro", + "lat": 56.3503, + "lng": 9.5115 + }, + "8850": { + "city": "Bjerringbro", + "lat": 56.379, + "lng": 9.6515 + }, + "9632": { + "city": "Møldrup", + "lat": 56.6077, + "lng": 9.5031 + }, + "7900": { + "city": "Nykøbing M", + "lat": 56.8107, + "lng": 8.8325 + }, + "7950": { + "city": "Erslev", + "lat": 56.8472, + "lng": 8.7063 + }, + "7960": { + "city": "Karby", + "lat": 56.7533, + "lng": 8.5789 + }, + "7970": { + "city": "Redsted M", + "lat": 56.741, + "lng": 8.6453 + }, + "7980": { + "city": "Vils", + "lat": 56.7585, + "lng": 8.7271 + }, + "7990": { + "city": "Øster Assels", + "lat": 56.7025, + "lng": 8.7222 + }, + "7700": { + "city": "Thisted", + "lat": 56.9726, + "lng": 8.6263 + }, + "7730": { + "city": "Hanstholm", + "lat": 57.107, + "lng": 8.6391 + }, + "7741": { + "city": "Frøstrup", + "lat": 57.1063, + "lng": 8.9832 + }, + "7742": { + "city": "Vesløs", + "lat": 57.022, + "lng": 8.9721 + }, + "7752": { + "city": "Snedsted", + "lat": 56.8782, + "lng": 8.5045 + }, + "7755": { + "city": "Bedsted Thy", + "lat": 56.821, + "lng": 8.4021 + }, + "7760": { + "city": "Hurup Thy", + "lat": 56.7306, + "lng": 8.4147 + }, + "7770": { + "city": "Vestervig", + "lat": 56.7726, + "lng": 8.2802 + }, + "9320": { + "city": "Hjallerup", + "lat": 57.1772, + "lng": 10.1484 + }, + "9330": { + "city": "Dronninglund", + "lat": 57.1791, + "lng": 10.2976 + }, + "9340": { + "city": "Asaa", + "lat": 57.1367, + "lng": 10.3919 + }, + "9700": { + "city": "Brønderslev", + "lat": 57.273, + "lng": 9.9482 + }, + "9740": { + "city": "Jerslev J", + "lat": 57.2896, + "lng": 10.1101 + }, + "9300": { + "city": "Sæby", + "lat": 57.3102, + "lng": 10.5013 + }, + "9352": { + "city": "Dybvad", + "lat": 57.2803, + "lng": 10.3281 + }, + "9750": { + "city": "Østervrå", + "lat": 57.3401, + "lng": 10.2594 + }, + "9900": { + "city": "Frederikshavn", + "lat": 57.4404, + "lng": 10.5041 + }, + "9970": { + "city": "Strandby", + "lat": 57.4956, + "lng": 10.4893 + }, + "9981": { + "city": "Jerup", + "lat": 57.5261, + "lng": 10.4362 + }, + "9982": { + "city": "Ålbæk", + "lat": 57.5996, + "lng": 10.4044 + }, + "9990": { + "city": "Skagen", + "lat": 57.7208, + "lng": 10.5621 + }, + "9600": { + "city": "Aars", + "lat": 56.8062, + "lng": 9.4964 + }, + "9620": { + "city": "Aalestrup", + "lat": 56.694, + "lng": 9.4909 + }, + "9631": { + "city": "Gedsted", + "lat": 56.6911, + "lng": 9.3438 + }, + "9640": { + "city": "Farsø", + "lat": 56.7691, + "lng": 9.2872 + }, + "9670": { + "city": "Løgstør", + "lat": 56.9303, + "lng": 9.2656 + }, + "9681": { + "city": "Ranum", + "lat": 56.8967, + "lng": 9.2038 + }, + "9940": { + "city": "Læsø", + "lat": 57.288, + "lng": 11.0146 + }, + "9520": { + "city": "Skørping", + "lat": 56.8442, + "lng": 9.9058 + }, + "9530": { + "city": "Støvring", + "lat": 56.8945, + "lng": 9.8197 + }, + "9541": { + "city": "Suldrup", + "lat": 56.8479, + "lng": 9.6904 + }, + "9574": { + "city": "Bælum", + "lat": 56.8271, + "lng": 10.1248 + }, + "9575": { + "city": "Terndrup", + "lat": 56.8125, + "lng": 10.0575 + }, + "9610": { + "city": "Nørager", + "lat": 56.7454, + "lng": 9.6701 + }, + "9500": { + "city": "Hobro", + "lat": 56.6469, + "lng": 9.7953 + }, + "9510": { + "city": "Arden", + "lat": 56.7647, + "lng": 9.892 + }, + "9550": { + "city": "Mariager", + "lat": 56.6527, + "lng": 10.008 + }, + "9560": { + "city": "Hadsund", + "lat": 56.7505, + "lng": 10.2076 + }, + "9440": { + "city": "Aabybro", + "lat": 57.1458, + "lng": 9.7416 + }, + "9460": { + "city": "Brovst", + "lat": 57.1072, + "lng": 9.5186 + }, + "9490": { + "city": "Pandrup", + "lat": 57.2111, + "lng": 9.6381 + }, + "9492": { + "city": "Blokhus", + "lat": 57.2542, + "lng": 9.6048 + }, + "9493": { + "city": "Saltum", + "lat": 57.2809, + "lng": 9.6602 + }, + "9690": { + "city": "Fjerritslev", + "lat": 57.0961, + "lng": 9.2608 + }, + "9000": { + "city": "Aalborg", + "lat": 57.0394, + "lng": 9.9135 + }, + "9200": { + "city": "Aalborg SV", + "lat": 57.0116, + "lng": 9.8702 + }, + "9210": { + "city": "Aalborg SØ", + "lat": 57.0108, + "lng": 9.9382 + }, + "9220": { + "city": "Aalborg Øst", + "lat": 57.0291, + "lng": 9.9939 + }, + "9230": { + "city": "Svenstrup J", + "lat": 56.9679, + "lng": 9.8502 + }, + "9240": { + "city": "Nibe", + "lat": 56.9807, + "lng": 9.6229 + }, + "9260": { + "city": "Gistrup", + "lat": 56.9813, + "lng": 9.9943 + }, + "9270": { + "city": "Klarup", + "lat": 57.0119, + "lng": 10.05 + }, + "9280": { + "city": "Storvorde", + "lat": 56.9769, + "lng": 10.1718 + }, + "9293": { + "city": "Kongerslev", + "lat": 56.8928, + "lng": 10.1153 + }, + "9310": { + "city": "Vodskov", + "lat": 57.1002, + "lng": 10.0665 + }, + "9362": { + "city": "Gandrup", + "lat": 57.0555, + "lng": 10.1854 + }, + "9370": { + "city": "Hals", + "lat": 57.0316, + "lng": 10.3312 + }, + "9380": { + "city": "Vestbjerg", + "lat": 57.1318, + "lng": 9.9628 + }, + "9381": { + "city": "Sulsted", + "lat": 57.1645, + "lng": 9.9601 + }, + "9382": { + "city": "Tylstrup", + "lat": 57.1981, + "lng": 9.9408 + }, + "9400": { + "city": "Nørresundby", + "lat": 57.0698, + "lng": 9.9249 + }, + "9430": { + "city": "Vadum", + "lat": 57.1195, + "lng": 9.8578 + }, + "9480": { + "city": "Løkken", + "lat": 57.3825, + "lng": 9.7439 + }, + "9760": { + "city": "Vrå", + "lat": 57.3581, + "lng": 9.9481 + }, + "9800": { + "city": "Hjørring", + "lat": 57.4654, + "lng": 9.9685 + }, + "9830": { + "city": "Tårs", + "lat": 57.3804, + "lng": 10.1308 + }, + "9850": { + "city": "Hirtshals", + "lat": 57.5707, + "lng": 9.9667 + }, + "9870": { + "city": "Sindal", + "lat": 57.4677, + "lng": 10.236 + }, + "9881": { + "city": "Bindslev", + "lat": 57.5707, + "lng": 10.2023 + }, + "2670": { + "city": "Greve", + "lat": 55.5906, + "lng": 12.3018 + }, + "2690": { + "city": "Karlslunde", + "lat": 55.5663, + "lng": 12.2468 + }, + "4030": { + "city": "Tune", + "lat": 55.5955, + "lng": 12.1851 + }, + "4140": { + "city": "Borup", + "lat": 55.4947, + "lng": 11.9809 + }, + "4600": { + "city": "Køge", + "lat": 55.4624, + "lng": 12.1696 + }, + "4623": { + "city": "Lille Skensved", + "lat": 55.4975, + "lng": 12.096 + }, + "4632": { + "city": "Bjæverskov", + "lat": 55.4571, + "lng": 12.0418 + }, + "4681": { + "city": "Herfølge", + "lat": 55.4109, + "lng": 12.1414 + }, + "4682": { + "city": "Tureby", + "lat": 55.3841, + "lng": 12.0821 + }, + "4000": { + "city": "Roskilde", + "lat": 55.6513, + "lng": 12.0958 + }, + "4040": { + "city": "Jyllinge", + "lat": 55.7585, + "lng": 12.1069 + }, + "4130": { + "city": "Viby Sjælland", + "lat": 55.5499, + "lng": 12.0221 + }, + "4621": { + "city": "Gadstrup", + "lat": 55.5705, + "lng": 12.1032 + }, + "2680": { + "city": "Solrød Strand", + "lat": 55.532, + "lng": 12.213 + }, + "4622": { + "city": "Havdrup", + "lat": 55.5438, + "lng": 12.1221 + }, + "4500": { + "city": "Nykøbing Sj", + "lat": 55.9281, + "lng": 11.6393 + }, + "4534": { + "city": "Hørve", + "lat": 55.7538, + "lng": 11.4328 + }, + "4540": { + "city": "Fårevejle", + "lat": 55.8166, + "lng": 11.4282 + }, + "4550": { + "city": "Asnæs", + "lat": 55.8255, + "lng": 11.4991 + }, + "4560": { + "city": "Vig", + "lat": 55.8585, + "lng": 11.5577 + }, + "4571": { + "city": "Grevinge", + "lat": 55.7935, + "lng": 11.5885 + }, + "4572": { + "city": "Nørre Asmindrup", + "lat": 55.8798, + "lng": 11.6151 + }, + "4573": { + "city": "Højby", + "lat": 55.9059, + "lng": 11.5548 + }, + "4581": { + "city": "Rørvig", + "lat": 55.9497, + "lng": 11.7498 + }, + "4583": { + "city": "Sjællands Odde", + "lat": 55.9712, + "lng": 11.3624 + }, + "4300": { + "city": "Holbæk", + "lat": 55.7186, + "lng": 11.7069 + }, + "4305": { + "city": "Orø", + "lat": 55.7717, + "lng": 11.813 + }, + "4340": { + "city": "Tølløse", + "lat": 55.6114, + "lng": 11.727 + }, + "4350": { + "city": "Ugerløse", + "lat": 55.5881, + "lng": 11.6489 + }, + "4360": { + "city": "Kirke Eskilstrup", + "lat": 55.5705, + "lng": 11.7737 + }, + "4370": { + "city": "Store Merløse", + "lat": 55.5462, + "lng": 11.7159 + }, + "4390": { + "city": "Vipperød", + "lat": 55.6675, + "lng": 11.7431 + }, + "4420": { + "city": "Regstrup", + "lat": 55.6664, + "lng": 11.6185 + }, + "4440": { + "city": "Mørkøv", + "lat": 55.6513, + "lng": 11.5085 + }, + "4450": { + "city": "Jyderup", + "lat": 55.6602, + "lng": 11.4104 + }, + "4520": { + "city": "Svinninge", + "lat": 55.7188, + "lng": 11.4769 + }, + "4532": { + "city": "Gislinge", + "lat": 55.7328, + "lng": 11.5543 + }, + "4640": { + "city": "Faxe", + "lat": 55.2452, + "lng": 12.12 + }, + "4653": { + "city": "Karise", + "lat": 55.3055, + "lng": 12.1959 + }, + "4654": { + "city": "Faxe Ladeplads", + "lat": 55.2174, + "lng": 12.1601 + }, + "4683": { + "city": "Rønnede", + "lat": 55.2514, + "lng": 12.0302 + }, + "4690": { + "city": "Haslev", + "lat": 55.325, + "lng": 11.9696 + }, + "4270": { + "city": "Høng", + "lat": 55.5073, + "lng": 11.296 + }, + "4281": { + "city": "Gørlev", + "lat": 55.5324, + "lng": 11.1825 + }, + "4400": { + "city": "Kalundborg", + "lat": 55.6882, + "lng": 11.0848 + }, + "4460": { + "city": "Snertinge", + "lat": 55.7118, + "lng": 11.3801 + }, + "4470": { + "city": "Svebølle", + "lat": 55.6511, + "lng": 11.2885 + }, + "4480": { + "city": "Store Fuglede", + "lat": 55.5759, + "lng": 11.1709 + }, + "4490": { + "city": "Jerslev Sjælland", + "lat": 55.6163, + "lng": 11.2278 + }, + "4591": { + "city": "Føllenslev", + "lat": 55.746, + "lng": 11.3329 + }, + "4592": { + "city": "Sejerø", + "lat": 55.8916, + "lng": 11.1334 + }, + "4593": { + "city": "Eskebjerg", + "lat": 55.7022, + "lng": 11.274 + }, + "4100": { + "city": "Ringsted", + "lat": 55.4442, + "lng": 11.8065 + }, + "4174": { + "city": "Jystrup Midtsj", + "lat": 55.5176, + "lng": 11.8643 + }, + "4200": { + "city": "Slagelse", + "lat": 55.4044, + "lng": 11.3353 + }, + "4220": { + "city": "Korsør", + "lat": 55.3415, + "lng": 11.1549 + }, + "4230": { + "city": "Skælskør", + "lat": 55.2517, + "lng": 11.3043 + }, + "4241": { + "city": "Vemmelev", + "lat": 55.3612, + "lng": 11.2565 + }, + "4242": { + "city": "Boeslunde", + "lat": 55.305, + "lng": 11.2653 + }, + "4243": { + "city": "Rude", + "lat": 55.2142, + "lng": 11.4891 + }, + "4244": { + "city": "Agersø", + "lat": 55.2155, + "lng": 11.186 + }, + "4245": { + "city": "Omø", + "lat": 55.1575, + "lng": 11.1527 + }, + "4261": { + "city": "Dalmose", + "lat": 55.2855, + "lng": 11.4168 + }, + "4652": { + "city": "Hårlev", + "lat": 55.3509, + "lng": 12.2291 + }, + "4660": { + "city": "Store Heddinge", + "lat": 55.3096, + "lng": 12.3772 + }, + "4671": { + "city": "Strøby", + "lat": 55.395, + "lng": 12.2964 + }, + "4672": { + "city": "Klippinge", + "lat": 55.3553, + "lng": 12.3319 + }, + "4673": { + "city": "Rødvig Stevns", + "lat": 55.2576, + "lng": 12.3671 + }, + "4173": { + "city": "Fjenneslev", + "lat": 55.4334, + "lng": 11.6617 + }, + "4180": { + "city": "Sorø", + "lat": 55.4361, + "lng": 11.5633 + }, + "4190": { + "city": "Munke Bjergby", + "lat": 55.4991, + "lng": 11.5253 + }, + "4291": { + "city": "Ruds Vedby", + "lat": 55.5393, + "lng": 11.3794 + }, + "4293": { + "city": "Dianalund", + "lat": 55.5331, + "lng": 11.4889 + }, + "4295": { + "city": "Stenlille", + "lat": 55.543, + "lng": 11.5842 + }, + "4296": { + "city": "Nyrup", + "lat": 55.5434, + "lng": 11.6494 + }, + "4060": { + "city": "Kirke Såby", + "lat": 55.6459, + "lng": 11.8572 + }, + "4070": { + "city": "Kirke Hyllinge", + "lat": 55.7007, + "lng": 11.8935 + }, + "4320": { + "city": "Lejre", + "lat": 55.5819, + "lng": 11.9668 + }, + "4330": { + "city": "Hvalsø", + "lat": 55.5938, + "lng": 11.8649 + }, + "4895": { + "city": "Errindlev", + "lat": 54.6636, + "lng": 11.5015 + }, + "4900": { + "city": "Nakskov", + "lat": 54.8288, + "lng": 11.1277 + }, + "4912": { + "city": "Harpelunde", + "lat": 54.8771, + "lng": 11.0719 + }, + "4913": { + "city": "Horslunde", + "lat": 54.9212, + "lng": 11.2104 + }, + "4920": { + "city": "Søllested", + "lat": 54.8032, + "lng": 11.278 + }, + "4930": { + "city": "Maribo", + "lat": 54.7737, + "lng": 11.4972 + }, + "4941": { + "city": "Bandholm", + "lat": 54.8389, + "lng": 11.4681 + }, + "4942": { + "city": "Askø", + "lat": 54.893, + "lng": 11.4993 + }, + "4943": { + "city": "Torrig L", + "lat": 54.9085, + "lng": 11.3244 + }, + "4944": { + "city": "Fejø", + "lat": 54.9441, + "lng": 11.4089 + }, + "4945": { + "city": "Femø", + "lat": 54.9739, + "lng": 11.5378 + }, + "4951": { + "city": "Nørreballe", + "lat": 54.8094, + "lng": 11.4285 + }, + "4952": { + "city": "Stokkemarke", + "lat": 54.843, + "lng": 11.3728 + }, + "4953": { + "city": "Vesterborg", + "lat": 54.8652, + "lng": 11.2954 + }, + "4960": { + "city": "Holeby", + "lat": 54.7098, + "lng": 11.4829 + }, + "4970": { + "city": "Rødby", + "lat": 54.6835, + "lng": 11.3591 + }, + "4983": { + "city": "Dannemare", + "lat": 54.7396, + "lng": 11.189 + }, + "4160": { + "city": "Herlufmagle", + "lat": 55.3139, + "lng": 11.751 + }, + "4171": { + "city": "Glumsø", + "lat": 55.3621, + "lng": 11.6897 + }, + "4250": { + "city": "Fuglebjerg", + "lat": 55.3092, + "lng": 11.5482 + }, + "4262": { + "city": "Sandved", + "lat": 55.2534, + "lng": 11.5218 + }, + "4684": { + "city": "Holmegaard", + "lat": 55.268, + "lng": 11.8297 + }, + "4700": { + "city": "Næstved", + "lat": 55.2237, + "lng": 11.7629 + }, + "4733": { + "city": "Tappernøje", + "lat": 55.1769, + "lng": 11.9719 + }, + "4736": { + "city": "Karrebæksminde", + "lat": 55.1778, + "lng": 11.6523 + }, + "4800": { + "city": "Nykøbing F", + "lat": 54.7723, + "lng": 11.884 + }, + "4840": { + "city": "Nørre Alslev", + "lat": 54.9069, + "lng": 11.8529 + }, + "4850": { + "city": "Stubbekøbing", + "lat": 54.8846, + "lng": 12.0383 + }, + "4862": { + "city": "Guldborg", + "lat": 54.8637, + "lng": 11.7322 + }, + "4863": { + "city": "Eskilstrup", + "lat": 54.8542, + "lng": 11.8843 + }, + "4871": { + "city": "Horbelev", + "lat": 54.8238, + "lng": 12.0644 + }, + "4872": { + "city": "Idestrup", + "lat": 54.7247, + "lng": 11.9782 + }, + "4873": { + "city": "Væggerløse", + "lat": 54.6829, + "lng": 11.9496 + }, + "4874": { + "city": "Gedser", + "lat": 54.5953, + "lng": 11.944 + }, + "4880": { + "city": "Nysted", + "lat": 54.6704, + "lng": 11.7255 + }, + "4891": { + "city": "Toreby L", + "lat": 54.7597, + "lng": 11.7775 + }, + "4892": { + "city": "Kettinge", + "lat": 54.7008, + "lng": 11.747 + }, + "4894": { + "city": "Øster Ulslev", + "lat": 54.6958, + "lng": 11.6061 + }, + "4990": { + "city": "Sakskøbing", + "lat": 54.7971, + "lng": 11.6452 + }, + "4720": { + "city": "Præstø", + "lat": 55.1112, + "lng": 12.0618 + }, + "4735": { + "city": "Mern", + "lat": 55.0464, + "lng": 12.0706 + }, + "4750": { + "city": "Lundby", + "lat": 55.1098, + "lng": 11.8361 + }, + "4760": { + "city": "Vordingborg", + "lat": 55.0184, + "lng": 11.9152 + }, + "4771": { + "city": "Kalvehave", + "lat": 55.003, + "lng": 12.1508 + }, + "4772": { + "city": "Langebæk", + "lat": 54.9976, + "lng": 12.0811 + }, + "4773": { + "city": "Stensved", + "lat": 54.995, + "lng": 12.0268 + }, + "4780": { + "city": "Stege", + "lat": 54.9904, + "lng": 12.2915 + }, + "4791": { + "city": "Borre", + "lat": 54.9777, + "lng": 12.4697 + }, + "4792": { + "city": "Askeby", + "lat": 54.9063, + "lng": 12.1605 + }, + "4793": { + "city": "Bogø By", + "lat": 54.9233, + "lng": 12.0508 + }, + "5463": { + "city": "Harndrup", + "lat": 55.4572, + "lng": 10.0226 + }, + "5464": { + "city": "Brenderup Fyn", + "lat": 55.4986, + "lng": 9.9731 + }, + "5466": { + "city": "Asperup", + "lat": 55.4964, + "lng": 9.9025 + }, + "5500": { + "city": "Middelfart", + "lat": 55.5063, + "lng": 9.764 + }, + "5580": { + "city": "Nørre Aaby", + "lat": 55.4544, + "lng": 9.8711 + }, + "5591": { + "city": "Gelsted", + "lat": 55.3948, + "lng": 9.9623 + }, + "5592": { + "city": "Ejby", + "lat": 55.4228, + "lng": 9.9224 + }, + "5492": { + "city": "Vissenbjerg", + "lat": 55.3875, + "lng": 10.137 + }, + "5560": { + "city": "Aarup", + "lat": 55.3759, + "lng": 10.0484 + }, + "5610": { + "city": "Assens", + "lat": 55.2803, + "lng": 9.9166 + }, + "5620": { + "city": "Glamsbjerg", + "lat": 55.2758, + "lng": 10.0941 + }, + "5631": { + "city": "Ebberup", + "lat": 55.2081, + "lng": 9.9902 + }, + "5683": { + "city": "Haarby", + "lat": 55.2123, + "lng": 10.1075 + }, + "5690": { + "city": "Tommerup", + "lat": 55.3243, + "lng": 10.2044 + }, + "5600": { + "city": "Faaborg", + "lat": 55.1049, + "lng": 10.2503 + }, + "5601": { + "city": "Lyø", + "lat": 55.0434, + "lng": 10.1513 + }, + "5602": { + "city": "Avernakø", + "lat": 55.025, + "lng": 10.2758 + }, + "5603": { + "city": "Bjørnø", + "lat": 55.0639, + "lng": 10.2517 + }, + "5642": { + "city": "Millinge", + "lat": 55.1412, + "lng": 10.1733 + }, + "5672": { + "city": "Broby", + "lat": 55.2422, + "lng": 10.2629 + }, + "5750": { + "city": "Ringe", + "lat": 55.2326, + "lng": 10.4568 + }, + "5772": { + "city": "Kværndrup", + "lat": 55.179, + "lng": 10.5316 + }, + "5792": { + "city": "Årslev", + "lat": 55.3009, + "lng": 10.4407 + }, + "5854": { + "city": "Gislev", + "lat": 55.2161, + "lng": 10.6006 + }, + "5856": { + "city": "Ryslinge", + "lat": 55.2371, + "lng": 10.5366 + }, + "5863": { + "city": "Ferritslev Fyn", + "lat": 55.3133, + "lng": 10.5821 + }, + "5290": { + "city": "Marslev", + "lat": 55.395, + "lng": 10.5238 + }, + "5300": { + "city": "Kerteminde", + "lat": 55.4519, + "lng": 10.6486 + }, + "5330": { + "city": "Munkebo", + "lat": 55.458, + "lng": 10.5544 + }, + "5350": { + "city": "Rynkeby", + "lat": 55.3997, + "lng": 10.6134 + }, + "5370": { + "city": "Mesinge", + "lat": 55.508, + "lng": 10.629 + }, + "5380": { + "city": "Dalby", + "lat": 55.5166, + "lng": 10.6722 + }, + "5390": { + "city": "Martofte", + "lat": 55.5703, + "lng": 10.6254 + }, + "5550": { + "city": "Langeskov", + "lat": 55.3614, + "lng": 10.5855 + }, + "5540": { + "city": "Ullerslev", + "lat": 55.3583, + "lng": 10.6646 + }, + "5800": { + "city": "Nyborg", + "lat": 55.322, + "lng": 10.7801 + }, + "5853": { + "city": "Ørbæk", + "lat": 55.264, + "lng": 10.6608 + }, + "5871": { + "city": "Frørup", + "lat": 55.2388, + "lng": 10.7645 + }, + "5000": { + "city": "Odense C", + "lat": 55.4028, + "lng": 10.392 + }, + "5200": { + "city": "Odense V", + "lat": 55.3953, + "lng": 10.3289 + }, + "5210": { + "city": "Odense NV", + "lat": 55.415, + "lng": 10.3132 + }, + "5220": { + "city": "Odense SØ", + "lat": 55.3727, + "lng": 10.4601 + }, + "5230": { + "city": "Odense M", + "lat": 55.381, + "lng": 10.4017 + }, + "5240": { + "city": "Odense NØ", + "lat": 55.4176, + "lng": 10.4446 + }, + "5250": { + "city": "Odense SV", + "lat": 55.3585, + "lng": 10.3366 + }, + "5260": { + "city": "Odense S", + "lat": 55.3462, + "lng": 10.3902 + }, + "5270": { + "city": "Odense N", + "lat": 55.4341, + "lng": 10.3612 + }, + "5320": { + "city": "Agedrup", + "lat": 55.4259, + "lng": 10.4757 + }, + "5491": { + "city": "Blommenslyst", + "lat": 55.3879, + "lng": 10.25 + }, + "5700": { + "city": "Svendborg", + "lat": 55.0528, + "lng": 10.6094 + }, + "5762": { + "city": "Vester Skerninge", + "lat": 55.0722, + "lng": 10.4594 + }, + "5771": { + "city": "Stenstrup", + "lat": 55.1272, + "lng": 10.5131 + }, + "5874": { + "city": "Hesselager", + "lat": 55.1711, + "lng": 10.766 + }, + "5881": { + "city": "Skårup Fyn", + "lat": 55.0869, + "lng": 10.6986 + }, + "5882": { + "city": "Vejstrup", + "lat": 55.1092, + "lng": 10.7094 + }, + "5883": { + "city": "Oure", + "lat": 55.1218, + "lng": 10.725 + }, + "5884": { + "city": "Gudme", + "lat": 55.1497, + "lng": 10.7034 + }, + "5892": { + "city": "Gudbjerg Sydfyn", + "lat": 55.157, + "lng": 10.6569 + }, + "5400": { + "city": "Bogense", + "lat": 55.5548, + "lng": 10.0939 + }, + "5450": { + "city": "Otterup", + "lat": 55.5401, + "lng": 10.4029 + }, + "5462": { + "city": "Morud", + "lat": 55.4437, + "lng": 10.1928 + }, + "5471": { + "city": "Søndersø", + "lat": 55.4912, + "lng": 10.2028 + }, + "5474": { + "city": "Veflinge", + "lat": 55.4682, + "lng": 10.1526 + }, + "5485": { + "city": "Skamby", + "lat": 55.5188, + "lng": 10.2766 + }, + "5900": { + "city": "Rudkøbing", + "lat": 54.923, + "lng": 10.7403 + }, + "5932": { + "city": "Humble", + "lat": 54.8126, + "lng": 10.6901 + }, + "5935": { + "city": "Bagenkop", + "lat": 54.7511, + "lng": 10.6862 + }, + "5943": { + "city": "Strynø", + "lat": 54.9049, + "lng": 10.6108 + }, + "5953": { + "city": "Tranekær", + "lat": 55.0605, + "lng": 10.8773 + }, + "5960": { + "city": "Marstal", + "lat": 54.8575, + "lng": 10.5085 + }, + "5965": { + "city": "Birkholm", + "lat": 54.9307, + "lng": 10.5042 + }, + "5970": { + "city": "Ærøskøbing", + "lat": 54.8771, + "lng": 10.3895 + }, + "5985": { + "city": "Søby Ærø", + "lat": 54.9319, + "lng": 10.2671 + }, + "6100": { + "city": "Haderslev", + "lat": 55.2431, + "lng": 9.5239 + }, + "6500": { + "city": "Vojens", + "lat": 55.2428, + "lng": 9.2999 + }, + "6510": { + "city": "Gram", + "lat": 55.2814, + "lng": 9.0265 + }, + "6541": { + "city": "Bevtoft", + "lat": 55.198, + "lng": 9.204 + }, + "6560": { + "city": "Sommersted", + "lat": 55.3226, + "lng": 9.284 + }, + "6623": { + "city": "Vorbasse", + "lat": 55.6354, + "lng": 9.0813 + }, + "7190": { + "city": "Billund", + "lat": 55.7261, + "lng": 9.1164 + }, + "7200": { + "city": "Grindsted", + "lat": 55.7602, + "lng": 8.9211 + }, + "7250": { + "city": "Hejnsvig", + "lat": 55.6884, + "lng": 8.9799 + }, + "7260": { + "city": "Sønder Omme", + "lat": 55.8425, + "lng": 8.8964 + }, + "6300": { + "city": "Gråsten", + "lat": 54.9146, + "lng": 9.5725 + }, + "6310": { + "city": "Broager", + "lat": 54.8859, + "lng": 9.6782 + }, + "6320": { + "city": "Egernsund", + "lat": 54.9041, + "lng": 9.6154 + }, + "6400": { + "city": "Sønderborg", + "lat": 54.9213, + "lng": 9.7764 + }, + "6430": { + "city": "Nordborg", + "lat": 55.0331, + "lng": 9.7881 + }, + "6440": { + "city": "Augustenborg", + "lat": 54.9631, + "lng": 9.9198 + }, + "6470": { + "city": "Sydals", + "lat": 54.9011, + "lng": 9.9565 + }, + "6240": { + "city": "Løgumkloster", + "lat": 55.0555, + "lng": 8.979 + }, + "6261": { + "city": "Bredebro", + "lat": 55.0545, + "lng": 8.7706 + }, + "6270": { + "city": "Tønder", + "lat": 54.9442, + "lng": 8.8692 + }, + "6280": { + "city": "Højer", + "lat": 54.973, + "lng": 8.704 + }, + "6520": { + "city": "Toftlund", + "lat": 55.1794, + "lng": 9.0356 + }, + "6534": { + "city": "Agerskov", + "lat": 55.1294, + "lng": 9.1426 + }, + "6535": { + "city": "Branderup J", + "lat": 55.1198, + "lng": 9.065 + }, + "6780": { + "city": "Skærbæk", + "lat": 55.1659, + "lng": 8.7766 + }, + "6792": { + "city": "Rømø", + "lat": 55.1154, + "lng": 8.5377 + }, + "6690": { + "city": "Gørding", + "lat": 55.4732, + "lng": 8.8019 + }, + "6700": { + "city": "Esbjerg", + "lat": 55.4732, + "lng": 8.4592 + }, + "6705": { + "city": "Esbjerg Ø", + "lat": 55.4886, + "lng": 8.4965 + }, + "6710": { + "city": "Esbjerg V", + "lat": 55.5165, + "lng": 8.3942 + }, + "6715": { + "city": "Esbjerg N", + "lat": 55.517, + "lng": 8.4587 + }, + "6731": { + "city": "Tjæreborg", + "lat": 55.4648, + "lng": 8.5852 + }, + "6740": { + "city": "Bramming", + "lat": 55.4711, + "lng": 8.7055 + }, + "6760": { + "city": "Ribe", + "lat": 55.3209, + "lng": 8.7714 + }, + "6771": { + "city": "Gredstedbro", + "lat": 55.4033, + "lng": 8.7495 + }, + "6720": { + "city": "Fanø", + "lat": 55.4173, + "lng": 8.4037 + }, + "6753": { + "city": "Agerbæk", + "lat": 55.6024, + "lng": 8.8009 + }, + "6800": { + "city": "Varde", + "lat": 55.6349, + "lng": 8.5033 + }, + "6818": { + "city": "Årre", + "lat": 55.5748, + "lng": 8.6743 + }, + "6823": { + "city": "Ansager", + "lat": 55.7173, + "lng": 8.7474 + }, + "6830": { + "city": "Nørre Nebel", + "lat": 55.7814, + "lng": 8.2688 + }, + "6840": { + "city": "Oksbøl", + "lat": 55.6419, + "lng": 8.2731 + }, + "6851": { + "city": "Janderup Vestj", + "lat": 55.6306, + "lng": 8.3734 + }, + "6852": { + "city": "Billum", + "lat": 55.6137, + "lng": 8.3274 + }, + "6853": { + "city": "Vejers Strand", + "lat": 55.6247, + "lng": 8.1316 + }, + "6854": { + "city": "Henne", + "lat": 55.7332, + "lng": 8.2051 + }, + "6855": { + "city": "Outrup", + "lat": 55.7166, + "lng": 8.353 + }, + "6857": { + "city": "Blåvand", + "lat": 55.5542, + "lng": 8.1504 + }, + "6862": { + "city": "Tistrup", + "lat": 55.7165, + "lng": 8.612 + }, + "6870": { + "city": "Ølgod", + "lat": 55.8017, + "lng": 8.6196 + }, + "6600": { + "city": "Vejen", + "lat": 55.4789, + "lng": 9.1389 + }, + "6621": { + "city": "Gesten", + "lat": 55.5269, + "lng": 9.2039 + }, + "6622": { + "city": "Bække", + "lat": 55.5753, + "lng": 9.1472 + }, + "6630": { + "city": "Rødding", + "lat": 55.3707, + "lng": 9.1124 + }, + "6650": { + "city": "Brørup", + "lat": 55.4951, + "lng": 9.0153 + }, + "6660": { + "city": "Lintrup", + "lat": 55.4117, + "lng": 8.9784 + }, + "6670": { + "city": "Holsted", + "lat": 55.4998, + "lng": 8.9129 + }, + "6682": { + "city": "Hovborg", + "lat": 55.6063, + "lng": 8.9381 + }, + "6683": { + "city": "Føvling", + "lat": 55.4394, + "lng": 8.9093 + }, + "6752": { + "city": "Glejbjerg", + "lat": 55.5571, + "lng": 8.8302 + }, + "6200": { + "city": "Aabenraa", + "lat": 55.033, + "lng": 9.4398 + }, + "6210": { + "city": "Barsø", + "lat": 55.1214, + "lng": 9.5554 + }, + "6230": { + "city": "Rødekro", + "lat": 55.072, + "lng": 9.3241 + }, + "6330": { + "city": "Padborg", + "lat": 54.8367, + "lng": 9.3538 + }, + "6340": { + "city": "Kruså", + "lat": 54.858, + "lng": 9.4359 + }, + "6360": { + "city": "Tinglev", + "lat": 54.9316, + "lng": 9.2426 + }, + "6372": { + "city": "Bylderup-Bov", + "lat": 54.9577, + "lng": 9.1024 + }, + "6392": { + "city": "Bolderslev", + "lat": 54.9917, + "lng": 9.2719 + }, + "7000": { + "city": "Fredericia", + "lat": 55.5618, + "lng": 9.7151 + }, + "6000": { + "city": "Kolding", + "lat": 55.4924, + "lng": 9.4798 + }, + "6051": { + "city": "Almind", + "lat": 55.5629, + "lng": 9.4824 + }, + "6052": { + "city": "Viuf", + "lat": 55.5882, + "lng": 9.4914 + }, + "6064": { + "city": "Jordrup", + "lat": 55.5509, + "lng": 9.3138 + }, + "6070": { + "city": "Christiansfeld", + "lat": 55.3609, + "lng": 9.4699 + }, + "6091": { + "city": "Bjert", + "lat": 55.4528, + "lng": 9.5657 + }, + "6092": { + "city": "Sønder Stenderup", + "lat": 55.4581, + "lng": 9.6225 + }, + "6093": { + "city": "Sjølund", + "lat": 55.4074, + "lng": 9.5588 + }, + "6094": { + "city": "Hejls", + "lat": 55.3733, + "lng": 9.5986 + }, + "6580": { + "city": "Vamdrup", + "lat": 55.4235, + "lng": 9.3053 + }, + "6640": { + "city": "Lunderskov", + "lat": 55.4831, + "lng": 9.3079 + }, + "6040": { + "city": "Egtved", + "lat": 55.61, + "lng": 9.3509 + }, + "7080": { + "city": "Børkop", + "lat": 55.6471, + "lng": 9.6723 + }, + "7100": { + "city": "Vejle", + "lat": 55.7042, + "lng": 9.5245 + }, + "7120": { + "city": "Vejle Øst", + "lat": 55.7229, + "lng": 9.6142 + }, + "7173": { + "city": "Vonge", + "lat": 55.8628, + "lng": 9.4181 + }, + "7182": { + "city": "Bredsten", + "lat": 55.7049, + "lng": 9.3603 + }, + "7183": { + "city": "Randbøl", + "lat": 55.687, + "lng": 9.2611 + }, + "7184": { + "city": "Vandel", + "lat": 55.7109, + "lng": 9.2101 + }, + "7300": { + "city": "Jelling", + "lat": 55.7642, + "lng": 9.425 + }, + "7321": { + "city": "Gadbjerg", + "lat": 55.7698, + "lng": 9.3054 + }, + "7323": { + "city": "Give", + "lat": 55.8507, + "lng": 9.25 + }, + "9100": { + "city": "Aalborg", + "lat": 57.048, + "lng": 9.9187 + }, + "8100": { + "city": "Aarhus C", + "lat": 56.1567, + "lng": 10.2108 + }, + "8245": { + "city": "Risskov Ø", + "lat": 56.1972, + "lng": 10.248 + }, + "5100": { + "city": "Odense C", + "lat": 55.3959, + "lng": 10.3883 + }, + "6701": { + "city": "Esbjerg", + "lat": 55.4703, + "lng": 8.4519 + }, + "7007": { + "city": "Fredericia", + "lat": 55.5657, + "lng": 9.7526 + }, + "0900": { + "city": "København C", + "lat": 57.048, + "lng": 9.9187 + }, + "0960": { + "city": "Udland", + "lat": 56.804, + "lng": 9.5144 + }, + "0999": { + "city": "København C", + "lat": 57.7209, + "lng": 10.5839 + }, + "1001": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1002": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1003": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1004": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1005": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1006": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1007": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1008": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1009": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1010": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1011": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1012": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1013": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1014": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1015": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1016": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1017": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1018": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1019": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1020": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1021": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1022": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1023": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1024": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1025": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1026": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1092": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1093": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1095": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1098": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1140": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1147": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1148": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1217": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1240": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1448": { + "city": "København K", + "lat": 55.6759, + "lng": 12.5655 + }, + "1500": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1501": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1502": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1503": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1504": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1505": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1506": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1507": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1508": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1509": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1510": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1513": { + "city": "Centraltastning", + "lat": 55.6711, + "lng": 12.5653 + }, + "1592": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1599": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1630": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1780": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1785": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1786": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1787": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1790": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1835": { + "city": "Frederiksberg C", + "lat": 55.6794, + "lng": 12.5346 + }, + "0917": { + "city": "Københavns Pakkecent", + "lat": 55.6759, + "lng": 12.5655 + }, + "0800": { + "city": "Høje Taastrup", + "lat": 55.6471, + "lng": 12.2742 + }, + "1532": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + }, + "1533": { + "city": "København V", + "lat": 55.6759, + "lng": 12.5655 + } +} diff --git a/wwwroot/postnumre.json b/wwwroot/postnumre.json new file mode 100644 index 0000000..5e4df6f --- /dev/null +++ b/wwwroot/postnumre.json @@ -0,0 +1,1161 @@ +{ + "1050": "København K", + "1051": "København K", + "1052": "København K", + "1053": "København K", + "1054": "København K", + "1055": "København K", + "1056": "København K", + "1057": "København K", + "1058": "København K", + "1059": "København K", + "1060": "København K", + "1061": "København K", + "1062": "København K", + "1063": "København K", + "1064": "København K", + "1065": "København K", + "1066": "København K", + "1067": "København K", + "1068": "København K", + "1069": "København K", + "1070": "København K", + "1071": "København K", + "1072": "København K", + "1073": "København K", + "1074": "København K", + "1100": "København K", + "1101": "København K", + "1102": "København K", + "1103": "København K", + "1104": "København K", + "1105": "København K", + "1106": "København K", + "1107": "København K", + "1110": "København K", + "1111": "København K", + "1112": "København K", + "1113": "København K", + "1114": "København K", + "1115": "København K", + "1116": "København K", + "1117": "København K", + "1118": "København K", + "1119": "København K", + "1120": "København K", + "1121": "København K", + "1122": "København K", + "1123": "København K", + "1124": "København K", + "1125": "København K", + "1126": "København K", + "1127": "København K", + "1128": "København K", + "1129": "København K", + "1130": "København K", + "1131": "København K", + "1150": "København K", + "1151": "København K", + "1152": "København K", + "1153": "København K", + "1154": "København K", + "1155": "København K", + "1156": "København K", + "1157": "København K", + "1158": "København K", + "1159": "København K", + "1160": "København K", + "1161": "København K", + "1162": "København K", + "1164": "København K", + "1165": "København K", + "1166": "København K", + "1167": "København K", + "1168": "København K", + "1169": "København K", + "1170": "København K", + "1171": "København K", + "1172": "København K", + "1173": "København K", + "1174": "København K", + "1175": "København K", + "1200": "København K", + "1201": "København K", + "1202": "København K", + "1203": "København K", + "1204": "København K", + "1205": "København K", + "1206": "København K", + "1207": "København K", + "1208": "København K", + "1209": "København K", + "1210": "København K", + "1211": "København K", + "1212": "København K", + "1213": "København K", + "1214": "København K", + "1215": "København K", + "1216": "København K", + "1218": "København K", + "1219": "København K", + "1220": "København K", + "1221": "København K", + "1250": "København K", + "1251": "København K", + "1252": "København K", + "1253": "København K", + "1254": "København K", + "1255": "København K", + "1256": "København K", + "1257": "København K", + "1259": "København K", + "1260": "København K", + "1261": "København K", + "1263": "København K", + "1264": "København K", + "1265": "København K", + "1266": "København K", + "1267": "København K", + "1268": "København K", + "1270": "København K", + "1271": "København K", + "1300": "København K", + "1301": "København K", + "1302": "København K", + "1303": "København K", + "1304": "København K", + "1306": "København K", + "1307": "København K", + "1308": "København K", + "1309": "København K", + "1310": "København K", + "1311": "København K", + "1312": "København K", + "1313": "København K", + "1314": "København K", + "1315": "København K", + "1316": "København K", + "1317": "København K", + "1318": "København K", + "1319": "København K", + "1320": "København K", + "1321": "København K", + "1322": "København K", + "1323": "København K", + "1324": "København K", + "1325": "København K", + "1326": "København K", + "1327": "København K", + "1328": "København K", + "1329": "København K", + "1350": "København K", + "1352": "København K", + "1353": "København K", + "1354": "København K", + "1355": "København K", + "1356": "København K", + "1357": "København K", + "1358": "København K", + "1359": "København K", + "1360": "København K", + "1361": "København K", + "1362": "København K", + "1363": "København K", + "1364": "København K", + "1365": "København K", + "1366": "København K", + "1367": "København K", + "1368": "København K", + "1369": "København K", + "1370": "København K", + "1371": "København K", + "1400": "København K", + "1401": "København K", + "1402": "København K", + "1403": "København K", + "1406": "København K", + "1407": "København K", + "1408": "København K", + "1409": "København K", + "1410": "København K", + "1411": "København K", + "1412": "København K", + "1413": "København K", + "1414": "København K", + "1415": "København K", + "1416": "København K", + "1417": "København K", + "1418": "København K", + "1419": "København K", + "1420": "København K", + "1421": "København K", + "1422": "København K", + "1423": "København K", + "1424": "København K", + "1425": "København K", + "1426": "København K", + "1427": "København K", + "1428": "København K", + "1429": "København K", + "1430": "København K", + "1432": "København K", + "1433": "København K", + "1434": "København K", + "1435": "København K", + "1436": "København K", + "1437": "København K", + "1438": "København K", + "1439": "København K", + "1440": "København K", + "1441": "København K", + "1450": "København K", + "1451": "København K", + "1452": "København K", + "1453": "København K", + "1454": "København K", + "1455": "København K", + "1456": "København K", + "1457": "København K", + "1458": "København K", + "1459": "København K", + "1460": "København K", + "1461": "København K", + "1462": "København K", + "1463": "København K", + "1464": "København K", + "1465": "København K", + "1466": "København K", + "1467": "København K", + "1468": "København K", + "1470": "København K", + "1471": "København K", + "1472": "København K", + "1473": "København K", + "1550": "København V", + "1551": "København V", + "1552": "København V", + "1553": "København V", + "1554": "København V", + "1555": "København V", + "1556": "København V", + "1557": "København V", + "1558": "København V", + "1559": "København V", + "1560": "København V", + "1561": "København V", + "1562": "København V", + "1563": "København V", + "1564": "København V", + "1567": "København V", + "1568": "København V", + "1569": "København V", + "1570": "København V", + "1571": "København V", + "1572": "København V", + "1573": "København V", + "1574": "København V", + "1575": "København V", + "1576": "København V", + "1577": "København V", + "1600": "København V", + "1601": "København V", + "1602": "København V", + "1603": "København V", + "1604": "København V", + "1605": "København V", + "1606": "København V", + "1607": "København V", + "1608": "København V", + "1609": "København V", + "1610": "København V", + "1611": "København V", + "1612": "København V", + "1613": "København V", + "1614": "København V", + "1615": "København V", + "1616": "København V", + "1617": "København V", + "1618": "København V", + "1619": "København V", + "1620": "København V", + "1621": "København V", + "1622": "København V", + "1623": "København V", + "1624": "København V", + "1631": "København V", + "1632": "København V", + "1633": "København V", + "1634": "København V", + "1635": "København V", + "1650": "København V", + "1651": "København V", + "1652": "København V", + "1653": "København V", + "1654": "København V", + "1655": "København V", + "1656": "København V", + "1657": "København V", + "1658": "København V", + "1659": "København V", + "1660": "København V", + "1661": "København V", + "1662": "København V", + "1663": "København V", + "1664": "København V", + "1665": "København V", + "1666": "København V", + "1667": "København V", + "1668": "København V", + "1669": "København V", + "1670": "København V", + "1671": "København V", + "1672": "København V", + "1673": "København V", + "1674": "København V", + "1675": "København V", + "1676": "København V", + "1677": "København V", + "1699": "København V", + "1700": "København V", + "1701": "København V", + "1702": "København V", + "1703": "København V", + "1704": "København V", + "1705": "København V", + "1706": "København V", + "1707": "København V", + "1708": "København V", + "1709": "København V", + "1710": "København V", + "1711": "København V", + "1712": "København V", + "1714": "København V", + "1715": "København V", + "1716": "København V", + "1717": "København V", + "1718": "København V", + "1719": "København V", + "1720": "København V", + "1721": "København V", + "1722": "København V", + "1723": "København V", + "1724": "København V", + "1725": "København V", + "1726": "København V", + "1727": "København V", + "1728": "København V", + "1729": "København V", + "1730": "København V", + "1731": "København V", + "1732": "København V", + "1733": "København V", + "1734": "København V", + "1735": "København V", + "1736": "København V", + "1737": "København V", + "1738": "København V", + "1739": "København V", + "1749": "København V", + "1750": "København V", + "1751": "København V", + "1752": "København V", + "1753": "København V", + "1754": "København V", + "1755": "København V", + "1756": "København V", + "1757": "København V", + "1758": "København V", + "1759": "København V", + "1760": "København V", + "1761": "København V", + "1762": "København V", + "1763": "København V", + "1764": "København V", + "1765": "København V", + "1766": "København V", + "1770": "København V", + "1771": "København V", + "1772": "København V", + "1773": "København V", + "1774": "København V", + "1775": "København V", + "1777": "København V", + "1799": "København V", + "2100": "København Ø", + "2150": "Nordhavn", + "2200": "København N", + "2300": "København S", + "2400": "København NV", + "2450": "København SV", + "2500": "Valby", + "2700": "Brønshøj", + "2720": "Vanløse", + "1800": "Frederiksberg C", + "1801": "Frederiksberg C", + "1802": "Frederiksberg C", + "1803": "Frederiksberg C", + "1804": "Frederiksberg C", + "1805": "Frederiksberg C", + "1806": "Frederiksberg C", + "1807": "Frederiksberg C", + "1808": "Frederiksberg C", + "1809": "Frederiksberg C", + "1810": "Frederiksberg C", + "1811": "Frederiksberg C", + "1812": "Frederiksberg C", + "1813": "Frederiksberg C", + "1814": "Frederiksberg C", + "1815": "Frederiksberg C", + "1816": "Frederiksberg C", + "1817": "Frederiksberg C", + "1818": "Frederiksberg C", + "1819": "Frederiksberg C", + "1820": "Frederiksberg C", + "1822": "Frederiksberg C", + "1823": "Frederiksberg C", + "1824": "Frederiksberg C", + "1825": "Frederiksberg C", + "1826": "Frederiksberg C", + "1827": "Frederiksberg C", + "1828": "Frederiksberg C", + "1829": "Frederiksberg C", + "1850": "Frederiksberg C", + "1851": "Frederiksberg C", + "1852": "Frederiksberg C", + "1853": "Frederiksberg C", + "1854": "Frederiksberg C", + "1855": "Frederiksberg C", + "1856": "Frederiksberg C", + "1857": "Frederiksberg C", + "1860": "Frederiksberg C", + "1861": "Frederiksberg C", + "1862": "Frederiksberg C", + "1863": "Frederiksberg C", + "1864": "Frederiksberg C", + "1865": "Frederiksberg C", + "1866": "Frederiksberg C", + "1867": "Frederiksberg C", + "1868": "Frederiksberg C", + "1870": "Frederiksberg C", + "1871": "Frederiksberg C", + "1872": "Frederiksberg C", + "1873": "Frederiksberg C", + "1874": "Frederiksberg C", + "1875": "Frederiksberg C", + "1876": "Frederiksberg C", + "1877": "Frederiksberg C", + "1878": "Frederiksberg C", + "1879": "Frederiksberg C", + "1900": "Frederiksberg C", + "1901": "Frederiksberg C", + "1902": "Frederiksberg C", + "1903": "Frederiksberg C", + "1904": "Frederiksberg C", + "1905": "Frederiksberg C", + "1906": "Frederiksberg C", + "1908": "Frederiksberg C", + "1909": "Frederiksberg C", + "1910": "Frederiksberg C", + "1911": "Frederiksberg C", + "1912": "Frederiksberg C", + "1913": "Frederiksberg C", + "1914": "Frederiksberg C", + "1915": "Frederiksberg C", + "1916": "Frederiksberg C", + "1917": "Frederiksberg C", + "1920": "Frederiksberg C", + "1921": "Frederiksberg C", + "1922": "Frederiksberg C", + "1923": "Frederiksberg C", + "1924": "Frederiksberg C", + "1925": "Frederiksberg C", + "1926": "Frederiksberg C", + "1927": "Frederiksberg C", + "1928": "Frederiksberg C", + "1950": "Frederiksberg C", + "1951": "Frederiksberg C", + "1952": "Frederiksberg C", + "1953": "Frederiksberg C", + "1954": "Frederiksberg C", + "1955": "Frederiksberg C", + "1956": "Frederiksberg C", + "1957": "Frederiksberg C", + "1958": "Frederiksberg C", + "1959": "Frederiksberg C", + "1960": "Frederiksberg C", + "1961": "Frederiksberg C", + "1962": "Frederiksberg C", + "1963": "Frederiksberg C", + "1964": "Frederiksberg C", + "1965": "Frederiksberg C", + "1966": "Frederiksberg C", + "1967": "Frederiksberg C", + "1970": "Frederiksberg C", + "1971": "Frederiksberg C", + "1972": "Frederiksberg C", + "1973": "Frederiksberg C", + "1974": "Frederiksberg C", + "2000": "Frederiksberg", + "2740": "Skovlunde", + "2750": "Ballerup", + "2760": "Måløv", + "2605": "Brøndby", + "2660": "Brøndby Strand", + "2791": "Dragør", + "2820": "Gentofte", + "2870": "Dyssegård", + "2900": "Hellerup", + "2920": "Charlottenlund", + "2930": "Klampenborg", + "2860": "Søborg", + "2880": "Bagsværd", + "2600": "Glostrup", + "2730": "Herlev", + "2620": "Albertslund", + "2650": "Hvidovre", + "2630": "Taastrup", + "2640": "Hedehusene", + "2800": "Kongens Lyngby", + "2830": "Virum", + "2610": "Rødovre", + "2635": "Ishøj", + "2770": "Kastrup", + "2625": "Vallensbæk", + "2665": "Vallensbæk Strand", + "3500": "Værløse", + "3520": "Farum", + "3450": "Allerød", + "3540": "Lynge", + "2980": "Kokkedal", + "2990": "Nivå", + "3050": "Humlebæk", + "3480": "Fredensborg", + "3000": "Helsingør", + "3060": "Espergærde", + "3070": "Snekkersten", + "3080": "Tikøb", + "3100": "Hornbæk", + "3140": "Ålsgårde", + "3150": "Hellebæk", + "3490": "Kvistgård", + "3320": "Skævinge", + "3330": "Gørløse", + "3400": "Hillerød", + "2960": "Rungsted Kyst", + "2970": "Hørsholm", + "2840": "Holte", + "2850": "Nærum", + "2942": "Skodsborg", + "2950": "Vedbæk", + "3460": "Birkerød", + "2765": "Smørum", + "3650": "Ølstykke", + "3660": "Stenløse", + "3670": "Veksø Sjælland", + "3550": "Slangerup", + "3600": "Frederikssund", + "3630": "Jægerspris", + "4050": "Skibby", + "3300": "Frederiksværk", + "3310": "Ølsted", + "3360": "Liseleje", + "3370": "Melby", + "3390": "Hundested", + "3120": "Dronningmølle", + "3200": "Helsinge", + "3210": "Vejby", + "3220": "Tisvildeleje", + "3230": "Græsted", + "3250": "Gilleleje", + "3700": "Rønne", + "3720": "Aakirkeby", + "3730": "Nexø", + "3740": "Svaneke", + "3751": "Østermarie", + "3760": "Gudhjem", + "3770": "Allinge", + "3782": "Klemensker", + "3790": "Hasle", + "8700": "Horsens", + "8732": "Hovedgård", + "8740": "Brædstrup", + "8751": "Gedved", + "8752": "Østbirk", + "8789": "Endelave", + "6933": "Kibæk", + "6973": "Ørnhøj", + "7270": "Stakroge", + "7280": "Sønder Felding", + "7400": "Herning", + "7451": "Sunds", + "7480": "Vildbjerg", + "7490": "Aulum", + "7540": "Haderup", + "7550": "Sørvad", + "6990": "Ulfborg", + "7500": "Holstebro", + "7570": "Vemb", + "7830": "Vinderup", + "7620": "Lemvig", + "7650": "Bøvlingbjerg", + "7660": "Bækmarksbro", + "7673": "Harboøre", + "7680": "Thyborøn", + "7560": "Hjerm", + "7600": "Struer", + "7790": "Thyholm", + "8400": "Ebeltoft", + "8410": "Rønde", + "8420": "Knebel", + "8444": "Balle", + "8543": "Hornslet", + "8544": "Mørke", + "8550": "Ryomgård", + "8560": "Kolind", + "8581": "Nimtofte", + "8500": "Grenaa", + "8570": "Trustrup", + "8585": "Glesborg", + "8586": "Ørum Djurs", + "8592": "Anholt", + "8950": "Ørsted", + "8961": "Allingåbro", + "8963": "Auning", + "8370": "Hadsten", + "8382": "Hinnerup", + "8450": "Hammel", + "8472": "Sporup", + "8860": "Ulstrup", + "8881": "Thorsø", + "8300": "Odder", + "8350": "Hundslund", + "8799": "Tunø", + "8870": "Langå", + "8900": "Randers C", + "8920": "Randers NV", + "8930": "Randers NØ", + "8940": "Randers SV", + "8960": "Randers SØ", + "8970": "Havndal", + "8981": "Spentrup", + "8983": "Gjerlev J", + "8990": "Fårup", + "8600": "Silkeborg", + "8620": "Kjellerup", + "8632": "Lemming", + "8641": "Sorring", + "8643": "Ans By", + "8653": "Them", + "8654": "Bryrup", + "8882": "Fårvang", + "8883": "Gjern", + "8305": "Samsø", + "8362": "Hørning", + "8464": "Galten", + "8660": "Skanderborg", + "8670": "Låsby", + "8680": "Ry", + "8000": "Aarhus C", + "8200": "Aarhus N", + "8210": "Aarhus V", + "8220": "Brabrand", + "8230": "Åbyhøj", + "8240": "Risskov", + "8250": "Egå", + "8260": "Viby J", + "8270": "Højbjerg", + "8310": "Tranbjerg J", + "8320": "Mårslet", + "8330": "Beder", + "8340": "Malling", + "8355": "Solbjerg", + "8361": "Hasselager", + "8380": "Trige", + "8381": "Tilst", + "8462": "Harlev J", + "8471": "Sabro", + "8520": "Lystrup", + "8530": "Hjortshøj", + "8541": "Skødstrup", + "7330": "Brande", + "7361": "Ejstrupholm", + "7362": "Hampen", + "7430": "Ikast", + "7441": "Bording", + "7442": "Engesvang", + "8765": "Klovborg", + "8766": "Nørre Snede", + "6880": "Tarm", + "6893": "Hemmet", + "6900": "Skjern", + "6920": "Videbæk", + "6940": "Lem St", + "6950": "Ringkøbing", + "6960": "Hvide Sande", + "6971": "Spjald", + "6980": "Tim", + "7130": "Juelsminde", + "7140": "Stouby", + "7150": "Barrit", + "7160": "Tørring", + "7171": "Uldum", + "8721": "Daugård", + "8722": "Hedensted", + "8723": "Løsning", + "8762": "Flemming", + "8763": "Rask Mølle", + "8781": "Stenderup", + "8783": "Hornsyld", + "7800": "Skive", + "7840": "Højslev", + "7860": "Spøttrup", + "7870": "Roslev", + "7884": "Fur", + "7470": "Karup J", + "7850": "Stoholm Jyll", + "8800": "Viborg", + "8830": "Tjele", + "8831": "Løgstrup", + "8832": "Skals", + "8840": "Rødkærsbro", + "8850": "Bjerringbro", + "9632": "Møldrup", + "7900": "Nykøbing M", + "7950": "Erslev", + "7960": "Karby", + "7970": "Redsted M", + "7980": "Vils", + "7990": "Øster Assels", + "7700": "Thisted", + "7730": "Hanstholm", + "7741": "Frøstrup", + "7742": "Vesløs", + "7752": "Snedsted", + "7755": "Bedsted Thy", + "7760": "Hurup Thy", + "7770": "Vestervig", + "9320": "Hjallerup", + "9330": "Dronninglund", + "9340": "Asaa", + "9700": "Brønderslev", + "9740": "Jerslev J", + "9300": "Sæby", + "9352": "Dybvad", + "9750": "Østervrå", + "9900": "Frederikshavn", + "9970": "Strandby", + "9981": "Jerup", + "9982": "Ålbæk", + "9990": "Skagen", + "9600": "Aars", + "9620": "Aalestrup", + "9631": "Gedsted", + "9640": "Farsø", + "9670": "Løgstør", + "9681": "Ranum", + "9940": "Læsø", + "9520": "Skørping", + "9530": "Støvring", + "9541": "Suldrup", + "9574": "Bælum", + "9575": "Terndrup", + "9610": "Nørager", + "9500": "Hobro", + "9510": "Arden", + "9550": "Mariager", + "9560": "Hadsund", + "9440": "Aabybro", + "9460": "Brovst", + "9490": "Pandrup", + "9492": "Blokhus", + "9493": "Saltum", + "9690": "Fjerritslev", + "9000": "Aalborg", + "9200": "Aalborg SV", + "9210": "Aalborg SØ", + "9220": "Aalborg Øst", + "9230": "Svenstrup J", + "9240": "Nibe", + "9260": "Gistrup", + "9270": "Klarup", + "9280": "Storvorde", + "9293": "Kongerslev", + "9310": "Vodskov", + "9362": "Gandrup", + "9370": "Hals", + "9380": "Vestbjerg", + "9381": "Sulsted", + "9382": "Tylstrup", + "9400": "Nørresundby", + "9430": "Vadum", + "9480": "Løkken", + "9760": "Vrå", + "9800": "Hjørring", + "9830": "Tårs", + "9850": "Hirtshals", + "9870": "Sindal", + "9881": "Bindslev", + "2670": "Greve", + "2690": "Karlslunde", + "4030": "Tune", + "4140": "Borup", + "4600": "Køge", + "4623": "Lille Skensved", + "4632": "Bjæverskov", + "4681": "Herfølge", + "4682": "Tureby", + "4000": "Roskilde", + "4040": "Jyllinge", + "4130": "Viby Sjælland", + "4621": "Gadstrup", + "2680": "Solrød Strand", + "4622": "Havdrup", + "4500": "Nykøbing Sj", + "4534": "Hørve", + "4540": "Fårevejle", + "4550": "Asnæs", + "4560": "Vig", + "4571": "Grevinge", + "4572": "Nørre Asmindrup", + "4573": "Højby", + "4581": "Rørvig", + "4583": "Sjællands Odde", + "4300": "Holbæk", + "4305": "Orø", + "4340": "Tølløse", + "4350": "Ugerløse", + "4360": "Kirke Eskilstrup", + "4370": "Store Merløse", + "4390": "Vipperød", + "4420": "Regstrup", + "4440": "Mørkøv", + "4450": "Jyderup", + "4520": "Svinninge", + "4532": "Gislinge", + "4640": "Faxe", + "4653": "Karise", + "4654": "Faxe Ladeplads", + "4683": "Rønnede", + "4690": "Haslev", + "4270": "Høng", + "4281": "Gørlev", + "4400": "Kalundborg", + "4460": "Snertinge", + "4470": "Svebølle", + "4480": "Store Fuglede", + "4490": "Jerslev Sjælland", + "4591": "Føllenslev", + "4592": "Sejerø", + "4593": "Eskebjerg", + "4100": "Ringsted", + "4174": "Jystrup Midtsj", + "4200": "Slagelse", + "4220": "Korsør", + "4230": "Skælskør", + "4241": "Vemmelev", + "4242": "Boeslunde", + "4243": "Rude", + "4244": "Agersø", + "4245": "Omø", + "4261": "Dalmose", + "4652": "Hårlev", + "4660": "Store Heddinge", + "4671": "Strøby", + "4672": "Klippinge", + "4673": "Rødvig Stevns", + "4173": "Fjenneslev", + "4180": "Sorø", + "4190": "Munke Bjergby", + "4291": "Ruds Vedby", + "4293": "Dianalund", + "4295": "Stenlille", + "4296": "Nyrup", + "4060": "Kirke Såby", + "4070": "Kirke Hyllinge", + "4320": "Lejre", + "4330": "Hvalsø", + "4895": "Errindlev", + "4900": "Nakskov", + "4912": "Harpelunde", + "4913": "Horslunde", + "4920": "Søllested", + "4930": "Maribo", + "4941": "Bandholm", + "4942": "Askø", + "4943": "Torrig L", + "4944": "Fejø", + "4945": "Femø", + "4951": "Nørreballe", + "4952": "Stokkemarke", + "4953": "Vesterborg", + "4960": "Holeby", + "4970": "Rødby", + "4983": "Dannemare", + "4160": "Herlufmagle", + "4171": "Glumsø", + "4250": "Fuglebjerg", + "4262": "Sandved", + "4684": "Holmegaard", + "4700": "Næstved", + "4733": "Tappernøje", + "4736": "Karrebæksminde", + "4800": "Nykøbing F", + "4840": "Nørre Alslev", + "4850": "Stubbekøbing", + "4862": "Guldborg", + "4863": "Eskilstrup", + "4871": "Horbelev", + "4872": "Idestrup", + "4873": "Væggerløse", + "4874": "Gedser", + "4880": "Nysted", + "4891": "Toreby L", + "4892": "Kettinge", + "4894": "Øster Ulslev", + "4990": "Sakskøbing", + "4720": "Præstø", + "4735": "Mern", + "4750": "Lundby", + "4760": "Vordingborg", + "4771": "Kalvehave", + "4772": "Langebæk", + "4773": "Stensved", + "4780": "Stege", + "4791": "Borre", + "4792": "Askeby", + "4793": "Bogø By", + "5463": "Harndrup", + "5464": "Brenderup Fyn", + "5466": "Asperup", + "5500": "Middelfart", + "5580": "Nørre Aaby", + "5591": "Gelsted", + "5592": "Ejby", + "5492": "Vissenbjerg", + "5560": "Aarup", + "5610": "Assens", + "5620": "Glamsbjerg", + "5631": "Ebberup", + "5683": "Haarby", + "5690": "Tommerup", + "5600": "Faaborg", + "5601": "Lyø", + "5602": "Avernakø", + "5603": "Bjørnø", + "5642": "Millinge", + "5672": "Broby", + "5750": "Ringe", + "5772": "Kværndrup", + "5792": "Årslev", + "5854": "Gislev", + "5856": "Ryslinge", + "5863": "Ferritslev Fyn", + "5290": "Marslev", + "5300": "Kerteminde", + "5330": "Munkebo", + "5350": "Rynkeby", + "5370": "Mesinge", + "5380": "Dalby", + "5390": "Martofte", + "5550": "Langeskov", + "5540": "Ullerslev", + "5800": "Nyborg", + "5853": "Ørbæk", + "5871": "Frørup", + "5000": "Odense C", + "5200": "Odense V", + "5210": "Odense NV", + "5220": "Odense SØ", + "5230": "Odense M", + "5240": "Odense NØ", + "5250": "Odense SV", + "5260": "Odense S", + "5270": "Odense N", + "5320": "Agedrup", + "5491": "Blommenslyst", + "5700": "Svendborg", + "5762": "Vester Skerninge", + "5771": "Stenstrup", + "5874": "Hesselager", + "5881": "Skårup Fyn", + "5882": "Vejstrup", + "5883": "Oure", + "5884": "Gudme", + "5892": "Gudbjerg Sydfyn", + "5400": "Bogense", + "5450": "Otterup", + "5462": "Morud", + "5471": "Søndersø", + "5474": "Veflinge", + "5485": "Skamby", + "5900": "Rudkøbing", + "5932": "Humble", + "5935": "Bagenkop", + "5943": "Strynø", + "5953": "Tranekær", + "5960": "Marstal", + "5965": "Birkholm", + "5970": "Ærøskøbing", + "5985": "Søby Ærø", + "6100": "Haderslev", + "6500": "Vojens", + "6510": "Gram", + "6541": "Bevtoft", + "6560": "Sommersted", + "6623": "Vorbasse", + "7190": "Billund", + "7200": "Grindsted", + "7250": "Hejnsvig", + "7260": "Sønder Omme", + "6300": "Gråsten", + "6310": "Broager", + "6320": "Egernsund", + "6400": "Sønderborg", + "6430": "Nordborg", + "6440": "Augustenborg", + "6470": "Sydals", + "6240": "Løgumkloster", + "6261": "Bredebro", + "6270": "Tønder", + "6280": "Højer", + "6520": "Toftlund", + "6534": "Agerskov", + "6535": "Branderup J", + "6780": "Skærbæk", + "6792": "Rømø", + "6690": "Gørding", + "6700": "Esbjerg", + "6705": "Esbjerg Ø", + "6710": "Esbjerg V", + "6715": "Esbjerg N", + "6731": "Tjæreborg", + "6740": "Bramming", + "6760": "Ribe", + "6771": "Gredstedbro", + "6720": "Fanø", + "6753": "Agerbæk", + "6800": "Varde", + "6818": "Årre", + "6823": "Ansager", + "6830": "Nørre Nebel", + "6840": "Oksbøl", + "6851": "Janderup Vestj", + "6852": "Billum", + "6853": "Vejers Strand", + "6854": "Henne", + "6855": "Outrup", + "6857": "Blåvand", + "6862": "Tistrup", + "6870": "Ølgod", + "6600": "Vejen", + "6621": "Gesten", + "6622": "Bække", + "6630": "Rødding", + "6650": "Brørup", + "6660": "Lintrup", + "6670": "Holsted", + "6682": "Hovborg", + "6683": "Føvling", + "6752": "Glejbjerg", + "6200": "Aabenraa", + "6210": "Barsø", + "6230": "Rødekro", + "6330": "Padborg", + "6340": "Kruså", + "6360": "Tinglev", + "6372": "Bylderup-Bov", + "6392": "Bolderslev", + "7000": "Fredericia", + "6000": "Kolding", + "6051": "Almind", + "6052": "Viuf", + "6064": "Jordrup", + "6070": "Christiansfeld", + "6091": "Bjert", + "6092": "Sønder Stenderup", + "6093": "Sjølund", + "6094": "Hejls", + "6580": "Vamdrup", + "6640": "Lunderskov", + "6040": "Egtved", + "7080": "Børkop", + "7100": "Vejle", + "7120": "Vejle Øst", + "7173": "Vonge", + "7182": "Bredsten", + "7183": "Randbøl", + "7184": "Vandel", + "7300": "Jelling", + "7321": "Gadbjerg", + "7323": "Give", + "9100": "Aalborg", + "8100": "Aarhus C", + "8245": "Risskov Ø", + "5100": "Odense C", + "6701": "Esbjerg", + "7007": "Fredericia", + "0900": "København C", + "0960": "Udland", + "0999": "København C", + "1001": "København K", + "1002": "København K", + "1003": "København K", + "1004": "København K", + "1005": "København K", + "1006": "København K", + "1007": "København K", + "1008": "København K", + "1009": "København K", + "1010": "København K", + "1011": "København K", + "1012": "København K", + "1013": "København K", + "1014": "København K", + "1015": "København K", + "1016": "København K", + "1017": "København K", + "1018": "København K", + "1019": "København K", + "1020": "København K", + "1021": "København K", + "1022": "København K", + "1023": "København K", + "1024": "København K", + "1025": "København K", + "1026": "København K", + "1092": "København K", + "1093": "København K", + "1095": "København K", + "1098": "København K", + "1140": "København K", + "1147": "København K", + "1148": "København K", + "1217": "København K", + "1240": "København K", + "1448": "København K", + "1500": "København V", + "1501": "København V", + "1502": "København V", + "1503": "København V", + "1504": "København V", + "1505": "København V", + "1506": "København V", + "1507": "København V", + "1508": "København V", + "1509": "København V", + "1510": "København V", + "1513": "Centraltastning", + "1592": "København V", + "1599": "København V", + "1630": "København V", + "1780": "København V", + "1785": "København V", + "1786": "København V", + "1787": "København V", + "1790": "København V", + "1835": "Frederiksberg C", + "0917": "Københavns Pakkecent", + "0800": "Høje Taastrup", + "1532": "København V", + "1533": "København V" +} diff --git a/wwwroot/styles.css b/wwwroot/styles.css new file mode 100644 index 0000000..f1e4999 --- /dev/null +++ b/wwwroot/styles.css @@ -0,0 +1,274 @@ +:root { + color-scheme: light; + --bg: #edf2ef; + --panel: #fbfcf7; + --text: #18221c; + --muted: #617066; + --line: #cad6ce; + --accent: #1d5b39; + --accent-dark: #16472d; + --danger: #8a1f11; + --success: #1f6a3c; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; + min-height: 100vh; + background: linear-gradient(135deg, rgba(29, 91, 57, 0.12), transparent 34%), var(--bg); + color: var(--text); + font-family: Arial, Helvetica, sans-serif; +} + +.shell { + width: min(100% - 32px, 920px); + margin: 0 auto; + padding: 36px 0; +} + +.shell.admin-shell { + width: calc(100% - 32px); + max-width: 1600px; +} + +.panel { + max-width: 560px; + margin: 0 auto; + padding: 28px; + background: var(--panel); + border: 1px solid var(--line); + border-radius: 8px; + box-shadow: 0 16px 50px rgba(24, 34, 28, 0.12); +} + +.panel.wide { + max-width: none; +} + +.eyebrow { + margin: 0 0 8px; + color: var(--accent); + font-size: 14px; + font-weight: 700; + letter-spacing: 0; + text-transform: uppercase; +} + +h1 { + margin: 0 0 12px; + font-size: 32px; + line-height: 1.15; +} + +.intro { + margin: 0 0 24px; + color: var(--muted); + font-size: 16px; + line-height: 1.5; +} + +.form { + display: grid; + gap: 16px; +} + +.address-grid { + display: grid; + grid-template-columns: minmax(120px, 0.6fr) minmax(180px, 1fr); + gap: 16px; +} + +label { + display: grid; + gap: 7px; + color: var(--text); + font-size: 15px; + font-weight: 700; +} + +input { + width: 100%; + border: 1px solid var(--line); + border-radius: 6px; + padding: 12px; + color: var(--text); + background: #fff; + font: inherit; +} + +input:focus { + border-color: var(--accent); + box-shadow: 0 0 0 3px rgba(29, 91, 57, 0.16); + outline: none; +} + +button { + margin-top: 8px; + border: 0; + border-radius: 6px; + padding: 13px 18px; + color: #fff; + background: var(--accent); + font: inherit; + font-weight: 700; + cursor: pointer; +} + +button:hover { + background: var(--accent-dark); +} + +button:disabled { + cursor: wait; + opacity: 0.72; +} + +.notice { + margin: 0 0 18px; + border-radius: 6px; + padding: 12px 14px; + font-size: 15px; + line-height: 1.45; +} + +.notice.error { + color: var(--danger); + background: #fff2ef; + border: 1px solid #efc5bd; +} + +.notice.success { + color: var(--success); + background: #edf8f0; + border: 1px solid #bfddc8; +} + +.toolbar { + display: flex; + align-items: start; + justify-content: space-between; + gap: 20px; + margin-bottom: 20px; +} + +.count { + white-space: nowrap; + border: 1px solid var(--line); + border-radius: 999px; + padding: 8px 12px; + color: var(--accent); + background: #fff; + font-size: 14px; + font-weight: 700; +} + +.table-wrap { + overflow-x: auto; + border: 1px solid var(--line); + border-radius: 8px; + background: #fff; +} + +table { + width: 100%; + border-collapse: collapse; + min-width: 920px; +} + +th, +td { + padding: 12px 14px; + border-bottom: 1px solid var(--line); + text-align: left; + vertical-align: top; + font-size: 14px; + line-height: 1.4; +} + +th { + color: var(--muted); + background: #f5f8f6; + font-weight: 700; +} + +tr:last-child td { + border-bottom: 0; +} + +a { + color: var(--accent); +} + +.empty { + color: var(--muted); + text-align: center; +} + +.admin-actions { + display: flex; + flex-wrap: wrap; + gap: 12px; + margin-bottom: 20px; +} + +.participant-map { margin: 0 0 24px; } +.participant-map h2 { margin: 0 0 8px; font-size: 22px; } +.participant-map p { color: var(--muted); font-size: 14px; } +#participant-map { height: 380px; border: 1px solid var(--line); border-radius: 8px; z-index: 0; } + +.delete-button { + margin: 0; + padding: 8px 12px; + background: var(--danger); +} + +.delete-button:hover { + background: #69170d; +} + +@media print { + @page { size: A4 landscape; margin: 12mm; } + body { min-height: 0; background: #fff; color: #000; } + .shell { width: 100%; margin: 0; padding: 0; } + .shell.admin-shell { width: 100%; max-width: none; } + .panel { padding: 0; border: 0; box-shadow: none; } + .no-print, .notice { display: none !important; } + .table-wrap { overflow: visible; border: 0; } + table { min-width: 0; width: 100%; table-layout: fixed; } + th, td { padding: 6px; font-size: 10px; overflow-wrap: anywhere; } + thead { display: table-header-group; } + tr { break-inside: avoid; } + a { color: #000; text-decoration: none; } + .count { color: #000; } +} + +@media (max-width: 620px) { + .shell { + width: min(100% - 20px, 920px); + padding: 16px 0; + } + + .panel { + padding: 20px; + } + + h1 { + font-size: 28px; + } + + .toolbar { + display: block; + } + + .count { + display: inline-block; + margin-top: 6px; + } + + .address-grid { + grid-template-columns: 1fr; + } +} diff --git a/wwwroot/vendor/leaflet/LICENSE b/wwwroot/vendor/leaflet/LICENSE new file mode 100644 index 0000000..7b41f20 --- /dev/null +++ b/wwwroot/vendor/leaflet/LICENSE @@ -0,0 +1,26 @@ +BSD 2-Clause License + +Copyright (c) 2010-2023, Volodymyr Agafonkin +Copyright (c) 2010-2011, CloudMade +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/wwwroot/vendor/leaflet/leaflet.css b/wwwroot/vendor/leaflet/leaflet.css new file mode 100644 index 0000000..9ade8dc --- /dev/null +++ b/wwwroot/vendor/leaflet/leaflet.css @@ -0,0 +1,661 @@ +/* required styles */ + +.leaflet-pane, +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-tile-container, +.leaflet-pane > svg, +.leaflet-pane > canvas, +.leaflet-zoom-box, +.leaflet-image-layer, +.leaflet-layer { + position: absolute; + left: 0; + top: 0; + } +.leaflet-container { + overflow: hidden; + } +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + -webkit-user-drag: none; + } +/* Prevents IE11 from highlighting tiles in blue */ +.leaflet-tile::selection { + background: transparent; +} +/* Safari renders non-retina tile on retina better with this, but Chrome is worse */ +.leaflet-safari .leaflet-tile { + image-rendering: -webkit-optimize-contrast; + } +/* hack that prevents hw layers "stretching" when loading new tiles */ +.leaflet-safari .leaflet-tile-container { + width: 1600px; + height: 1600px; + -webkit-transform-origin: 0 0; + } +.leaflet-marker-icon, +.leaflet-marker-shadow { + display: block; + } +/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */ +/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */ +.leaflet-container .leaflet-overlay-pane svg { + max-width: none !important; + max-height: none !important; + } +.leaflet-container .leaflet-marker-pane img, +.leaflet-container .leaflet-shadow-pane img, +.leaflet-container .leaflet-tile-pane img, +.leaflet-container img.leaflet-image-layer, +.leaflet-container .leaflet-tile { + max-width: none !important; + max-height: none !important; + width: auto; + padding: 0; + } + +.leaflet-container img.leaflet-tile { + /* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */ + mix-blend-mode: plus-lighter; +} + +.leaflet-container.leaflet-touch-zoom { + -ms-touch-action: pan-x pan-y; + touch-action: pan-x pan-y; + } +.leaflet-container.leaflet-touch-drag { + -ms-touch-action: pinch-zoom; + /* Fallback for FF which doesn't support pinch-zoom */ + touch-action: none; + touch-action: pinch-zoom; +} +.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom { + -ms-touch-action: none; + touch-action: none; +} +.leaflet-container { + -webkit-tap-highlight-color: transparent; +} +.leaflet-container a { + -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4); +} +.leaflet-tile { + filter: inherit; + visibility: hidden; + } +.leaflet-tile-loaded { + visibility: inherit; + } +.leaflet-zoom-box { + width: 0; + height: 0; + -moz-box-sizing: border-box; + box-sizing: border-box; + z-index: 800; + } +/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */ +.leaflet-overlay-pane svg { + -moz-user-select: none; + } + +.leaflet-pane { z-index: 400; } + +.leaflet-tile-pane { z-index: 200; } +.leaflet-overlay-pane { z-index: 400; } +.leaflet-shadow-pane { z-index: 500; } +.leaflet-marker-pane { z-index: 600; } +.leaflet-tooltip-pane { z-index: 650; } +.leaflet-popup-pane { z-index: 700; } + +.leaflet-map-pane canvas { z-index: 100; } +.leaflet-map-pane svg { z-index: 200; } + +.leaflet-vml-shape { + width: 1px; + height: 1px; + } +.lvml { + behavior: url(#default#VML); + display: inline-block; + position: absolute; + } + + +/* control positioning */ + +.leaflet-control { + position: relative; + z-index: 800; + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; + } +.leaflet-top, +.leaflet-bottom { + position: absolute; + z-index: 1000; + pointer-events: none; + } +.leaflet-top { + top: 0; + } +.leaflet-right { + right: 0; + } +.leaflet-bottom { + bottom: 0; + } +.leaflet-left { + left: 0; + } +.leaflet-control { + float: left; + clear: both; + } +.leaflet-right .leaflet-control { + float: right; + } +.leaflet-top .leaflet-control { + margin-top: 10px; + } +.leaflet-bottom .leaflet-control { + margin-bottom: 10px; + } +.leaflet-left .leaflet-control { + margin-left: 10px; + } +.leaflet-right .leaflet-control { + margin-right: 10px; + } + + +/* zoom and fade animations */ + +.leaflet-fade-anim .leaflet-popup { + opacity: 0; + -webkit-transition: opacity 0.2s linear; + -moz-transition: opacity 0.2s linear; + transition: opacity 0.2s linear; + } +.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { + opacity: 1; + } +.leaflet-zoom-animated { + -webkit-transform-origin: 0 0; + -ms-transform-origin: 0 0; + transform-origin: 0 0; + } +svg.leaflet-zoom-animated { + will-change: transform; +} + +.leaflet-zoom-anim .leaflet-zoom-animated { + -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); + -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); + transition: transform 0.25s cubic-bezier(0,0,0.25,1); + } +.leaflet-zoom-anim .leaflet-tile, +.leaflet-pan-anim .leaflet-tile { + -webkit-transition: none; + -moz-transition: none; + transition: none; + } + +.leaflet-zoom-anim .leaflet-zoom-hide { + visibility: hidden; + } + + +/* cursors */ + +.leaflet-interactive { + cursor: pointer; + } +.leaflet-grab { + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab; + } +.leaflet-crosshair, +.leaflet-crosshair .leaflet-interactive { + cursor: crosshair; + } +.leaflet-popup-pane, +.leaflet-control { + cursor: auto; + } +.leaflet-dragging .leaflet-grab, +.leaflet-dragging .leaflet-grab .leaflet-interactive, +.leaflet-dragging .leaflet-marker-draggable { + cursor: move; + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + cursor: grabbing; + } + +/* marker & overlays interactivity */ +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-image-layer, +.leaflet-pane > svg path, +.leaflet-tile-container { + pointer-events: none; + } + +.leaflet-marker-icon.leaflet-interactive, +.leaflet-image-layer.leaflet-interactive, +.leaflet-pane > svg path.leaflet-interactive, +svg.leaflet-image-layer.leaflet-interactive path { + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; + } + +/* visual tweaks */ + +.leaflet-container { + background: #ddd; + outline-offset: 1px; + } +.leaflet-container a { + color: #0078A8; + } +.leaflet-zoom-box { + border: 2px dotted #38f; + background: rgba(255,255,255,0.5); + } + + +/* general typography */ +.leaflet-container { + font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; + font-size: 12px; + font-size: 0.75rem; + line-height: 1.5; + } + + +/* general toolbar styles */ + +.leaflet-bar { + box-shadow: 0 1px 5px rgba(0,0,0,0.65); + border-radius: 4px; + } +.leaflet-bar a { + background-color: #fff; + border-bottom: 1px solid #ccc; + width: 26px; + height: 26px; + line-height: 26px; + display: block; + text-align: center; + text-decoration: none; + color: black; + } +.leaflet-bar a, +.leaflet-control-layers-toggle { + background-position: 50% 50%; + background-repeat: no-repeat; + display: block; + } +.leaflet-bar a:hover, +.leaflet-bar a:focus { + background-color: #f4f4f4; + } +.leaflet-bar a:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; + } +.leaflet-bar a:last-child { + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom: none; + } +.leaflet-bar a.leaflet-disabled { + cursor: default; + background-color: #f4f4f4; + color: #bbb; + } + +.leaflet-touch .leaflet-bar a { + width: 30px; + height: 30px; + line-height: 30px; + } +.leaflet-touch .leaflet-bar a:first-child { + border-top-left-radius: 2px; + border-top-right-radius: 2px; + } +.leaflet-touch .leaflet-bar a:last-child { + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; + } + +/* zoom control */ + +.leaflet-control-zoom-in, +.leaflet-control-zoom-out { + font: bold 18px 'Lucida Console', Monaco, monospace; + text-indent: 1px; + } + +.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out { + font-size: 22px; + } + + +/* layers control */ + +.leaflet-control-layers { + box-shadow: 0 1px 5px rgba(0,0,0,0.4); + background: #fff; + border-radius: 5px; + } +.leaflet-control-layers-toggle { + background-image: url(images/layers.png); + width: 36px; + height: 36px; + } +.leaflet-retina .leaflet-control-layers-toggle { + background-image: url(images/layers-2x.png); + background-size: 26px 26px; + } +.leaflet-touch .leaflet-control-layers-toggle { + width: 44px; + height: 44px; + } +.leaflet-control-layers .leaflet-control-layers-list, +.leaflet-control-layers-expanded .leaflet-control-layers-toggle { + display: none; + } +.leaflet-control-layers-expanded .leaflet-control-layers-list { + display: block; + position: relative; + } +.leaflet-control-layers-expanded { + padding: 6px 10px 6px 6px; + color: #333; + background: #fff; + } +.leaflet-control-layers-scrollbar { + overflow-y: scroll; + overflow-x: hidden; + padding-right: 5px; + } +.leaflet-control-layers-selector { + margin-top: 2px; + position: relative; + top: 1px; + } +.leaflet-control-layers label { + display: block; + font-size: 13px; + font-size: 1.08333em; + } +.leaflet-control-layers-separator { + height: 0; + border-top: 1px solid #ddd; + margin: 5px -10px 5px -6px; + } + +/* Default icon URLs */ +.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */ + background-image: url(images/marker-icon.png); + } + + +/* attribution and scale controls */ + +.leaflet-container .leaflet-control-attribution { + background: #fff; + background: rgba(255, 255, 255, 0.8); + margin: 0; + } +.leaflet-control-attribution, +.leaflet-control-scale-line { + padding: 0 5px; + color: #333; + line-height: 1.4; + } +.leaflet-control-attribution a { + text-decoration: none; + } +.leaflet-control-attribution a:hover, +.leaflet-control-attribution a:focus { + text-decoration: underline; + } +.leaflet-attribution-flag { + display: inline !important; + vertical-align: baseline !important; + width: 1em; + height: 0.6669em; + } +.leaflet-left .leaflet-control-scale { + margin-left: 5px; + } +.leaflet-bottom .leaflet-control-scale { + margin-bottom: 5px; + } +.leaflet-control-scale-line { + border: 2px solid #777; + border-top: none; + line-height: 1.1; + padding: 2px 5px 1px; + white-space: nowrap; + -moz-box-sizing: border-box; + box-sizing: border-box; + background: rgba(255, 255, 255, 0.8); + text-shadow: 1px 1px #fff; + } +.leaflet-control-scale-line:not(:first-child) { + border-top: 2px solid #777; + border-bottom: none; + margin-top: -2px; + } +.leaflet-control-scale-line:not(:first-child):not(:last-child) { + border-bottom: 2px solid #777; + } + +.leaflet-touch .leaflet-control-attribution, +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + box-shadow: none; + } +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + border: 2px solid rgba(0,0,0,0.2); + background-clip: padding-box; + } + + +/* popup */ + +.leaflet-popup { + position: absolute; + text-align: center; + margin-bottom: 20px; + } +.leaflet-popup-content-wrapper { + padding: 1px; + text-align: left; + border-radius: 12px; + } +.leaflet-popup-content { + margin: 13px 24px 13px 20px; + line-height: 1.3; + font-size: 13px; + font-size: 1.08333em; + min-height: 1px; + } +.leaflet-popup-content p { + margin: 17px 0; + margin: 1.3em 0; + } +.leaflet-popup-tip-container { + width: 40px; + height: 20px; + position: absolute; + left: 50%; + margin-top: -1px; + margin-left: -20px; + overflow: hidden; + pointer-events: none; + } +.leaflet-popup-tip { + width: 17px; + height: 17px; + padding: 1px; + + margin: -10px auto 0; + pointer-events: auto; + + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); + } +.leaflet-popup-content-wrapper, +.leaflet-popup-tip { + background: white; + color: #333; + box-shadow: 0 3px 14px rgba(0,0,0,0.4); + } +.leaflet-container a.leaflet-popup-close-button { + position: absolute; + top: 0; + right: 0; + border: none; + text-align: center; + width: 24px; + height: 24px; + font: 16px/24px Tahoma, Verdana, sans-serif; + color: #757575; + text-decoration: none; + background: transparent; + } +.leaflet-container a.leaflet-popup-close-button:hover, +.leaflet-container a.leaflet-popup-close-button:focus { + color: #585858; + } +.leaflet-popup-scrolled { + overflow: auto; + } + +.leaflet-oldie .leaflet-popup-content-wrapper { + -ms-zoom: 1; + } +.leaflet-oldie .leaflet-popup-tip { + width: 24px; + margin: 0 auto; + + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; + filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); + } + +.leaflet-oldie .leaflet-control-zoom, +.leaflet-oldie .leaflet-control-layers, +.leaflet-oldie .leaflet-popup-content-wrapper, +.leaflet-oldie .leaflet-popup-tip { + border: 1px solid #999; + } + + +/* div icon */ + +.leaflet-div-icon { + background: #fff; + border: 1px solid #666; + } + + +/* Tooltip */ +/* Base styles for the element that has a tooltip */ +.leaflet-tooltip { + position: absolute; + padding: 6px; + background-color: #fff; + border: 1px solid #fff; + border-radius: 3px; + color: #222; + white-space: nowrap; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + pointer-events: none; + box-shadow: 0 1px 3px rgba(0,0,0,0.4); + } +.leaflet-tooltip.leaflet-interactive { + cursor: pointer; + pointer-events: auto; + } +.leaflet-tooltip-top:before, +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + position: absolute; + pointer-events: none; + border: 6px solid transparent; + background: transparent; + content: ""; + } + +/* Directions */ + +.leaflet-tooltip-bottom { + margin-top: 6px; +} +.leaflet-tooltip-top { + margin-top: -6px; +} +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-top:before { + left: 50%; + margin-left: -6px; + } +.leaflet-tooltip-top:before { + bottom: 0; + margin-bottom: -12px; + border-top-color: #fff; + } +.leaflet-tooltip-bottom:before { + top: 0; + margin-top: -12px; + margin-left: -6px; + border-bottom-color: #fff; + } +.leaflet-tooltip-left { + margin-left: -6px; +} +.leaflet-tooltip-right { + margin-left: 6px; +} +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + top: 50%; + margin-top: -6px; + } +.leaflet-tooltip-left:before { + right: 0; + margin-right: -12px; + border-left-color: #fff; + } +.leaflet-tooltip-right:before { + left: 0; + margin-left: -12px; + border-right-color: #fff; + } + +/* Printing */ + +@media print { + /* Prevent printers from removing background-images of controls. */ + .leaflet-control { + -webkit-print-color-adjust: exact; + print-color-adjust: exact; + } + } diff --git a/wwwroot/vendor/leaflet/leaflet.js b/wwwroot/vendor/leaflet/leaflet.js new file mode 100644 index 0000000..a3bf693 --- /dev/null +++ b/wwwroot/vendor/leaflet/leaflet.js @@ -0,0 +1,6 @@ +/* @preserve + * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com + * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).leaflet={})}(this,function(t){"use strict";function l(t){for(var e,i,n=1,o=arguments.length;n=this.min.x&&i.x<=this.max.x&&e.y>=this.min.y&&i.y<=this.max.y},intersects:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>=e.x&&n.x<=i.x,t=t.y>=e.y&&n.y<=i.y;return o&&t},overlaps:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>e.x&&n.xe.y&&n.y=n.lat&&i.lat<=o.lat&&e.lng>=n.lng&&i.lng<=o.lng},intersects:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>=e.lat&&n.lat<=i.lat,t=t.lng>=e.lng&&n.lng<=i.lng;return o&&t},overlaps:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>e.lat&&n.late.lng&&n.lng","http://www.w3.org/2000/svg"===(Wt.firstChild&&Wt.firstChild.namespaceURI));function y(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var b={ie:pt,ielt9:mt,edge:n,webkit:ft,android:gt,android23:vt,androidStock:yt,opera:xt,chrome:wt,gecko:bt,safari:Pt,phantom:Lt,opera12:o,win:Tt,ie3d:Mt,webkit3d:zt,gecko3d:_t,any3d:Ct,mobile:Zt,mobileWebkit:St,mobileWebkit3d:Et,msPointer:kt,pointer:Ot,touch:Bt,touchNative:At,mobileOpera:It,mobileGecko:Rt,retina:Nt,passiveEvents:Dt,canvas:jt,svg:Ht,vml:!Ht&&function(){try{var t=document.createElement("div"),e=(t.innerHTML='',t.firstChild);return e.style.behavior="url(#default#VML)",e&&"object"==typeof e.adj}catch(t){return!1}}(),inlineSvg:Wt,mac:0===navigator.platform.indexOf("Mac"),linux:0===navigator.platform.indexOf("Linux")},Ft=b.msPointer?"MSPointerDown":"pointerdown",Ut=b.msPointer?"MSPointerMove":"pointermove",Vt=b.msPointer?"MSPointerUp":"pointerup",qt=b.msPointer?"MSPointerCancel":"pointercancel",Gt={touchstart:Ft,touchmove:Ut,touchend:Vt,touchcancel:qt},Kt={touchstart:function(t,e){e.MSPOINTER_TYPE_TOUCH&&e.pointerType===e.MSPOINTER_TYPE_TOUCH&&O(e);ee(t,e)},touchmove:ee,touchend:ee,touchcancel:ee},Yt={},Xt=!1;function Jt(t,e,i){return"touchstart"!==e||Xt||(document.addEventListener(Ft,$t,!0),document.addEventListener(Ut,Qt,!0),document.addEventListener(Vt,te,!0),document.addEventListener(qt,te,!0),Xt=!0),Kt[e]?(i=Kt[e].bind(this,i),t.addEventListener(Gt[e],i,!1),i):(console.warn("wrong event specified:",e),u)}function $t(t){Yt[t.pointerId]=t}function Qt(t){Yt[t.pointerId]&&(Yt[t.pointerId]=t)}function te(t){delete Yt[t.pointerId]}function ee(t,e){if(e.pointerType!==(e.MSPOINTER_TYPE_MOUSE||"mouse")){for(var i in e.touches=[],Yt)e.touches.push(Yt[i]);e.changedTouches=[e],t(e)}}var ie=200;function ne(t,i){t.addEventListener("dblclick",i);var n,o=0;function e(t){var e;1!==t.detail?n=t.detail:"mouse"===t.pointerType||t.sourceCapabilities&&!t.sourceCapabilities.firesTouchEvents||((e=Ne(t)).some(function(t){return t instanceof HTMLLabelElement&&t.attributes.for})&&!e.some(function(t){return t instanceof HTMLInputElement||t instanceof HTMLSelectElement})||((e=Date.now())-o<=ie?2===++n&&i(function(t){var e,i,n={};for(i in t)e=t[i],n[i]=e&&e.bind?e.bind(t):e;return(t=n).type="dblclick",n.detail=2,n.isTrusted=!1,n._simulated=!0,n}(t)):n=1,o=e))}return t.addEventListener("click",e),{dblclick:i,simDblclick:e}}var oe,se,re,ae,he,le,ue=we(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),ce=we(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),de="webkitTransition"===ce||"OTransition"===ce?ce+"End":"transitionend";function _e(t){return"string"==typeof t?document.getElementById(t):t}function pe(t,e){var i=t.style[e]||t.currentStyle&&t.currentStyle[e];return"auto"===(i=i&&"auto"!==i||!document.defaultView?i:(t=document.defaultView.getComputedStyle(t,null))?t[e]:null)?null:i}function P(t,e,i){t=document.createElement(t);return t.className=e||"",i&&i.appendChild(t),t}function T(t){var e=t.parentNode;e&&e.removeChild(t)}function me(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function fe(t){var e=t.parentNode;e&&e.lastChild!==t&&e.appendChild(t)}function ge(t){var e=t.parentNode;e&&e.firstChild!==t&&e.insertBefore(t,e.firstChild)}function ve(t,e){return void 0!==t.classList?t.classList.contains(e):0<(t=xe(t)).length&&new RegExp("(^|\\s)"+e+"(\\s|$)").test(t)}function M(t,e){var i;if(void 0!==t.classList)for(var n=F(e),o=0,s=n.length;othis.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,e){this._enforcingBounds=!0;var i=this.getCenter(),t=this._limitCenter(i,this._zoom,g(t));return i.equals(t)||this.panTo(t,e),this._enforcingBounds=!1,this},panInside:function(t,e){var i=m((e=e||{}).paddingTopLeft||e.padding||[0,0]),n=m(e.paddingBottomRight||e.padding||[0,0]),o=this.project(this.getCenter()),t=this.project(t),s=this.getPixelBounds(),i=_([s.min.add(i),s.max.subtract(n)]),s=i.getSize();return i.contains(t)||(this._enforcingBounds=!0,n=t.subtract(i.getCenter()),i=i.extend(t).getSize().subtract(s),o.x+=n.x<0?-i.x:i.x,o.y+=n.y<0?-i.y:i.y,this.panTo(this.unproject(o),e),this._enforcingBounds=!1),this},invalidateSize:function(t){if(!this._loaded)return this;t=l({animate:!1,pan:!0},!0===t?{animate:!0}:t);var e=this.getSize(),i=(this._sizeChanged=!0,this._lastCenter=null,this.getSize()),n=e.divideBy(2).round(),o=i.divideBy(2).round(),n=n.subtract(o);return n.x||n.y?(t.animate&&t.pan?this.panBy(n):(t.pan&&this._rawPanBy(n),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(a(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:e,newSize:i})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire("viewreset"),this._stop()},locate:function(t){var e,i;return t=this._locateOptions=l({timeout:1e4,watch:!1},t),"geolocation"in navigator?(e=a(this._handleGeolocationResponse,this),i=a(this._handleGeolocationError,this),t.watch?this._locationWatchId=navigator.geolocation.watchPosition(e,i,t):navigator.geolocation.getCurrentPosition(e,i,t)):this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var e;this._container._leaflet_id&&(e=t.code,t=t.message||(1===e?"permission denied":2===e?"position unavailable":"timeout"),this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:e,message:"Geolocation error: "+t+"."}))},_handleGeolocationResponse:function(t){if(this._container._leaflet_id){var e,i,n=new v(t.coords.latitude,t.coords.longitude),o=n.toBounds(2*t.coords.accuracy),s=this._locateOptions,r=(s.setView&&(e=this.getBoundsZoom(o),this.setView(n,s.maxZoom?Math.min(e,s.maxZoom):e)),{latlng:n,bounds:o,timestamp:t.timestamp});for(i in t.coords)"number"==typeof t.coords[i]&&(r[i]=t.coords[i]);this.fire("locationfound",r)}},addHandler:function(t,e){return e&&(e=this[t]=new e(this),this._handlers.push(e),this.options[t]&&e.enable()),this},remove:function(){if(this._initEvents(!0),this.options.maxBounds&&this.off("moveend",this._panInsideMaxBounds),this._containerId!==this._container._leaflet_id)throw new Error("Map container is being reused by another instance");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=void 0,this._containerId=void 0}for(var t in void 0!==this._locationWatchId&&this.stopLocate(),this._stop(),T(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._resizeRequest&&(r(this._resizeRequest),this._resizeRequest=null),this._clearHandlers(),this._loaded&&this.fire("unload"),this._layers)this._layers[t].remove();for(t in this._panes)T(this._panes[t]);return this._layers=[],this._panes=[],delete this._mapPane,delete this._renderer,this},createPane:function(t,e){e=P("div","leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),e||this._mapPane);return t&&(this._panes[t]=e),e},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter.clone():this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds();return new s(this.unproject(t.getBottomLeft()),this.unproject(t.getTopRight()))},getMinZoom:function(){return void 0===this.options.minZoom?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return void 0===this.options.maxZoom?void 0===this._layersMaxZoom?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,e,i){t=g(t),i=m(i||[0,0]);var n=this.getZoom()||0,o=this.getMinZoom(),s=this.getMaxZoom(),r=t.getNorthWest(),t=t.getSouthEast(),i=this.getSize().subtract(i),t=_(this.project(t,n),this.project(r,n)).getSize(),r=b.any3d?this.options.zoomSnap:1,a=i.x/t.x,i=i.y/t.y,t=e?Math.max(a,i):Math.min(a,i),n=this.getScaleZoom(t,n);return r&&(n=Math.round(n/(r/100))*(r/100),n=e?Math.ceil(n/r)*r:Math.floor(n/r)*r),Math.max(o,Math.min(s,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new p(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,e){t=this._getTopLeftPoint(t,e);return new f(t,t.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(void 0===t?this.getZoom():t)},getPane:function(t){return"string"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,e){var i=this.options.crs;return e=void 0===e?this._zoom:e,i.scale(t)/i.scale(e)},getScaleZoom:function(t,e){var i=this.options.crs,t=(e=void 0===e?this._zoom:e,i.zoom(t*i.scale(e)));return isNaN(t)?1/0:t},project:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.latLngToPoint(w(t),e)},unproject:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.pointToLatLng(m(t),e)},layerPointToLatLng:function(t){t=m(t).add(this.getPixelOrigin());return this.unproject(t)},latLngToLayerPoint:function(t){return this.project(w(t))._round()._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(w(t))},wrapLatLngBounds:function(t){return this.options.crs.wrapLatLngBounds(g(t))},distance:function(t,e){return this.options.crs.distance(w(t),w(e))},containerPointToLayerPoint:function(t){return m(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return m(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){t=this.containerPointToLayerPoint(m(t));return this.layerPointToLatLng(t)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(w(t)))},mouseEventToContainerPoint:function(t){return De(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){t=this._container=_e(t);if(!t)throw new Error("Map container not found.");if(t._leaflet_id)throw new Error("Map container is already initialized.");S(t,"scroll",this._onScroll,this),this._containerId=h(t)},_initLayout:function(){var t=this._container,e=(this._fadeAnimated=this.options.fadeAnimation&&b.any3d,M(t,"leaflet-container"+(b.touch?" leaflet-touch":"")+(b.retina?" leaflet-retina":"")+(b.ielt9?" leaflet-oldie":"")+(b.safari?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":"")),pe(t,"position"));"absolute"!==e&&"relative"!==e&&"fixed"!==e&&"sticky"!==e&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),Z(this._mapPane,new p(0,0)),this.createPane("tilePane"),this.createPane("overlayPane"),this.createPane("shadowPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(M(t.markerPane,"leaflet-zoom-hide"),M(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,e,i){Z(this._mapPane,new p(0,0));var n=!this._loaded,o=(this._loaded=!0,e=this._limitZoom(e),this.fire("viewprereset"),this._zoom!==e);this._moveStart(o,i)._move(t,e)._moveEnd(o),this.fire("viewreset"),n&&this.fire("load")},_moveStart:function(t,e){return t&&this.fire("zoomstart"),e||this.fire("movestart"),this},_move:function(t,e,i,n){void 0===e&&(e=this._zoom);var o=this._zoom!==e;return this._zoom=e,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),n?i&&i.pinch&&this.fire("zoom",i):((o||i&&i.pinch)&&this.fire("zoom",i),this.fire("move",i)),this},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return r(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){Z(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(t){this._targets={};var e=t?k:S;e((this._targets[h(this._container)]=this)._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress keydown keyup",this._handleDOMEvent,this),this.options.trackResize&&e(window,"resize",this._onResize,this),b.any3d&&this.options.transform3DLimit&&(t?this.off:this.on).call(this,"moveend",this._onMoveEnd)},_onResize:function(){r(this._resizeRequest),this._resizeRequest=x(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,e){for(var i,n=[],o="mouseout"===e||"mouseover"===e,s=t.target||t.srcElement,r=!1;s;){if((i=this._targets[h(s)])&&("click"===e||"preclick"===e)&&this._draggableMoved(i)){r=!0;break}if(i&&i.listens(e,!0)){if(o&&!We(s,t))break;if(n.push(i),o)break}if(s===this._container)break;s=s.parentNode}return n=n.length||r||o||!this.listens(e,!0)?n:[this]},_isClickDisabled:function(t){for(;t&&t!==this._container;){if(t._leaflet_disable_click)return!0;t=t.parentNode}},_handleDOMEvent:function(t){var e,i=t.target||t.srcElement;!this._loaded||i._leaflet_disable_events||"click"===t.type&&this._isClickDisabled(i)||("mousedown"===(e=t.type)&&Me(i),this._fireDOMEvent(t,e))},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,e,i){"click"===t.type&&((a=l({},t)).type="preclick",this._fireDOMEvent(a,a.type,i));var n=this._findEventTargets(t,e);if(i){for(var o=[],s=0;sthis.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),n=this._getCenterOffset(t)._divideBy(1-1/n);if(!0!==i.animate&&!this.getSize().contains(n))return!1;x(function(){this._moveStart(!0,i.noMoveStart||!1)._animateZoom(t,e,!0)},this)}return!0},_animateZoom:function(t,e,i,n){this._mapPane&&(i&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=e,M(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:e,noUpdate:n}),this._tempFireZoomEvent||(this._tempFireZoomEvent=this._zoom!==this._animateToZoom),this._move(this._animateToCenter,this._animateToZoom,void 0,!0),setTimeout(a(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&z(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom,void 0,!0),this._tempFireZoomEvent&&this.fire("zoom"),delete this._tempFireZoomEvent,this.fire("move"),this._moveEnd(!0))}});function Ue(t){return new B(t)}var B=et.extend({options:{position:"topright"},initialize:function(t){c(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var e=this._map;return e&&e.removeControl(this),this.options.position=t,e&&e.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var e=this._container=this.onAdd(t),i=this.getPosition(),t=t._controlCorners[i];return M(e,"leaflet-control"),-1!==i.indexOf("bottom")?t.insertBefore(e,t.firstChild):t.appendChild(e),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(T(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0",e=document.createElement("div");return e.innerHTML=t,e.firstChild},_addItem:function(t){var e,i=document.createElement("label"),n=this._map.hasLayer(t.layer),n=(t.overlay?((e=document.createElement("input")).type="checkbox",e.className="leaflet-control-layers-selector",e.defaultChecked=n):e=this._createRadioElement("leaflet-base-layers_"+h(this),n),this._layerControlInputs.push(e),e.layerId=h(t.layer),S(e,"click",this._onInputClick,this),document.createElement("span")),o=(n.innerHTML=" "+t.name,document.createElement("span"));return i.appendChild(o),o.appendChild(e),o.appendChild(n),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(i),this._checkDisabledLayers(),i},_onInputClick:function(){if(!this._preventClick){var t,e,i=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=i.length-1;0<=s;s--)t=i[s],e=this._getLayer(t.layerId).layer,t.checked?n.push(e):t.checked||o.push(e);for(s=0;se.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expandSafely:function(){var t=this._section,e=(this._preventClick=!0,S(t,"click",O),this.expand(),this);setTimeout(function(){k(t,"click",O),e._preventClick=!1})}})),qe=B.extend({options:{position:"topleft",zoomInText:'',zoomInTitle:"Zoom in",zoomOutText:'',zoomOutTitle:"Zoom out"},onAdd:function(t){var e="leaflet-control-zoom",i=P("div",e+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,e+"-in",i,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,e+"-out",i,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),i},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,e,i,n,o){i=P("a",i,n);return i.innerHTML=t,i.href="#",i.title=e,i.setAttribute("role","button"),i.setAttribute("aria-label",e),Ie(i),S(i,"click",Re),S(i,"click",o,this),S(i,"click",this._refocusOnMap,this),i},_updateDisabled:function(){var t=this._map,e="leaflet-disabled";z(this._zoomInButton,e),z(this._zoomOutButton,e),this._zoomInButton.setAttribute("aria-disabled","false"),this._zoomOutButton.setAttribute("aria-disabled","false"),!this._disabled&&t._zoom!==t.getMinZoom()||(M(this._zoomOutButton,e),this._zoomOutButton.setAttribute("aria-disabled","true")),!this._disabled&&t._zoom!==t.getMaxZoom()||(M(this._zoomInButton,e),this._zoomInButton.setAttribute("aria-disabled","true"))}}),Ge=(A.mergeOptions({zoomControl:!0}),A.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new qe,this.addControl(this.zoomControl))}),B.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var e="leaflet-control-scale",i=P("div",e),n=this.options;return this._addScales(n,e+"-line",i),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,e,i){t.metric&&(this._mScale=P("div",e,i)),t.imperial&&(this._iScale=P("div",e,i))},_update:function(){var t=this._map,e=t.getSize().y/2,t=t.distance(t.containerPointToLatLng([0,e]),t.containerPointToLatLng([this.options.maxWidth,e]));this._updateScales(t)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var e=this._getRoundNum(t);this._updateScale(this._mScale,e<1e3?e+" m":e/1e3+" km",e/t)},_updateImperial:function(t){var e,i,t=3.2808399*t;5280'+(b.inlineSvg?' ':"")+"Leaflet"},initialize:function(t){c(this,t),this._attributions={}},onAdd:function(t){for(var e in(t.attributionControl=this)._container=P("div","leaflet-control-attribution"),Ie(this._container),t._layers)t._layers[e].getAttribution&&this.addAttribution(t._layers[e].getAttribution());return this._update(),t.on("layeradd",this._addAttribution,this),this._container},onRemove:function(t){t.off("layeradd",this._addAttribution,this)},_addAttribution:function(t){t.layer.getAttribution&&(this.addAttribution(t.layer.getAttribution()),t.layer.once("remove",function(){this.removeAttribution(t.layer.getAttribution())},this))},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t,e=[];for(t in this._attributions)this._attributions[t]&&e.push(t);var i=[];this.options.prefix&&i.push(this.options.prefix),e.length&&i.push(e.join(", ")),this._container.innerHTML=i.join(' ')}}}),n=(A.mergeOptions({attributionControl:!0}),A.addInitHook(function(){this.options.attributionControl&&(new Ke).addTo(this)}),B.Layers=Ve,B.Zoom=qe,B.Scale=Ge,B.Attribution=Ke,Ue.layers=function(t,e,i){return new Ve(t,e,i)},Ue.zoom=function(t){return new qe(t)},Ue.scale=function(t){return new Ge(t)},Ue.attribution=function(t){return new Ke(t)},et.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}})),ft=(n.addTo=function(t,e){return t.addHandler(e,this),this},{Events:e}),Ye=b.touch?"touchstart mousedown":"mousedown",Xe=it.extend({options:{clickTolerance:3},initialize:function(t,e,i,n){c(this,n),this._element=t,this._dragStartTarget=e||t,this._preventOutline=i},enable:function(){this._enabled||(S(this._dragStartTarget,Ye,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(Xe._dragging===this&&this.finishDrag(!0),k(this._dragStartTarget,Ye,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){var e,i;this._enabled&&(this._moved=!1,ve(this._element,"leaflet-zoom-anim")||(t.touches&&1!==t.touches.length?Xe._dragging===this&&this.finishDrag():Xe._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((Xe._dragging=this)._preventOutline&&Me(this._element),Le(),re(),this._moving||(this.fire("down"),i=t.touches?t.touches[0]:t,e=Ce(this._element),this._startPoint=new p(i.clientX,i.clientY),this._startPos=Pe(this._element),this._parentScale=Ze(e),i="mousedown"===t.type,S(document,i?"mousemove":"touchmove",this._onMove,this),S(document,i?"mouseup":"touchend touchcancel",this._onUp,this)))))},_onMove:function(t){var e;this._enabled&&(t.touches&&1e&&(i.push(t[n]),o=n);oe.max.x&&(i|=2),t.ye.max.y&&(i|=8),i}function ri(t,e,i,n){var o=e.x,e=e.y,s=i.x-o,r=i.y-e,a=s*s+r*r;return 0this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()t.y!=n.y>t.y&&t.x<(n.x-i.x)*(t.y-i.y)/(n.y-i.y)+i.x&&(l=!l);return l||yi.prototype._containsPoint.call(this,t,!0)}});var wi=ci.extend({initialize:function(t,e){c(this,e),this._layers={},t&&this.addData(t)},addData:function(t){var e,i,n,o=d(t)?t:t.features;if(o){for(e=0,i=o.length;es.x&&(r=i.x+a-s.x+o.x),i.x-r-n.x<(a=0)&&(r=i.x-n.x),i.y+e+o.y>s.y&&(a=i.y+e-s.y+o.y),i.y-a-n.y<0&&(a=i.y-n.y),(r||a)&&(this.options.keepInView&&(this._autopanning=!0),t.fire("autopanstart").panBy([r,a]))))},_getAnchor:function(){return m(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}})),Ii=(A.mergeOptions({closePopupOnClick:!0}),A.include({openPopup:function(t,e,i){return this._initOverlay(Bi,t,e,i).openOn(this),this},closePopup:function(t){return(t=arguments.length?t:this._popup)&&t.close(),this}}),o.include({bindPopup:function(t,e){return this._popup=this._initOverlay(Bi,this._popup,t,e),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t){return this._popup&&(this instanceof ci||(this._popup._source=this),this._popup._prepareOpen(t||this._latlng)&&this._popup.openOn(this._map)),this},closePopup:function(){return this._popup&&this._popup.close(),this},togglePopup:function(){return this._popup&&this._popup.toggle(this),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var e;this._popup&&this._map&&(Re(t),e=t.layer||t.target,this._popup._source!==e||e instanceof fi?(this._popup._source=e,this.openPopup(t.latlng)):this._map.hasLayer(this._popup)?this.closePopup():this.openPopup(t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}}),Ai.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,opacity:.9},onAdd:function(t){Ai.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&(this.addEventParent(this._source),this._source.fire("tooltipopen",{tooltip:this},!0))},onRemove:function(t){Ai.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&(this.removeEventParent(this._source),this._source.fire("tooltipclose",{tooltip:this},!0))},getEvents:function(){var t=Ai.prototype.getEvents.call(this);return this.options.permanent||(t.preclick=this.close),t},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=P("div",t),this._container.setAttribute("role","tooltip"),this._container.setAttribute("id","leaflet-tooltip-"+h(this))},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var e,i=this._map,n=this._container,o=i.latLngToContainerPoint(i.getCenter()),i=i.layerPointToContainerPoint(t),s=this.options.direction,r=n.offsetWidth,a=n.offsetHeight,h=m(this.options.offset),l=this._getAnchor(),i="top"===s?(e=r/2,a):"bottom"===s?(e=r/2,0):(e="center"===s?r/2:"right"===s?0:"left"===s?r:i.xthis.options.maxZoom||nthis.options.maxZoom||void 0!==this.options.minZoom&&oi.max.x)||!e.wrapLat&&(t.yi.max.y))return!1}return!this.options.bounds||(e=this._tileCoordsToBounds(t),g(this.options.bounds).overlaps(e))},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var e=this._map,i=this.getTileSize(),n=t.scaleBy(i),i=n.add(i);return[e.unproject(n,t.z),e.unproject(i,t.z)]},_tileCoordsToBounds:function(t){t=this._tileCoordsToNwSe(t),t=new s(t[0],t[1]);return t=this.options.noWrap?t:this._map.wrapLatLngBounds(t)},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var t=t.split(":"),e=new p(+t[0],+t[1]);return e.z=+t[2],e},_removeTile:function(t){var e=this._tiles[t];e&&(T(e.el),delete this._tiles[t],this.fire("tileunload",{tile:e.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){M(t,"leaflet-tile");var e=this.getTileSize();t.style.width=e.x+"px",t.style.height=e.y+"px",t.onselectstart=u,t.onmousemove=u,b.ielt9&&this.options.opacity<1&&C(t,this.options.opacity)},_addTile:function(t,e){var i=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),a(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&x(a(this._tileReady,this,t,null,o)),Z(o,i),this._tiles[n]={el:o,coords:t,current:!0},e.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,e,i){e&&this.fire("tileerror",{error:e,tile:i,coords:t});var n=this._tileCoordsToKey(t);(i=this._tiles[n])&&(i.loaded=+new Date,this._map._fadeAnimated?(C(i.el,0),r(this._fadeFrame),this._fadeFrame=x(this._updateOpacity,this)):(i.active=!0,this._pruneTiles()),e||(M(i.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:i.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),b.ielt9||!this._map._fadeAnimated?x(this._pruneTiles,this):setTimeout(a(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var e=new p(this._wrapX?H(t.x,this._wrapX):t.x,this._wrapY?H(t.y,this._wrapY):t.y);return e.z=t.z,e},_pxBoundsToTileRange:function(t){var e=this.getTileSize();return new f(t.min.unscaleBy(e).floor(),t.max.unscaleBy(e).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var Di=Ni.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1,referrerPolicy:!1},initialize:function(t,e){this._url=t,(e=c(this,e)).detectRetina&&b.retina&&0')}}catch(t){}return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}(),zt={_initContainer:function(){this._container=P("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(Wi.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var e=t._container=Vi("shape");M(e,"leaflet-vml-shape "+(this.options.className||"")),e.coordsize="1 1",t._path=Vi("path"),e.appendChild(t._path),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){var e=t._container;this._container.appendChild(e),t.options.interactive&&t.addInteractiveTarget(e)},_removePath:function(t){var e=t._container;T(e),t.removeInteractiveTarget(e),delete this._layers[h(t)]},_updateStyle:function(t){var e=t._stroke,i=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(e=e||(t._stroke=Vi("stroke")),o.appendChild(e),e.weight=n.weight+"px",e.color=n.color,e.opacity=n.opacity,n.dashArray?e.dashStyle=d(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):e.dashStyle="",e.endcap=n.lineCap.replace("butt","flat"),e.joinstyle=n.lineJoin):e&&(o.removeChild(e),t._stroke=null),n.fill?(i=i||(t._fill=Vi("fill")),o.appendChild(i),i.color=n.fillColor||n.color,i.opacity=n.fillOpacity):i&&(o.removeChild(i),t._fill=null)},_updateCircle:function(t){var e=t._point.round(),i=Math.round(t._radius),n=Math.round(t._radiusY||i);this._setPath(t,t._empty()?"M0 0":"AL "+e.x+","+e.y+" "+i+","+n+" 0,23592600")},_setPath:function(t,e){t._path.v=e},_bringToFront:function(t){fe(t._container)},_bringToBack:function(t){ge(t._container)}},qi=b.vml?Vi:ct,Gi=Wi.extend({_initContainer:function(){this._container=qi("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=qi("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){T(this._container),k(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_update:function(){var t,e,i;this._map._animatingZoom&&this._bounds||(Wi.prototype._update.call(this),e=(t=this._bounds).getSize(),i=this._container,this._svgSize&&this._svgSize.equals(e)||(this._svgSize=e,i.setAttribute("width",e.x),i.setAttribute("height",e.y)),Z(i,t.min),i.setAttribute("viewBox",[t.min.x,t.min.y,e.x,e.y].join(" ")),this.fire("update"))},_initPath:function(t){var e=t._path=qi("path");t.options.className&&M(e,t.options.className),t.options.interactive&&M(e,"leaflet-interactive"),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){T(t._path),t.removeInteractiveTarget(t._path),delete this._layers[h(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var e=t._path,t=t.options;e&&(t.stroke?(e.setAttribute("stroke",t.color),e.setAttribute("stroke-opacity",t.opacity),e.setAttribute("stroke-width",t.weight),e.setAttribute("stroke-linecap",t.lineCap),e.setAttribute("stroke-linejoin",t.lineJoin),t.dashArray?e.setAttribute("stroke-dasharray",t.dashArray):e.removeAttribute("stroke-dasharray"),t.dashOffset?e.setAttribute("stroke-dashoffset",t.dashOffset):e.removeAttribute("stroke-dashoffset")):e.setAttribute("stroke","none"),t.fill?(e.setAttribute("fill",t.fillColor||t.color),e.setAttribute("fill-opacity",t.fillOpacity),e.setAttribute("fill-rule",t.fillRule||"evenodd")):e.setAttribute("fill","none"))},_updatePoly:function(t,e){this._setPath(t,dt(t._parts,e))},_updateCircle:function(t){var e=t._point,i=Math.max(Math.round(t._radius),1),n="a"+i+","+(Math.max(Math.round(t._radiusY),1)||i)+" 0 1,0 ",e=t._empty()?"M0 0":"M"+(e.x-i)+","+e.y+n+2*i+",0 "+n+2*-i+",0 ";this._setPath(t,e)},_setPath:function(t,e){t._path.setAttribute("d",e)},_bringToFront:function(t){fe(t._path)},_bringToBack:function(t){ge(t._path)}});function Ki(t){return b.svg||b.vml?new Gi(t):null}b.vml&&Gi.include(zt),A.include({getRenderer:function(t){t=(t=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer)||(this._renderer=this._createRenderer());return this.hasLayer(t)||this.addLayer(t),t},_getPaneRenderer:function(t){var e;return"overlayPane"!==t&&void 0!==t&&(void 0===(e=this._paneRenderers[t])&&(e=this._createRenderer({pane:t}),this._paneRenderers[t]=e),e)},_createRenderer:function(t){return this.options.preferCanvas&&Ui(t)||Ki(t)}});var Yi=xi.extend({initialize:function(t,e){xi.prototype.initialize.call(this,this._boundsToLatLngs(t),e)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=g(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});Gi.create=qi,Gi.pointsToPath=dt,wi.geometryToLayer=bi,wi.coordsToLatLng=Li,wi.coordsToLatLngs=Ti,wi.latLngToCoords=Mi,wi.latLngsToCoords=zi,wi.getFeature=Ci,wi.asFeature=Zi,A.mergeOptions({boxZoom:!0});var _t=n.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){S(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){k(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){T(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),re(),Le(),this._startPoint=this._map.mouseEventToContainerPoint(t),S(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=P("div","leaflet-zoom-box",this._container),M(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var t=new f(this._point,this._startPoint),e=t.getSize();Z(this._box,t.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(T(this._box),z(this._container,"leaflet-crosshair")),ae(),Te(),k(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){1!==t.which&&1!==t.button||(this._finish(),this._moved&&(this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(a(this._resetState,this),0),t=new s(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point)),this._map.fitBounds(t).fire("boxzoomend",{boxZoomBounds:t})))},_onKeyDown:function(t){27===t.keyCode&&(this._finish(),this._clearDeferredResetState(),this._resetState())}}),Ct=(A.addInitHook("addHandler","boxZoom",_t),A.mergeOptions({doubleClickZoom:!0}),n.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var e=this._map,i=e.getZoom(),n=e.options.zoomDelta,i=t.originalEvent.shiftKey?i-n:i+n;"center"===e.options.doubleClickZoom?e.setZoom(i):e.setZoomAround(t.containerPoint,i)}})),Zt=(A.addInitHook("addHandler","doubleClickZoom",Ct),A.mergeOptions({dragging:!0,inertia:!0,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0}),n.extend({addHooks:function(){var t;this._draggable||(t=this._map,this._draggable=new Xe(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))),M(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){z(this._map._container,"leaflet-grab"),z(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t,e=this._map;e._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity?(t=g(this._map.options.maxBounds),this._offsetLimit=_(this._map.latLngToContainerPoint(t.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(t.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))):this._offsetLimit=null,e.fire("movestart").fire("dragstart"),e.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){var e,i;this._map.options.inertia&&(e=this._lastTime=+new Date,i=this._lastPos=this._draggable._absPos||this._draggable._newPos,this._positions.push(i),this._times.push(e),this._prunePositions(e)),this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1e.max.x&&(t.x=this._viscousLimit(t.x,e.max.x)),t.y>e.max.y&&(t.y=this._viscousLimit(t.y,e.max.y)),this._draggable._newPos=this._draggable._startPos.add(t))},_onPreDragWrap:function(){var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,n=(n+e+i)%t-e-i,t=Math.abs(o+i)e.getMaxZoom()&&1