Compare commits

..
84 Commits
Author SHA1 Message Date
randy efddc55ad0 refactor: enhance Overpass API handling with multiple endpoints and improved error reporting
CI / check (push) Successful in 19s
CI / deploy (push) Successful in 12s
2026-10-09 22:07:45 +02:00
randy 33be95ef59 Send a User-Agent to Overpass, overpass-api.de 406s Ruby's default
CI / check (push) Successful in 19s
CI / deploy (push) Successful in 13s
The Camper POIs plugin died with "plugin exited with status 1": Net::HTTP's
bare "Ruby" User-Agent now gets a 406 Not Acceptable from overpass-api.de,
any identifying one goes through.
2026-10-09 21:51:24 +02:00
randy ede21454a2 Draw offline hiking trails sharing a path as parallel lanes
CI / check (push) Successful in 22s
CI / deploy (push) Successful in 12s
Several marked routes running down one path drew as a single line, only
the topmost color visible. maplibre-gl-lanes puts each route in its own
lane; OSM relations already share exact vertices, which is all it needs.
One LaneLayer across every picked country; click hit-testing and the
highlight move to queryLane/setHighlight.
2026-10-09 21:46:05 +02:00
randy 9c80a20f3e compose: enable IPv6 on default network (fixes broken container DNS on brick)
CI / check (push) Successful in 38s
CI / deploy (push) Successful in 12s
2026-10-08 12:28:05 +02:00
randy 43785a074b Note the NPS arrowhead logo's official Pantone/RAL colors
CI / check (push) Successful in 38s
CI / deploy (push) Successful in 12s
Unrelated to anything the app renders, but the doc already collects
NPS-ecosystem color facts and this came up while sourcing colors
for a 3D print of the shield.
2026-09-21 18:08:35 +02:00
randy b0c93d10d7 Detect a LiveTrack session ending the moment Garmin confirms it, not 30min later
CI / check (push) Successful in 18s
CI / deploy (push) Successful in 12s
Watched the session from the last two commits actually get saved:
Garmin updated its `end` field from the future 24h placeholder to
within a second of the last point's own time, immediately — much
faster than the recency-of-last-point fallback alone would have
noticed (that only flips after ACTIVE_WITHIN with no new points, so a
just-saved session with a last point seconds old would still read as
active for up to 30 more minutes).

Now checks end-already-in-the-past first (authoritative and near
instant when Garmin has set it), falling back to point recency only
when end still shows the future placeholder — the case an abandoned,
never-saved session never updates.
2026-09-20 16:55:57 +02:00
randy 3106f8c103 Draw a LiveTrack session's planned course alongside the actual track
CI / check (push) Successful in 19s
CI / deploy (push) Successful in 13s
Garmin's own LiveTrack page already shows both when the activity was
started from a saved course — the session payload carries the course's
geoPoints right alongside the track points (LiveTrackClient found it
nested under the same React Query cache the session/points come from).

Rendered as a second, dashed LineString distinct from the actual
track's own line ("kind": "actual" vs "planned" on each GeoJSON
feature) — muted gray rather than matching Garmin's own purple-for-
planned, since this app's actual track is already purple and reusing
it would make the two indistinguishable.
2026-09-20 16:54:24 +02:00
randy 8eada07869 Drop subject:LiveTrack from the Apps Script's Gmail search, it finds nothing
CI / check (push) Successful in 21s
CI / deploy (push) Successful in 12s
Documented as matching regardless of language, on the assumption
Gmail's subject: operator does a substring match — empirically false
against a real, currently-arriving LiveTrack email whose subject does
contain the word ("Sledujte LiveTrack používateľa ...", confirmed
2026-09-20): with the filter, the search returned zero threads;
removing it and rerunning found the email immediately. Left out
entirely rather than replaced — from:noreply@garmin.com plus the
session-link regex already narrows this down to real LiveTrack emails
with something usable in them.
2026-09-20 16:44:20 +02:00
randy 5d86cb1d04 Detect a live LiveTrack session from its last point, not session["end"]
CI / check (push) Successful in 40s
CI / deploy (push) Successful in 13s
session["end"].nil? was the active signal since this was first built,
on the assumption Garmin leaves it unset until the activity actually
stops. Checked directly against a real still-recording session today
(2026-09-20): end was already non-nil, set to exactly start + 24h — the
share link's own expiry, not an end time — so every currently-active
session was showing as "Ended". A genuinely ended session's end does
hold its real end time (confirmed against the 2026-09-06 session this
was originally, and only, verified against), which is what made the
bug easy to miss.

Recency of the last track point is a directly-observable signal
instead of reverse-engineering what a given `end` value means: Garmin
posts one roughly every postTrackPointFrequency seconds (~15, observed)
while genuinely still recording.
2026-09-20 16:42:52 +02:00
randy b7618edc25 Move the session-skip from a before filter to real Rack middleware
CI / check (push) Successful in 19s
CI / deploy (push) Successful in 12s
The before filter added in the previous commit never ran for static
assets: Sinatra serves public_folder files (every JS/CSS/font/vendor
file) through its own built-in shortcut, bypassing route and filter
dispatch entirely — confirmed live, curl still got a fresh set-cookie
on /js/map.js after that commit deployed, and the user hit the exact
same logout on refresh again. A HAR from that retest shows the same
clobbering pattern as before, just via a different response each time.

SkipSessionWrite is a plain Rack middleware instead, positioned (via
`use`, after `set :sessions`) inside Rack::Session::Cookie's own
wrapping — it sees the same env static dispatch does, so every response
is covered, not just Sinatra-routed ones.
2026-09-16 18:03:28 +02:00
randy bd46b72144 Skip re-writing the session cookie on every response, not just the three that change it
CI / check (push) Successful in 19s
CI / deploy (push) Successful in 12s
Rack::Session::Cookie re-serializes and re-sets the cookie on every
response that even reads session — Rack::Protection's CSRF check does,
on nearly every request — reflecting whatever cookie that particular
request happened to arrive with, whether or not anything actually
changed. A HAR capture caught the real failure mode: seconds after a
successful login, offline_data.js's _checkUpdate (an unrelated
background poll fired the instant the page loads) was still carrying
the browser's pre-login cookie — a client-side timing race across the
OAuth redirect chain, not something this server controls — and its own
re-issued Set-Cookie landed after the login's, silently overwriting
session[:user] with nothing logged anywhere to explain it.

Only /login, /auth/callback and /logout ever actually write to
session. A before filter now skips the write everywhere else, removing
every other response from that race — a stale request can still read a
stale cookie, but it can no longer clobber a fresher one.

Also drops the earlier except: [:session_hijacking] from the previous
commit: rack-protection 4.2.1 only enables SessionHijacking when
explicitly opted into via :use, so Sinatra's default setup never turned
it on in the first place — the exclusion was a no-op, not the fix.
2026-09-16 17:56:44 +02:00
randy 6126b5055b Disable Rack::Protection::SessionHijacking, it silently logs everyone out
CI / check (push) Successful in 37s
CI / deploy (push) Successful in 19s
Sinatra turns this on by default once sessions are enabled: it pins a
session to the User-Agent header seen on whichever request first wrote
to it, and empties the session — no exception, nothing logged — on any
later request where that header doesn't match. That's exactly what
production hit behind its reverse proxy: OAuth login set session[:user]
fine, then the very next page load (even a plain refresh) came back
logged out with nothing in the logs to explain why.

Its own docs concede every header it checks is spoofable anyway ("will
not prevent determined hijacking attempts"), so losing it is a minor
tradeoff for a login that actually stays logged in. Every other
Rack::Protection check stays on.
2026-09-16 16:11:01 +02:00
randy 9edc2d9534 Show clicked hiking trail info in a docked panel, not a popup
CI / check (push) Successful in 22s
CI / deploy (push) Successful in 12s
A map-anchored Popup on a trail click routinely overlapped the very
line it described. Follows the same click -> docked panel pattern
gpx.js already uses for a track line click (TrackProfilePanel) rather
than inventing a new one: a fixed #trail-panel docks to the right edge
on desktop and the bottom edge on narrow viewports (this file's first
@media breakpoint), so the trail stays fully visible either way.

routeHtml()'s own markup is reused unchanged for the panel body —
.trail-panel__body's padding matches .maplibregl-popup-content's own
(15px 10px) so the header's canceling negative margin still lines up.
The popup-identity staleness guard for the async Overpass lookup is
replaced with a plain request token, since there's no longer a fresh
Popup instance to key off of.
2026-09-15 12:52:54 +02:00
randy eada464fb3 Highlight trails in their own color instead of recoloring to yellow
CI / check (push) Successful in 22s
CI / deploy (push) Successful in 12s
2026-09-13 20:17:48 +02:00
randy ca7772dd72 Highlight the clicked trail(s) on the map, both online and offline
CI / check (push) Successful in 19s
CI / deploy (push) Successful in 12s
The real app had no visual feedback for which line a click actually
matched, unlike the earlier SVG prototype's hover highlight — just a
popup. Draws the matched route's real geometry (from the offline
vector feature, or reassembled from the online Overpass response's own
member-way geometry) as a separate yellow highlight layer, cleared
when the popup closes.

Guarded against a stale popup's closeOnClick "close" event clearing a
highlight that a newer click already set in the same event dispatch —
tracks which popup is currently "active" and only clears on its own
close, not a predecessor's delayed one.
2026-09-13 19:28:51 +02:00
randy 4c95927231 Pin check/renovate back to brick-build now that its image has Node
CI / check (push) Successful in 38s
CI / deploy (push) Successful in 12s
The runner's label-to-image mapping got repointed at Gitea's own
official runner image (docker.gitea.com/runner-images:ubuntu-latest,
has Node out of the box) — the earlier opensuse/leap:16.0 mapping for
brick-build specifically was what broke check/renovate on 2026-09-12,
not brick-build the label itself. Back to pinning both to this
machine specifically instead of whichever runner answers to the
shared ubuntu-latest label.
2026-09-13 12:32:14 +02:00
randy c6e4a455b6 Split offline hiking trails per country, add a picker instead of one big file
CI / check (push) Successful in 21s
CI / deploy (push) Successful in 11s
data/hiking_trails.geojson is now data/hiking_trails/<CODE>.geojson —
one file per country instead of a merge, generated per-source
(PmtilesBuilder.extract_hiking_trails), cached the same way
geofabrik_cache is (skipped once a country's own extract is already
newer than its source .osm.pbf, so growing the selection by one
country only re-extracts that one). GET /api/hiking-trails now lists
available country codes instead of a single file's status.

The Overlays panel's "Hiking trails" item becomes an expandable
per-country checklist once any offline extract exists (same shape as
Radar's own expand), replacing the plain on/off checkbox — nobody
covering a dozen countries' worth of offline map data needs all of
their hiking trails loaded and parsed at once, so each ticked country
fetches its own GeoJSON independently instead.

HikingTrails.extract_merged (server-side multi-country merge, no
longer needed now that the client picks per country) removed again.
Verified the new extract_hiking_trails + caching skip live on brick
against a real cached country PBF.
2026-09-13 11:17:05 +02:00
randy 079ac37787 Wire offline hiking trails into the real build, API, and renderer
CI / check (push) Successful in 19s
CI / deploy (push) Successful in 12s
data/hiking_trails.geojson now generates automatically as the last
step of every offline.pmtiles build (PmtilesBuilder.extract_hiking_trails,
best-effort — a failure here doesn't fail the whole build), merged
across all selected countries with cross-border dedup by OSM relation
id (HikingTrails.extract_merged). Served at GET /tiles/hiking_trails.geojson
and GET /api/hiking-trails, fetched client-side only once the overlay
is actually toggled on.

hiking_trails.js now prefers this local file whenever it exists,
regardless of which base map (online/offline) is active — same
"prefer local when available" story as HillshadeControl already uses
for terrain. Offline click hit-tests the real vector layer directly
(queryRenderedFeatures) instead of querying Overpass — instant, no
network. Coordinates are rounded to 5dp to keep the combined file
smaller; colour tag values are normalized against a known-safe set
before ever reaching a style paint property.

Verified extract_merged (new: combines multiple countries' extracts,
dedupes overlapping relations) against two real cached country PBFs
on brick directly, not just fixtures.
2026-09-13 10:31:59 +02:00
randy b35ace9734 Fix hiking trails extraction: add-locations-to-ways was missing
Verified live on brick against real cached extracts: a plain Geofabrik
PBF's ways only carry bare node references, not coordinates, so
locations_on_ways on the final `cat -f opl` had nothing to embed —
every way came out as e.g. n123xy, empty x/y, and every relation got
dropped for having no usable geometry (0 routes for Macedonia).

osmium add-locations-to-ways between the tags-filter and cat steps
resolves those references first. Re-verified after the fix: 45 routes
for Macedonia, 3009 for Slovakia, with real colour/ref/operator/
distance (326 red, 782 yellow, 510 blue, 902 green KST-style routes).
2026-09-13 09:26:22 +02:00
randy 714795d52b Prototype: extract offline hiking trails from the Geofabrik PBF we already have
CI / check (push) Successful in 43s
CI / deploy (push) Successful in 13s
No custom Planetiler profile needed after all — Maptool::HikingTrails
runs osmium tags-filter r/route=hiking against the same .osm.pbf
PmtilesBuilder already downloads per country for offline.pmtiles, then
osmium cat -f opl (locations_on_ways=true) to get member-way geometry
back as plain text, no separate node-id lookup table to build.

No general OSM tool stitches a route relation into one line (routes
are a semantic grouping, not a geometry type) — parse_opl does that
walk itself, same as the Overpass-based click handler already does
client-side. Kept pure/testable apart from the two osmium subprocess
calls, mirroring OverpassPois.fetch vs .to_geojson.

rake hiking:trails[pbf,out] to try it by hand against a real cached
extract. Not wired into the actual offline build or rendering yet —
still just a prototype, per TODO.adoc.
2026-09-13 09:18:50 +02:00
randy cc3d8ca5f3 Race 3 Overpass mirrors for speed, show more per-route detail
CI / check (push) Successful in 2m18s
CI / deploy (push) Successful in 11s
The single shared overpass-api.de instance varies wildly in load —
Promise.any against three independent public mirrors (also CORS-open,
verified) means only the slowest one determines wait time, not
whichever happens to be hit.

Also show the description tag (falls back to it for the title when a
route has no name, e.g. many KST route relations), the ref number, and
a "View on OpenStreetMap" link — the popup was skipping data that was
already in the response for free.
2026-09-13 08:53:48 +02:00
randy 6f1577f957 Click a hiking trail to see its name, color, network and distance
CI / check (push) Successful in 19s
CI / deploy (push) Successful in 12s
The Waymarked Trails raster overlay has no queryable features (just
pixels), so this answers "what trail is this" with a one-off Overpass
query on click instead: way(around:40m) finds candidate ways, then
rel(bw) walks backward to their parent route=hiking relations. Overpass
has permissive CORS, so this runs straight from the browser, no server
proxy needed — verified against a real KST route in the Tatras.

Route length isn't tagged directly, so it's summed from each member
way's own geometry (measure.js's existing haversine lineLength, now
exported and reused rather than duplicated). The colour tag is only
ever used as a CSS background after matching a strict hex/word regex —
untrusted free text otherwise.
2026-09-12 23:32:56 +02:00
randy 9c45e7275c Add a Hiking trails overlay (Waymarked Trails, online only)
CI / check (push) Successful in 2m16s
CI / deploy (push) Successful in 11s
New Overlays panel toggle, same plain on/off shape as Contour lines —
raster tiles from waymarkedtrails.org, which already color each route
by its OSM colour tag (the KST/KČT paint-blaze colors used in
Slovakia/Czechia, plain red elsewhere), so no styling work needed here.

Online only for now; offline (baked into offline.pmtiles) needs a
custom Planetiler profile for route relations, deferred until there's
a route planner/router to pair it with.
2026-09-12 22:36:10 +02:00
randy c894706140 Revert check/renovate to ubuntu-latest — brick-build's image has no Node
CI / check (push) Successful in 19s
CI / deploy (push) Successful in 12s
brick-build's job container (opensuse/leap:16.0) has no Node.js, and
every step in check/renovate (checkout, setup-ruby, setup-node) is a
JS-based Action that needs it just to start — both runs since the
brick-build switch failed immediately, and deploy never ran because it
depends on check passing. ubuntu-latest is shared with "Gitea Runner on
Cube" (not pinned to this specific machine), but that's fine: only
deploy (a unique label held by just brick's native runner) actually
needs to land on a specific box.
2026-09-12 21:39:21 +02:00
randy 21988c61da Lower offline terrain to z13, not z15 — raster DEM storage explodes with zoom
CI / check (push) Failing after 4s
CI / deploy (push) Skipped
The 12-country selection's terrain.pmtiles was headed well past the
181GB an earlier 5-country build already produced at z15. Raster DEM
tiles don't compress away like vector ones (every tile is a real
image, even over empty terrain), so each extra zoom level roughly
quadruples storage. z13 is each Mapterhorn regional chunk's own native
minzoom — one raster level per chunk instead of a 15-13=2-level
pyramid on top — still enough for the hillshade toggle and the planned
slope readout. Online hillshade keeps its own z15 cap; this only
affects the offline copy.
2026-09-12 20:18:36 +02:00
randy f18e5c19d3 Truncate noisy build-failure output, fix the recurring terrain death
CI / check (push) Failing after 4s
CI / deploy (push) Skipped
The web UI was showing a raw ~500k-character stdout/stderr dump on a
failed build — go-pmtiles' extract logs one progress line per chunk,
which is fine on a terminal (it overwrites itself) but not captured
non-interactively. command_output now keeps just the tail, and the
status line renders it with preserved line breaks in a scrollable box
instead of one unreadable blob.

Root cause of the actual failure (terrain build dying ~11 minutes in
with an HTTP/2 stream reset): go-pmtiles' default --overfetch=0.05
merged this multi-country planet.pmtiles extract into a single ~60GB
request with no way to resume after a dropped stream. --overfetch=0
splits it into many smaller requests instead.
2026-09-12 19:41:45 +02:00
randy 237e5b2e54 Move check/renovate onto brick-build, deploy stays brick-host
Renovate no longer needs Docker access for a one-shot docker-run job:
switched to setup-node + npm install -g renovate (matching labelprint's
workflow), so it fits the same brick-build runner as check instead of
the stale "deploy" label. Also note down the build-log readability/API
gaps flagged from a real failed terrain build.
2026-09-12 19:36:08 +02:00
randy 3f9c46e846 Skip rebuilding offline/terrain data when nothing actually changed
CI / check (push) Successful in 21s
CI / deploy (push) Successful in 12s
2026-09-12 13:32:02 +02:00
randy 17d1adedbc Guard syncTerrain against running before the style has loaded
CI / check (push) Successful in 18s
CI / deploy (push) Successful in 12s
2026-09-12 13:27:53 +02:00
randy cd02b03502 Retry pmtiles extract/merge on failure, not just on the first try
CI / check (push) Successful in 39s
CI / deploy (push) Successful in 12s
2026-09-12 12:50:09 +02:00
randy 5c3151c2f5 Add a 3D pitch toggle, with raised terrain following it 2026-09-12 12:50:09 +02:00
randy f5eb9a4a8d Tell Planetiler explicitly how many CPUs it has
CI / check (push) Successful in 18s
CI / deploy (push) Successful in 12s
Its own autodetection was leaving most of a 16-core host idle
(observed in production) — likely a container cgroup/JVM detection
quirk. Etc.nprocessors asks the OS directly instead.
2026-09-12 01:34:29 +02:00
randy f09b5de6c2 Relabel data bind mounts for SELinux (:Z)
CI / check (push) Successful in 21s
CI / deploy (push) Successful in 12s
App crashed on startup on brick (Permission denied @ dir_s_mkdir -
/app/data/gpx) — brick has SELinux enforcing, unlike cube, and Podman
denies a container write access to a bind-mounted host directory
without a relabel regardless of Unix permissions. Applied to both
maptool's ./data mount and kiwix's ZIM mount (same underlying cause,
would have hit this too once a real ZIM is placed there).
2026-09-12 01:27:23 +02:00
randy 0080ac6170 Deploy to brick-host instead of cube-host
CI / check (push) Successful in 19s
CI / deploy (push) Failing after 5m1s
cube.local and brick.local swapped IPs and brick is now the deploy
target — rename the native runner label everywhere it's referenced.
2026-09-12 01:15:09 +02:00
randy 78362d51f2 Show what's actually cached per-country, with a delete button per row
CI / check (push) Successful in 17s
CI / deploy (push) Successful in 13s
The only visibility into downloaded data was the whole offline.pmtiles
row, and the only delete was "everything" (whole file + whole cache).
GET /api/offline-tiles/cache lists what's really in
data/geofabrik_cache/ right now — distinct from offline.pmtiles' own
meta.sources, which only reflects the last successful build and can
disagree with both the current selection and the cache (ticked-but-
not-Applied, or built-from-but-since-unticked).

The region picker now shows each cached country's size next to its
checkbox, with its own delete button (DELETE
/api/offline-tiles/cache/:code, already added but unused by the UI
until now) — removing just that entry rather than clearing the whole
cache.
2026-09-11 23:39:43 +02:00
randy d09d953cbf Pass --download to Planetiler for its auxiliary OpenMapTiles sources
CI / check (push) Successful in 18s
CI / deploy (push) Successful in 13s
Real build failure once the tmp-filename fix got past the format-
detection error: "data/sources/lake_centerline.shp.zip does not exist.
Run with --download to fetch it". The OpenMapTiles profile needs a few
small non-OSM sources (water polygons, Natural Earth, lake
centerlines) alongside the .osm.pbf itself, and Planetiler only
fetches them when told to. They land under its own default
data/sources/, gitignored alongside the rest of data/ — fetched once,
reused by every later build.
2026-09-11 23:28:07 +02:00
randy b54020e23b Fix Planetiler tmp-file format detection, add build progress and delete
CI / check (push) Successful in 19s
CI / deploy (push) Successful in 13s
Root cause of "planetiler exited with status 1: ... Unsupported format
tmp" (and likely the earlier unexplained "pmtiles exited with status
1"): Planetiler/go-pmtiles pick their output archive format from the
file extension, and the atomic-rename tmp files were named
"offline.pmtiles.tmp"/"terrain.pmtiles.tmp" — ".tmp" as the extension,
not ".pmtiles". Renamed to "offline.tmp.pmtiles"/"terrain.tmp.pmtiles".

Also, since build-status only ever said "running since X" with no way
to tell what it was actually doing:
- GET .../build-status now includes a `step` string ("fetching PL
  (3/4) — done: SK, CZ — pending: HU", "tiling with planetiler", ...)
  while a build is in progress.
- DELETE /api/offline-tiles / /api/terrain-tiles clear a built file,
  its sidecar meta, and (for offline) the whole per-country download
  cache — a manual "reclaim space" / "start over" action the region
  picker's Apply never did on its own. DELETE
  /api/offline-tiles/cache/:code clears just one country's cached
  extract. All three are 409 while that kind's build is running, and
  surfaced as a small "Delete" button on each row in the Offline data
  panel.
2026-09-11 23:23:46 +02:00
randy 2878270187 Include stdout in run_*! build error messages, not just stderr
Real cause of "pmtiles exited with status 1:" with nothing after the
colon: go-pmtiles (like some other CLIs) can write its actual error to
stdout, which was being silently discarded. Applies the same fix to
osmium/planetiler for consistency.
2026-09-11 23:07:49 +02:00
randy 007dee7341 Cache per-country Geofabrik extracts so Apply doesn't redownload everything
Every region-selection change re-downloaded every selected country's
.osm.pbf from scratch, even ones already fetched by a prior build —
painful for multi-GB countries. Extracts now persist in
data/geofabrik_cache/, keyed by country, and are only re-fetched when
Geofabrik's Last-Modified for that country actually moved on (checked
with a cheap HEAD) or the file isn't cached yet.
2026-09-11 22:52:16 +02:00
randy 077b44ece1 Note OpenTopoMap-style forest/meadow fill patterns as a TODO idea
CI / check (push) Successful in 18s
CI / deploy (push) Successful in 2m54s
2026-09-11 22:13:30 +02:00
randy 619f2293df Move Docker base image to Debian trixie for Java 21
Planetiler 0.10.2 needs Java 21+; bookworm's default-jre-headless (and
its backports) only goes up to 17, causing a real build to fail with
UnsupportedClassVersionError. trixie's default-jre-headless is Java 21.
2026-09-11 22:13:30 +02:00
randy a84e6ae22f Follow Geofabrik's 302 redirects on extract download and Last-Modified check
CI / check (push) Successful in 29s
CI / deploy (push) Successful in 16s
Geofabrik redirects europe/<slug>-latest.osm.pbf to a dated filename
(confirmed live: .../europe/austria-latest.osm.pbf -> .../europe/austria-
260910.osm.pbf) — a real build hit this immediately. Net::HTTP doesn't
follow redirects on its own; both the streaming download and the HEAD-based
update-check now do, up to a small limit.
2026-09-11 20:57:22 +02:00
randy 920a1d2d36 Stream Geofabrik extract downloads instead of buffering in memory
Net::HTTP's plain #get loads the whole response body before returning —
fine for the small JSON manifests elsewhere in this file, but a real risk
for a multi-GB country .osm.pbf (Germany, Russia, ...). Streams to disk
via read_body instead.
2026-09-11 20:56:06 +02:00
randy d08ed41185 Replace offline basemap pipeline with Planetiler, unify online/offline styling
CI / check (push) Successful in 18s
CI / deploy (push) Successful in 2m43s
Offline tiles were built from Protomaps' own basemap schema, needing a
completely separate hand-tuned theme (protomaps-themes-base + OFFLINE_THEME)
from the online Liberty style's ONLINE_STYLE_PATCH — the two could never be
made to match exactly no matter how much either side got tuned (today's
session found and fixed several mismatches: building opacity, park
boundaries, road casings, road widths).

Offline.pmtiles is now built with Planetiler's default OpenMapTiles profile
against Geofabrik per-country OSM extracts (osmium-merged when more than one
country is selected), the same vector schema Liberty already expects.
offlineStyle() now clones the same Liberty JSON (vendored as a local
snapshot for reliability with no internet) and applies the identical
ONLINE_STYLE_PATCH, just repointed at local PMTiles/glyphs/sprite — one
palette instead of two, correct on both sides by construction.

Also vendors Liberty's icon sprite for the first time (offline had none
before), adds Java/osmium-tool/planetiler.jar to the Docker image, and
removes the now-unused protomaps-themes-base dependency and the
theme-comparison debug page that found today's bugs.
2026-09-11 20:52:11 +02:00
randy 0874e8f8ed Add a debug page for comparing offline base-map themes side by side
CI / check (push) Successful in 19s
CI / deploy (push) Successful in 13s
Renders the bare protomaps-themes-base themes next to the app's actual
offline/online styles (each real app instance, embedded), with pan/zoom
kept in sync via the existing URL-hash mechanism, to make it easy to see
where the hand-tuned offline palette diverges from the online one.
2026-09-11 16:58:32 +02:00
randy 9223410b40 Swap flag emoji for real (square, bordered) SVG flags
CI / check (push) Successful in 21s
CI / deploy (push) Successful in 16s
Emoji flags are font glyphs, not shapes — no way to resize, border, or
tone them down to fit this app's controlled, hand-drawn-icon look
(same reasoning the topbar readout already settled earlier this
session). Vendored flag-icons' pre-cropped square SVGs (MIT) instead,
framed in a small rounded-square badge — the same convention
icons.js's MAP_MARKER_ICON already uses for framing a glyph, not a new
visual language.
2026-09-11 13:31:36 +02:00
randy 4a3862189f Track what was actually built, and flag when it's stale
CI / check (push) Successful in 19s
CI / deploy (push) Successful in 16s
The .pmtiles files themselves carry no record of what upstream
snapshot they came from — only a local mtime. Each successful build
now writes a small sidecar (offline.pmtiles.meta.json: the Protomaps
build date used; terrain.pmtiles.meta.json: the Mapterhorn source
names/md5sums) recording that, surfaced in the panel next to the
existing size/updated line.

New GET .../check-update routes compare the recorded build against
the live upstream index/manifest — true/false/null, null meaning
"don't know" (no local build yet, or the check itself failed) rather
than a false "no". Kept separate from the plain status endpoints
(which map.js's own topbar dot hits on every page load) since this
one reaches an external service; only called once when the Offline
data panel is actually opened.

Also: flag emoji next to each country in the picker (derived from the
ISO code via Unicode regional indicators, no image assets needed).
2026-09-11 13:18:32 +02:00
randy 53c9a82af2 Add a country-based region picker for offline data
CI / check (push) Successful in 17s
CI / deploy (push) Successful in 12s
Replaces "regenerate for the current viewport" with what Locus/OsmAnd-
style apps give you: tick which countries you want offline (a Natural
Earth-derived checklist, public domain, vendored), Apply rebuilds
offline.pmtiles/terrain.pmtiles to cover the whole selection at once.
Multiple regions can be offline simultaneously (e.g. Slovakia + Austria
for a trip that crosses the border) — the selection itself is the
source of truth (data/offline_regions.json), not a set of per-country
files, so "remove a country" and "refresh a country" are both just
"change the selection, then Apply."

Confirmed against go-pmtiles' own source (not just its docs) before
committing to this shape: `extract --region=<geojson>` treats a
FeatureCollection's features as their union already (no dissolve/union
math needed on our side — pmtiles/region.go's UnmarshalRegion just
concatenates every feature's rings), and `merge` hard-errors on any
overlapping tile id between inputs (merge.go's prepareInputs). That
second fact rules out "extract each country separately, merge them
all" — adjacent countries' region-extracts would share border tiles,
since extraction copies whole tiles rather than clipping vector
content to the polygon. The actual fix: extract per *source archive*
(the Protomaps build, each intersecting Mapterhorn chunk), each call
covering the whole current selection via one --region= file — the
terrain pipeline already extracted-then-merged per source this way, it
just needed a multi-country region instead of a single bbox.
2026-09-11 12:55:56 +02:00
randy f89dea5805 Build terrain.pmtiles from Mapterhorn instead of fetching tiles ourselves
CI / check (push) Successful in 18s
CI / deploy (push) Successful in 1m52s
Mapterhorn (mapterhorn.com, Protomaps-affiliated) publishes pre-built
Terrarium-encoded terrain as PMTiles: a global planet.pmtiles (z0-12)
plus ~450 regional chunks (z13+). Same pmtiles extract --bbox=...
mechanism offline.pmtiles already uses, just against their files —
confirmed live against their real manifest and the documented
Interlaken example. Replaces fetching every individual tile ourselves
(even after this session's earlier concurrency fix, still tens of
minutes for a real region) with 1-3 extract calls plus a merge when
the bbox spans more than one chunk: seconds, not minutes.

Removes CONCURRENT_TILE_FETCHES, write_terrarium_mbtiles, tile_range,
lng/lat_to_tile_x/y, fetch_terrarium_tile, and the sqlite3 gem
entirely — none of it is needed once the tiles arrive pre-packaged.

dem.js's point-elevation lookup (shadow.js's terrain-shadow overlay)
hardcoded a 256px PNG tile assumption that Mapterhorn's 512px WebP
tiles would have silently broken — now reads the actually-decoded
tile's own size and mime type instead of assuming either.
2026-09-11 12:26:03 +02:00
randy d041c21270 Fetch terrain tiles concurrently with persistent connections
CI / check (push) Successful in 20s
CI / deploy (push) Successful in 13s
Serial fetches (no connection reuse) measured ~650ms/tile, almost all
TCP+TLS handshake — a real bbox at z0..15 is tens of thousands of
tiles, so this was hours for a modest region. Now: 16 worker threads
share a queue (I/O-bound, so the GVL doesn't get in the way), each
keeping its own persistent connection across every tile it fetches.
Measured live against the real Terrarium source: ~40ms/tile, ~16x
faster.

write_terrarium_mbtiles's SQLite writes and progress updates stay on
one thread (draining a results Queue the workers feed), so nothing
needed its own locking beyond the two Queues themselves.
2026-09-11 12:04:13 +02:00
randy bbe9f38bda Show build progress instead of a static "Building…"
CI / check (push) Successful in 18s
CI / deploy (push) Successful in 13s
terrain.pmtiles can take minutes (tiles fetched one at a time) with no
way to tell a slow build from a stuck one. Now reports tiles_done/
tiles_total into the same status Hash the frontend already polls, and
the panel shows elapsed time (both files) plus tile counts (terrain
only) so the numbers visibly move every ~3s poll instead of sitting on
one static string.
2026-09-11 11:57:43 +02:00
randy d72f8a3c94 Bundle go-pmtiles into the Docker image
CI / check (push) Successful in 18s
CI / deploy (push) Successful in 2m23s
The "Regenerate for current view" build was failing in production with
"could not run 'pmtiles'" — go-pmtiles was never actually installed
anywhere, just documented as something a developer runs by hand
locally (docs/development.adoc). Installs the static Linux binary from
go-pmtiles' own GitHub releases, architecture-matched via dpkg rather
than hardcoded amd64.

Verified the exact download/extract/exec sequence end-to-end outside
Docker (no daemon available in this sandbox to run a real build).
2026-09-11 11:47:31 +02:00
randy cd56ebe0a1 Add in-app regeneration of offline.pmtiles and terrain.pmtiles
CI / check (push) Successful in 20s
CI / deploy (push) Successful in 1m52s
A logged-in user can now trigger, from a new "Offline data" sidebar
panel, what was previously a fully manual go-pmtiles workflow
(docs/development.adoc): regenerate either file for the current map
viewport, no area-picker (same "visible area is the area" convention
the Overpass POI plugin already uses).

- lib/maptool/pmtiles_builder.rb: two independent background jobs
  (Thread + Mutex-guarded status Hash, same shape as app.rb's own GNSS
  poller), each writing to a .tmp path and atomically renaming into
  place so a build never serves a partially-written file mid-run.
  offline.pmtiles is a single `pmtiles extract` against Protomaps'
  public daily basemap build (byte-range extraction, not a full
  ~120GB download). terrain.pmtiles has no equivalent public
  Terrarium-encoded archive to extract from, so it fetches individual
  Terrarium tiles itself, packs them into an intermediate MBTiles
  (new sqlite3 gem), then the same `pmtiles convert`.
- 4 new app.rb routes (POST .../build, GET .../build-status) plus
  size/mtime added to the existing availability endpoints.
- public/js/offline_data.js: new sidebar panel, polling build-status
  the same self-rescheduling-setTimeout shape livetrack.js already
  uses for its own refresh loop.
- Both network-heavy pieces (the Protomaps build index, per-tile
  fetches) are injectable, so test/test_pmtiles_builder.rb exercises
  the actual build pipeline against a fake `pmtiles` binary without
  hitting a real network, matching this suite's existing
  keep-it-offline convention for external services.
2026-09-11 01:25:08 +02:00
randy fba8ca10a2 Add contour lines to the Overlays panel via maplibre-contour
CI / check (push) Successful in 18s
CI / deploy (push) Successful in 12s
5th Overlays item, generated client-side from the same online Terrarium
DEM tiles Terrain shading already fetches (no offline fallback — the
plugin's DemSource has no public hook to route through the pmtiles://
protocol the offline basemap uses, so this quietly renders nothing
without a network, same as Radar/the Wikipedia layer).

A plain vector source/layer under MapLibre's own tile lifecycle, no
manual refetch-on-move code needed. Thresholds are the plugin's own
generic starting point, not yet tuned against real terrain. Labels
skipped for now (font-name matching across the online/offline styles'
own glyph sets adds real risk for a nice-to-have, not the actual ask).
2026-09-11 00:12:32 +02:00
randy b4a1c6c0cc Add a search box, matching NPS's Park Tiles viewer
CI / check (push) Successful in 19s
CI / deploy (push) Successful in 13s
Top-left map control (topmost, above Home/zoom) with a text input:
"lat, lng" is parsed and jumped to directly (same plain-text shape the
topbar's coordinate readout already copies to the clipboard), anything
else is geocoded via Nominatim — OSM's own geocoder, free, no API key,
matching the online basemap's own OSM-derived style. Online only, same
story as this app's other non-basemap online features (Radar, the
Wikipedia layer) — no offline geocoding index to fall back to.
2026-09-10 23:59:35 +02:00
randy 23a84ac185 Bump the topbar wordmark to 20px
CI / check (push) Successful in 18s
CI / deploy (push) Successful in 12s
2026-09-10 23:53:32 +02:00
randy c8b6dd2fb1 Use the National Park typeface for the topbar wordmark
CI / check (push) Successful in 17s
CI / deploy (push) Successful in 12s
Self-hosted Bold woff2 only (the one weight .topbar__brand renders at)
under public/vendor/national-park-typeface/ — a router-carved-signage
display face for the "MAPTOOL" heading, matching the uppercase/
letter-spaced treatment it already had. Everything else stays on the
system font stack; this is a wordmark swap, not a body-text one.

docs/nps-resources.adoc/third-party-notices.adoc updated to record it.
2026-09-10 23:50:19 +02:00
randy a5adb39770 Add monoline icons to the topbar coordinates/sun readout
CI / check (push) Successful in 18s
CI / deploy (push) Successful in 13s
WAYPOINT_ICON (coords) and PENDING_ICON (countdown) reused as-is; two new
hand-drawn SUNRISE_ICON/SUNSET_ICON since NPS's symbol set has no match —
same currentColor stroke style as the rest of icons.js, so they render
monochrome in the dark topbar rather than colored emoji.

sun.js's formatSunInfo now returns {sunrise, sunset, countdown} instead of
one joined string, so map.js can place its own icon in front of each
piece instead of the module owning any markup.
2026-09-10 22:54:18 +02:00
randy b5466b53e4 Widen the side panels so the hourly forecast strip fits
CI / check (push) Successful in 17s
CI / deploy (push) Successful in 12s
260px -> 300px on the shared .basemap-panel class (Overlays/GPX/Livetrack
all use it) — the next-8-hours row was getting clipped.
2026-09-10 22:47:35 +02:00
randy 6911e67c81 Add a next-8-hours strip to the Radar panel's forecast
CI / check (push) Successful in 17s
CI / deploy (push) Successful in 13s
Same Open-Meteo call and cache as the daily outlook, just with an hourly
field added — a rolling window from now rather than "rest of today", so
it doesn't shrink to nothing right before midnight.
2026-09-10 22:39:51 +02:00
randy 254e9b4c61 Add a scale bar to the map
CI / check (push) Successful in 53s
CI / deploy (push) Successful in 12s
MapLibre's own ScaleControl, bottom-left (attribution already owns
bottom-right) — no custom NPS-style bar needed, the built-in one covers it.
2026-09-10 22:14:40 +02:00
randy c9561a5489 Add an offline terrain shadow overlay to the Overlays panel
Shades the visible map by whether each point is currently blocked from
the sun by surrounding terrain (shademap.app-style), computed fully
offline via the same Terrarium DEM tiles the Terrain shading layer
already renders, plus this session's sun-position math and Radar's
checkbox+expandable UI shape.

dem.js pulls elevation-at-a-point out on its own since TODO.adoc's
slope readout and solar calculator will need the same lookup.
2026-09-10 21:43:51 +02:00
randy a8d58abaca Move Radar and Terrain shading into the Overlays panel
Both used to be their own separate sidebar icons; neither has
anything to manage beyond on/off, same as Wikipedia already got its
own Overlays entry for. Terrain shading is a plain checkbox item now.
Radar keeps its scrub/forecast controls, but behind an explicit
expand (clicking its name), separate from the checkbox — checking it
on shouldn't force the details open, and expanding to scrub/check the
forecast shouldn't also flip the layer on.

Both controls now build their own <li> (RadarControl.mount(li),
HillshadeControl.mount(li) — the latter moved into overlays.js
entirely, it has no reason to live in map.js once it's not building
its own sidebar icon) rather than a whole sidebar-item + flyout the
way they used to.

Also gave each Overlays item a leading icon: Wikipedia and Terrain
shading reuse existing NPS pictograms (WIKI_ICON, and WILDERNESS_ICON
newly exported from icons.js's forest entry — NPS has no dedicated
mountain/terrain glyph, wilderness-22.svg is the closest honest
match). Radar's is hand-drawn (a rain cloud) since NPS's set has
nothing weather-related to reuse.
2026-09-10 21:23:51 +02:00
randy dce5fd87da Add a Locus Pro-style toolbar readout: DMS coords + sunrise/sunset
The topbar's coordinate display was plain decimal degrees ("48.14611,
17.17722") — switched to DMS (48°08'46"N 17°10'38"E), the more
GPS-unit-like format Locus Pro itself uses, and made it click-to-copy
(plain decimal, since that's what pastes cleanly into another map/GPS
app — not the DMS text actually shown).

Added sunrise/sunset + a countdown to whichever's next, for the same
map-center point the coordinates already describe. Vendored SunCalc
(BSD-2-Clause, github.com/mourner/suncalc) rather than hand-rolling
the astronomical math — small, dependency-free, and correctness here
has real pitfalls (equation of time, refraction, polar day/night) a
first-pass reimplementation would risk getting subtly wrong.

Also added a test asserting every public/js/*.js module has a
versioned importmap entry in layout.erb — caught that overlays.js
(from the previous commit) was missing one, which would have quietly
skipped ASSET_VERSION's cache-busting for that file after every
deploy.
2026-09-10 21:08:02 +02:00
randy c5b4a9ffb2 Move the Wikipedia layer into its own "Overlays" panel
Wikipedia doesn't belong inside "Tracks & Points" — that panel is for
files you add/remove/reorder, while Wikipedia is a live layer with
nothing to manage, just on/off. Gave it its own sidebar panel
(#overlays-panel, same shell as LiveTrackPanelControl) instead, sized
to hold more such checklist-only layers later without a redesign.

Moved all the wiki layer logic out of GpxPanelControl into a new
OverlaysControl (public/js/overlays.js). svgToImageData/badgeImageId/
escapeHtml are now exported from gpx.js so it doesn't have to
reimplement them — the same three helpers a second overlay would also
need.
2026-09-10 20:54:40 +02:00
randy 787df5478d Replace the per-popup "Nearby on Wikipedia" link with a live Wikipedia layer
The old link only ever surfaced one nearby article at a time, buried
in whatever POI's popup you happened to open, and only for uploaded
files with a category. Replaced it with a standalone "Wikipedia"
toggle under the renamed "Tracks & Points" panel: enabling it adds a
live map layer that refetches GET /api/kiwix/nearby on every pan/zoom
and plots every nearby article as its own point.

kiwix-serve's own geo search never echoes back a result's coordinates
(confirmed live against the real production ZIM, both its HTML and
?format=xml output) — it only filters by distance from a point. So
Maptool::Kiwix.nearby fetches each matching article's own page too and
reads its <meta name="geo.position"> tag, which every geotagged
Wikipedia article carries. Tried parallelizing those per-article
fetches with threads first; measured no improvement against the real
ZIM (kiwix-serve appears to serialize requests regardless), so it
stayed sequential — ~1.6s for a 30-result page, fine for a
refetch-on-pan-end layer.

Clicking a point opens a small popup linking to the article (proxied
through the existing /kiwix/* passthrough). New WIKI_ICON (NPS's
bookstore-22.svg) marks these, kept out of POI_ICONS since that set
doubles as notes.js's icon-picker option list and this fixed-glyph
layer has no per-feature category to key off of.
2026-09-10 20:45:41 +02:00
randy 47e3f9c7e8 Update TODO.adoc for this session's work
CI / check (push) Successful in 41s
CI / deploy (push) Successful in 13s
Marks Park4Night (private plugin), the category-filter polygon/line
bug, and the overpass-pois icon/description work as done.
2026-09-09 18:22:28 +02:00
randy ea9cd5fc40 Fix three bugs found reviewing this session's changes
- notes.js's ICON_LABELS wasn't extended for the shop_supermarket/
  shop_convenience keys icons.js added — the note icon picker showed
  the raw internal key as the title instead of a real label.
- Plugins.run mislabeled a malformed plugin.json as "plugin did not
  print valid JSON" — a message written for bad script stdout, not a
  bad manifest, since both paths shared one rescue.
- overpass_pois.rb's description_for joined raw OSM tag values with
  "\n" — an operator/opening_hours tag with an embedded newline could
  inject an extra line into the popup that gpx.js's formatDescription
  (built for p4n2gpx's own well-formed lines) would render as its own
  independent, legitimate-looking link. Tag values are stripped of
  embedded newlines before joining.
2026-09-09 18:21:47 +02:00
randy 7c664578af Fix category filter not hiding polygon/line notes, only points
TODO.adoc had this flagged: toggling a category off in the legend only
re-sliced the points source (_applyCategoryFilter), so a polygon or
line note (Measure's "Save as note") sharing that category stayed
visible. Added _linesByPath alongside the existing _pointsByPath,
tracked/cleaned up the same way, and reused for both the legend's
category scan and the filter's re-slice.
2026-09-09 18:21:39 +02:00
randy d9cc468478 Show the actual plugin run error instead of a generic message
A failed run showed "Failed — see server log" regardless of why —
misleading, since a Plugins::RunError never actually reaches any log
(app.rb turns it straight into a 502 JSON response). Found this the
hard way debugging the p4n2gpx plugin, having to SSH in and reproduce
the run by hand each time just to see why it failed. Now shows the
response's actual error message (e.g. "plugin exited with status 1"),
wrapping instead of overflowing the flyout for a longer one.
2026-09-09 18:17:24 +02:00
randy 2c3dd4534e Add P4N_SESSION_COOKIE for p4n2gpx, since login alone can't work headless
CI / check (push) Successful in 40s
CI / deploy (push) Successful in 13s
Traced the plugin's "Login failed" error directly against
park4night.com: correct credentials still get rejected because the
login form is behind invisible reCAPTCHA, which only a real browser
ever satisfies. p4n2gpx.rb (outside this repo) now checks
P4N_SESSION_COOKIE first and uses it as-is, skipping the login POST
entirely — the cookie comes from an already-authenticated browser,
copied out by hand and refreshed when it expires. Wired the env var
through docker-compose.yaml and the deploy workflow's "Write .env"
step the same way as P4N_USER/P4N_PASSWORD.
2026-09-09 18:07:03 +02:00
randy 92cc0c87ed Wire up p4n2gpx as a private plugin
CI / check (push) Successful in 47s
CI / deploy (push) Successful in 1m53s
data/plugins/p4n2gpx/ (outside git, see .gitignore) now holds a
plugin.json + run.rb wrapper around ../p4n2gpx/ruby/p4n2gpx.rb, so it
runs through the same --south/--west/--north/--east-in,
GeoJSON-on-stdout-out contract as the built-in overpass-pois plugin.
run.rb converts the requested bbox to the center+radius p4n2gpx.rb
itself expects, then reuses lib/maptool/gpx.rb to turn its .gpx output
into GeoJSON.

p4n2gpx.rb needs faraday-cookie_jar, which wasn't in the Gemfile yet
(faraday itself already was, transitively via oauth2) — added and
locked. Also wires P4N_USER/P4N_PASSWORD through docker-compose.yaml
and the deploy workflow's "Write .env" step, the same optional-secret
pattern as LIVETRACK_WEBHOOK_SECRET, since the container has no
browser for p4n2gpx.rb's Chrome-cookie auth fallback.
2026-09-09 17:38:53 +02:00
randy 6e0b67f2a0 Support a persistent, private plugins directory alongside the built-in ones
CI / check (push) Successful in 41s
CI / deploy (push) Successful in 13s
plugins/ ships baked into the image and gets wiped/replaced by the
checkout sync on every deploy (docs/deployment.adoc), so a private
plugin dropped there — the exact use case the plugin contract was
designed for — didn't survive a redeploy the way uploaded GPX/kiwix
data under data/ does.

Plugins.list/run now accept either one directory or an array, and
app.rb checks the built-in plugins/ plus data/plugins/ (already
covered by the existing ./data bind mount, no new volume needed).
2026-09-09 17:24:52 +02:00
randy 1733fc7c1b Give Overpass POI downloads icons/descriptions and unique filenames
CI / check (push) Successful in 41s
CI / deploy (push) Successful in 12s
Overpass categories now carry the same icon+color styling a p4n2gpx
waypoint gets, instead of falling back to gpx.js's plain red marker,
plus a popup description built from opening_hours/operator/website
tags. Supermarket/convenience store reuse NPS's generic store glyph,
the only honest match in that icon set.

Each plugin run's saved filename now bakes in the area's center and a
timestamp, so repeated downloads for different areas land as separate,
identifiable files instead of overpass-pois.geojson/-1/-2/...
2026-09-09 17:14:20 +02:00
randy 72ffd0ef18 Add an import plugin system, with the Overpass POI query as its first plugin
CI / check (push) Successful in 40s
CI / deploy (push) Successful in 13s
A plugin is a directory under plugins/ with a plugin.json manifest
({"label": "...", "command": "./run.sh"}) plus a script that reads
--south/--west/--north/--east and prints a GeoJSON FeatureCollection
to stdout (lib/maptool/plugins.rb) — that's the entire interface a
plugin needs to know about this app. The sidebar's new import icon
(logged in only, GET /api/plugins + POST /api/plugins/:name/run) lists
whatever's found and runs one for the current map viewport, saving its
output as a new .geojson file the same way an upload would be.

The point: a scraper for a site whose ToS forbids that (Park4Night,
iOverlander, Freecampsites) doesn't need to live in this public repo
to work here — its own directory just goes under plugins/ locally and
is never git add'ed, no special-casing needed anywhere.

plugins/overpass-pois wraps the existing rake overpass:pois query as
the first, in-repo, reference example of the contract.

Also fills in four modules (auth.js, locate.js, measure.js, notes.js)
missing from layout.erb's cache-busting importmap alongside adding
plugins.js's own entry — a pre-existing gap that meant they could keep
serving a stale cached copy across a deploy despite the importmap
existing specifically to prevent that.
2026-09-09 16:23:31 +02:00
randy 2b49eda7cb Fix kiwix proxy 502ing on article links with non-ASCII titles
CI / check (push) Successful in 40s
CI / deploy (push) Successful in 12s
Sinatra decodes a route's splat before handing it to the block, so an
article link like /kiwix/content/wikipedia/Dlhé_diely arrived as raw
UTF-8, not percent-encoded. URI#path= rejects that outright
(URI::InvalidComponentError) rather than escaping it, which .proxy's
rescue turned into a silent nil -> every article link 502'd, while the
search results page linking to them worked fine (its own path,
/kiwix/search, is plain ASCII).
2026-09-09 15:55:48 +02:00
randy 5ff9b113d9 Proxy kiwix-serve through this app instead of linking to it directly
CI / check (push) Successful in 39s
CI / deploy (push) Successful in 12s
map.priesol.net sits behind a reverse proxy that only forwards to
maptool itself, so the previous approach (publish kiwix-serve's port,
link the browser straight at it) had no address a real browser could
ever reach — not just a Docker-internal hostname as first assumed, but
no host/port combination at all works from outside.

GET /kiwix/* now proxies to kiwix-serve (Kiwix.proxy in
lib/maptool/kiwix.rb, a plain Net::HTTP passthrough), and the kiwix
service runs with --urlRootLocation=/kiwix so every link/asset it
emits already carries that same prefix and needs no rewriting
(confirmed against libkiwix/internalServer.cpp, which strips this
exact prefix off incoming requests). Drops the port-publishing
approach from the previous commit entirely.
2026-09-09 15:29:08 +02:00
randy 9997a8a8c0 Fix note UX: unreachable wiki link, white Save hover, stale icon preview, invisible new points
CI / check (push) Successful in 41s
CI / deploy (push) Successful in 12s
- "Nearby on Wikipedia" linked to KIWIX_URL, a Docker-internal hostname
  (http://kiwix:8080) no real browser can resolve. Split it: KIWIX_URL
  stays server-side-only for the reachability check, and the link
  itself is built from KIWIX_PUBLIC_PORT (kiwix-serve's newly
  published host port) plus whatever host the visitor already used to
  reach maptool — works regardless of which hostname/IP that is.
- The Save button went white on hover in GTK-themed Chrome: the
  browser's native button skin was painting over the custom
  background because appearance wasn't reset.
- The map preview marker for a pending note always showed a plain red
  pin no matter which icon was picked in the form. NoteSaveForm now
  reports icon changes via onIconChange so NotesControl can update the
  marker's glyph live.
- Saving a note (or a Measure "Save as note") left the new/grown
  .geojson file unchecked and invisible until manually toggled on.
  notifyGpxStoreChanged now carries the affected path so
  GpxPanelControl auto-shows it.
2026-09-09 15:11:50 +02:00
randy 4f022ec43a Fix production outage: build context and kiwix arg duplication
CI / check (push) Successful in 40s
CI / deploy (push) Successful in 11s
docker-compose's build context resolves relative to the symlink's own
directory (/srv/podman/maptool/), same as volume paths — but the
checkout now lives one level down in build/, so "build: ." pointed at
the wrong place and compose up --build failed outright looking for a
Dockerfile that isn't there. Point it at ./build instead.

Also drop kiwix's explicit --port=8080: the image's own start.sh
already prepends its default --port=8080 before appending the command
array, so passing it again produced "Unexpected argument" and the
container never started.

Both applied directly to production to restore service, verified via
docker-compose config + live health checks.
2026-09-09 14:29:40 +02:00
randy 76e3239d54 Tidy the deploy checkout into build/, symlink docker-compose.yaml up
CI / check (push) Successful in 44s
CI / deploy (push) Canceled after 40s
Sources now sync into /srv/podman/maptool/build/ (wiped and fully
replaced every deploy, nothing in it needs preserving) instead of
directly into /srv/podman/maptool/ itself, where data/ and .env also
live — the old sync step had to specifically skip data/ by name to
avoid wiping it; this way there's nothing to skip.

docker-compose.yaml is symlinked (ln -sf, relative target) from
/srv/podman/maptool/ up to build/ — both for a human to still find it
at the top, and because that symlink's own location, not build/, is
what compose resolves ./data and .env's directory against. No changes
to docker-compose.yaml or the podman-compose@.service systemd unit's
WorkingDirectory needed.

Verified against a full local dry run of the new sync step (copy into
a fake build/, symlink up, confirm pre-existing data/ survives) and
`docker-compose config` against the real docker-compose.yaml through
that symlink — both volume mounts (./data, the kiwix ZIM path)
resolved to the sibling data/ directory as intended, not build/data.
2026-09-09 14:13:42 +02:00
randy c66ae8d2d0 Fix kiwix ZIM volume mount to work with a symlink
CI / check (push) Successful in 1m7s
CI / deploy (push) Successful in 14s
Bind-mounting data/kiwix/ (the directory) meant a symlink placed
inside it broke: the container has to resolve that symlink itself,
in its own filesystem, where the host path it points to doesn't
exist. Binding the exact data/kiwix/wikipedia.zim file path instead
resolves it on the host at mount time (plain mount(2) semantics), so
the real ZIM can live anywhere on the host without duplicating a
multi-GB file into this repo's data/ directory.
2026-09-09 14:01:39 +02:00
randy 24ac5931f8 Link POI popups to offline Wikipedia via kiwix-serve
CI / check (push) Successful in 40s
CI / deploy (push) Successful in 12s
lib/maptool/kiwix.rb: a small reachability check for an external
kiwix-serve instance. GET /api/kiwix reports it (same optional-
integration pattern as offline-tiles/terrain-tiles); the frontend
adds a "Nearby on Wikipedia" link to a point's popup pointing straight
at kiwix-serve's own geo search (GET /search?latitude=&longitude=
&distance=, confirmed from libkiwix's actual source rather than
guessed) — linked to directly, not proxied/embedded, since it already
has a full search UI of its own.

docker-compose.yaml: new `kiwix` service (ghcr.io/kiwix/kiwix-serve)
on the default network, KIWIX_URL wired to reach it by service name.
The ZIM itself isn't part of the repo (large, self-contained archive)
— data/kiwix/ gitignored same as the *.pmtiles files, setup steps in
docs/development.adoc.

No kiwix-serve/ZIM available here to test end-to-end — verified the
app side against a stand-in local HTTP server (GET /api/kiwix flips
available correctly) and confirmed the generated popup link matches
the real geo-search query shape. docker-compose.yaml validated with
`docker-compose config`. Full test suite: 118 runs, 0 failures.
2026-09-09 13:44:37 +02:00
randy 7cd3171998 Mark Park4Night-to-pictogram mapping as done, verified against real exports 2026-09-09 13:16:34 +02:00
randy 5576d2edf1 Note UX polish: pin marker, icon picker, fix Save button color
- The clicked location now stays marked (a plain maplibre-gl Marker,
  removed on save/cancel/deactivate) while the note form is open —
  before, nothing on the map showed where the pending note would land.
- POI_ICONS gains a dozen more symbols (water, dump station, toilets,
  playground, viewpoint, swimming, fishing, climbing, hiking, …) via
  Object.assign after PARK4NIGHT_TAGS' own icon constants are declared
  (they're below POI_ICONS in the file, so the literal itself can't
  reference them directly) — reused as real marker-badge glyphs, not
  just PARK4NIGHT_TAGS' inline description-tag icons. NoteSaveForm
  gets a picker grid for these, shown only for a Point note (a
  Measure-drawn line/polygon has no one spot for a badge).
- Fixed: .notes-panel__save's blue background was losing to
  .notes-panel__actions button's gray — same class-vs-class+element
  specificity trap .gpx-panel__action[hidden] already has a comment
  about elsewhere in this file. The button was never actually blue.

Verified live (properly simulating a logged-in session this time, via
Page.addScriptToEvaluateOnNewDocument rather than a post-load DOM
poke, since NotesControl's mount decision happens once, synchronously,
at page load): marker appears and clears correctly, 19 icons + "none"
render and select, Save renders #1a5fb4. Full suite: 115 runs, 0
failures.
2026-09-09 13:14:19 +02:00
107 changed files with 16240 additions and 506 deletions

No files matched your search

+34 -19
View File
@@ -6,7 +6,14 @@ on:
jobs: jobs:
check: check:
runs-on: ubuntu-latest # brick-build's job container now points at Gitea's own official
# runner image (docker.gitea.com/runner-images:ubuntu-latest, has
# Node out of the box) — the earlier opensuse/leap:16.0 image that
# failed here on 2026-09-12 (no Node, every step below is a JS-based
# Action) got repointed. Pinned to brick specifically again, rather
# than the shared ubuntu-latest label "Gitea Runner on Cube" also
# answers to.
runs-on: brick-build
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -34,13 +41,13 @@ jobs:
run: find public/js -name "*.js" -print0 | xargs -0 -n1 node --check run: find public/js -name "*.js" -print0 | xargs -0 -n1 node --check
# Handled by a separate, native (non-Docker) runner registered with the # Handled by a separate, native (non-Docker) runner registered with the
# single "cube-host" label (see docs/deployment.adoc) — it runs directly # single "brick-host" label (see docs/deployment.adoc) — it runs directly
# on the server, so it has podman/git/etc. from the host, no socket/bind # on the server, so it has podman/git/etc. from the host, no socket/bind
# mount tricks needed. The Docker-based runner keeps handling `check`. # mount tricks needed. The Docker-based runner keeps handling `check`.
deploy: deploy:
needs: check needs: check
if: github.event_name == 'push' && github.ref == 'refs/heads/main' if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: cube-host runs-on: brick-host
steps: steps:
# Not actions/checkout@v4: keeping this plain-git checkout from when # Not actions/checkout@v4: keeping this plain-git checkout from when
# the job ran in a Node-less container — no reason to add a Node # the job ran in a Node-less container — no reason to add a Node
@@ -62,21 +69,26 @@ jobs:
- name: Write REVISION - name: Write REVISION
run: git rev-parse --short HEAD > REVISION run: git rev-parse --short HEAD > REVISION
# Clears out everything in the target except data/ (uploaded GPX # The checkout lives in build/, wiped and fully replaced every
# files, offline.pmtiles) and copies the fresh checkout over, dropping # deploy — data/ and .env live one level up, in /srv/podman/maptool/
# .git afterwards. Dotfiles like .env (deployment secrets) are left # itself, so they're never inside the directory this nukes and never
# alone too — the glob below doesn't match them — and neither is ever # need special-casing here (an earlier version of this step had to
# part of the git checkout in the first place, since both are # skip data/ by name for exactly that reason). docker-compose.yaml
# gitignored. # itself is symlinked up to /srv/podman/maptool/ (relative target, so
- name: Sync to /srv/podman/maptool # it survives /srv/podman itself ever being renamed) purely for
# discoverability — a human poking around expects to find it at the
# top, not a level down — and because that's what makes `./data` in
# it resolve to the sibling directory: compose resolves a relative
# volume path against the *symlink's* location, not build/ (verified
# against plain `docker-compose config`), so podman-compose@.service's
# own WorkingDirectory=/srv/podman/maptool needs no change either.
- name: Sync to /srv/podman/maptool/build
run: | run: |
mkdir -p /srv/podman/maptool rm -rf /srv/podman/maptool/build
for f in /srv/podman/maptool/*; do mkdir -p /srv/podman/maptool/build
[ "$(basename "$f")" = "data" ] && continue cp -a . /srv/podman/maptool/build/
rm -rf "$f" rm -rf /srv/podman/maptool/build/.git
done ln -sf build/docker-compose.yaml /srv/podman/maptool/docker-compose.yaml
cp -a . /srv/podman/maptool/
rm -rf /srv/podman/maptool/.git
# Regenerated on every deploy from repo secrets (Settings -> Actions # Regenerated on every deploy from repo secrets (Settings -> Actions
# -> Secrets) rather than created once by hand on the server — see # -> Secrets) rather than created once by hand on the server — see
@@ -94,6 +106,9 @@ jobs:
GITEA_OAUTH_CLIENT_SECRET=${{ secrets.OAUTH_CLIENT_SECRET }} GITEA_OAUTH_CLIENT_SECRET=${{ secrets.OAUTH_CLIENT_SECRET }}
MAPTOOL_ALLOWED_GITEA_USER=${{ secrets.MAPTOOL_ALLOWED_GITEA_USER }} MAPTOOL_ALLOWED_GITEA_USER=${{ secrets.MAPTOOL_ALLOWED_GITEA_USER }}
LIVETRACK_WEBHOOK_SECRET=${{ secrets.LIVETRACK_WEBHOOK_SECRET }} LIVETRACK_WEBHOOK_SECRET=${{ secrets.LIVETRACK_WEBHOOK_SECRET }}
P4N_USER=${{ secrets.P4N_USER }}
P4N_PASSWORD=${{ secrets.P4N_PASSWORD }}
P4N_SESSION_COOKIE=${{ secrets.P4N_SESSION_COOKIE }}
EOF EOF
chmod 600 /srv/podman/maptool/.env chmod 600 /srv/podman/maptool/.env
@@ -106,14 +121,14 @@ jobs:
# layers (apt-get/bundle install) as cache — unlike explicitly # layers (apt-get/bundle install) as cache — unlike explicitly
# removing the image first, which would delete that cache along with # removing the image first, which would delete that cache along with
# it. sudo is needed since the unit is root's, not gitea-runner's own # it. sudo is needed since the unit is root's, not gitea-runner's own
# (gitea-runner has passwordless sudo for this on cube-host). # (gitea-runner has passwordless sudo for this on brick-host).
- name: Deploy - name: Deploy
run: sudo systemctl restart podman-compose@maptool.service run: sudo systemctl restart podman-compose@maptool.service
# systemctl restart above only confirms the process forked # systemctl restart above only confirms the process forked
# (Type=simple, no readiness protocol) — not that `podman compose up # (Type=simple, no readiness protocol) — not that `podman compose up
# --build` actually finished and Puma is answering. Polls the health # --build` actually finished and Puma is answering. Polls the health
# endpoint (cube-host itself, same machine the container's port is # endpoint (brick-host itself, same machine the container's port is
# published on) instead of trusting that — checking for this # published on) instead of trusting that — checking for this
# deploy's own revision, not just any 200, so a stuck old container # deploy's own revision, not just any 200, so a stuck old container
# that never got torn down can't pass as a successful deploy of the # that never got torn down can't pass as a successful deploy of the
+20 -12
View File
@@ -8,17 +8,25 @@ on:
jobs: jobs:
renovate: renovate:
# The native deploy runner (see docs/deployment.adoc) already has # Same reasoning as check's runs-on in ci.yml: brick-build's job
# Docker access — Renovate itself is a one-shot batch job, not a # container now has Node (repointed at Gitea's own official runner
# long-running service, so `docker run`, not docker-compose. # image), which setup-node/npm below need.
runs-on: deploy runs-on: brick-build
steps: steps:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "22"
- name: Install Renovate
run: npm install -g renovate
- name: Run Renovate - name: Run Renovate
run: | run: renovate
docker run --rm \ env:
-e RENOVATE_PLATFORM=gitea \ RENOVATE_PLATFORM: gitea
-e RENOVATE_ENDPOINT="${{ gitea.server_url }}/api/v1/" \ RENOVATE_ENDPOINT: "${{ gitea.server_url }}/api/v1/"
-e RENOVATE_TOKEN="${{ secrets.RENOVATE_TOKEN }}" \ RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
-e RENOVATE_REPOSITORIES="${{ gitea.repository }}" \ RENOVATE_REPOSITORIES: "${{ gitea.repository }}"
-e RENOVATE_ONBOARDING=false \ RENOVATE_ONBOARDING: "false"
renovate/renovate GITHUB_COM_TOKEN: ${{ secrets.GITHUB_COM_TOKEN }}
+22
View File
@@ -12,6 +12,22 @@
# see docs/development.adoc) # see docs/development.adoc)
/data/*.pmtiles /data/*.pmtiles
# Per-country .osm.pbf cache for offline.pmtiles rebuilds (also large,
# also local-only — see PmtilesBuilder.cached_extract)
/data/geofabrik_cache/
# Planetiler's own auxiliary-source cache and scratch working directory
# (water polygons/Natural Earth/lake centerlines, --download; temp feature
# DBs, --tmpdir) — relative to the app's CWD, which lands them here
# alongside the rest of data/ (see extract_offline's --download comment)
/data/sources/
/data/tmp/
# Offline Wikipedia ZIM for kiwix-serve (also large, also local-only —
# same story, see docs/development.adoc)
/data/kiwix/*
!/data/kiwix/.gitkeep
# User-uploaded GPX files # User-uploaded GPX files
/data/gpx/* /data/gpx/*
!/data/gpx/.gitkeep !/data/gpx/.gitkeep
@@ -19,6 +35,12 @@
# Garmin LiveTrack session IDs received via webhook # Garmin LiveTrack session IDs received via webhook
/data/livetrack.json /data/livetrack.json
# Private import plugins (see lib/maptool/plugins.rb's PLUGINS_DIRS,
# docs/deployment.adoc) — a plugin whose ToS forbids living in this public
# repo belongs here instead, outside git entirely.
/data/plugins/*
!/data/plugins/.gitkeep
# Editor / OS # Editor / OS
.DS_Store .DS_Store
*.swp *.swp
+40 -2
View File
@@ -1,11 +1,49 @@
FROM ruby:4.0.6-slim-bookworm # trixie, not bookworm: Planetiler needs Java 21+ (UnsupportedClassVersionError
# otherwise) and bookworm's own default-jre-headless is only Java 17 —
# bookworm-backports doesn't carry a newer one either, only trixie's does.
FROM ruby:4.0.6-slim-trixie
# build-essential: puma has a native (C) extension; harmless if the # build-essential: puma has a native (C) extension; harmless if the
# platform-specific gem in Gemfile.lock already has a precompiled binary # platform-specific gem in Gemfile.lock already has a precompiled binary
# matching this base image, but keeps the build working if it doesn't. # matching this base image, but keeps the build working if it doesn't.
RUN apt-get update && apt-get install --no-install-recommends -y build-essential \ # ca-certificates/curl: needed for the go-pmtiles/planetiler.jar downloads
# below (also handy for anyone debugging inside a running container).
# default-jre-headless: Planetiler is a JVM tool (see PLANETILER_VERSION
# below) — headless since this never touches a display; trixie's version
# of this package is Java 21, see above.
# osmium-tool: merges multiple countries' OSM extracts into one file before
# handing them to Planetiler (lib/maptool/pmtiles_builder.rb) — a normal
# Debian package, no separate download/pinning needed like the other two.
RUN apt-get update && apt-get install --no-install-recommends -y build-essential ca-certificates curl default-jre-headless osmium-tool \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# The `pmtiles` CLI (lib/maptool/pmtiles_builder.rb's "Regenerate for
# current view" — see docs/development.adoc) — no Debian package exists,
# so this pulls the static binary straight from its own GitHub releases.
# Architecture-matched (Debian's dpkg arch name translated to the release
# asset's own naming) rather than hardcoded amd64, so this still works
# building on an arm64 host. Pinned, like every other dependency in this
# repo (Gemfile, docs/third-party-notices.adoc) — bump PMTILES_VERSION
# deliberately, not via `latest`.
ARG PMTILES_VERSION=1.31.2
RUN set -eux; \
case "$(dpkg --print-architecture)" in \
amd64) pmtiles_arch=x86_64 ;; \
arm64) pmtiles_arch=arm64 ;; \
*) echo "unsupported architecture for go-pmtiles: $(dpkg --print-architecture)" >&2; exit 1 ;; \
esac; \
curl -fsSL "https://github.com/protomaps/go-pmtiles/releases/download/v${PMTILES_VERSION}/go-pmtiles_${PMTILES_VERSION}_Linux_${pmtiles_arch}.tar.gz" \
| tar xz -C /usr/local/bin pmtiles
# Planetiler (lib/maptool/pmtiles_builder.rb's offline.pmtiles build,
# replacing an earlier Protomaps-CDN-based pipeline — see
# docs/development.adoc) — a single JVM fat jar, no per-arch variant needed
# unlike go-pmtiles above. Default PLANETILER_JAR path (pmtiles_builder.rb)
# expects it here.
ARG PLANETILER_VERSION=0.10.2
RUN curl -fsSL "https://github.com/onthegomap/planetiler/releases/download/v${PLANETILER_VERSION}/planetiler.jar" \
-o /usr/local/lib/planetiler.jar
WORKDIR /app WORKDIR /app
COPY Gemfile Gemfile.lock ./ COPY Gemfile Gemfile.lock ./
+2
View File
@@ -15,3 +15,5 @@ group :test do
gem "minitest", "~> 6.0" gem "minitest", "~> 6.0"
gem "rake", "~> 13.0" gem "rake", "~> 13.0"
end end
gem "faraday-cookie_jar", "~> 0.0.8"
+10
View File
@@ -7,11 +7,15 @@ GEM
version_gem (~> 1.1, >= 1.1.14) version_gem (~> 1.1, >= 1.1.14)
base64 (0.3.0) base64 (0.3.0)
bigdecimal (4.1.2) bigdecimal (4.1.2)
domain_name (0.6.20260902)
drb (2.2.3) drb (2.2.3)
faraday (2.14.3) faraday (2.14.3)
faraday-net_http (>= 2.0, < 3.5) faraday-net_http (>= 2.0, < 3.5)
json json
logger logger
faraday-cookie_jar (0.0.8)
faraday (>= 0.8.0)
http-cookie (>= 1.0.0)
faraday-net_http (3.4.4) faraday-net_http (3.4.4)
net-http (~> 0.5) net-http (~> 0.5)
ffi (1.17.4-aarch64-linux-gnu) ffi (1.17.4-aarch64-linux-gnu)
@@ -26,6 +30,8 @@ GEM
ffi (1.17.4-x86_64-linux-musl) ffi (1.17.4-x86_64-linux-musl)
hashie (5.1.0) hashie (5.1.0)
logger logger
http-cookie (1.1.6)
domain_name (~> 0.5)
json (2.21.2) json (2.21.2)
jwt (3.2.0) jwt (3.2.0)
base64 base64
@@ -106,6 +112,7 @@ PLATFORMS
x86_64-linux-musl x86_64-linux-musl
DEPENDENCIES DEPENDENCIES
faraday-cookie_jar (~> 0.0.8)
minitest (~> 6.0) minitest (~> 6.0)
oauth2 (~> 2.0) oauth2 (~> 2.0)
puma (~> 8.0) puma (~> 8.0)
@@ -122,8 +129,10 @@ CHECKSUMS
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd
bundler (4.0.18) sha256=02d9a17429de1847b4e0c9f27a9ee4b20c0a74c0a641b4e77195d6019e3618ac bundler (4.0.18) sha256=02d9a17429de1847b4e0c9f27a9ee4b20c0a74c0a641b4e77195d6019e3618ac
domain_name (0.6.20260902) sha256=4fac7f8e0a77dc85ec02f6534fdeff38e143d434ab8a86528fe68ca5bc45a042
drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373 drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
faraday (2.14.3) sha256=1882247e6766615c8220b4392bf1d27f6ebb63d8e28267587cef1fb0bf37f278 faraday (2.14.3) sha256=1882247e6766615c8220b4392bf1d27f6ebb63d8e28267587cef1fb0bf37f278
faraday-cookie_jar (0.0.8) sha256=0140605823f8cc63c7028fccee486aaed8e54835c360cffc1f7c8c07c4299dbb
faraday-net_http (3.4.4) sha256=0e78af151747ed1b00f33e25973b4bc220d7f16c00c39676817c8b12331eb588 faraday-net_http (3.4.4) sha256=0e78af151747ed1b00f33e25973b4bc220d7f16c00c39676817c8b12331eb588
ffi (1.17.4-aarch64-linux-gnu) sha256=b208f06f91ffd8f5e1193da3cae3d2ccfc27fc36fba577baf698d26d91c080df ffi (1.17.4-aarch64-linux-gnu) sha256=b208f06f91ffd8f5e1193da3cae3d2ccfc27fc36fba577baf698d26d91c080df
ffi (1.17.4-aarch64-linux-musl) sha256=9286b7a615f2676245283aef0a0a3b475ae3aae2bb5448baace630bb77b91f39 ffi (1.17.4-aarch64-linux-musl) sha256=9286b7a615f2676245283aef0a0a3b475ae3aae2bb5448baace630bb77b91f39
@@ -136,6 +145,7 @@ CHECKSUMS
ffi (1.17.4-x86_64-linux-gnu) sha256=9d3db14c2eae074b382fa9c083fe95aec6e0a1451da249eab096c34002bc752d ffi (1.17.4-x86_64-linux-gnu) sha256=9d3db14c2eae074b382fa9c083fe95aec6e0a1451da249eab096c34002bc752d
ffi (1.17.4-x86_64-linux-musl) sha256=3fdf9888483de005f8ef8d1cf2d3b20d86626af206cbf780f6a6a12439a9c49e ffi (1.17.4-x86_64-linux-musl) sha256=3fdf9888483de005f8ef8d1cf2d3b20d86626af206cbf780f6a6a12439a9c49e
hashie (5.1.0) sha256=c266471896f323c446ea8207f8ffac985d2718df0a0ba98651a3057096ca3870 hashie (5.1.0) sha256=c266471896f323c446ea8207f8ffac985d2718df0a0ba98651a3057096ca3870
http-cookie (1.1.6) sha256=ba4b82be64de61dc281243dac70e3c382c45142f20268ed9276a3670c93feaa9
json (2.21.2) sha256=1f1d3b7cf2b3ba1a69beca0bb6db13d5438b80bff3cd54cdaaa620b9b07c1c6a json (2.21.2) sha256=1f1d3b7cf2b3ba1a69beca0bb6db13d5438b80bff3cd54cdaaa620b9b07c1c6a
jwt (3.2.0) sha256=5419b1fe37b1da0982bd07051f573a8b8789ab724c2aa7e785e4784a3ed217d7 jwt (3.2.0) sha256=5419b1fe37b1da0982bd07051f573a8b8789ab724c2aa7e785e4784a3ed217d7
listen (3.10.0) sha256=c6e182db62143aeccc2e1960033bebe7445309c7272061979bb098d03760c9d2 listen (3.10.0) sha256=c6e182db62143aeccc2e1960033bebe7445309c7272061979bb098d03760c9d2
+16
View File
@@ -24,6 +24,22 @@ namespace :overpass do
end end
end end
namespace :hiking do
desc "Extract route=hiking relations (name/colour/network/operator, full geometry) from a local " \
".osm.pbf (e.g. one of PmtilesBuilder's own data/geofabrik_cache/*.osm.pbf) and write GeoJSON. " \
"Prototype — see lib/maptool/hiking_trails.rb. Usage: rake hiking:trails[input.osm.pbf,out.geojson]"
task :trails, %i[pbf out] do |_t, args|
%i[pbf out].each { |key| abort("usage: rake hiking:trails[input.osm.pbf,out.geojson]") unless args[key] }
require_relative "lib/maptool/hiking_trails"
puts "Extracting hiking routes from #{args[:pbf]}..."
geojson = Maptool::HikingTrails.extract(args[:pbf])
File.write(args[:out], JSON.generate(geojson))
puts "Wrote #{geojson["features"].size} route(s) to #{args[:out]}"
end
end
namespace :gpx do namespace :gpx do
desc "Backfill properties.id on Note-category features saved before edit/delete (and its id targeting) existed" desc "Backfill properties.id on Note-category features saved before edit/delete (and its id targeting) existed"
task :backfill_note_ids do task :backfill_note_ids do
+24 -6
View File
@@ -8,25 +8,31 @@ independence from connectivity.
== Offline data and cartography == Offline data and cartography
* [ ] Offline vector tiles (PMTiles/MBTiles) for Europe/world via Planetiler or MapTiler * [x] Offline vector tiles (PMTiles/MBTiles) for Europe/world via Planetiler or MapTiler — Geofabrik per-country extracts, `osmium merge`, Planetiler's default OpenMapTiles profile straight to PMTiles (`lib/maptool/pmtiles_builder.rb`); offline now shares the exact same style/palette as online (`ONLINE_STYLE_PATCH`) instead of a separate protomaps-schema theme
* [x] Shaded relief / DEM layer — hillshade toggle in the sidebar, sourced from public Terrarium tiles online; reads `data/terrain.pmtiles` for offline if one's been generated (see docs/development.adoc), otherwise the toggle is online-only for now * [x] Shaded relief / DEM layer — hillshade toggle in the sidebar, sourced from public Terrarium tiles online; reads `data/terrain.pmtiles` for offline if one's been generated (see docs/development.adoc), otherwise the toggle is online-only for now
** [ ] Terrain slope readout for parking (numeric, not just visual shading) ** [ ] Terrain slope readout for parking (numeric, not just visual shading)
* [ ] Contour lines from OSM for hikes and mountain passes * [ ] Contour lines from OSM for hikes and mountain passes
* [x] Overpass/OSM scripts to extract POIs (drinking water, dump stations, LPG, public toilets, laundromats, shops, springs) — `rake overpass:pois`, see docs/development.adoc; writes a `.geojson` to drop in `data/gpx/` or upload, not called by the running app itself * [x] Hiking trail overlay — Waymarked Trails raster tiles online (`public/js/hiking_trails.js`), colored per-route by the OSM `colour` tag they already render (the KST/KČT paint-blaze colors in Slovakia/Czechia, plain red elsewhere). Click queries a one-off Overpass `around` search (racing 3 public mirrors) for the route's name/colour/network/operator/distance
* [ ] Import Park4Night / iOverlander / Freecampsites data ** [x] Offline copy wired in for real, no custom Planetiler profile needed — `Maptool::HikingTrails` (`lib/maptool/hiking_trails.rb`) runs `osmium tags-filter r/route=hiking` + `add-locations-to-ways` + `cat -f opl` against the *same* per-country Geofabrik `.osm.pbf` already downloaded for `offline.pmtiles`, no new download. One `data/hiking_trails/<CODE>.geojson` per country (not one combined file), generated as the last step of every offline build and cached like `geofabrik_cache` (skipped once already newer than its source PBF) — a many-country selection no longer means one giant file, since `GET /api/hiking-trails` lists available countries and the Overlays panel's own checklist only fetches `GET /tiles/hiking_trails/<CODE>.geojson` for whichever ones get ticked. Offline click uses a local `queryRenderedFeatures` hit-test instead of Overpass — instant, no network. See docs/development.adoc
* [ ] Kiwix/ZIM offline Wikipedia linked to POI GPS coordinates * [x] Overpass/OSM scripts to extract POIs (drinking water, dump stations, LPG, public toilets, laundromats, shops, springs) — `rake overpass:pois`, see docs/development.adoc; writes a `.geojson` to drop in `data/gpx/` or upload. Also runnable from inside the app itself now, see the import plugins entry below (`plugins/overpass-pois` wraps this same query). Each category now carries a real `POI_ICONS` glyph and color (not p4n2gpx's plain red marker) plus a popup description built from opening_hours/operator/website tags
* [x] Import plugins: a pluggable way to add more data sources (Park4Night, iOverlander, Freecampsites, ...) without their scrapers necessarily living in this (public) repo — sidebar icon (logged in only) lists whatever's under `plugins/`, "Run for this area" uses the current map viewport as the bbox, no separate area-picker needed. Contract: a `plugin.json` manifest + a script that reads `--south`/`--west`/`--north`/`--east` and prints a GeoJSON `FeatureCollection` to stdout (`lib/maptool/plugins.rb`, `GET /api/plugins`, `POST /api/plugins/:name/run`) — output saved the same way an upload would be. `plugins/overpass-pois` ships as the reference example; a private/ToS-sensitive scraper just drops its own directory in locally and is never `git add`ed
** [x] Park4Night — private plugin (`data/plugins/p4n2gpx/`, outside this repo per the "ToS-sensitive scraper" note above); iOverlander/Freecampsites still open, same story
** [x] A private plugin's own dependencies now have somewhere to live too: `data/plugins/` is under the persistent `data/` bind mount (survives a redeploy, unlike `build/`), and `docs/deployment.adoc` documents the convention
* [x] Kiwix/ZIM offline Wikipedia linked to POI GPS coordinates — proxied through this app (`GET /kiwix/*` in app.rb) rather than a direct link to kiwix-serve — production sits behind a reverse proxy that only forwards to this app, so no address exists for a browser to reach kiwix-serve at directly; kiwix-serve runs with `--urlRootLocation=/kiwix` so its own emitted links already match. `KIWIX_URL` + `GET /api/kiwix` reachability check, same optional-integration pattern as offline.pmtiles/terrain.pmtiles; `docker-compose.yaml` now runs a `kiwix` service, ZIM not included (see docs/development.adoc for where to get one)
** [x] Replaced the old per-popup "Nearby on Wikipedia" link (one POI at a time, easy to miss) with a standalone "Wikipedia" layer under Tracks & Points — a live `GET /api/kiwix/nearby` refetch on every pan/zoom, not a saved file. kiwix-serve's own geo search never echoes back a result's coordinates, so `Maptool::Kiwix.nearby` fetches each matching article's own page too and reads its `<meta name="geo.position">` tag — verified against the real production ZIM (~1.6s for a 30-result page; tried parallelizing those fetches with threads, no measured gain, kept sequential)
* [x] Cache weather forecast when temporarily connected — Open-Meteo 3-day forecast in the Radar flyout, last successful fetch cached in localStorage as a fallback when offline * [x] Cache weather forecast when temporarily connected — Open-Meteo 3-day forecast in the Radar flyout, last successful fetch cached in localStorage as a fallback when offline
** [x] Cache the radar tile *images* too — `public/sw.js`, network-falling-back-to-cache for RainViewer tile requests, registered from layout.erb ** [x] Cache the radar tile *images* too — `public/sw.js`, network-falling-back-to-cache for RainViewer tile requests, registered from layout.erb
== NPS visual style == NPS visual style
* [ ] Map Park4Night/OSM place types to NPS pictograms (campground, primitive camp, drinking water, dump station, viewpoint, picnic table) for instant recognition without reading text * [x] Map Park4Night/OSM place types to NPS pictograms (campground, primitive camp, drinking water, dump station, viewpoint, picnic table) for instant recognition without reading text — verified against real p4n2gpx exports (`data/gpx/p4n_*.gpx`, ~5000 waypoints, 15 distinct `<type>` values): every one already resolves to a registered `POI_ICONS` key, 0 waypoints fall back iconless. Drinking water/dump station aren't standalone p4n place types (they're description tags on a camping spot, already shown via `PARK4NIGHT_TAGS`); viewpoint doesn't appear in these exports but has an icon (`tourism_viewpoint`) ready if it ever does
* [ ] Restyle popovers, side panels, and point detail views after the NPS Unigrid layout system (Massimo Vignelli) with Frutiger/Rawlinson Roadside-style typography * [ ] Restyle popovers, side panels, and point detail views after the NPS Unigrid layout system (Massimo Vignelli) with Frutiger/Rawlinson Roadside-style typography
** [x] Top black banner (full width): "MAPTOOL" on the left, live map-center coordinates in the center, offline-data status dot on the right, white sans-serif type — DEM elevation and a hamburger menu skipped (no DEM layer yet; sidebar isn't mobile-collapsed, so nothing for a hamburger to reveal) ** [x] Top black banner (full width): "MAPTOOL" on the left, live map-center coordinates in the center, offline-data status dot on the right, white sans-serif type — DEM elevation and a hamburger menu skipped (no DEM layer yet; sidebar isn't mobile-collapsed, so nothing for a hamburger to reveal)
** [ ] Point detail/sidepanel: black header banner with white location name and an NPS pictogram in the corner; amenities (water, waste, power, slope) shown as a pictogram grid, no extra text; action buttons for "route here" (Valhalla), "start leveling", "save offline" ** [ ] Point detail/sidepanel: black header banner with white location name and an NPS pictogram in the corner; amenities (water, waste, power, slope) shown as a pictogram grid, no extra text; action buttons for "route here" (Valhalla), "start leveling", "save offline"
** [x] Filter panel as a "Unigrid Matrix" — an icon grid to toggle categories on/off, styled like the legend on an official NPS paper map, instead of plain dropdowns ** [x] Filter panel as a "Unigrid Matrix" — an icon grid to toggle categories on/off, styled like the legend on an official NPS paper map, instead of plain dropdowns
* [ ] Custom vector style (MVT/MapLibre) using the NPS color palette — muted natural tones for forests, water, and contours — so POIs and routes stand out at high zoom * [ ] Custom vector style (MVT/MapLibre) using the NPS color palette — muted natural tones for forests, water, and contours — so POIs and routes stand out at high zoom
** [ ] Landuse & protections: distinct styling for national parks, nature reserves (translucent green/gray-green), military zones, and private land (important for wild camping) ** [ ] Landuse & protections: distinct styling for national parks, nature reserves (translucent green/gray-green), military zones, and private land (important for wild camping)
** [ ] OpenTopoMap-style `fill-pattern` texture for forest (tree icons) and meadow/pasture (grass texture) landcover, instead of flat fill colors — Liberty's own sprite (`public/vendor/liberty-sprite/`) only has a `wetland` dot pattern, no tree/grass, so this needs custom pattern images added to the sprite sheet; works offline and online alike since it's just a style/sprite change, unlike pulling in OpenTopoMap's own raster tiles (online-only, restrictive tile-usage policy, wouldn't match the NPS palette)
** [x] Elevation-tinted terrain — a `color-relief` layer (hypsometric tint, this app's own green→brown→gray palette) under the hillshade layer, same "Terrain shading" toggle ** [x] Elevation-tinted terrain — a `color-relief` layer (hypsometric tint, this app's own green→brown→gray palette) under the hillshade layer, same "Terrain shading" toggle
** [x] Road hierarchy: clearly distinguish paved roads from unpaved/gravel/track — critical for knowing if the camper can get there ** [x] Road hierarchy: clearly distinguish paved roads from unpaved/gravel/track — critical for knowing if the camper can get there
@@ -47,7 +53,10 @@ independence from connectivity.
** [x] Fixed: a note saved before `properties.id` existed (the earliest test notes) had no Edit/Delete-able target — the popup no longer offers them without an id, and `rake gpx:backfill_note_ids` assigns one to any pre-existing Note feature missing it ** [x] Fixed: a note saved before `properties.id` existed (the earliest test notes) had no Edit/Delete-able target — the popup no longer offers them without an id, and `rake gpx:backfill_note_ids` assigns one to any pre-existing Note feature missing it
** [x] Title + body split (name in the black header, body in a separate field) with light self-authored markdown (`**bold**`, `*italic*`, auto-linked URLs) in the body — a *new*, separate `formatNoteBody` (not `formatDescription`, which stays plain/untrusted-safe for uploaded GPX/park4night content per docs/nps-resources.adoc's earlier markdown-rendering call) ** [x] Title + body split (name in the black header, body in a separate field) with light self-authored markdown (`**bold**`, `*italic*`, auto-linked URLs) in the body — a *new*, separate `formatNoteBody` (not `formatDescription`, which stays plain/untrusted-safe for uploaded GPX/park4night content per docs/nps-resources.adoc's earlier markdown-rendering call)
** [x] Gated behind login: NotesControl isn't added to the map at all when logged out, Measure's "Save as note" button is hidden (Measure itself stays usable either way) ** [x] Gated behind login: NotesControl isn't added to the map at all when logged out, Measure's "Save as note" button is hidden (Measure itself stays usable either way)
** [ ] The Unigrid Matrix category filter only re-slices the *points* source (`_applyCategoryFilter`) — toggling the "Note" category off hides point notes but not polygon/line ones sharing that category ** [x] The clicked point stays marked on the map while the note form is open (a plain `Marker`, removed on save/cancel/deactivate) — it was disappearing back into the flat map with nothing showing where the note would land
** [x] Icon picker for point notes (a grid in the save form) — extends `POI_ICONS` with more of the symbols `PARK4NIGHT_TAGS` already vendors (water, dump station, toilets, playground, viewpoint, swimming, fishing, climbing, hiking, …), reusable as real marker-badge glyphs, not just inline tag icons. Hidden for a Measure-drawn line/polygon note — no single spot for a badge to sit at
** [x] Fixed: the Save button's own blue background was losing to `.notes-panel__actions button`'s gray — same class-vs-class+element specificity trap as `.gpx-panel__action[hidden]` already has a comment about elsewhere in this file, just not yet applied here
** [x] Fixed: the Unigrid Matrix category filter only re-sliced the *points* source (`_applyCategoryFilter`) — toggling the "Note" category off hid point notes but not polygon/line ones sharing that category. `_linesByPath` now tracks those alongside `_pointsByPath`, re-sliced/scanned the same way
* [ ] Offline satellite tile caching (e.g. ESRI) for a selected route area — key for judging surface quality and obstacles when wild camping * [ ] Offline satellite tile caching (e.g. ESRI) for a selected route area — key for judging surface quality and obstacles when wild camping
== Nice to have (later) == Nice to have (later)
@@ -64,3 +73,12 @@ Deprioritized for now — revisit after the sections above land.
* [ ] Level gauge from IMU (ESP32/RPi) — camper tilt, wheel-chock leveling calculation * [ ] Level gauge from IMU (ESP32/RPi) — camper tilt, wheel-chock leveling calculation
* [ ] Victron/Home Assistant via MQTT or WebSocket — battery SoC, tank levels, temperatures * [ ] Victron/Home Assistant via MQTT or WebSocket — battery SoC, tank levels, temperatures
* [ ] Plot GPS track with historical battery/speed data * [ ] Plot GPS track with historical battery/speed data
== Admin / ops tooling
* [ ] Offline build log readability — a failed pmtiles/terrain build currently surfaces as one
~500k-character line; format it for the web UI instead (e.g. per-country/state name + status,
not the raw combined stdout/stderr dump)
* [ ] Expose the build log via an API endpoint, not just embedded in the admin page
* [ ] Document all API endpoints somewhere and make them easy to browse (status of each) —
maybe a status page, login-gated
+316 -7
View File
@@ -10,8 +10,45 @@ require_relative "lib/maptool/gpx_store"
require_relative "lib/maptool/gpsd_client" require_relative "lib/maptool/gpsd_client"
require_relative "lib/maptool/livetrack_store" require_relative "lib/maptool/livetrack_store"
require_relative "lib/maptool/livetrack_client" require_relative "lib/maptool/livetrack_client"
require_relative "lib/maptool/kiwix"
require_relative "lib/maptool/plugins"
require_relative "lib/maptool/pmtiles_builder"
module Maptool module Maptool
# Only /login, /auth/callback and /logout ever write to session
# (oauth_state, user, session.clear) — everything else only ever reads
# it, if it touches session at all. That still matters:
# Rack::Session::Cookie re-serializes and re-sets the cookie on *every*
# response that so much as read session (Rack::Protection's own CSRF
# check does, on nearly every request) — reflecting whatever cookie
# that particular request happened to arrive with, whether or not
# anything changed. A HAR capture caught the actual failure mode this
# caused: seconds after a successful login, a background poll fired the
# instant the page loads was still carrying the browser's pre-login
# cookie (a client-side timing race across the OAuth redirect chain,
# not something this server controls), and its own re-issued Set-Cookie
# landed *after* the login's, silently overwriting session[:user] with
# nothing logged anywhere to explain it.
#
# A plain Rack middleware, not a Sinatra `before` filter: static assets
# (public_folder — every JS/CSS/font/vendor file) are served by
# Sinatra's own built-in static-file shortcut, which bypasses route and
# filter dispatch entirely but is still wrapped by this, same as every
# other response — each one was independently capable of winning the
# clobbering race a `before` filter alone left uncovered.
class SkipSessionWrite
WRITE_PATHS = %w[/login /auth/callback /logout].freeze
def initialize(app)
@app = app
end
def call(env)
env["rack.session.options"][:skip] = true unless WRITE_PATHS.include?(env["PATH_INFO"])
@app.call(env)
end
end
class App < Sinatra::Base class App < Sinatra::Base
set :public_folder, File.join(__dir__, "public") set :public_folder, File.join(__dir__, "public")
set :views, File.join(__dir__, "views") set :views, File.join(__dir__, "views")
@@ -30,6 +67,7 @@ module Maptool
# don't survive a restart there, which is fine outside production. # don't survive a restart there, which is fine outside production.
set :sessions, httponly: true, secure: production?, same_site: :lax, set :sessions, httponly: true, secure: production?, same_site: :lax,
secret: ENV.fetch("SESSION_SECRET") { SecureRandom.hex(32) } secret: ENV.fetch("SESSION_SECRET") { SecureRandom.hex(32) }
use SkipSessionWrite
# Cache-busts /js and /css requests: browsers (and a caching proxy in # Cache-busts /js and /css requests: browsers (and a caching proxy in
# front of production, see docs/deployment.adoc) hang onto static # front of production, see docs/deployment.adoc) hang onto static
@@ -62,6 +100,24 @@ module Maptool
GPX_STORE = GpxStore.new(File.join(DATA_DIR, "gpx")) GPX_STORE = GpxStore.new(File.join(DATA_DIR, "gpx"))
LIVETRACK_STORE = LiveTrackStore.new(File.join(DATA_DIR, "livetrack.json")) LIVETRACK_STORE = LiveTrackStore.new(File.join(DATA_DIR, "livetrack.json"))
# Not under DATA_DIR: unlike everything else there (uploads, PMTiles,
# the kiwix ZIM), a plugin is code, not local data — plugins/overpass-pois
# ships checked into this repo as the reference example of the
# contract. Overridable so tests can point it at a throwaway fixture
# directory. In production this whole directory is baked into the
# image (see Dockerfile's `COPY . .`) and wiped/replaced on every
# deploy along with the rest of the checkout (docs/deployment.adoc) —
# fine for a plugin checked into this repo, not for a private one.
PLUGINS_DIR = ENV.fetch("MAPTOOL_PLUGINS_DIR") { File.join(__dir__, "plugins") }
# A second, optional plugin directory under DATA_DIR — the same
# persistent bind mount as gpx/kiwix (docs/deployment.adoc), so a
# private/scraper plugin (one whose ToS forbids living in this public
# repo) dropped in data/plugins/ survives a redeploy the way PLUGINS_DIR
# above can't. Checked after PLUGINS_DIR (see Plugins.list/run), so a
# same-named private plugin never shadows the built-in one.
PLUGINS_DIRS = [PLUGINS_DIR, File.join(DATA_DIR, "plugins")].freeze
# Shared secret for the Garmin LiveTrack webhook (a Google Apps Script # Shared secret for the Garmin LiveTrack webhook (a Google Apps Script
# watching Gmail for LiveTrack emails, see docs/deployment.adoc) — not a # watching Gmail for LiveTrack emails, see docs/deployment.adoc) — not a
# Gitea-authenticated user, so it can't use the OAuth2 login flow above. # Gitea-authenticated user, so it can't use the OAuth2 login flow above.
@@ -69,6 +125,16 @@ module Maptool
# OAuth2 secrets: fine outside production, nothing works without it set. # OAuth2 secrets: fine outside production, nothing works without it set.
LIVETRACK_WEBHOOK_SECRET = ENV.fetch("LIVETRACK_WEBHOOK_SECRET", "") LIVETRACK_WEBHOOK_SECRET = ENV.fetch("LIVETRACK_WEBHOOK_SECRET", "")
# An external kiwix-serve instance (see docs/development.adoc), not
# something this app runs itself — blank disables the "Nearby on
# Wikipedia" popup link the same way the other optional-integration
# blanks above do. Only ever reached server-side (the Docker-network
# service name in production, e.g. "http://kiwix:8080") — production
# sits behind a reverse proxy (map.priesol.net) that only forwards to
# this app, so a browser can't reach kiwix-serve directly by any
# hostname/port of its own. GET /kiwix/* below proxies to it instead.
KIWIX_URL = ENV.fetch("KIWIX_URL", "")
# Login delegates to the Gitea instance the user already has an account # Login delegates to the Gitea instance the user already has an account
# on, rather than maintaining a local username/password — see # on, rather than maintaining a local username/password — see
# docs/architecture.adoc. Only users listed in ALLOWED_GITEA_USERS may # docs/architecture.adoc. Only users listed in ALLOWED_GITEA_USERS may
@@ -95,6 +161,13 @@ module Maptool
halt 401, json(error: "login required", login_url: "/login") unless logged_in? halt 401, json(error: "login required", login_url: "/login") unless logged_in?
end end
def pmtiles_file_status(path, meta)
return { available: false } unless File.exist?(path)
status = { available: true, size: File.size(path), mtime: File.mtime(path).utc.iso8601 }
meta ? status.merge(meta: meta) : status
end
def callback_url def callback_url
"#{request.base_url}/auth/callback" "#{request.base_url}/auth/callback"
end end
@@ -174,7 +247,7 @@ module Maptool
end end
get "/api/offline-tiles" do get "/api/offline-tiles" do
json available: File.exist?(OFFLINE_PMTILES_PATH) json pmtiles_file_status(OFFLINE_PMTILES_PATH, PmtilesBuilder.offline_meta(DATA_DIR))
end end
# Served as a plain range-request-capable file, not decoded server-side: # Served as a plain range-request-capable file, not decoded server-side:
@@ -186,11 +259,100 @@ module Maptool
send_file OFFLINE_PMTILES_PATH, type: "application/octet-stream" send_file OFFLINE_PMTILES_PATH, type: "application/octet-stream"
end end
# Compares the recorded build (offline.pmtiles.meta.json) against the
# current latest Protomaps build without rebuilding anything —
# update_available is null (not true/false) if there's no local build
# yet, or the live index couldn't be reached, so the frontend can tell
# "don't know" apart from "no, up to date". Not folded into GET
# /api/offline-tiles above: that route is on the hot path (map.js's own
# topbar-dot check on every page load), this one only gets called when
# the Offline data panel is actually opened.
get "/api/offline-tiles/check-update" do
json update_available: PmtilesBuilder.offline_update_available?(DATA_DIR)
end
# Lists the selectable countries and which of them are currently
# selected (data/offline_regions.json) — read-only, no login needed,
# same tier as the plain availability checks above.
get "/api/offline-regions" do
json available: PmtilesBuilder.available_regions, selected: PmtilesBuilder.selected_regions(DATA_DIR)
end
# Just updates the selection — does not itself start a build, so
# ticking several countries doesn't fire off several rebuilds. The
# frontend follows this with the two build routes below once the user
# is done choosing.
post "/api/offline-regions" do
require_login!
codes = Array(params[:codes])
begin
PmtilesBuilder.set_selected_regions(DATA_DIR, codes)
rescue PmtilesBuilder::BuildError => e
halt 400, json(error: e.message)
end
json ok: true
end
# Regenerates offline.pmtiles for the currently selected regions (see
# POST /api/offline-regions above) by downloading each from Geofabrik
# and tiling them with Planetiler — see lib/maptool/pmtiles_builder.rb.
# Runs in the background; poll build-status below for progress.
post "/api/offline-tiles/build" do
require_login!
begin
PmtilesBuilder.build_offline(data_dir: DATA_DIR)
rescue PmtilesBuilder::BuildError => e
halt 409, json(error: e.message)
end
json status: "started"
end
get "/api/offline-tiles/build-status" do
json PmtilesBuilder.offline_status
end
# Deletes offline.pmtiles plus its whole per-country download cache —
# a manual "reclaim the space"/"start over" action, distinct from
# unticking countries in the region picker (which only changes what a
# future build covers, doesn't free anything already on disk).
delete "/api/offline-tiles" do
require_login!
begin
PmtilesBuilder.delete_offline_data(DATA_DIR)
rescue PmtilesBuilder::BuildError => e
halt 409, json(error: e.message)
end
json ok: true
end
# What's actually in the per-country download cache right now (not the
# same as offline.pmtiles' own meta.sources — see cached_extracts) —
# read-only, same tier as GET /api/offline-regions above, so the region
# picker can show a size + delete affordance next to each cached
# country regardless of whether it's still selected or already built.
get "/api/offline-tiles/cache" do
json extracts: PmtilesBuilder.cached_extracts(DATA_DIR)
end
# Deletes one country's cached Geofabrik extract only — e.g. to force a
# clean re-download of just that one, or reclaim space for a country
# that's no longer selected (the cache otherwise keeps it indefinitely).
delete "/api/offline-tiles/cache/:code" do
require_login!
begin
PmtilesBuilder.delete_cached_extract(DATA_DIR, params[:code])
rescue PmtilesBuilder::BuildError => e
halt 409, json(error: e.message)
end
json ok: true
end
# Same optional-local-file story as offline.pmtiles above — see # Same optional-local-file story as offline.pmtiles above — see
# docs/development.adoc for how to generate one, until then hillshade # docs/development.adoc for how to generate one, until then hillshade
# just stays unavailable while the offline basemap is active. # just stays unavailable while the offline basemap is active.
get "/api/terrain-tiles" do get "/api/terrain-tiles" do
json available: File.exist?(TERRAIN_PMTILES_PATH) json pmtiles_file_status(TERRAIN_PMTILES_PATH, PmtilesBuilder.terrain_meta(DATA_DIR))
end end
get "/tiles/terrain.pmtiles" do get "/tiles/terrain.pmtiles" do
@@ -199,6 +361,102 @@ module Maptool
send_file TERRAIN_PMTILES_PATH, type: "application/octet-stream" send_file TERRAIN_PMTILES_PATH, type: "application/octet-stream"
end end
# Same reasoning as GET /api/offline-tiles/check-update above.
get "/api/terrain-tiles/check-update" do
json update_available: PmtilesBuilder.terrain_update_available?(DATA_DIR)
end
post "/api/terrain-tiles/build" do
require_login!
begin
PmtilesBuilder.build_terrain(data_dir: DATA_DIR)
rescue PmtilesBuilder::BuildError => e
halt 409, json(error: e.message)
end
json status: "started"
end
get "/api/terrain-tiles/build-status" do
json PmtilesBuilder.terrain_status
end
# Same reasoning as DELETE /api/offline-tiles above.
delete "/api/terrain-tiles" do
require_login!
begin
PmtilesBuilder.delete_terrain_data(DATA_DIR)
rescue PmtilesBuilder::BuildError => e
halt 409, json(error: e.message)
end
json ok: true
end
# Generated as a step inside POST /api/offline-tiles/build (see
# PmtilesBuilder.extract_hiking_trails) rather than its own separate
# build — it's derived from the exact same per-country .osm.pbf cache
# offline.pmtiles itself already downloads, so there's nothing of its
# own to trigger; DELETE /api/offline-tiles removes it too. One file
# per country (not one combined file) so a viewer only ever fetches
# the country they actually pick in the Hiking trails overlay's own
# checklist (public/js/hiking_trails.js), not every selected country's
# trails at once — `countries` lists which ones exist to build that
# checklist from.
get "/api/hiking-trails" do
json countries: PmtilesBuilder.hiking_trails_countries(DATA_DIR)
end
# Fetched client-side only for a country the viewer actually ticks in
# the Hiking trails checklist, not on page load. :code is constrained
# to exactly what hiking_trails_countries can ever return (two
# uppercase letters) — otherwise this would accept an arbitrary
# ".."-laden path segment.
get "/tiles/hiking_trails/:code.geojson" do
halt 404 unless params[:code].match?(/\A[A-Z]{2}\z/)
path = PmtilesBuilder.hiking_trails_country_path(DATA_DIR, params[:code])
halt 404 unless File.exist?(path)
send_file path, type: "application/geo+json"
end
# Pinged once per page load (public/js/map.js) — url is a same-origin
# path (not kiwix-serve's own address, which the browser can't reach
# directly behind the reverse proxy in front of this app), proxied by
# GET /kiwix/* below.
get "/api/kiwix" do
reachable = Kiwix.reachable?(KIWIX_URL)
json available: reachable, url: (reachable ? "/kiwix" : "")
end
# Backs the "Wikipedia" map layer (public/js/gpx.js) — replaces the old
# per-popup "Nearby on Wikipedia" link, which only ever pointed at one
# POI at a time. Read-only and login-free, same as the tree/plugin
# listing routes below: viewing the map needs no account, only writing
# to it does.
get "/api/kiwix/nearby" do
halt 404 if KIWIX_URL.empty?
bbox = %w[south west north east].map { |key| params[key].to_s }
halt 400, json(error: "south, west, north, east are required") if bbox.any?(&:empty?)
json Kiwix.nearby(KIWIX_URL, bbox.map(&:to_f))
end
# Proxies kiwix-serve's own search UI and content pages through this
# app instead of linking the browser to it directly (see KIWIX_URL) —
# kiwix-serve is started with --urlRootLocation=/kiwix
# (docker-compose.yaml), so every link/asset it emits already carries
# this same /kiwix prefix and Just Works through this passthrough. GET
# only: browsing a read-only ZIM archive never needs to write anything.
get "/kiwix/*" do
halt 404 if KIWIX_URL.empty?
response = Kiwix.proxy(KIWIX_URL, "/kiwix/#{params[:splat].first}", request.query_string)
halt 502 unless response
content_type response["content-type"] || "application/octet-stream"
status response.code.to_i
body response.body
end
get "/api/gpx/tree" do get "/api/gpx/tree" do
json GPX_STORE.tree json GPX_STORE.tree
end end
@@ -293,6 +551,45 @@ module Maptool
json ok: true json ok: true
end end
# Lists whatever import plugins are on disk (see lib/maptool/plugins.rb
# for the contract) — read-only, doesn't need require_login! the way
# actually running one does below.
get "/api/plugins" do
json Plugins.list(PLUGINS_DIRS)
end
# Runs one plugin for the given bbox (the current map viewport, from
# the frontend's "Run for this area" button) and saves its GeoJSON
# output as a new file the same way an uploaded .geojson would be
# saved — reusing GpxStore#save rather than #append_feature since this
# writes a whole FeatureCollection at once, not one feature into an
# existing one.
post "/api/plugins/:name/run" do
require_login!
bbox = %w[south west north east].map { |key| params[key].to_s }
halt 400, json(error: "south, west, north, east are required") if bbox.any?(&:empty?)
south, west, north, east = bbox.map(&:to_f)
begin
geojson = Plugins.run(PLUGINS_DIRS, params[:name], [south, west, north, east])
rescue Plugins::RunError => e
halt 502, json(error: e.message)
end
# Filename carries the area's center and the run's timestamp (same
# idea as a p4n2gpx export's own "p4n_area_<lat>_<lon>_<date>_<time>"
# naming) — without it, running this again for a different area just
# overwrote/renamed-with-a-counter the same "overpass-pois.geojson",
# with nothing in the file tree to tell one run's POIs from another's.
center_lat = format("%.2f", (south + north) / 2)
center_lon = format("%.2f", (west + east) / 2)
timestamp = Time.now.strftime("%y%m%d_%H%M")
filename = "#{params[:name]}_#{center_lat}_#{center_lon}_#{timestamp}.geojson"
path = GPX_STORE.save(folder: "", filename: filename, io: StringIO.new(JSON.generate(geojson)))
json path: path, tree: GPX_STORE.tree
end
# ?download=geojson exports the file's GeoJSON as an attachment instead # ?download=geojson exports the file's GeoJSON as an attachment instead
# of rendering it on the map — the only way to get a .gpx/.fit's # of rendering it on the map — the only way to get a .gpx/.fit's
# converted form out of the app, since GpxStore#geojson's cache is # converted form out of the app, since GpxStore#geojson's cache is
@@ -446,10 +743,8 @@ module Maptool
halt 502, json(error: "track has no positions") if coordinates.empty? halt 502, json(error: "track has no positions") if coordinates.empty?
last = points.last last = points.last
json( features = [
type: "FeatureCollection", { type: "Feature", geometry: { type: "LineString", coordinates: coordinates }, properties: { "kind" => "actual" } },
features: [
{ type: "Feature", geometry: { type: "LineString", coordinates: coordinates }, properties: {} },
{ {
type: "Feature", type: "Feature",
geometry: { type: "Point", coordinates: coordinates.last }, geometry: { type: "Point", coordinates: coordinates.last },
@@ -463,7 +758,21 @@ module Maptool
), ),
}, },
] ]
)
# Only present when the activity was started from a saved Garmin
# course (see LiveTrackClient#fetch) — plotted separately from the
# actual track ("kind" distinguishes the two LineStrings) since it's
# the planned route, not where the person has actually been.
course_coordinates = result.course&.[]("geoPoints")&.filter_map { |p| p.dig("position", "lon") && p.dig("position", "lat") && [p["position"]["lon"], p["position"]["lat"]] }
if course_coordinates&.any?
features << {
type: "Feature",
geometry: { type: "LineString", coordinates: course_coordinates },
properties: { "kind" => "planned", "name" => result.course["name"] },
}
end
json(type: "FeatureCollection", features: features)
end end
get "/api/gnss/position" do get "/api/gnss/position" do
View File
Whitespace-only changes.
View File
Whitespace-only changes.
+89 -3
View File
@@ -1,6 +1,16 @@
services: services:
maptool: maptool:
build: . # "./build", not ".": the compose file's own context ("." would mean
# the symlink's directory, /srv/podman/maptool/ — see docs/deployment.adoc)
# is one level above where the actual checkout (and its Dockerfile)
# lives since the previous commit moved it into build/. Volume paths
# below resolve against that same symlink directory too, but a relative
# *build context* specifically needs pointing at build/ itself — the
# gap this fixes: production's compose up --build failed outright
# ("lstat .../maptool/Dockerfile: no such file or directory") until this
# was caught, since only the volume-path resolution got dry-run tested
# before the previous commit shipped, not this one.
build: ./build
image: maptool:latest image: maptool:latest
restart: unless-stopped restart: unless-stopped
ports: ports:
@@ -21,12 +31,46 @@ services:
# Optional: blank disables the LiveTrack webhook endpoint rather than # Optional: blank disables the LiveTrack webhook endpoint rather than
# failing to start, since it's not needed for the app's core function. # failing to start, since it's not needed for the app's core function.
LIVETRACK_WEBHOOK_SECRET: ${LIVETRACK_WEBHOOK_SECRET:-} LIVETRACK_WEBHOOK_SECRET: ${LIVETRACK_WEBHOOK_SECRET:-}
# Optional, only read by data/plugins/p4n2gpx/'s own p4n2gpx.rb (not
# part of this repo — see docs/deployment.adoc) if that private
# plugin is present; blank just means it fails with its own "could
# not authenticate" error when run, same non-fatal-to-startup story
# as the other optional secrets here. P4N_USER/P4N_PASSWORD alone
# don't actually work here — park4night's login form is behind
# invisible reCAPTCHA, which no browserless login can satisfy — so
# P4N_SESSION_COOKIE (a real logged-in browser's session cookie,
# copied out by hand and refreshed whenever it expires) is what
# p4n2gpx.rb's make_session actually ends up using.
P4N_USER: ${P4N_USER:-}
P4N_PASSWORD: ${P4N_PASSWORD:-}
P4N_SESSION_COOKIE: ${P4N_SESSION_COOKIE:-}
# The kiwix service below, reached by its compose service name (both
# are on the same default compose network) — port matches its own
# --port=8080 in the command below. Not made conditional on the ZIM
# actually being present: GET /api/kiwix pings it and just reports
# unavailable if the container isn't up/reachable, same story as
# every other optional-local-file feature (offline.pmtiles, etc).
# Reached server-side only — production sits behind a reverse proxy
# that only forwards to maptool itself, so app.rb's GET /kiwix/*
# proxies to this instead of handing the browser this address.
KIWIX_URL: "http://kiwix:8080"
volumes: volumes:
# Uploaded GPX files and the offline PMTiles extract — kept outside # Uploaded GPX files and the offline PMTiles extract — kept outside
# the image so a rebuild/redeploy doesn't wipe them (see # the image so a rebuild/redeploy doesn't wipe them (see
# docs/development.adoc for how the deploy job treats this # docs/development.adoc for how the deploy job treats this
# directory). # directory). A private plugin (app.rb's PLUGINS_DIRS) also belongs
- ./data:/app/data # under here, at data/plugins/<name>/ — nothing further to mount,
# this one bind already covers the whole data/ tree. An offline.pmtiles
# build's own scratch work (Dir.mktmpdir, lib/maptool/pmtiles_builder.rb)
# happens outside this mount, in the container's own filesystem — a
# large country's .osm.pbf plus Planetiler's working set can be
# several GB, worth knowing if the host is ever short on space there.
# :Z (not :z — this path is only ever mounted into this one
# container) relabels the host directory for SELinux, since Podman
# on an SELinux-enforcing host otherwise denies the container write
# access to a bind-mounted directory regardless of Unix permissions
# — harmless/ignored on a host without SELinux.
- ./data:/app/data:Z
# Fakes a GNSS fix (a loop around Bratislava, see # Fakes a GNSS fix (a loop around Bratislava, see
# bin/gnss_simulator.rb/docs/development.adoc) since there's no real # bin/gnss_simulator.rb/docs/development.adoc) since there's no real
@@ -43,3 +87,45 @@ services:
restart: unless-stopped restart: unless-stopped
network_mode: "service:maptool" network_mode: "service:maptool"
command: ["ruby", "bin/gnss_simulator.rb"] command: ["ruby", "bin/gnss_simulator.rb"]
# Serves an offline Wikipedia ZIM for the popup's "Nearby on Wikipedia"
# link (see docs/development.adoc for where to get one and drop it in —
# same "not part of the repo, place it under ./data locally" story as
# offline.pmtiles/terrain.pmtiles). On the default compose network (not
# network_mode: "service:maptool" — unlike gnss-simulator this doesn't
# need a hardcoded localhost port, KIWIX_URL above reaches it by this
# service's own name), so maptool and kiwix stay independent containers.
# Keeps restarting (harmlessly) if data/kiwix/wikipedia.zim isn't there
# yet — GET /api/kiwix just reports unavailable until it comes up.
#
# The volume binds the exact *file* path, not the data/kiwix/ directory —
# deliberately, so data/kiwix/wikipedia.zim can be a symlink to wherever
# the (large) real ZIM actually lives. A bind mount resolves a symlink at
# its *source* path once, at mount time (plain mount(2) semantics, same
# as Podman); a symlink sitting inside an already-mounted directory
# doesn't get that treatment — the container would have to resolve it
# itself, inside its own filesystem, where the host path it points to
# doesn't exist.
kiwix:
image: ghcr.io/kiwix/kiwix-serve:latest
restart: unless-stopped
# No --port here: the image's own start.sh already prepends
# --port=8080 (its default) before appending this command array, so
# passing it again produced "Unexpected argument: --port=8080,
# --port=8080, /data/wikipedia.zim" and kiwix-serve refused to start.
#
# --urlRootLocation=/kiwix makes every link/asset kiwix-serve itself
# emits (search results, article pages, its CSS/JS) carry a /kiwix
# prefix, matching where app.rb's GET /kiwix/* proxies requests in
# from (confirmed against libkiwix's internalServer.cpp: it strips
# this same prefix off incoming request paths, so both ends agree on
# it) — no ports: mapping needed, nothing outside the compose network
# ever talks to this container directly.
command: ["--urlRootLocation=/kiwix", "/data/wikipedia.zim"]
volumes:
# :Z, same SELinux reasoning as maptool's own ./data mount above.
- ./data/kiwix/wikipedia.zim:/data/wikipedia.zim:Z
networks:
default:
enable_ipv6: true
+70 -62
View File
@@ -44,18 +44,33 @@ opened in a browser.
Map data is vector, not raster: the app ships Map data is vector, not raster: the app ships
https://maplibre.org[MapLibre GL JS] (vendored, see below) and the map https://maplibre.org[MapLibre GL JS] (vendored, see below) and the map
view (`public/js/map.js`) offers two styles: view (`public/js/map.js`) offers two styles, both **the same
OpenMapTiles-schema Liberty style** (https://tiles.openfreemap.org/styles/liberty[OpenFreeMap
"liberty"]), just pointed at different vector sources:
* *Online* — a full hosted vector style, * *Online* — Liberty's own hosted tiles, `tiles.openfreemap.org`,
https://tiles.openfreemap.org/styles/liberty[OpenFreeMap "liberty"],
requires internet access. requires internet access.
* *Offline* — built at runtime from a local * *Offline* — a local https://github.com/protomaps/PMTiles[PMTiles]
https://github.com/protomaps/PMTiles[PMTiles] archive at archive at `data/offline.pmtiles`, built by
`data/offline.pmtiles`, served as-is (see below) at https://github.com/onthegomap/planetiler[Planetiler] from an OSM
`/tiles/offline.pmtiles`, decoded client-side by extract (see `docs/development.adoc`), served as-is at
`/tiles/offline.pmtiles` and decoded client-side by
https://github.com/protomaps/PMTiles[pmtiles.js] registered as a https://github.com/protomaps/PMTiles[pmtiles.js] registered as a
`pmtiles://` protocol handler, and styled with base layers from `pmtiles://` protocol handler.
https://github.com/protomaps/basemaps[protomaps-themes-base].
Using the same schema both ways is deliberate: an earlier version of
this app built offline tiles from Protomaps' own basemap schema
instead, which needed a *separate* hand-tuned theme
(`protomaps-themes-base` + a since-removed `OFFLINE_THEME`) to
approximate the online look — two independently-maintained palettes
that drifted out of sync (building opacity, road casings, park
boundaries) every time one side changed. Planetiler's default profile
*is* OpenMapTiles, so `offlineStyle()` now just clones the same parsed
Liberty JSON `ONLINE_STYLE` already fetched, repoints its `sources`,
`glyphs`, and `sprite` at local copies, and applies the exact same
`ONLINE_STYLE_PATCH` recolor (below) — one palette, one place to tune
it, correct on both sides by construction rather than by re-checking
every time something changes.
`GET /api/offline-tiles` reports whether `data/offline.pmtiles` is `GET /api/offline-tiles` reports whether `data/offline.pmtiles` is
present (`{"available": true|false}`); the frontend uses it once, on present (`{"available": true|false}`); the frontend uses it once, on
@@ -72,28 +87,35 @@ support) just returns byte ranges of the file; pmtiles.js in the
browser reads the archive's own directory and requests only the bytes browser reads the archive's own directory and requests only the bytes
it needs for the tiles on screen. it needs for the tiles on screen.
=== Offline text labels and color palette No PMTiles file ships with the repository — it is built locally or
in-app (see `docs/development.adoc`) and stays gitignored because such
extracts are typically large binary files. Geofabrik's per-country
extracts are OSM data, ODbL-licensed, same attribution
(`© OpenStreetMap contributors`) the map already shows either way — no
separate licensing story the way the old Protomaps-basemap pipeline's
NPS-Park-Tiles color research needed.
=== Offline text labels, sprite, and color palette
Label rendering in MapLibre needs a "glyphs" server serving font PBF Label rendering in MapLibre needs a "glyphs" server serving font PBF
ranges (256 Unicode code points each); `data/offline.pmtiles`'s fields ranges (256 Unicode code points each). The glyphs Liberty's style
(`name`, `name:en`, `script`, ...) match what references are vendored under `public/vendor/fonts/` — Noto Sans
`protomaps-themes-base`'s `layers(source, theme, { lang: "en" })` Regular/Italic/Medium, ranges `0-255` and `256-511` (Basic Latin +
expects for its label layers (verified against the actual PMTiles Latin-1 Supplement + Latin Extended-A, SIL OFL licensed, from
vector layer schema), so passing that option turns labels on. The
glyphs themselves are vendored under `public/vendor/fonts/` — Noto
Sans Regular/Italic/Medium, ranges `0-255` and `256-511`
(Basic Latin + Latin-1 Supplement + Latin Extended-A, SIL OFL
licensed, from
https://github.com/protomaps/basemaps-assets[protomaps/basemaps-assets]), https://github.com/protomaps/basemaps-assets[protomaps/basemaps-assets]),
covering accented Latin place names (Slovak, Czech, Polish, German, covering accented Latin place names (Slovak, Czech, Polish, German,
...). Labels in other scripts (Cyrillic, Greek, CJK, ...) won't render ...). Labels in other scripts (Cyrillic, Greek, CJK, ...) won't render
offline, since those glyph ranges aren't vendored. offline, since those glyph ranges aren't vendored. Liberty's icon
sprite (shields, POI icons) is likewise vendored as a one-time
snapshot under `public/vendor/liberty-sprite/` — both `offlineStyle()`
and the online style otherwise share identical `glyphs`/`sprite`
roles, just resolved to local vs. `tiles.openfreemap.org` URLs.
`public/js/map.js`'s `OFFLINE_THEME` nudges a couple dozen color roles `public/js/map.js`'s `ONLINE_STYLE_PATCH` — applied to whichever
from `protomaps-themes-base`'s stock "light" theme towards the source is loaded, online or offline (see above) — nudges Liberty's
National Park Service's own "Park Tiles" cartography — a warm, OpenMapTiles layer ids towards a warm, National Park Service
Harpers-Ferry-Center-derived look. A few of these values are the "Park Tiles"-inspired look. A few of these values are the genuine
genuine paint colors pulled from a public Park Tiles style JSON paint colors pulled from a public Park Tiles style JSON
(`nps.gov/lib/npmap.js/style/ck72fwp2642dv07o7tbqinvz4.json`, the (`nps.gov/lib/npmap.js/style/ck72fwp2642dv07o7tbqinvz4.json`, the
"Imagery" variant — the only one of NPS's four styles served from a "Imagery" variant — the only one of NPS's four styles served from a
plain, unauthenticated URL; "Standard"/"Slate"/"Light" resolve through plain, unauthenticated URL; "Standard"/"Slate"/"Light" resolve through
@@ -101,50 +123,36 @@ Mapbox Studio's private API with an access token, which isn't
something to piggyback on even though it's technically visible in something to piggyback on even though it's technically visible in
their own JS bundle) — background, the park/protected-area green, the their own JS bundle) — background, the park/protected-area green, the
two road-importance tiers, and the park-boundary line color. The rest two road-importance tiers, and the park-boundary line color. The rest
are reasoned to match that same warm family (olive greens, muted blue) are reasoned to match that same warm family (olive greens, muted blue,
rather than sourced. This is deliberately partial — labels, casings, brown road casings) rather than sourced. This is deliberately
and roles with no clean real-color anchor are left at theme partial — labels, halos, rail, and minor overlays (cemetery/hospital/
defaults — not the kind of full per-layer recolor a previous iteration school/pitch/track shading) are left at Liberty's own defaults.
of this app did (and removed, along with any dependency on OsmAnd's
own tile server, which this app cannot use per OsmAnd's terms
restricting tile use to "personal, non-commercial use within OsmAnd
applications and platforms").
+ +
Recreating the *color choices* is fine — that's not the kind of thing Recreating the *color choices* is fine — that's not the kind of thing
a data license restricts — but the actual Park Tiles *service* stays a data license restricts — but the actual Park Tiles *service* stays
off-limits: its OSM/terrain layers are licensed through Mapbox Atlas off-limits: its OSM/terrain layers are licensed through Mapbox Atlas
(a commercial, non-sublicensable data service scoped to NPS), and it's (a commercial, non-sublicensable data service scoped to NPS), and it's
built for park visitors specifically (park-unit and trailhead built for park visitors specifically (park-unit and trailhead
labeling prioritized), not general-purpose worldwide cartography. labeling prioritized), not general-purpose worldwide cartography —
irrelevant to this app either way now, since it never talks to NPS's
tile service, only ever OpenFreeMap/Geofabrik.
No PMTiles file ships with the repository — it is expected to be `loadOnlineStyle` (`public/js/map.js`) fetches Liberty's live
supplied locally (see `docs/development.adoc`) and stays gitignored `style.json` once, patches it in place, and uses the resulting object
because such extracts are typically large binary files. everywhere `ONLINE_STYLE` used to be a plain URL string — MapLibre
accepts a style object anywhere it accepts a style URL, so
The Online map (OpenFreeMap Liberty) gets the same treatment via `applyStyle`'s `map.setStyle(... : ONLINE_STYLE)` needed no change.
`ONLINE_STYLE_PATCH`, a separate hand-built table — Liberty is an That fetch runs before the map (and the rest of the page) is
OpenMapTiles-schema style, with its own layer ids (`landcover_wood`, constructed — a top-level `await` — so there's no flash of Liberty's
`road_secondary_tertiary`, `boundary_2`, ...) that don't correspond to own colors before the patch lands; a 3s timeout and a catch-all fall
protomaps' theme roles, so the two palettes can't share one object, back to the plain URL (letting MapLibre fetch and render it unpatched)
only the same underlying color choices. `loadOnlineStyle` rather than block the whole page's startup on a remote style server.
(`public/js/map.js`) fetches Liberty's `style.json` once, patches it Offline mode can't rely on that same live fetch succeeding — the field
in place, and uses the resulting object everywhere `ONLINE_STYLE` used usage this app is built for is exactly when it won't — so
to be a plain URL string — MapLibre accepts a style object anywhere it `offlineStyle()` instead clones a vendored, point-in-time snapshot of
accepts a style URL, so `applyStyle`'s `map.setStyle(... : ONLINE_STYLE)` the same Liberty JSON (`public/vendor/liberty-style/liberty.json`),
needed no change. That fetch runs before the map (and the rest of the patches it the same way, and repoints it at the local PMTiles/glyphs/
page) is constructed — a top-level `await` — so there's no flash of sprite described above.
Liberty's own colors before the patch lands; a 3s timeout and a
catch-all fall back to the plain URL (letting MapLibre fetch and
render it unpatched) rather than block the whole page's startup on a
remote style server, since this app is meant to keep working offline
in the field, independent of whether the online map itself loads.
Only the layers that dominate the map's overall color read are
patched (land cover, water, parks, roads, boundaries, buildings) —
same deliberately-partial scope as `OFFLINE_THEME`, not a full
per-layer recolor. Road casings are the one addition with no
protomaps-role equivalent to reuse, since offline roads don't get a
separate outline color there; `#c9a66b` is reasoned to fit the family
rather than sourced from anywhere real.
== Map permalink == Map permalink
+67 -20
View File
@@ -7,11 +7,21 @@ MapTool deploys as a Podman container (via `podman compose`, driven by a
the Gitea Actions runners run on. Two separate runners are registered the Gitea Actions runners run on. Two separate runners are registered
against the Gitea instance: against the Gitea instance:
* The existing Docker-based runner (`gitea/runner:3`), labels * The existing Docker-based runner (`gitea/runner:3`), label
`ubuntu-latest`/`ubuntu-24.04`/`ubuntu-22.04` — runs the `check` job `brick-build` — runs the `check` and `renovate` jobs in a fresh,
in a fresh, isolated container per job, same as before. isolated container per job. Every label on this runner (including
`ubuntu-latest`/`ubuntu-24.04`/`ubuntu-22.04`, still registered but no
longer what `check`/`renovate` pin to) now maps to Gitea's own
official runner image (`docker.gitea.com/runner-images:ubuntu-latest`,
has Node out of the box) — an earlier `opensuse/leap:16.0` mapping for
`brick-build` specifically had no Node, which every step in
`check`/`renovate` needs (they're JS-based Actions), and briefly broke
both jobs (2026-09-12) until reverted to the shared `ubuntu-latest`
label; now that the image itself is fixed, both are pinned back to
`brick-build` — this machine specifically, not whichever runner
happens to answer to the shared label (e.g. "Gitea Runner on Cube").
* A dedicated native runner, installed directly on the host (no Docker * A dedicated native runner, installed directly on the host (no Docker
around it), label `cube-host` — runs only the `deploy` job. around it), label `brick-host` — runs only the `deploy` job.
They're separate because the Docker-based runner's jobs (whether in They're separate because the Docker-based runner's jobs (whether in
its usual isolated per-job containers, or tried directly inside its its usual isolated per-job containers, or tried directly inside its
@@ -31,13 +41,42 @@ existing paths/tooling that still assume `/srv/docker` keep working;
expect this to flip the other way, `/srv/docker` symlinked to expect this to flip the other way, `/srv/docker` symlinked to
`/srv/podman`, once nothing depends on the old name anymore) holds: `/srv/podman`, once nothing depends on the old name anymore) holds:
* A checkout of this repository (kept in sync by the deploy job, see * `build/` — a checkout of this repository (kept in sync by the
below) — `Dockerfile`, `docker-compose.yaml`, application code. deploy job, see below), wiped and fully replaced every deploy —
`podman compose` reads the same `docker-compose.yaml` — no `Dockerfile`, `docker-compose.yaml`, application code.
Podman-specific compose file needed. * `docker-compose.yaml` — a relative symlink to `build/docker-compose.yaml`,
* `data/`, *not* part of that sync — uploaded GPX files and purely so it's where a human poking around expects to find it, at
`offline.pmtiles`. Persisted via a bind mount (`./data:/app/data` in the top rather than a level down. Also what makes the layout work at
`docker-compose.yaml`), so a redeploy never touches it. all: `podman compose`/`docker compose` resolve a relative volume
path (`./data` below) against the *symlink's own* directory, not
where it points — confirmed against plain `docker-compose config`,
not assumed — so `./data:/app/data` in the compose file keeps
meaning `/srv/podman/maptool/data`, and
`podman-compose@.service`'s `WorkingDirectory=/srv/podman/maptool`
needs no change either.
* `data/`, *not* part of the checkout sync (nothing in `build/`
references it, and the sync step doesn't need to special-case it
the way an earlier version of this layout did) — uploaded GPX
files, `offline.pmtiles`, `terrain.pmtiles`, and
`kiwix/wikipedia.zim` (see `docs/development.adoc` for each).
Persisted via that bind mount, so a redeploy never touches it.
Also where a private import plugin belongs (`data/plugins/<name>/`,
see `lib/maptool/plugins.rb`'s `PLUGINS_DIRS`) — `build/plugins/`
only holds what's checked into this public repo, and gets wiped and
replaced by the checkout sync on every deploy same as the rest of
`build/`.
`data/` (and the kiwix ZIM path) carries a `:Z` SELinux relabel in
`docker-compose.yaml`'s bind mounts — without it, Podman on an
SELinux-enforcing host denies the container write access to the
bind-mounted directory regardless of its Unix permissions (surfaces
as a plain `Permission denied` in the app's own logs, nothing
SELinux-labeled unless you go looking in `audit.log`); harmless/
ignored on a host where SELinux isn't enforcing.
* `.env` — regenerated every deploy (see below), lives here rather
than in `build/` for the same reason as the symlink: `docker
compose`/`podman compose` auto-load `.env` from the compose file's
own directory (as invoked, i.e. following the symlink's location,
same story as the volume path above).
== The native deploy runner == The native deploy runner
@@ -62,7 +101,7 @@ label:
---- ----
runner: runner:
labels: labels:
- "cube-host" - "brick-host"
---- ----
The `host` scheme means jobs run directly via the runner process's own The `host` scheme means jobs run directly via the runner process's own
@@ -173,7 +212,7 @@ const PROCESSED_LABEL = "livetrack-processed";
function checkLiveTrackEmail() { function checkLiveTrackEmail() {
const label = GmailApp.getUserLabelByName(PROCESSED_LABEL) || GmailApp.createLabel(PROCESSED_LABEL); const label = GmailApp.getUserLabelByName(PROCESSED_LABEL) || GmailApp.createLabel(PROCESSED_LABEL);
const threads = GmailApp.search(`from:noreply@garmin.com subject:LiveTrack -label:${PROCESSED_LABEL}`); const threads = GmailApp.search(`from:noreply@garmin.com -label:${PROCESSED_LABEL}`);
threads.forEach(thread => { threads.forEach(thread => {
// getBody() (raw HTML), not getPlainBody(): the email has no text/plain // getBody() (raw HTML), not getPlainBody(): the email has no text/plain
@@ -196,9 +235,14 @@ function checkLiveTrackEmail() {
The Gmail label (rather than marking the message read/unread) tracks which The Gmail label (rather than marking the message read/unread) tracks which
threads are already handled without touching the user's own inbox state. threads are already handled without touching the user's own inbox state.
`subject:LiveTrack` matches regardless of the account's language — Garmin No `subject:LiveTrack` filter on the search — despite Gmail's own
keeps "LiveTrack" as-is in the subject even in a localized substring-match documentation for `subject:`, that filter empirically
("Sledujte LiveTrack používateľa ...") one. returned zero threads against a real, currently-arriving LiveTrack email
whose subject does contain the word ("Sledujte LiveTrack používateľa
...", confirmed 2026-09-20), so it's left out entirely — the regex match
below is what actually narrows this down to real LiveTrack emails with a
usable session link, `from:noreply@garmin.com` alone is deliberately
broad.
Set the trigger from the editor: clock icon on the left (Triggers) → *Add Set the trigger from the editor: clock icon on the left (Triggers) → *Add
Trigger* → function `checkLiveTrackEmail`, time-driven, "Minutes timer", Trigger* → function `checkLiveTrackEmail`, time-driven, "Minutes timer",
@@ -215,16 +259,19 @@ webhook simply won't receive that session; nothing breaks.
== CI deploy job == CI deploy job
`.gitea/workflows/ci.yml`'s `deploy` job runs after `check` passes, only `.gitea/workflows/ci.yml`'s `deploy` job runs after `check` passes, only
on a push to `main`, with `runs-on: cube-host`: on a push to `main`, with `runs-on: brick-host`:
. Checks out the repo with plain `git` (`fetch` + `checkout`, . Checks out the repo with plain `git` (`fetch` + `checkout`,
authenticated via a one-off `http.extraHeader`) rather than authenticated via a one-off `http.extraHeader`) rather than
`actions/checkout@v4` — a leftover from when this job ran in a `actions/checkout@v4` — a leftover from when this job ran in a
Node-less container; kept as-is since there's no reason to bring Node-less container; kept as-is since there's no reason to bring
Node back in for something this already does. Node back in for something this already does.
. Copies the checkout into `/srv/podman/maptool/` using plain `cp`/`rm`: . Wipes and replaces `/srv/podman/maptool/build/` with the fresh
clears everything in the target except `data/`, copies the fresh checkout (plain `cp`/`rm`, dropping the copied `.git`), then
checkout over, then drops the copied `.git`. `ln -sf`s `docker-compose.yaml` up to it — self-healing (harmless
to redo every deploy) and, being a fresh checkout each time, nothing
in `build/` needs preserving the way `data/`/`.env` (both a level
up, see "Layout on the server" above) do.
. `sudo systemctl restart podman-compose@maptool.service`. The service . `sudo systemctl restart podman-compose@maptool.service`. The service
(`/etc/systemd/system/podman-compose@.service`, a systemd template (`/etc/systemd/system/podman-compose@.service`, a systemd template
instantiated as `podman-compose@maptool.service`) owns the actual instantiated as `podman-compose@maptool.service`) owns the actual
+270 -25
View File
@@ -27,18 +27,27 @@ reload (e.g. Ctrl/Cmd+Shift+R) if that happens.
To enable the offline style, place a PMTiles file at To enable the offline style, place a PMTiles file at
`data/offline.pmtiles` (see `docs/architecture.adoc` for how it is `data/offline.pmtiles` (see `docs/architecture.adoc` for how it is
served and styled). It is not part of the repository — obtain or served and styled — the same OpenMapTiles schema/style the online map
build one locally: uses, just from local data). Logged-in users can generate this from
the app itself — see "In-app regeneration" below — or it can be built
by hand:
* The simplest source is a pre-built extract from * Download one or more country extracts from
https://app.protomaps.com[protomaps.com's extract builder] — pick a https://download.geofabrik.de[Geofabrik] (`.osm.pbf`, ODbL/OSM
region and download it as `.pmtiles`. Its schema is what attribution) — e.g.
`protomaps-themes-base` (the styling library used for the offline `curl -O https://download.geofabrik.de/europe/slovakia-latest.osm.pbf`.
style) expects. * If more than one country, merge them with
* To convert some other vector tile source (e.g. an `.mbtiles` file) https://github.com/osmcode/osmium-tool[osmium-tool]:
into PMTiles, use the `osmium merge slovakia-latest.osm.pbf austria-latest.osm.pbf -o merged.osm.pbf`
https://github.com/protomaps/go-pmtiles[go-pmtiles] CLI: (each Geofabrik file is already clipped to that country's real
`pmtiles convert in.mbtiles data/offline.pmtiles`. border, so no separate bbox/polygon clip step is needed either
before or after — skip this step entirely for a single country).
* Tile it with https://github.com/onthegomap/planetiler[Planetiler]'s
default profile, which *is* OpenMapTiles — no `--profile` flag
needed — writing PMTiles directly:
`java -jar planetiler.jar --osm-path=merged.osm.pbf --output=data/offline.pmtiles`
(needs Java 21+; `planetiler.jar` from
https://github.com/onthegomap/planetiler/releases/latest[the latest release]).
Once the file is in place, `GET /api/offline-tiles` reports Once the file is in place, `GET /api/offline-tiles` reports
`available: true` and the map defaults to the offline style. `available: true` and the map defaults to the offline style.
@@ -50,14 +59,192 @@ The sidebar's "Terrain shading" toggle works online out of the box
no API key). For it to work offline too, place a PMTiles archive of no API key). For it to work offline too, place a PMTiles archive of
Terrarium-encoded `raster-dem` tiles at `data/terrain.pmtiles` Terrarium-encoded `raster-dem` tiles at `data/terrain.pmtiles`
(`GET /api/terrain-tiles` reports `available: true` once it's there, (`GET /api/terrain-tiles` reports `available: true` once it's there,
same pattern as offline map data above). It is not part of the same pattern as offline map data above). Also generatable in-app (see
repository — build one locally from a DEM source (e.g. Copernicus below) or by hand, the same `go-pmtiles extract` mechanism as
GLO-30 or SRTM) with a tool like `data/offline.pmtiles` above — but from
https://github.com/mapbox/rio-rgbify[rio-rgbify] (GeoTIFF -> https://mapterhorn.com[Mapterhorn], a Protomaps-affiliated project
Terrarium-encoded PNG tiles in an `.mbtiles`), then publishing pre-built Terrarium-encoded terrain as PMTiles (a global
`pmtiles convert out.mbtiles data/terrain.pmtiles` with `planet.pmtiles`, z0-12, plus ~450 regional chunks covering z13 and up
https://github.com/protomaps/go-pmtiles[go-pmtiles], same as — see https://mapterhorn.com/data-access/[their own data-access page]
`data/offline.pmtiles`. for the full manifest and per-source license/attribution details, CC-BY-4.0
and similar, varying by region):
[source,shell]
----
pmtiles extract https://download.mapterhorn.com/planet.pmtiles planet-extract.pmtiles --bbox=west,south,east,north --maxzoom=13 --overfetch=0
# only if a regional chunk covers the bbox too (see download_urls.json) —
# most bboxes hit exactly one, a bbox straddling a chunk boundary hits two:
pmtiles extract https://download.mapterhorn.com/<chunk>.pmtiles chunk-extract.pmtiles --bbox=west,south,east,north --maxzoom=13 --overfetch=0
pmtiles merge planet-extract.pmtiles chunk-extract.pmtiles data/terrain.pmtiles
----
`--overfetch=0`: the default (0.05) merges nearby byte ranges into fewer,
bigger requests to save round-trips — for `planet.pmtiles` (global z0-12,
tens of GB) over a bbox spanning several countries this can collapse the
whole extract into a *single* multi-GB request with no way to resume after
a mid-transfer HTTP/2 stream reset. `--overfetch=0` trades that one
fragile mega-request for many small ones instead (spread over
`--download-threads`, default 4) — slower end to end, but a dropped
connection only loses one small request's worth of progress, not the
whole extract.
`--maxzoom=13`: raster DEM tiles don't compress away like vector ones do
(every tile is a real image, even over flat/empty terrain), so each extra
zoom level roughly quadruples storage — the app's own build
(`PmtilesBuilder::TERRAIN_MAX_ZOOM`) caps at 13, each regional chunk's
own native minzoom, rather than the online hillshade layer's z15. A
12-country selection at z15 was headed well past 181GB; z13 is still
plenty for the hillshade toggle and the planned slope readout.
Tiles are 512px WebP, not the 256px PNG this app's *online* Terrarium
source uses — `public/js/dem.js`'s own point-elevation lookups
(`shadow.js`'s terrain-shadow overlay) read the actual decoded tile
size rather than assuming one, so this isn't a problem either way.
== Offline hiking trails
The sidebar's "Hiking trails" overlay works online out of the box
(waymarkedtrails.org raster tiles, `public/js/hiking_trails.js`) —
clicking a trail fires a one-off Overpass query for its name/colour/
network/distance. For it to work offline too, one `data/hiking_trails/
<CODE>.geojson` per country is generated automatically as the last step
of every `offline.pmtiles` build (`Maptool::HikingTrails`,
`lib/maptool/hiking_trails.rb`), straight from the *same* per-country
`.osm.pbf` files already downloaded for `offline.pmtiles` itself — no
separate download, no third-party service:
[source,shell]
----
osmium tags-filter country.osm.pbf r/route=hiking -o hiking.osm.pbf
osmium add-locations-to-ways hiking.osm.pbf -o hiking-located.osm.pbf
osmium cat hiking-located.osm.pbf -f opl,locations_on_ways=true,add_metadata=false -o hiking.opl
----
`add-locations-to-ways` matters: a plain Geofabrik PBF's ways only carry
bare node *references*, not coordinates, so skipping this step silently
produces ways with empty x/y in the OPL output and every route gets
dropped for having no usable geometry — not an error, just wrong output
(verified against a real extract before this was caught). No general OSM
tool stitches a route relation's member ways into one line for you
(routes are a semantic grouping, not a geometry type), so
`HikingTrails.parse_opl` does that walk itself — the same thing
waymarkedtrails.org and this app's own online Overpass click handler
already do.
Best-effort per country: an extraction problem on one country's PBF logs
a warning and is skipped rather than failing the whole `offline.pmtiles`
build, or even the other countries in the same selection, over what's a
bonus overlay, not the core map (`PmtilesBuilder.extract_hiking_trails`).
Cached the same way `geofabrik_cache` is (skipped once a country's own
extract is already newer than its source `.osm.pbf`), so growing the
region selection by one country only extracts that one. Coordinates are
rounded to 5 decimal places (~1m, plenty for a rendered line) — Slovakia
alone is ~3000 routes, ~30MB unrounded.
One file per country rather than one combined file: `GET /api/hiking-trails`
lists which country codes have an extract (`countries: [...]`), and the
Overlays panel's "Hiking trails" item turns that into a checklist —
each ticked country fetches its own `GET /tiles/hiking_trails/<CODE>.geojson`
only then, not on page load and not for countries never ticked. Offline
click hit-tests the loaded vector layer(s) directly
(`queryRenderedFeatures`) instead of querying Overpass, so it resolves
instantly with no network at all. `rake hiking:trails[pbf,out]` runs the
extraction by hand against one `.osm.pbf` for testing.
`DELETE /api/offline-tiles` removes the whole `data/hiking_trails/`
directory along with `offline.pmtiles` and the Geofabrik cache — there's
no separate delete/rebuild route for it, since it's not an independent
build.
== In-app regeneration
A logged-in user can also generate both files above from the app
itself, no local tooling needed — the sidebar's "Offline data" icon
(Offline hub group) shows a checklist of European countries
(`lib/maptool/data/europe_countries.geojson`, Natural Earth 110m
admin-0, public domain) plus each file's status (size, last updated).
Ticking countries and clicking "Apply changes" saves the selection
(`data/offline_regions.json`, an array of ISO A2 codes) and rebuilds
both files to cover it.
There's no standalone per-country *built* file — `offline.pmtiles`/
`terrain.pmtiles` are always one combined extract for the *whole
current selection*. "Remove a country" is just "change the selection,
then Apply" (unticking a country and applying rebuilds without it).
terrain.pmtiles re-extracts its selection from scratch on
every Apply — fine given that extraction is byte-range requests
against a remote archive, not full downloads. offline.pmtiles, by
contrast, downloads a whole country's `.osm.pbf` from Geofabrik (can be
multi-GB), so it keeps a per-country cache under
`data/geofabrik_cache/` instead of re-fetching on every Apply — a
country already cached is only re-downloaded if Geofabrik's own
`Last-Modified` for it has moved on since (checked with a cheap `HEAD`,
see `PmtilesBuilder.cached_extract`), so growing or shrinking the
selection only touches whatever's actually new to it.
This wraps exactly the manual workflows documented above
(`lib/maptool/pmtiles_builder.rb`). offline.pmtiles downloads each
selected country's Geofabrik extract, `osmium merge`s them if there's
more than one, then tiles the result with Planetiler — the server
needs `osmium` and `java` + `planetiler.jar` installed and on `PATH`
(override with the `OSMIUM_BIN`/`JAVA_BIN`/`PLANETILER_JAR` env vars if
they live somewhere else; the Docker image installs all three, see
`Dockerfile`). terrain.pmtiles still uses `go-pmtiles`
(`PMTILES_BIN`) against Mapterhorn, unrelated to this — it extracts
`planet.pmtiles` (always) plus whichever Mapterhorn regional chunks
intersect the selection, `merge`s them if there was more than one —
always safe regardless of how many/which countries are selected, since
each chunk is Mapterhorn's own pre-partitioned, non-overlapping source
file (extracting the *same* source once per country and merging those,
by contrast, would fail — adjacent countries' region-extracts share
border tiles, since extraction copies whole tiles rather than clipping
vector content to the polygon, and `pmtiles merge` refuses any
overlapping tile id between inputs).
A build runs in the background (`GET /api/offline-regions` to list/see
the current selection, `POST` to change it, then `POST
/api/offline-tiles/build` / `/api/terrain-tiles/build`, polled via the
matching `*/build-status` route) — only one of each kind at a time;
starting a second while one's running gets a 409, as does starting
either with nothing selected yet. While running, `build-status` also
includes a `step` string (e.g. `"fetching PL (3/4) — done: SK, CZ —
pending: HU"`, or `"tiling with planetiler"`) — see
`PmtilesBuilder.run_job`'s `report_step`.
`DELETE /api/offline-tiles` removes offline.pmtiles, its sidecar meta,
and the whole per-country download cache (`data/geofabrik_cache/`) —
`DELETE /api/terrain-tiles` does the same for terrain.pmtiles. Both are
a manual "reclaim the space" / "start over" action (409 while that
kind's build is running), separate from the region picker's Apply,
which only changes what a *future* build covers and never frees
anything already on disk. `DELETE
/api/offline-tiles/cache/:code` removes just one country's cached
extract, e.g. to force a clean re-download of it without touching the
rest of the cache. `GET /api/offline-tiles/cache` lists what's
actually in that cache right now (code/size/Last-Modified per file) —
not the same thing as offline.pmtiles' own `meta.sources`, which only
reflects the last successful build: a country can be cached without
ever having been built (ticked, not yet Applied) or built from without
still being selected (unticked since). The region picker shows this
next to each country's checkbox, with its own delete button, rather
than only offering "delete everything" on the whole offline.pmtiles
row.
Each successful build also writes a small sidecar (`offline.pmtiles.
meta.json` — each source country's code/Geofabrik slug/Last-Modified;
`terrain.pmtiles.meta.json` — the Mapterhorn source names/md5sums)
recording what was actually built, since the `.pmtiles` file itself
carries no such record. `GET /api/offline-tiles`/`/api/terrain-tiles`
include it as `meta`, shown in the panel next to the existing
size/updated line. `GET .../check-update` compares that recorded build
against each source's live upstream state (a Geofabrik `HEAD` per
country for offline, the Mapterhorn manifest for terrain — without
rebuilding anything) and reports `update_available: true/false/null` —
`null` means "don't know" (no local build yet, or a check itself
failed), kept as its own route rather than folded into the plain
status endpoints above since those are on the page-load hot path (the
topbar's offline-status dot) and this one reaches an external service,
only worth doing when the Offline data panel is actually open.
== Camper-relevant POIs (Overpass) == Camper-relevant POIs (Overpass)
@@ -65,12 +252,70 @@ https://github.com/protomaps/go-pmtiles[go-pmtiles], same as
https://overpass-api.de[Overpass] for drinking water, dump stations, https://overpass-api.de[Overpass] for drinking water, dump stations,
LPG refill, public toilets, laundromats, supermarkets/convenience LPG refill, public toilets, laundromats, supermarkets/convenience
stores, and springs within a bbox, and writes the result as a stores, and springs within a bbox, and writes the result as a
`.geojson` file (`lib/maptool/overpass_pois.rb`). A dev-time tool, not `.geojson` file (`lib/maptool/overpass_pois.rb`). Nodes only (nothing
something the running app calls itself — drop the output into that's mapped as a way/relation, e.g. a supermarket traced as a
`data/gpx/` (or upload it through the Tracks panel) like any other building outline rather than a single point). Also reachable from
`.geojson` layer once it's generated. Nodes only (nothing that's inside the running app itself, without the command line — see Import
mapped as a way/relation, e.g. a supermarket traced as a building plugins below, which wraps this exact query as `plugins/overpass-pois`.
outline rather than a single point).
== Import plugins
The sidebar's import icon (logged in only) lists whatever's under
`plugins/` and runs one for the current map viewport with a click — no
area-picker to fill in, the visible area *is* the area. Each plugin is
a directory with a `plugin.json` manifest (`{"label": "...", "command":
"./run.sh"}`) plus whatever script that command names; the entire
interface a plugin needs to know about maptool is "read
`--south`/`--west`/`--north`/`--east`, print a GeoJSON
`FeatureCollection` to stdout" (`lib/maptool/plugins.rb`) — the result
is saved as a new `.geojson` file the same way an upload would be.
`plugins/overpass-pois` ships as the reference example (a thin wrapper
around the `rake overpass:pois` logic above). A plugin that scrapes a
site whose terms of service forbid that — Park4Night, iOverlander,
Freecampsites — doesn't have to live in this (public) repo to work
here: drop its directory under `plugins/` locally and just don't
`git add` it, same as any other local-only file this app already
treats that way (`data/offline.pmtiles`, the kiwix ZIM, ...).
== Offline Wikipedia (kiwix-serve)
A point popup's "Nearby on Wikipedia" link needs
https://github.com/kiwix/kiwix-tools[kiwix-serve] running with a
Wikipedia https://library.kiwix.org[ZIM] loaded — set `KIWIX_URL` to
wherever *the server* can reach it (`docker-compose.yaml` already runs
a `kiwix` service pointed at `data/kiwix/wikipedia.zim` and wires
`KIWIX_URL` to it via its compose service name; blank/unset disables
the link, same as every other optional integration here). Used only
server-side: production sits behind a reverse proxy that forwards only
to this app, so there's no address a browser could reach kiwix-serve
at directly — `GET /kiwix/*` (`app.rb`) proxies to it instead, and the
`kiwix` service runs with `--urlRootLocation=/kiwix` so its own
emitted links/assets already carry that same prefix. Not part of the
repo — a ZIM is a large, self-contained archive, obtain one locally:
* https://library.kiwix.org/#lang=eng&category=wikipedia[Kiwix's own
library] has pre-built Wikipedia ZIMs — a `_maxi` variant per
language/region includes images, `_nopic` is much smaller if
browsing images offline doesn't matter here.
* Download it to `data/kiwix/wikipedia.zim` (the exact filename
`docker-compose.yaml`'s `kiwix` service expects — rename after
downloading, Kiwix's own filenames are much more specific). A symlink
there works too (`ln -s /wherever/the-real-file.zim
data/kiwix/wikipedia.zim`), so the real file doesn't have to sit inside
this repo's checkout at all — the compose file's volume binds that exact
path, not the `data/kiwix/` directory, specifically so this resolves
correctly (a symlink *inside* an already-mounted directory wouldn't: the
container would have to resolve it itself, in its own filesystem, where
the host path it points to doesn't exist).
Once it's there, `docker compose up -d kiwix` (or a full restart)
picks it up — `GET /api/kiwix` reports `available: true` and the
"Nearby on Wikipedia" link appears, pointed at kiwix-serve's own geo
search (`GET /kiwix/search?pattern=&latitude=&longitude=&distance=`)
through this app's own proxy rather than at kiwix-serve directly — it
already has a full search UI of its own, this just makes it reachable
through the same origin/reverse proxy as the rest of the app.
== GNSS position (gpsd) == GNSS position (gpsd)
+64 -6
View File
@@ -24,8 +24,8 @@ checking here before searching from zero next time.
| MIT (per `package.json`); the whole `npmap5-plugins` repo is separately | MIT (per `package.json`); the whole `npmap5-plugins` repo is separately
public domain as a US government work public domain as a US government work
| Park Tiles color palette (offline + online basemap themes) | Park Tiles color palette (shared offline + online basemap theme)
| `public/js/map.js`'s `OFFLINE_THEME` and `ONLINE_STYLE_PATCH` | `public/js/map.js`'s `ONLINE_STYLE_PATCH`
| Colors only — see <<park-tiles>> for why the actual tile service isn't used | Colors only — see <<park-tiles>> for why the actual tile service isn't used
| `overview` (top-right minimap/inset control) | `overview` (top-right minimap/inset control)
@@ -187,7 +187,7 @@ why this app uses OpenFreeMap Liberty as its actual basemap, not Park
Tiles — see `docs/architecture.adoc`'s "Offline maps" section. Tiles — see `docs/architecture.adoc`'s "Offline maps" section.
Recreating the *color choices* is a different matter — not the kind of Recreating the *color choices* is a different matter — not the kind of
thing a data license restricts — and is what `OFFLINE_THEME` in thing a data license restricts — and is what `ONLINE_STYLE_PATCH` in
`public/js/map.js` actually does (see `docs/architecture.adoc`). `public/js/map.js` actually does (see `docs/architecture.adoc`).
=== Public style JSON (source for the real colors we did pull) === Public style JSON (source for the real colors we did pull)
@@ -219,11 +219,11 @@ embedded credentials, even when technically reachable:
|=== |===
Colors actually pulled from the Imagery style JSON and used in Colors actually pulled from the Imagery style JSON and used in
`OFFLINE_THEME`: background (`hsl(40, 37%, 97%)`, a warm cream), the `ONLINE_STYLE_PATCH`: background (`hsl(40, 37%, 97%)`, a warm cream), the
park/protected-area green (`#b3e378`), the two road-importance tiers park/protected-area green (`#b3e378`), the two road-importance tiers
(`#fdefbe`/`#fef7dd`), and the park-boundary line color (`#546619`, dark (`#fdefbe`/`#fef7dd`), and the park-boundary line color (`#546619`, dark
olive). The rest of `OFFLINE_THEME` extends that same warm/olive family olive). The rest of `ONLINE_STYLE_PATCH` extends that same warm/olive
by eye rather than from a sourced value. family by eye rather than from a sourced value.
=== Legend / cartographic hierarchy === Legend / cartographic hierarchy
@@ -259,6 +259,20 @@ own work (a map viewer, not a publisher of NPS-branded content):
own UI chrome (currently plain system fonts, `public/css/style.css`) — own UI chrome (currently plain system fonts, `public/css/style.css`) —
no current use case, but no licensing blocker either, worth no current use case, but no licensing blocker either, worth
remembering if that comes up. remembering if that comes up.
* *Another open alternative, for display use*: https://nationalparktypeface.com[National Park]
— a separate, unrelated project (Ben Hoepner, Andrea Herstowski, Jeremy
Shellhorn / DO Studio), also SIL OFL licensed, also original ("inspired
by" park signage, not a Rawlinson reproduction). Ships as variable
`.ttf`, `.woff`/`.woff2`, and `.otf` — self-hostable via `@font-face`
the same way. Where it differs from Sequoia Sans above: it's a
router-carved-signage *display* face (the chunky all-caps look of
actual trailhead signs), not a general body/UI sans — best fit would be
a wordmark/heading use (e.g. the topbar's "MAPTOOL" text) alongside a
more legible sans for body copy, not a full typeface swap. Now used for
exactly that: `.topbar__brand` only (`public/css/style.css`), Bold
weight vendored under `public/vendor/national-park-typeface/` — see
`docs/third-party-notices.adoc`. Body copy elsewhere still plain system
fonts, unchanged.
* *Hawaiian typography*: NPS Rawlinson includes vowels with Hawaiian * *Hawaiian typography*: NPS Rawlinson includes vowels with Hawaiian
macrons (ā, ē, ī, ō, ū) and the okina (ʻ); the regular weight of macrons (ā, ē, ī, ō, ū) and the okina (ʻ); the regular weight of
Frutiger doesn't, so NPS uses a separate "HFrutiger" weight for Frutiger doesn't, so NPS uses a separate "HFrutiger" weight for
@@ -272,6 +286,50 @@ own work (a map viewer, not a publisher of NPS-branded content):
resource — included here only because it was shared alongside the resource — included here only because it was shared alongside the
typography notes above. typography notes above.
== Arrowhead (shield) logo colors
Unrelated to anything this app renders — noted here only because it came up
in conversation (wanting exact colors to 3D-print the NPS arrowhead) and
this doc is already the dumping ground for NPS-ecosystem color/graphic-identity
facts. Per NPS's own graphic identity standards (Harpers Ferry Center), the
arrowhead uses three official Pantone spot colors plus white:
[cols="2,2,1,1"]
|===
| Element | Pantone | Hex (converted) | Nearest RAL Classic
| Mountain
| Dark Rust, PMS 1615 C
| `#8b4720`
| RAL 2013 Pearl orange (`#923E25`)
| Sky
| Medium Rust, PMS 1605 C
| `#a65523`
| RAL 8023 Orange brown (`#A45729`)
| Trees / grass
| Dark Green, PMS 553 C
| `#284734`
| RAL 6012 Black green (`#2F3D3A`)
| Bison, lake, snowfield, type
| White
| `#ffffff`
| RAL 9016 Traffic white (`#F1F1EA`) — RAL has no pure white
|===
Hex values are third-party Pantone→RGB conversions, not something NPS
publishes directly (their style guide only specifies PMS codes). RAL codes
are the closest match by RGB distance against the RAL Classic chart — same
caveat, not an official NPS-endorsed mapping, just the nearest available
code for filament/paint shopping. Source: NPS Graphic Identity and Style
Guides (https://www.nps.gov/subjects/hfc/nps-graphic-identity-and-style-guides.htm),
FAQs About Arrowhead Artwork
(https://www.nps.gov/subjects/hfc/faqs-about-arrowhead-artwork.htm). Use of
the arrowhead symbol itself is controlled by law/regulation/policy — see
the FAQ page before printing/distributing anything bearing it.
== NPMap4 (the older, Leaflet-based generation) == NPMap4 (the older, Leaflet-based generation)
https://www.nps.gov/lib/npmap.js/4.2.1/ — predecessor to npmap5, https://www.nps.gov/lib/npmap.js/4.2.1/ — predecessor to npmap5,
+95 -8
View File
@@ -18,9 +18,9 @@ BSD-3-Clause licensed.
| 4.5.0 | 4.5.0
| https://github.com/protomaps/PMTiles | https://github.com/protomaps/PMTiles
| protomaps-themes-base | maplibre-contour (Overlays panel's "Contour lines", `public/js/contour.js`)
| 4.5.0 | 0.1.0
| https://github.com/protomaps/basemaps | https://github.com/onthegomap/maplibre-contour
|=== |===
Also vendored under `public/vendor/`, but not BSD-3-Clause like the Also vendored under `public/vendor/`, but not BSD-3-Clause like the
@@ -51,6 +51,34 @@ overview's polar pan limit, but MapLibre 6's `Map` no longer exposes
`.transform` at all — guarded to skip that (cosmetic) adjustment `.transform` at all — guarded to skip that (cosmetic) adjustment
instead of throwing when it's absent. instead of throwing when it's absent.
Also vendored under `public/vendor/` — MIT-licensed, attribution
required (`LICENSE` included alongside):
[cols="1,1,2"]
|===
| Library | Version | Source
| maplibre-gl-lanes (offline hiking trails, `public/js/hiking_trails.js`
— trails sharing a path drawn as parallel lanes); its `dist/*.mjs`
build, minus the trailing `sourceMappingURL` comment
| 1.3.0
| https://github.com/c0nsumer/maplibre-gl-lanes
|===
Also vendored under `public/vendor/` — MIT-licensed (© 2013 Panayiotis
Lipiridis), attribution required (this notice satisfies that):
[cols="1,1,2"]
|===
| Library | Version | Source
| flag-icons (just the square `1x1/` crop, only the 39 European
countries `lib/maptool/data/europe_countries.geojson` lists — see
`public/js/offline_data.js`)
| 7.5.0
| https://github.com/lipis/flag-icons
|===
Offline map text labels need font glyphs too (see Offline map text labels need font glyphs too (see
`docs/architecture.adoc`), vendored under `public/vendor/fonts/` — `docs/architecture.adoc`), vendored under `public/vendor/fonts/` —
SIL Open Font License, not BSD-3-Clause like the above: SIL Open Font License, not BSD-3-Clause like the above:
@@ -63,13 +91,72 @@ SIL Open Font License, not BSD-3-Clause like the above:
`256-511` only) `256-511` only)
| https://github.com/protomaps/basemaps-assets[protomaps/basemaps-assets] | https://github.com/protomaps/basemaps-assets[protomaps/basemaps-assets]
(`fonts/`, `OFL.txt` included alongside) (`fonts/`, `OFL.txt` included alongside)
| National Park (Bold weight only, `.woff2`), topbar wordmark
(`.topbar__brand`, `public/css/style.css`) — see
`docs/nps-resources.adoc`
| https://nationalparktypeface.com[nationalparktypeface.com] (Ben
Hoepner, Andrea Herstowski, Jeremy Shellhorn / DO Studio) — "published
for free use under the SIL Open Font License" per the site; no
`OFL.txt` ships in its own download zips, unlike Noto Sans above
|=== |===
The online map style (not vendored, fetched at runtime when the The map style — https://tiles.openfreemap.org/styles/liberty[OpenFreeMap
"Online" layer is selected) is "liberty"], built from https://www.openstreetmap.org[OpenStreetMap]
https://tiles.openfreemap.org/styles/liberty[OpenFreeMap "liberty"], data — is used two ways (see `docs/architecture.adoc`): fetched live
built from https://www.openstreetmap.org[OpenStreetMap] data. at runtime for the "Online" layer, and as a one-time vendored snapshot
(`public/vendor/liberty-style/liberty.json`) that the "Offline" layer
repoints at local data instead. Its icon sprite is vendored the same
way, under `public/vendor/liberty-sprite/` (`ofm.json`/`ofm.png` +
`@2x` variants, from `tiles.openfreemap.org/sprites/`). Neither has
been re-checked against a specific upstream version pin the way the
table above does — re-fetch both from `tiles.openfreemap.org` if
Liberty's own style/sprite ever visibly drifts from what's vendored.
`data/offline.pmtiles` (`lib/maptool/pmtiles_builder.rb`'s in-app
regeneration, or the manual recipe in `docs/development.adoc`) is
built at build time, not vendored, from
https://download.geofabrik.de[Geofabrik]'s per-country OpenStreetMap
extracts (ODbL).
`terrain.pmtiles` (same regeneration mechanism) is extracted at build
time, not vendored, from https://mapterhorn.com[Mapterhorn] — a
Protomaps-affiliated project publishing pre-built Terrarium-encoded
terrain as PMTiles. Per-region source licenses vary (CC-BY-4.0 and
similar); see
https://download.mapterhorn.com/attribution.json[their own attribution
list] for the full provenance.
Not a frontend asset like the above, but also baked into this app's own
Docker image (not a separate container the way kiwix-serve/gpsd are —
see `docs/deployment.adoc`/`docs/development.adoc`): three CLI tools
`lib/maptool/pmtiles_builder.rb` shells out to for offline.pmtiles/
terrain.pmtiles regeneration.
[cols="1,1,1,2"]
|===
| Tool | Version | License | Source
| go-pmtiles (`pmtiles` CLI)
| 1.31.2
| BSD-3-Clause
| https://github.com/protomaps/go-pmtiles
| Planetiler (`planetiler.jar`)
| 0.10.2
| Apache-2.0
| https://github.com/onthegomap/planetiler
| osmium-tool (`osmium`, installed via the `osmium-tool` Debian package)
| (Debian trixie's packaged version)
| GPL-3.0
| https://github.com/osmcode/osmium-tool
|===
To update a vendored library: download its package (e.g. To update a vendored library: download its package (e.g.
`npm pack <name>@<version>`), replace the corresponding files under `npm pack <name>@<version>`), replace the corresponding files under
`public/vendor/<name>/`, and update the version in this file. `public/vendor/<name>/`, and update the version in this file. To
update go-pmtiles or Planetiler, bump `PMTILES_VERSION`/
`PLANETILER_VERSION` in the `Dockerfile` and the version here —
osmium-tool tracks whatever version Debian trixie currently packages,
nothing to pin on this side.
@@ -0,0 +1 @@
{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"name":"Albania","iso_a2":"AL","iso_a3":"ALB"},"geometry":{"type":"Polygon","coordinates":[[[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.371768,41.877551],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855409],[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727]]]}},{"type":"Feature","properties":{"name":"Austria","iso_a2":"AT","iso_a3":"AUT"},"geometry":{"type":"Polygon","coordinates":[[[16.979667,48.123497],[16.903754,47.714866],[16.340584,47.712902],[16.534268,47.496171],[16.202298,46.852386],[16.011664,46.683611],[15.137092,46.658703],[14.632472,46.431817],[13.806475,46.509306],[12.376485,46.767559],[12.153088,47.115393],[11.164828,46.941579],[11.048556,46.751359],[10.442701,46.893546],[9.932448,46.920728],[9.47997,47.10281],[9.632932,47.347601],[9.594226,47.525058],[9.896068,47.580197],[10.402084,47.302488],[10.544504,47.566399],[11.426414,47.523766],[12.141357,47.703083],[12.62076,47.672388],[12.932627,47.467646],[13.025851,47.637584],[12.884103,48.289146],[13.243357,48.416115],[13.595946,48.877172],[14.338898,48.555305],[14.901447,48.964402],[15.253416,49.039074],[16.029647,48.733899],[16.499283,48.785808],[16.960288,48.596982],[16.879983,48.470013],[16.979667,48.123497]]]}},{"type":"Feature","properties":{"name":"Belarus","iso_a2":"BY","iso_a3":"BLR"},"geometry":{"type":"Polygon","coordinates":[[[28.176709,56.16913],[29.229513,55.918344],[29.371572,55.670091],[29.896294,55.789463],[30.873909,55.550976],[30.971836,55.081548],[30.757534,54.811771],[31.384472,54.157056],[31.791424,53.974639],[31.731273,53.794029],[32.405599,53.618045],[32.693643,53.351421],[32.304519,53.132726],[31.49764,53.16743],[31.305201,53.073996],[31.540018,52.742052],[31.78597,52.10168],[31.785992,52.101678],[30.927549,52.042353],[30.619454,51.822806],[30.555117,51.319503],[30.157364,51.416138],[29.254938,51.368234],[28.992835,51.602044],[28.617613,51.427714],[28.241615,51.572227],[27.454066,51.592303],[26.337959,51.832289],[25.327788,51.910656],[24.553106,51.888461],[24.005078,51.617444],[23.527071,51.578454],[23.508002,52.023647],[23.199494,52.486977],[23.799199,52.691099],[23.804935,53.089731],[23.527536,53.470122],[23.484128,53.912498],[24.450684,53.905702],[25.536354,54.282423],[25.768433,54.846963],[26.588279,55.167176],[26.494331,55.615107],[27.10246,55.783314],[28.176709,56.16913]]]}},{"type":"Feature","properties":{"name":"Belgium","iso_a2":"BE","iso_a3":"BEL"},"geometry":{"type":"Polygon","coordinates":[[[6.156658,50.803721],[6.043073,50.128052],[5.782417,50.090328],[5.674052,49.529484],[4.799222,49.985373],[4.286023,49.907497],[3.588184,50.378992],[3.123252,50.780363],[2.658422,50.796848],[2.513573,51.148506],[3.314971,51.345781],[3.315011,51.345777],[3.314971,51.345755],[4.047071,51.267259],[4.973991,51.475024],[5.606976,51.037298],[6.156658,50.803721]]]}},{"type":"Feature","properties":{"name":"Bosnia and Herz.","iso_a2":"BA","iso_a3":"BIH"},"geometry":{"type":"Polygon","coordinates":[[[18.56,42.65],[17.674922,43.028563],[17.297373,43.446341],[16.916156,43.667722],[16.456443,44.04124],[16.23966,44.351143],[15.750026,44.818712],[15.959367,45.233777],[16.318157,45.004127],[16.534939,45.211608],[17.002146,45.233777],[17.861783,45.06774],[18.553214,45.08159],[19.005485,44.860234],[19.00548,44.86023],[19.36803,44.863],[19.11761,44.42307],[19.59976,44.03847],[19.454,43.5681],[19.21852,43.52384],[19.03165,43.43253],[18.70648,43.20011],[18.56,42.65]]]}},{"type":"Feature","properties":{"name":"Bulgaria","iso_a2":"BG","iso_a3":"BGR"},"geometry":{"type":"Polygon","coordinates":[[[22.65715,44.234923],[22.944832,43.823785],[23.332302,43.897011],[24.100679,43.741051],[25.569272,43.688445],[26.065159,43.943494],[27.2424,44.175986],[27.970107,43.812468],[28.558081,43.707462],[28.039095,43.293172],[27.673898,42.577892],[27.99672,42.007359],[27.135739,42.141485],[26.117042,41.826905],[26.106138,41.328899],[25.197201,41.234486],[24.492645,41.583896],[23.692074,41.309081],[22.952377,41.337994],[22.881374,41.999297],[22.380526,42.32026],[22.545012,42.461362],[22.436595,42.580321],[22.604801,42.898519],[22.986019,43.211161],[22.500157,43.642814],[22.410446,44.008063],[22.65715,44.234923]]]}},{"type":"Feature","properties":{"name":"Croatia","iso_a2":"HR","iso_a3":"HRV"},"geometry":{"type":"Polygon","coordinates":[[[16.564808,46.503751],[16.882515,46.380632],[17.630066,45.951769],[18.456062,45.759481],[18.829825,45.908872],[19.072769,45.521511],[19.390476,45.236516],[19.005485,44.860234],[18.553214,45.08159],[17.861783,45.06774],[17.002146,45.233777],[16.534939,45.211608],[16.318157,45.004127],[15.959367,45.233777],[15.750026,44.818712],[Line truncated
+181
View File
@@ -0,0 +1,181 @@
require "open3"
require "tmpdir"
require "json"
require_relative "track_stats"
module Maptool
# Prototype: extracts route=hiking relations (name/colour/network/operator,
# full member-way geometry) straight out of a Geofabrik .osm.pbf — the same
# file PmtilesBuilder already downloads per country for offline.pmtiles, so
# this needs no separate download or third-party service. Three osmium
# subprocess steps do the heavy lifting (osmium is already a server
# dependency, see PmtilesBuilder/docs/development.adoc):
#
# 1. `osmium tags-filter FILE r/route=hiking -o hiking.osm.pbf` — pulls
# out just the hiking relations *and* (by default, no -R) every way/
# node they reference, so the output is small and self-contained.
# 2. `osmium add-locations-to-ways` — a plain Geofabrik PBF's ways only
# carry bare node *references* (ids), not coordinates; this resolves
# each way's node ids against the node objects in the same file and
# rewrites the way with real coordinates attached. Verified against a
# real extract (Macedonia) that skipping this step silently produces
# ways with empty x/y (`n123xy`, no numbers) in the OPL output below —
# not an error, just wrong output, so easy to miss without checking.
# 3. `osmium cat hiking.osm.pbf -f opl,locations_on_ways=true,add_metadata=false`
# — OPL is a plain-text, one-object-per-line format (see
# https://osmcode.org/opl-file-format/); locations_on_ways (now that
# step 2 actually populated them) embeds each way's node coordinates
# directly in its own line, so no separate node-id -> [lon,lat] table
# needs building, just two passes over text.
#
# No general OSM tool stitches a route relation's member ways into one
# line for you (routes are a semantic grouping, not a geometry type) —
# every hiking-trail renderer, including this app's own Overpass-based
# click handler (public/js/hiking_trails.js) and waymarkedtrails.org
# itself, does this same member-way walk by hand.
module HikingTrails
class ExtractError < StandardError; end
ROUTE_TAGS = %w[name description ref colour network operator].freeze
def self.osmium_bin
ENV.fetch("OSMIUM_BIN", "osmium")
end
# pbf_path: a Geofabrik-style .osm.pbf, e.g. one of
# PmtilesBuilder.cached_extracts' own files. Returns a GeoJSON
# FeatureCollection (MultiLineString per relation, one sub-line per
# member way — not one big concatenated LineString, since a relation's
# ways aren't always contiguous/ordered and jumping across a gap would
# draw a spurious straight connector).
def self.extract(pbf_path)
Dir.mktmpdir("maptool-hiking-trails") do |dir|
filtered = File.join(dir, "hiking.osm.pbf")
run!(osmium_bin, "tags-filter", pbf_path, "r/route=hiking", "-o", filtered)
located = File.join(dir, "hiking-located.osm.pbf")
run!(osmium_bin, "add-locations-to-ways", filtered, "-o", located)
opl_path = File.join(dir, "hiking.opl")
run!(osmium_bin, "cat", located, "-f", "opl,locations_on_ways=true,add_metadata=false", "-o", opl_path)
parse_opl(File.read(opl_path))
end
end
# Pure — no subprocess — so it's cheaply testable against a canned OPL
# fixture, same "keep the real logic testable without the real tool
# installed" reasoning OverpassPois.to_geojson already gives for staying
# separate from OverpassPois.fetch.
def self.parse_opl(text)
ways = {} # way id -> [[lon, lat], ...]
relations = [] # { tags:, members: [{type:, id:}, ...] }
text.each_line do |line|
fields = line.chomp.split(" ")
head = fields.first
next unless head
case head[0]
when "w"
ways[head[1..].to_i] = way_coordinates(fields)
when "r"
tags = tags_field(fields)
relations << { id: head[1..].to_i, tags: tags, members: members_field(fields) } if tags["route"] == "hiking"
end
end
features = relations.filter_map { |relation| relation_feature(relation, ways) }
{ "type" => "FeatureCollection", "features" => features }
end
def self.relation_feature(relation, ways)
lines = relation[:members]
.select { |member| member[:type] == "w" }
.filter_map { |member| ways[member[:id]] }
.select { |coords| coords.size >= 2 }
return nil if lines.empty?
distance = lines.sum { |coords| TrackStats.compute(coords)["distance_meters"] }
tags = relation[:tags]
properties = {
"id" => relation[:id],
"name" => tags["name"] || tags["description"],
"distance_meters" => distance.round(1),
}
ROUTE_TAGS.each { |key| properties[key] ||= tags[key] }
{
"type" => "Feature",
"properties" => properties.compact,
# Rounded to 5 decimal places (~1m) — full OSM float precision
# (~1cm) is pointless for a rendered line and roughly doubles the
# size of every coordinate pair once this many-country GeoJSON is
# actually served to a browser.
"geometry" => { "type" => "MultiLineString", "coordinates" => round_coordinates(lines) },
}
end
private_class_method :relation_feature
def self.round_coordinates(lines)
lines.map { |coords| coords.map { |lon, lat| [lon.round(5), lat.round(5)] } }
end
private_class_method :round_coordinates
def self.field(fields, letter)
fields.find { |f| f.start_with?(letter) }
end
private_class_method :field
def self.tags_field(fields)
raw = field(fields, "T")&.delete_prefix("T") || ""
return {} if raw.empty?
raw.split(",").to_h { |pair| pair.split("=", 2).map { |part| unescape(part.to_s) } }
end
private_class_method :tags_field
def self.members_field(fields)
raw = field(fields, "M")&.delete_prefix("M") || ""
return [] if raw.empty?
raw.split(",").map do |member|
{ type: member[0], id: member[1..].split("@", 2).first.to_i }
end
end
private_class_method :members_field
# "n123x14.123y49.456,n124x14.130y49.460,..." -> [[14.123, 49.456], ...].
# A member id with no embedded location (shouldn't happen with
# locations_on_ways=true and -R omitted, but a way with a dangling/
# missing node reference is possible in real-world data) is skipped
# rather than raising — one bad node shouldn't drop the whole route.
def self.way_coordinates(fields)
raw = field(fields, "N")&.delete_prefix("N") || ""
return [] if raw.empty?
raw.split(",").filter_map do |node_ref|
match = node_ref.match(/\An\d+x(?<lon>-?[\d.]+)y(?<lat>-?[\d.]+)\z/)
[match[:lon].to_f, match[:lat].to_f] if match
end
end
private_class_method :way_coordinates
# OPL escapes space/newline/comma/equals/@/% as %<hex>% (see
# https://osmcode.org/opl-file-format/#_encoding) — only tag keys/
# values and usernames can contain them; the field-letter prefixes and
# id/comma/@ separators we split on above are never themselves escaped.
def self.unescape(str)
str.gsub(/%([0-9a-fA-F]{1,6})%/) { [Regexp.last_match(1).to_i(16)].pack("U") }
end
private_class_method :unescape
def self.run!(*args)
stdout, stderr, status = Open3.capture3(*args)
raise ExtractError, "#{args.first} exited with status #{status.exitstatus}: #{[stdout, stderr].map(&:strip).reject(&:empty?).join("\n")}" unless status.success?
rescue Errno::ENOENT, Errno::EACCES => e
raise ExtractError, "could not run '#{args.first}' (#{e.message}) — is osmium-tool installed and on PATH?"
end
private_class_method :run!
end
end
+130
View File
@@ -0,0 +1,130 @@
require "net/http"
require "rexml/document"
module Maptool
# A reachability check plus a passthrough proxy for an external
# kiwix-serve instance serving an offline Wikipedia ZIM (see
# docs/development.adoc for how to set one up). A POI popup's "Nearby on
# Wikipedia" link (public/js/gpx.js) used to point straight at
# kiwix-serve itself — fine on a LAN, broken once this app started
# running behind a reverse proxy (map.priesol.net) that only forwards to
# *this* app, leaving no address a browser could reach kiwix-serve at
# directly. GET /kiwix/* in app.rb calls .proxy below instead.
module Kiwix
# <meta name="geo.position" content="LAT;LON"> — a standard tag
# Wikipedia's own MediaWiki geo extension puts on every geotagged
# article's page (confirmed live against a real ZIM), semicolon rather
# than comma-separated. Far simpler to match than the human-facing
# "48°08′46″N 17°10′38″E / 48.14611°N 17.17722°E" markup the article
# body itself renders (DMS *and* decimal, in varying wrapper markup).
GEO_POSITION_PATTERN = /<meta name="geo\.position" content="(-?[\d.]+);(-?[\d.]+)"/
def self.reachable?(url, open_timeout: 1, read_timeout: 2)
return false if url.to_s.strip.empty?
uri = URI(url)
Net::HTTP.start(uri.host, uri.port, open_timeout: open_timeout, read_timeout: read_timeout) { |http| http.head("/") }
true
rescue StandardError
false
end
# path already carries the /kiwix prefix kiwix-serve itself expects
# (started with --urlRootLocation=/kiwix, see docker-compose.yaml) —
# this is a plain passthrough, not a rewrite, so its emitted links stay
# correct without this having to touch response bodies at all. Returns
# nil (halted as a 502 by the caller) rather than raising, same
# not-reachable-isn't-exceptional stance as .reachable? above.
#
# path arrives already URL-*decoded* — Sinatra decodes a route's splat
# before handing it over — so an article title with non-ASCII
# characters (e.g. "/kiwix/content/wikipedia/Dlhé_diely") has to be
# re-escaped before URI#path= will accept it at all; it raises
# URI::InvalidComponentError on raw UTF-8 bytes rather than escaping
# them itself. Article links otherwise 502'd for exactly this reason.
def self.proxy(base_url, path, query_string, open_timeout: 2, read_timeout: 10)
uri = URI(base_url)
uri.path = URI::RFC2396_PARSER.escape(path)
uri.query = query_string unless query_string.to_s.empty?
Net::HTTP.start(uri.host, uri.port, open_timeout: open_timeout, read_timeout: read_timeout) { |http| http.request(Net::HTTP::Get.new(uri)) }
rescue StandardError
nil
end
# bbox: [south, west, north, east] — the "Wikipedia" map layer
# (public/js/gpx.js) refetches this on every pan/zoom for whatever's
# currently on screen. kiwix-serve's own geo search only *filters* by
# distance from a point, it doesn't echo each result's own coordinates
# back (confirmed live: neither its HTML nor its ?format=xml output
# carries one) — so every matching article's page is fetched too, and
# its coordinates read from GEO_POSITION_PATTERN above. Cheap since
# kiwix-serve serves its ZIM locally with no network round trip, unlike
# this same fetch-every-result shape would be against live Wikipedia.
def self.nearby(base_url, bbox, limit: 30, open_timeout: 2, read_timeout: 10)
south, west, north, east = bbox
lat = (south + north) / 2.0
lng = (west + east) / 2.0
radius_m = (haversine_km(lat, lng, north, east) * 1000).round
query = URI.encode_www_form(pattern: "", latitude: lat, longitude: lng, distance: radius_m, pageLength: limit, format: "xml")
response = proxy(base_url, "/kiwix/search", query, open_timeout: open_timeout, read_timeout: read_timeout)
return empty_collection unless response&.code == "200"
# One request per result — tried running these in parallel threads
# first (each is blocking I/O, so MRI's GIL releases during the
# actual wait), but measured no improvement against the real
# production ZIM (kiwix-serve itself appears to serialize incoming
# requests regardless), so plain sequential stayed. ~1.6s for a
# 30-result page on that box — fine for a refetch-on-pan-end layer,
# not for anything tighter; lower `limit` first if that's ever not
# enough headroom, before reaching for something more involved.
features = parse_search_results(response.body).filter_map { |result| point_feature(base_url, result, open_timeout, read_timeout) }
{ "type" => "FeatureCollection", "features" => features }
end
def self.empty_collection
{ "type" => "FeatureCollection", "features" => [] }
end
private_class_method :empty_collection
def self.parse_search_results(xml)
doc = REXML::Document.new(xml)
(doc.root&.get_elements("channel/item") || []).filter_map do |item|
title = item.elements["title"]&.text
link = item.elements["link"]&.text
{ title: title, link: link } if title && link
end
rescue REXML::ParseException
[]
end
private_class_method :parse_search_results
# result[:link] arrives already percent-encoded, straight out of
# kiwix-serve's own XML (e.g. "/kiwix/content/wikipedia/%C5%A0tadi%C3%B3n_Rapid")
# — decoded first so .proxy's own escaping (built for Sinatra's
# already-*decoded* splat, see its own comment above) doesn't double-
# encode the "%" and 404 the request.
def self.point_feature(base_url, result, open_timeout, read_timeout)
response = proxy(base_url, URI::RFC2396_PARSER.unescape(result[:link]), nil, open_timeout: open_timeout, read_timeout: read_timeout)
return nil unless response&.code == "200"
match = response.body.match(GEO_POSITION_PATTERN)
return nil unless match
{
"type" => "Feature",
"properties" => { "name" => result[:title], "link" => result[:link] },
"geometry" => { "type" => "Point", "coordinates" => [match[2].to_f, match[1].to_f] },
}
end
private_class_method :point_feature
def self.haversine_km(lat1, lng1, lat2, lng2)
earth_radius_km = 6371.0
dlat = (lat2 - lat1) * Math::PI / 180
dlng = (lng2 - lng1) * Math::PI / 180
a = (Math.sin(dlat / 2)**2) + (Math.cos(lat1 * Math::PI / 180) * Math.cos(lat2 * Math::PI / 180) * (Math.sin(dlng / 2)**2))
2 * earth_radius_km * Math.asin(Math.sqrt(a))
end
private_class_method :haversine_km
end
end
+47 -7
View File
@@ -1,5 +1,6 @@
require "net/http" require "net/http"
require "json" require "json"
require "time"
module Maptool module Maptool
# Fetches a Garmin LiveTrack session's track and metadata. # Fetches a Garmin LiveTrack session's track and metadata.
@@ -18,7 +19,7 @@ module Maptool
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36" USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36"
PUSH_PATTERN = /self\.__next_f\.push\((\[.*?\])\)<\/script>/m PUSH_PATTERN = /self\.__next_f\.push\((\[.*?\])\)<\/script>/m
Result = Struct.new(:points, :session, keyword_init: true) Result = Struct.new(:points, :session, :course, keyword_init: true)
def self.fetch(session_id, token) def self.fetch(session_id, token)
new.fetch(session_id, token) new.fetch(session_id, token)
@@ -29,6 +30,10 @@ module Maptool
# if that part wasn't found even though points were (seen in practice: # if that part wasn't found even though points were (seen in practice:
# session details are consistently present alongside points, but nothing # session details are consistently present alongside points, but nothing
# here depends on that holding forever). # here depends on that holding forever).
# `course`: the planned route (name/geoPoints), or nil — only present
# when the activity was actually started from a saved Garmin course
# (session["courseIds"] is how the page itself knows to fetch one; a
# plain unplanned activity has neither).
def fetch(session_id, token) def fetch(session_id, token)
payloads = parse_payloads(fetch_html(session_id, token)) payloads = parse_payloads(fetch_html(session_id, token))
@@ -36,18 +41,42 @@ module Maptool
raise FetchError, "no track points found (session invalid or expired?)" unless points raise FetchError, "no track points found (session invalid or expired?)" unless points
session = search(payloads) { |node| node if node["sessionName"] } session = search(payloads) { |node| node if node["sessionName"] }
# First of possibly several — a LiveTrack session only ever follows
# the one course it was started from.
course = search(payloads) { |node| node["courses"].first if node["courses"].is_a?(Array) && !node["courses"].empty? }
Result.new(points: clean(points), session: clean(session)) Result.new(points: clean(points), session: clean(session), course: clean(course))
end end
# Distance/duration/activity type come from the last track point (its # Distance/duration/activity type come from the last track point (its
# totals are cumulative for the whole session), name/type from the # totals are cumulative for the whole session), name/type from the
# session details — nil-safe throughout since either can be missing. # session details — nil-safe throughout since either can be missing.
# #
# "active": Garmin doesn't set a session's `end` until the activity is # "active": originally `session["end"].nil?`, on the assumption Garmin
# actually stopped, so its absence means the session is still recording # doesn't set `end` until the activity actually stops — disproven
# — inferred from the one (already-ended) session this was built # against a real still-recording session (2026-09-20): `end` was
# against, not verified against a session actually caught mid-activity. # already non-nil, set to exactly `start + 24h`, the share link's own
# expiry, not an actual end time. Two signals now, both verified live
# against that same session:
#
# * `end` itself, once it's actually in the past — watched the same
# session update it from that 24h placeholder to within a second of
# the last point's own time, immediately after the activity was
# saved on the watch. Authoritative and near-instant when present,
# so this is checked first.
# * failing that (still showing the future placeholder — an abandoned
# session never gets saved, so `end` never moves), recency of the
# last track point: Garmin posts one roughly every
# `postTrackPointFrequency` seconds (~15, observed) while genuinely
# still recording, so one older than ACTIVE_WITHIN means signal was
# lost a while ago (same "looks ended until it isn't" behavior
# Garmin's own LiveTrack page shows in that case).
#
# Both must agree the session is live — `end` already in the past
# means stopped even if the last point is only seconds old (exactly
# the save-immediately-after-the-last-point case above).
ACTIVE_WITHIN = 30 * 60 # seconds
def self.summarize(result) def self.summarize(result)
last = result.points.last || {} last = result.points.last || {}
session = result.session || {} session = result.session || {}
@@ -56,12 +85,23 @@ module Maptool
"activity_type" => last["activityType"], "activity_type" => last["activityType"],
"distance_meters" => last["totalDistanceMeters"], "distance_meters" => last["totalDistanceMeters"],
"duration_secs" => last["totalDurationSecs"], "duration_secs" => last["totalDurationSecs"],
"active" => session["end"].nil?, "active" => active?(last["dateTime"], session["end"]),
"start" => session["start"], "start" => session["start"],
"end" => session["end"], "end" => session["end"],
} }
end end
def self.active?(last_point_time, session_end)
return false unless last_point_time
now = Time.now.utc
return false if session_end && Time.parse(session_end) <= now
Time.parse(last_point_time) > now - ACTIVE_WITHIN
rescue ArgumentError, TypeError
false
end
private private
# The RSC payload serializes an absent field as the literal string # The RSC payload serializes an absent field as the literal string
+95 -26
View File
@@ -2,39 +2,82 @@ require "net/http"
require "json" require "json"
module Maptool module Maptool
# A dev-time tool (see the "overpass:pois" Rake task), not something the # Originally a dev-time-only tool (the "overpass:pois" Rake task) kept
# deployed app calls itself — same "generate locally, drop the result in # off the running server so it never depended on Overpass's public
# data/gpx/" story as offline.pmtiles/terrain.pmtiles (docs/development.adoc), # instance being up, or ate into its (fairly strict, shared) rate limits,
# kept off the running server so it never depends on Overpass's public # on every page load. plugins/overpass-pois now also calls this from the
# instance being up, or eats into its (fairly strict, shared) rate limits # running app — but only ever on an explicit, login-gated "Run for this
# on every page load. # area" click (see lib/maptool/plugins.rb), never automatically, so that
# concern doesn't apply there the way it would if this ran on page load.
module OverpassPois module OverpassPois
class FetchError < StandardError; end class FetchError < StandardError; end
OVERPASS_API = "https://overpass-api.de/api/interpreter".freeze # Same three public mirrors public/js/hiking_trails.js races — tried in
# turn here instead, falling through to the next on any failure: the
# shared free instances regularly 504/429 under load, and a plugin run
# is a one-off click, not worth threads to race them.
OVERPASS_APIS = [
"https://overpass-api.de/api/interpreter",
"https://overpass.kumi.systems/api/interpreter",
"https://overpass.private.coffee/api/interpreter",
].freeze
# Each entry: an Overpass tag filter -> a human category label, used # Each entry: an Overpass tag filter -> { label:, icon:, color: }, used
# both to build the query (unioning every filter) and to label results # both to build the query (unioning every filter) and to label/style
# back (matched by scanning an element's own tags for the same # results back (matched by scanning an element's own tags for the same
# key/value, not by which branch of the query found it — Overpass's # key/value, not by which branch of the query found it — Overpass's
# `out body` doesn't say which union member matched). # `out body` doesn't say which union member matched). `icon` names one
# of the marker glyphs public/js/icons.js's POI_ICONS already vendors
# for the GPX/p4n upload path — reused here rather than drawn again —
# so these render the same way a p4n2gpx waypoint of the same kind
# does, instead of every point falling back to gpx.js's plain red
# unlabeled marker (its TRACK_COLOR default for a point with no color
# of its own). shop_supermarket/shop_convenience both point at the same
# NPS "store" glyph (icons.js's STORE_ICON) — that set has no separate
# grocery-specific pictogram, so this is the honest match for both.
CATEGORIES = { CATEGORIES = {
{ "amenity" => "drinking_water" } => "Drinking water", { "amenity" => "drinking_water" } => { label: "Drinking water", icon: "amenity_drinking_water", color: "#2e86de" },
{ "amenity" => "sanitary_dump_station" } => "Dump station", { "amenity" => "sanitary_dump_station" } => { label: "Dump station", icon: "amenity_sanitary_dump_station", color: "#8d6e63" },
{ "amenity" => "fuel", "fuel:lpg" => "yes" } => "LPG refill", { "amenity" => "fuel", "fuel:lpg" => "yes" } => { label: "LPG refill", icon: "shop_gas", color: "#e67e22" },
{ "shop" => "gas" } => "LPG refill", { "shop" => "gas" } => { label: "LPG refill", icon: "shop_gas", color: "#e67e22" },
{ "amenity" => "toilets" } => "Public toilet", { "amenity" => "toilets" } => { label: "Public toilet", icon: "amenity_toilets", color: "#8d6e63" },
{ "shop" => "laundry" } => "Laundry", { "shop" => "laundry" } => { label: "Laundry", icon: "shop_laundry", color: "#5b9bd5" },
{ "shop" => "supermarket" } => "Supermarket", { "shop" => "supermarket" } => { label: "Supermarket", icon: "shop_supermarket", color: "#27ae60" },
{ "shop" => "convenience" } => "Convenience store", { "shop" => "convenience" } => { label: "Convenience store", icon: "shop_convenience", color: "#27ae60" },
{ "natural" => "spring" } => "Spring", { "natural" => "spring" } => { label: "Spring", icon: "amenity_drinking_water", color: "#2e86de" },
}.freeze }.freeze
# Tags worth surfacing in a popup, beyond the bare category label —
# each rendered as its own "Label: value" line, which gpx.js's
# formatDescription (written for p4n2gpx's own "Label: value" export
# lines) already turns into a distinct row with no changes needed on
# that end. website/contact:website are emitted as a bare URL line
# instead, since formatDescription also already auto-links those.
DESCRIPTION_TAGS = [
["opening_hours", "Opening hours"],
["operator", "Operator"],
].freeze
# bbox: [south, west, north, east] (Overpass's own axis order). # bbox: [south, west, north, east] (Overpass's own axis order).
def self.fetch(bbox, timeout: 60) def self.fetch(bbox, timeout: 60)
query = build_query(bbox, timeout: timeout) query = build_query(bbox, timeout: timeout)
uri = URI(OVERPASS_API) errors = OVERPASS_APIS.map do |url|
response = Net::HTTP.post_form(uri, "data" => query) return post(URI(url), query, timeout)
rescue FetchError, Net::OpenTimeout, Net::ReadTimeout, SystemCallError, SocketError, OpenSSL::SSL::SSLError, JSON::ParserError => e
"#{URI(url).host}: #{e.message}"
end
raise FetchError, errors.join("; ")
end
def self.post(uri, query, timeout)
# overpass-api.de answers Net::HTTP's default "Ruby" User-Agent with
# a 406 (verified 2026-10-09) — any identifying UA gets through.
request = Net::HTTP::Post.new(uri, "User-Agent" => "maptool (Overpass camper POIs plugin)")
request.set_form_data("data" => query)
# read_timeout past the query's own [timeout:] — Net::HTTP's default
# 60s equals it, so a big viewport could hit Net::ReadTimeout just as
# Overpass was about to answer (a country-sized bbox measured ~57s).
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true, read_timeout: timeout + 30) { |http| http.request(request) }
raise FetchError, "unexpected response #{response.code}" unless response.is_a?(Net::HTTPSuccess) raise FetchError, "unexpected response #{response.code}" unless response.is_a?(Net::HTTPSuccess)
JSON.parse(response.body) JSON.parse(response.body)
@@ -58,12 +101,19 @@ module Maptool
features = (overpass_response["elements"] || []).filter_map do |element| features = (overpass_response["elements"] || []).filter_map do |element|
next unless element["type"] == "node" next unless element["type"] == "node"
category = category_for(element["tags"] || {}) tags = element["tags"] || {}
category = category_for(tags)
next unless category next unless category
{ {
"type" => "Feature", "type" => "Feature",
"properties" => { "name" => (element["tags"] || {})["name"] || category, "category" => category }, "properties" => {
"name" => tags["name"] || category[:label],
"category" => category[:label],
"icon" => category[:icon],
"color" => category[:color],
"description" => description_for(tags),
}.compact,
"geometry" => { "type" => "Point", "coordinates" => [element["lon"], element["lat"]] }, "geometry" => { "type" => "Point", "coordinates" => [element["lon"], element["lat"]] },
} }
end end
@@ -71,11 +121,30 @@ module Maptool
end end
def self.category_for(tags) def self.category_for(tags)
CATEGORIES.each do |filter, label| CATEGORIES.each do |filter, category|
return label if filter.all? { |k, v| tags[k] == v } return category if filter.all? { |k, v| tags[k] == v }
end end
nil nil
end end
private_class_method :category_for private_class_method :category_for
def self.description_for(tags)
lines = DESCRIPTION_TAGS.filter_map { |tag, label| "#{label}: #{clean_tag(tags[tag])}" if tags[tag] }
website = tags["website"] || tags["contact:website"]
lines << clean_tag(website) if website
lines.empty? ? nil : lines.join("\n")
end
private_class_method :description_for
# An OSM tag value is free text from a world-editable map — an embedded
# newline could otherwise inject an extra "line" of its own into the
# description, e.g. an operator tag ending in "\nhttps://evil.example"
# would render as its own separate, legitimate-looking link line once
# gpx.js's formatDescription (written for p4n2gpx's own well-formed
# "Label: value" lines) splits on "\n".
def self.clean_tag(value)
value.to_s.tr("\n\r", " ").strip
end
private_class_method :clean_tag
end end
end end
+86
View File
@@ -0,0 +1,86 @@
require "json"
require "open3"
module Maptool
# Runs an external "importer" script that turns a bbox into a GeoJSON
# FeatureCollection, and lists what's available. Each plugin is a
# directory under one of `dirs` with a plugin.json manifest ({"label":
# "...", "command": "./run.rb"}) plus whatever script it names — the
# entire interface a plugin needs to know about maptool is "read
# --south/--west/--north/--east, print GeoJSON to stdout". Kept this thin
# on purpose: it's what lets an importer that scrapes a site whose ToS
# forbids that live in its own private repo, dropped into plugins/
# locally, never touching this (public) one — see plugins/overpass-pois
# for a real, in-repo example of the contract itself.
#
# `dirs` takes either one directory or an array of them (wrapped with
# Array() below) — app.rb passes both the built-in plugins/ (baked into
# the image, wiped and replaced on every deploy along with the rest of
# the checkout) and an optional second directory under the persistent
# data/ bind mount, so a private plugin dropped there survives a
# redeploy the same way an uploaded GPX file does.
module Plugins
class RunError < StandardError; end
# A bare directory name, same rule Sinatra's own :name route param
# already enforces (no "/"), but ".." alone would still resolve one
# level up via File.join — reject that too before it ever reaches the
# filesystem, same spirit as GpxStore's own path-escape guard.
NAME_PATTERN = /\A[A-Za-z0-9_-]+\z/
def self.list(dirs)
Array(dirs).flat_map do |dir|
Dir.glob(File.join(dir, "*", "plugin.json")).filter_map do |manifest_path|
name = File.basename(File.dirname(manifest_path))
manifest = JSON.parse(File.read(manifest_path))
{ "name" => name, "label" => manifest["label"] || name }
rescue JSON::ParserError
nil
end
end.uniq { |plugin| plugin["name"] }.sort_by { |p| p["label"] }
end
# bbox: [south, west, north, east]. Raises RunError with a short
# message on anything that isn't a clean run — an unknown plugin, a
# non-zero exit, or output that isn't a GeoJSON FeatureCollection — so
# the route can turn it into a single error response without knowing
# any of these details itself. When the same name exists under more
# than one of `dirs`, the first one that has it wins — same precedence
# as list's `uniq` above.
def self.run(dirs, name, bbox)
raise RunError, "unknown plugin" unless name =~ NAME_PATTERN
plugin_dir = Array(dirs).map { |dir| File.join(dir, name) }.find { |dir| File.file?(File.join(dir, "plugin.json")) }
raise RunError, "unknown plugin" unless plugin_dir
manifest_path = File.join(plugin_dir, "plugin.json")
command = begin
JSON.parse(File.read(manifest_path))["command"]
rescue JSON::ParserError
raise RunError, "plugin has an invalid plugin.json"
end
raise RunError, "plugin has no command" unless command
south, west, north, east = bbox
args = ["--south=#{south}", "--west=#{west}", "--north=#{north}", "--east=#{east}"]
stdout, stderr, status = Open3.capture3(command, *args, chdir: plugin_dir)
# First stderr line too — for a Ruby plugin that's the exception
# message (e.g. "...: unexpected response 406"), the only clue to why.
unless status.success?
reason = stderr.lines.first&.strip
raise RunError, ["plugin exited with status #{status.exitstatus}", reason].compact.reject(&:empty?).join(": ")
end
geojson = JSON.parse(stdout)
raise RunError, "plugin did not print a GeoJSON FeatureCollection" unless geojson.is_a?(Hash) && geojson["type"] == "FeatureCollection"
geojson
rescue Errno::ENOENT, Errno::EACCES => e
raise RunError, e.message
rescue JSON::ParserError
raise RunError, "plugin did not print valid JSON"
end
end
end
+745
View File
@@ -0,0 +1,745 @@
require "open3"
require "net/http"
require "uri"
require "json"
require "tmpdir"
require "fileutils"
require "etc"
require_relative "hiking_trails"
module Maptool
# Regenerates data/offline.pmtiles and data/terrain.pmtiles for the
# currently *selected* regions (data/offline_regions.json, an array of
# Natural Earth iso_a2 country codes — see available_regions/
# selected_regions/set_selected_regions below). No job queue: each build
# runs on its own background Thread and reports into a Mutex-guarded
# status Hash a route can poll, the same shape app.rb's own GNSS poller
# (GNSS_LATEST/GNSS_LATEST_MUTEX) already uses.
module PmtilesBuilder
class BuildError < StandardError; end
# Natural Earth (public domain, no attribution required) 110m admin-0
# countries, filtered to Europe and trimmed to name/iso_a2/iso_a3 —
# see the plan this was built from for the exact filter. 110m is
# deliberately coarse (a km or so of border precision, not
# survey-grade) — fine for "which country to grab," a same-schema swap
# to Natural Earth's 50m/10m cut if that ever needs to be tighter.
REGIONS_FILE = File.join(__dir__, "data", "europe_countries.geojson")
# Every iso_a2 code in REGIONS_FILE mapped to its Geofabrik download
# slug (https://download.geofabrik.de/<slug>-latest.osm.pbf) — Geofabrik
# names regions, not ISO codes, and doesn't always split the way a
# country border does, so this table exists rather than deriving the
# slug from the country name. Two known quirks worth knowing about,
# not worth working around:
# - RU has no "europe/" prefix (Russia is its own top-level index,
# and unlike every other entry here is a single ~4GB file covering
# the whole country rather than a European-only slice).
# - GB's "great-britain" slug is England/Scotland/Wales only —
# Northern Ireland lives in "ireland-and-northern-ireland" instead
# (bundled with IE, not GB). Selecting GB alone won't include NI.
GEOFABRIK_SLUGS = {
"AL" => "europe/albania",
"AT" => "europe/austria",
"BY" => "europe/belarus",
"BE" => "europe/belgium",
"BA" => "europe/bosnia-herzegovina",
"BG" => "europe/bulgaria",
"HR" => "europe/croatia",
"CZ" => "europe/czech-republic",
"DK" => "europe/denmark",
"EE" => "europe/estonia",
"FI" => "europe/finland",
"FR" => "europe/france",
"DE" => "europe/germany",
"GR" => "europe/greece",
"HU" => "europe/hungary",
"IS" => "europe/iceland",
"IE" => "europe/ireland-and-northern-ireland",
"IT" => "europe/italy",
"XK" => "europe/kosovo",
"LV" => "europe/latvia",
"LT" => "europe/lithuania",
"LU" => "europe/luxembourg",
"MD" => "europe/moldova",
"ME" => "europe/montenegro",
"NL" => "europe/netherlands",
"MK" => "europe/macedonia",
"NO" => "europe/norway",
"PL" => "europe/poland",
"PT" => "europe/portugal",
"RO" => "europe/romania",
"RU" => "russia",
"RS" => "europe/serbia",
"SK" => "europe/slovakia",
"SI" => "europe/slovenia",
"ES" => "europe/spain",
"SE" => "europe/sweden",
"CH" => "europe/switzerland",
"UA" => "europe/ukraine",
"GB" => "europe/great-britain",
}.freeze
# Mapterhorn (a Protomaps-affiliated project) publishes Terrarium-
# encoded terrain as pre-built PMTiles archives: one global
# planet.pmtiles (z0-12) plus ~450 regional chunks (z13 up to a
# per-region max, 13-18) — extract_offline below no longer touches
# Protomaps at all (see GEOFABRIK_SLUGS above), but terrain stays on
# this same "extract only the region's byte ranges from a remote
# archive" story via go-pmtiles, unrelated to the basemap swap.
MAPTERHORN_MANIFEST_URL = "https://download.mapterhorn.com/download_urls.json"
MAPTERHORN_PLANET_NAME = "planet.pmtiles"
# Deliberately *below* the online hillshade layer's own cap
# (public/js/overlays.js's ONLINE_TERRAIN_TILES source, maxzoom: 15) —
# raster DEM tiles don't compress away like vector ones do, so every
# extra zoom level roughly quadruples storage. z13 is each regional
# chunk's own native minzoom (see the comment above), so this is the
# cheapest useful cut: one raster level per chunk, not a 15-13=2-level
# pyramid on top of it. Bumped into a 181GB terrain.pmtiles for a
# 5-country selection before this was lowered — see docs/development.adoc.
TERRAIN_MAX_ZOOM = 13
OFFLINE_STATUS = { state: "idle" }
TERRAIN_STATUS = { state: "idle" }
OFFLINE_MUTEX = Mutex.new
TERRAIN_MUTEX = Mutex.new
def self.offline_status
OFFLINE_MUTEX.synchronize { OFFLINE_STATUS.dup }
end
def self.terrain_status
TERRAIN_MUTEX.synchronize { TERRAIN_STATUS.dup }
end
# Test-only: the status hashes are process-wide state (same caveat as
# GPX_STORE/LIVETRACK_STORE in app.rb), so the suite needs a way to
# reset them between tests the way AppTestHelper#teardown already does
# for those.
def self.reset!
OFFLINE_MUTEX.synchronize { OFFLINE_STATUS.replace(state: "idle") }
TERRAIN_MUTEX.synchronize { TERRAIN_STATUS.replace(state: "idle") }
end
# --- region selection ---
def self.available_regions
region_features.map { |f| { code: f["properties"]["iso_a2"], name: f["properties"]["name"] } }.sort_by { |r| r[:name] }
end
def self.selected_regions(data_dir)
path = selected_regions_path(data_dir)
return [] unless File.exist?(path)
JSON.parse(File.read(path))
rescue JSON::ParserError
[]
end
def self.set_selected_regions(data_dir, codes)
unknown = codes - available_regions.map { |r| r[:code] }
raise BuildError, "unknown region code(s): #{unknown.join(", ")}" unless unknown.empty?
File.write(selected_regions_path(data_dir), JSON.generate(codes))
end
def self.selected_regions_path(data_dir)
File.join(data_dir, "offline_regions.json")
end
private_class_method :selected_regions_path
def self.region_features
@region_features ||= JSON.parse(File.read(REGIONS_FILE))["features"]
end
private_class_method :region_features
# Still used by terrain (below) to compute the aggregate bbox Mapterhorn
# chunk intersection needs — offline.pmtiles no longer needs this at
# all, since each Geofabrik country file is already clipped to that
# country's real border (more accurate than this 110m polygon, not
# less), so there's no separate "--region=" precision step for it
# anymore.
def self.region_bbox(codes)
selected = region_features.select { |f| codes.include?(f["properties"]["iso_a2"]) }
raise BuildError, "no matching regions for #{codes.join(", ")}" if selected.empty?
coords = selected.flat_map { |f| ring_coordinates(f["geometry"]) }
lons = coords.map { |lng, _lat| lng }
lats = coords.map { |_lng, lat| lat }
[lats.min, lons.min, lats.max, lons.max]
end
private_class_method :region_bbox
def self.ring_coordinates(geometry)
case geometry["type"]
when "Polygon" then geometry["coordinates"].flatten(1)
when "MultiPolygon" then geometry["coordinates"].flatten(2)
else []
end
end
private_class_method :ring_coordinates
# --- builds ---
# Returns once the background Thread has started, not once the build
# finishes — raises BuildError (the caller turns this into an error
# response) if nothing's selected yet, or one's already running.
#
# download_extract/fetch_last_modified exist as injectable seams so
# tests can exercise the rest of this (scratch dir, osmium/planetiler
# invocation, atomic rename, the per-country cache below) without a
# real network call — same reasoning test_helper.rb already gives for
# keeping /api/plugins route tests off the real Overpass API.
def self.build_offline(data_dir:, download_extract: method(:download_extract), fetch_last_modified: method(:fetch_geofabrik_last_modified))
codes = selected_regions(data_dir)
raise BuildError, "select at least one region first" if codes.empty?
begin_run!(OFFLINE_MUTEX, OFFLINE_STATUS)
Thread.new do
run_job(OFFLINE_MUTEX, OFFLINE_STATUS) do |report_step|
extract_offline(codes, data_dir, download_extract, fetch_last_modified, report_step)
end
end
end
# fetch_manifest: same injectable-seam reasoning as download_extract
# above, for the one Mapterhorn manifest lookup this needs.
def self.build_terrain(data_dir:, fetch_manifest: method(:fetch_mapterhorn_manifest))
codes = selected_regions(data_dir)
raise BuildError, "select at least one region first" if codes.empty?
begin_run!(TERRAIN_MUTEX, TERRAIN_STATUS)
Thread.new do
run_job(TERRAIN_MUTEX, TERRAIN_STATUS) do |report_step|
build_terrain_pmtiles(codes, data_dir, fetch_manifest, report_step)
end
end
end
def self.begin_run!(mutex, status)
mutex.synchronize do
raise BuildError, "a build is already running" if status[:state] == "running"
status.replace(state: "running", started_at: Time.now.utc.iso8601)
end
end
private_class_method :begin_run!
# Yields a report_step proc the build can call with a short
# human-readable description of what it's doing right now ("downloading
# SK (1/2)", "tiling with planetiler", ...) — surfaced as status[:step]
# so GET .../build-status can show progress beyond just "running since
# X" (see docs/development.adoc).
def self.run_job(mutex, status)
report_step = ->(text) { mutex.synchronize { status[:step] = text } }
yield report_step
mutex.synchronize { status.merge!(state: "done", finished_at: Time.now.utc.iso8601).delete(:message) }
rescue => e
mutex.synchronize { status.merge!(state: "error", finished_at: Time.now.utc.iso8601, message: e.message) }
ensure
mutex.synchronize { status.delete(:step) }
end
private_class_method :run_job
# --- offline.pmtiles ---
# One Geofabrik .osm.pbf per selected country (already clipped to that
# country's real border), osmium-merged into one file if more than one
# was selected (skipped entirely for a single country — nothing to
# merge), then tiled by Planetiler using its default OpenMapTiles
# profile straight to PMTiles — the same vector schema
# tiles.openfreemap.org's Liberty style already expects, so
# public/js/map.js's offlineStyle() can reuse ONLINE_STYLE_PATCH
# unchanged instead of a separate protomaps-themes-base palette.
def self.extract_offline(codes, data_dir, download_extract, fetch_last_modified, report_step)
scratch_dir = Dir.mktmpdir("maptool-offline")
sources = codes.each_with_index.map do |code, i|
slug = GEOFABRIK_SLUGS.fetch(code) { raise BuildError, "no Geofabrik source known for region #{code}" }
report_step.call(progress_step("fetching #{code}", codes, i))
cached_extract(code, slug, data_dir, download_extract, fetch_last_modified)
end
osm_path =
if sources.size == 1
sources.first["path"]
else
report_step.call("merging with osmium")
merged_path = File.join(scratch_dir, "merged.osm.pbf")
run_osmium!("merge", *sources.map { |s| s["path"] }, "-o", merged_path)
merged_path
end
report_step.call("tiling with planetiler")
# .tmp.pmtiles, not .pmtiles.tmp — Planetiler picks its output archive
# format (pmtiles vs mbtiles) from the file extension, so a ".tmp"
# suffix made it fail with "Unsupported format tmp" instead of
# actually tiling anything.
tmp_path = File.join(data_dir, "offline.tmp.pmtiles")
# --download: the OpenMapTiles profile also needs a few small auxiliary
# sources (water polygons, Natural Earth, lake centerlines) alongside
# the OSM extract itself — without this flag Planetiler expects them
# to already exist on disk and fails instead of fetching them. They
# land under Planetiler's own default "data/sources/", relative to
# this process's working directory (the app root, so in practice
# that's data_dir's own "sources" subdirectory) — fetched once,
# reused by every later build.
# --threads: Planetiler's own core-count autodetection can come up
# short in a container (cgroup/JVM detection quirks vary by runtime),
# leaving most of a many-core host idle — Etc.nprocessors asks the
# OS directly (sched_getaffinity on Linux), which correctly reflects
# whatever's actually usable by this process even under a container.
run_planetiler!("--osm-path=#{osm_path}", "--output=#{tmp_path}", "--download", "--threads=#{Etc.nprocessors}")
File.rename(tmp_path, File.join(data_dir, "offline.pmtiles"))
File.write(offline_meta_path(data_dir), JSON.generate(sources: sources.map { |s| s.slice("code", "slug", "last_modified") }))
report_step.call("extracting hiking trails")
extract_hiking_trails(sources, data_dir)
ensure
FileUtils.remove_entry(scratch_dir) if scratch_dir && Dir.exist?(scratch_dir)
File.delete(tmp_path) if tmp_path && File.exist?(tmp_path)
end
private_class_method :extract_offline
# One GeoJSON per country (data/hiking_trails/<CODE>.geojson), not one
# merged file — the frontend only ever needs to show a country at a
# time the viewer actually picks (see HikingTrailsControl's country
# checklist), and a combined multi-country file was needlessly making
# every viewer fetch every selected country's trails regardless.
#
# Runs over the same per-country .osm.pbf files `sources` above already
# downloaded/cached for offline.pmtiles itself — no separate download.
# Cached the same way geofabrik_cache is: skipped for a country whose
# extract is already newer than its source .osm.pbf, so growing the
# region selection by one country only extracts that one, not every
# already-covered country all over again.
#
# Best-effort per country: an extraction problem (a malformed PBF
# region, an osmium hiccup) shouldn't fail the whole offline.pmtiles
# build, or even the other countries in this same selection, over
# what's a bonus overlay, not the core map.
def self.extract_hiking_trails(sources, data_dir)
FileUtils.mkdir_p(hiking_trails_dir(data_dir))
sources.each do |source|
out_path = hiking_trails_country_path(data_dir, source["code"])
next if File.exist?(out_path) && File.mtime(out_path) >= File.mtime(source["path"])
tmp_path = "#{out_path}.tmp"
begin
File.write(tmp_path, JSON.generate(HikingTrails.extract(source["path"])))
File.rename(tmp_path, out_path)
rescue HikingTrails::ExtractError => e
File.delete(tmp_path) if File.exist?(tmp_path)
warn "hiking trails extraction failed for #{source["code"]}, skipping: #{e.message}"
end
end
end
private_class_method :extract_hiking_trails
def self.hiking_trails_dir(data_dir)
File.join(data_dir, "hiking_trails")
end
def self.hiking_trails_country_path(data_dir, code)
File.join(hiking_trails_dir(data_dir), "#{code}.geojson")
end
# Country codes with an already-extracted offline hiking-trails file,
# sorted — not necessarily the same as the *current* region selection
# (accumulates like geofabrik_cache does; a country deselected after
# being built once is left alone rather than swept up here).
def self.hiking_trails_countries(data_dir)
Dir.glob(File.join(hiking_trails_dir(data_dir), "*.geojson")).map { |path| File.basename(path, ".geojson") }.sort
end
# Renders a report_step string like "fetching PL (3/4) — done: SK, CZ —
# pending: HU" — so GET .../build-status shows not just "it's running"
# but which of the current build's sources is in flight and which are
# already behind/ahead of it.
def self.progress_step(action, labels, index)
done = labels[0...index]
pending = labels[(index + 1)..] || []
parts = ["#{action} (#{index + 1}/#{labels.size})"]
parts << "done: #{done.join(", ")}" unless done.empty?
parts << "pending: #{pending.join(", ")}" unless pending.empty?
parts.join(" — ")
end
private_class_method :progress_step
def self.geofabrik_url(slug)
"https://download.geofabrik.de/#{slug}-latest.osm.pbf"
end
private_class_method :geofabrik_url
# Per-country .osm.pbf cache, kept across builds under data_dir (not
# scratch_dir, which is wiped every run) — changing the region
# selection re-downloads only the countries that are new to it, and
# re-running the same selection re-downloads nothing unless Geofabrik's
# own Last-Modified for that country moved on. A stamp file next to
# each cached extract records the Last-Modified it was fetched with;
# a HEAD check (cheap) decides whether the multi-GB GET (not cheap) is
# skippable.
def self.cached_extract(code, slug, data_dir, download_extract, fetch_last_modified)
cache_dir = geofabrik_cache_dir(data_dir)
FileUtils.mkdir_p(cache_dir)
path = File.join(cache_dir, "#{code}.osm.pbf")
stamp_path = "#{path}.last_modified"
url = geofabrik_url(slug)
if File.exist?(path) && File.exist?(stamp_path)
current = begin
fetch_last_modified.call(url)
rescue BuildError
nil
end
return { "code" => code, "slug" => slug, "last_modified" => current, "path" => path } if current && current == File.read(stamp_path)
end
last_modified = download_extract.call(url, path)
File.write(stamp_path, last_modified.to_s)
{ "code" => code, "slug" => slug, "last_modified" => last_modified, "path" => path }
end
private_class_method :cached_extract
def self.geofabrik_cache_dir(data_dir)
File.join(data_dir, "geofabrik_cache")
end
private_class_method :geofabrik_cache_dir
# Real network implementation of the download_extract seam above —
# streams the extract to dest (some of these are multi-GB — Net::HTTP's
# plain #get buffers the whole response body in memory first, which
# read_body's block form avoids) and returns its Last-Modified header
# (free off the same GET, no separate HEAD needed) for the sidecar
# meta / update-check below. Geofabrik 302s (e.g. .../europe/austria
# redirecting to wherever actually serves it) — followed manually
# since request_get's block form doesn't do this itself.
def self.download_extract(url, dest, limit: 5)
raise BuildError, "too many redirects downloading #{url}" if limit.zero?
uri = URI(url)
last_modified = nil
redirect_to = nil
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request_get(uri) do |response|
case response
when Net::HTTPSuccess
last_modified = response["last-modified"]
File.open(dest, "wb") { |file| response.read_body { |chunk| file.write(chunk) } }
when Net::HTTPRedirection
redirect_to = URI.join(url, response["location"]).to_s
else
raise BuildError, "could not download #{url} (HTTP #{response.code})"
end
end
end
return download_extract(redirect_to, dest, limit: limit - 1) if redirect_to
last_modified
end
# Sidecar recording which Geofabrik sources (country code, slug, and
# that request's Last-Modified) the on-disk offline.pmtiles was
# actually built from — the file itself carries no such record. nil if
# never built (or built before this existed).
def self.offline_meta(data_dir)
read_json(offline_meta_path(data_dir))
end
# Compares each currently-selected country's live Geofabrik
# Last-Modified against what's recorded, without downloading anything
# — nil (not true/false) if there's nothing to compare yet (no local
# build, nothing selected) or a check couldn't be completed, so the
# caller can tell "don't know" apart from "no". Also naturally reports
# "yes" if the selection changed since the last build (a country now
# relevant that wasn't recorded, or vice versa) — same reasoning
# terrain_update_available? below already uses.
def self.offline_update_available?(data_dir, fetch_last_modified: method(:fetch_geofabrik_last_modified))
meta = offline_meta(data_dir)
return nil unless meta
codes = selected_regions(data_dir)
return nil if codes.empty?
current = codes.map do |code|
slug = GEOFABRIK_SLUGS[code]
return nil unless slug
{ "code" => code, "last_modified" => fetch_last_modified.call(geofabrik_url(slug)) }
end.sort_by { |s| s["code"] }
recorded = (meta["sources"] || []).map { |s| s.slice("code", "last_modified") }.sort_by { |s| s["code"] }
current != recorded
rescue BuildError
nil
end
def self.fetch_geofabrik_last_modified(url, limit: 5)
raise BuildError, "too many redirects reaching #{url}" if limit.zero?
uri = URI(url)
response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.head(uri) }
case response
when Net::HTTPSuccess then response["last-modified"]
when Net::HTTPRedirection then fetch_geofabrik_last_modified(URI.join(url, response["location"]).to_s, limit: limit - 1)
else raise BuildError, "could not reach #{url}"
end
end
def self.offline_meta_path(data_dir)
File.join(data_dir, "offline.pmtiles.meta.json")
end
private_class_method :offline_meta_path
# Deletes offline.pmtiles, its sidecar meta, and the whole per-country
# download cache (data/geofabrik_cache/) — "start over" for the offline
# basemap. The current selection (data/offline_regions.json) is left
# alone, so a following build just re-downloads it fresh.
def self.delete_offline_data(data_dir)
OFFLINE_MUTEX.synchronize { raise BuildError, "a build is already running" if OFFLINE_STATUS[:state] == "running" }
File.delete(File.join(data_dir, "offline.pmtiles")) if File.exist?(File.join(data_dir, "offline.pmtiles"))
File.delete(offline_meta_path(data_dir)) if File.exist?(offline_meta_path(data_dir))
FileUtils.remove_entry(hiking_trails_dir(data_dir)) if Dir.exist?(hiking_trails_dir(data_dir))
cache_dir = geofabrik_cache_dir(data_dir)
FileUtils.remove_entry(cache_dir) if Dir.exist?(cache_dir)
end
# Deletes just one country's cached .osm.pbf (and its Last-Modified
# stamp) — e.g. to force a fresh download without touching the others,
# or to reclaim space for a country no longer selected.
def self.delete_cached_extract(data_dir, code)
OFFLINE_MUTEX.synchronize { raise BuildError, "a build is already running" if OFFLINE_STATUS[:state] == "running" }
cache_dir = geofabrik_cache_dir(data_dir)
path = File.join(cache_dir, "#{code}.osm.pbf")
File.delete(path) if File.exist?(path)
File.delete("#{path}.last_modified") if File.exist?("#{path}.last_modified")
end
# What's actually sitting in the per-country download cache right now —
# not the same thing as offline_meta's "sources", which only reflects
# whatever the *last successful build* used. A country can be cached
# without ever having been built (selected, then deselected again
# before Apply) or built from without still being selected, and this is
# what lets the region picker show/clear either case.
def self.cached_extracts(data_dir)
cache_dir = geofabrik_cache_dir(data_dir)
return [] unless Dir.exist?(cache_dir)
Dir.glob(File.join(cache_dir, "*.osm.pbf")).map do |path|
stamp_path = "#{path}.last_modified"
{
"code" => File.basename(path, ".osm.pbf"),
"size" => File.size(path),
"last_modified" => File.exist?(stamp_path) ? File.read(stamp_path) : nil,
}
end.sort_by { |s| s["code"] }
end
# --- terrain.pmtiles ---
# planet.pmtiles (z0-12, always) plus whichever regional chunks
# intersect the selection's aggregate bbox (z13+, zero or more) are
# each `extract`ed on their own using the *same* --region= file, then
# combined with `pmtiles merge` if there was more than one. Always
# safe to merge regardless of how many countries are selected or
# whether they're adjacent: each Mapterhorn chunk is its own
# pre-partitioned, non-overlapping source grid cell, so two different
# chunks' extracts can never share a tile id — the only thing `merge`
# refuses (see pmtiles/merge.go's own disjointness check). What would
# NOT be safe is extracting the *same* source once per country and
# merging those — adjacent countries' region-extracts would share
# border tiles (extraction copies whole tiles, it doesn't clip vector
# content to the polygon) — so this always does one extract per
# *source archive*, never one per country.
def self.build_terrain_pmtiles(codes, data_dir, fetch_manifest, report_step)
report_step.call("fetching mapterhorn manifest")
items = fetch_manifest.call
planet = items.find { |item| item["name"] == MAPTERHORN_PLANET_NAME }
raise BuildError, "mapterhorn manifest is missing #{MAPTERHORN_PLANET_NAME}" unless planet
scratch_dir = Dir.mktmpdir("maptool-terrain")
south, west, north, east = region_bbox(codes)
region_path = File.join(scratch_dir, "region.geojson")
selected = region_features.select { |f| codes.include?(f["properties"]["iso_a2"]) }
File.write(region_path, JSON.generate(type: "FeatureCollection", features: selected))
chunks = items.select { |item| item["name"] != MAPTERHORN_PLANET_NAME && bbox_intersects?(item, south, west, north, east) }
# .tmp.pmtiles, not .pmtiles.tmp — same reasoning as offline.pmtiles'
# own tmp_path above, in case go-pmtiles also derives format from
# the extension for its "merge" output.
tmp_path = File.join(data_dir, "terrain.tmp.pmtiles")
sources = [planet, *chunks]
labels = sources.map { |item| item["name"] }
extracts = sources.each_with_index.map do |item, i|
report_step.call(progress_step("extracting #{item["name"]}", labels, i))
extract_path = File.join(scratch_dir, "extract-#{i}.pmtiles")
# --overfetch=0: go-pmtiles' default (0.05) merges nearby byte
# ranges into fewer, bigger HTTP requests to save round-trips —
# for planet.pmtiles (global z0-12, tens of GB) covering a
# multi-country selection that collapsed the whole extract into
# a *single* ~60GB request, which then had no way to resume after
# an HTTP/2 stream reset 11 minutes in (see the "died again"
# 2026-09-12 build). Disabling merging trades that one fragile,
# unresumable mega-request for many small ones spread over
# --download-threads (default 4) — slower on a clean run, but no
# longer one dropped stream away from losing 20 minutes of transfer.
run_pmtiles!("extract", item["url"], extract_path, "--region=#{region_path}", "--maxzoom=#{TERRAIN_MAX_ZOOM}", "--overfetch=0")
extract_path
end
if extracts.size == 1
File.rename(extracts.first, tmp_path)
else
report_step.call("merging with pmtiles")
run_pmtiles!("merge", *extracts, tmp_path)
end
File.rename(tmp_path, File.join(data_dir, "terrain.pmtiles"))
File.write(terrain_meta_path(data_dir), JSON.generate(sources: [planet, *chunks].map { |i| { name: i["name"], md5sum: i["md5sum"] } }))
ensure
FileUtils.remove_entry(scratch_dir) if scratch_dir && Dir.exist?(scratch_dir)
File.delete(tmp_path) if tmp_path && File.exist?(tmp_path)
end
private_class_method :build_terrain_pmtiles
def self.bbox_intersects?(item, south, west, north, east)
item["min_lon"] < east && item["max_lon"] > west && item["min_lat"] < north && item["max_lat"] > south
end
private_class_method :bbox_intersects?
def self.fetch_mapterhorn_manifest
response = Net::HTTP.get_response(URI(MAPTERHORN_MANIFEST_URL))
raise BuildError, "could not reach #{MAPTERHORN_MANIFEST_URL}" unless response.is_a?(Net::HTTPSuccess)
JSON.parse(response.body).fetch("items")
rescue JSON::ParserError
raise BuildError, "mapterhorn manifest was not valid JSON"
end
private_class_method :fetch_mapterhorn_manifest
# Sidecar recording which Mapterhorn sources (name + md5sum) the on-disk
# terrain.pmtiles was actually extracted+merged from. nil if never built.
def self.terrain_meta(data_dir)
read_json(terrain_meta_path(data_dir))
end
# Same "don't know" vs. "no" distinction as offline_update_available?
# above. Recomputes which sources *would* be selected for the current
# selection (same manifest + bbox_intersects? this build itself uses)
# and compares their md5sums against what's recorded — so this also
# correctly says "yes" if the selection changed since the last build
# (a chunk now relevant that wasn't recorded), not just if Mapterhorn's
# own data moved on.
def self.terrain_update_available?(data_dir, fetch_manifest: method(:fetch_mapterhorn_manifest))
meta = terrain_meta(data_dir)
return nil unless meta
codes = selected_regions(data_dir)
return nil if codes.empty?
items = fetch_manifest.call
planet = items.find { |item| item["name"] == MAPTERHORN_PLANET_NAME }
return nil unless planet
south, west, north, east = region_bbox(codes)
chunks = items.select { |item| item["name"] != MAPTERHORN_PLANET_NAME && bbox_intersects?(item, south, west, north, east) }
current = [planet, *chunks].map { |i| { "name" => i["name"], "md5sum" => i["md5sum"] } }.sort_by { |s| s["name"] }
current != (meta["sources"] || []).sort_by { |s| s["name"] }
rescue BuildError
nil
end
def self.terrain_meta_path(data_dir)
File.join(data_dir, "terrain.pmtiles.meta.json")
end
private_class_method :terrain_meta_path
# Deletes terrain.pmtiles and its sidecar meta — same "start over"
# reasoning as delete_offline_data above. No download cache to clean up
# here: terrain.pmtiles' pmtiles-extract step reads its sources over
# HTTP range requests rather than downloading a whole archive first.
def self.delete_terrain_data(data_dir)
TERRAIN_MUTEX.synchronize { raise BuildError, "a build is already running" if TERRAIN_STATUS[:state] == "running" }
File.delete(File.join(data_dir, "terrain.pmtiles")) if File.exist?(File.join(data_dir, "terrain.pmtiles"))
File.delete(terrain_meta_path(data_dir)) if File.exist?(terrain_meta_path(data_dir))
end
# --- shared ---
def self.read_json(path)
File.exist?(path) ? JSON.parse(File.read(path)) : nil
rescue JSON::ParserError
nil
end
private_class_method :read_json
# ENV read lazily (not load-time constants) so tests can point these at
# fake binaries without a require-order dance.
def self.pmtiles_bin
ENV.fetch("PMTILES_BIN", "pmtiles")
end
def self.osmium_bin
ENV.fetch("OSMIUM_BIN", "osmium")
end
def self.java_bin
ENV.fetch("JAVA_BIN", "java")
end
def self.planetiler_jar
ENV.fetch("PLANETILER_JAR", "/usr/local/lib/planetiler.jar")
end
# go-pmtiles' extract logs one progress line per chunk fetched
# ("fetching N dirs, M chunks, K requests") — fine on a terminal where
# it overwrites itself, but captured non-interactively that's one line
# per chunk, easily hundreds of thousands of characters for a big
# region. The actual failure is always at the end, so keep only the
# tail — same story for osmium/planetiler's own chatty stdout.
OUTPUT_TAIL_LINES = 40
# Some CLI tools (go-pmtiles included) write their actual error to
# stdout rather than stderr — combine both rather than risk raising a
# BuildError with nothing useful in it.
def self.command_output(stdout, stderr)
lines = [stdout, stderr].map(&:strip).reject(&:empty?).join("\n").lines
return lines.join if lines.size <= OUTPUT_TAIL_LINES
omitted = lines.size - OUTPUT_TAIL_LINES
"(#{omitted} earlier lines omitted)\n#{lines.last(OUTPUT_TAIL_LINES).join}"
end
private_class_method :command_output
# extract/merge stream tens of GB over HTTP range requests; retry a
# transient failure (e.g. a mid-transfer HTTP/2 stream reset from the
# remote) a couple times before giving up, rather than forcing a full
# re-download on every hiccup.
def self.run_pmtiles!(*args, attempts: 3)
attempts.times do |i|
stdout, stderr, status = Open3.capture3(pmtiles_bin, *args)
return if status.success?
raise BuildError, "pmtiles exited with status #{status.exitstatus}: #{command_output(stdout, stderr)}" if i == attempts - 1
end
rescue Errno::ENOENT, Errno::EACCES => e
raise BuildError, "could not run '#{pmtiles_bin}' (#{e.message}) — is go-pmtiles installed and on PATH? See docs/development.adoc."
end
private_class_method :run_pmtiles!
def self.run_osmium!(*args)
stdout, stderr, status = Open3.capture3(osmium_bin, *args)
raise BuildError, "osmium exited with status #{status.exitstatus}: #{command_output(stdout, stderr)}" unless status.success?
rescue Errno::ENOENT, Errno::EACCES => e
raise BuildError, "could not run '#{osmium_bin}' (#{e.message}) — is osmium-tool installed and on PATH? See docs/development.adoc."
end
private_class_method :run_osmium!
def self.run_planetiler!(*args)
stdout, stderr, status = Open3.capture3(java_bin, "-jar", planetiler_jar, *args)
raise BuildError, "planetiler exited with status #{status.exitstatus}: #{command_output(stdout, stderr)}" unless status.success?
rescue Errno::ENOENT, Errno::EACCES => e
raise BuildError, "could not run '#{java_bin} -jar #{planetiler_jar}' (#{e.message}) — is Java and planetiler.jar installed? See docs/development.adoc."
end
private_class_method :run_planetiler!
end
end
+4
View File
@@ -0,0 +1,4 @@
{
"label": "Camper POIs (Overpass)",
"command": "./run.rb"
}
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
# The reference example of the plugin contract (see lib/maptool/plugins.rb):
# read --south/--west/--north/--east, print a GeoJSON FeatureCollection to
# stdout. Thin wrapper around lib/maptool/overpass_pois.rb, which already
# did all the real work for the "rake overpass:pois" dev-time task this
# plugin now sits alongside as a second way to run the same query.
require_relative "../../lib/maptool/overpass_pois"
args = ARGV.to_h { |arg| arg.sub(/\A--/, "").split("=", 2) }
bbox = %w[south west north east].map { |key| Float(args.fetch(key)) }
response = Maptool::OverpassPois.fetch(bbox)
puts JSON.generate(Maptool::OverpassPois.to_geojson(response))
+632 -4
View File
@@ -4,6 +4,18 @@ html, body {
font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
} }
/* Router-carved-signage display face (docs/nps-resources.adoc), used only
for the topbar wordmark below — a full body-text swap is a separate,
bigger decision this isn't. Bold is the only weight vendored since
.topbar__brand only ever renders at font-weight 700. */
@font-face {
font-family: "National Park";
src: url("/vendor/national-park-typeface/NationalPark-Bold.woff2") format("woff2");
font-weight: 700;
font-style: normal;
font-display: swap;
}
#app { #app {
height: 100%; height: 100%;
display: flex; display: flex;
@@ -20,20 +32,65 @@ html, body {
} }
.topbar__brand { .topbar__brand {
font-size: 14px; font-family: "National Park", -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
font-size: 20px;
font-weight: 700; font-weight: 700;
letter-spacing: 0.12em; letter-spacing: 0.12em;
text-transform: uppercase; text-transform: uppercase;
color: #fff; color: #fff;
} }
.topbar__coords { .topbar__center {
margin: 0 auto; margin: 0 auto;
display: flex;
align-items: center;
gap: 14px;
}
.topbar__coords,
.topbar__sun {
display: flex;
align-items: center;
gap: 5px;
font-size: 12px; font-size: 12px;
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
color: #bbb; color: #bbb;
} }
.topbar__sun {
gap: 14px;
}
.topbar__group {
display: flex;
align-items: center;
gap: 5px;
}
.topbar__icon {
display: flex;
width: 13px;
height: 13px;
flex-shrink: 0;
}
.topbar__icon svg {
width: 100%;
height: 100%;
}
.topbar__coords {
cursor: pointer;
}
.topbar__coords:hover {
color: #fff;
}
.topbar__sun[hidden] {
display: none;
}
.topbar__offline-status { .topbar__offline-status {
width: 8px; width: 8px;
height: 8px; height: 8px;
@@ -199,6 +256,29 @@ html, body {
border-top: 1px solid #eee; border-top: 1px solid #eee;
} }
.radar-control__forecast-hours {
display: flex;
gap: 10px;
overflow-x: auto;
padding-bottom: 6px;
margin-bottom: 4px;
border-bottom: 1px solid #eee;
}
.radar-control__forecast-hour {
display: flex;
flex-direction: column;
align-items: center;
gap: 2px;
flex: 0 0 auto;
font-variant-numeric: tabular-nums;
}
.radar-control__forecast-hour span:first-child {
color: #888;
font-size: 11px;
}
.radar-control__forecast-day { .radar-control__forecast-day {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -223,11 +303,32 @@ html, body {
font-size: 11px; font-size: 11px;
} }
.shadow-control__time {
display: flex;
align-items: center;
gap: 6px;
}
.shadow-control__slider {
width: 110px;
}
.shadow-control__clock {
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.shadow-control__hint {
margin: 6px 0 0;
color: #888;
font-size: 11px;
}
.basemap-panel { .basemap-panel {
position: fixed; position: fixed;
top: 0; top: 0;
left: 52px; left: 52px;
width: 260px; width: 300px;
max-width: 90vw; max-width: 90vw;
height: 100%; height: 100%;
display: flex; display: flex;
@@ -296,6 +397,225 @@ html, body {
visibility: visible; visibility: visible;
} }
/* Docked detail panel for a clicked hiking trail — replaces a map-anchored
Popup (which routinely covered up the very trail line it described) with
a fixed side panel, same "click info moves off the map" idea
track_profile.js already established for clicking a GPX track line
(TrackProfilePanel). .trail-panel__body gets the exact padding
.maplibregl-popup-content used (15px 10px) so routeHtml()'s own output —
built for that popup, including its header's canceling negative margin —
renders here unchanged; no separate panel-flavored template needed. */
.trail-panel {
position: fixed;
top: 0;
right: 0;
bottom: 0;
width: 300px;
max-width: 90vw;
background: #fff;
border-left: 1px solid #ddd;
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.15);
z-index: 10;
}
.trail-panel__body {
height: 100%;
box-sizing: border-box;
overflow-y: auto;
padding: 15px 10px;
font-size: 13px;
}
.trail-panel__close {
position: absolute;
top: 6px;
right: 6px;
border: none;
border-radius: 50%;
background: rgba(255, 255, 255, 0.85);
font-size: 18px;
line-height: 1;
padding: 2px 7px;
cursor: pointer;
}
/* First breakpoint in this file. Below it the same panel docks to the
bottom edge instead of the right one — a fixed-width side panel would
otherwise eat most of a phone-width map, the exact "popup dominates the
screen" problem this panel was meant to fix in the first place. */
@media (max-width: 640px) {
.trail-panel {
top: auto;
left: 0;
right: 0;
bottom: 0;
width: auto;
max-width: none;
max-height: 50vh;
border-left: none;
border-top: 1px solid #ddd;
border-radius: 8px 8px 0 0;
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.15);
}
}
.offline-data-panel__body {
padding: 8px 12px;
}
.offline-data-panel__regions-label {
margin: 0 0 4px;
font-weight: 600;
}
.offline-data-panel__region-list {
list-style: none;
margin: 0;
padding: 0;
max-height: 220px;
overflow-y: auto;
border: 1px solid #eee;
border-radius: 4px;
}
.offline-data-panel__region-list li {
display: flex;
align-items: center;
justify-content: space-between;
gap: 6px;
}
.offline-data-panel__region-list label {
display: flex;
align-items: center;
gap: 6px;
padding: 4px 8px;
min-width: 0;
flex: 1;
cursor: pointer;
}
.offline-data-panel__region-list label:hover {
background: #f0f0f0;
}
.offline-data-panel__cache-info {
display: flex;
align-items: center;
gap: 4px;
padding-right: 8px;
color: #888;
font-size: 11px;
white-space: nowrap;
}
.offline-data-panel__cache-delete {
border: none;
background: none;
padding: 0 2px;
color: #a33;
font-size: 11px;
cursor: pointer;
}
.offline-data-panel__cache-delete:hover {
text-decoration: underline;
}
.offline-data-panel__cache-delete:disabled {
opacity: 0.5;
cursor: default;
}
/* Same rounded-square badge ratio as icons.js's own MAP_MARKER_ICON
(rx 5 of a 22-wide square) — a consistent frame rather than however
each flag's own artwork happens to fill an unbordered square. */
.offline-data-panel__flag {
flex-shrink: 0;
width: 18px;
height: 18px;
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.15);
object-fit: cover;
}
.offline-data-panel__region-status {
padding: 6px 8px;
color: #888;
}
.offline-data-panel__apply {
margin-top: 8px;
width: 100%;
border: 1px solid #ccc;
border-radius: 4px;
background: #fff;
padding: 6px 8px;
font: inherit;
font-size: 12px;
cursor: pointer;
}
.offline-data-panel__apply:hover {
background: #f0f0f0;
}
.offline-data-panel__apply:disabled {
opacity: 0.5;
cursor: default;
}
.offline-data-panel__row {
margin-top: 14px;
padding-top: 10px;
border-top: 1px solid #eee;
}
.offline-data-panel__row-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.offline-data-panel__delete {
border: 1px solid #ccc;
border-radius: 4px;
background: #fff;
padding: 2px 8px;
font: inherit;
font-size: 11px;
color: #a33;
cursor: pointer;
}
.offline-data-panel__delete:hover {
background: #fdecec;
}
.offline-data-panel__delete:disabled {
opacity: 0.5;
cursor: default;
}
.offline-data-panel__status {
margin: 6px 0 0;
color: #666;
font-size: 12px;
}
.offline-data-panel__status--error {
white-space: pre-wrap;
word-break: break-word;
max-height: 200px;
overflow-y: auto;
color: #b3261e;
}
.offline-data-panel__update-badge {
color: #b8860b;
}
.gpx-panel { .gpx-panel {
position: fixed; position: fixed;
top: 0; top: 0;
@@ -778,6 +1098,72 @@ html, body {
color: #333; color: #333;
} }
.search-ctrl {
position: relative;
}
.search-ctrl__button svg {
display: block;
margin: 0 auto;
width: 18px;
height: 18px;
}
.search-ctrl__button.active {
background: #dbe9ff;
}
.search-panel {
position: absolute;
top: 0;
left: 100%;
margin-left: 8px;
z-index: 20;
width: 240px;
background: #fff;
border: 1px solid #ddd;
border-radius: 6px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
padding: 6px 8px;
font-size: 13px;
}
.search-panel[hidden] {
display: none;
}
.search-panel__input {
width: 100%;
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 4px;
padding: 5px 7px;
font: inherit;
}
.search-panel__results {
list-style: none;
margin: 6px 0 0;
padding: 0;
max-height: 220px;
overflow-y: auto;
}
.search-panel__result {
padding: 6px 4px;
border-radius: 4px;
cursor: pointer;
}
.search-panel__result:hover {
background: #f0f0f0;
}
.search-panel__status {
padding: 6px 4px;
color: #888;
}
.notes-ctrl { .notes-ctrl {
position: relative; position: relative;
} }
@@ -888,6 +1274,71 @@ html, body {
resize: vertical; resize: vertical;
} }
.notes-panel__icons {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 2px;
margin: 2px 0;
}
/* Same "author display wins over the UA [hidden] rule" gotcha as
.gpx-panel__action[hidden] elsewhere in this file. */
.notes-panel__icons[hidden] {
display: none;
}
.notes-panel__icon-option {
width: auto;
height: auto;
display: flex;
align-items: center;
justify-content: center;
padding: 3px;
border: 1px solid transparent;
border-radius: 4px;
background: none;
color: #555;
cursor: pointer;
}
.notes-panel__icon-option svg {
width: 16px;
height: 16px;
}
.notes-panel__icon-option:hover {
background: #f0f0f0;
}
.notes-panel__icon-option.active {
border-color: #1a5fb4;
color: #1a5fb4;
background: #dbe9ff;
}
/* The pending-note marker shown on the map while the save form is open —
updates live to whatever icon is picked (see notes.js's onIconChange). A
plain round badge (not a drop-pin shape) since MapLibre anchors a custom
marker element at its center, and a pin's usual tip-points-at-the-spot
shape needs a bottom anchor to line up correctly. */
.notes-panel__preview-marker {
width: 26px;
height: 26px;
border-radius: 50%;
background: #c0392b;
border: 2px solid #fff;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
display: flex;
align-items: center;
justify-content: center;
color: #fff;
}
.notes-panel__preview-marker svg {
width: 15px;
height: 15px;
}
.notes-panel__target, .notes-panel__target,
.notes-panel__new-name { .notes-panel__new-name {
width: 100%; width: 100%;
@@ -906,6 +1357,11 @@ html, body {
} }
.notes-panel__actions button { .notes-panel__actions button {
/* Without this, some browsers (GTK-themed Chrome on Linux in
particular) paint their own native hover/active highlight over a
button's background instead of leaving a custom one alone — the
Save button visibly went white on hover because of exactly this. */
appearance: none;
width: auto; width: auto;
height: auto; height: auto;
padding: 4px 10px; padding: 4px 10px;
@@ -917,7 +1373,11 @@ html, body {
cursor: pointer; cursor: pointer;
} }
.notes-panel__save { /* ".notes-panel__actions " prefix (not just ".notes-panel__save") to
outrank ".notes-panel__actions button" — same class-count-vs-class+
element specificity trap as elsewhere in this file; without it this
lost and the Save button just looked like a second Cancel button. */
.notes-panel__actions .notes-panel__save {
background: #1a5fb4; background: #1a5fb4;
color: #fff; color: #fff;
} }
@@ -934,6 +1394,17 @@ html, body {
user-select: none; user-select: none;
} }
.pitch-toggle-ctrl__button {
width: 29px;
height: 29px;
font-size: 11px;
font-weight: 600;
}
.pitch-toggle-ctrl__button.active {
background: #dbe9ff;
}
.gpx-popup__header { .gpx-popup__header {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -945,6 +1416,14 @@ html, body {
color: #fff; color: #fff;
} }
.hiking-trail-popup__swatch {
flex-shrink: 0;
width: 14px;
height: 14px;
border-radius: 50%;
border: 1px solid rgba(255, 255, 255, 0.6);
}
.gpx-popup__header-icon { .gpx-popup__header-icon {
flex-shrink: 0; flex-shrink: 0;
width: 18px; width: 18px;
@@ -962,6 +1441,11 @@ html, body {
font-size: 12px; font-size: 12px;
} }
.gpx-popup__wiki {
margin-top: 6px;
font-size: 12px;
}
.gpx-popup__category { .gpx-popup__category {
color: #888; color: #888;
font-size: 12px; font-size: 12px;
@@ -1095,6 +1579,84 @@ html, body {
box-shadow: 0 0 0 2px rgba(42, 157, 143, 0.4); box-shadow: 0 0 0 2px rgba(42, 157, 143, 0.4);
} }
.overlays-panel__list {
flex: 1;
overflow-y: auto;
list-style: none;
margin: 0;
padding: 8px 12px;
}
.overlays-panel__item label {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 4px;
border-radius: 4px;
cursor: pointer;
}
.overlays-panel__item label:hover {
background: #f0f0f0;
}
.overlays-panel__icon {
display: flex;
width: 16px;
height: 16px;
flex-shrink: 0;
color: #555;
}
.overlays-panel__icon svg {
width: 100%;
height: 100%;
}
.overlays-panel__row {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 4px;
}
.overlays-panel__name {
border: none;
background: none;
padding: 0;
font: inherit;
color: inherit;
text-align: left;
cursor: pointer;
}
.overlays-panel__name:hover {
text-decoration: underline;
}
.overlays-panel__details {
margin: 0 4px 6px 26px;
padding-top: 6px;
border-top: 1px solid #eee;
font-size: 12px;
}
.hiking-trail-countries {
display: flex;
flex-wrap: wrap;
gap: 4px 12px;
list-style: none;
margin: 0;
padding: 0;
}
.hiking-trail-countries__item label {
display: flex;
align-items: center;
gap: 4px;
cursor: pointer;
}
.livetrack-panel__list { .livetrack-panel__list {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
@@ -1360,3 +1922,69 @@ html, body {
.profile-panel__tooltip-label { .profile-panel__tooltip-label {
color: #c3c2b7; color: #c3c2b7;
} }
.plugins-panel__hint {
margin: 0 0 6px;
max-width: 200px;
color: #888;
font-size: 11px;
}
.plugins-panel__list {
list-style: none;
margin: 0;
padding: 0;
}
.plugins-panel__item {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 0;
white-space: nowrap;
}
.plugins-panel__label {
flex: 1;
}
.plugins-panel__run {
/* See .notes-panel__actions button's own comment — without this some
browsers paint their own hover/active highlight over a custom
background. */
appearance: none;
padding: 4px 10px;
border: none;
border-radius: 4px;
background: #1a5fb4;
color: #fff;
font: inherit;
font-size: 12px;
cursor: pointer;
}
.plugins-panel__run:disabled {
opacity: 0.6;
cursor: default;
}
.plugins-panel__status {
min-width: 3.5em;
max-width: 200px;
color: #888;
font-size: 11px;
/* Overrides the parent's nowrap: "Running…"/"Done" never wrap either
way, but a real RunError message (e.g. "plugin exited with status 1")
needs to, or it just overflows the flyout unreadably. */
white-space: normal;
}
.plugins-panel__status--error {
color: #c62828;
}
.plugins-panel__empty {
color: #888;
white-space: normal;
max-width: 200px;
}
+99
View File
@@ -0,0 +1,99 @@
import { addProtocol } from "/vendor/maplibre-gl/maplibre-gl.mjs";
import { ONLINE_TERRAIN_TILES } from "/js/overlays.js";
import { firstSymbolLayerId } from "/js/radar.js";
import { CONTOUR_ICON } from "/js/icons.js";
const SOURCE_ID = "contour-lines";
const LINE_LAYER_ID = "contour-lines-line";
// Topographic contour lines, generated client-side by the vendored
// maplibre-contour plugin (public/vendor/maplibre-contour/) from the same
// online Terrarium DEM tiles overlays.js's HillshadeControl already
// fetches. Online only, unlike Terrain shading/Terrain shadow: the
// plugin's DemSource has no public hook to route its own tile fetch
// through the pmtiles:// protocol HillshadeControl uses for the offline
// basemap, so — same story as the Wikipedia layer and Radar — this just
// quietly renders nothing without a network.
export class ContourControl {
constructor(map) {
this._map = map;
this._active = false;
this._demSource = new window.mlcontour.DemSource({
url: ONLINE_TERRAIN_TILES[0],
encoding: "terrarium",
maxzoom: 15,
worker: true,
cacheSize: 100,
});
this._demSource.setupMaplibre({ addProtocol });
// setStyle() (switching Online/Offline) tears down all custom sources/
// layers — put contour lines back if they were on, same as every other
// Overlays control.
map.on("style.load", () => {
if (this._active) this._addLayer();
});
}
mount(li) {
li.innerHTML = `
<label>
<input type="checkbox" class="overlays-panel__toggle">
<span class="overlays-panel__icon">${CONTOUR_ICON}</span>
<span>Contour lines</span>
</label>
`;
this._checkbox = li.querySelector(".overlays-panel__toggle");
this._checkbox.addEventListener("change", (event) => this._toggle(event.target.checked));
}
_toggle(active) {
this._active = active;
if (active) this._addLayer();
else this._removeLayer();
}
_addLayer() {
if (this._map.getSource(SOURCE_ID)) return;
// Starting-point thresholds (README's own generic example) — meters,
// more/tighter contours at higher zoom. Expect to eyeball-tune against
// real Tatras-scale terrain.
const tiles = [
this._demSource.contourProtocolUrl({
thresholds: {
11: [200, 1000],
12: [100, 500],
14: [50, 200],
15: [20, 100],
},
contourLayer: "contours",
elevationKey: "ele",
levelKey: "level",
}),
];
this._map.addSource(SOURCE_ID, { type: "vector", tiles, maxzoom: 15 });
this._map.addLayer(
{
id: LINE_LAYER_ID,
type: "line",
source: SOURCE_ID,
"source-layer": "contours",
paint: {
// Roughly the same brown as the mid-slope band of overlays.js's
// own ELEVATION_COLOR_RAMP, so this reads as part of the same
// terrain treatment rather than a bolted-on layer.
"line-color": "#8a6d3b",
"line-width": ["match", ["get", "level"], 1, 1.2, 0.6],
"line-opacity": 0.6,
},
},
firstSymbolLayerId(this._map),
);
}
_removeLayer() {
if (this._map.getLayer(LINE_LAYER_ID)) this._map.removeLayer(LINE_LAYER_ID);
if (this._map.getSource(SOURCE_ID)) this._map.removeSource(SOURCE_ID);
}
}
+74
View File
@@ -0,0 +1,74 @@
// Elevation lookups against the same Terrarium-encoded terrain tiles
// overlays.js's HillshadeControl already renders — pulled into its own file
// since TODO.adoc lists two more near-future features (slope readout, solar
// calculator) that will need the same "elevation at a point" primitive,
// shadow.js's raymarch being the first real consumer.
import { ONLINE_TERRAIN_TILES } from "/js/overlays.js";
const DEM_ZOOM = 10; // fixed lookup zoom, independent of the map's own display zoom
const tileCache = new Map(); // "z/x/y" -> Promise<{elevations,size}|null>, so concurrent lookups on the same not-yet-fetched tile share one fetch
let offlinePmtiles = null;
// fracX/fracY (not pixel coordinates): the tile hasn't been fetched yet at
// this point, so its actual pixel size isn't known — online tiles are
// 256px PNG, offline ones (Mapterhorn, see lib/maptool/pmtiles_builder.rb)
// are 512px WebP. elevationAt scales these once the real size is known.
function lngLatToTile(lng, lat, zoom) {
const n = 2 ** zoom;
const x = ((lng + 180) / 360) * n;
const latRad = (lat * Math.PI) / 180;
const y = ((1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2) * n;
const tileX = Math.floor(x);
const tileY = Math.floor(y);
return { tileX, tileY, fracX: x - tileX, fracY: y - tileY };
}
async function decodeTerrarium(bytes, mime) {
const bitmap = await createImageBitmap(new Blob([bytes], { type: mime }));
const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
const ctx = canvas.getContext("2d");
ctx.drawImage(bitmap, 0, 0);
const { data } = ctx.getImageData(0, 0, bitmap.width, bitmap.height);
const elevations = new Int16Array(bitmap.width * bitmap.height);
for (let i = 0; i < elevations.length; i++) {
elevations[i] = data[i * 4] * 256 + data[i * 4 + 1] + data[i * 4 + 2] / 256 - 32768;
}
return { elevations, size: bitmap.width };
}
async function fetchTileBytes(z, x, y, offlineAvailable) {
if (offlineAvailable) {
if (!offlinePmtiles) offlinePmtiles = new window.pmtiles.PMTiles(`${window.location.origin}/tiles/terrain.pmtiles`);
const result = await offlinePmtiles.getZxy(z, x, y);
return result ? { bytes: new Uint8Array(result.data), mime: "image/webp" } : null;
}
const url = ONLINE_TERRAIN_TILES[0].replace("{z}", z).replace("{x}", x).replace("{y}", y);
const response = await fetch(url);
return response.ok ? { bytes: new Uint8Array(await response.arrayBuffer()), mime: "image/png" } : null;
}
function fetchTile(z, x, y, offlineAvailable) {
const key = `${z}/${x}/${y}`;
let cached = tileCache.get(key);
if (cached) return cached;
const promise = fetchTileBytes(z, x, y, offlineAvailable)
.then((result) => (result ? decodeTerrarium(result.bytes, result.mime) : null))
.catch(() => null);
tileCache.set(key, promise);
return promise;
}
// -> Promise<number|null> — null on a fetch/decode failure, or a point
// falling outside a partial offline extract's zoom range.
export async function elevationAt(lng, lat, offlineAvailable) {
const { tileX, tileY, fracX, fracY } = lngLatToTile(lng, lat, DEM_ZOOM);
const tile = await fetchTile(DEM_ZOOM, tileX, tileY, offlineAvailable);
if (!tile) return null;
const px = Math.min(tile.size - 1, Math.floor(fracX * tile.size));
const py = Math.min(tile.size - 1, Math.floor(fracY * tile.size));
return tile.elevations[py * tile.size + px];
}
+34 -8
View File
@@ -43,6 +43,7 @@ export class GpxPanelControl {
this._visible = new Set(); // file paths currently shown on the map this._visible = new Set(); // file paths currently shown on the map
this._interactiveLayers = new Set(); // point layer ids with click/hover wired up this._interactiveLayers = new Set(); // point layer ids with click/hover wired up
this._pointsByPath = new Map(); // path -> its waypoints FeatureCollection, for the category legend this._pointsByPath = new Map(); // path -> its waypoints FeatureCollection, for the category legend
this._linesByPath = new Map(); // path -> its lines/polygons FeatureCollection, same reason (a polygon/line note also carries a category)
this._hiddenCategories = new Set(); // category names toggled off in the legend this._hiddenCategories = new Set(); // category names toggled off in the legend
this._openDownloadMenu = null; // the one gpx-tree__download-menu currently open, if any this._openDownloadMenu = null; // the one gpx-tree__download-menu currently open, if any
@@ -60,8 +61,17 @@ export class GpxPanelControl {
// notes.js writes directly into the same GPX store (a hand-drawn note // notes.js writes directly into the same GPX store (a hand-drawn note
// saved into a .geojson layer) — refresh so a newly created/grown file // saved into a .geojson layer) — refresh so a newly created/grown file
// shows up in the tree without a manual reopen. // shows up in the tree without a manual reopen, and auto-show it (check
onGpxStoreChanged(() => this._loadTree()); // + render) since a note the user just placed being invisible until
// they find and check its layer by hand defeats the point of dropping
// a pin right there on the map.
onGpxStoreChanged((path) => {
if (path) {
this._visible.add(path);
this._reloadFile(path);
}
this._loadTree();
});
} }
// Registered once, always white, as plain (non-SDF) images: these used to // Registered once, always white, as plain (non-SDF) images: these used to
@@ -107,7 +117,7 @@ export class GpxPanelControl {
mount(sidebar) { mount(sidebar) {
this._container = document.createElement("div"); this._container = document.createElement("div");
this._container.className = "sidebar-item"; this._container.className = "sidebar-item";
this._container.innerHTML = `<button type="button" class="sidebar-icon" title="Tracks" aria-label="Tracks">${GPX_ICON}</button>`; this._container.innerHTML = `<button type="button" class="sidebar-icon" title="Tracks &amp; Points" aria-label="Tracks &amp; Points">${GPX_ICON}</button>`;
this._icon = this._container.querySelector(".sidebar-icon"); this._icon = this._container.querySelector(".sidebar-icon");
this._icon.addEventListener("click", () => this._togglePanel()); this._icon.addEventListener("click", () => this._togglePanel());
@@ -588,6 +598,7 @@ export class GpxPanelControl {
this._addClusterLayers(pointsId, path); this._addClusterLayers(pointsId, path);
if (points.features.length > 0) this._pointsByPath.set(path, points); if (points.features.length > 0) this._pointsByPath.set(path, points);
if (lines.features.length > 0) this._linesByPath.set(path, lines);
this._updateLegend(); this._updateLegend();
this._applyCategoryFilter(); this._applyCategoryFilter();
@@ -834,6 +845,7 @@ export class GpxPanelControl {
if (this._map.getSource(pointsId)) this._map.removeSource(pointsId); if (this._map.getSource(pointsId)) this._map.removeSource(pointsId);
this._pointsByPath.delete(path); this._pointsByPath.delete(path);
this._linesByPath.delete(path);
this._updateLegend(); this._updateLegend();
} }
@@ -844,8 +856,8 @@ export class GpxPanelControl {
// on the map, not just a read-only color key. // on the map, not just a read-only color key.
_updateLegend() { _updateLegend() {
const categories = new Map(); // category name -> { color, icon } const categories = new Map(); // category name -> { color, icon }
for (const points of this._pointsByPath.values()) { for (const collection of [...this._pointsByPath.values(), ...this._linesByPath.values()]) {
for (const feature of points.features) { for (const feature of collection.features) {
const category = feature.properties.category; const category = feature.properties.category;
if (category && !categories.has(category)) { if (category && !categories.has(category)) {
categories.set(category, { color: feature.properties.color || TRACK_COLOR, icon: feature.properties.icon }); categories.set(category, { color: feature.properties.color || TRACK_COLOR, icon: feature.properties.icon });
@@ -900,6 +912,16 @@ export class GpxPanelControl {
const visible = points.features.filter((f) => !this._hiddenCategories.has(f.properties.category)); const visible = points.features.filter((f) => !this._hiddenCategories.has(f.properties.category));
source.setData({ type: "FeatureCollection", features: visible }); source.setData({ type: "FeatureCollection", features: visible });
} }
// Same re-slicing for polygon/line notes sharing the "lines" source with
// plain tracks/routes — those have no `category` of their own, so
// `_hiddenCategories.has(undefined)` is always false and they're never
// affected by this, only a hidden Note (or other categorized) shape is.
for (const [path, lines] of this._linesByPath) {
const source = this._map.getSource(linesSourceId(path));
if (!source) continue;
const visible = lines.features.filter((f) => !this._hiddenCategories.has(f.properties.category));
source.setData({ type: "FeatureCollection", features: visible });
}
} }
async _uploadFiles(fileList, folder) { async _uploadFiles(fileList, folder) {
@@ -1038,7 +1060,11 @@ function uploadFile(formData, onUploadComplete) {
// fixed square size (the source SVGs have no explicit width/height, just a // fixed square size (the source SVGs have no explicit width/height, just a
// viewBox, so one is injected — otherwise an <img> falls back to the CSS // viewBox, so one is injected — otherwise an <img> falls back to the CSS
// default replaced-element size instead of the viewBox's aspect). // default replaced-element size instead of the viewBox's aspect).
async function svgToImageData(svgMarkup, size) { // Exported: overlays.js's own live layers (Wikipedia, more to come per its
// own doc comment) need the same SVG-to-map-image/badge-id/escaping
// helpers this file already has, and reimplementing them there would just
// be the same three functions typed twice.
export async function svgToImageData(svgMarkup, size) {
// xmlns is required here even though the other hand-drawn icons in this // xmlns is required here even though the other hand-drawn icons in this
// app get away without it — those are inlined via innerHTML, where the // app get away without it — those are inlined via innerHTML, where the
// HTML parser assigns the SVG namespace from context, but a standalone // HTML parser assigns the SVG namespace from context, but a standalone
@@ -1061,7 +1087,7 @@ async function svgToImageData(svgMarkup, size) {
} }
} }
function badgeImageId(color) { export function badgeImageId(color) {
return `${BADGE_IMAGE_PREFIX}${color}`; return `${BADGE_IMAGE_PREFIX}${color}`;
} }
@@ -1134,7 +1160,7 @@ function formatDuration(totalSeconds) {
return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`; return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
} }
function escapeHtml(text) { export function escapeHtml(text) {
const div = document.createElement("div"); const div = document.createElement("div");
div.textContent = text; div.textContent = text;
return div.innerHTML; return div.innerHTML;
+442
View File
@@ -0,0 +1,442 @@
import { WALKING_ICON } from "/js/icons.js";
import { firstSymbolLayerId } from "/js/radar.js";
import { escapeHtml } from "/js/gpx.js";
import { lineLength, formatDistance } from "/js/measure.js";
import { buildLineGraph, orderLanesAsync, LaneLayer } from "/vendor/maplibre-gl-lanes/maplibre-gl-lanes.mjs";
// Overpass has permissive CORS (verified: Access-Control-Allow-Origin: *),
// so this queries it directly from the browser — no server-side proxy
// needed, same "public API, no key" story as the Nominatim search already
// hits from here. One query per click (not per pan/move like the
// Wikipedia layer's live refetch), so this stays well within Overpass's
// shared rate limits.
//
// Three independent public mirrors (also CORS-open, verified), raced with
// Promise.any rather than called one at a time — the shared free instances
// vary a lot in load from one moment to the next, and a multi-second wait
// on a single one was the main complaint. Whichever answers first wins;
// the others are simply left to finish and get GC'd, not worth the extra
// AbortController plumbing for a single one-off per-click request.
const OVERPASS_APIS = [
"https://overpass-api.de/api/interpreter",
"https://overpass.kumi.systems/api/interpreter",
"https://overpass.private.coffee/api/interpreter",
];
const CLICK_RADIUS_M = 40;
// OSM colour tag values are free text (untrusted) — only used as a CSS
// background if they look like an actual color (hex or a plain word),
// never interpolated unchecked into a style attribute.
const SAFE_COLOR = /^(#[0-9a-fA-F]{3,8}|[a-zA-Z]+)$/;
// Pre-rendered raster tiles, not vector — waymarkedtrails.org already
// colors each route by its OSM `colour` tag (the KST/KČT-style paint-blaze
// colors used in Slovakia/Czechia), falling back to plain red where a route
// has none, so there's no styling to do here ourselves. Used whenever no
// offline extract is available at all — same "quietly renders nothing
// without a network" story as the Wikipedia/Radar/Contour lines overlays.
const ONLINE_SOURCE_ID = "hiking-trails-online";
const ONLINE_LAYER_ID = "hiking-trails-online-line";
const TILE_URL = "https://tile.waymarkedtrails.org/hiking/{z}/{x}/{y}.png";
const ATTRIBUTION =
'Trails &copy; <a href="https://waymarkedtrails.org" target="_blank">Waymarked Trails</a> (CC-BY-SA), map data &copy; OpenStreetMap contributors';
const OPACITY = 0.85;
// Offline: real vector trails for each country the viewer actually picks,
// GeoJSON generated at build time by Maptool::HikingTrails straight
// from the same Geofabrik .osm.pbf offline.pmtiles itself is built from
// (see lib/maptool/hiking_trails.rb, PmtilesBuilder.extract_hiking_trails)
// — no network needed, and no waiting on Overpass for click details either
// (hit-tested locally via LaneLayer.queryLane instead, see _handleClick
// below). One file per country rather than one combined file: a viewer
// covering a dozen countries' worth of offline map data rarely wants all
// of their hiking trails loaded at once, so this is opt-in per country
// instead.
//
// Drawn with maplibre-gl-lanes rather than a plain line layer: a stretch
// of path several marked routes share (very common with KST blazes) is
// otherwise one line drawn over and over, only the topmost color visible.
// Lanes puts each route in its own parallel lane instead. It needs routes
// sharing a path to share exact vertices, which OSM relations over shared
// ways already do. One LaneLayer over every picked country, not one per
// country, so lanes at a border stay ordered together. Doesn't drape over
// 3D terrain (sinks under raised ground, warns on the console) — a known
// limitation of the library, not worth working around for an overlay.
const LANES_LAYER_ID = "hiking-trails-lanes";
const LANE_SIZES = () => ({ spacing: 3.5, width: 3, casingWidth: 0.5 });
function offlineUrl(code) {
return `/tiles/hiking_trails/${code}.geojson`;
}
// waymarkedtrails.org's own fallback for an untagged route.
const DEFAULT_TRAIL_COLOR = "#c1272d";
// Real-world `colour` values seen in production data (see the 2026-09-13
// extraction against SK.osm.pbf) — anything outside this set (typos like
// "yelllow", multi-value combos like "blue, yellow", stray hex codes) falls
// back to DEFAULT_TRAIL_COLOR rather than being trusted as a CSS value
// straight from OSM tag text.
const KNOWN_TRAIL_COLORS = new Set(["red", "yellow", "blue", "green", "orange", "purple", "brown", "black", "white", "grey", "gray", "darkblue"]);
function normalizedTrailColor(raw) {
if (!raw) return DEFAULT_TRAIL_COLOR;
const trimmed = raw.trim();
if (KNOWN_TRAIL_COLORS.has(trimmed.toLowerCase())) return trimmed.toLowerCase();
return /^#[0-9a-fA-F]{3,8}$/.test(trimmed) ? trimmed : DEFAULT_TRAIL_COLOR;
}
// Online mode's highlight outline for whichever route(s) the last click
// matched — drawn as its own separate source/layer (real geometry, from the
// Overpass response), since the raster tiles have no paintable features to
// highlight at all. Offline lanes use LaneLayer.setHighlight instead. Same "yellow outline on a picked
// route" treatment the earlier SVG prototype visualization used.
const HIGHLIGHT_SOURCE_ID = "hiking-trails-highlight";
const HIGHLIGHT_LAYER_ID = "hiking-trails-highlight-line";
// An Overlays panel item — a plain on/off checkbox (raster overlay) until
// offline extracts exist for at least one country, at which point it
// becomes an expandable per-country checklist instead (same expand shape
// as RadarControl), since a viewer with a dozen countries' worth of
// offline map data rarely wants all of their hiking trails loaded, let
// alone parsed by the browser, at once.
export class HikingTrailsControl {
constructor(map) {
this._map = map;
this._active = false; // the online-mode checkbox's own state
this._offlineCountries = []; // codes with an extract available on the server
this._selectedCountries = new Set(); // codes currently shown, offline mode
this._trailData = new Map(); // code -> fetched GeoJSON, kept across toggles/style swaps
this._routeInfo = new Map(); // String(relation id) -> feature properties, for the panel
this._lanes = null; // the current LaneLayer, null when no country is shown
map.on("click", (event) => this._handleClick(event));
this._panel = document.getElementById("trail-panel");
this._panelBody = this._panel.querySelector(".trail-panel__body");
this._panel.querySelector(".trail-panel__close").addEventListener("click", () => this._hidePanel());
// setStyle() (switching Online/Offline) tears down all custom sources/
// layers — put whatever was showing back, same as every other
// Overlays control. The highlight is transient (tied to whichever
// trail is showing in the panel, if any) — simpler to just drop it
// here than try to carry it across a style swap.
map.on("style.load", () => {
if (this._active) this._addOnlineLayer();
this._clearHighlight();
if (this._selectedCountries.size > 0) this._rebuildLanes();
});
}
mount(li) {
li.innerHTML = `
<div class="overlays-panel__row">
<input type="checkbox" class="overlays-panel__toggle">
<span class="overlays-panel__icon">${WALKING_ICON}</span>
<button type="button" class="overlays-panel__name">Hiking trails</button>
</div>
<div class="overlays-panel__details" hidden>
<ul class="hiking-trail-countries"></ul>
</div>
`;
this._checkbox = li.querySelector(".overlays-panel__toggle");
this._nameButton = li.querySelector(".overlays-panel__name");
this._details = li.querySelector(".overlays-panel__details");
this._countryList = li.querySelector(".hiking-trail-countries");
this._checkbox.addEventListener("change", (event) => this._toggleOnline(event.target.checked));
this._nameButton.addEventListener("click", () => {
if (this._offlineCountries.length === 0) return; // nothing to expand into yet
const expanding = this._details.hidden;
this._details.hidden = !expanding;
this._nameButton.setAttribute("aria-expanded", String(expanding));
});
}
// Called once map.js's GET /api/hiking-trails check resolves. Switches
// this item from "online raster, plain on/off" to "offline vector,
// pick your countries" — the two are mutually exclusive rather than
// both offered at once, since once a real local extract exists there's
// no reason to still fall back to a third-party tile server for any of
// it.
setOfflineCountries(countries) {
this._offlineCountries = countries;
if (countries.length === 0) return;
if (this._active) this._toggleOnline(false);
this._checkbox.hidden = true;
this._countryList.innerHTML = countries
.map(
(code) => `
<li class="hiking-trail-countries__item">
<label>
<input type="checkbox" class="hiking-trail-countries__toggle" value="${code}">
${code}
</label>
</li>
`,
)
.join("");
this._countryList.querySelectorAll(".hiking-trail-countries__toggle").forEach((input) => {
input.addEventListener("change", (event) => this._toggleCountry(event.target.value, event.target.checked));
});
}
_toggleOnline(active) {
this._active = active;
if (active) this._addOnlineLayer();
else this._removeOnlineLayer();
}
async _toggleCountry(code, active) {
if (!active) {
this._selectedCountries.delete(code);
this._rebuildLanes();
return;
}
this._selectedCountries.add(code);
if (!this._trailData.has(code)) {
let geojson;
try {
geojson = await (await fetch(offlineUrl(code))).json();
} catch {
return; // degrade quietly, same story as every other optional layer here
}
// Normalized once here so an untrustworthy `colour` tag value never
// reaches the layer's color directly — same reasoning gpx.js's own
// feature.properties.color ||= TRACK_COLOR normalization gives.
for (const feature of geojson.features) {
feature.properties.color = normalizedTrailColor(feature.properties.colour);
}
this._trailData.set(code, geojson);
if (!this._selectedCountries.has(code)) return; // toggled back off while fetching
}
this._rebuildLanes();
}
// Rebuilt from scratch on every country toggle and style swap (setStyle
// drops custom layers too) — lane order depends on every route drawn, so
// there's no cheaper incremental path. Ordering runs in a worker; a newer
// rebuild started meanwhile wins, same token guard as _handleOnlineClick.
async _rebuildLanes() {
const build = (this._lanesBuild = {});
const features = [...this._selectedCountries].flatMap((code) => this._trailData.get(code)?.features || []);
let graph = null;
if (features.length > 0) {
graph = buildLineGraph(features, { routeProperty: "id" });
await orderLanesAsync(graph);
}
if (this._lanesBuild !== build) return;
this._hidePanel();
if (this._map.getLayer(LANES_LAYER_ID)) this._map.removeLayer(LANES_LAYER_ID);
this._lanes = null;
this._routeInfo = new Map(features.map((feature) => [String(feature.properties.id), feature.properties]));
if (!graph) return;
this._lanes = new LaneLayer({ id: LANES_LAYER_ID, graph, sizes: LANE_SIZES, casingColor: "rgba(255, 255, 255, 0.8)" });
// Below labels (same firstSymbolLayerId spot contour.js/radar.js use),
// so place names/POI icons stay readable on top of the trail lines.
this._map.addLayer(this._lanes, firstSymbolLayerId(this._map));
}
_handleClick(event) {
if (this._selectedCountries.size > 0) this._handleOfflineClick(event);
else if (this._active) this._handleOnlineClick(event);
}
// The lanes have real geometry to hit-test directly — no network
// round-trip, so this resolves instantly. Each route has its own lane, so
// a click picks exactly one, highlighted by the layer itself. A genuine
// miss just closes an already-open panel rather than showing a "not
// found" message, same as clicking empty space anywhere else on the map.
_handleOfflineClick(event) {
const hit = this._lanes?.queryLane(event.point, 8);
const info = hit && this._routeInfo.get(String(hit.route));
if (!info) {
this._hidePanel();
return;
}
this._lanes.setHighlight(hit.route);
this._showPanel(routeHtml(info));
}
_showPanel(html) {
this._panelBody.innerHTML = html;
this._panel.hidden = false;
}
_hidePanel() {
if (this._panel.hidden) return;
this._panel.hidden = true;
this._clearHighlight();
}
// The raster tiles have no queryable features (they're pixels), so
// "what trail is this" is answered with a one-off Overpass query instead
// of a MapLibre feature hit-test — an `around` search rather than an
// exact point match, since a click rarely lands exactly on the (already
// pixel-thick) rendered line.
async _handleOnlineClick(event) {
const { lng, lat } = event.lngLat;
this._showPanel(`<p class="gpx-popup__category">Looking for trails…</p>`);
// A newer click's request replaces this one while Overpass is still
// answering — same "in-flight response arrives after it's already
// stale" guard the old Popup-identity check gave, just keyed off a
// fresh token each click instead of a fresh Popup instance.
const request = (this._onlineRequest = {});
let relations;
try {
relations = await fetchNearbyRoutes(lng, lat);
} catch {
if (this._onlineRequest === request) this._panelBody.innerHTML = `<p class="gpx-popup__category">Could not reach Overpass.</p>`;
return;
}
if (this._onlineRequest !== request) return;
if (relations.length === 0) {
this._panelBody.innerHTML = `<p class="gpx-popup__category">No hiking trail found here.</p>`;
return;
}
this._panelBody.innerHTML = relations.map((relation) => routeHtml(overpassRouteInfo(relation))).join("<hr>");
this._setHighlight(relations.map((relation) => ({ geometry: routeGeometry(relation), color: normalizedTrailColor(relation.tags?.colour) })));
}
_addOnlineLayer() {
if (this._map.getSource(ONLINE_SOURCE_ID)) return;
this._map.addSource(ONLINE_SOURCE_ID, {
type: "raster",
tiles: [TILE_URL],
tileSize: 256,
maxzoom: 17,
attribution: ATTRIBUTION,
});
// Below labels (same firstSymbolLayerId spot contour.js/radar.js use),
// so place names/POI icons stay readable on top of the trail lines.
this._map.addLayer(
{ id: ONLINE_LAYER_ID, type: "raster", source: ONLINE_SOURCE_ID, paint: { "raster-opacity": OPACITY } },
firstSymbolLayerId(this._map),
);
}
_removeOnlineLayer() {
if (this._map.getLayer(ONLINE_LAYER_ID)) this._map.removeLayer(ONLINE_LAYER_ID);
if (this._map.getSource(ONLINE_SOURCE_ID)) this._map.removeSource(ONLINE_SOURCE_ID);
}
// features: an array of { geometry, color } — geometry a GeoJSON
// LineString or MultiLineString (mixed is fine), color the trail's own
// (already-normalized) colour — everything the last click matched, drawn
// as one highlight layer (a wider outline in the trail's own color,
// rather than a fixed color that would repaint it) on top of the base
// trail rendering.
_setHighlight(features) {
const data = {
type: "FeatureCollection",
features: features.map(({ geometry, color }) => ({ type: "Feature", properties: { color }, geometry })),
};
const source = this._map.getSource(HIGHLIGHT_SOURCE_ID);
if (source) {
source.setData(data);
return;
}
this._map.addSource(HIGHLIGHT_SOURCE_ID, { type: "geojson", data });
this._map.addLayer({
id: HIGHLIGHT_LAYER_ID,
type: "line",
source: HIGHLIGHT_SOURCE_ID,
layout: { "line-cap": "round", "line-join": "round" },
paint: { "line-color": ["get", "color"], "line-width": 5, "line-opacity": 0.9 },
});
}
_clearHighlight() {
this._lanes?.setHighlight(null);
if (this._map.getLayer(HIGHLIGHT_LAYER_ID)) this._map.removeLayer(HIGHLIGHT_LAYER_ID);
if (this._map.getSource(HIGHLIGHT_SOURCE_ID)) this._map.removeSource(HIGHLIGHT_SOURCE_ID);
}
}
// way(around:...) finds candidate ways near the click, then rel(bw...)
// walks backward from those to their parent relations — the same
// find-the-way-then-its-relation shape as clicking a route on
// waymarkedtrails.org's own site. `out geom` inlines each member way's
// full coordinate list right on the relation, so no separate stitching
// step is needed to get real geometry back.
async function queryOverpass(url, query) {
const response = await fetch(url, { method: "POST", body: `data=${encodeURIComponent(query)}` });
if (!response.ok) throw new Error(`overpass ${response.status}`);
return response.json();
}
async function fetchNearbyRoutes(lng, lat) {
const query = `[out:json][timeout:15];way(around:${CLICK_RADIUS_M},${lat},${lng})->.w;rel(bw.w)["route"="hiking"];out geom;`;
const data = await Promise.any(OVERPASS_APIS.map((url) => queryOverpass(url, query)));
return (data.elements || []).filter((element) => element.type === "relation");
}
// OSM doesn't tag a route's length directly — summed from each member
// way's own geometry instead, same haversine-sum measure.js's own Measure
// tool uses for a hand-drawn line. Shared endpoints between adjacent ways
// get walked twice, same as how a real hike over those ways would. Mirrors
// Maptool::HikingTrails.relation_feature's own distance calc server-side
// (lib/maptool/hiking_trails.rb) — this is the online, no-server-file path.
function routeDistance(relation) {
return (relation.members || [])
.filter((member) => member.type === "way" && member.geometry)
.reduce((total, member) => total + lineLength(member.geometry.map((point) => [point.lon, point.lat])), 0);
}
// Same member-way walk as routeDistance above, collecting coordinates
// instead of summing them — the online click highlight's geometry source,
// since there's no vector feature to read it back from the way the offline
// layer's own queryRenderedFeatures result already carries one.
function routeGeometry(relation) {
const lines = (relation.members || [])
.filter((member) => member.type === "way" && member.geometry)
.map((member) => member.geometry.map((point) => [point.lon, point.lat]));
return { type: "MultiLineString", coordinates: lines };
}
// Adapts a raw Overpass relation into the same shape offline GeoJSON
// features' properties already carry (lib/maptool/hiking_trails.rb's own
// ROUTE_TAGS + distance_meters + id) — one HTML builder (routeHtml) below
// serves both instead of two near-identical ones.
function overpassRouteInfo(relation) {
const tags = relation.tags || {};
return {
id: relation.id,
name: tags.name,
description: tags.description,
colour: tags.colour,
network: tags.network,
operator: tags.operator,
ref: tags.ref,
distance_meters: routeDistance(relation),
};
}
function routeHtml(info) {
const name = info.name || info.description || "Hiking trail";
const swatch = SAFE_COLOR.test(info.colour || "")
? `<span class="hiking-trail-popup__swatch" style="background:${info.colour}"></span>`
: "";
const meta = [formatDistance(info.distance_meters || 0)];
if (info.ref) meta.push(`#${info.ref}`);
if (info.network) meta.push(info.network);
if (info.operator) meta.push(escapeHtml(info.operator));
const parts = [
`<div class="gpx-popup__header"><strong>${escapeHtml(name)}</strong>${swatch}</div>`,
`<p class="gpx-popup__category">${meta.filter(Boolean).join(" · ")}</p>`,
];
// description already used as the title above when there's no name — only
// shown again here as its own line if there both is a name *and* a
// description to add, so it's never rendered twice for the common
// no-name case.
if (info.name && info.description) parts.push(`<p class="gpx-popup__description">${escapeHtml(info.description)}</p>`);
parts.push(
`<p class="gpx-popup__link"><a href="https://www.openstreetmap.org/relation/${info.id}" target="_blank" rel="noopener noreferrer">View on OpenStreetMap →</a></p>`,
);
return parts.join("");
}
+154 -11
View File
@@ -7,10 +7,14 @@ export const LAYERS_ICON = `
<path d="M2 14l10 6 10-6"/> <path d="M2 14l10 6 10-6"/>
</svg>`; </svg>`;
export const HILLSHADE_ICON = ` // Two overlapping circles — distinct from LAYERS_ICON's stacked-planes
// look (that one picks a *base* map; this one is for the sidebar flyout
// toggling live overlay layers, e.g. Wikipedia, on top of whichever base
// map is showing) while still reading as "layers combining."
export const OVERLAYS_ICON = `
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round" stroke-linecap="round"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round" stroke-linecap="round">
<path d="M2 18 9 7l3.5 5.5L15 9l7 9z"/> <circle cx="9" cy="12" r="6"/>
<path d="M2 18h20"/> <circle cx="15" cy="12" r="6"/>
</svg>`; </svg>`;
export const NOTE_PIN_ICON = ` export const NOTE_PIN_ICON = `
@@ -26,11 +30,6 @@ export const GPX_ICON = `
<path d="M6.5 7.5C10 11 8 13 12 13s2 5 6.5 5"/> <path d="M6.5 7.5C10 11 8 13 12 13s2 5 6.5 5"/>
</svg>`; </svg>`;
export const RADAR_ICON = `
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round" stroke-linecap="round">
<path d="M7 18a4 4 0 1 1 .7-7.94A5 5 0 0 1 17 9a4 4 0 0 1 0 8H7z"/>
</svg>`;
export const GNSS_ICON = ` export const GNSS_ICON = `
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round">
<circle cx="12" cy="12" r="5.5"/> <circle cx="12" cy="12" r="5.5"/>
@@ -44,6 +43,31 @@ export const RULER_ICON = `
<path d="M9 10l1.5 1.5M12 7l1.5 1.5M15 4l1.5 1.5M6 13l1.5 1.5"/> <path d="M9 10l1.5 1.5M12 7l1.5 1.5M15 4l1.5 1.5M6 13l1.5 1.5"/>
</svg>`; </svg>`;
// Toolbar readout glyphs (public/js/sun.js's text, assembled with these by
// map.js) — same monoline style as the sidebar icons above, no NPS source
// for either (that set has no sunrise/sunset pictogram).
export const SUNRISE_ICON = `
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 18h18"/>
<path d="M6 18a6 6 0 0 1 12 0"/>
<path d="M12 13V5"/>
<path d="M9 8l3-3 3 3"/>
</svg>`;
export const SUNSET_ICON = `
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 18h18"/>
<path d="M6 18a6 6 0 0 1 12 0"/>
<path d="M12 5v8"/>
<path d="M9 10l3 3 3-3"/>
</svg>`;
export const SEARCH_ICON = `
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
<circle cx="11" cy="11" r="7"/>
<path d="M20 20l-4.35-4.35"/>
</svg>`;
export const NEW_FOLDER_ICON = ` export const NEW_FOLDER_ICON = `
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7z"/> <path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7z"/>
@@ -56,6 +80,15 @@ export const UPLOAD_ICON = `
<path d="M4 15v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3"/> <path d="M4 15v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3"/>
</svg>`; </svg>`;
// The inverse of UPLOAD_ICON (arrow into the tray, not out of it) — used
// for the import plugins panel (plugins.js), which pulls data in from
// somewhere else rather than sending a file out.
export const PLUGIN_ICON = `
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 4v11M8 11l4 4 4-4"/>
<path d="M4 15v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3"/>
</svg>`;
// Shown next to each file in the GPX tree, indicating whether it has // Shown next to each file in the GPX tree, indicating whether it has
// waypoints, a track, or both. // waypoints, a track, or both.
export const WAYPOINT_ICON = ` export const WAYPOINT_ICON = `
@@ -132,6 +165,46 @@ export const MAP_MARKER_ICON = `
// tinted at render time, see gpx.js's _registerCategoryGlyphs) so only the // tinted at render time, see gpx.js's _registerCategoryGlyphs) so only the
// alpha shape matters, not the actual `currentColor` value. // alpha shape matters, not the actual `currentColor` value.
// src/wilderness-22.svg — exported (unlike BICYCLE_TRAIL_ICON below, this
// one's also used outside this file) as the Overlays panel's Terrain
// shading glyph (overlays.js): the closest honest match in NPS's set for
// "mountains/terrain" — it has no weather or elevation-specific pictogram.
export const WILDERNESS_ICON = `
<svg viewBox="0 0 22 22" fill="currentColor"><polygon points="18,18 13,15 17,15 13,11 16,11 12,7 15,7 12,4 14,4 11,0 8,4 10,4 7,7 10,7 6,11 9,11 5,15 9,15 4,18 10,18 10,22 12,22 12,18 "/></svg>`;
// Hand-drawn, not NPS-sourced — that set has no weather/precipitation
// pictogram to reuse for the Overlays panel's Radar item, unlike Wikipedia
// (WIKI_ICON) and Terrain shading (WILDERNESS_ICON) above.
export const RADAR_CLOUD_ICON = `
<svg viewBox="0 0 22 22" fill="currentColor">
<path d="M17,10.1c-0.4-3-2.9-5.3-6-5.3c-2.5,0-4.7,1.5-5.6,3.8C3.4,8.9,1,11.1,1,13.9C1,16.7,3.3,19,6.1,19h10.3
c2.5,0,4.6-2,4.6-4.5C21,12.2,19.3,10.4,17,10.1z"/>
<rect x="6" y="20" width="1.6" height="2"/>
<rect x="10.2" y="20" width="1.6" height="2"/>
<rect x="14.4" y="20" width="1.6" height="2"/>
</svg>`;
// Hand-drawn, not NPS-sourced — same story as RADAR_CLOUD_ICON above, no
// terrain-shadow/sun-behind-a-ridge pictogram in that set either. Used as
// the Overlays panel's Terrain shadow glyph (shadow.js via overlays.js).
export const TERRAIN_SHADOW_ICON = `
<svg viewBox="0 0 22 22" fill="currentColor">
<circle cx="16" cy="6" r="3"/>
<polygon points="0,19 6,9 9,13 13,6 22,19"/>
</svg>`;
// Hand-drawn, not NPS-sourced — no contour-line pictogram in that set
// either. Concentric rings via fill-rule evenodd, same solid-glyph
// convention as WILDERNESS_ICON/RADAR_CLOUD_ICON/TERRAIN_SHADOW_ICON above —
// used as the Overlays panel's Contour lines glyph (contour.js).
export const CONTOUR_ICON = `
<svg viewBox="0 0 22 22" fill="currentColor" fill-rule="evenodd">
<path d="M21,11 A10,10 0 1,0 1,11 A10,10 0 1,0 21,11 Z
M18.5,11 A7.5,7.5 0 1,0 3.5,11 A7.5,7.5 0 1,0 18.5,11 Z
M16,11 A5,5 0 1,0 6,11 A5,5 0 1,0 16,11 Z
M13.5,11 A2.5,2.5 0 1,0 8.5,11 A2.5,2.5 0 1,0 13.5,11 Z"/>
</svg>`;
// src/bicycle-trail-22.svg — pulled out to its own constant since it's also // src/bicycle-trail-22.svg — pulled out to its own constant since it's also
// used unrasterized, inline, as PARK4NIGHT_TAGS.vtt below. // used unrasterized, inline, as PARK4NIGHT_TAGS.vtt below.
const BICYCLE_TRAIL_ICON = ` const BICYCLE_TRAIL_ICON = `
@@ -146,6 +219,20 @@ const BICYCLE_TRAIL_ICON = `
c1,0,1,1.3,0,1.3H13.1L13.1,9.8z"/> c1,0,1,1.3,0,1.3H13.1L13.1,9.8z"/>
</svg>`; </svg>`;
// src/store-22.svg — NPS's generic shop pictogram, the closest match in
// their set for both a supermarket and a convenience store (no separate
// grocery-specific glyph exists there).
const STORE_ICON = `
<svg viewBox="0 0 22 22" fill="currentColor">
<path d="M20,9c0,0-0.8,3-4,3C16,12,15.8,9.9,20,9z"/>
<path d="M17,14.3c0.5-0.5,1.3-0.9,2.1-0.9c1.6,0,2.9,1.3,2.9,3v0.2l0,0c-0.1,0.6-0.3,1.5-0.7,2.4c0,0-0.8,1.6-1.5,2.3l-0.1,0.1
c-0.3,0.3-0.8,0.5-1.3,0.5c-0.6,0-1.1-0.5-1.5-1c-0.3,0.5-0.9,1-1.5,1c-0.5,0-0.9-0.2-1.3-0.5L14,21.3c-0.7-0.7-1.5-2.3-1.5-2.3
c-0.5-1-0.7-1.8-0.7-2.4l0,0v-0.2c0-1.7,1.3-3,2.9-3C15.7,13.5,16.5,13.8,17,14.3"/>
<polygon points="4,0 8,0 8,2 4,2 "/>
<path d="M7,3H3c0,0-0.7,0.2-1.2,0.7L0.2,5.8C0.1,6,0,5.9,0,6.1V21c0,0.4,0.6,1,1,1h8c0.4,0,1-0.6,1-1V6C10,6,9.6,3.3,7,3z M4,4v5H3
v1H2l-1,1v-1V6h1V5h1L4,4z"/>
</svg>`;
export const POI_ICONS = { export const POI_ICONS = {
// src/parking-22.svg // src/parking-22.svg
amenity_parking: ` amenity_parking: `
@@ -180,8 +267,7 @@ export const POI_ICONS = {
</svg>`, </svg>`,
// src/wilderness-22.svg // src/wilderness-22.svg
forest: ` forest: WILDERNESS_ICON,
<svg viewBox="0 0 22 22" fill="currentColor"><polygon points="18,18 13,15 17,15 13,11 16,11 12,7 15,7 12,4 14,4 11,0 8,4 10,4 7,7 10,7 6,11 9,11 5,15 9,15 4,18 10,18 10,22 12,22 12,18 "/></svg>`,
// src/bicycle-trail-22.svg // src/bicycle-trail-22.svg
sport_cycling: BICYCLE_TRAIL_ICON, sport_cycling: BICYCLE_TRAIL_ICON,
@@ -242,7 +328,11 @@ const FISHING_ICON = `
const SCENIC_VIEWPOINT_ICON = ` const SCENIC_VIEWPOINT_ICON = `
<svg viewBox="0 0 22 22" fill="currentColor"><g transform="translate(4.000000, 0.000000)"><path d="M3.2,11c0,1.2-0.9,2.2-2.1,2.2c-1.2,0-2.1-1-2.1-2.2 c0-1.2,0.9-2.2,2.1-2.2C2.2,8.8,3.2,9.8,3.2,11"/><path d="M4.6,10.4v1.3l10.6,0.8v-3L4.6,10.4"/><path d="M2.3,7.5l1.1,0.7L7.7,2L5.3,0.5L2.3,7.5"/><path d="M4.4,9.8l7.9-3.8l-1.4-2.6L3.8,8.6L4.4,9.8z"/><path d="M2.3,14.5l1.1-0.7l4.3,6.2l-2.4,1.5L2.3,14.5"/><path d="M3.8,13.4l0.6-1.2l7.9,3.8l-1.4,2.6L3.8,13.4"/></g></svg>`; <svg viewBox="0 0 22 22" fill="currentColor"><g transform="translate(4.000000, 0.000000)"><path d="M3.2,11c0,1.2-0.9,2.2-2.1,2.2c-1.2,0-2.1-1-2.1-2.2 c0-1.2,0.9-2.2,2.1-2.2C2.2,8.8,3.2,9.8,3.2,11"/><path d="M4.6,10.4v1.3l10.6,0.8v-3L4.6,10.4"/><path d="M2.3,7.5l1.1,0.7L7.7,2L5.3,0.5L2.3,7.5"/><path d="M4.4,9.8l7.9-3.8l-1.4-2.6L3.8,8.6L4.4,9.8z"/><path d="M2.3,14.5l1.1-0.7l4.3,6.2l-2.4,1.5L2.3,14.5"/><path d="M3.8,13.4l0.6-1.2l7.9,3.8l-1.4,2.6L3.8,13.4"/></g></svg>`;
const WALKING_ICON = ` // Exported (unlike the other POI glyphs around it) — also used as the
// Overlays panel's Hiking trails glyph (hiking_trails.js), same "reuse an
// existing NPS-sourced pictogram" story as WILDERNESS_ICON above rather
// than hand-drawing another one.
export const WALKING_ICON = `
<svg viewBox="0 0 22 22" fill="currentColor"><path d="M10.4,3.6c1,0,1.8-0.8,1.7-1.8c0-1-0.8-1.8-1.8-1.7c-1,0-1.8,0.8-1.7,1.8C8.6,2.8,9.5,3.6,10.4,3.6z"/><path d="M16.5,9.5L13.9,8l-2.2-3.4c-0.3-0.4-0.9-0.8-1.5-0.7C9.7,4,9.3,4.2,9,4.4L5.8,7.7C5.7,7.8,5.6,8,5.6,8.1l-0.4,3.6 c0,0,0,0.1,0,0.1c0,0.4,0.4,0.8,0.8,0.8c0.4,0,0.7-0.4,0.8-0.8l0.3-3.1l1.1-1.1l-1,8.6l-1.9,4.1c-0.1,0.1-0.1,0.3-0.1,0.5 c0,0.7,0.6,1.2,1.2,1.2c0.5,0,0.9-0.3,1.1-0.7l2-4.4c0-0.1,0.2-0.4,0.2-0.5l0.2-2.1l2.1,6.9c0.2,0.5,0.6,0.8,1.2,0.8 c0.7,0,1.2-0.6,1.2-1.2c0-0.1,0-0.1,0-0.2L11.5,11l0.4-3.1l0.8,1.3c0.1,0.1,0.1,0.2,0.2,0.2l2.8,1.6c0.1,0,0.2,0.1,0.4,0.1 c0.4,0,0.8-0.4,0.8-0.8C16.9,9.8,16.7,9.6,16.5,9.5z"/></svg>`; <svg viewBox="0 0 22 22" fill="currentColor"><path d="M10.4,3.6c1,0,1.8-0.8,1.7-1.8c0-1-0.8-1.8-1.8-1.7c-1,0-1.8,0.8-1.7,1.8C8.6,2.8,9.5,3.6,10.4,3.6z"/><path d="M16.5,9.5L13.9,8l-2.2-3.4c-0.3-0.4-0.9-0.8-1.5-0.7C9.7,4,9.3,4.2,9,4.4L5.8,7.7C5.7,7.8,5.6,8,5.6,8.1l-0.4,3.6 c0,0,0,0.1,0,0.1c0,0.4,0.4,0.8,0.8,0.8c0.4,0,0.7-0.4,0.8-0.8l0.3-3.1l1.1-1.1l-1,8.6l-1.9,4.1c-0.1,0.1-0.1,0.3-0.1,0.5 c0,0.7,0.6,1.2,1.2,1.2c0.5,0,0.9-0.3,1.1-0.7l2-4.4c0-0.1,0.2-0.4,0.2-0.5l0.2-2.1l2.1,6.9c0.2,0.5,0.6,0.8,1.2,0.8 c0.7,0,1.2-0.6,1.2-1.2c0-0.1,0-0.1,0-0.2L11.5,11l0.4-3.1l0.8,1.3c0.1,0.1,0.1,0.2,0.2,0.2l2.8,1.6c0.1,0,0.2,0.1,0.4,0.1 c0.4,0,0.8-0.4,0.8-0.8C16.9,9.8,16.7,9.6,16.5,9.5z"/></svg>`;
const GUIDED_TOURS_ICON = ` const GUIDED_TOURS_ICON = `
@@ -305,6 +395,59 @@ export const PARK4NIGHT_TAGS = {
windsurf: { icon: WIND_SURFING_ICON, label: "Windsurfing" }, windsurf: { icon: WIND_SURFING_ICON, label: "Windsurfing" },
}; };
// Extends POI_ICONS (and so POI_ICON_KEYS, and what a marker badge can
// show — see gpx.js's _registerCategoryGlyphs) with a handful of the same
// symbols PARK4NIGHT_TAGS above already vendors, reused rather than
// duplicated — this app's own hand-drawn notes (notes.js's icon picker)
// need marker-badge glyphs for "water source"/"dump station"/"viewpoint"
// far more than the original OSM-POI-upload set (parking/hotel/fuel) ever
// covered. Object.assign, not more entries in the POI_ICONS literal
// itself, since these constants are declared below it in this file.
Object.assign(POI_ICONS, {
amenity_drinking_water: DRINKING_WATER_ICON,
amenity_sanitary_dump_station: SANITARY_DISPOSAL_ICON,
amenity_toilets: RESTROOMS_ICON,
shop_gas: PROPANE_ICON,
amenity_electricity: ELECTRICAL_HOOKUP_ICON,
shop_laundry: LAUNDRY_ICON,
leisure_playground: PLAYGROUND_ICON,
tourism_viewpoint: SCENIC_VIEWPOINT_ICON,
leisure_swimming: SWIMMING_ICON,
leisure_fishing: FISHING_ICON,
sport_climbing: CLIMBING_ICON,
route_hiking: WALKING_ICON,
shop_supermarket: STORE_ICON,
shop_convenience: STORE_ICON,
});
// Hand-drawn, not NPS-sourced — no "download offline map data" pictogram
// in that set either. A tray with a downward arrow into it, same solid
// 22x22 currentColor convention as CONTOUR_ICON/TERRAIN_SHADOW_ICON above
// — used for the "Offline data" sidebar icon (offline_data.js).
export const OFFLINE_DATA_ICON = `
<svg viewBox="0 0 22 22" fill="currentColor">
<path d="M10,0h2v10.5l3-3l1.4,1.4L11,14.3L5.6,8.9L7,7.5l3,3V0z"/>
<path d="M2,15h18v2H2z M2,18h18v2H2z"/>
</svg>`;
// src/bookstore-22.svg (NPS symbol library, same source/license as
// POI_ICONS above) — used as the fixed marker glyph for the "Wikipedia"
// map layer (gpx.js), not part of POI_ICONS itself: that set is keyed by
// OSM/p4n2gpx category and doubles as the note icon-picker's option list
// (notes.js), neither of which applies here — every point on this layer
// gets the same one glyph, there's no per-feature category to key it by.
export const WIKI_ICON = `
<svg viewBox="0 0 22 22" fill="currentColor">
<path d="M16.6,20.7c-0.6,0-0.9-0.4-0.9-0.9c0-0.5,0.3-0.9,0.9-0.9c0.3,0,0.5-0.2,0.5-0.5
S16.9,18,16.6,18c-1.1,0-1.9,0.8-1.9,1.9c0,1,0.7,1.9,1.9,1.9c0.3,0,0.5-0.2,0.5-0.5S16.9,20.7,16.6,20.7L16.6,20.7z"/>
<path d="M5,18c0,0,0,0,0,0c0,3.1,0.5,4,2.7,4l8.9,0c0.3,0,0.5-0.2,0.5-0.5
c0-0.3-0.2-0.5-0.5-0.5H8c-1.5,0-2-0.5-2-3c0,0,0,0,0-0.1c0-0.3-0.2-0.5-0.5-0.5S5,17.7,5,18L5,18z"/>
<path d="M5,8c0-0.6,5-5,5-5h5h1c0.6,0,1,0.4,1,1v14c0,0.6-0.4,1-1,1H6c-0.6,0-1-0.4-1-1
V8z M9,4L6,18c0,0,10,0,10,0c0,0,0-14,0-14C16,4,9,4,9,4z"/>
<path d="M5,6.8c0-0.5,0.4-1.3,0.8-1.6l6.4-4.7C12.7,0.2,13,0.4,13,1v10
c0,0.6-0.3,1.7-0.7,2.1l-6.5,5.3C5.4,18.8,5,18.6,5,18V6.8z"/>
</svg>`;
export const LIVETRACK_ICON = ` export const LIVETRACK_ICON = `
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 21s7-7.58 7-12a7 7 0 0 0-14 0c0 4.42 7 12 7 12z"/> <path d="M12 21s7-7.58 7-12a7 7 0 0 0-14 0c0 4.42 7 12 7 12z"/>
+17 -1
View File
@@ -5,6 +5,11 @@ import { notifySidePanelOpen, onlyOneSidePanelOpen } from "/js/panels.js";
const SESSIONS_URL = "/api/livetrack/sessions"; const SESSIONS_URL = "/api/livetrack/sessions";
const TRACK_SOURCE = "livetrack-track"; const TRACK_SOURCE = "livetrack-track";
const TRACK_COLOR = "#7209b7"; const TRACK_COLOR = "#7209b7";
// The planned route (only present when the activity was started from a
// saved Garmin course, see LiveTrackClient#fetch) — dashed and muted so it
// reads as a reference line, not more recorded data next to the actual
// track's own color.
const PLANNED_COLOR = "#888";
// Garmin devices post a new point roughly every 15s (postTrackPointFrequency // Garmin devices post a new point roughly every 15s (postTrackPointFrequency
// in the session data) — polling twice that often would just re-fetch the // in the session data) — polling twice that often would just re-fetch the
// same 400+KB page for nothing most of the time. // same 400+KB page for nothing most of the time.
@@ -171,11 +176,22 @@ export class LiveTrackPanelControl {
if (this._map.getSource(TRACK_SOURCE)) return; if (this._map.getSource(TRACK_SOURCE)) return;
this._map.addSource(TRACK_SOURCE, { type: "geojson", data: geojson }); this._map.addSource(TRACK_SOURCE, { type: "geojson", data: geojson });
// Added before the actual track's own line layer so it paints
// underneath — the recorded track is the thing that actually matters
// when the two overlap.
this._map.addLayer({
id: `${TRACK_SOURCE}-planned`,
type: "line",
source: TRACK_SOURCE,
filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", ["get", "kind"], "planned"]],
layout: { "line-cap": "round", "line-join": "round" },
paint: { "line-color": PLANNED_COLOR, "line-width": 2, "line-dasharray": [2, 2] },
});
this._map.addLayer({ this._map.addLayer({
id: `${TRACK_SOURCE}-line`, id: `${TRACK_SOURCE}-line`,
type: "line", type: "line",
source: TRACK_SOURCE, source: TRACK_SOURCE,
filter: ["==", ["geometry-type"], "LineString"], filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", ["get", "kind"], "actual"]],
layout: { "line-cap": "round", "line-join": "round" }, layout: { "line-cap": "round", "line-join": "round" },
paint: { "line-color": TRACK_COLOR, "line-width": 3 }, paint: { "line-color": TRACK_COLOR, "line-width": 3 },
}); });
+221 -213
View File
@@ -2,17 +2,22 @@ import {
Map as MaplibreMap, Map as MaplibreMap,
NavigationControl, NavigationControl,
Popup, Popup,
ScaleControl,
addProtocol, addProtocol,
} from "/vendor/maplibre-gl/maplibre-gl.mjs"; } from "/vendor/maplibre-gl/maplibre-gl.mjs";
import { RadarControl } from "/js/radar.js";
import { GpxPanelControl } from "/js/gpx.js"; import { GpxPanelControl } from "/js/gpx.js";
import { OverlaysControl } from "/js/overlays.js";
import { GnssControl } from "/js/gnss.js"; import { GnssControl } from "/js/gnss.js";
import { LiveTrackPanelControl } from "/js/livetrack.js"; import { LiveTrackPanelControl } from "/js/livetrack.js";
import { TrackProfilePanel } from "/js/track_profile.js"; import { TrackProfilePanel } from "/js/track_profile.js";
import { MeasureControl } from "/js/measure.js"; import { MeasureControl } from "/js/measure.js";
import { NotesControl } from "/js/notes.js"; import { NotesControl } from "/js/notes.js";
import { PluginsControl } from "/js/plugins.js";
import { LocateControl } from "/js/locate.js"; import { LocateControl } from "/js/locate.js";
import { LAYERS_ICON, HILLSHADE_ICON } from "/js/icons.js"; import { SearchControl } from "/js/search.js";
import { OfflineDataControl } from "/js/offline_data.js";
import { LAYERS_ICON, WAYPOINT_ICON, SUNRISE_ICON, SUNSET_ICON, PENDING_ICON } from "/js/icons.js";
import { formatCoords, formatSunInfo } from "/js/sun.js";
import { notifySidePanelOpen, onlyOneSidePanelOpen } from "/js/panels.js"; import { notifySidePanelOpen, onlyOneSidePanelOpen } from "/js/panels.js";
import { isLoggedIn } from "/js/auth.js"; import { isLoggedIn } from "/js/auth.js";
import HomeButton from "/vendor/npmap-home-button/home-button.esm.js"; import HomeButton from "/vendor/npmap-home-button/home-button.esm.js";
@@ -23,29 +28,46 @@ const CENTER = [17.1077, 48.1486];
const ZOOM = 13; const ZOOM = 13;
const ONLINE_STYLE_URL = "https://tiles.openfreemap.org/styles/liberty"; const ONLINE_STYLE_URL = "https://tiles.openfreemap.org/styles/liberty";
// Recolors OpenFreeMap Liberty to the same NPS-inspired palette as // Recolors OpenFreeMap Liberty to a warm, NPS-Park-Tiles-inspired palette —
// OFFLINE_THEME below — warm cream ground, muted roads/boundaries — mapped // cream ground, muted roads/boundaries — mapped onto Liberty's OpenMapTiles
// onto Liberty's OpenMapTiles layer ids instead of protomaps' theme roles // layer ids. Applied identically regardless of which PMTiles data actually
// (the two schemas don't share layer names, so this is a separate // backs the "openmaptiles" source (see offlineStyle() below): offline tiles
// hand-built table, not a shared object). Only the layers that dominate the // are built by Planetiler's own OpenMapTiles profile (docs/development.adoc),
// map's overall color read are touched; labels, halos, rail, and minor // the same schema Liberty already expects, so one patch serves both —
// overlays (cemetery/hospital/school/pitch/track shading, building // no separate offline theme/palette to keep in sync. Only the layers that
// outlines) are left at Liberty's own defaults — same "not a full // dominate the map's overall color read are touched; labels, halos, rail,
// recolor" scope as OFFLINE_THEME. Road casings have no protomaps-role // and minor overlays (cemetery/hospital/school/pitch/track shading,
// equivalent to reuse (offline roads don't get a separate outline), so // building outlines) are left at Liberty's own defaults.
// #c9a66b there is reasoned to fit the family rather than sourced from
// anywhere real.
// //
// wood/grass are deliberately left unpatched — Liberty's own green reads // wood/grass are deliberately left unpatched — Liberty's own green (a
// better than this app's earlier brown/khaki recolor, and OFFLINE_THEME's // translucent landcover_wood/landcover_grass wash) already reads well over
// wood_a/scrub_a below were changed to match Liberty's green instead. // the patched cream background.
const ONLINE_STYLE_PATCH = { const ONLINE_STYLE_PATCH = {
background: { "background-color": "#f9f6ef" }, background: { "background-color": "#f9f6ef" },
// Liberty washes every built-up area in a translucent gray-tan below
// z12 (landuse_residential, maxzoom 12 — gone by this app's default
// z13) that the offline schema has no equivalent of; protomaps just
// leaves that ground as plain background/earth. Matched to background
// here rather than left alone, so a zoomed-out view doesn't read as
// visibly dingier online than offline.
landuse_residential: { "fill-color": "#f9f6ef" },
landcover_sand: { "fill-color": "#f0e4c4" }, landcover_sand: { "fill-color": "#f0e4c4" },
water: { "fill-color": "#a3cedf" }, water: { "fill-color": "#a3cedf" },
park: { "fill-color": "#b3e378" }, // fill-outline-color isn't touched by a plain fill-color patch — Liberty
park_outline: { "line-color": "#546619" }, // draws it separately, defaulting to a bright green that reads as a
building: { "fill-color": "#ded7cc" }, // distinct border around named conservation areas (e.g. the Malé
// Karpaty CHKO). Matched to the fill itself, and park_outline's own
// dashed line hidden below, so a reserve blends in as ordinary forest —
// offline has no equivalent stroke at all (see park_a/park_b below),
// and the point was never to call reserves out as visibly different,
// on either side.
park: { "fill-color": "#b3e378", "fill-outline-color": "#b3e378" },
park_outline: { "line-opacity": 0 },
// fill-opacity: 0.5 matches the offline theme's own "buildings" layer —
// without it, Liberty's dense individual building footprints (each with
// its own outline) paint fully opaque and read much heavier/grayer than
// offline's softer, half-transparent fill over the same cream ground.
building: { "fill-color": "#ded7cc", "fill-opacity": 0.5 },
boundary_2: { "line-color": "#546619" }, boundary_2: { "line-color": "#546619" },
boundary_3: { "line-color": "#546619" }, boundary_3: { "line-color": "#546619" },
@@ -53,19 +75,30 @@ const ONLINE_STYLE_PATCH = {
// minor (residential/service/track), pedestrian — each repeated for its // minor (residential/service/track), pedestrian — each repeated for its
// tunnel_/bridge_ counterpart so a road doesn't change color when it // tunnel_/bridge_ counterpart so a road doesn't change color when it
// dips into a tunnel or crosses a bridge. Rail is left alone. // dips into a tunnel or crosses a bridge. Rail is left alone.
road_motorway: { "line-color": "#fdefbe" }, //
road_trunk_primary: { "line-color": "#fdefbe" }, // line-width below is a flat number, not Liberty's own zoom-interpolated
road_secondary_tertiary: { "line-color": "#fef7dd" }, // expression — picked to match the offline theme's actual rendered width
road_link: { "line-color": "#fef7dd" }, // at this app's default zoom (13; verified live via queryRenderedFeatures
road_motorway_link: { "line-color": "#fef7dd" }, // on both sides), since without it Liberty's own curve draws surface
// roads roughly twice as thick as offline at street level, reading as a
// much bolder road network online.
// ponytail: tuned for z13 only, not a matching curve across all zooms —
// will drift back apart at very different zoom levels. Upgrade path:
// sample offline's width at a few more zooms and replace with a matching
// ["interpolate", ["linear"], ["zoom"], ...] expression.
road_motorway: { "line-color": "#fdefbe", "line-width": 2.26 },
road_trunk_primary: { "line-color": "#fdefbe", "line-width": 2.26 },
road_secondary_tertiary: { "line-color": "#fef7dd", "line-width": 1.87 },
road_link: { "line-color": "#fef7dd", "line-width": 1 },
road_motorway_link: { "line-color": "#fef7dd", "line-width": 1 },
road_minor: { "line-color": "#fffdf8" }, road_minor: { "line-color": "#fffdf8" },
road_service_track: { "line-color": "#fffdf8" }, road_service_track: { "line-color": "#fffdf8" },
road_path_pedestrian: { "line-color": "#e9e2d8" }, road_path_pedestrian: { "line-color": "#e9e2d8" },
road_motorway_casing: { "line-color": "#c9a66b" }, road_motorway_casing: { "line-color": "#c9a66b", "line-width": 1.48 },
road_trunk_primary_casing: { "line-color": "#c9a66b" }, road_trunk_primary_casing: { "line-color": "#c9a66b", "line-width": 1.48 },
road_secondary_tertiary_casing: { "line-color": "#c9a66b" }, road_secondary_tertiary_casing: { "line-color": "#c9a66b", "line-width": 1 },
road_link_casing: { "line-color": "#c9a66b" }, road_link_casing: { "line-color": "#c9a66b", "line-width": 1.5 },
road_motorway_link_casing: { "line-color": "#c9a66b" }, road_motorway_link_casing: { "line-color": "#c9a66b", "line-width": 1.5 },
road_minor_casing: { "line-color": "#c9a66b" }, road_minor_casing: { "line-color": "#c9a66b" },
road_service_track_casing: { "line-color": "#c9a66b" }, road_service_track_casing: { "line-color": "#c9a66b" },
@@ -156,95 +189,45 @@ async function loadOnlineStyle() {
const ONLINE_STYLE = await loadOnlineStyle(); const ONLINE_STYLE = await loadOnlineStyle();
// A vendored copy of the same Liberty style ONLINE_STYLE fetches live
// (public/vendor/liberty-style/liberty.json — a point-in-time snapshot, not
// auto-updated) that offlineStyle() below patches+repoints the exact same
// way. Offline mode can't depend on ONLINE_STYLE_URL actually being
// reachable — that fetch failing/timing out is the normal case in the
// field, not an edge case — so this is a local, same-origin fetch instead
// (fast and always available, since it's served by this app itself).
const OFFLINE_STYLE_TEMPLATE = await fetch("/vendor/liberty-style/liberty.json").then((response) => response.json());
const protocol = new pmtiles.Protocol(); const protocol = new pmtiles.Protocol();
addProtocol("pmtiles", protocol.tile); addProtocol("pmtiles", protocol.tile);
// Nudged from protomaps-themes-base's stock "light" theme towards the // Builds the offline style from OFFLINE_STYLE_TEMPLATE — the identical
// National Park Service's own "Park Tiles" cartography — a warm, // Liberty JSON + ONLINE_STYLE_PATCH recolor as the online map, just
// Harpers-Ferry-Center-derived look. Not their actual map: a handful of // repointed at a local PMTiles source instead of tiles.openfreemap.org.
// values below (marked) are the genuine paint colors pulled from a public // This works because data/offline.pmtiles is now built by Planetiler's own
// Park Tiles style JSON // OpenMapTiles profile (see docs/development.adoc), the same vector schema
// (nps.gov/lib/npmap.js/style/ck72fwp2642dv07o7tbqinvz4.json, the "Imagery" // Liberty expects — before that, offline tiles used a different schema
// variant — the only one of their four styles served from a plain, // (protomaps' own basemaps) needing a completely separate hand-tuned
// unauthenticated URL; "Standard"/"Slate"/"Light" resolve through Mapbox // theme (protomaps-themes-base + OFFLINE_THEME) that could never be made
// Studio's private API with an access token, which isn't something to // to match ONLINE_STYLE_PATCH's look exactly, no matter how much either
// piggyback on even though it's technically visible in their own JS bundle). // side got tuned.
// The rest are reasoned to match that same family (warm cream ground, olive
// greens, muted blue) rather than sourced. Not a full recolor: labels,
// casings, and roles with no clean real-color anchor are left at theme
// defaults.
// //
// Recreating the color choices is legitimate — that's not the kind of thing // glyphs/sprite point at vendored local copies (public/vendor/fonts,
// a data license restricts (see docs/architecture.adoc's "Offline maps" // public/vendor/liberty-sprite) rather than tiles.openfreemap.org's —
// section) — what stays off-limits is their actual tile *service*: its // glyphs are Latin-only (see docs/architecture.adoc: labels in other
// OSM/terrain layers are licensed through Mapbox Atlas, a commercial, // scripts won't render offline), sprite is a one-time snapshot like
// non-sublicensable data service scoped to NPS. // OFFLINE_STYLE_TEMPLATE itself. ne2_shaded (Liberty's low-zoom shaded-
const OFFLINE_THEME = { // relief backdrop, z0-6 only) is left pointing at its remote URL
...protomaps_themes_base.namedTheme("light"), // unchanged — offline usage is regional, not whole-earth zoomed out, so
background: "#f9f6ef", // real: Park Tiles' own background, hsl(40, 37%, 97%) // this only ever silently fails to load at a zoom level offline users
earth: "#f9f6ef", // aren't in, the same graceful-degradation story as this app's other
water: "#a3cedf", // online-only extras (Wikipedia, live radar).
// Matches OpenFreeMap Liberty's own wood/grass green (its landcover_wood
// hsla(98,61%,72%,0.7) and landcover_grass rgba(176,213,154,1) at 0.3
// opacity, blended over the cream background) — the online map's actual
// look whenever ONLINE_STYLE_PATCH's brown/khaki recolor fails to apply
// (see loadOnlineStyle's fetch fallback) turned out to be the look this
// app's users actually want, so offline was changed to match it instead
// of chasing the patch's own reliability.
wood_a: "#c3e8ab",
wood_b: "#a8d888",
scrub_a: "#dcecc9",
scrub_b: "#cfe3b8",
// Close to wood_b, not the more saturated Park Tiles green: protomaps'
// theme routes "forest"/"nature_reserve"/"protected_area" (e.g. the Malé
// Karpaty CHKO boundary) through this same park_a/park_b pair as actual
// named parks — Liberty's online style doesn't make that reserve-boundary
// distinction at all, so a visibly different green here reads as an
// offline-only blotch rather than a deliberate distinction.
park_a: "#c3e8ab",
park_b: "#a8d888",
sand: "#f0e4c4",
beach: "#f0e4c4",
buildings: "#ded7cc",
pedestrian: "#e9e2d8",
highway: "#fdefbe", // real: Park Tiles' primary/highway road color
major: "#fef7dd", // real: Park Tiles' secondary road color
// "minor" (singular) is never actually read by protomaps' own paint
// expressions — only the zoom-interpolated minor_a/minor_b pair is, so a
// plain "minor" key here was dead: ordinary streets were silently
// falling back to the base theme's default pale yellow instead of this
// app's cream.
minor_a: "#fffdf8",
minor_b: "#fffdf8",
link: "#fef7dd",
// Distinct brown, not cream: protomaps' "other"/"path" kind is what a
// camper actually needs called out — unpaved tracks and footpaths,
// separate from paved minor_road/service (minor_service, left at the
// base theme's default since it's real driveways/parking aisles, not
// unpaved). Already rendered dashed by the theme itself; this just picks
// a real "dirt" tone instead of unstyled white.
other: "#c9a66b",
boundaries: "#546619", // real: Park Tiles' park-boundary line color
};
function offlineStyle() { function offlineStyle() {
const pmtilesUrl = `${window.location.origin}/tiles/offline.pmtiles`; const style = patchOnlineStyle(structuredClone(OFFLINE_STYLE_TEMPLATE));
style.sources.openmaptiles.url = `pmtiles://${window.location.origin}/tiles/offline.pmtiles`;
return { style.glyphs = `${window.location.origin}/vendor/fonts/{fontstack}/{range}.pbf`;
version: 8, style.sprite = `${window.location.origin}/vendor/liberty-sprite/ofm`;
glyphs: `${window.location.origin}/vendor/fonts/{fontstack}/{range}.pbf`, return style;
sources: {
offline: {
type: "vector",
url: `pmtiles://${pmtilesUrl}`,
attribution: "&copy; OpenStreetMap contributors",
},
},
// lang: "en" pulls in labels_layers (see docs/architecture.adoc) — only
// the Latin-script glyph ranges are vendored, so labels using other
// scripts won't render offline.
layers: protomaps_themes_base.layers("offline", OFFLINE_THEME, { lang: "en" }),
};
} }
// A sidebar icon that opens a full-height side panel (like the GPX one) // A sidebar icon that opens a full-height side panel (like the GPX one)
@@ -307,100 +290,6 @@ class LayerToggleControl {
} }
} }
const HILLSHADE_ID = "hillshade-dem";
const COLOR_RELIEF_ID = "elevation-tint";
// Hypsometric tint reusing this app's own palette (wood_a's green at
// valley floor, the road casing brown through the mid-slopes) rather than
// a generic rainbow ramp, so it reads as part of the same map rather than
// a bolted-on overlay. Stops picked for Central European terrain — the
// Tatras top out around 2600m — not a general-purpose world ramp.
const ELEVATION_COLOR_RAMP = [
"interpolate",
["linear"],
["raster-value"],
0, "#c3e8ab",
400, "#dcd08f",
900, "#c9a66b",
1600, "#a89a86",
2600, "#f9f6ef",
];
// Public, unauthenticated, no API key — the same open (SRTM/ArcticDEM-derived)
// elevation tiles OpenStreetMap's own hillshade layer and many other free
// tools use. Only reachable online; while the offline basemap is active this
// is skipped in favor of a local terrain.pmtiles if one's been generated
// (see docs/development.adoc), same optional-local-file story as
// offline.pmtiles itself.
const ONLINE_TERRAIN_TILES = ["https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png"];
// A simple on/off sidebar toggle, not a panel — there's nothing to choose,
// just whether the shading shows.
class HillshadeControl {
constructor(map) {
this._map = map;
this._active = false;
this._offlineAvailable = false;
// setStyle() (switching Online/Offline) tears down all custom
// sources/layers — put hillshade back if it was on.
map.on("style.load", () => {
if (this._active) this._addLayer();
});
}
mount(sidebar) {
this._container = document.createElement("div");
this._container.className = "sidebar-item";
this._container.innerHTML = `<button type="button" class="sidebar-icon" title="Terrain shading" aria-label="Terrain shading" aria-pressed="false">${HILLSHADE_ICON}</button>`;
this._button = this._container.querySelector(".sidebar-icon");
this._button.addEventListener("click", () => this._toggle());
sidebar.appendChild(this._container);
}
setOfflineAvailable(available) {
this._offlineAvailable = available;
}
_toggle() {
this._active = !this._active;
this._button.classList.toggle("active", this._active);
this._button.setAttribute("aria-pressed", String(this._active));
if (this._active) this._addLayer();
else this._removeLayer();
}
_addLayer() {
if (this._map.getSource(HILLSHADE_ID)) return;
const source = this._offlineAvailable
? { type: "raster-dem", url: `pmtiles://${window.location.origin}/tiles/terrain.pmtiles`, encoding: "terrarium" }
: {
type: "raster-dem",
tiles: ONLINE_TERRAIN_TILES,
tileSize: 256,
encoding: "terrarium",
maxzoom: 15,
attribution: "Terrain tiles: Mapzen, SRTM, ArcticDEM",
};
this._map.addSource(HILLSHADE_ID, source);
// Elevation tint under, hillshade on top: the tint sets the base color
// per elevation band, hillshade multiplies slope-shading over it — the
// combined "characteristic relief look" the TODO asked for, not two
// independent layers.
this._map.addLayer({
id: COLOR_RELIEF_ID,
type: "color-relief",
source: HILLSHADE_ID,
paint: { "color-relief-color": ELEVATION_COLOR_RAMP, "color-relief-opacity": 0.7 },
});
this._map.addLayer({ id: HILLSHADE_ID, type: "hillshade", source: HILLSHADE_ID, paint: { "hillshade-exaggeration": 0.4 } });
}
_removeLayer() {
if (this._map.getLayer(HILLSHADE_ID)) this._map.removeLayer(HILLSHADE_ID);
if (this._map.getLayer(COLOR_RELIEF_ID)) this._map.removeLayer(COLOR_RELIEF_ID);
if (this._map.getSource(HILLSHADE_ID)) this._map.removeSource(HILLSHADE_ID);
}
}
// A small map-corner button (grouped with Home/zoom, see below) that's a // A small map-corner button (grouped with Home/zoom, see below) that's a
// second entry point to the same panel LayerToggleControl already manages // second entry point to the same panel LayerToggleControl already manages
// in the page's own sidebar — matching the National Park Service's own // in the page's own sidebar — matching the National Park Service's own
@@ -466,6 +355,65 @@ class ZoomLevelControl {
} }
} }
// Tilts the camera between a flat top-down view and a fixed 3D-perspective
// pitch — bearing stays untouched (this map never rotates, see the
// NavigationControl comment below), so this is purely "look at it from an
// angle", not a rotate/compass control. Independent of the "Terrain
// shading" overlay toggle (overlays.js) — that adds a raster-dem hillshade/
// color-relief layer, this just moves the camera; combining both gives a
// real sense of relief but neither depends on the other.
const PITCH_3D = 60;
class PitchToggleControl {
onAdd(map) {
this._map = map;
this._container = document.createElement("div");
this._container.className = "maplibregl-ctrl maplibregl-ctrl-group pitch-toggle-ctrl";
this._button = document.createElement("button");
this._button.type = "button";
this._button.className = "pitch-toggle-ctrl__button";
this._button.addEventListener("click", () => this._toggle());
this._container.appendChild(this._button);
this._update = () => this._render();
map.on("pitchend", this._update);
this._render();
return this._container;
}
onRemove() {
this._map.off("pitchend", this._update);
this._container.remove();
}
getDefaultPosition() {
return "top-left";
}
// Set once overlaysControl exists (it's built later in this file) —
// lets raised terrain (OverlaysControl.syncTerrain, see overlays.js)
// follow the pitch toggle without this control needing to know anything
// about hillshade/DEM sources itself.
setOverlaysControl(overlaysControl) {
this._overlaysControl = overlaysControl;
this._overlaysControl.syncTerrain(this._map.getPitch() > 0);
}
_toggle() {
this._map.easeTo({ pitch: this._map.getPitch() > 0 ? 0 : PITCH_3D, duration: 300 });
}
_render() {
const is3d = this._map.getPitch() > 0;
this._button.textContent = is3d ? "2D" : "3D";
this._button.title = is3d ? "Switch to 2D view" : "Switch to 3D view";
this._button.setAttribute("aria-label", this._button.title);
this._button.classList.toggle("active", is3d);
this._overlaysControl?.syncTerrain(is3d);
}
}
const map = new MaplibreMap({ const map = new MaplibreMap({
container: "map", container: "map",
style: ONLINE_STYLE, style: ONLINE_STYLE,
@@ -496,11 +444,14 @@ const SLOVAKIA_BOUNDS = [
[16.83, 47.73], [16.83, 47.73],
[22.57, 49.61], [22.57, 49.61],
]; ];
map.addControl(new SearchControl(), "top-left");
map.addControl(new HomeButton({ bounds: SLOVAKIA_BOUNDS }), "top-left"); map.addControl(new HomeButton({ bounds: SLOVAKIA_BOUNDS }), "top-left");
// showCompass: false — this map never rotates, so a bearing-reset button // showCompass: false — this map never rotates, so a bearing-reset button
// (NavigationControl's default third button) would just be dead weight. // (NavigationControl's default third button) would just be dead weight.
map.addControl(new NavigationControl({ showCompass: false }), "top-left"); map.addControl(new NavigationControl({ showCompass: false }), "top-left");
map.addControl(new ZoomLevelControl(), "top-left"); map.addControl(new ZoomLevelControl(), "top-left");
const pitchToggle = new PitchToggleControl();
map.addControl(pitchToggle, "top-left");
map.addControl(new MeasureControl(), "top-left"); map.addControl(new MeasureControl(), "top-left");
// Writing a note needs a login (POST /api/gpx/notes) — no point adding a // Writing a note needs a login (POST /api/gpx/notes) — no point adding a
// button that can only ever end in a 401 for a logged-out viewer, same // button that can only ever end in a 401 for a logged-out viewer, same
@@ -519,6 +470,7 @@ const gnssControl = new GnssControl(map);
// the "GNSS" sidebar icon actually turns it on — not just whenever a // the "GNSS" sidebar icon actually turns it on — not just whenever a
// receiver happens to have a fix. See locate.js. // receiver happens to have a fix. See locate.js.
map.addControl(new LocateControl(gnssControl), "top-left"); map.addControl(new LocateControl(gnssControl), "top-left");
map.addControl(new ScaleControl({ unit: "metric" }), "bottom-left");
// A small inset map showing where the current view sits in context — NPS's // A small inset map showing where the current view sits in context — NPS's
// own overview plugin (docs/nps-resources.adoc's "overview" entry, still on // own overview plugin (docs/nps-resources.adoc's "overview" entry, still on
@@ -538,11 +490,50 @@ map.once("style.load", () => {
const coordsLabel = document.querySelector(".topbar__coords"); const coordsLabel = document.querySelector(".topbar__coords");
const updateCoords = () => { const updateCoords = () => {
const { lng, lat } = map.getCenter(); const { lng, lat } = map.getCenter();
coordsLabel.textContent = `${lat.toFixed(5)}, ${lng.toFixed(5)}`; coordsLabel.innerHTML = `<span class="topbar__icon">${WAYPOINT_ICON}</span><span>${formatCoords(lat, lng)}</span>`;
}; };
updateCoords(); updateCoords();
map.on("move", updateCoords); map.on("move", updateCoords);
// Plain decimal degrees, not the DMS text actually shown — that's what
// pastes cleanly into another map/GPS app, which is the whole point of
// copying a coordinate in the first place.
coordsLabel.title = "Click to copy coordinates";
coordsLabel.addEventListener("click", async () => {
const { lng, lat } = map.getCenter();
try {
await navigator.clipboard.writeText(`${lat.toFixed(6)}, ${lng.toFixed(6)}`);
} catch {
return; // clipboard API unavailable (e.g. an insecure context) — nothing to fall back to
}
coordsLabel.textContent = "Copied!";
setTimeout(updateCoords, 1000);
});
// Sunrise/sunset for the same center point the coords above already show —
// on moveend (not every "move" frame, unlike updateCoords: the sun position
// barely moves between two nearby spots, not worth recomputing constantly)
// plus a periodic tick so the "Xh Ym to sunset" countdown keeps counting
// down even while the map sits still.
const sunLabel = document.querySelector(".topbar__sun");
const updateSun = () => {
const { lng, lat } = map.getCenter();
const info = formatSunInfo(lat, lng);
sunLabel.hidden = info === null;
if (!info) return;
const countdownGroup = info.countdown
? `<span class="topbar__group"><span class="topbar__icon">${PENDING_ICON}</span><span>${info.countdown}</span></span>`
: "";
sunLabel.innerHTML =
`<span class="topbar__group"><span class="topbar__icon">${SUNRISE_ICON}</span><span>${info.sunrise}</span></span>` +
`<span class="topbar__group"><span class="topbar__icon">${SUNSET_ICON}</span><span>${info.sunset}</span></span>` +
countdownGroup;
};
updateSun();
map.on("moveend", updateSun);
setInterval(updateSun, 60000);
const sidebar = document.getElementById("sidebar"); const sidebar = document.getElementById("sidebar");
// Grouped into the TODO's planned 4-module menu (Explorer / Offline hub / // Grouped into the TODO's planned 4-module menu (Explorer / Offline hub /
@@ -555,13 +546,17 @@ profilePanel.mount();
sidebar.insertAdjacentHTML("beforeend", `<div class="sidebar-group-label" title="Explorer"></div>`); sidebar.insertAdjacentHTML("beforeend", `<div class="sidebar-group-label" title="Explorer"></div>`);
new GpxPanelControl(map, profilePanel).mount(sidebar); new GpxPanelControl(map, profilePanel).mount(sidebar);
const hillshadeControl = new HillshadeControl(map); const overlaysControl = new OverlaysControl(map);
hillshadeControl.mount(sidebar); overlaysControl.mount(sidebar);
pitchToggle.setOverlaysControl(overlaysControl);
// Running a plugin needs a login (POST /api/plugins/:name/run) — same
// "hide the write-only affordance" story as NotesControl above.
if (isLoggedIn()) new PluginsControl(map).mount(sidebar);
sidebar.insertAdjacentHTML("beforeend", `<div class="sidebar-group-label" title="Offline hub"></div>`); sidebar.insertAdjacentHTML("beforeend", `<div class="sidebar-group-label" title="Offline hub"></div>`);
layerToggle.mount(sidebar); layerToggle.mount(sidebar);
layerToggle.setActive("online"); layerToggle.setActive("online");
new RadarControl(map).mount(sidebar); new OfflineDataControl().mount(sidebar);
sidebar.insertAdjacentHTML("beforeend", `<div class="sidebar-group-label" title="Navigation"></div>`); sidebar.insertAdjacentHTML("beforeend", `<div class="sidebar-group-label" title="Navigation"></div>`);
gnssControl.mount(sidebar); gnssControl.mount(sidebar);
@@ -606,7 +601,20 @@ fetch("/api/offline-tiles")
fetch("/api/terrain-tiles") fetch("/api/terrain-tiles")
.then((response) => response.json()) .then((response) => response.json())
.then(({ available }) => hillshadeControl.setOfflineAvailable(available)) .then(({ available }) => {
overlaysControl.setHillshadeOfflineAvailable(available);
overlaysControl.setShadowOfflineAvailable(available);
})
.catch(() => {});
fetch("/api/hiking-trails")
.then((response) => response.json())
.then(({ countries }) => overlaysControl.setHikingTrailsOfflineCountries(countries))
.catch(() => {});
fetch("/api/kiwix")
.then((response) => response.json())
.then(({ available }) => overlaysControl.setWikiAvailable(available))
.catch(() => {}); .catch(() => {});
// Alt+click anywhere shows every rendered feature at that point — base map // Alt+click anywhere shows every rendered feature at that point — base map
+5 -2
View File
@@ -317,7 +317,9 @@ function haversine([lng1, lat1], [lng2, lat2]) {
return 2 * EARTH_RADIUS_M * Math.asin(Math.sqrt(a)); return 2 * EARTH_RADIUS_M * Math.asin(Math.sqrt(a));
} }
function lineLength(points) { // Exported — also used by hiking_trails.js to total up an OSM route
// relation's member ways into one distance, same haversine-sum approach.
export function lineLength(points) {
let total = 0; let total = 0;
for (let i = 1; i < points.length; i++) total += haversine(points[i - 1], points[i]); for (let i = 1; i < points.length; i++) total += haversine(points[i - 1], points[i]);
return total; return total;
@@ -347,7 +349,8 @@ function polygonArea(points) {
return Math.abs((area * EARTH_RADIUS_M * EARTH_RADIUS_M) / 2); return Math.abs((area * EARTH_RADIUS_M * EARTH_RADIUS_M) / 2);
} }
function formatDistance(meters) { // Exported — also used by hiking_trails.js's route-details popup.
export function formatDistance(meters) {
if (meters === 0) return ""; if (meters === 0) return "";
return meters >= 1000 ? `${(meters / 1000).toFixed(2)} km` : `${Math.round(meters)} m`; return meters >= 1000 ? `${(meters / 1000).toFixed(2)} km` : `${Math.round(meters)} m`;
} }
+85 -6
View File
@@ -1,6 +1,33 @@
import { NOTE_PIN_ICON } from "/js/icons.js"; import { Marker } from "/vendor/maplibre-gl/maplibre-gl.mjs";
import { NOTE_PIN_ICON, POI_ICONS } from "/js/icons.js";
import { notifyGpxStoreChanged } from "/js/panels.js"; import { notifyGpxStoreChanged } from "/js/panels.js";
// Human labels for the icon picker's title attribute — POI_ICONS' own keys
// are internal (OSM-tag-shaped) ids, not display text.
const ICON_LABELS = {
amenity_parking: "Parking",
tourism_camp_site: "Camp site",
leisure_picnic_table: "Picnic table",
amenity_fuel: "Fuel",
tourism_hotel: "Lodging",
forest: "Forest",
sport_cycling: "Cycling",
amenity_drinking_water: "Drinking water",
amenity_sanitary_dump_station: "Dump station",
amenity_toilets: "Toilets",
shop_gas: "Gas/LPG refill",
amenity_electricity: "Electricity",
shop_laundry: "Laundry",
leisure_playground: "Playground",
tourism_viewpoint: "Viewpoint",
leisure_swimming: "Swimming",
leisure_fishing: "Fishing",
sport_climbing: "Climbing",
route_hiking: "Hiking",
shop_supermarket: "Supermarket",
shop_convenience: "Convenience store",
};
const NEW_LAYER_VALUE = "__new__"; const NEW_LAYER_VALUE = "__new__";
// Every hand-drawn note (from here or measure.js's "Save as note") gets one // Every hand-drawn note (from here or measure.js's "Save as note") gets one
@@ -20,15 +47,25 @@ export function generateNoteId() {
// container it's given (each caller owns where that sits in its own panel); // container it's given (each caller owns where that sits in its own panel);
// hidden until open() is called. // hidden until open() is called.
export class NoteSaveForm { export class NoteSaveForm {
constructor(container, { onSaved, onCancel } = {}) { constructor(container, { onSaved, onCancel, onIconChange } = {}) {
this._onSaved = onSaved; this._onSaved = onSaved;
this._onCancel = onCancel; this._onCancel = onCancel;
this._onIconChange = onIconChange;
this._el = document.createElement("div"); this._el = document.createElement("div");
this._el.className = "notes-panel__form"; this._el.className = "notes-panel__form";
this._el.hidden = true; this._el.hidden = true;
this._el.innerHTML = ` this._el.innerHTML = `
<input type="text" class="notes-panel__title" placeholder="Title"> <input type="text" class="notes-panel__title" placeholder="Title">
<div class="notes-panel__icons">
<button type="button" class="notes-panel__icon-option active" data-icon="" title="No icon">${NOTE_PIN_ICON}</button>
${Object.keys(POI_ICONS)
.map(
(key) =>
`<button type="button" class="notes-panel__icon-option" data-icon="${key}" title="${escapeAttr(ICON_LABELS[key] || key)}">${POI_ICONS[key]}</button>`,
)
.join("")}
</div>
<textarea class="notes-panel__body" rows="3" placeholder="Details (optional) — **bold**, *italic*, links"></textarea> <textarea class="notes-panel__body" rows="3" placeholder="Details (optional) — **bold**, *italic*, links"></textarea>
<select class="notes-panel__target"></select> <select class="notes-panel__target"></select>
<input type="text" class="notes-panel__new-name" placeholder="Layer name" hidden> <input type="text" class="notes-panel__new-name" placeholder="Layer name" hidden>
@@ -40,11 +77,20 @@ export class NoteSaveForm {
container.appendChild(this._el); container.appendChild(this._el);
this._title = this._el.querySelector(".notes-panel__title"); this._title = this._el.querySelector(".notes-panel__title");
this._iconPicker = this._el.querySelector(".notes-panel__icons");
this._body = this._el.querySelector(".notes-panel__body"); this._body = this._el.querySelector(".notes-panel__body");
this._target = this._el.querySelector(".notes-panel__target"); this._target = this._el.querySelector(".notes-panel__target");
this._newName = this._el.querySelector(".notes-panel__new-name"); this._newName = this._el.querySelector(".notes-panel__new-name");
this._saveButton = this._el.querySelector(".notes-panel__save"); this._saveButton = this._el.querySelector(".notes-panel__save");
this._selectedIcon = "";
this._iconPicker.querySelectorAll(".notes-panel__icon-option").forEach((button) => {
button.addEventListener("click", () => {
this._selectedIcon = button.dataset.icon;
this._iconPicker.querySelectorAll(".notes-panel__icon-option").forEach((b) => b.classList.toggle("active", b === button));
this._onIconChange?.(this._selectedIcon);
});
});
this._target.addEventListener("change", () => { this._target.addEventListener("change", () => {
this._newName.hidden = this._target.value !== NEW_LAYER_VALUE; this._newName.hidden = this._target.value !== NEW_LAYER_VALUE;
if (!this._newName.hidden) this._newName.focus(); if (!this._newName.hidden) this._newName.focus();
@@ -62,6 +108,13 @@ export class NoteSaveForm {
this._el.hidden = false; this._el.hidden = false;
this._title.value = ""; this._title.value = "";
this._body.value = ""; this._body.value = "";
this._selectedIcon = "";
this._iconPicker.querySelectorAll(".notes-panel__icon-option").forEach((b, i) => b.classList.toggle("active", i === 0));
this._onIconChange?.(this._selectedIcon);
// An icon only makes sense on a single point — Measure's "Save as
// note" can hand this a LineString/Polygon, which has no one spot for
// a badge glyph to sit at.
this._iconPicker.hidden = geometry.type !== "Point";
this._title.focus(); this._title.focus();
await this._populateTargets(); await this._populateTargets();
} }
@@ -112,6 +165,7 @@ export class NoteSaveForm {
category: "Note", category: "Note",
time: new Date().toISOString(), time: new Date().toISOString(),
...(details ? { description: details } : {}), ...(details ? { description: details } : {}),
...(this._selectedIcon ? { icon: this._selectedIcon } : {}),
}, },
geometry: this._geometry, geometry: this._geometry,
}; };
@@ -124,7 +178,8 @@ export class NoteSaveForm {
try { try {
const response = await fetch("/api/gpx/notes", { method: "POST", body: requestBody }); const response = await fetch("/api/gpx/notes", { method: "POST", body: requestBody });
if (!response.ok) throw new Error(`save failed: ${response.status}`); if (!response.ok) throw new Error(`save failed: ${response.status}`);
notifyGpxStoreChanged(); const { path } = await response.json();
notifyGpxStoreChanged(path);
this.close(); this.close();
this._onSaved?.(); this._onSaved?.();
} catch (err) { } catch (err) {
@@ -143,6 +198,7 @@ export class NoteSaveForm {
export class NotesControl { export class NotesControl {
constructor() { constructor() {
this._active = false; this._active = false;
this._marker = null; // where the pending note will land — visible until saved/cancelled
} }
onAdd(map) { onAdd(map) {
@@ -161,8 +217,19 @@ export class NotesControl {
this._hint = this._container.querySelector(".notes-panel__hint"); this._hint = this._container.querySelector(".notes-panel__hint");
this._form = new NoteSaveForm(this._panel, { this._form = new NoteSaveForm(this._panel, {
onSaved: () => (this._hint.hidden = false), onSaved: () => {
onCancel: () => (this._hint.hidden = false), this._hint.hidden = false;
this._removeMarker();
},
onCancel: () => {
this._hint.hidden = false;
this._removeMarker();
},
// Keeps the map preview in sync with the icon picker — it used to
// always show a plain red pin no matter which icon got picked.
onIconChange: (icon) => {
if (this._marker) this._marker.getElement().innerHTML = icon && POI_ICONS[icon] ? POI_ICONS[icon] : NOTE_PIN_ICON;
},
}); });
this._button.addEventListener("click", () => this._setActive(!this._active)); this._button.addEventListener("click", () => this._setActive(!this._active));
@@ -170,6 +237,10 @@ export class NotesControl {
this._onClick = (event) => { this._onClick = (event) => {
if (!this._active || this._form.isOpen) return; if (!this._active || this._form.isOpen) return;
this._hint.hidden = true; this._hint.hidden = true;
const el = document.createElement("div");
el.className = "notes-panel__preview-marker";
el.innerHTML = NOTE_PIN_ICON;
this._marker = new Marker({ element: el }).setLngLat(event.lngLat).addTo(this._map);
this._form.open({ type: "Point", coordinates: [event.lngLat.lng, event.lngLat.lat] }); this._form.open({ type: "Point", coordinates: [event.lngLat.lng, event.lngLat.lat] });
}; };
map.on("click", this._onClick); map.on("click", this._onClick);
@@ -177,6 +248,11 @@ export class NotesControl {
return this._container; return this._container;
} }
_removeMarker() {
this._marker?.remove();
this._marker = null;
}
onRemove() { onRemove() {
this._map.off("click", this._onClick); this._map.off("click", this._onClick);
this._container.remove(); this._container.remove();
@@ -191,7 +267,10 @@ export class NotesControl {
this._button.classList.toggle("active", active); this._button.classList.toggle("active", active);
this._panel.hidden = !active; this._panel.hidden = !active;
this._map.getCanvas().style.cursor = active ? "crosshair" : ""; this._map.getCanvas().style.cursor = active ? "crosshair" : "";
if (!active) this._form.close(); if (!active) {
this._form.close();
this._removeMarker();
}
} }
} }
+400
View File
@@ -0,0 +1,400 @@
import { OFFLINE_DATA_ICON } from "/js/icons.js";
import { notifySidePanelOpen, onlyOneSidePanelOpen } from "/js/panels.js";
import { isLoggedIn } from "/js/auth.js";
import { escapeHtml } from "/js/gpx.js";
const POLL_INTERVAL_MS = 3000;
function formatBytes(bytes) {
const mb = bytes / (1024 * 1024);
return mb >= 1024 ? `${(mb / 1024).toFixed(1)} GB` : `${mb.toFixed(1)} MB`;
}
function formatElapsed(ms) {
const totalSeconds = Math.max(0, Math.floor(ms / 1000));
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
return minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
}
// "Building…" alone gave no way to tell a slow build from a stuck one, or
// which of the current selection's sources it's actually working on right
// now — elapsed time answers "is it alive", status.step (see
// PmtilesBuilder.run_job) answers "doing what, and what's left".
function formatRunning(status) {
const elapsed = status.started_at ? ` (${formatElapsed(Date.now() - new Date(status.started_at).getTime())})` : "";
const step = status.step ? `: ${status.step}` : "";
return `Building…${elapsed}${step}`;
}
// Vendored square-cropped SVGs (public/vendor/flag-icons/, MIT, see
// docs/third-party-notices.adoc) rather than Unicode flag emoji — emoji
// are font glyphs, not shapes, so they can't be resized/bordered/muted to
// fit this app's own controlled, hand-drawn-icon look the way a real SVG
// can (same reasoning the topbar readout's icons already settled on
// earlier — see icons.js). Framed in a small rounded-square badge in the
// markup below, the same convention icons.js's MAP_MARKER_ICON already
// uses for framing a category glyph, rather than a new visual language.
function flagIconUrl(code) {
return `/vendor/flag-icons/1x1/${code.toLowerCase()}.svg`;
}
// meta.sources is one entry per country the current build covers (see
// lib/maptool/pmtiles_builder.rb) — listing the codes is more useful here
// than a count, since they're exactly what RegionPicker's checklist above
// already shows.
function formatOfflineMeta(meta) {
if (!meta) return "";
return ` · ${meta.sources.map((s) => s.code).join(", ")}`;
}
function formatTerrainMeta(meta) {
if (!meta) return "";
const count = meta.sources.length;
return ` · ${count} source${count === 1 ? "" : "s"}`;
}
// The checklist of selectable countries (GET /api/offline-regions) plus
// the "Apply changes" button that saves the ticked set (POST, same URL)
// and hands it off — doesn't trigger a build itself, OfflineDataControl
// does that across both files once the selection is saved.
class RegionPicker {
constructor(onApply) {
this._onApply = onApply;
}
async mount(container) {
const section = document.createElement("div");
section.className = "offline-data-panel__regions";
section.innerHTML = `
<p class="offline-data-panel__regions-label">Regions</p>
<ul class="offline-data-panel__region-list"><li class="offline-data-panel__region-status">Loading…</li></ul>
<button type="button" class="offline-data-panel__apply" hidden>Apply changes</button>
`;
this._list = section.querySelector(".offline-data-panel__region-list");
this._applyButton = section.querySelector(".offline-data-panel__apply");
// Viewing/ticking works for anyone; only saving needs a login — same
// finer-grained gating measure.js/gpx.js use for their own
// write-only affordances, rather than hiding this whole control.
this._applyButton.hidden = !isLoggedIn();
this._applyButton.addEventListener("click", () => this._apply());
container.appendChild(section);
let data;
let cache;
try {
[data, cache] = await Promise.all([
fetch("/api/offline-regions").then((r) => r.json()),
fetch("/api/offline-tiles/cache").then((r) => r.json()),
]);
} catch {
this._list.innerHTML = `<li class="offline-data-panel__region-status">Could not load the region list.</li>`;
return;
}
const selected = new Set(data.selected);
const cached = new Map(cache.extracts.map((e) => [e.code, e]));
this._list.innerHTML = data.available
.map((region) => {
const extract = cached.get(region.code);
// Downloaded-but-not-(yet)-built is a real state (ticked, not
// Applied yet) as is built-but-no-longer-selected (unticked since)
// — this badge reflects the cache on disk, independent of either.
const cacheInfo = extract
? `
<span class="offline-data-panel__cache-info">
${formatBytes(extract.size)}
${
isLoggedIn()
? `<button type="button" class="offline-data-panel__cache-delete" data-code="${escapeHtml(region.code)}" data-name="${escapeHtml(region.name)}" title="Delete downloaded data for ${escapeHtml(region.name)}">✕</button>`
: ""
}
</span>`
: "";
return `
<li>
<label>
<input type="checkbox" value="${escapeHtml(region.code)}" ${selected.has(region.code) ? "checked" : ""}>
<img class="offline-data-panel__flag" src="${flagIconUrl(region.code)}" alt="" width="18" height="18">
${escapeHtml(region.name)}
</label>
${cacheInfo}
</li>`;
})
.join("");
this._list.querySelectorAll(".offline-data-panel__cache-delete").forEach((button) => {
button.addEventListener("click", () => this._deleteCache(button));
});
}
// Removes just this row's cache badge on success, rather than re-fetching
// and re-rendering the whole list — that would also overwrite whatever
// unticked/ticked-but-not-yet-Applied state the user has pending.
async _deleteCache(button) {
const code = button.dataset.code;
if (!window.confirm(`Delete downloaded data for ${button.dataset.name}? This can't be undone.`)) return;
button.disabled = true;
try {
const response = await fetch(`/api/offline-tiles/cache/${code}`, { method: "DELETE" });
const data = await response.json().catch(() => ({}));
if (!response.ok) throw new Error(data.error || `could not delete: ${response.status}`);
} catch (err) {
window.alert(err.message);
button.disabled = false;
return;
}
button.closest(".offline-data-panel__cache-info").remove();
}
async _apply() {
const codes = [...this._list.querySelectorAll("input:checked")].map((el) => el.value);
const body = new URLSearchParams();
codes.forEach((code) => body.append("codes[]", code));
this._applyButton.disabled = true;
try {
const response = await fetch("/api/offline-regions", { method: "POST", body });
const data = await response.json().catch(() => ({}));
if (!response.ok) throw new Error(data.error || `could not save the selection: ${response.status}`);
} catch (err) {
window.alert(err.message);
return;
} finally {
this._applyButton.disabled = false;
}
this._onApply();
}
}
// One row of the Offline data panel — just a status readout for either
// offline.pmtiles or terrain.pmtiles, both driven by the same selection
// (RegionPicker above). Both files behave identically from here (same
// status/build/build-status/check-update endpoint shape, see
// lib/maptool/pmtiles_builder.rb), just against different URLs/labels and
// a different way of describing what was actually built (formatMeta), so
// one class covers both rather than writing the same fetch/poll logic
// twice.
class DataFileRow {
constructor({ label, statusUrl, deleteUrl, buildUrl, buildStatusUrl, checkUpdateUrl, formatMeta }) {
this._label = label;
this._statusUrl = statusUrl;
this._deleteUrl = deleteUrl;
this._buildUrl = buildUrl;
this._buildStatusUrl = buildStatusUrl;
this._checkUpdateUrl = checkUpdateUrl;
this._formatMeta = formatMeta;
}
mount(container) {
const row = document.createElement("div");
row.className = "offline-data-panel__row";
row.innerHTML = `
<div class="offline-data-panel__row-head">
<strong>${this._label}</strong>
<button type="button" class="offline-data-panel__delete" hidden>Delete</button>
</div>
<p class="offline-data-panel__status">Checking…</p>
`;
this._statusEl = row.querySelector(".offline-data-panel__status");
this._deleteButton = row.querySelector(".offline-data-panel__delete");
this._deleteButton.addEventListener("click", () => this._delete());
container.appendChild(row);
this._refreshStatus();
}
// Single place that writes to _statusEl, so the error styling (pre-wrap,
// scrollable, red — see style.css) never stays stuck on once a build's
// failure message has scrolled past into a normal status line.
_setStatus(text, isError = false) {
this._statusEl.textContent = text;
this._statusEl.classList.toggle("offline-data-panel__status--error", isError);
}
async _refreshStatus() {
let data;
try {
data = await (await fetch(this._statusUrl)).json();
} catch {
this._setStatus("Could not check status.");
return;
}
if (!data.available) {
this._setStatus("Not generated yet.");
this._deleteButton.hidden = true;
return;
}
const updated = new Date(data.mtime).toLocaleString([], { dateStyle: "short", timeStyle: "short" });
this._setStatus(`${formatBytes(data.size)} · updated ${updated}${this._formatMeta(data.meta)}`);
this._deleteButton.hidden = !isLoggedIn();
this._checkUpdate();
}
// Deletes the built file (and, for offline.pmtiles, its whole per-country
// download cache — see PmtilesBuilder.delete_offline_data) so the row
// goes back to "Not generated yet." — a manual way to reclaim space or
// force a completely fresh rebuild, since Apply alone never removes
// anything already on disk.
async _delete() {
if (!window.confirm(`Delete ${this._label.toLowerCase()}? This can't be undone.`)) return;
this._deleteButton.disabled = true;
try {
const response = await fetch(this._deleteUrl, { method: "DELETE" });
const data = await response.json().catch(() => ({}));
if (!response.ok) throw new Error(data.error || `could not delete: ${response.status}`);
} catch (err) {
window.alert(err.message);
return;
} finally {
this._deleteButton.disabled = false;
}
this._refreshStatus();
}
// Separate from _refreshStatus's own fetch (and only called once, right
// after — not polled): this one reaches an external service (Geofabrik
// or Mapterhorn's manifest, see lib/maptool/pmtiles_builder.rb), so it's
// kept off the hot status path
// and just silently skipped if it fails, same as everywhere else this
// app degrades gracefully when an optional network check doesn't answer.
async _checkUpdate() {
let data;
try {
data = await (await fetch(this._checkUpdateUrl)).json();
} catch {
return;
}
if (!data.update_available) return;
const badge = document.createElement("span");
badge.className = "offline-data-panel__update-badge";
badge.textContent = " · a newer version is available";
this._statusEl.appendChild(badge);
}
// Called by OfflineDataControl once RegionPicker's Apply has saved a
// new selection — not tied to a button of this row's own.
async triggerBuild() {
this._setStatus("Checking…");
try {
// false (not null/true — see offline_update_available? in
// pmtiles_builder.rb) means the just-saved selection matches what's
// already on disk byte-for-byte: same countries, nothing upstream
// changed. Rebuilding would just burn bandwidth/CPU to reproduce
// the same file, so skip it. null (never built, or can't tell)
// still falls through to building below.
const check = await (await fetch(this._checkUpdateUrl)).json();
if (check.update_available === false) {
this._refreshStatus();
return;
}
} catch {
// couldn't tell — fall through and build rather than silently skip
}
this._setStatus("Starting…");
try {
const response = await fetch(this._buildUrl, { method: "POST" });
const data = await response.json().catch(() => ({}));
if (!response.ok) throw new Error(data.error || `build failed: ${response.status}`);
} catch (err) {
this._setStatus(err.message, true);
return;
}
this._setStatus("Building…");
this._poll();
}
// Self-rescheduling setTimeout loop, same shape as livetrack.js's
// _scheduleRefresh — check status, only reschedule while still running.
_poll() {
setTimeout(async () => {
let status;
try {
status = await (await fetch(this._buildStatusUrl)).json();
} catch {
this._poll(); // transient failure — try again next tick
return;
}
if (status.state === "running") {
this._setStatus(formatRunning(status));
this._poll();
return;
}
if (status.state === "error") {
this._setStatus(`Build failed: ${status.message}`, true);
} else {
this._refreshStatus();
}
}, POLL_INTERVAL_MS);
}
}
// A sidebar panel wrapping the manual go-pmtiles workflow
// docs/development.adoc documents — a region picker (which countries
// should be available offline) plus, on "Apply changes", a rebuild of
// offline.pmtiles/terrain.pmtiles covering the whole current selection
// (see lib/maptool/pmtiles_builder.rb — there's no standalone per-country
// file to individually delete; "remove a country" and "refresh a
// country" are both just "change the selection, then Apply").
export class OfflineDataControl {
constructor() {
this._rows = [
new DataFileRow({
label: "Offline map data",
statusUrl: "/api/offline-tiles",
deleteUrl: "/api/offline-tiles",
buildUrl: "/api/offline-tiles/build",
buildStatusUrl: "/api/offline-tiles/build-status",
checkUpdateUrl: "/api/offline-tiles/check-update",
formatMeta: formatOfflineMeta,
}),
new DataFileRow({
label: "Offline terrain data",
statusUrl: "/api/terrain-tiles",
deleteUrl: "/api/terrain-tiles",
buildUrl: "/api/terrain-tiles/build",
buildStatusUrl: "/api/terrain-tiles/build-status",
checkUpdateUrl: "/api/terrain-tiles/check-update",
formatMeta: formatTerrainMeta,
}),
];
this._regionPicker = new RegionPicker(() => this._rows.forEach((row) => row.triggerBuild()));
}
mount(sidebar) {
this._container = document.createElement("div");
this._container.className = "sidebar-item";
this._container.innerHTML = `<button type="button" class="sidebar-icon" title="Offline data" aria-label="Offline data">${OFFLINE_DATA_ICON}</button>`;
this._icon = this._container.querySelector(".sidebar-icon");
this._icon.addEventListener("click", () => this._togglePanel());
this._panel = document.getElementById("offline-data-panel");
this._panel.querySelector(".basemap-panel__close").addEventListener("click", () => this._togglePanel(false));
const body = this._panel.querySelector(".offline-data-panel__body");
this._regionPicker.mount(body);
this._rows.forEach((row) => row.mount(body));
onlyOneSidePanelOpen(this._panel, () => this._icon.classList.remove("active"));
sidebar.appendChild(this._container);
}
_togglePanel(force) {
const open = force === undefined ? this._panel.hidden : force;
this._panel.hidden = !open;
this._icon.classList.toggle("active", open);
if (open) notifySidePanelOpen(this._panel);
}
}
+408
View File
@@ -0,0 +1,408 @@
import { Popup } from "/vendor/maplibre-gl/maplibre-gl.mjs";
import { OVERLAYS_ICON, WIKI_ICON, WILDERNESS_ICON, MAP_MARKER_ICON } from "/js/icons.js";
import { notifySidePanelOpen, onlyOneSidePanelOpen } from "/js/panels.js";
import { svgToImageData, badgeImageId, escapeHtml } from "/js/gpx.js";
import { RadarControl } from "/js/radar.js";
import { ShadowControl } from "/js/shadow.js";
import { ContourControl } from "/js/contour.js";
import { HikingTrailsControl } from "/js/hiking_trails.js";
const ICON_IMAGE_SIZE = 48; // rasterized once at this size, rendered much smaller by icon-size below
const ICON_SIZE = 0.3; // 48 * 0.3 = ~14px, sized to sit inside the marker badge below
const MARKER_SIZE = 0.55;
const WIKI_SOURCE_ID = "wiki-points";
const WIKI_ICON_ID = "wiki-icon";
const WIKI_BADGE_COLOR = "#795548";
const HILLSHADE_ID = "hillshade-dem";
const COLOR_RELIEF_ID = "elevation-tint";
// MapLibre's own default light ({anchor:"viewport", intensity:0.5,
// position:[1.15,210,30]}) sits the sun almost overhead (polar 30°) — fine
// for flat 2D, but it barely rakes across 3D terrain at all, which is
// most of why real relief still looked flat/washed out even once the mesh
// itself was raised. Lower polar angle = lower sun = longer, more visible
// slope shadows; azimuth 315 is the classic NW hillshade convention.
// anchor:"map" (not "viewport") keeps the sun fixed to geography rather
// than spinning with the camera as you look around a tilted view.
const TERRAIN_LIGHT = { anchor: "map", color: "#fff", intensity: 0.6, position: [1.5, 315, 65] };
const DEFAULT_LIGHT = { anchor: "viewport", color: "#fff", intensity: 0.5, position: [1.15, 210, 30] };
// Hypsometric tint reusing this app's own palette (wood_a's green at
// valley floor, the road casing brown through the mid-slopes) rather than
// a generic rainbow ramp, so it reads as part of the same map rather than
// a bolted-on overlay. Stops picked for Central European terrain — the
// Tatras top out around 2600m — not a general-purpose world ramp.
const ELEVATION_COLOR_RAMP = [
"interpolate",
["linear"],
["raster-value"],
0, "#c3e8ab",
400, "#dcd08f",
900, "#c9a66b",
1600, "#a89a86",
2600, "#f9f6ef",
];
// Public, unauthenticated, no API key — the same open (SRTM/ArcticDEM-derived)
// elevation tiles OpenStreetMap's own hillshade layer and many other free
// tools use. Only reachable online; while the offline basemap is active this
// is skipped in favor of a local terrain.pmtiles if one's been generated
// (see docs/development.adoc), same optional-local-file story as
// offline.pmtiles itself.
// Exported: dem.js's elevation lookups (shadow.js's raymarch) hit the same
// online tile source, rather than duplicating the URL template.
export const ONLINE_TERRAIN_TILES = ["https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png"];
// A plain on/off Overlays item — there's nothing to choose, just whether
// the shading shows, unlike Radar's expandable scrub/forecast.
class HillshadeControl {
constructor(map) {
this._map = map;
this._active = false;
this._offlineAvailable = false;
// setStyle() (switching Online/Offline) tears down all custom
// sources/layers — put hillshade back if it was on.
map.on("style.load", () => {
if (this._active) this._addLayer();
this.syncTerrain(this._map.getPitch() > 0);
});
}
mount(li) {
li.innerHTML = `
<label>
<input type="checkbox" class="overlays-panel__toggle">
<span class="overlays-panel__icon">${WILDERNESS_ICON}</span>
<span>Terrain shading</span>
</label>
`;
this._checkbox = li.querySelector(".overlays-panel__toggle");
this._checkbox.addEventListener("change", (event) => this._toggle(event.target.checked));
}
setOfflineAvailable(available) {
this._offlineAvailable = available;
}
_toggle(active) {
this._active = active;
// Clear first: setTerrain may still be pointing at HILLSHADE_ID from
// before, and removing that source out from under it is worth avoiding
// even for the instant before syncTerrain below re-evaluates it.
if (this._map.getTerrain()) this._map.setTerrain(null);
if (active) this._addLayer();
else this._removeLayer();
this.syncTerrain(this._map.getPitch() > 0);
}
// Real terrain displacement (map.setTerrain), not just the flat
// hillshade/color-relief paint above — called both when this checkbox
// changes and when the 3D pitch toggle changes (map.js's
// PitchToggleControl, via OverlaysControl.syncTerrain below), since
// showing raised terrain needs both "tilted enough to see it" and "the
// DEM source this checkbox controls is actually loaded".
syncTerrain(pitched) {
// setLight/setTerrain throw if the style isn't loaded yet — called
// synchronously from map.js's setOverlaysControl during page init,
// before the first style.load; that listener re-invokes this once it
// actually is loaded, so bailing here just skips the premature call.
if (!this._map.isStyleLoaded()) return;
const terrainOn = pitched && this._active && this._map.getSource(HILLSHADE_ID);
if (terrainOn) {
this._map.setTerrain({ source: HILLSHADE_ID, exaggeration: 3 });
} else if (this._map.getTerrain()) {
this._map.setTerrain(null);
}
this._map.setLight(terrainOn ? TERRAIN_LIGHT : DEFAULT_LIGHT);
// The raster hillshade layer fakes relief by shading a flat texture —
// once real 3D geometry is doing that job (with its own lit shading
// for free), the raster version just looks like a blurry, low-res
// texture pasted on top of it. It's the only way to suggest relief in
// flat 2D though, so only hide it once real terrain is actually up.
// The color-relief elevation tint stays regardless — that's
// colour-by-height information, not a shading trick.
if (this._map.getLayer(HILLSHADE_ID)) {
this._map.setLayoutProperty(HILLSHADE_ID, "visibility", terrainOn ? "none" : "visible");
}
}
_addLayer() {
if (this._map.getSource(HILLSHADE_ID)) return;
// terrain.pmtiles is built from Mapterhorn (mapterhorn.com — see
// lib/maptool/pmtiles_builder.rb) whether generated in-app or by hand
// (docs/development.adoc), so this credits them regardless of how it
// got there — their own site lists the full per-region source
// provenance (CC-BY-4.0 and similar), not practical to reproduce here.
const source = this._offlineAvailable
? {
type: "raster-dem",
url: `pmtiles://${window.location.origin}/tiles/terrain.pmtiles`,
encoding: "terrarium",
attribution: "Terrain: Mapterhorn",
}
: {
type: "raster-dem",
tiles: ONLINE_TERRAIN_TILES,
tileSize: 256,
encoding: "terrarium",
maxzoom: 15,
attribution: "Terrain tiles: Mapzen, SRTM, ArcticDEM",
};
this._map.addSource(HILLSHADE_ID, source);
// Elevation tint under, hillshade on top: the tint sets the base color
// per elevation band, hillshade multiplies slope-shading over it — the
// combined "characteristic relief look" the TODO asked for, not two
// independent layers.
this._map.addLayer({
id: COLOR_RELIEF_ID,
type: "color-relief",
source: HILLSHADE_ID,
paint: { "color-relief-color": ELEVATION_COLOR_RAMP, "color-relief-opacity": 0.7 },
});
this._map.addLayer({ id: HILLSHADE_ID, type: "hillshade", source: HILLSHADE_ID, paint: { "hillshade-exaggeration": 0.4 } });
}
_removeLayer() {
if (this._map.getLayer(HILLSHADE_ID)) this._map.removeLayer(HILLSHADE_ID);
if (this._map.getLayer(COLOR_RELIEF_ID)) this._map.removeLayer(COLOR_RELIEF_ID);
if (this._map.getSource(HILLSHADE_ID)) this._map.removeSource(HILLSHADE_ID);
}
}
// A sidebar side panel (same shell as LiveTrackPanelControl/#livetrack-panel)
// listing live map layers that aren't a base map or a Tracks & Points file —
// each one refetched/toggled live rather than something to add/remove/
// reorder, so this is a plain checklist, its items built here (like
// PluginsControl's own list) rather than as static markup. Radar and
// Terrain shading used to be their own separate sidebar icons; both moved
// here since neither has anything to "manage," just on/off (Radar's own
// scrub/forecast controls live behind expanding its item, not a factor in
// where it's mounted).
export class OverlaysControl {
constructor(map) {
this._map = map;
this._hillshade = new HillshadeControl(map);
this._radar = new RadarControl(map);
this._shadow = new ShadowControl(map);
this._contour = new ContourControl(map);
this._hikingTrails = new HikingTrailsControl(map);
this._wikiEnabled = false; // the checkbox's own state
this._wikiMoveHandler = null; // the moveend listener driving its live refetch, while enabled
this._wikiRequestSeq = 0; // ignores an in-flight refetch a newer one has already superseded
this._interactivityRegistered = false; // guards against double-registering the click/hover handlers below across enable/disable cycles
// setStyle() (switching the Online/Offline base map) tears down all
// custom sources/layers/images — put the wiki layer back afterwards,
// same as GpxPanelControl does for visible GPX files. Hillshade/Radar
// handle their own the same way, from their own constructors above.
map.on("style.load", () => {
if (this._wikiEnabled) this._addWikiLayers().then(() => this._refreshWikiLayer());
});
}
mount(sidebar) {
this._container = document.createElement("div");
this._container.className = "sidebar-item";
this._container.innerHTML = `<button type="button" class="sidebar-icon" title="Overlays" aria-label="Overlays">${OVERLAYS_ICON}</button>`;
this._icon = this._container.querySelector(".sidebar-icon");
this._icon.addEventListener("click", () => this._togglePanel());
this._panel = document.getElementById("overlays-panel");
this._panel
.querySelector(".basemap-panel__close")
.addEventListener("click", () => this._togglePanel(false));
const list = this._panel.querySelector(".overlays-panel__list");
list.innerHTML = `
<li class="overlays-panel__item"></li>
<li class="overlays-panel__item"></li>
<li class="overlays-panel__item overlays-panel__item--expandable"></li>
<li class="overlays-panel__item overlays-panel__item--expandable"></li>
<li class="overlays-panel__item"></li>
<li class="overlays-panel__item overlays-panel__item--expandable"></li>
`;
const [hillshadeItem, wikiItem, radarItem, shadowItem, contourItem, hikingTrailsItem] = list.children;
this._hillshade.mount(hillshadeItem);
this._mountWiki(wikiItem);
this._radar.mount(radarItem);
this._shadow.mount(shadowItem);
this._contour.mount(contourItem);
this._hikingTrails.mount(hikingTrailsItem);
onlyOneSidePanelOpen(this._panel, () => this._icon.classList.remove("active"));
sidebar.appendChild(this._container);
}
_togglePanel(force) {
const open = force === undefined ? this._panel.hidden : force;
this._panel.hidden = !open;
this._icon.classList.toggle("active", open);
if (open) notifySidePanelOpen(this._panel);
}
setHillshadeOfflineAvailable(available) {
this._hillshade.setOfflineAvailable(available);
}
setHikingTrailsOfflineCountries(countries) {
this._hikingTrails.setOfflineCountries(countries);
}
// Called by map.js's PitchToggleControl whenever the 3D pitch toggle
// changes, so raised terrain follows the camera tilt rather than needing
// the "Terrain shading" checkbox re-clicked to notice.
syncTerrain(pitched) {
this._hillshade.syncTerrain(pitched);
}
setShadowOfflineAvailable(available) {
this._shadow.setOfflineAvailable(available);
}
_mountWiki(li) {
li.innerHTML = `
<label>
<input type="checkbox" class="overlays-panel__toggle">
<span class="overlays-panel__icon">${WIKI_ICON}</span>
<span>Wikipedia</span>
</label>
`;
this._wikiItem = li;
this._wikiToggle = li.querySelector(".overlays-panel__toggle");
this._wikiToggle.addEventListener("change", (event) => {
if (event.target.checked) this._enableWikiLayer();
else this._disableWikiLayer();
});
}
// Called once map.js's one-time GET /api/kiwix check resolves — disables
// (rather than hides) the checkbox rather than the whole panel/icon,
// since the other overlays are still usable with no kiwix-serve
// configured at all.
setWikiAvailable(available) {
this._wikiToggle.disabled = !available;
if (!available) this._wikiItem.title = "No kiwix-serve configured";
}
async _enableWikiLayer() {
this._wikiEnabled = true;
await this._addWikiLayers();
this._wikiMoveHandler = () => this._refreshWikiLayer();
this._map.on("moveend", this._wikiMoveHandler);
this._refreshWikiLayer();
}
_disableWikiLayer() {
this._wikiEnabled = false;
if (this._wikiMoveHandler) {
this._map.off("moveend", this._wikiMoveHandler);
this._wikiMoveHandler = null;
}
this._removeWikiLayers();
}
async _registerWikiIcon() {
if (this._map.hasImage(WIKI_ICON_ID)) return;
const whiteSvg = WIKI_ICON.replace(/currentColor/g, "#fff");
const imageData = await svgToImageData(whiteSvg, ICON_IMAGE_SIZE);
if (!this._map.hasImage(WIKI_ICON_ID)) this._map.addImage(WIKI_ICON_ID, imageData);
}
// Same one-image-per-color story as gpx.js's own _registerBadgeColors,
// just for this layer's single fixed color rather than a set of them
// discovered from a file.
async _registerWikiBadge() {
const id = badgeImageId(WIKI_BADGE_COLOR);
if (this._map.hasImage(id)) return;
const coloredSvg = MAP_MARKER_ICON.replace(/currentColor/g, WIKI_BADGE_COLOR);
const imageData = await svgToImageData(coloredSvg, ICON_IMAGE_SIZE);
if (!this._map.hasImage(id)) this._map.addImage(id, imageData);
}
async _addWikiLayers() {
if (this._map.getSource(WIKI_SOURCE_ID)) return;
await Promise.all([this._registerWikiIcon(), this._registerWikiBadge()]);
if (this._map.getSource(WIKI_SOURCE_ID)) return; // style.load raced this while awaiting
this._map.addSource(WIKI_SOURCE_ID, { type: "geojson", data: { type: "FeatureCollection", features: [] } });
this._map.addLayer({
id: `${WIKI_SOURCE_ID}-badge`,
type: "symbol",
source: WIKI_SOURCE_ID,
layout: {
"icon-image": badgeImageId(WIKI_BADGE_COLOR),
"icon-size": MARKER_SIZE,
"icon-allow-overlap": true,
"icon-ignore-placement": true,
},
});
this._map.addLayer({
id: `${WIKI_SOURCE_ID}-icon`,
type: "symbol",
source: WIKI_SOURCE_ID,
layout: { "icon-image": WIKI_ICON_ID, "icon-size": ICON_SIZE, "icon-allow-overlap": true, "icon-ignore-placement": true },
});
this._registerWikiInteractivity(`${WIKI_SOURCE_ID}-badge`);
}
_removeWikiLayers() {
[`${WIKI_SOURCE_ID}-badge`, `${WIKI_SOURCE_ID}-icon`].forEach((layerId) => {
if (this._map.getLayer(layerId)) this._map.removeLayer(layerId);
});
if (this._map.getSource(WIKI_SOURCE_ID)) this._map.removeSource(WIKI_SOURCE_ID);
}
_registerWikiInteractivity(layerId) {
if (this._interactivityRegistered) return;
this._interactivityRegistered = true;
this._map.on("click", layerId, (event) => {
const feature = event.features[0];
if (!feature) return;
new Popup({ closeButton: true, maxWidth: "260px" }).setLngLat(event.lngLat).setHTML(wikiPopupHtml(feature.properties)).addTo(this._map);
});
this._map.on("mouseenter", layerId, () => {
this._map.getCanvas().style.cursor = "pointer";
});
this._map.on("mouseleave", layerId, () => {
this._map.getCanvas().style.cursor = "";
});
}
// seq guards against an out-of-order response — a fast second pan's
// fetch resolving before a slower first one's — overwriting newer data
// with stale data; not a full abort-in-flight setup, just the ordering
// guarantee this actually needs.
async _refreshWikiLayer() {
const seq = ++this._wikiRequestSeq;
const bounds = this._map.getBounds();
const params = new URLSearchParams({
south: bounds.getSouth(),
west: bounds.getWest(),
north: bounds.getNorth(),
east: bounds.getEast(),
});
let geojson;
try {
geojson = await (await fetch(`/api/kiwix/nearby?${params}`)).json();
} catch {
return;
}
if (seq !== this._wikiRequestSeq) return;
const source = this._map.getSource(WIKI_SOURCE_ID);
if (source) source.setData(geojson);
}
}
// properties come from GET /api/kiwix/nearby — kiwix-serve's own ZIM
// content, not an uploaded file, but still untrusted-by-convention like
// every other popup builder in this app (escaped all the same). link
// already carries the /kiwix prefix this app proxies (lib/maptool/kiwix.rb).
function wikiPopupHtml({ name, link }) {
const parts = [`<div class="gpx-popup__header"><strong>${escapeHtml(name)}</strong></div>`];
parts.push(`<p class="gpx-popup__wiki"><a href="${escapeHtml(link)}" target="_blank" rel="noopener noreferrer">Read on Wikipedia →</a></p>`);
return parts.join("");
}
+7 -4
View File
@@ -18,13 +18,16 @@ export function onlyOneSidePanelOpen(panel, onClosedByOther) {
// Lets a control that writes into the GPX store (e.g. notes.js saving a // Lets a control that writes into the GPX store (e.g. notes.js saving a
// drawn point) tell GpxPanelControl its tree is stale, without either one // drawn point) tell GpxPanelControl its tree is stale, without either one
// holding a reference to the other. // holding a reference to the other. path (the .geojson file just written
// to) lets the listener also auto-show that file instead of just refreshing
// the tree — the point/shape just saved is otherwise invisible until the
// user finds and checks it by hand.
const STORE_CHANGED_EVENT = "gpx-store-changed"; const STORE_CHANGED_EVENT = "gpx-store-changed";
export function notifyGpxStoreChanged() { export function notifyGpxStoreChanged(path) {
document.dispatchEvent(new CustomEvent(STORE_CHANGED_EVENT)); document.dispatchEvent(new CustomEvent(STORE_CHANGED_EVENT, { detail: path }));
} }
export function onGpxStoreChanged(callback) { export function onGpxStoreChanged(callback) {
document.addEventListener(STORE_CHANGED_EVENT, callback); document.addEventListener(STORE_CHANGED_EVENT, (event) => callback(event.detail));
} }
+107
View File
@@ -0,0 +1,107 @@
import { PLUGIN_ICON } from "/js/icons.js";
import { notifyGpxStoreChanged } from "/js/panels.js";
// A sidebar flyout listing whatever import plugins are on disk (see
// lib/maptool/plugins.rb for the contract) — each one just a "Run for
// this area" button using the current map viewport as the bbox, so there's
// no separate area-picker to build: pan/zoom to where you want, click Run.
// Only ever mounted when logged in (see map.js) — same "hide the
// write-only affordance" story as NotesControl, since the only thing this
// panel does is a login-gated write.
export class PluginsControl {
constructor(map) {
this._map = map;
}
mount(sidebar) {
this._container = document.createElement("div");
this._container.className = "sidebar-item";
this._container.innerHTML = `
<button type="button" class="sidebar-icon" title="Import plugins" aria-label="Import plugins">${PLUGIN_ICON}</button>
<div class="sidebar-flyout" hidden>
<p class="plugins-panel__hint">Runs for whatever area is currently on screen.</p>
<ul class="plugins-panel__list"></ul>
</div>
`;
this._icon = this._container.querySelector(".sidebar-icon");
this._flyout = this._container.querySelector(".sidebar-flyout");
this._list = this._container.querySelector(".plugins-panel__list");
this._icon.addEventListener("click", () => {
const opening = this._flyout.hidden;
this._flyout.hidden = !opening;
this._icon.classList.toggle("active", opening);
if (opening) this._loadPlugins();
});
sidebar.appendChild(this._container);
}
async _loadPlugins() {
this._list.innerHTML = `<li class="plugins-panel__empty">Loading…</li>`;
let plugins;
try {
plugins = await (await fetch("/api/plugins")).json();
} catch (err) {
this._list.innerHTML = `<li class="plugins-panel__empty">Could not load plugins</li>`;
return;
}
if (plugins.length === 0) {
this._list.innerHTML = `<li class="plugins-panel__empty">No plugins installed — see docs/development.adoc</li>`;
return;
}
this._list.innerHTML = "";
plugins.forEach((plugin) => this._list.appendChild(this._renderItem(plugin)));
}
_renderItem(plugin) {
const li = document.createElement("li");
li.className = "plugins-panel__item";
li.innerHTML = `
<span class="plugins-panel__label"></span>
<button type="button" class="plugins-panel__run">Run for this area</button>
<span class="plugins-panel__status"></span>
`;
li.querySelector(".plugins-panel__label").textContent = plugin.label;
const button = li.querySelector(".plugins-panel__run");
const status = li.querySelector(".plugins-panel__status");
button.addEventListener("click", () => this._run(plugin, button, status));
return li;
}
async _run(plugin, button, status) {
button.disabled = true;
status.textContent = "Running…";
try {
const bounds = this._map.getBounds();
const body = new URLSearchParams({
south: bounds.getSouth(),
west: bounds.getWest(),
north: bounds.getNorth(),
east: bounds.getEast(),
});
const response = await fetch(`/api/plugins/${encodeURIComponent(plugin.name)}/run`, { method: "POST", body });
// Every app.rb response on this route is JSON, success or error —
// the catch below is only for an infra-level failure in front of it
// (a proxy's own HTML error page, a dropped connection) that never
// reached app.rb at all.
const data = await response.json().catch(() => ({}));
if (!response.ok) throw new Error(data.error || `run failed: ${response.status}`);
notifyGpxStoreChanged(data.path);
status.textContent = "Done";
status.classList.remove("plugins-panel__status--error");
} catch (err) {
// Plugins::RunError's message (e.g. "plugin exited with status 1")
// reaches here as `data.error` above — nothing about a plugin run
// failure gets logged server-side (app.rb turns it into a plain 502
// JSON response, not an exception), so showing that message directly
// is the only way to see why, short of SSHing in to reproduce it.
status.textContent = err.message;
status.classList.add("plugins-panel__status--error");
} finally {
button.disabled = false;
}
}
}
+76 -33
View File
@@ -1,4 +1,4 @@
import { RADAR_ICON } from "/js/icons.js"; import { RADAR_CLOUD_ICON } from "/js/icons.js";
const RAINVIEWER_API = "https://api.rainviewer.com/public/weather-maps.json"; const RAINVIEWER_API = "https://api.rainviewer.com/public/weather-maps.json";
@@ -12,6 +12,7 @@ const RAINVIEWER_API = "https://api.rainviewer.com/public/weather-maps.json";
// radar animation above can't. // radar animation above can't.
const FORECAST_API = "https://api.open-meteo.com/v1/forecast"; const FORECAST_API = "https://api.open-meteo.com/v1/forecast";
const FORECAST_DAYS = 3; const FORECAST_DAYS = 3;
const HOURLY_FORECAST_COUNT = 8;
const FORECAST_CACHE_KEY = "maptool:forecast"; const FORECAST_CACHE_KEY = "maptool:forecast";
// A small subset of WMO weather codes (open-meteo's `weather_code`) mapped // A small subset of WMO weather codes (open-meteo's `weather_code`) mapped
@@ -30,6 +31,21 @@ function weatherEmoji(code) {
return WEATHER_EMOJI.find(([codes]) => codes.includes(code))?.[1] ?? "🌡️"; return WEATHER_EMOJI.find(([codes]) => codes.includes(code))?.[1] ?? "🌡️";
} }
// A rolling window from "now" rather than "rest of today" — the latter
// shrinks to nothing right before midnight and balloons to ~24 entries just
// after, for no good reason.
function nextHours(hourly, count) {
const now = new Date();
return hourly.time
.map((time, i) => ({
time,
code: hourly.weather_code[i],
temp: Math.round(hourly.temperature_2m[i]),
}))
.filter((hour) => new Date(hour.time) >= now)
.slice(0, count);
}
// Matches the default window used by github.com/jpettitt/weather-radar-card // Matches the default window used by github.com/jpettitt/weather-radar-card
// (60 minutes of history at RainViewer's native 10-minute cadence = 7 // (60 minutes of history at RainViewer's native 10-minute cadence = 7
// frames, the last one being "now"). // frames, the last one being "now").
@@ -39,10 +55,10 @@ const OPACITY = 0.7;
const ATTRIBUTION = const ATTRIBUTION =
'Weather data &copy; <a href="https://www.rainviewer.com" target="_blank">RainViewer</a>'; 'Weather data &copy; <a href="https://www.rainviewer.com" target="_blank">RainViewer</a>';
// A sidebar icon that fetches RainViewer's recent precipitation frames on // An Overlays panel item (see overlays.js) that fetches RainViewer's recent
// demand and animates them as a raster overlay, with play/pause and a scrub // precipitation frames on demand and animates them as a raster overlay,
// slider in a flyout. No API key needed — see docs/architecture.adoc for // with play/pause and a scrub slider revealed by expanding the item. No API
// RainViewer's usage terms. // key needed — see docs/architecture.adoc for RainViewer's usage terms.
export class RadarControl { export class RadarControl {
constructor(map) { constructor(map) {
this._map = map; this._map = map;
@@ -59,12 +75,19 @@ export class RadarControl {
}); });
} }
mount(sidebar) { // li: the <li class="overlays-panel__item"> this item owns (see
this._container = document.createElement("div"); // overlays.js) — built here rather than in the static markup since this
this._container.className = "sidebar-item"; // control is the only thing that knows its own internal structure
this._container.innerHTML = ` // (playback/forecast), same as before when it built its own sidebar
<button type="button" class="sidebar-icon" title="Radar" aria-label="Radar">${RADAR_ICON}</button> // flyout.
<div class="sidebar-flyout" hidden> mount(li) {
li.innerHTML = `
<div class="overlays-panel__row">
<input type="checkbox" class="overlays-panel__toggle">
<span class="overlays-panel__icon">${RADAR_CLOUD_ICON}</span>
<button type="button" class="overlays-panel__name">Radar</button>
</div>
<div class="overlays-panel__details" hidden>
<div class="radar-control__playback"> <div class="radar-control__playback">
<button type="button" class="radar-control__play" aria-label="Play">&#9654;</button> <button type="button" class="radar-control__play" aria-label="Play">&#9654;</button>
<input type="range" class="radar-control__scrub" min="0" max="0" step="1" value="0"> <input type="range" class="radar-control__scrub" min="0" max="0" step="1" value="0">
@@ -74,27 +97,34 @@ export class RadarControl {
</div> </div>
`; `;
this._icon = this._container.querySelector(".sidebar-icon"); this._checkbox = li.querySelector(".overlays-panel__toggle");
this._flyout = this._container.querySelector(".sidebar-flyout"); this._nameButton = li.querySelector(".overlays-panel__name");
this._playback = this._container.querySelector(".radar-control__playback"); this._details = li.querySelector(".overlays-panel__details");
this._playButton = this._container.querySelector(".radar-control__play"); this._playback = li.querySelector(".radar-control__playback");
this._scrub = this._container.querySelector(".radar-control__scrub"); this._playButton = li.querySelector(".radar-control__play");
this._time = this._container.querySelector(".radar-control__time"); this._scrub = li.querySelector(".radar-control__scrub");
this._forecastEl = this._container.querySelector(".radar-control__forecast"); this._time = li.querySelector(".radar-control__time");
this._forecastEl = li.querySelector(".radar-control__forecast");
this._icon.addEventListener("click", () => this._setEnabled(!this._enabled)); this._checkbox.addEventListener("change", (event) => this._setEnabled(event.target.checked));
// Separate from the checkbox on purpose — expanding to see the scrub/
// forecast shouldn't also flip the layer on, and turning the layer on
// shouldn't force the details open (a viewer who never cares to scrub
// history/see the forecast keeps a one-line item either way).
this._nameButton.addEventListener("click", () => {
const expanding = this._details.hidden;
this._details.hidden = !expanding;
this._nameButton.setAttribute("aria-expanded", String(expanding));
});
this._playButton.addEventListener("click", () => this._togglePlayback()); this._playButton.addEventListener("click", () => this._togglePlayback());
this._scrub.addEventListener("input", () => { this._scrub.addEventListener("input", () => {
this._stopAnimation(); this._stopAnimation();
this._showFrame(Number(this._scrub.value)); this._showFrame(Number(this._scrub.value));
}); });
sidebar.appendChild(this._container);
} }
async _setEnabled(enabled) { async _setEnabled(enabled) {
this._enabled = enabled; this._enabled = enabled;
this._icon.classList.toggle("active", enabled);
if (!enabled) { if (!enabled) {
this._stopAnimation(); this._stopAnimation();
this._removeLayers(); this._removeLayers();
@@ -104,15 +134,15 @@ export class RadarControl {
return; return;
} }
this._icon.disabled = true; this._checkbox.disabled = true;
// Independent fetches: RainViewer being unreachable shouldn't hide a // Independent fetches: RainViewer being unreachable shouldn't hide a
// forecast that Open-Meteo still answered, or vice versa — especially // forecast that Open-Meteo still answered, or vice versa — especially
// since only the forecast has a cached fallback to fall back to. // since only the forecast has a cached fallback to fall back to.
const [framesResult, forecastResult] = await Promise.allSettled([fetchFrames(), this._loadForecast()]); const [framesResult, forecastResult] = await Promise.allSettled([fetchFrames(), this._loadForecast()]);
this._icon.disabled = false; this._checkbox.disabled = false;
// The icon may have been clicked again (disabling) while the fetches // The checkbox may have been unchecked again (disabling) while the
// were in flight. // fetches were in flight.
if (!this._enabled) return; if (!this._enabled) return;
const frames = framesResult.status === "fulfilled" ? framesResult.value : []; const frames = framesResult.status === "fulfilled" ? framesResult.value : [];
@@ -123,7 +153,7 @@ export class RadarControl {
// own failure. // own failure.
if (frames.length === 0 && !forecast) { if (frames.length === 0 && !forecast) {
this._enabled = false; this._enabled = false;
this._icon.classList.remove("active"); this._checkbox.checked = false;
} else if (frames.length > 0) { } else if (frames.length > 0) {
this._frames = frames; this._frames = frames;
this._frameIndex = frames.length - 1; this._frameIndex = frames.length - 1;
@@ -166,7 +196,17 @@ export class RadarControl {
precip: data.daily.precipitation_probability_max[i], precip: data.daily.precipitation_probability_max[i],
})); }));
const rows = days const hourRows = nextHours(data.hourly, HOURLY_FORECAST_COUNT)
.map(
(hour) => `
<div class="radar-control__forecast-hour">
<span>${new Date(hour.time).toLocaleTimeString([], { hour: "2-digit" })}</span>
<span>${weatherEmoji(hour.code)}</span>
<span>${hour.temp}°</span>
</div>`,
)
.join("");
const dayRows = days
.map( .map(
(day) => ` (day) => `
<div class="radar-control__forecast-day"> <div class="radar-control__forecast-day">
@@ -180,7 +220,7 @@ export class RadarControl {
const staleNote = cachedAt const staleNote = cachedAt
? `<p class="radar-control__forecast-stale">Cached from ${new Date(cachedAt).toLocaleString([], { dateStyle: "short", timeStyle: "short" })}</p>` ? `<p class="radar-control__forecast-stale">Cached from ${new Date(cachedAt).toLocaleString([], { dateStyle: "short", timeStyle: "short" })}</p>`
: ""; : "";
this._forecastEl.innerHTML = rows + staleNote; this._forecastEl.innerHTML = `<div class="radar-control__forecast-hours">${hourRows}</div>` + dayRows + staleNote;
} }
_addLayers() { _addLayers() {
@@ -252,9 +292,6 @@ export class RadarControl {
} }
_updateFrameUI() { _updateFrameUI() {
// Shown whenever there's radar frames, a forecast, or both — either
// one on its own is still worth showing the flyout for.
this._flyout.hidden = !this._enabled;
this._playback.hidden = this._frames.length === 0; this._playback.hidden = this._frames.length === 0;
this._scrub.max = String(Math.max(0, this._frames.length - 1)); this._scrub.max = String(Math.max(0, this._frames.length - 1));
this._scrub.value = String(this._frameIndex); this._scrub.value = String(this._frameIndex);
@@ -288,6 +325,10 @@ async function fetchForecast(lat, lon) {
url.searchParams.set("latitude", lat); url.searchParams.set("latitude", lat);
url.searchParams.set("longitude", lon); url.searchParams.set("longitude", lon);
url.searchParams.set("daily", "weather_code,temperature_2m_max,temperature_2m_min,precipitation_probability_max"); url.searchParams.set("daily", "weather_code,temperature_2m_max,temperature_2m_min,precipitation_probability_max");
// Same call, same cached JSON (writeCachedForecast below) — the next-few-
// hours strip alongside the multi-day outlook rather than a second
// request/cache entry.
url.searchParams.set("hourly", "weather_code,temperature_2m");
url.searchParams.set("timezone", "auto"); url.searchParams.set("timezone", "auto");
url.searchParams.set("forecast_days", String(FORECAST_DAYS)); url.searchParams.set("forecast_days", String(FORECAST_DAYS));
const response = await fetch(url); const response = await fetch(url);
@@ -316,7 +357,9 @@ function readCachedForecast() {
} }
} }
function firstSymbolLayerId(map) { // Exported: contour.js's own contour-line layers want the same
// "sit above base fill/roads, below place labels" placement.
export function firstSymbolLayerId(map) {
const layers = map.getStyle()?.layers || []; const layers = map.getStyle()?.layers || [];
const symbolLayer = layers.find((layer) => layer.type === "symbol"); const symbolLayer = layers.find((layer) => layer.type === "symbol");
return symbolLayer ? symbolLayer.id : undefined; return symbolLayer ? symbolLayer.id : undefined;
+111
View File
@@ -0,0 +1,111 @@
import { SEARCH_ICON } from "/js/icons.js";
import { escapeHtml } from "/js/gpx.js";
const NOMINATIM_API = "https://nominatim.openstreetmap.org/search";
// "lat, lng" / "lat lng" decimal degrees — the same plain-text shape the
// topbar's own coordinate readout copies to the clipboard (map.js). Tried
// before hitting the geocoder, so pasting a coordinate pair jumps straight
// there with no network round-trip.
const COORD_PATTERN = /^\s*(-?\d+(?:\.\d+)?)\s*[, ]\s*(-?\d+(?:\.\d+)?)\s*$/;
// A place-name/coordinate search box, matching NPS's own Park Tiles viewer.
// Online only, like this app's other non-basemap online features (Radar,
// the Wikipedia layer) — no offline geocoding index to fall back to.
// Nominatim: OpenStreetMap's own geocoder, free, no API key, matching the
// online basemap's own OSM-derived style already used here.
export class SearchControl {
constructor() {
this._results = [];
}
onAdd(map) {
this._map = map;
this._container = document.createElement("div");
this._container.className = "maplibregl-ctrl maplibregl-ctrl-group search-ctrl";
this._container.innerHTML = `
<button type="button" class="search-ctrl__button" title="Search" aria-label="Search">${SEARCH_ICON}</button>
<div class="search-panel" hidden>
<form class="search-panel__form">
<input type="text" class="search-panel__input" placeholder="Search, or lat, lng">
</form>
<ul class="search-panel__results"></ul>
</div>
`;
this._button = this._container.querySelector(".search-ctrl__button");
this._panel = this._container.querySelector(".search-panel");
this._input = this._container.querySelector(".search-panel__input");
this._resultsEl = this._container.querySelector(".search-panel__results");
this._button.addEventListener("click", () => this._toggle());
this._container.querySelector(".search-panel__form").addEventListener("submit", (event) => {
event.preventDefault();
this._search();
});
return this._container;
}
onRemove() {
this._container.remove();
}
getDefaultPosition() {
return "top-left";
}
_toggle() {
const opening = this._panel.hidden;
this._panel.hidden = !opening;
this._button.classList.toggle("active", opening);
if (opening) this._input.focus();
}
async _search() {
const query = this._input.value.trim();
if (!query) return;
const coords = query.match(COORD_PATTERN);
if (coords) {
this._resultsEl.innerHTML = "";
this._jumpTo(Number(coords[1]), Number(coords[2]));
return;
}
this._resultsEl.innerHTML = `<li class="search-panel__status">Searching…</li>`;
let places;
try {
const url = new URL(NOMINATIM_API);
url.searchParams.set("q", query);
url.searchParams.set("format", "jsonv2");
url.searchParams.set("limit", "5");
places = await (await fetch(url)).json();
} catch {
this._resultsEl.innerHTML = `<li class="search-panel__status">Search unavailable — check your connection.</li>`;
return;
}
this._renderResults(places);
}
_renderResults(places) {
this._results = places;
if (places.length === 0) {
this._resultsEl.innerHTML = `<li class="search-panel__status">No results</li>`;
return;
}
this._resultsEl.innerHTML = places
.map((place, i) => `<li class="search-panel__result" data-index="${i}">${escapeHtml(place.display_name)}</li>`)
.join("");
this._resultsEl.querySelectorAll(".search-panel__result").forEach((el) => {
el.addEventListener("click", () => {
const place = this._results[Number(el.dataset.index)];
this._jumpTo(Number(place.lat), Number(place.lon));
});
});
}
_jumpTo(lat, lng) {
this._map.flyTo({ center: [lng, lat], zoom: Math.max(this._map.getZoom(), 14) });
this._panel.hidden = true;
this._button.classList.remove("active");
}
}
+237
View File
@@ -0,0 +1,237 @@
import { getPosition } from "/vendor/suncalc/suncalc.js";
import { elevationAt } from "/js/dem.js";
import { TERRAIN_SHADOW_ICON } from "/js/icons.js";
const MIN_ZOOM = 11; // below this, a screen is roughly the same scale as the 40km raymarch — "one screen, one shadow-casting neighborhood" stops holding
const GRID_COLS = 96;
const GRID_ROWS = 64;
const RAYMARCH_STEPS = 16;
const RAYMARCH_START_M = 150;
const RAYMARCH_MAX_M = 40000;
const RAYMARCH_RATIO = (RAYMARCH_MAX_M / RAYMARCH_START_M) ** (1 / (RAYMARCH_STEPS - 1)); // geometric spacing: dense near the point, coarse far out
const EARTH_RADIUS_M = 6371000;
const SHADOW_RGBA = [20, 20, 50, Math.round(0.45 * 255)];
const SLIDER_DEBOUNCE_MS = 300;
const IMAGE_SOURCE_ID = "terrain-shadow";
// An Overlays panel item (see overlays.js) shading the parts of the visible
// map currently blocked from the sun by surrounding terrain — offline
// equivalent of shademap.app, built on the same Terrarium DEM tiles
// HillshadeControl already renders (via dem.js) and the same sun-position
// math the toolbar readout uses (public/js/sun.js). No Web Worker: a
// recompute is dozens of small awaited fetches (mostly cache hits after the
// first pan), not sustained sync CPU work, so it already yields to the
// event loop on its own between grid rows without blocking a pan/zoom.
export class ShadowControl {
constructor(map) {
this._map = map;
this._enabled = false;
this._offlineAvailable = false;
this._seq = 0; // bumped on every recompute/disable so a superseded in-flight one (a fast second pan, or turning the layer off mid-compute) discards its result instead of overwriting newer data
this._moveHandler = null;
this._sliderMinutes = currentMinutesOfDay();
this._sliderTimer = null;
// setStyle() (switching Online/Offline) tears down all custom sources/
// layers — recompute puts the shadow layer back if it was on, same as
// every other Overlays control.
map.on("style.load", () => {
if (this._enabled) this._recompute();
});
}
mount(li) {
li.innerHTML = `
<div class="overlays-panel__row">
<input type="checkbox" class="overlays-panel__toggle">
<span class="overlays-panel__icon">${TERRAIN_SHADOW_ICON}</span>
<button type="button" class="overlays-panel__name">Terrain shadow</button>
</div>
<div class="overlays-panel__details" hidden>
<div class="shadow-control__time">
<input type="range" class="shadow-control__slider" min="0" max="1439" step="5" value="${this._sliderMinutes}">
<span class="shadow-control__clock">${formatMinutes(this._sliderMinutes)}</span>
</div>
<p class="shadow-control__hint" hidden>Zoom in further to compute terrain shadow.</p>
</div>
`;
this._checkbox = li.querySelector(".overlays-panel__toggle");
this._nameButton = li.querySelector(".overlays-panel__name");
this._details = li.querySelector(".overlays-panel__details");
this._slider = li.querySelector(".shadow-control__slider");
this._clock = li.querySelector(".shadow-control__clock");
this._hint = li.querySelector(".shadow-control__hint");
this._checkbox.addEventListener("change", (event) => this._setEnabled(event.target.checked));
this._nameButton.addEventListener("click", () => {
const expanding = this._details.hidden;
this._details.hidden = !expanding;
this._nameButton.setAttribute("aria-expanded", String(expanding));
});
this._slider.addEventListener("input", () => {
this._sliderMinutes = Number(this._slider.value);
this._clock.textContent = formatMinutes(this._sliderMinutes);
clearTimeout(this._sliderTimer);
this._sliderTimer = setTimeout(() => this._recompute(), SLIDER_DEBOUNCE_MS);
});
}
setOfflineAvailable(available) {
this._offlineAvailable = available;
}
_setEnabled(enabled) {
this._enabled = enabled;
if (enabled) {
this._moveHandler = () => this._recompute();
this._map.on("moveend", this._moveHandler);
this._recompute();
return;
}
this._seq++;
if (this._moveHandler) {
this._map.off("moveend", this._moveHandler);
this._moveHandler = null;
}
this._hint.hidden = true;
this._removeLayer();
}
async _recompute() {
const seq = ++this._seq;
if (this._map.getZoom() < MIN_ZOOM) {
this._hint.hidden = false;
this._removeLayer();
return;
}
this._hint.hidden = true;
const bounds = this._map.getBounds();
const center = this._map.getCenter();
const date = this._selectedDate();
// One sun position for the whole viewport — azimuth/altitude vary
// negligibly across it next to the raymarch's own 150m-step coarseness.
const sun = getPosition(date, center.lat, center.lng);
const west = bounds.getWest();
const east = bounds.getEast();
const south = bounds.getSouth();
const north = bounds.getNorth();
const canvas = document.createElement("canvas");
canvas.width = GRID_COLS;
canvas.height = GRID_ROWS;
const ctx = canvas.getContext("2d");
const imageData = ctx.createImageData(GRID_COLS, GRID_ROWS);
if (sun.altitude <= 0) {
// Sun's below the horizon everywhere in view — no point raymarching.
fillShadow(imageData);
} else {
for (let row = 0; row < GRID_ROWS; row++) {
const lat = north - ((row + 0.5) / GRID_ROWS) * (north - south);
const rowWork = [];
for (let col = 0; col < GRID_COLS; col++) {
const lng = west + ((col + 0.5) / GRID_COLS) * (east - west);
rowWork.push(
this._isShadowed(lng, lat, sun.azimuth, sun.altitude).then((shadowed) => setPixel(imageData, col, row, shadowed)),
);
}
await Promise.all(rowWork); // yields once per row, so a fast pan/zoom's newer recompute can cut in
if (seq !== this._seq) return;
}
}
ctx.putImageData(imageData, 0, 0);
if (seq !== this._seq) return;
this._publish(canvas.toDataURL(), bounds);
}
async _isShadowed(lng, lat, sunAzimuth, sunAltitude) {
const pointElev = await elevationAt(lng, lat, this._offlineAvailable);
if (pointElev === null) return false; // no DEM data here — render sunlit rather than guess
let dist = RAYMARCH_START_M;
const samples = [];
for (let i = 0; i < RAYMARCH_STEPS; i++) {
samples.push(this._horizonSample(lng, lat, pointElev, sunAzimuth, dist));
dist *= RAYMARCH_RATIO;
}
const angles = (await Promise.all(samples)).filter((a) => a !== null);
const horizonMax = angles.length ? Math.max(...angles) : -90;
return sunAltitude <= horizonMax;
}
async _horizonSample(lng, lat, pointElev, sunAzimuth, dist) {
const sample = destinationPoint(lng, lat, sunAzimuth, dist);
const sampleElev = await elevationAt(sample.lng, sample.lat, this._offlineAvailable);
if (sampleElev === null) return null;
const curvatureDrop = (dist * dist) / (2 * EARTH_RADIUS_M);
return (Math.atan2(sampleElev - pointElev - curvatureDrop, dist) * 180) / Math.PI;
}
_selectedDate() {
const date = new Date();
date.setHours(0, this._sliderMinutes, 0, 0);
return date;
}
// First image-source usage in this app — addSource/addLayer once, then
// updateImage on every later recompute rather than remove+re-add.
_publish(dataUrl, bounds) {
const coordinates = [
[bounds.getWest(), bounds.getNorth()],
[bounds.getEast(), bounds.getNorth()],
[bounds.getEast(), bounds.getSouth()],
[bounds.getWest(), bounds.getSouth()],
];
const source = this._map.getSource(IMAGE_SOURCE_ID);
if (source) {
source.updateImage({ url: dataUrl, coordinates });
} else {
this._map.addSource(IMAGE_SOURCE_ID, { type: "image", url: dataUrl, coordinates });
this._map.addLayer({ id: IMAGE_SOURCE_ID, type: "raster", source: IMAGE_SOURCE_ID });
}
}
_removeLayer() {
if (this._map.getLayer(IMAGE_SOURCE_ID)) this._map.removeLayer(IMAGE_SOURCE_ID);
if (this._map.getSource(IMAGE_SOURCE_ID)) this._map.removeSource(IMAGE_SOURCE_ID);
}
}
// Flat-earth destination point (bearing/distance -> lng/lat) — fine under
// 40km, and nothing in this codebase already does lng/lat offset math.
function destinationPoint(lng, lat, bearingDeg, distanceM) {
const bearing = (bearingDeg * Math.PI) / 180;
const latRad = (lat * Math.PI) / 180;
const dLat = (distanceM * Math.cos(bearing)) / EARTH_RADIUS_M;
const dLng = (distanceM * Math.sin(bearing)) / (EARTH_RADIUS_M * Math.cos(latRad));
return { lng: lng + (dLng * 180) / Math.PI, lat: lat + (dLat * 180) / Math.PI };
}
function setPixel(imageData, col, row, shadowed) {
if (!shadowed) return; // ImageData starts fully transparent — nothing to do for a sunlit cell
const i = (row * imageData.width + col) * 4;
imageData.data.set(SHADOW_RGBA, i);
}
function fillShadow(imageData) {
for (let i = 0; i < imageData.data.length; i += 4) imageData.data.set(SHADOW_RGBA, i);
}
function formatMinutes(minutes) {
const h = Math.floor(minutes / 60);
const m = minutes % 60;
return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`;
}
function currentMinutesOfDay() {
const now = new Date();
return now.getHours() * 60 + now.getMinutes();
}
+71
View File
@@ -0,0 +1,71 @@
import { getTimes } from "/vendor/suncalc/suncalc.js";
// A Locus Pro-style toolbar readout: DMS coordinates (plain decimal degrees
// read less like a "GPS unit" and are harder to scan at a glance) plus
// sunrise/sunset and a countdown to whichever comes next — both computed
// for the map's current center, the same point the coordinates already
// describe, not a GNSS fix (this app's coordinate readout was never tied
// to having one).
function toDMS(value, positiveLabel, negativeLabel) {
const label = value >= 0 ? positiveLabel : negativeLabel;
const abs = Math.abs(value);
const degrees = Math.floor(abs);
const minutesFull = (abs - degrees) * 60;
let minutes = Math.floor(minutesFull);
let seconds = Math.round((minutesFull - minutes) * 60);
// A seconds value that rounds up to 60 has to carry into minutes (and
// from there, in the rare case, into degrees) rather than print "60".
if (seconds === 60) {
seconds = 0;
minutes += 1;
}
const carriedDegrees = minutes === 60 ? degrees + 1 : degrees;
const carriedMinutes = minutes === 60 ? 0 : minutes;
return `${carriedDegrees}°${String(carriedMinutes).padStart(2, "0")}'${String(seconds).padStart(2, "0")}"${label}`;
}
export function formatCoords(lat, lng) {
return `${toDMS(lat, "N", "S")} ${toDMS(lng, "E", "W")}`;
}
function formatTime(date) {
return `${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`;
}
function formatCountdown(ms) {
const totalMinutes = Math.max(0, Math.round(ms / 60000));
const hours = Math.floor(totalMinutes / 60);
const minutes = totalMinutes % 60;
return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
}
const DAY_MS = 24 * 60 * 60 * 1000;
// null when there's no sunrise/sunset to show at all — getTimes returns
// null (not Invalid Date) for both on a polar day/night, per its own
// comment in suncalc.js — the caller just hides the readout in that case
// rather than showing something misleading. Returns the three pieces
// separately (not one joined string) so the caller can put its own icon in
// front of each rather than this module owning any markup.
export function formatSunInfo(lat, lng, now = new Date()) {
const today = getTimes(now, lat, lng);
if (today.sunrise === null || today.sunset === null) return null;
let next;
if (now < today.sunrise) {
next = { label: "sunrise", at: today.sunrise };
} else if (now < today.sunset) {
next = { label: "sunset", at: today.sunset };
} else {
// Already past today's sunset — the next event is tomorrow's sunrise.
const tomorrow = getTimes(new Date(now.getTime() + DAY_MS), lat, lng);
next = tomorrow.sunrise === null ? null : { label: "sunrise", at: tomorrow.sunrise };
}
return {
sunrise: formatTime(today.sunrise),
sunset: formatTime(today.sunset),
countdown: next ? `${formatCountdown(next.at - now)} to ${next.label}` : null,
};
}
+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="flag-icons-al" viewBox="0 0 512 512">
<path fill="red" d="M0 0h512v512H0z"/>
<path id="al-a" fill="#000001" d="M204.9 99.5c-5 0-13.2 1.6-13 5.4-14-2.3-15.4 3.4-14.6 8.5q2.3-3 4.2-3.3 2.8-.4 5.8 1.5a23 23 0 0 1 5 4.4c-4.8 1.1-8.6.4-12.4-.3a18 18 0 0 1-6.1-2.5c-1.6-1.1-2.1-2.1-4.6-4.7-2.9-3-6-2.1-5 2.5 2.2 4.3 6 6.3 10.7 7 2.2.4 5.6 1.2 9.4 1.2s8.1-.5 10.5 0c-1.4.8-3 2.4-6.2 3s-8-2-11-2.6c.4 2.5 3.5 4.8 9.7 6 10.2 2.2 18.7 4 24.3 7s9.1 6.8 11.6 9.8c5 6 5.3 10.5 5.6 11.5 1 9.5-2.2 14.8-8.4 16.4-3 .8-8.5-.7-10.5-3-2-2.4-4-6.4-3.4-12.7.5-2.5 3.4-9 1-10.3a292 292 0 0 0-34.4-16c-2.7-1.1-5 2.5-5.8 4A54 54 0 0 1 129 107c-4.6-8.1-12.1 0-10.9 7.7 2.1 8.6 8.6 14.8 16.5 19.2 8 4.5 18.1 8.8 28.3 8.6 5.5 1 5.5 8.2-1.1 9.5-13 0-23.2-.2-32.9-9.6-7.4-6.7-11.5 1.3-9.4 5.8 3.6 14 23.6 18 43.8 13.4 7.8-1.3 3.1 7 .9 7.2-8.4 6-23.5 12-36.8-.1-6.1-4.7-10.2-.7-8 6 6 17.5 28.5 13.8 44 5.2 4-2.2 7.6 3 2.7 6.9-19.2 13.4-28.9 13.6-37.6 8.4-10.8-4.3-11.8 7.8-5.3 11.8 7.2 4.4 25.4 1 38.9-7.4 5.7-4.2 6 2.4 2.3 5-15.9 13.8-22.2 17.5-38.8 15.2-8.2-.6-8 9.5-1.6 13.5 8.8 5.4 26.1-3.6 39.5-14.7 5.6-3 6.6 2 3.8 7.8a57 57 0 0 1-23.3 19.2 29 29 0 0 1-19.5.7c-6.2-2.2-7 4.2-3.6 10 2 3.5 10.6 4.7 19.7 1.4 9.2-3.2 19-10.8 25.7-19.8 6-5.1 5.2 1.8 2.5 6.7-13.5 21.3-25.9 29.2-42.1 27.9-7.3-1.2-8.9 4.4-4.3 9.6 8 6.7 18.2 6.4 27-.2a751 751 0 0 0 30.8-32.6c5.5-4.4 7.3 0 5.7 9-1.5 5.1-5.2 10.5-15.3 14.5-7 4-1.8 9.4 3.4 9.5 2.9 0 8.7-3.3 13-8.3 5.9-6.5 6.2-11 9.5-21.1 3-5 8.4-2.7 8.4 2.5-2.6 10.2-4.8 12-10 16.2-5.1 4.7 3.4 6.3 6.3 4.4 8.3-5.6 11.3-12.8 14.1-19.4 2-4.8 7.8-2.5 5.1 5.3-6.4 18.5-17 25.8-35.5 29.6-1.9.3-3 1.4-2.4 3.6l7.5 7.5c-11.5 3.3-20.8 5.2-32.2 8.5L142 300.6c-1.5-3.4-2.2-8.7-10.4-5-5.7-2.6-8.2-1.6-11.4 1 4.5.1 6.5 1.3 8.3 3.4 2.3 6 7.6 6.6 13 5 3.5 2.9 5.4 5.2 9 8.2l-17.8-.6c-6.3-6.7-11.3-6.3-15.8-1-3.5.5-5 .5-7.3 4.7 3.7-1.5 6-2 7.7-.3 6.6 3.9 11 3 14.3 0l18.7 1.1c-2.3 2-5.6 3.1-8 5.2-9.7-2.8-14.7 1-16.4 8.8a18 18 0 0 0-1.4 10c1-3.2 2.5-5.9 5.3-7.6 8.6 2.2 11.8-1.3 12.3-6.5 4.2-3.4 10.5-4.1 14.6-7.6 4.9 1.6 7.2 2.6 12.1 4.1q2.5 8 12 6c7.7.3 6.3 3.4 7 5.9 2-3.6 2-7-2.8-10.3-1.7-4.6-5.5-6.7-10.4-4-4.7-1.3-5.9-3.2-10.5-4.6 11.7-3.7 20-4.5 31.8-8.3 3 2.8 5.2 4.8 8.2 7.2q2.5 1.6 4 0c7.3-10.6 10.6-20 17.4-27 2.6-2.9 6-6.8 9.6-7.8 1.8-.4 4-.2 5.5 1.4 1.4 1.6 2.6 4.4 2 8.7-.6 6.2-2 8.2-3.8 11.8s-3.9 6-6 8.8c-4.4 5.7-10.1 9-13.5 11.2-6.8 4.4-9.7 2.5-15 2.2-6.7.8-8.5 4.1-3 8.7a21 21 0 0 0 13.7 2.3c3.3-.6 7-4.8 9.8-7 3-3.6 8.1.6 4.7 4.7-6.3 7.5-12.6 12.4-20.3 12.3-8.2 1-6.7 5.7-1.3 7.9 9.8 4 18.6-3.5 23-8.5 3.5-3.7 6-3.9 5.3 2-3.4 10.5-8.1 14.6-15.7 15.1-6.2-.5-6.3 4.2-1.7 7.5 10.3 7 17.7-5 21.2-12.4 2.5-6.6 6.3-3.5 6.7 2 0 7.3-3.2 13.2-12 20.7 6.7 10.7 14.5 21.7 21.3 32.5l20.5-228.2-20.5-36c-2.1-2-9.3-10.5-11.2-11.7-.7-.7-1.1-1.2-.1-1.6s3.2-.8 4.8-1c-4.4-4.4-8-5.8-16.3-8.2 2-.8 4-.3 9.9-.6a32 32 0 0 0-14.4-11c4.5-3 5.3-3.3 9.8-7-7.7-.6-14.3-2-20.8-4a41 41 0 0 0-12.8-3.7m.7 9c4 0 6.6 1.4 6.6 3s-2.5 3.1-6.6 3.1-6.6-1.5-6.6-3.2 2.6-3 6.6-3z"/>
<use xlink:href="#al-a" width="100%" height="100%" transform="matrix(-1 0 0 1 512 0)"/>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

+4
View File
@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-at" viewBox="0 0 512 512">
<path fill="#fff" d="M0 170.7h512v170.6H0z"/>
<path fill="#c8102e" d="M0 0h512v170.7H0zm0 341.3h512V512H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 203 B

+12
View File
@@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-ba" viewBox="0 0 512 512">
<defs>
<clipPath id="ba-a">
<path fill-opacity=".7" d="M0 0h512v512H0z"/>
</clipPath>
</defs>
<g fill-rule="evenodd" clip-path="url(#ba-a)">
<path fill="#009" d="M0 0h512v512H0z"/>
<path fill="#fc0" d="m77 0 437 437V0z"/>
<path fill="#FFF" d="m461.4 470.4-26.1-19.1-26.9 19 10.2-31.2-26.4-19.2h32.7l10.2-31 10 31.1 32.8.1-26.2 19.4zm76.7 10.4h-32.7l-10-31.2-10.2 31.1h-32.8l26.4 19.2-10.1 31.2 26.8-19 26.2 19-9.8-30.9zM391.8 379.6l26.2-19.4h-32.7L375.2 329 365 360h-32.7l26.4 19.3-10.1 31.1 26.8-19 26.1 19.1zm-60.3-60.4 26.2-19.4-32.8-.1-10-31.2-10.2 31.2-32.7-.1 26.4 19.2-10.2 31.2 26.9-19 26.1 19.1zm-59.7-59.7 26.2-19.4h-32.7l-10.1-31.2L245 240h-32.7l26.4 19.2-10.1 31.2 26.8-19 26.1 19zm-60.4-60.3 26.2-19.3-32.8-.1-10-31.2-10.2 31.2-32.7-.1 26.4 19.2-10.2 31.2 26.9-19 26.1 19-9.7-30.8zm-59.7-59.9L178 120l-32.7-.1-10-31.2-10.3 31.1H92.2l26.4 19.2-10.1 31.2 26.8-19 26.1 19zm-60-60L118 60l-32.7-.1-10-31.2L65 59.8H32.2L58.6 79l-10.1 31.2 26.8-19 26.2 19zm-60-60L58 0 25.2-.1l-10-31.2L4.8-.2h-32.7L-1.4 19l-10.1 31.2 26.8-19 26.1 19z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-be" viewBox="0 0 512 512">
<g fill-rule="evenodd" stroke-width="1pt">
<path fill="#000001" d="M0 0h170.7v512H0z"/>
<path fill="#ffd90c" d="M170.7 0h170.6v512H170.7z"/>
<path fill="#f31830" d="M341.3 0H512v512H341.3z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 302 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-bg" viewBox="0 0 512 512">
<path fill="#fff" d="M0 0h512v170.7H0z"/>
<path fill="#00966e" d="M0 170.7h512v170.6H0z"/>
<path fill="#d62612" d="M0 341.3h512V512H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 233 B

+18
View File
@@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" id="flag-icons-by" viewBox="0 0 512 512">
<defs>
<clipPath id="by-a">
<path d="M0 0h200v608h8v284l-8 8H0Z"/>
</clipPath>
</defs>
<path fill="#ce1720" d="M0 0h512v512H0Z"/>
<g fill="#fff" clip-path="url(#by-a)" transform="matrix(.5625 0 0 .56889 5 0)">
<g id="by-c">
<path id="by-b" d="M36 0v14h-9v14H16v16H8v13H-8V24H8V6H-8V0Zm26 77v15h-8v12h-8V92h-8V77h-8V57h8V42h8V30h8v12h8v15h8v20Zm-17-1h10V58H45ZM19 183h8v-18h-8zm54 0h8v-18h-8ZM-8 305H6v13h6v16h9v15h12v-15h9v-16h8v-13H38v-15h21v10h13v17h11v19h-8v14h-7v13h-6v14h-9v12h-7v11h-9v14H24v-15h-9v-14H8v-9H-8v-23H8v-20H-8Z"/>
<use xlink:href="#by-b" transform="matrix(-1 0 0 1 200 0)"/>
<path d="M96 0v32h8V0h32v14h-8v14h-12v16h-8v13H92V44h-8V28H72V14h-8V0Zm-2 274v-11h-6v-13h-7v-14h-8v-14h-8v-10h-9v-14H44v14h-9v10h-7v14h-8v14h-6v13H8v17H-8v-44H8v-20H-8v-33H8v14h10v14h10v-14h10v-14h8v-18h-8v-14H28v-14H18v14H8v14H-8v-41H8v-19H-8V77H8v13h8v16h11v13h9v15h7v12h14v-12h7v-15h9v-13h11V90h8V77h16v13h8v16h11v13h9v15h7v12h14v-12h7v-15h9v-13h11V90h8V77h16v28h-16v19h16v41h-16v-14h-10v-14h-10v14h-10v14h-8v18h8v14h10v14h10v-14h10v-14h16v33h-16v20h16v44h-16v-17h-6v-13h-6v-14h-8v-14h-7v-10h-9v-14h-12v14h-9v10h-8v14h-8v14h-7v13h-6v11zm2-167v27h8v-27zm-4 58v-14H82v-14H72v14H62v14h-8v18h8v14h10v14h10v-14h10v-14h16v14h10v14h10v-14h10v-14h8v-18h-8v-14h-10v-14h-10v14h-10v14zm4 46v27h8v-27z"/>
</g>
<use xlink:href="#by-c" transform="matrix(1 0 0 -1 0 900)"/>
<path d="M-8 408H8v14h7v8h8v14h7v12h-7v14h-8v8H8v14H-8Zm216 0v84h-16v-14h-7v-8h-8v-14h-7v-12h7v-14h8v-8h7v-14ZM62 459h8v-18h-8zm76 0v-18h-8v18zm-42-59h8v-18h-8zm0 100v18h8v-18Zm-50-75h14v-11h10v-10h5v-10h6v-14h8v-14h4v-13h14v13h4v14h8v14h6v10h5v10h10v11h14v50h-14v11h-10v10h-5v10h-6v14h-8v14h-4v13H93v-13h-4v-14h-8v-14h-6v-10h-5v-10H60v-11H46Zm50 9v-15h-8v-10h-8v25h8v9h5v14h-5v9h-8v25h8v-10h8v-15h8v15h8v10h8v-25h-8v-9h-5v-14h5v-9h8v-25h-8v10h-8v15z"/>
</g>
<path fill="#007c30" d="M117.3 341.3h395V512h-395z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+9
View File
@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-ch" viewBox="0 0 512 512">
<g fill-rule="evenodd" stroke-width="1pt">
<path fill="red" d="M0 0h512v512H0z"/>
<g fill="#fff">
<path d="M96 208h320v96H96z"/>
<path d="M208 96h96v320h-96z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 288 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-cz" viewBox="0 0 512 512">
<path fill="#fff" d="M0 0h512v256H0z"/>
<path fill="#d7141a" d="M0 256h512v256H0z"/>
<path fill="#11457e" d="M300 256 0 56v400z"/>
</svg>

After

Width:  |  Height:  |  Size: 226 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-de" viewBox="0 0 512 512">
<path fill="#fc0" d="M0 341.3h512V512H0z"/>
<path fill="#000001" d="M0 0h512v170.7H0z"/>
<path fill="red" d="M0 170.7h512v170.6H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 229 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-dk" viewBox="0 0 512 512">
<path fill="#c8102e" d="M0 0h512.1v512H0z"/>
<path fill="#fff" d="M144 0h73.1v512H144z"/>
<path fill="#fff" d="M0 219.4h512.1v73.2H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 232 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-ee" viewBox="0 0 512 512">
<path fill="#1791ff" d="M0 0h512v170.7H0z"/>
<path fill="#000001" d="M0 170.7h512v170.6H0z"/>
<path fill="#fff" d="M0 341.3h512V512H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 233 B

+547
View File
@@ -0,0 +1,547 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-es" viewBox="0 0 512 512">
<path fill="#AA151B" d="M0 0h512v512H0z"/>
<path fill="#F1BF00" d="M0 128h512v256H0z"/>
<path fill="#ad1519" d="M171.7 227.6s-.5 0-.8-.2l-1.1-1-.7-.5-.7-.9s-.7-1.2-.4-2q.7-1.3 1.5-1.6c.5-.3 1.6-.6 1.6-.6l1.2-.5 1.3-.3.6-.3.9-.1 1.1-.3 1.7.1h5.1l3.6 1.2c.6.1 1.9.3 2.4.6q.9.6 1.3 1.1l.4 1.1v1.1l-.5.9-.6 1-.8.7s-.6.5-1.1.5-5.1-.9-8.2-.9-7.8.9-7.8.9"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".3" d="M171.7 227.6s-.5 0-.8-.2l-1.1-1-.7-.5-.7-.9s-.7-1.2-.4-2q.7-1.3 1.5-1.6c.5-.3 1.6-.6 1.6-.6l1.2-.5 1.3-.3.6-.3.9-.1 1.1-.3 1.7.1h5.1l3.6 1.2c.6.1 1.9.3 2.4.6q.9.6 1.3 1.1l.4 1.1v1.1l-.5.9-.6 1-.8.7s-.6.5-1.1.5-5.1-.9-8.2-.9-7.8.9-7.8.9z"/>
<path fill="#c8b100" d="M178.2 220.9q.1-2.4 1.4-2.6 1.3.2 1.4 2.6-.1 2.3-1.4 2.5-1.3-.2-1.4-2.5"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M178.2 220.9q.1-2.4 1.4-2.6 1.3.2 1.4 2.6-.1 2.3-1.4 2.5-1.3-.2-1.4-2.5z"/>
<path fill="#c8b100" d="M179 220.9c0-1.3.3-2.4.6-2.4q.7.2.7 2.4t-.7 2.3q-.5-.2-.6-2.3"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M179 220.9c0-1.3.3-2.4.6-2.4q.7.2.7 2.4t-.7 2.3q-.5-.2-.6-2.3z"/>
<path fill="#c8b100" d="M178.7 218.2q0-.9.9-1 1.2 0 1 1c-.2 1-.5.9-1 .9a1 1 0 0 1-1-1"/>
<path fill="#c8b100" d="M180.3 217.8v.6h-1.5v-.6h.5v-1.3h-.7v-.6h.7v-.6h.6v.6h.6v.6h-.6v1.3z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M180.3 217.8v.6h-1.5v-.6h.5v-1.3h-.7v-.6h.7v-.6h.6v.6h.6v.6h-.6v1.3h.4"/>
<path fill="#c8b100" d="M181 217.8v.6h-2.7v-.6h1v-1.3h-.7v-.6h.7v-.6h.6v.6h.6v.6h-.6v1.3z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M181 217.8v.6h-2.7v-.6h1v-1.3h-.7v-.6h.7v-.6h.6v.6h.6v.6h-.6v1.3h1"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M179.9 217.3a1 1 0 0 1 .6.9q0 .8-.9.9-1.2 0-1-1 .1-.6.8-.8"/>
<path fill="#c8b100" d="M179.6 227.4h-5v-1.2l-.3-1.2-.2-1.6c-1.4-1.8-2.6-3-3-2.7q0-.6.4-.8c1.2-.7 3.7 1 5.6 3.9l.5.7h4l.5-.7c1.9-2.9 4.4-4.6 5.6-3.9l.5.8c-.5-.3-1.7.9-3 2.7l-.3 1.6-.2 1.2-.1 1.2z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M179.6 227.4h-5v-1.2l-.3-1.2-.2-1.6c-1.4-1.8-2.6-3-3-2.7q0-.6.4-.8c1.2-.7 3.7 1 5.6 3.9l.5.7h4l.5-.7c1.9-2.9 4.4-4.6 5.6-3.9l.5.8c-.5-.3-1.7.9-3 2.7l-.3 1.6-.2 1.2-.1 1.2z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M171.3 220.6c1-.5 3 1.2 4.8 3.8m11.9-3.8c-1-.5-3.1 1.2-4.9 3.8"/>
<path fill="#c8b100" d="m172.3 229.6-.6-1q3.1-1 7.9-1c3 0 5.9.3 7.9 1l-.6.9-.3.8q-2.7-.9-7-.8c-2.9 0-5.6.3-7 .8z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m172.3 229.6-.6-1q3.1-1 7.9-1c3 0 5.9.3 7.9 1l-.6.9-.3.8q-2.7-.9-7-.8c-2.9 0-5.6.3-7 .8l-.3-.7"/>
<path fill="#c8b100" d="M179.6 232.2a27 27 0 0 0 6.2-.7q1.1-.3 1-.8 0-.3-.3-.4a26 26 0 0 0-7-.9c-2.6 0-5.3.4-6.8.9q-.3 0-.4.4 0 .5 1 .8c1 .3 3.8.7 6.3.7"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M179.6 232.2a27 27 0 0 0 6.2-.7q1.1-.3 1-.8 0-.3-.3-.4a26 26 0 0 0-7-.9c-2.6 0-5.3.4-6.8.9q-.3 0-.4.4 0 .5 1 .8c1 .3 3.8.7 6.3.7z"/>
<path fill="#c8b100" d="m187.6 227.4-.6-.5s-.6.3-1.3.2-1-1-1-1-.8.7-1.5.6-1-.6-1-.6-.8.5-1.4.5c-.7 0-1.3-.9-1.3-.9s-.6.9-1.2 1-1.2-.6-1.2-.6-.3.6-1 .7c-.9.1-1.6-.6-1.6-.6s-.5.7-1 1c-.6.1-1.3-.4-1.3-.4l-.2.5-.3.2.2.4a33 33 0 0 1 15.5.1z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m187.6 227.4-.6-.5s-.6.3-1.3.2-1-1-1-1-.8.7-1.5.6-1-.6-1-.6-.8.5-1.4.5c-.7 0-1.3-.9-1.3-.9s-.6.9-1.2 1-1.2-.6-1.2-.6-.3.6-1 .7c-.9.1-1.6-.6-1.6-.6s-.5.7-1 1c-.6.1-1.3-.4-1.3-.4l-.2.5-.3.2.2.4a33 33 0 0 1 15.5.1z"/>
<path fill="#c8b100" d="M179.6 224.8h.3a1 1 0 0 0 1 1.5q.9 0 1.2-.8l.1-.4v.5q.2.8 1.2.9a1 1 0 0 0 1.1-1.1v-.1l.4-.4.2.4-.1.5q.1 1 1 1 .7 0 1-.4l.2-.3v.4q0 .5.5.7l1-.4.8-.8v.5s-.5.8-1 1.1l-1 .3q-.4-.2-.7-.7l-.8.3q-1 0-1.4-1a2 2 0 0 1-1.2.6 2 2 0 0 1-1.3-.6l-1.1.4q-1 0-1.4-.7-.5.7-1.4.7l-1-.4q-.6.5-1.4.6a2 2 0 0 1-1.2-.5q-.4.8-1.4.8-.5 0-.8-.2-.2.5-.7.7l-1-.3-1-1.1v-.5l.9.8q.8.5.9.4.5-.1.5-.7v-.4l.2.3q.3.5 1 .5.9-.1 1-1v-.6l.1-.4.4.4q.1 1.1 1 1.2 1.1 0 1.2-1v-.3l.2.3q.3.8 1.1.8 1.1-.1 1.2-1.1l-.1-.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M179.6 224.8h.3a1 1 0 0 0 1 1.5q.9 0 1.2-.8l.1-.4v.5q.2.8 1.2.9a1 1 0 0 0 1.1-1.1v-.1l.4-.4.2.4-.1.5q.1 1 1 1 .7 0 1-.4l.2-.3v.4q0 .5.5.7l1-.4.8-.8v.5s-.5.8-1 1.1l-1 .3q-.4-.2-.7-.7l-.8.3q-1 0-1.4-1a2 2 0 0 1-1.2.6 2 2 0 0 1-1.3-.6l-1.1.4q-1 0-1.4-.7-.5.7-1.4.7l-1-.4q-.6.5-1.4.6a2 2 0 0 1-1.2-.5q-.4.8-1.4.8-.5 0-.8-.2-.2.5-.7.7l-1-.3-1-1.1v-.5l.9.8q.8.5.9.4.5-.1.5-.7v-.4l.2.3q.3.5 1 .5.9-.1 1-1v-.6l.1-.4.4.4q.1 1.1 1 1.2 1.1 0 1.2-1v-.3l.2.3q.3.8 1.1.8 1.1-.1 1.2-1.1l-.1-.4z"/>
<path fill="#c8b100" d="M179.6 227.6q-4.8 0-7.9 1l-.3-.2q0-.3.2-.4 3.1-1 8-1c4.9 0 6 .4 8 1l.2.3q0 .3-.3.2-3.1-1-8-1"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".3" d="M179.6 227.6q-4.8 0-7.9 1l-.3-.2q0-.3.2-.4 3.1-1 8-1c4.9 0 6 .4 8 1l.2.3q0 .3-.3.2-3.1-1-8-1z"/>
<path fill="#fff" d="M176.6 228.7q0-.5.5-.5.3 0 .4.5 0 .3-.5.4-.6 0-.4-.4"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M176.6 228.7q0-.5.5-.5.3 0 .4.5 0 .3-.5.4-.6 0-.4-.4z"/>
<path fill="#ad1519" d="M179.6 228.8h-1l-.3-.3q0-.2.3-.3h2a.3.3 0 0 1 .4.3.3.3 0 0 1-.4.3z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M179.6 228.8h-1l-.3-.3q0-.2.3-.3h2a.3.3 0 0 1 .4.3.3.3 0 0 1-.4.3h-1"/>
<path fill="#058e6e" d="M174.7 229.2h-.7q-.3.1-.4-.2l.2-.3.7-.1.8-.2q.3 0 .4.3 0 .3-.3.4h-.8"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M174.7 229.2h-.7q-.3.1-.4-.2l.2-.3.7-.1.8-.2q.3 0 .4.3 0 .3-.3.4h-.8"/>
<path fill="#ad1519" d="m171.8 229.7.3-.5.7.1-.4.6z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m171.8 229.7.3-.5.7.1-.4.6-.6-.2"/>
<path fill="#fff" d="M181.7 228.7q0-.5.4-.5t.5.5q0 .3-.5.4-.6 0-.4-.4"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M181.7 228.7q0-.5.4-.5t.5.5q0 .3-.5.4-.6 0-.4-.4z"/>
<path fill="#058e6e" d="M184.5 229.2h.8q.2.1.3-.2l-.2-.3-.8-.1-.7-.2q-.3 0-.4.3 0 .3.3.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M184.5 229.2h.8q.2.1.3-.2l-.2-.3-.8-.1-.7-.2q-.3 0-.4.3 0 .3.3.4h.7"/>
<path fill="#ad1519" d="m187.3 229.7-.2-.5h-.7l.3.6h.7"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m187.3 229.7-.2-.5h-.7l.3.6h.7"/>
<path fill="#ad1519" d="M179.6 231.6q-3.9 0-6.5-.7a27 27 0 0 1 6.5-.7q3.8 0 6.5.7-2.7.7-6.5.7"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".3" d="M179.6 231.6q-3.9 0-6.5-.7a27 27 0 0 1 6.5-.7q3.8 0 6.5.7-2.7.7-6.5.7z"/>
<path fill="#c8b100" d="M187.4 226.2v-.4q-.3 0-.5.2 0 .3.2.5.2 0 .3-.3"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M187.4 226.2v-.4q-.3 0-.5.2 0 .3.2.5.2 0 .3-.3z"/>
<path fill="#c8b100" d="M182.5 225.2q0-.3-.2-.4-.3 0-.3.4t.2.4.3-.4"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M182.5 225.2q0-.3-.2-.4-.3 0-.3.4t.2.4.3-.4z"/>
<path fill="#c8b100" d="M176.7 225.2q0-.3.2-.4.3 0 .3.4t-.2.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M176.7 225.2q0-.3.2-.4.3 0 .3.4t-.2.4z"/>
<path fill="#c8b100" d="M171.8 226.2q-.1-.3.1-.4t.4.2q0 .3-.2.5-.2 0-.3-.3"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M171.8 226.2q-.1-.3.1-.4t.4.2q0 .3-.2.5-.2 0-.3-.3z"/>
<path fill="#c8b100" d="m179.6 222.4-.9.5.7 1.4.2.2.2-.2.7-1.4-1-.5"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m179.6 222.4-.9.5.7 1.4.2.2.2-.2.7-1.4-1-.5"/>
<path fill="#c8b100" d="m177.7 224.5.4.6 1.3-.4.2-.2-.2-.2-1.3-.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m177.7 224.5.4.6 1.3-.4.2-.2-.2-.2-1.3-.4-.4.6"/>
<path fill="#c8b100" d="m181.5 224.5-.4.6-1.3-.4-.2-.2.1-.2 1.4-.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m181.5 224.5-.4.6-1.3-.4-.2-.2.1-.2 1.4-.4.4.6"/>
<path fill="#c8b100" d="m173.9 223-.7.6.9 1.2.2.1.2-.2.3-1.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m173.9 223-.7.6.9 1.2.2.1.2-.2.3-1.4-1-.3"/>
<path fill="#c8b100" d="m172.4 225.3.5.5 1.3-.7v-.4h-1.5z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m172.4 225.3.5.5 1.3-.7v-.4h-1.5l-.3.6"/>
<path fill="#c8b100" d="m176.2 224.6-.3.6-1.4-.1-.2-.2.1-.2 1.3-.7z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m176.2 224.6-.3.6-1.4-.1-.2-.2.1-.2 1.3-.7.5.6"/>
<path fill="#c8b100" d="M171 225.5v.7l-1.5.1h-.2v-.3l1.1-1z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M171 225.5v.7l-1.5.1h-.2v-.3l1.1-1 .6.5"/>
<path fill="#c8b100" d="M173.8 225q0-.6.5-.6t.5.5l-.5.5z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M173.8 225q0-.6.5-.6t.5.5l-.5.5z"/>
<path fill="#c8b100" d="m185.3 223 .7.6-.9 1.2-.2.1-.2-.2-.3-1.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m185.3 223 .7.6-.9 1.2-.2.1-.2-.2-.3-1.4 1-.3"/>
<path fill="#c8b100" d="m186.8 225.3-.6.5-1.2-.7-.1-.2.2-.2h1.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m186.8 225.3-.6.5-1.2-.7-.1-.2.2-.2h1.4l.3.6"/>
<path fill="#c8b100" d="m183 224.6.3.6 1.4-.1.2-.2-.1-.2-1.3-.7z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m183 224.6.3.6 1.4-.1.2-.2-.1-.2-1.3-.7-.5.6"/>
<path fill="#c8b100" d="M188 225.5v.7l1.5.1h.2v-.3l-1.1-1z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M188 225.5v.7l1.5.1h.2v-.3l-1.1-1-.6.5"/>
<path fill="#c8b100" d="M179 224.5a.5.5 0 0 1 .6-.5q.5 0 .5.5l-.5.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M179 224.5a.5.5 0 0 1 .6-.5q.5 0 .5.5l-.5.4z"/>
<path fill="#c8b100" d="M184.4 225a.5.5 0 0 1 .5-.6l.5.5-.5.5z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M184.4 225a.5.5 0 0 1 .5-.6l.5.5-.5.5z"/>
<path fill="#c8b100" d="m169.1 226.3-.7-.8-.7-.3s.3-.3.6-.3l.5.2v-.2s.3 0 .4.4v1"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m169.1 226.3-.7-.8-.7-.3s.3-.3.6-.3l.5.2v-.2s.3 0 .4.4v1z"/>
<path fill="#c8b100" d="m169.1 226 .6.1q.3.3 0 .5-.4.2-.4 0-.3-.3-.2-.5"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m169.1 226 .6.1q.3.3 0 .5-.4.2-.4 0-.3-.3-.2-.5z"/>
<path fill="#c8b100" d="m189.9 226.3.7-.8.7-.3s-.3-.3-.6-.3l-.5.2v-.2s-.3 0-.4.4v.7z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m189.9 226.3.7-.8.7-.3s-.3-.3-.6-.3l-.5.2v-.2s-.3 0-.4.4v.7z"/>
<path fill="#c8b100" d="m189.9 226-.5.1q-.3.3-.2.5h.6q.3-.3.1-.5"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m189.9 226-.5.1q-.3.3-.2.5h.6q.3-.3.1-.5z"/>
<path fill="#c8b100" d="M168.2 238h22.9v-6h-22.9z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M168.2 238h22.9v-6h-22.9z"/>
<path fill="#c8b100" d="m170.6 242 .5-.1h17.5q-1-.3-1-1.3.1-1 1-1.4l-.5.1h-17.5q1 .3 1 1.3t-1 1.3"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".4" d="m170.6 242 .5-.1h17.5q-1-.3-1-1.3.1-1 1-1.4l-.5.1h-17.5q1 .3 1 1.3t-1 1.3z"/>
<path fill="#c8b100" d="M171 241.9h17.2q.9 0 1 .8-.1.7-1 .8H171q-1-.1-1.1-.8.1-.8 1-.8"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M171 241.9h17.2q.9 0 1 .8-.1.7-1 .8H171q-1-.1-1.1-.8.1-.8 1-.8z"/>
<path fill="#c8b100" d="M171 238h17.2q.9 0 1 .6-.1.7-1 .7H171q-1 0-1-.7t1-.7"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M171 238h17.2q.9 0 1 .6-.1.7-1 .7H171q-1 0-1-.7t1-.7z"/>
<path fill="#005bbf" d="M195.6 338.6a9 9 0 0 1-4-.9 9 9 0 0 0-4-.8q-2.5 0-4 .8a9 9 0 0 1-4 1 9 9 0 0 1-4-1 9 9 0 0 0-4-.8 9 9 0 0 0-3.9.8q-1.6 1-4 1v2.4a9 9 0 0 0 4-1 9 9 0 0 1 4-.8 9 9 0 0 1 3.9.9 9 9 0 0 0 4 .9 9 9 0 0 0 4-.9 9 9 0 0 1 4-.9q2.4 0 4 .9a9 9 0 0 0 4 .9z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M195.6 338.6a9 9 0 0 1-4-.9 9 9 0 0 0-4-.8q-2.5 0-4 .8a9 9 0 0 1-4 1 9 9 0 0 1-4-1 9 9 0 0 0-4-.8 9 9 0 0 0-3.9.8q-1.6 1-4 1v2.4a9 9 0 0 0 4-1 9 9 0 0 1 4-.8 9 9 0 0 1 3.9.9 9 9 0 0 0 4 .9 9 9 0 0 0 4-.9 9 9 0 0 1 4-.9q2.4 0 4 .9a9 9 0 0 0 4 .9z"/>
<path fill="#ccc" d="M195.6 341a9 9 0 0 1-4-.8 9 9 0 0 0-4-.8q-2.5 0-4 .8a9 9 0 0 1-4 .9 9 9 0 0 1-4-1 9 9 0 0 0-4-.8q-2.3 0-3.9.9a9 9 0 0 1-4 .9v2.4a9 9 0 0 0 4-.9 9 9 0 0 1 4-.8 9 9 0 0 1 3.9.8 9 9 0 0 0 4 1 9 9 0 0 0 4-1 9 9 0 0 1 4-.8 9 9 0 0 1 4 .9 9 9 0 0 0 4 .9z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M195.6 341a9 9 0 0 1-4-.8 9 9 0 0 0-4-.8q-2.5 0-4 .8a9 9 0 0 1-4 .9 9 9 0 0 1-4-1 9 9 0 0 0-4-.8q-2.3 0-3.9.9a9 9 0 0 1-4 .9v2.4a9 9 0 0 0 4-.9 9 9 0 0 1 4-.8 9 9 0 0 1 3.9.8 9 9 0 0 0 4 1 9 9 0 0 0 4-1 9 9 0 0 1 4-.8 9 9 0 0 1 4 .9 9 9 0 0 0 4 .9V341"/>
<path fill="#005bbf" d="M195.6 343.6a9 9 0 0 1-4-1 9 9 0 0 0-4-.8 9 9 0 0 0-4 .9 9 9 0 0 1-4 .9 9 9 0 0 1-4-1 9 9 0 0 0-4-.8 9 9 0 0 0-3.9.8 9 9 0 0 1-4 1v2.4q2.4 0 4-.9a9 9 0 0 1 4-.8 9 9 0 0 1 3.9.8 9 9 0 0 0 8 0 9 9 0 0 1 4-.8q2.4 0 4 .8 1.5 1 4 1v-2.6"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M195.6 343.6a9 9 0 0 1-4-1 9 9 0 0 0-4-.8 9 9 0 0 0-4 .9 9 9 0 0 1-4 .9 9 9 0 0 1-4-1 9 9 0 0 0-4-.8 9 9 0 0 0-3.9.8 9 9 0 0 1-4 1v2.4q2.4 0 4-.9a9 9 0 0 1 4-.8 9 9 0 0 1 3.9.8 9 9 0 0 0 8 0 9 9 0 0 1 4-.8q2.4 0 4 .8 1.5 1 4 1v-2.6"/>
<path fill="#ccc" d="M195.6 348.5a9 9 0 0 1-4-1 9 9 0 0 0-4-.7 9 9 0 0 0-4 .8 9 9 0 0 1-4 .9 9 9 0 0 1-4-1 9 9 0 0 0-4-.7 9 9 0 0 0-3.9.8 9 9 0 0 1-4 .9V346a9 9 0 0 0 4-.9 9 9 0 0 1 4-.8 9 9 0 0 1 3.9.8q1.5 1 4 1a9 9 0 0 0 4-1 9 9 0 0 1 4-.8 9 9 0 0 1 4 .8q1.5 1 4 1z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M195.6 348.5a9 9 0 0 1-4-1 9 9 0 0 0-4-.7 9 9 0 0 0-4 .8 9 9 0 0 1-4 .9 9 9 0 0 1-4-1 9 9 0 0 0-4-.7 9 9 0 0 0-3.9.8 9 9 0 0 1-4 .9V346a9 9 0 0 0 4-.9 9 9 0 0 1 4-.8 9 9 0 0 1 3.9.8q1.5 1 4 1a9 9 0 0 0 4-1 9 9 0 0 1 4-.8 9 9 0 0 1 4 .8q1.5 1 4 1v2.4"/>
<path fill="#005bbf" d="M195.6 351a9 9 0 0 1-4-1 9 9 0 0 0-4-.8 9 9 0 0 0-4 .9 9 9 0 0 1-4 .8 9 9 0 0 1-4-.9 9 9 0 0 0-4-.8 9 9 0 0 0-3.9.8q-1.6 1-4 1v-2.5q2.4 0 4-1a9 9 0 0 1 4-.7 9 9 0 0 1 3.9.8 9 9 0 0 0 4 .9 9 9 0 0 0 4-.9 9 9 0 0 1 4-.8 9 9 0 0 1 4 .8 9 9 0 0 0 4 .9z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M195.6 351a9 9 0 0 1-4-1 9 9 0 0 0-4-.8 9 9 0 0 0-4 .9 9 9 0 0 1-4 .8 9 9 0 0 1-4-.9 9 9 0 0 0-4-.8 9 9 0 0 0-3.9.8q-1.6 1-4 1v-2.5q2.4 0 4-1a9 9 0 0 1 4-.7 9 9 0 0 1 3.9.8 9 9 0 0 0 4 .9 9 9 0 0 0 4-.9 9 9 0 0 1 4-.8 9 9 0 0 1 4 .8 9 9 0 0 0 4 .9z"/>
<path fill="#c8b100" d="m170.6 328.5.2.6c0 1.5-1.3 2.7-3 2.7h23.6c-1.6 0-2.9-1.2-2.9-2.7l.1-.6h-.5z"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".4" d="m170.6 328.5.2.6c0 1.5-1.3 2.7-3 2.7h23.6c-1.6 0-2.9-1.2-2.9-2.7l.1-.6h-.5z"/>
<path fill="#c8b100" d="M171 327h17.2q.9 0 1 .7-.1.8-1 .8H171q-1 0-1.1-.8.1-.7 1-.8"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M171 327h17.2q.9 0 1 .7-.1.8-1 .8H171q-1 0-1.1-.8.1-.7 1-.8z"/>
<path fill="#c8b100" d="M168 337.8h23.3v-6H168z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M168 337.8h23.3v-6H168z"/>
<path fill="#ad1519" d="M166 305.8c-2.2 1.3-3.8 2.7-3.5 3.4q.1.8 1.9 1.8c1.6 1.1 2.6 3.2 1.8 4.1a6 6 0 0 0-.1-9.3"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M166 305.8c-2.2 1.3-3.8 2.7-3.5 3.4q.1.8 1.9 1.8c1.6 1.1 2.6 3.2 1.8 4.1a6 6 0 0 0-.1-9.3z"/>
<path fill="#ccc" d="M171.3 326h16.6v-81.6h-16.6z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M183.1 244.5V326m2-81.4V326m-13.8 0h16.6v-81.5h-16.6z"/>
<path fill="#ad1519" d="M205 275a53 53 0 0 0-17-3 52 52 0 0 0-8 .8c-9.9 1.7-17.5 5.6-16.9 8.9v.2l-3.7-8.7c-.7-3.6 7.7-8 18.8-9.8a57 57 0 0 1 9.8-.8c7 0 13.2.9 16.9 2.3v10"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".4" d="M205 275a53 53 0 0 0-17-3 52 52 0 0 0-8 .8c-9.9 1.7-17.5 5.6-16.9 8.9v.2l-3.7-8.7c-.7-3.6 7.7-8 18.8-9.8a57 57 0 0 1 9.8-.8c7 0 13.2.9 16.9 2.3v10"/>
<path fill="#ad1519" d="M171.3 285.1c-4.7-.3-7.8-1.5-8.2-3.5-.3-1.5 1.3-3.2 4-4.7l4.2.3v8"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M171.3 285.1c-4.7-.3-7.8-1.5-8.2-3.5-.3-1.5 1.3-3.2 4-4.7l4.2.3v8"/>
<path fill="#ad1519" d="M188 279q4.4.5 6 2l.2.1c.5 1-2 3.3-6.3 5.8v-8"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M188 279q4.4.5 6 2l.2.1c.5 1-2 3.3-6.3 5.8v-8"/>
<path fill="#ad1519" d="M160.9 300.9c-.4-1.3 4-4 10.4-6.3 3-1 5.3-2.1 8.3-3.4 8.9-4 15.4-8.4 14.6-10l-.1-.2c.5.4 1.2 8.4 1.2 8.4.8 1.5-5.2 6-13.3 9.8-2.6 1.3-8.1 3.3-10.7 4.2-4.7 1.6-9.3 4.7-8.9 5.8z"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".4" d="M160.9 300.9c-.4-1.3 4-4 10.4-6.3 3-1 5.3-2.1 8.3-3.4 8.9-4 15.4-8.4 14.6-10l-.1-.2c.5.4 1.2 8.4 1.2 8.4.8 1.5-5.2 6-13.3 9.8-2.6 1.3-8.1 3.3-10.7 4.2-4.7 1.6-9.3 4.7-8.9 5.8z"/>
<path fill="#c8b100" d="M170.1 271c2-.7 3.4-1.6 2.7-3.2q-.6-1.5-3-.7l-2.8 1 2.5 6.2.9-.3.8-.3zm-1.2-3 .7-.2q1-.4 1.5.8.5.8-.5 1.6l-.7.3zm7.7-2.6-.8.3h-1l1.5 6.5 4.5-.9-.2-.4v-.4l-2.7.7zm9 5.6 2.9-6.8h-1.1l-2 5-2.4-4.7-1 .1h-1.1l3.7 6.5.5-.1zm9.4-5 .5-.9a4 4 0 0 0-1.9-.6q-2.7-.1-3 1.7c-.2 2.3 3.4 2.1 3.3 3.7q-.3 1-1.6.8-1.3 0-1.5-1.2h-.2l-.5 1.2q.8.4 1.9.6c1.8.2 3.3-.6 3.4-1.8.2-2.2-3.4-2.3-3.3-3.6q0-1 1.4-.8 1 0 1.3 1z"/>
<path fill="#ad1519" d="M332.4 225.7s-.8.8-1.3 1c-.6 0-1.3-.6-1.3-.6s-.5.5-1.1.7-1.4-.7-1.4-.7-.6.8-1.2 1-1.1-.2-1.1-.2-.2.4-.7.6h-.5l-.6-.5-.7-.7-.6-.2-.3-1.1-.1-.6q0-1.1 2.4-1.8 1.2-.2 2 0a6 6 0 0 1 3.3-.8 6 6 0 0 1 3.2.7 6 6 0 0 1 3-.7q2.3 0 3.3.8a4 4 0 0 1 2.1 0q2.4.7 2.4 1.8v.6l-.4 1-.6.3-.7.8-.6.3s-.3.2-.5.1q-.7-.4-.7-.6c0-.2-.6.4-1.2.2s-1-1-1-1-.9.8-1.5.7q-1-.5-1.1-.7c-.1-.2-.7.6-1.2.5s-1.4-.9-1.4-.9"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M332.4 225.7s-.8.8-1.3 1c-.6 0-1.3-.6-1.3-.6s-.5.5-1.1.7-1.4-.7-1.4-.7-.6.8-1.2 1-1.1-.2-1.1-.2-.2.4-.7.6h-.5l-.6-.5-.7-.7-.6-.2-.3-1.1-.1-.6q0-1.1 2.4-1.8 1.2-.2 2 0a6 6 0 0 1 3.3-.8 6 6 0 0 1 3.2.7 6 6 0 0 1 3-.7q2.3 0 3.3.8a4 4 0 0 1 2.1 0q2.4.7 2.4 1.8v.6l-.4 1-.6.3-.7.8-.6.3s-.3.2-.5.1q-.7-.4-.7-.6c0-.2-.6.4-1.2.2s-1-1-1-1-.9.8-1.5.7q-1-.5-1.1-.7c-.1-.2-.7.6-1.2.5s-1.4-.9-1.4-.9z"/>
<path fill="#c8b100" d="M331 221.4q.1-1.8 1.3-2 1.3.2 1.4 2c.1 1.8-.6 2-1.4 2q-1.3-.2-1.4-2"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M331 221.4q.1-1.8 1.3-2 1.3.2 1.4 2c.1 1.8-.6 2-1.4 2q-1.3-.2-1.4-2z"/>
<path fill="#c8b100" d="M331.7 221.4c0-1 .3-1.9.7-1.9s.6.9.6 1.9q0 1.7-.7 1.8-.5-.2-.6-1.8"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M331.7 221.4c0-1 .3-1.9.7-1.9s.6.9.6 1.9q0 1.7-.7 1.8-.5-.2-.6-1.8z"/>
<path fill="#c8b100" d="m325 229.6-.5-1q3-1 7.8-1t8 1l-.6.9-.4.8q-2.7-.9-7-.8c-2.8 0-5.6.3-7 .8l-.2-.7"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m325 229.6-.5-1q3-1 7.8-1t8 1l-.6.9-.4.8q-2.7-.9-7-.8c-2.8 0-5.6.3-7 .8l-.2-.7"/>
<path fill="#c8b100" d="M332.3 232.2c2.5 0 5.3-.4 6.3-.7q1-.3 1-.8 0-.3-.4-.4a26 26 0 0 0-6.9-.9 26 26 0 0 0-6.8.9q-.4 0-.4.4t1 .8c1 .3 3.7.7 6.2.7"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M332.3 232.2c2.5 0 5.3-.4 6.3-.7q1-.3 1-.8 0-.3-.4-.4a26 26 0 0 0-6.9-.9 26 26 0 0 0-6.8.9q-.4 0-.4.4t1 .8c1 .3 3.7.7 6.2.7z"/>
<path fill="#fff" d="m338.4 222.3.4-.5q.5 0 .5.5 0 .3-.5.4z"/>
<path fill="none" stroke="#000" stroke-width=".2" d="m338.4 222.3.4-.5q.5 0 .5.5 0 .3-.5.4zm-.3-1.6.5-.4q.3 0 .4.4 0 .5-.4.5l-.5-.4zm-1.1-1 .4-.3q.5 0 .5.4t-.5.4l-.4-.4zm-1.5-.4q0-.3.5-.4l.4.4-.4.5q-.5 0-.5-.5zm-1.5 0 .5-.4q.5 0 .5.5t-.5.4z"/>
<path fill="none" stroke="#000" stroke-linecap="round" stroke-width=".3" d="m343 225.3.2-1.1a3 3 0 0 0-3-3l-1.3.4"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m337.8 223.2.3-.9c0-1.2-1.3-2.1-2.7-2.1q-1 0-1.7.4"/>
<path fill="none" stroke="#000" stroke-width=".2" d="M343.4 224q0-.5.4-.5.6 0 .5.4-.1.6-.5.5t-.4-.5zm-.2-1.7q0-.3.5-.4.3 0 .4.4 0 .5-.5.4t-.4-.4zm-1-1.2.4-.5q.5 0 .5.5t-.5.4l-.5-.4zm-1.5-.7q.1-.3.5-.4.5 0 .5.4l-.5.5-.4-.5zm-1.4 0q0-.3.4-.4.5 0 .5.5t-.5.4q-.6-.2-.4-.4z"/>
<path fill="#c8b100" d="m340.3 227.4-.6-.5s-.6.3-1.3.2-1-1-1-1-.7.7-1.4.6-1.1-.6-1.1-.6-.7.5-1.4.5-1.2-.9-1.2-.9-.7.9-1.3 1-1.1-.6-1.1-.6-.3.6-1.1.7-1.5-.6-1.5-.6-.5.7-1 1c-.6.1-1.3-.4-1.3-.4l-.2.5-.4.2.2.4a33 33 0 0 1 15.5.1z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m340.3 227.4-.6-.5s-.6.3-1.3.2-1-1-1-1-.7.7-1.4.6-1.1-.6-1.1-.6-.7.5-1.4.5-1.2-.9-1.2-.9-.7.9-1.3 1-1.1-.6-1.1-.6-.3.6-1.1.7-1.5-.6-1.5-.6-.5.7-1 1c-.6.1-1.3-.4-1.3-.4l-.2.5-.4.2.2.4a33 33 0 0 1 15.5.1z"/>
<path fill="#fff" d="m325.3 222.3.5-.5.4.5-.4.4q-.5 0-.5-.4"/>
<path fill="none" stroke="#000" stroke-width=".2" d="m325.3 222.3.5-.5.4.5-.4.4q-.5 0-.5-.4zm.3-1.6.4-.4.5.4-.5.5a.4.4 0 0 1-.4-.4zm1.1-1q0-.2.5-.3t.5.4q-.1.6-.5.4l-.5-.4zm1.5-.4q0-.3.4-.4.5 0 .5.4t-.5.5q-.4 0-.4-.5zm1.5 0 .4-.4.5.5q0 .3-.5.4z"/>
<path fill="none" stroke="#000" stroke-linecap="round" stroke-width=".3" d="m321.7 225.3-.3-1.1a3 3 0 0 1 3-3q.7 0 1.3.4"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m326.9 223.2-.3-.9c0-1.2 1.2-2.1 2.7-2.1q1 0 1.6.4"/>
<path fill="none" stroke="#000" stroke-width=".2" d="M320.3 224q0-.5.5-.5t.5.4l-.5.5q-.5 0-.5-.5zm.2-1.7q0-.3.5-.4.6 0 .4.4t-.4.4zm1-1.2q.1-.5.5-.5l.5.5-.5.4-.4-.4zm1.5-.7.4-.4q.5 0 .5.4l-.5.5-.5-.5zm1.4 0q0-.3.5-.4l.4.5q0 .3-.4.4-.5 0-.5-.4z"/>
<path fill="#c8b100" d="M332.4 224.8h.2v.4q.1 1 1.1 1 .8 0 1.1-.7l.2-.4v.5q.2.8 1.1.9a1 1 0 0 0 1.2-1.1v-.1l.3-.4.2.4v.5q0 1 1 1a1 1 0 0 0 1-.4l.1-.3v.4q0 .5.5.7l1-.4.8-.8v.5s-.5.8-1 1.1l-1 .3q-.5-.2-.6-.7l-.8.3q-1.1 0-1.5-1a2 2 0 0 1-1.2.6 2 2 0 0 1-1.3-.6q-.5.4-1 .4a2 2 0 0 1-1.5-.7 2 2 0 0 1-2.4.3 2 2 0 0 1-1.3.6q-.8 0-1.2-.5-.4.8-1.5.8l-.8-.2q-.1.5-.7.7l-1-.3-1-1.1v-.5l1 .8q.7.5.8.4.5-.1.5-.7v-.4l.3.3q.3.5.9.5 1-.1 1-1v-.6l.2-.4.3.4q.1 1.1 1.1 1.2t1.2-1v-.3l.2.3q.3.8 1 .8a1.1 1.1 0 0 0 1.2-1.5z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M332.4 224.8h.2v.4q.1 1 1.1 1 .8 0 1.1-.7l.2-.4v.5q.2.8 1.1.9a1 1 0 0 0 1.2-1.1v-.1l.3-.4.2.4v.5q0 1 1 1a1 1 0 0 0 1-.4l.1-.3v.4q0 .5.5.7l1-.4.8-.8v.5s-.5.8-1 1.1l-1 .3q-.5-.2-.6-.7l-.8.3q-1.1 0-1.5-1a2 2 0 0 1-1.2.6 2 2 0 0 1-1.3-.6q-.5.4-1 .4a2 2 0 0 1-1.5-.7 2 2 0 0 1-2.4.3 2 2 0 0 1-1.3.6q-.8 0-1.2-.5-.4.8-1.5.8l-.8-.2q-.1.5-.7.7l-1-.3-1-1.1v-.5l1 .8q.7.5.8.4.5-.1.5-.7v-.4l.3.3q.3.5.9.5 1-.1 1-1v-.6l.2-.4.3.4q.1 1.1 1.1 1.2t1.2-1v-.3l.2.3q.3.8 1 .8a1.1 1.1 0 0 0 1.2-1.5z"/>
<path fill="#c8b100" d="M332.3 227.6q-4.6 0-7.8 1l-.4-.2.2-.4q3.2-1 8-1c4.8 0 6 .4 8 1q.3 0 .2.3t-.3.2q-3.1-1-7.9-1"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M332.3 227.6q-4.6 0-7.8 1l-.4-.2.2-.4q3.2-1 8-1c4.8 0 6 .4 8 1q.3 0 .2.3t-.3.2q-3.1-1-7.9-1z"/>
<path fill="#fff" d="M329.4 228.7q0-.5.4-.5t.5.5q-.1.3-.5.4-.5 0-.5-.4"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M329.4 228.7q0-.5.4-.5t.5.5q-.1.3-.5.4-.5 0-.5-.4z"/>
<path fill="#ad1519" d="M332.4 228.8h-1q-.4 0-.4-.3t.4-.3h2l.3.3q0 .3-.3.3z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M332.4 228.8h-1q-.4 0-.4-.3t.4-.3h2l.3.3q0 .3-.3.3h-1"/>
<path fill="#058e6e" d="M327.4 229.2h-.7a.3.3 0 0 1-.4-.2l.3-.3.7-.1.7-.2q.3 0 .4.3 0 .3-.3.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M327.4 229.2h-.7a.3.3 0 0 1-.4-.2l.3-.3.7-.1.7-.2q.3 0 .4.3 0 .3-.3.4h-.7"/>
<path fill="#ad1519" d="m324.5 229.7.4-.5.6.1-.4.6z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m324.5 229.7.4-.5.6.1-.4.6-.6-.2"/>
<path fill="#fff" d="M334.4 228.7q0-.5.5-.5t.4.5q0 .3-.4.4-.5 0-.5-.4"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M334.4 228.7q0-.5.5-.5t.4.5q0 .3-.4.4-.5 0-.5-.4z"/>
<path fill="#058e6e" d="M337.3 229.2h.7q.3.1.4-.2l-.3-.3-.7-.1-.7-.2q-.3 0-.4.3 0 .3.3.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M337.3 229.2h.7q.3.1.4-.2l-.3-.3-.7-.1-.7-.2q-.3 0-.4.3 0 .3.3.4h.7"/>
<path fill="#ad1519" d="m340.1 229.7-.3-.5h-.7l.4.6z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m340.1 229.7-.3-.5h-.7l.4.6h.6"/>
<path fill="#ad1519" d="M332.3 231.6a27 27 0 0 1-6.4-.7 28 28 0 0 1 13 0 27 27 0 0 1-6.6.7"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".3" d="M332.3 231.6a27 27 0 0 1-6.4-.7 28 28 0 0 1 13 0 27 27 0 0 1-6.6.7z"/>
<path fill="#c8b100" d="m340.2 226.2-.1-.4q-.3 0-.4.2l.1.5q.3 0 .4-.3"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m340.2 226.2-.1-.4q-.3 0-.4.2l.1.5q.3 0 .4-.3z"/>
<path fill="#c8b100" d="M335.2 225.2q0-.3-.2-.4-.2 0-.3.4t.2.4.3-.4"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M335.2 225.2q0-.3-.2-.4-.2 0-.3.4t.2.4.3-.4z"/>
<path fill="#c8b100" d="M329.5 225.2q0-.3.2-.4.2 0 .3.4t-.2.4-.3-.4"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M329.5 225.2q0-.3.2-.4.2 0 .3.4t-.2.4-.3-.4z"/>
<path fill="#c8b100" d="m324.5 226.2.1-.4q.3 0 .4.2l-.1.5q-.3 0-.4-.3"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m324.5 226.2.1-.4q.3 0 .4.2l-.1.5q-.3 0-.4-.3z"/>
<path fill="#c8b100" d="m332.3 222.4-.8.5.6 1.4.2.2.3-.2.6-1.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m332.3 222.4-.8.5.6 1.4.2.2.3-.2.6-1.4-.9-.5"/>
<path fill="#c8b100" d="m330.4 224.5.4.6 1.4-.4.1-.2-.1-.2-1.4-.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m330.4 224.5.4.6 1.4-.4.1-.2-.1-.2-1.4-.4-.4.6"/>
<path fill="#c8b100" d="m334.3 224.5-.4.6-1.4-.4-.1-.2.1-.2 1.4-.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m334.3 224.5-.4.6-1.4-.4-.1-.2.1-.2 1.4-.4.4.6"/>
<path fill="#c8b100" d="m326.6 223-.7.6 1 1.2.2.1.1-.2.3-1.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m326.6 223-.7.6 1 1.2.2.1.1-.2.3-1.4-.9-.3"/>
<path fill="#c8b100" d="m325.2 225.3.5.5 1.2-.7.1-.2-.1-.2h-1.5z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m325.2 225.3.5.5 1.2-.7.1-.2-.1-.2h-1.5l-.2.6"/>
<path fill="#c8b100" d="m329 224.6-.3.6-1.4-.1-.2-.2v-.2l1.3-.7z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m329 224.6-.3.6-1.4-.1-.2-.2v-.2l1.3-.7.6.6"/>
<path fill="#c8b100" d="m323.8 225.5-.1.7-1.5.1h-.2v-.3l1.2-1z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m323.8 225.5-.1.7-1.5.1h-.2v-.3l1.2-1 .6.5"/>
<path fill="#c8b100" d="M326.6 225a.5.5 0 0 1 .5-.6l.5.5-.5.5z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M326.6 225a.5.5 0 0 1 .5-.6l.5.5-.5.5z"/>
<path fill="#c8b100" d="m338 223 .8.6-1 1.2-.2.1-.1-.2-.3-1.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m338 223 .8.6-1 1.2-.2.1-.1-.2-.3-1.4.9-.3"/>
<path fill="#c8b100" d="m339.5 225.3-.5.5-1.3-.7v-.2l.1-.2h1.5z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m339.5 225.3-.5.5-1.3-.7v-.2l.1-.2h1.5l.2.6"/>
<path fill="#c8b100" d="m335.7 224.6.3.6 1.4-.1.2-.2v-.2l-1.3-.7z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m335.7 224.6.3.6 1.4-.1.2-.2v-.2l-1.3-.7-.6.6"/>
<path fill="#c8b100" d="m340.7 225.5.1.7 1.4.1h.3v-.3l-1.2-1z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m340.7 225.5.1.7 1.4.1h.3v-.3l-1.2-1-.6.5"/>
<path fill="#c8b100" d="M331.8 224.5q.1-.5.5-.5.6 0 .5.5 0 .3-.5.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M331.8 224.5q.1-.5.5-.5.6 0 .5.5 0 .3-.5.4z"/>
<path fill="#c8b100" d="M337.1 225a.5.5 0 0 1 .5-.6q.5 0 .5.5t-.5.5z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M337.1 225a.5.5 0 0 1 .5-.6q.5 0 .5.5t-.5.5z"/>
<path fill="#c8b100" d="M331.4 219q0-.7 1-.8c1-.1.9.4.9.9s-.4.9-1 .9a1 1 0 0 1-.9-1"/>
<path fill="#c8b100" d="M333 218.8v.6h-1.5v-.6h.5v-1.4h-.6v-.6h.6v-.5h.7v.5h.6v.6h-.6v1.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M333 218.8v.6h-1.5v-.6h.5v-1.4h-.6v-.6h.6v-.5h.7v.5h.6v.6h-.6v1.4z"/>
<path fill="#c8b100" d="M333.7 218.8v.6H331v-.6h1v-1.4h-.7v-.6h.6v-.5h.7v.5h.6v.6h-.6v1.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M332.6 218.2a1 1 0 0 1 .7.9q0 .8-1 .9a1 1 0 0 1-.9-1q0-.6.7-.8"/>
<path fill="#c8b100" d="m321.9 226.3-.7-.8-.7-.3s.3-.3.6-.3l.5.2v-.2s.2 0 .3.4v.7z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m321.9 226.3-.7-.8-.7-.3s.3-.3.6-.3l.5.2v-.2s.2 0 .3.4v.7z"/>
<path fill="#c8b100" d="m321.9 226 .5.1q.4.3.1.5h-.5q-.3-.3-.1-.5"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m321.9 226 .5.1q.4.3.1.5h-.5q-.3-.3-.1-.5z"/>
<path fill="#c8b100" d="m342.6 226.3.7-.8.7-.3s-.3-.3-.6-.3l-.5.2v-.2s-.3 0-.4.4v.7z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m342.6 226.3.7-.8.7-.3s-.3-.3-.6-.3l-.5.2v-.2s-.3 0-.4.4v.7z"/>
<path fill="#c8b100" d="m342.6 226-.5.1q-.3.3-.1.5t.5 0q.4-.3.1-.5"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m342.6 226-.5.1q-.3.3-.1.5t.5 0q.4-.3.1-.5z"/>
<path fill="#c8b100" d="M321 238h22.8v-6h-22.9z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M321 238h22.8v-6h-22.9z"/>
<path fill="#c8b100" d="m341.4 242-.4-.1h-17.6q1-.3 1-1.3-.1-1-1-1.4l.4.1h17.6q-1 .3-1 1.3t1 1.3"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".4" d="m341.4 242-.4-.1h-17.6q1-.3 1-1.3-.1-1-1-1.4l.4.1h17.6q-1 .3-1 1.3t1 1.3z"/>
<path fill="#c8b100" d="M323.9 241.9h17q1 0 1.1.8-.1.7-1 .8h-17.1q-1-.1-1-.8t1-.8"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M323.9 241.9h17q1 0 1.1.8-.1.7-1 .8h-17.1q-1-.1-1-.8t1-.8z"/>
<path fill="#c8b100" d="M323.9 238h17q1 0 1.1.6-.1.7-1 .7h-17.1q-1 0-1.1-.7.1-.7 1-.7"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M323.9 238h17q1 0 1.1.6-.1.7-1 .7h-17.1q-1 0-1.1-.7.1-.7 1-.7z"/>
<path fill="#005bbf" d="M316.4 338.6q2.5 0 4-.9a9 9 0 0 1 4-.8q2.4 0 4 .8 1.6 1 4 1a9 9 0 0 0 4-1 9 9 0 0 1 4-.8q2.3 0 3.9.8 1.6 1 4 1v2.4a9 9 0 0 1-4-1 9 9 0 0 0-4-.8q-2.2 0-3.9.9a9 9 0 0 1-4 .9 9 9 0 0 1-4-.9 9 9 0 0 0-4-.9q-2.4 0-4 .9a9 9 0 0 1-4 .9z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M316.4 338.6q2.5 0 4-.9a9 9 0 0 1 4-.8q2.4 0 4 .8 1.6 1 4 1a9 9 0 0 0 4-1 9 9 0 0 1 4-.8q2.3 0 3.9.8 1.6 1 4 1v2.4a9 9 0 0 1-4-1 9 9 0 0 0-4-.8q-2.2 0-3.9.9a9 9 0 0 1-4 .9 9 9 0 0 1-4-.9 9 9 0 0 0-4-.9q-2.4 0-4 .9a9 9 0 0 1-4 .9z"/>
<path fill="#ccc" d="M316.4 341a9 9 0 0 0 4-.8 9 9 0 0 1 4-.8q2.4 0 4 .8a9 9 0 0 0 4 .9q2.5 0 4-1a9 9 0 0 1 4-.8 8 8 0 0 1 3.9.9 9 9 0 0 0 4 .9v2.4a9 9 0 0 1-4-.9 9 9 0 0 0-4-.8q-2.2 0-3.9.8a9 9 0 0 1-4 1 9 9 0 0 1-4-1 9 9 0 0 0-4-.8 9 9 0 0 0-4 .9 9 9 0 0 1-4 .9z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M316.4 341a9 9 0 0 0 4-.8 9 9 0 0 1 4-.8q2.4 0 4 .8a9 9 0 0 0 4 .9q2.5 0 4-1a9 9 0 0 1 4-.8 8 8 0 0 1 3.9.9 9 9 0 0 0 4 .9v2.4a9 9 0 0 1-4-.9 9 9 0 0 0-4-.8q-2.2 0-3.9.8a9 9 0 0 1-4 1 9 9 0 0 1-4-1 9 9 0 0 0-4-.8 9 9 0 0 0-4 .9 9 9 0 0 1-4 .9V341"/>
<path fill="#005bbf" d="M316.4 343.6q2.5 0 4-1a9 9 0 0 1 4-.8 9 9 0 0 1 4 .9q1.6.8 4 .9 2.5 0 4-1a9 9 0 0 1 4-.8q2.3 0 3.9.8 1.6 1 4 1v2.4a9 9 0 0 1-4-.9 9 9 0 0 0-4-.8 9 9 0 0 0-3.9.8 9 9 0 0 1-4 1 9 9 0 0 1-4-1 9 9 0 0 0-4-.8q-2.4 0-4 .8a9 9 0 0 1-4 1v-2.6"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M316.4 343.6q2.5 0 4-1a9 9 0 0 1 4-.8 9 9 0 0 1 4 .9q1.6.8 4 .9 2.5 0 4-1a9 9 0 0 1 4-.8q2.3 0 3.9.8 1.6 1 4 1v2.4a9 9 0 0 1-4-.9 9 9 0 0 0-4-.8 9 9 0 0 0-3.9.8 9 9 0 0 1-4 1 9 9 0 0 1-4-1 9 9 0 0 0-4-.8q-2.4 0-4 .8a9 9 0 0 1-4 1v-2.6"/>
<path fill="#ccc" d="M316.4 348.5a9 9 0 0 0 4-1 9 9 0 0 1 4-.7 9 9 0 0 1 4 .8q1.6.8 4 .9 2.5 0 4-1a9 9 0 0 1 4-.7q2.3 0 3.9.8t4 .9V346a9 9 0 0 1-4-.9 9 9 0 0 0-4-.8 9 9 0 0 0-3.9.8 9 9 0 0 1-4 1 9 9 0 0 1-4-1 9 9 0 0 0-4-.8 9 9 0 0 0-4 .8 9 9 0 0 1-4 1z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M316.4 348.5a9 9 0 0 0 4-1 9 9 0 0 1 4-.7 9 9 0 0 1 4 .8q1.6.8 4 .9 2.5 0 4-1a9 9 0 0 1 4-.7q2.3 0 3.9.8t4 .9V346a9 9 0 0 1-4-.9 9 9 0 0 0-4-.8 9 9 0 0 0-3.9.8 9 9 0 0 1-4 1 9 9 0 0 1-4-1 9 9 0 0 0-4-.8 9 9 0 0 0-4 .8 9 9 0 0 1-4 1v2.4"/>
<path fill="#005bbf" d="M316.4 351q2.5 0 4-1a9 9 0 0 1 4-.8 9 9 0 0 1 4 .9q1.6.8 4 .8 2.5 0 4-.9a9 9 0 0 1 4-.8q2.3 0 3.9.8 1.6 1 4 1v-2.5a9 9 0 0 1-4-1 9 9 0 0 0-4-.7q-2.2 0-3.9.8a9 9 0 0 1-4 .9 9 9 0 0 1-4-.9 9 9 0 0 0-4-.8 9 9 0 0 0-4 .8 9 9 0 0 1-4 .9z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M316.4 351q2.5 0 4-1a9 9 0 0 1 4-.8 9 9 0 0 1 4 .9q1.6.8 4 .8 2.5 0 4-.9a9 9 0 0 1 4-.8q2.3 0 3.9.8 1.6 1 4 1v-2.5a9 9 0 0 1-4-1 9 9 0 0 0-4-.7q-2.2 0-3.9.8a9 9 0 0 1-4 .9 9 9 0 0 1-4-.9 9 9 0 0 0-4-.8 9 9 0 0 0-4 .8 9 9 0 0 1-4 .9z"/>
<path fill="#c8b100" d="m341.4 328.5-.2.6c0 1.5 1.3 2.7 3 2.7h-23.6c1.6 0 2.9-1.2 2.9-2.7v-.6z"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".4" d="m341.4 328.5-.2.6c0 1.5 1.3 2.7 3 2.7h-23.6c1.6 0 2.9-1.2 2.9-2.7v-.6z"/>
<path fill="#c8b100" d="M323.9 327h17q1 0 1.1.7-.1.8-1 .8h-17.1q-1 0-1-.8 0-.7 1-.8"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M323.9 327h17q1 0 1.1.7-.1.8-1 .8h-17.1q-1 0-1-.8 0-.7 1-.8z"/>
<path fill="#c8b100" d="M320.7 337.8H344v-6h-23.4z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M320.7 337.8H344v-6h-23.4z"/>
<path fill="#ad1519" d="M346 305.8c2.2 1.3 3.8 2.7 3.6 3.4q-.4.8-2 1.8c-1.6 1.1-2.6 3.2-1.8 4.1a6 6 0 0 1 .1-9.3"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M346 305.8c2.2 1.3 3.8 2.7 3.6 3.4q-.4.8-2 1.8c-1.6 1.1-2.6 3.2-1.8 4.1a6 6 0 0 1 .1-9.3z"/>
<path fill="#ccc" d="M324 326h16.7v-81.6h-16.6z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M336.2 244.4v81.4m1.8-81.4v81.4m-14 .2h16.7v-81.6h-16.6z"/>
<path fill="#ad1519" d="M307 275a53 53 0 0 1 25-2.2c9.9 1.7 17.5 5.6 16.9 8.9v.2s3.7-8.4 3.7-8.7c.7-3.6-7.7-8-18.8-9.8a57 57 0 0 0-9.8-.8c-7 0-13.2.9-16.9 2.3v10"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".4" d="M307 275a53 53 0 0 1 25-2.2c9.9 1.7 17.5 5.6 16.9 8.9v.2s3.7-8.4 3.7-8.7c.7-3.6-7.7-8-18.8-9.8a57 57 0 0 0-9.8-.8c-7 0-13.2.9-16.9 2.3v10"/>
<path fill="#ad1519" d="M340.8 285.1c4.6-.3 7.7-1.5 8-3.5q.4-2.4-4-4.7l-4 .3v8"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M340.8 285.1c4.6-.3 7.7-1.5 8-3.5q.4-2.4-4-4.7l-4 .3v8"/>
<path fill="#ad1519" d="M324 279q-4.4.5-6 2l-.2.1c-.5 1 2 3.3 6.3 5.8v-8"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M324 279q-4.4.5-6 2l-.2.1c-.5 1 2 3.3 6.3 5.8v-8"/>
<path fill="#ad1519" d="M351.1 300.9c.4-1.3-4-4-10.4-6.3-3-1-5.3-2.1-8.3-3.4-8.8-4-15.4-8.4-14.6-10l.1-.2c-.4.4-1.2 8.4-1.2 8.4-.8 1.5 5.2 6 13.3 9.8 2.6 1.3 8.1 3.3 10.7 4.2 4.7 1.6 9.3 4.7 8.9 5.8z"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".4" d="M351.1 300.9c.4-1.3-4-4-10.4-6.3-3-1-5.3-2.1-8.3-3.4-8.8-4-15.4-8.4-14.6-10l.1-.2c-.4.4-1.2 8.4-1.2 8.4-.8 1.5 5.2 6 13.3 9.8 2.6 1.3 8.1 3.3 10.7 4.2 4.7 1.6 9.3 4.7 8.9 5.8z"/>
<path fill="#c8b100" d="M317.5 271.3q1-3.6 2.2-7l-.5.1h-.6q-.6 2.6-1.5 5.1l-2.9-4.4-1 .2-1 .1 4.2 6h1.1m6.3-7H322l-.2 6.5h4.6v-.8l-2.7.1zm7.3 1.1 2.1.3v-.4l.1-.4-6.2-.5v.8h2.2l-.6 6h1l.8.1zm2.5 6.5 1 .2.8.2.7-3h.1l.5 1.2 1 2.3 1 .2 1.1.2-.3-.6-1.5-3.1q1.8 0 2.3-1.3.2-1-.7-1.6l-1.9-.6-2.5-.5zm3.2-5.6c.8.2 1.7.3 1.7 1.1v.5q-.4 1.5-2.3 1zm8.7 7.6-.3 2.1.9.5.9.5.6-7.4-.8-.4-6.6 4.1.6.3.4.3 1.8-1.4zm-1.9-1.7 2.2-1.4-.3 2.4z"/>
<path fill="none" stroke="#000" stroke-width=".1" d="M230.3 205.3c0-1.2 1-2.1 2.2-2.1q2.1.2 2.3 2c0 1.2-1 2.2-2.3 2.2a2 2 0 0 1-2.2-2.1z"/>
<path fill="#ad1519" stroke="#000" stroke-width=".3" d="M255.3 187.1c6.8 0 13 1 16.8 2.6a32 32 0 0 0 8.6 2.2q4 .5 7 .2c2.9 0 6.9.8 11 2.6a29 29 0 0 1 8 5l-1.7 1.5-.4 4-4.4 5-2.2 2-5.3 4-2.6.3-.8 2.3-33.7-4-33.8 4-.9-2.3-2.6-.2-5.2-4.2-2.2-1.9-4.4-5-.5-4-1.6-1.5a30 30 0 0 1 8-5c4-1.8 8-2.6 10.9-2.6q3 .3 7-.2a32 32 0 0 0 8.6-2.2q6.1-2.5 16.4-2.6z"/>
<path fill="#c8b100" stroke="#000" stroke-width=".4" d="M255.9 231.6c-12.6 0-23.8-1.5-31.9-4q-1-.2-.8-1.2a1 1 0 0 1 .8-1.2 120 120 0 0 1 31.9-4c12.5.1 23.8 1.6 31.8 4q.9.4.9 1.2 0 1-1 1.3a119 119 0 0 1-31.7 4"/>
<path fill="#ad1519" d="M255.8 230a121 121 0 0 1-29.3-3.4c7.8-2 18-3.2 29.3-3.2a123 123 0 0 1 29.5 3.2c-7.8 2-18.1 3.4-29.5 3.4"/>
<path fill="none" stroke="#000" stroke-width=".1" d="M256.7 230v-6.7m-1.9 6.7v-6.7"/>
<path fill="none" stroke="#000" stroke-width=".2" d="M253.1 230v-6.7m-1.7 6.7v-6.7"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M249.9 230v-6.7m-2.9 6.4v-6.2m1.4 6.2v-6.4"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M244.3 229.4v-5.7m1.4 5.9v-6m-5 5.4v-4.9m1.2 5V224m1.2 5.4V224"/>
<path fill="none" stroke="#000" stroke-width=".5" d="M239.4 229v-4.8m-1.1 4.6v-4.5"/>
<path fill="none" stroke="#000" stroke-width=".6" d="M237 228.7v-4.2m-2.6 3.8V225m1.4 3.5v-3.7"/>
<path fill="none" stroke="#000" stroke-width=".7" d="M233.1 228v-2.9m-1.2 2.7v-2.4"/>
<path fill="none" stroke="#000" stroke-width=".8" d="M230.6 227.5v-2m-1.4 1.8v-1.4"/>
<path fill="none" stroke="#000" stroke-width=".9" d="M227.8 227v-.7"/>
<path fill="none" stroke="#000" stroke-width=".1" d="M264 229.7v-6.2m-3.2 6.4v-6.6m-2.2 6.6v-6.6"/>
<path fill="#c8b100" stroke="#000" stroke-width=".4" d="M255.8 221.3a115 115 0 0 0-32.2 4c.7-.3.6-1-.2-3.2-1-2.6-2.6-2.5-2.6-2.5a130 130 0 0 1 35-4.3c13.8 0 26.2 1.7 35.1 4.3 0 0-1.5-.1-2.5 2.5q-1.3 3-.3 3.3c-8-2.5-19.6-4.1-32.3-4.1"/>
<path fill="#c8b100" stroke="#000" stroke-width=".4" d="M255.8 215.3a131 131 0 0 0-35 4.3q-1 .3-1.4-.6a1 1 0 0 1 .8-1.4c8.9-2.7 21.6-4.4 35.6-4.4s26.9 1.7 35.8 4.4q1 .5.7 1.4t-1.4.6c-8.9-2.6-21.3-4.2-35-4.3"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".4" d="M255.8 230a121 121 0 0 1-29.3-3.4c7.8-2 18-3.2 29.3-3.2a123 123 0 0 1 29.5 3.2c-7.8 2-18.1 3.4-29.5 3.4z"/>
<path fill="#fff" stroke="#000" stroke-width=".4" d="M246 218.5q.1-1 1.1-1.1 1.1.1 1.2 1t-1.2 1.1a1 1 0 0 1-1-1"/>
<path fill="#ad1519" stroke="#000" stroke-width=".4" d="M255.9 219.3h-3.4q-1-.1-1.1-1 .1-1 1-1.1h6.9a1 1 0 0 1 1.1 1q-.1 1-1.1 1.1h-3.4"/>
<path fill="#058e6e" stroke="#000" stroke-width=".4" d="m239 220.2-2.5.3q-1 0-1.2-1a1 1 0 0 1 1-1.1l2.4-.3 2.5-.3a1 1 0 0 1 1.2 1q0 .9-1 1.1l-2.5.3"/>
<path fill="#fff" stroke="#000" stroke-width=".4" d="M229.1 220.4q.1-.9 1.1-1a1 1 0 0 1 1.2 1q0 1-1.2 1.1a1 1 0 0 1-1-1"/>
<path fill="#ad1519" stroke="#000" stroke-width=".4" d="m221.6 222.4 1.3-1.7 3.4.5-2.7 2-2-.8"/>
<path fill="#058e6e" stroke="#000" stroke-width=".4" d="m272.8 220.2 2.4.3q1 0 1.3-1a1 1 0 0 0-1-1.1l-2.5-.3-2.4-.3q-1.1 0-1.3 1 0 .9 1 1.1l2.5.3"/>
<path fill="#fff" stroke="#000" stroke-width=".4" d="M263.4 218.5q.2-1 1.2-1.1c1-.1 1.1.5 1.1 1q-.1 1-1.1 1.1a1 1 0 0 1-1.2-1m17 2q.1-1 1-1.1a1 1 0 0 1 1.2 1q-.1 1-1.1 1.1a1 1 0 0 1-1.1-1"/>
<path fill="#ad1519" stroke="#000" stroke-width=".4" d="m290 222.4-1.2-1.7-3.4.5 2.8 2 1.9-.8"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M225.1 227c8-2.3 18.7-3.6 30.7-3.7 12 0 22.9 1.4 30.8 3.7"/>
<path fill="#c8b100" d="m230.4 196 1.5 1.1 2.1-3.4a8 8 0 0 1-3.8-7.6c.2-4.5 5.6-8.1 12.5-8.1q5.4.1 9 2.5l.2-1.9a19 19 0 0 0-9.2-2.3c-8 0-14.1 4.4-14.4 9.8a10 10 0 0 0 3.3 8z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="m230.4 196 1.5 1.1 2.1-3.4a8 8 0 0 1-3.8-7.6c.2-4.5 5.6-8.1 12.5-8.1q5.4.1 9 2.5l.2-1.9a19 19 0 0 0-9.2-2.3c-8 0-14.1 4.4-14.4 9.8a10 10 0 0 0 3.3 8l-1.2 2"/>
<path fill="#c8b100" d="M230.5 196a10 10 0 0 1-4.3-7.7c0-3.5 2.2-6.6 5.7-8.6a9 9 0 0 0-3.6 6.4 10 10 0 0 0 3.3 8l-1 2"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M230.5 196a10 10 0 0 1-4.3-7.7c0-3.5 2.2-6.6 5.7-8.6a9 9 0 0 0-3.6 6.4 10 10 0 0 0 3.3 8l-1 2"/>
<path fill="#c8b100" d="M206.8 199.6a9 9 0 0 1-2.5-6.3q0-2.2 1-4c2.1-4.5 9-7.8 17.1-7.8q3.4 0 6.3.7-.7.8-1 1.5a27 27 0 0 0-5.3-.5c-7.4 0-13.6 3-15.4 6.8a8 8 0 0 0-.8 3.3 8 8 0 0 0 2.9 6l-2.7 4.4-1.5-1.2z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M206.8 199.6a9 9 0 0 1-2.5-6.3q0-2.2 1-4c2.1-4.5 9-7.8 17.1-7.8q3.4 0 6.3.7-.7.8-1 1.5a27 27 0 0 0-5.3-.5c-7.4 0-13.6 3-15.4 6.8a8 8 0 0 0-.8 3.3 8 8 0 0 0 2.9 6l-2.7 4.4-1.5-1.2z"/>
<path fill="#c8b100" d="M209.5 184.8a11 11 0 0 0-4.2 4.4 9 9 0 0 0-1 4.1q.1 3.7 2.5 6.3l-1.7 2.6a11 11 0 0 1-2.4-6.8c0-4.3 2.7-8.1 6.8-10.6"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M209.5 184.8a11 11 0 0 0-4.2 4.4 9 9 0 0 0-1 4.1q.1 3.7 2.5 6.3l-1.7 2.6a11 11 0 0 1-2.4-6.8c0-4.3 2.7-8.1 6.8-10.6z"/>
<path fill="#c8b100" d="M255.8 175.4c1.7 0 3.3 1.2 3.7 2.8q.3 2.1.4 4.7v1.2q.1 5.5 1.3 8.7l-5.5 5.2-5.5-5.2q1.1-3.2 1.3-8.7v-1.2q0-2.6.5-4.7c.3-1.6 2-2.8 3.7-2.8"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M255.8 175.4c1.7 0 3.3 1.2 3.7 2.8q.3 2.1.4 4.7v1.2q.1 5.5 1.3 8.7l-5.5 5.2-5.5-5.2q1.1-3.2 1.3-8.7v-1.2q0-2.6.5-4.7c.3-1.6 2-2.8 3.7-2.8z"/>
<path fill="#c8b100" d="M255.8 177a2 2 0 0 1 1.9 1.5l.4 4.5v1.1c0 3.4.5 6.4 1.2 8.2l-3.6 3.5-3.6-3.5c.7-1.8 1.2-4.8 1.2-8.2V183q0-2.4.5-4.5.4-1.3 2-1.4"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M255.8 177a2 2 0 0 1 1.9 1.5l.4 4.5v1.1c0 3.4.5 6.4 1.2 8.2l-3.6 3.5-3.6-3.5c.7-1.8 1.2-4.8 1.2-8.2V183q0-2.4.5-4.5.4-1.3 2-1.4z"/>
<path fill="#c8b100" d="m281 196-1.4 1.1-2.2-3.4a8 8 0 0 0 3.9-7.6c-.2-4.5-5.7-8.1-12.5-8.1a16 16 0 0 0-9 2.5l-.3-1.9a19 19 0 0 1 9.3-2.3c7.9 0 14 4.4 14.4 9.8a10 10 0 0 1-3.3 8z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="m281 196-1.4 1.1-2.2-3.4a8 8 0 0 0 3.9-7.6c-.2-4.5-5.7-8.1-12.5-8.1a16 16 0 0 0-9 2.5l-.3-1.9a19 19 0 0 1 9.3-2.3c7.9 0 14 4.4 14.4 9.8a10 10 0 0 1-3.3 8l1.1 1.9"/>
<path fill="#c8b100" d="M280.9 196q4.2-3.1 4.4-7.7c0-3.5-2.3-6.6-5.7-8.6a9 9 0 0 1 3.6 7.3q-.2 4.3-3.3 7.2l1 1.9"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M280.9 196q4.2-3.1 4.4-7.7c0-3.5-2.3-6.6-5.7-8.6a9 9 0 0 1 3.6 7.3q-.2 4.3-3.3 7.2l1 1.9"/>
<path fill="#c8b100" d="M304.7 199.6a9 9 0 0 0 1.5-10.3c-2.2-4.5-9-7.8-17.2-7.8a28 28 0 0 0-6.3.7l1.1 1.5a27 27 0 0 1 5.2-.5c7.5 0 13.7 3 15.5 6.8q.8 1.5.8 3.3a8 8 0 0 1-3 6l2.8 4.4 1.4-1.2z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M304.7 199.6a9 9 0 0 0 1.5-10.3c-2.2-4.5-9-7.8-17.2-7.8a28 28 0 0 0-6.3.7l1.1 1.5a27 27 0 0 1 5.2-.5c7.5 0 13.7 3 15.5 6.8q.8 1.5.8 3.3a8 8 0 0 1-3 6l2.8 4.4 1.4-1.2z"/>
<path fill="#c8b100" d="M302 184.8a11 11 0 0 1 4.2 4.4 9 9 0 0 1 1 4.1q-.1 3.7-2.5 6.3l1.6 2.6a11 11 0 0 0 2.5-6.8c0-4.3-2.7-8.1-6.9-10.6"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M302 184.8a11 11 0 0 1 4.2 4.4 9 9 0 0 1 1 4.1q-.1 3.7-2.5 6.3l1.6 2.6a11 11 0 0 0 2.5-6.8c0-4.3-2.7-8.1-6.9-10.6z"/>
<path fill="#fff" d="M253.8 193.5c0-1 .9-1.9 2-1.9 1 0 1.9.9 1.9 1.9a2 2 0 0 1-2 1.8 2 2 0 0 1-2-1.8"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M253.8 193.5c0-1 .9-1.9 2-1.9 1 0 1.9.9 1.9 1.9a2 2 0 0 1-2 1.8 2 2 0 0 1-2-1.8z"/>
<path fill="#fff" stroke="#000" stroke-width=".4" d="M253.8 189.8a2 2 0 0 1 2-1.8 2 2 0 0 1 1.9 1.9 2 2 0 0 1-2 1.8 2 2 0 0 1-2-1.8m.5-4q.1-1.3 1.5-1.4 1.5 0 1.6 1.5-.1 1.3-1.6 1.4-1.4-.1-1.5-1.4m.4-3.6q.1-.9 1.1-1a1 1 0 0 1 1.2 1q0 1-1.2 1.1a1 1 0 0 1-1-1m.1-3.1q0-.8 1-.9c1-.1.8.4.8.9s-.4.8-.9.8-.9-.3-.9-.8"/>
<path fill="#c8b100" stroke="#000" stroke-width=".4" d="m255.9 204.6 1.3.2a5 5 0 0 0 4.8 6.4 5 5 0 0 0 4.8-3.3s.4-1.7.6-1.7.2 1.9.3 1.9c.3 2.4 2.5 4 5 4a5 5 0 0 0 5-5.4l1.5-1.5.9 2a4 4 0 0 0-.5 2 4.7 4.7 0 0 0 4.8 4.6 5 5 0 0 0 4-2l1-1.3v1.6c0 1.5.7 3 2.2 3.2 0 0 1.8.1 4.1-1.7a28 28 0 0 0 3.7-3.4l.2 1.9s-2 3-4 4.2c-1.2.7-3 1.4-4.4 1.1s-2.6-1.4-3.1-2.7a7 7 0 0 1-3.6 1 7 7 0 0 1-6.5-4 7.5 7.5 0 0 1-11-.3 7 7 0 0 1-5 1.9 7 7 0 0 1-6.1-3.1 7 7 0 0 1-6.1 3 7 7 0 0 1-5-1.8 7.5 7.5 0 0 1-11 .3 7 7 0 0 1-6.5 4 7 7 0 0 1-3.6-1q-.9 2.2-3.1 2.8c-1.4.2-3.2-.5-4.3-1.2-2.2-1.2-4.1-4.3-4.1-4.3l.2-1.8s1.3 1.5 3.6 3.4c2.4 1.8 4.2 1.7 4.2 1.7 1.5-.2 2.2-1.7 2.2-3.2v-1.6l1 1.3a5 5 0 0 0 4 2c2.6 0 4.8-2 4.8-4.6q0-1-.5-2l.8-2 1.6 1.5v.6a5 5 0 0 0 5 4.8c2.5 0 4.7-1.7 5-4 0 0 0-1.9.2-1.9s.7 1.8.7 1.7a5 5 0 0 0 4.8 3.3 5 5 0 0 0 4.8-6.4l1.3-.2"/>
<path fill="#fff" stroke="#000" stroke-width=".4" d="M290.5 210.8c.3-.8 0-1.7-.6-1.8q-1.1-.2-1.6 1.2c-.3.8 0 1.7.5 1.8q1 .2 1.7-1.2m-22-4.2q.2-1.4-.9-1.7-1 0-1.3 1.4-.1 1.6 1 1.8 1 0 1.3-1.5m-25.4 0q-.1-1.4 1-1.7 1 0 1.3 1.4.1 1.6-1 1.8-1 0-1.3-1.5m-22 4.3q-.3-1.4.7-2 1-.1 1.6 1.3.4 1.4-.6 1.9-1 0-1.6-1.2"/>
<path fill="#c8b100" stroke="#000" stroke-width=".4" d="M230.8 196.3a6 6 0 0 1 2.4 3s0-.2.7-.6q1-.4 1.1-.3l-.2 1.4c-.1.3-.1 1.4-.4 2.3l-.6 1.8a2 2 0 0 0-1.6-.5 2 2 0 0 0-1.4 1s-.7-.6-1.2-1.4l-1.2-2.2-.7-1.2h1.1l1 .3a5 5 0 0 1 1-3.7"/>
<path fill="#c8b100" stroke="#000" stroke-width=".4" d="M231.3 206.7a2 2 0 0 1-.7-1.1 2 2 0 0 1 .2-1.3l-1.9-.7c-.7-.2-2-.2-2.4-.2h-1.2l.3.6.5.7a5 5 0 0 0-3 2.2 6 6 0 0 0 3.6 1l-.2.8v.7l1-.4c.4-.2 1.6-.6 2.2-1l1.6-1.3m2.9-.5.2-1.2a2 2 0 0 0-.7-1.1s.7-.8 1.5-1.3l2.3-1 1-.4v.6l-.2.9a6 6 0 0 1 3.7 1 5 5 0 0 1-3.1 2.1l.8 1.4h-1.2c-.4 0-1.7 0-2.4-.3-1-.2-2-.7-2-.7"/>
<path fill="#ad1519" stroke="#000" stroke-width=".4" d="M230.3 205.3c0-1.2 1-2.1 2.2-2.1q2.1.2 2.3 2c0 1.2-1 2.2-2.3 2.2a2 2 0 0 1-2.2-2.1"/>
<path fill="#c8b100" stroke="#000" stroke-width=".4" d="M255.8 192.9a6 6 0 0 1 2 3.9s.2-.3 1-.6 1.2-.1 1.2-.1l-.5 1.4c-.2.4-.4 1.6-.9 2.6l-1 1.8a2 2 0 0 0-1.8-.7q-1 0-1.7.7-.2 0-1-1.8c-.5-1-.7-2.2-.9-2.6l-.6-1.4s.6-.1 1.3.2q1.1.4 1 .5a6 6 0 0 1 2-4"/>
<path fill="#c8b100" stroke="#000" stroke-width=".4" d="M254.2 204.6a2 2 0 0 1-.6-1.3q0-.8.6-1.4s-1-.7-2-1.1c-.8-.4-2.2-.6-2.6-.7l-1.3-.3.1.7.4 1q-2.3.2-3.9 1.8a6 6 0 0 0 4 1.8l-.5 1-.2.6 1.4-.2 2.6-.7 2-1.2m3.3 0q.5-.5.5-1.3a2 2 0 0 0-.5-1.4s1-.7 2-1.1c.8-.4 2.2-.6 2.6-.7l1.3-.3-.2.7-.4 1a6 6 0 0 1 4 1.8 6 6 0 0 1-4 1.8l.4 1 .2.6-1.3-.2-2.6-.7-2-1.2m23.5-8.4a6 6 0 0 0-2.4 3.1l-.7-.6q-1-.4-1.1-.3l.2 1.4.3 2.3.7 1.8a2 2 0 0 1 1.6-.5 2 2 0 0 1 1.4 1l1.2-1.4 1.2-2.2.7-1.2h-1.2q-1 .2-.9.3a5 5 0 0 0-1-3.7"/>
<path fill="#c8b100" stroke="#000" stroke-width=".4" d="M280.5 206.7q.5-.5.7-1.1a2 2 0 0 0-.2-1.3l1.8-.7c.8-.2 2-.2 2.5-.2h1.1l-.2.6-.6.7a5 5 0 0 1 3.1 2.2 6 6 0 0 1-3.6 1l.2.8v.7l-1-.4-2.3-1-1.5-1.3m-2.9-.5-.3-1.2q.2-.8.7-1.1s-.7-.8-1.5-1.3c-.6-.4-1.8-.9-2.2-1l-1-.4v.6l.2.9a6 6 0 0 0-3.7 1q1.1 1.6 3 2.1l-.4.8-.3.6h1.2c.4 0 1.7 0 2.4-.3 1-.2 1.9-.7 1.9-.7"/>
<path fill="#ad1519" stroke="#000" stroke-width=".4" d="M277 205.3q.2-2 2.2-2.1 2.1.2 2.3 2c0 1.2-1 2.2-2.3 2.2a2 2 0 0 1-2.2-2.1m24.8 4.6c-.5-.5-1.6-.4-2.4.3s-1 1.7-.5 2.2 1.6.5 2.4-.2q1.2-1.2.5-2.3"/>
<path fill="#c8b100" stroke="#000" stroke-width=".4" d="M298.7 211.3q.1-.6.7-1.1c.8-.7 2-.8 2.4-.3l.2.3s1.2-2.1 2.5-2.9 3.6-.5 3.6-.5a3 3 0 0 0-3.1-3q-1.6 0-2.5 1.2l-.3-1.1s-1.4.3-2 1.8c-.6 1.7 0 4 0 4s-.3-1-.8-1.7a9 9 0 0 0-2.6-1.7l-1.4-.8v1.5a8 8 0 0 0-4 .5 5 5 0 0 0 2.7 2.3l-.8.8-.5.5 1.4.2c.4 0 1.8.3 2.7.2l1.8-.2m-85.6 0a2 2 0 0 0-.8-1.1c-.8-.7-1.9-.8-2.4-.3l-.2.3s-1-2.1-2.4-2.9-3.6-.5-3.6-.5a3 3 0 0 1 3-3q1.6 0 2.6 1.2l.2-1.1s1.4.3 2 1.9 0 3.9 0 3.9.4-1 .9-1.7 1.8-1.4 2.5-1.7l1.4-.8v1.5a8 8 0 0 1 4 .5 5 5 0 0 1-2.7 2.3l.9.8.4.5-1.3.2c-.4 0-1.9.3-2.7.2l-1.8-.2"/>
<path fill="#ad1519" stroke="#000" stroke-width=".4" d="M210 210q1-.9 2.3.2c.9.7 1 1.7.6 2.2q-1 .9-2.4-.2t-.6-2.3m43.7-6.6q.2-2 2.3-2.1c2.1-.1 2.2.9 2.2 2s-1 2.2-2.3 2.2a2 2 0 0 1-2.2-2.1"/>
<path fill="#005bbf" stroke="#000" stroke-width=".3" d="M251.2 171.3c0-2.4 2-4.3 4.6-4.3s4.5 2 4.5 4.3a4.4 4.4 0 0 1-4.5 4.3 4.4 4.4 0 0 1-4.6-4.3"/>
<path fill="#c8b100" stroke="#000" stroke-width=".3" d="M254.6 159.3v2.3H252v2.3h2.5v6.8h-3.2l-.2.6q0 1 .4 1.7h8.3l.4-1.7-.2-.6h-3V164h2.4v-2.3H257v-2.3z"/>
<path fill="#ccc" d="M256.2 352.6a87 87 0 0 1-37.8-8.8 24 24 0 0 1-13.7-21.6V288h102.8v34c0 9.5-5.4 17.7-13.7 21.8a86 86 0 0 1-37.6 8.7"/>
<path fill="none" stroke="#000" stroke-width=".5" d="M256.2 352.6a87 87 0 0 1-37.8-8.8 24 24 0 0 1-13.7-21.6V288h102.8v34c0 9.5-5.4 17.7-13.7 21.8a86 86 0 0 1-37.6 8.7z"/>
<path fill="#ccc" d="M256 288h51.5v-57H256z"/>
<path fill="none" stroke="#000" stroke-width=".5" d="M256 288h51.5v-57H256z"/>
<path fill="#ad1519" d="M256 322.1a25 25 0 0 1-25.6 24.4c-14.2 0-25.8-11-25.8-24.4V288H256v34"/>
<path fill="#c8b100" stroke="#000" stroke-width=".5" d="M215.8 342.3c1.7.8 3.9 2.2 6.2 2.8l-.1-58.3h-6v55.4z"/>
<path fill="#c8b100" stroke="#000" stroke-linejoin="round" stroke-width=".5" d="M204.5 321.7a26 26 0 0 0 6 16v-50.6h-5.9z"/>
<path fill="#c7b500" stroke="#000" stroke-width=".5" d="M227.3 346.4c2.4.2 4.1.2 6 0v-59.6h-6z"/>
<path fill="#c8b100" stroke="#000" stroke-width=".5" d="M238.6 345a20 20 0 0 0 6.2-2.6v-55.6h-6z"/>
<path fill="#ad1519" d="M204.6 288H256v-57h-51.4z"/>
<path fill="none" stroke="#000" stroke-width=".5" d="M204.6 288H256v-57h-51.4z"/>
<path fill="#c8b100" stroke="#000" stroke-width=".5" d="M250.4 337.1c2.5-2.2 4.9-7.3 5.7-13l.2-37.3h-6V337z"/>
<path fill="none" stroke="#000" stroke-width=".5" d="M256 322.1a25 25 0 0 1-25.6 24.4c-14.2 0-25.8-11-25.8-24.4V288H256v34"/>
<path fill="#ad1519" d="M307.6 288v34a25 25 0 0 1-25.8 24.4c-14.2 0-25.8-11-25.8-24.4v-34z"/>
<path fill="none" stroke="#000" stroke-width=".5" d="M307.6 288v34a25 25 0 0 1-25.8 24.4c-14.2 0-25.8-11-25.8-24.4v-34h51.6"/>
<path fill="#c8b100" d="m265.4 313.7.1.6q0 1-1.2 1.1-1-.1-1.2-1.1 0-.3.2-.5h-1.7a3 3 0 0 0 1.9 3v4.1h1.7v-4.1a3 3 0 0 0 1.8-1.7h4.7v-1.4zm23.1 0v1.4h-4.2l-.3.6 5 5.6-1.4 1-4.9-5.6-.2.1v9.3h-1.8v-9.3l-.2-.1-5 5.6-1.4-1 5.1-5.7-.2-.5h-4.4v-1.4h14zm2.8 0v1.4h4.8q.4 1.2 1.7 1.7v4.1h1.8v-4.1a3 3 0 0 0 2-2.5l-.2-.6h-1.6a1.2 1.2 0 0 1-1 1.7q-1.2-.1-1.3-1.1l.1-.5zm-7 23.5a17 17 0 0 0 3.8-1l.9 1.4a19 19 0 0 1-4.6 1.3 3 3 0 0 1-2.8 2 3 3 0 0 1-2.7-2 19 19 0 0 1-4.8-1.3l.8-1.5q2 .9 4.2 1.2a3 3 0 0 1 1.6-1.5v-7.1h1.8v7.1a3 3 0 0 1 1.7 1.4zm-11.8-2.4-.9 1.5a18 18 0 0 1-3.9-3.3 3 3 0 0 1-2.6-.5 2.5 2.5 0 0 1-.4-3.7l.2-.2a16 16 0 0 1-1.4-5.1h1.8a14 14 0 0 0 1.1 4.4l1.5.1 4.4-4.8 1.3 1-4.4 4.9a3 3 0 0 1 0 3 16 16 0 0 0 3.2 2.7zm-6.5-5a1.2 1.2 0 0 1 1.7-.2 1 1 0 0 1 0 1.6 1.3 1.3 0 0 1-1.6.2 1 1 0 0 1-.1-1.6m-2.2-4.8-1.8-.4-.3-4.6 1.8-.6v2.6l.2 3zm1.4-5.7 1.8.4v2.3c0-.8.3 2.3.3 2.3l-1.8.6-.3-2.9zm6 14.6a17 17 0 0 0 5.1 2.7l.4-1.7a15 15 0 0 1-4.3-2.1zm-1 1.6a19 19 0 0 0 5.2 2.7l-1.3 1.3a20 20 0 0 1-4.2-2.2zm2.3-10 1.7.7 3.2-3.5-1-1.5zm-1.3-1-1-1.5 3.1-3.5 1.7.7zm19.3 10.5.9 1.5a18 18 0 0 0 3.8-3.3q1.6.4 2.7-.5a2.5 2.5 0 0 0 .3-3.7l-.1-.2q1.1-2.4 1.3-5.1h-1.7a14 14 0 0 1-1.2 4.4l-1.5.1-4.3-4.8-1.3 1 4.3 4.9a3 3 0 0 0 .1 3 16 16 0 0 1-3.3 2.7m6.5-5a1.2 1.2 0 0 0-1.7-.2 1 1 0 0 0-.1 1.6q.8.8 1.7.1a1 1 0 0 0 0-1.6zm2.2-4.8 1.8-.5.2-4.5-1.7-.6v2.6zm-1.5-5.7-1.8.4v2.3c0-.8-.3 2.3-.3 2.3l1.9.6.2-2.9zm-6 14.6a17 17 0 0 1-5 2.7l-.5-1.7a15 15 0 0 0 4.3-2.1zm.9 1.6a19 19 0 0 1-5.2 2.7l1.3 1.3a20 20 0 0 0 4.3-2.2zm-2.4-10-1.7.7-3.1-3.5 1-1.5zm1.4-1 1-1.5-3.2-3.5-1.7.7 3.8 4.3m-21.4-9.3.5 1.7h4.8l.6-1.7zm22.5 0-.5 1.7h-4.8l-.5-1.7zm-12.4 23.3q0-1 1.2-1.1 1 .1 1.1 1.1 0 1.1-1.2 1.2c-1.2.1-1.2-.6-1.2-1.2zm2-8.2 1.8-.5v-5l-1.8-.5zm-1.8 0-1.8-.5v-5l1.8-.5z"/>
<path fill="#c8b100" d="M261.6 313.8q.4-1.5 1.9-2V306h1.7v5.7q1.4.5 1.8 1.7h4.7v.3h-6.3a1 1 0 0 0-1-.6 1 1 0 0 0-1.1.6h-1.7m13 0v-.3h4.4l.2-.4-5.4-6 1.3-1 5.3 5.8h.3v-8h1.7v7.9h.3l5.2-5.8 1.3 1-5.2 5.9.3.6h4.2v.3zm23 0a1 1 0 0 1 1.1-.6q.8 0 1 .6h1.7a3 3 0 0 0-1.8-2V306h-1.8v5.7a3 3 0 0 0-1.8 1.7h-4.6v.3zm-32.2-16 6.5 7.3 1.3-1-6.5-7.3.3-.6h4.7v-1.6H267a3 3 0 0 0-2.7-1.9 2.7 2.7 0 0 0-2.8 2.7q.1 1.8 1.9 2.5v5.6h1.7v-5.6zm34 .1v5.6h-1.7v-5.6l-.4-.2-6.3 7.4-1.3-1 6.5-7.5-.1-.3h-4.8v-1.6h4.8a3 3 0 0 1 2.6-1.9c1.6 0 2.8 1.2 2.8 2.7q-.1 2-2 2.5zm-17 0v3.4h-1.8V298a3 3 0 0 1-1.8-1.7h-4.3v-1.6h4.3a3 3 0 0 1 2.6-1.9q2 .1 2.7 1.9h4.3v1.6h-4.3a3 3 0 0 1-1.7 1.7zm-19 4.1-1.8.5v4.6l1.8.5V302m1.8 0 1.8.5v4.6l-1.8.5zm32.5 0-1.8.5v4.6l1.8.5zm1.8 0 1.8.5v4.6l-1.8.5zm-27.3 1 1.7-.8 3.2 3.5-1 1.5zm-1.3 1-1 1.5 3 3.5 1.8-.7zm19.7-1.2-1.8-.7-3 3.5 1 1.5zm1.3 1 1 1.6-3 3.5-1.8-.7 3.8-4.3m-21.7 9.6.5-1.7h4.8l.6 1.7zm-7-18.1q.1-1 1.1-1.2 1.1 0 1.2 1.2c.1 1.2-.5 1.1-1.2 1.1q-1-.1-1.2-1.1zm12.8.8-.5 1.7h-4.8l-.5-1.7zm0-1.7-.5-1.7h-4.8l-.5 1.7zm16.7 19-.5-1.7h-4.8l-.5 1.7zm4.6-18.1q.2-1 1.2-1.2 1.1 0 1.2 1.2c.1 1.2-.5 1.1-1.2 1.1q-1-.1-1.2-1.1m-17.2 0q.2-1 1.2-1.2c1-.2 1.2.5 1.2 1.2s-.5 1.1-1.2 1.1q-1-.1-1.2-1.1m6.7.8.6 1.7h4.8l.5-1.7zm0-1.6.5-1.8h4.9l.5 1.7H287m-6.3 5.4-1.8.5v4.6l1.8.5zm1.7 0 1.8.5v4.6l-1.8.5z"/>
<path fill="none" stroke="#c8b100" stroke-width=".3" d="M284.2 337.3a17 17 0 0 0 4-1l.8 1.4a19 19 0 0 1-4.6 1.3 3 3 0 0 1-2.8 2 3 3 0 0 1-2.7-2 19 19 0 0 1-4.8-1.3l.8-1.5q2 1 4.2 1.1a3 3 0 0 1 1.6-1.4v-7.2h1.8v7.2a3 3 0 0 1 1.7 1.4zm-5-21.7-.2-.5h-4.4v-1.6h4.4q0-.3.2-.4l-5.4-6 1.3-1 5.3 5.8.3-.1V304h1.7v7.7l.3.1 5.2-5.9 1.3 1-5.2 6 .3.6h4.2v1.6h-4.2l-.3.6 5 5.6-1.4 1-4.9-5.6-.2.1v9.3h-1.8v-9.3l-.2-.1-5 5.6-1.4-1 5.1-5.7m-13.7-17.7 6.5 7.2 1.3-1-6.5-7.3.3-.6h4.7v-1.7h-4.7a3 3 0 0 0-2.7-1.8 2.7 2.7 0 0 0-2.8 2.7q.1 1.8 1.9 2.5v5.5h1.7V298h.3zm7 37-.9 1.5a18 18 0 0 1-3.9-3.3q-1.4.4-2.6-.5a2.5 2.5 0 0 1-.3-3.7v-.2a16 16 0 0 1-1.3-5.1h1.8a14 14 0 0 0 1.1 4.4l1.5.1 4.4-4.8 1.3 1-4.3 4.9a3 3 0 0 1-.1 3 16 16 0 0 0 3.3 2.7zm-9-14v-4a3 3 0 0 1-2-2.6q.2-1.9 2-2.6v-5.6h1.7v5.7q1.4.4 1.8 1.7h4.7v1.6H267a3 3 0 0 1-1.8 1.7v4.1h-1.7m2.5 9a1.2 1.2 0 0 1 1.7-.2q.7.7 0 1.6a1.3 1.3 0 0 1-1.6.1 1 1 0 0 1-.1-1.6zm-2.2-4.9-1.8-.4-.3-4.5 1.8-.6v2.6q0 1.5.3 3zm1.5-5.6 1.7.4.3 4.6-1.8.6-.3-2.9v-2.7zm5.9 14.6a17 17 0 0 0 5.1 2.7l.4-1.7a15 15 0 0 1-4.3-2.2l-1.2 1.2m-1 1.5a19 19 0 0 0 5.3 2.7l-1.4 1.2a20 20 0 0 1-4.2-2.1l.4-1.8"/>
<path fill="none" stroke="#c8b100" stroke-width=".3" d="m272.6 325.4 1.7.8 3.2-3.5-1-1.5-3.9 4.2m-1.3-1-1-1.5 3.1-3.5 1.7.7-3.8 4.3m-8.2-10.1q.2-1.1 1.2-1.2 1.1 0 1.2 1.2 0 1-1.2 1.1-1-.1-1.2-1.1zm27.5 20.6.8 1.5a18 18 0 0 0 4-3.3q1.3.4 2.6-.5a2.5 2.5 0 0 0 .3-3.7l-.2-.2q1.1-2.4 1.4-5.1h-1.7a14 14 0 0 1-1.2 4.4l-1.5.1-4.3-4.8-1.4 1 4.4 4.9a3 3 0 0 0 .1 3 16 16 0 0 1-3.3 2.7zm9-14v-4.1a3 3 0 0 0 2-2.5 3 3 0 0 0-2-2.6v-5.6h-1.8v5.7q-1.3.4-1.8 1.7h-4.7v1.6h4.8a3 3 0 0 0 1.7 1.7v4.1zm-2.5 9a1.2 1.2 0 0 0-1.7-.2 1 1 0 0 0-.1 1.6q.7.8 1.7.1a1 1 0 0 0 0-1.6zm2.2-4.8 1.8-.4.2-4.6-1.7-.6v2.6zm-1.5-5.7-1.8.4v2.3c0-.8-.3 2.3-.3 2.3l1.9.6.2-2.9v-2.7m1.8-21.5v5.5h-1.8V298l-.4-.2-6.4 7.2-1.3-1.1 6.5-7.4-.1-.3h-4.8v-1.7h4.8a3 3 0 0 1 2.6-1.8c1.6 0 2.8 1.2 2.8 2.7q-.1 2-2 2.5zm-17.2 0v3.4h-1.7v-3.4a3 3 0 0 1-1.8-1.7h-4.3v-1.7h4.3a3 3 0 0 1 2.6-1.8q2 .2 2.7 1.8h4.3v1.7h-4.3a3 3 0 0 1-1.7 1.7zm9.5 36a17 17 0 0 1-5.2 2.8l-.4-1.7a15 15 0 0 0 4.3-2.1l1.3 1m.9 1.6a19 19 0 0 1-5.2 2.7l1.3 1.3a20 20 0 0 0 4.3-2.2l-.4-1.8M263.5 302l-1.8.5v4.6l1.8.5V302m1.8 0 1.8.5v4.6l-1.8.5V302m32.5 0-1.8.5v4.6l1.8.5V302"/>
<path fill="none" stroke="#c8b100" stroke-width=".3" d="m299.6 302 1.8.5v4.6l-1.8.5V302m-9.2 23.4-1.7.8-3.1-3.5 1-1.5 3.8 4.2m1.3-1 1-1.5-3-3.5-1.8.7 3.8 4.3m-19.4-21.5 1.7-.7 3.1 3.5-1 1.5-3.8-4.3M271 304l-1 1.5 3 3.5 1.8-.8-3.8-4.2m19.7-1.2-1.8-.7-3 3.5 1 1.5 3.8-4.3m1.3 1 1 1.5-3 3.5-1.8-.7 3.8-4.2m-21.7 9.6.5-1.7h4.8l.6 1.7h-5.9m0 1.6.5 1.7h4.8l.6-1.7h-5.9m-7-19.7q.1-1.1 1.1-1.2 1.1 0 1.2 1.2c.1 1.2-.5 1.1-1.2 1.1q-1-.1-1.2-1.1zm12.8.8-.5 1.7h-4.8l-.5-1.7h5.8m0-1.7-.5-1.7h-4.8l-.5 1.7h5.8m21.4 19.8q0-1 1.2-1.2c1.2-.2 1.2.5 1.2 1.2q0 1-1.2 1.1c-1.2.1-1.2-.5-1.2-1.1zm-4.7-.8-.5-1.7h-4.8l-.5 1.7h5.9m0 1.6-.6 1.7h-4.8l-.5-1.7h5.9m-12.4 23.3q0-1 1.2-1.1 1 .1 1.1 1.1 0 1.1-1.2 1.2c-1.2.1-1.2-.5-1.2-1.2zm2-8.2 1.8-.5V325l-1.8-.5v5.6m-1.8 0-1.8-.5V325l1.8-.5v5.6m16.8-34.8q.2-1.1 1.2-1.2 1.1 0 1.2 1.2c.1 1.2-.5 1.1-1.2 1.1q-1-.1-1.2-1.1zm-17.2 0q.2-1.1 1.2-1.2 1.1 0 1.2 1.2c.1 1.2-.5 1.1-1.2 1.1q-1-.1-1.2-1.1zm6.7.8.6 1.7h4.8l.5-1.7H287m0-1.7.6-1.7h4.8l.5 1.7H287m-6.3 5.4-1.8.5v4.5l1.8.5V300m1.7 0 1.8.5v4.5l-1.8.5V300"/>
<path fill="#058e6e" d="M278.8 314.3a2.7 2.7 0 0 1 2.8-2.6q2.6.2 2.8 2.6a2.7 2.7 0 0 1-2.8 2.7 2.7 2.7 0 0 1-2.8-2.7"/>
<path fill="#db4446" d="M282.3 245v-.6l.1-.4s-1.6.2-2.5 0a6 6 0 0 1-2.5-1.4q-1-1-1.7-1.2c-1.4-.2-2.4.4-2.4.4s1 .4 1.8 1.4a5 5 0 0 0 2 1.5c.6.2 2.7 0 3.3.1z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M282.3 245v-.6l.1-.4s-1.6.2-2.5 0a6 6 0 0 1-2.5-1.4q-1-1-1.7-1.2c-1.4-.2-2.4.4-2.4.4s1 .4 1.8 1.4a5 5 0 0 0 2 1.5c.6.2 2.7 0 3.3.1z"/>
<path fill="#ed72aa" stroke="#000" stroke-width=".4" d="M290 242.7v1.4c.1.7-.2 1.3 0 1.7l.2 1c.2.2.3.9.3.9l-.8-.6-.6-.4v1l.6 1.3q.6.6 1 1.4c.3.4.2 1.4.2 1.4s-.4-.7-.9-.9l-1.3-.6s.9.8.9 1.6c0 .7-.4 1.6-.4 1.6s-.3-.7-.8-1.1l-1.2-1s.5 1.2.5 2v2.6s-.5-.7-1-1l-1-.8c0-.2.5.7.6 1.2s.3 2.4 2 4.8c1 1.4 2.4 3.8 5.6 3s2-5 1.3-7-1-4.3-1-5c.1-.8.7-3 .6-3.5a9 9 0 0 1 .1-3.4q.6-1.8 1-2.4l.5-1.4v-1.4l.8 1.5.1 1.5s.1-1.1 1-1.7 2-1.2 2.2-1.5l.4-.5s-.1 2-.7 2.7l-1.8 2.2s.8-.3 1.3-.3h.9s-.7.5-1.5 1.6-.5 1.3-1 2.3c-.7 1-1.1 1-1.9 1.6-1 1-.5 4.5-.3 5 .1.5 2 4.9 2 6 .1 1 .3 3.3-1.6 4.9-1.2 1-3.1 1-3.6 1.2-.4.3-1.3 1.2-1.3 3s.7 2.1 1.2 2.6 1.2.2 1.3.5l.5.8q.4.3.3.8c0 .4-1 1.3-1.2 2-.3.6-1 2.2-1 2.5s0 1 .3 1.4c0 0 .9 1 .2 1.3-.4.1-.8-.3-1-.2l-1 .4q-.4 0-.4-.8l-.1-.7q-.4 0-.4.5c0 .2 0 .9-.3.9s-.6-.5-.9-.6c-.2 0-.8-.2-.9-.5q.1-.6.8-1 .8-.1.5-.5-.4-.3-.7 0-.6.3-.8-.3c-.2-.6.1-.7 0-.8 0-.2-.4-.6.2-.9s.8.3 1.4.2q1-.1 1.1-.7.4-.6-.2-1.5c-.6-.9-.8-.5-1-.8l-.3-1v2.4l-.8-.9c-.3-.3-.6-1.4-.6-1.4v1.4c0 .4.4.7.2.9-.1.1-.8-.8-1-.9q-.5-.3-1-1l-.6-1.5c0-.2-.2-1.4 0-1.6l.4-1.2h-1.4c-.8 0-1.3-.2-1.6.3q-.4.8.2 3 .6 2 .5 2.2l-.8 1-1-.1q-.2-.2-1.2-.3h-1.4c-.3 0-1-.4-1.2-.3q-.7 0-.7.7.1.9-.5.7l-1-.2c-.3-.1-.9 0-.8-.4q0-.5.4-.8.4-.5 0-.5h-.7q-.4.5-.7.5-.5-.2-.5-1.1c0-.7-.7-1.3 0-1.3s1.4.5 1.5.2q.2-.5-.3-.8c-.3-.3-.7-.5-.3-.8l.8-.6c.2-.1.4-.8.7-.6.7.3 0 .7.7 1.4s1 1 2.1.9q1.4-.1 1.4-.6l-.2-1 .2-1s-.5.3-.6.6l-.5.8v-2.1l-.2-.9-.3 1-.1 1s-.7-.5-.5-1.5v-2.1c.3-.4.9-1.7 2.2-1.8h2.8l2.1-.3s-3-1.5-3.7-2-1.8-1.7-2.1-2.2l-.7-1.6q-.1 0-1 .3l-1.3 1-.7 1v-2s-.4 1.3-1 1.8l-1.5 1.2v-1l.2-1s-.5.8-1.2 1-1.9 0-2 .5v1.4q-.3.6-.5.6l-.8-.4c-.6-.2-.7.2-.7.2s-.4-.4-.2-.7c0-.3.7-.7.5-.9l-.9.2c-.3.2-.9.3-.8-.2q.2-.6 0-1-.1-.5.2-.6c.2-.1 1.2 0 1.3-.2q0-.4-.9-.7t-.6-.8l.6-.6c.1-.3.2-.8.7-.6.6.3.5.9 1 1 .6.3 2 0 2.3-.1l1.5-1 1.7-1.2-1.1-.8-1-1.1-2-.7c-.5 0-1.8-.5-1.8-.5l.8-.3q.4-.4.9-.6h.3-1.5c-.3-.2-1-.6-1.3-.6h-.9s.8-.4 1.4-.5l1.2-.1s-1-.3-1.3-.6l-.6-1q-.2-.5-.6-.6c-.4-.1-.9.4-1.2.3q-.4 0-.6-.7v-.5c-.2-.3-.7-.8-.2-1h1.4c.1-.2-.5-.7-.8-1-.4-.1-1-.4-.7-.7l.8-.6c.2-.3.4-1 .8-.7.3.2.9 1.3 1.1 1.2s.4-.9.3-1.2c0-.3 0-1 .3-.9s.5.5 1 .5 1.1-.1 1 .2q0 .6-.6 1.1a2 2 0 0 0-.2 1.6 4 4 0 0 0 1.2 1.5c.4.3 1.3.5 1.8.8s1.9 1.4 2.3 1.5l.9.3s.5-.2 1.1-.2 2.2.1 2.8-.1 1.3-.7 1.1-1.2-1.5-1-1.4-1.4q.2-.5 1.4-.5c.8 0 1.8.2 2-1 .2-1 .3-1.6-.8-1.9q-1.8-.1-2.1-1t-.2-1.3 1.5-.3 2-.3l.6-1 1.5-.3s1.5.7 3 1.7c1.2 1 2.3 2.3 2.3 2.3"/>
<path d="m279.3 242-.2-.7-.1-.3s.9 0 .9.2q-.1.4-.4.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m279.3 242-.2-.7-.1-.3s.9 0 .9.2q-.1.4-.4.4z"/>
<path d="M283.4 240.5v-.5s.7 0 1.1.3c.6.4 1 1 1 1-.2.2-.6-.2-1-.3h-.4q-.3 0-.4-.2v-.3z"/>
<path fill="none" stroke="#000" stroke-width=".1" d="M283.4 240.5v-.5s.7 0 1.1.3c.6.4 1 1 1 1-.2.2-.6-.2-1-.3h-.4q-.3 0-.4-.2v-.3z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m289 246.7-.4-.7-.2-.5"/>
<path fill="#db4446" d="M267.9 241.8s.5.3.8.3l.9.1s.2-.5.1-1c-.2-1.2-1.3-1.4-1.3-1.4s.3.7.1 1q-.4 1-.6 1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M267.9 241.8s.5.3.8.3l.9.1s.2-.5.1-1c-.2-1.2-1.3-1.4-1.3-1.4s.3.7.1 1q-.4 1-.6 1z"/>
<path fill="#db4446" d="M265.5 242.8s-.4-.8-1.3-.7-1.6.9-1.6.9h1.3c.4.3.5 1 .5 1l.7-.6z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M265.5 242.8s-.4-.8-1.3-.7-1.6.9-1.6.9h1.3c.4.3.5 1 .5 1l.7-.6z"/>
<path fill="#db4446" d="M264.4 246s-.8.1-1.2.6c-.5.5-.4 1.5-.4 1.5s.5-.6 1-.6l1.2.2-.3-.9z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M264.4 246s-.8.1-1.2.6c-.5.5-.4 1.5-.4 1.5s.5-.6 1-.6l1.2.2-.3-.9z"/>
<path d="m279.3 245.9.4-.5.3.5z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m279.3 245.9.4-.5.3.5h-.7"/>
<path d="m280.2 245.9.4-.6.4.5z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m280.2 245.9.4-.6.4.5h-.8"/>
<path d="m279.8 242.5.8.3-.7.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m279.8 242.5.8.3-.7.4-.1-.7"/>
<path d="m280.8 242.8.8.2-.6.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m280.8 242.8.8.2-.6.4-.2-.6"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M275.2 249.2s-.9.3-1.2.7q-.4 1-.3 1.1c.1.1.7-.6 1.6-.3l1.3.3c.4 0 1.3-.4 1.3-.4s-.7.9-.6 1.5l.1 1.2c0 .7-.5 1.6-.5 1.6l1-.3a5 5 0 0 0 1.8-.9l1-1s-.2 1 0 1.5l.2 1.7s.4-.5.8-.7c.2 0 .8-.4 1-.7l.3-1s0 .8.4 1.3c.3.4.7 1.8.7 1.8s.3-.9.6-1.3q.6-.6.7-1v-1l.4 1m-11.7.6s.5-.9 1-1.2l1.2-.8 1-.4m1 5.3 1.4-.8 1.2-1.2"/>
<path fill="#db4446" d="M267 256.4s-.4-.5-1.2-.3c-.7 0-1.2 1-1.2 1l1-.2.6.5.5-.4z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M267 256.4s-.4-.5-1.2-.3c-.7 0-1.2 1-1.2 1l1-.2.6.5.5-.4z"/>
<path fill="#db4446" d="M266.2 259.4s-.7 0-1.2.4-.6 1.2-.6 1.2.5-.4 1-.3l.8.2.1-.6z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M266.2 259.4s-.7 0-1.2.4-.6 1.2-.6 1.2.5-.4 1-.3l.8.2.1-.6z"/>
<path fill="#db4446" d="M267.6 262.2s0 .8.4 1.3 1.2.6 1.2.6l-.3-.8c-.1-.4.3-.7.3-.7s-.4-.4-.7-.4z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M267.6 262.2s0 .8.4 1.3 1.2.6 1.2.6l-.3-.8c-.1-.4.3-.7.3-.7s-.4-.4-.7-.4zm17.1 1.4s2.1 1.3 2 2.4c0 1-1.1 2.4-1.1 2.4"/>
<path fill="#db4446" d="M275.2 269.4s-.5-.6-1.3-.6c-.7 0-1.5.7-1.5.7s1 0 1.2.2l.4.7.6-.3z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M275.2 269.4s-.5-.6-1.3-.6c-.7 0-1.5.7-1.5.7s1 0 1.2.2l.4.7.6-.3z"/>
<path fill="#db4446" d="M273 272.3s-1-.1-1.5.4-.4 1.4-.4 1.4.6-.7 1-.6q1 .1 1.2.3l-.2-.8z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M273 272.3s-1-.1-1.5.4-.4 1.4-.4 1.4.6-.7 1-.6q1 .1 1.2.3l-.2-.8z"/>
<path fill="#db4446" d="M275 275.4s-.5.6-.1 1.1c.3.6 1 .8 1 .8s-.2-.4-.1-.8.7-.8.7-.8z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M275 275.4s-.5.6-.1 1.1c.3.6 1 .8 1 .8s-.2-.4-.1-.8.7-.8.7-.8z"/>
<path fill="#db4446" d="M287.7 276.6s-.8-.2-1.3 0-.8 1.5-.8 1.5.7-.6 1.3-.6l1 .3v-.8z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M287.7 276.6s-.8-.2-1.3 0-.8 1.5-.8 1.5.7-.6 1.3-.6l1 .3v-.8z"/>
<path fill="#db4446" d="M288.1 279.7s-.6.6-.4 1.2l.6 1s0-.7.3-1 1-.3 1-.3l-.7-.6z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M288.1 279.7s-.6.6-.4 1.2l.6 1s0-.7.3-1 1-.3 1-.3l-.7-.6z"/>
<path fill="#db4446" d="M291.3 280.6s-.3.8.3 1.3q1 .8 1.1.6c.1-.2-.5-.8-.3-1.3q.3-.6.5-.7l-.8-.2z"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M291.3 280.6s-.3.8.3 1.3q1 .8 1.1.6c.1-.2-.5-.8-.3-1.3q.3-.6.5-.7l-.8-.2z"/>
<path fill="#ffd691" stroke="#000" stroke-width=".5" d="M258.7 337.5q3.2 1.1 3.2 4c0 2.5-2.3 4.3-5.4 4.3-3 0-5.6-1.8-5.6-4.2 0-1.9 1-4 3.2-4l-.3-.6-.6-.7h1.3l.7.5.6-.7.7-.6.6.7.3.6s.4-.4.8-.5l.9-.3-.3.7-.1.8"/>
<path fill="#058e6e" stroke="#000" stroke-width=".5" d="M256 348.5s-4-2.8-5.8-3.1c-2.3-.5-4.8-.1-5.9-.2l1.9 1.5a11 11 0 0 0 3.5 2c3.3.8 6.3-.2 6.3-.2m1.2.2s2.6-2.7 5.3-3c3.3-.5 5.4.2 6.6.5 0 0-1 .5-1.6 1-.5.3-2 1.5-4.2 1.6-2.2 0-4.7-.3-5.1-.2l-1 .1"/>
<path fill="#ad1519" stroke="#000" stroke-width=".5" d="M256.4 345.4a5.2 5.2 0 0 1 0-7.6 5 5 0 0 1 1.7 3.8 5 5 0 0 1-1.7 3.8"/>
<path fill="#058e6e" stroke="#000" stroke-width=".5" d="M255.4 351s.6-1.6.7-3l-.2-2.2h.8s.4 1.2.4 2.2l-.2 2.5-.7.1-.8.3"/>
<path fill="#fff" d="M307 203.4q0-1 1-1 1.1 0 1.2 1c.1 1-.5 1.1-1.2 1.1a1 1 0 0 1-1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M307 203.4q0-1 1-1 1.1 0 1.2 1c.1 1-.5 1.1-1.2 1.1a1 1 0 0 1-1-1z"/>
<path fill="#fff" d="M308.4 200.7q.2-1 1.2-1a1 1 0 0 1 1 1q0 1-1 1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M308.4 200.7q.2-1 1.2-1a1 1 0 0 1 1 1q0 1-1 1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M309.5 197.6q.1-1 1-1a1 1 0 0 1 1.2 1q-.1 1-1.1 1a1 1 0 0 1-1.1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M309.5 197.6q.1-1 1-1a1 1 0 0 1 1.2 1q-.1 1-1.1 1a1 1 0 0 1-1.1-1z"/>
<path fill="#fff" d="M309.6 194.2q.1-1 1.1-1a1 1 0 0 1 1.1 1q-.1 1-1 1-1.1 0-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M309.6 194.2q.1-1 1.1-1a1 1 0 0 1 1.1 1q-.1 1-1 1-1.1 0-1.2-1z"/>
<path fill="#fff" d="M308.8 190.9q.1-1 1-1a1 1 0 0 1 1.2 1q-.1 1-1.1 1a1 1 0 0 1-1.1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M308.8 190.9q.1-1 1-1a1 1 0 0 1 1.2 1q-.1 1-1.1 1a1 1 0 0 1-1.1-1z"/>
<path fill="#fff" d="M307 187.8q0-.9 1.2-1a1 1 0 0 1 1 1q0 1-1 1.1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M307 187.8q0-.9 1.2-1a1 1 0 0 1 1 1q0 1-1 1.1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M304.7 185.4q0-1 1.2-1a1 1 0 0 1 1 1q0 .9-1 1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M304.7 185.4q0-1 1.2-1a1 1 0 0 1 1 1q0 .9-1 1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M302 183.3q.2-1 1.2-1 1.3 0 1.1 1c-.2 1-.5 1-1.1 1a1 1 0 0 1-1.1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M302 183.3q.2-1 1.2-1 1.3 0 1.1 1c-.2 1-.5 1-1.1 1a1 1 0 0 1-1.1-1z"/>
<path fill="#fff" d="M298.9 181.6q.1-1 1-1 1.1 0 1.2 1c.1 1-.5 1-1.1 1a1 1 0 0 1-1.1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M298.9 181.6q.1-1 1-1 1.1 0 1.2 1c.1 1-.5 1-1.1 1a1 1 0 0 1-1.1-1z"/>
<path fill="#fff" d="M295.5 180.4q0-1 1.2-1a1 1 0 0 1 1 1q0 1-1 1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M295.5 180.4q0-1 1.2-1a1 1 0 0 1 1 1q0 1-1 1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M291.8 179.8q.1-1 1.1-1.1 1.1.1 1.2 1t-1.2 1.1a1 1 0 0 1-1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M291.8 179.8q.1-1 1.1-1.1 1.1.1 1.2 1t-1.2 1.1a1 1 0 0 1-1-1z"/>
<path fill="#fff" d="M288.3 179.6q.1-1 1.1-1a1 1 0 0 1 1.2 1q0 1-1.2 1a1 1 0 0 1-1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M288.3 179.6q.1-1 1.1-1a1 1 0 0 1 1.2 1q0 1-1.2 1a1 1 0 0 1-1-1z"/>
<path fill="#fff" d="M284.9 179.7q.1-1 1-1 1.1 0 1.2 1c.1 1-.5 1-1.1 1a1 1 0 0 1-1.1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M284.9 179.7q.1-1 1-1 1.1 0 1.2 1c.1 1-.5 1-1.1 1a1 1 0 0 1-1.1-1z"/>
<path fill="#fff" d="M281.4 179.7q.1-1 1.1-1t1.1 1c.1 1-.5 1-1 1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M281.4 179.7q.1-1 1.1-1t1.1 1c.1 1-.5 1-1 1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" stroke="#000" stroke-width=".4" d="M283.1 182.7q.1-1 1.1-1.1 1.1.1 1.2 1-.1 1-1.1 1.1a1 1 0 0 1-1.2-1m.7 3.2q0-1 1.2-1 1 0 1 1c0 1-.4 1-1 1a1 1 0 0 1-1.2-1m.2 3.3q.1-1 1-1a1 1 0 0 1 1.2 1q-.1 1-1.1 1a1 1 0 0 1-1.1-1m-1 3q0-1 1-1.1a1 1 0 0 1 1.2 1q-.1 1-1.1 1.1a1 1 0 0 1-1.2-1m-1.9 2.7q0-1 1.2-1 1 0 1 1c0 1-.4 1-1 1a1 1 0 0 1-1.2-1"/>
<path fill="#fff" d="M278.8 177.6q.1-.9 1.1-1t1.1 1c.1 1-.5 1.1-1 1.1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M278.8 177.6q.1-.9 1.1-1t1.1 1c.1 1-.5 1.1-1 1.1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M275.7 176q.1-1 1.1-1.1 1.1 0 1.2 1c.1 1-.5 1.1-1.1 1.1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M275.7 176q.1-1 1.1-1.1 1.1 0 1.2 1c.1 1-.5 1.1-1.1 1.1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M272.3 175q0-1 1.2-1.1 1 0 1 1c0 1-.4 1-1 1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M272.3 175q0-1 1.2-1.1 1 0 1 1c0 1-.4 1-1 1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M268.8 174.3q.1-1 1.1-1 1.1 0 1.2 1c.1 1-.5 1-1.2 1a1 1 0 0 1-1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M268.8 174.3q.1-1 1.1-1 1.1 0 1.2 1c.1 1-.5 1-1.2 1a1 1 0 0 1-1-1z"/>
<path fill="#fff" d="M265.4 174.4q.1-1 1.1-1t1.1 1c.1 1-.5 1-1.1 1a1 1 0 0 1-1.1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M265.4 174.4q.1-1 1.1-1t1.1 1c.1 1-.5 1-1.1 1a1 1 0 0 1-1.1-1z"/>
<path fill="#fff" d="M261.8 175q.1-1 1.1-1a1 1 0 0 1 1.1 1q-.1 1-1 1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M261.8 175q.1-1 1.1-1a1 1 0 0 1 1.1 1q-.1 1-1 1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M258.5 176.1q.1-1 1.1-1t1.1 1c.1 1-.5 1-1.1 1a1 1 0 0 1-1.1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M258.5 176.1q.1-1 1.1-1t1.1 1c.1 1-.5 1-1.1 1a1 1 0 0 1-1.1-1z"/>
<path fill="#fff" d="M202.3 203.4q.1-1 1.1-1a1 1 0 0 1 1.1 1q-.1 1-1 1.1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M202.3 203.4q.1-1 1.1-1a1 1 0 0 1 1.1 1q-.1 1-1 1.1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M200.8 200.7q.1-1 1-1 1.1 0 1.2 1c.1 1-.5 1-1.1 1a1 1 0 0 1-1.1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M200.8 200.7q.1-1 1-1 1.1 0 1.2 1c.1 1-.5 1-1.1 1a1 1 0 0 1-1.1-1z"/>
<path fill="#fff" d="M199.7 197.6q0-1 1.2-1a1 1 0 0 1 1 1q0 1-1 1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M199.7 197.6q0-1 1.2-1a1 1 0 0 1 1 1q0 1-1 1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M199.6 194.2q.1-1 1.1-1 1.1 0 1.2 1c.1 1-.5 1-1.2 1q-1 0-1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M199.6 194.2q.1-1 1.1-1 1.1 0 1.2 1c.1 1-.5 1-1.2 1q-1 0-1-1z"/>
<path fill="#fff" d="M200.4 190.9q0-1 1.2-1 1 0 1 1c0 1-.4 1-1 1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M200.4 190.9q0-1 1.2-1 1 0 1 1c0 1-.4 1-1 1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M202.2 187.8q.1-.9 1-1a1 1 0 0 1 1.2 1q-.1 1-1.1 1.1a1 1 0 0 1-1.1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M202.2 187.8q.1-.9 1-1a1 1 0 0 1 1.2 1q-.1 1-1.1 1.1a1 1 0 0 1-1.1-1z"/>
<path fill="#fff" d="M204.5 185.4q.1-1 1.1-1t1.1 1q-.1.9-1.1 1t-1.1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M204.5 185.4q.1-1 1.1-1t1.1 1q-.1.9-1.1 1t-1.1-1z"/>
<path fill="#fff" d="M207.2 183.3q.1-1 1-1 1.1 0 1.2 1c.1 1-.5 1-1.1 1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M207.2 183.3q.1-1 1-1 1.1 0 1.2 1c.1 1-.5 1-1.1 1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M210.3 181.6q0-1 1.2-1a1 1 0 0 1 1 1q0 1-1 1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M210.3 181.6q0-1 1.2-1a1 1 0 0 1 1 1q0 1-1 1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M213.7 180.4q.1-1 1-1 1.1 0 1.2 1c.1 1-.5 1-1.1 1a1 1 0 0 1-1.1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M213.7 180.4q.1-1 1-1 1.1 0 1.2 1c.1 1-.5 1-1.1 1a1 1 0 0 1-1.1-1z"/>
<path fill="#fff" d="M217.4 179.8q.1-1 1.1-1.1a1 1 0 0 1 1.1 1q-.1 1-1.1 1.1a1 1 0 0 1-1.1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M217.4 179.8q.1-1 1.1-1.1a1 1 0 0 1 1.1 1q-.1 1-1.1 1.1a1 1 0 0 1-1.1-1z"/>
<path fill="#fff" d="M220.9 179.6q.1-1 1.1-1t1.1 1c.1 1-.5 1-1 1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M220.9 179.6q.1-1 1.1-1t1.1 1c.1 1-.5 1-1 1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M224.3 179.7q0-1 1.2-1a1 1 0 0 1 1 1q0 1-1 1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M224.3 179.7q0-1 1.2-1a1 1 0 0 1 1 1q0 1-1 1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M227.8 179.7q.1-1 1.1-1t1.2 1c.2 1-.5 1-1.2 1a1 1 0 0 1-1.1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M227.8 179.7q.1-1 1.1-1t1.2 1c.2 1-.5 1-1.2 1a1 1 0 0 1-1.1-1z"/>
<path fill="#fff" stroke="#000" stroke-width=".4" d="M226 182.7q.1-1 1.2-1.1c1.1-.1 1.1.5 1.1 1q-.1 1-1.1 1.1a1 1 0 0 1-1.1-1m-.7 3.2q.1-1 1-1 1.1 0 1.2 1c.1 1-.5 1-1.1 1q-1 0-1.1-1m-.2 3.3q0-1 1.2-1 1 0 1 1c0 1-.4 1-1 1a1 1 0 0 1-1.2-1m1 3q.2-1 1.2-1.1a1 1 0 0 1 1.1 1q-.1 1-1.1 1.1a1 1 0 0 1-1.1-1m1.9 2.7q.1-1 1-1 1.1 0 1.2 1c.1 1-.5 1-1.1 1a1 1 0 0 1-1.1-1"/>
<path fill="#fff" d="M230.4 177.6q.1-.9 1.1-1 1.1 0 1.2 1c.1 1-.5 1.1-1.2 1.1a1 1 0 0 1-1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M230.4 177.6q.1-.9 1.1-1 1.1 0 1.2 1c.1 1-.5 1.1-1.2 1.1a1 1 0 0 1-1-1z"/>
<path fill="#fff" d="M233.5 176q.1-1 1.1-1.1 1 0 1.1 1c.1 1-.5 1.1-1 1.1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M233.5 176q.1-1 1.1-1.1 1 0 1.1 1c.1 1-.5 1.1-1 1.1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M236.9 175q.1-1 1-1.1 1.3 0 1.2 1c-.1 1-.5 1-1.1 1a1 1 0 0 1-1.1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M236.9 175q.1-1 1-1.1 1.3 0 1.2 1c-.1 1-.5 1-1.1 1a1 1 0 0 1-1.1-1z"/>
<path fill="#fff" d="M240.4 174.3q.1-1 1.1-1a1 1 0 0 1 1.1 1q-.1 1-1 1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M240.4 174.3q.1-1 1.1-1a1 1 0 0 1 1.1 1q-.1 1-1 1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M243.8 174.4q0-1 1.2-1a1 1 0 0 1 1 1q0 1-1 1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M243.8 174.4q0-1 1.2-1a1 1 0 0 1 1 1q0 1-1 1a1 1 0 0 1-1.2-1z"/>
<path fill="#fff" d="M247.4 175q.1-1 1.1-1a1 1 0 0 1 1.2 1q0 1-1.2 1a1 1 0 0 1-1-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M247.4 175q.1-1 1.1-1a1 1 0 0 1 1.2 1q0 1-1.2 1a1 1 0 0 1-1-1z"/>
<path fill="#fff" d="M250.7 176.1q0-1 1.2-1 1 0 1 1c0 1-.4 1-1 1a1 1 0 0 1-1.2-1"/>
<path fill="none" stroke="#000" stroke-width=".4" d="M250.7 176.1q0-1 1.2-1 1 0 1 1c0 1-.4 1-1 1a1 1 0 0 1-1.2-1z"/>
<path fill="#c8b100" stroke="#000" stroke-width=".5" d="M222.3 244.1h-1v-1h-1.6v3.9h1.6v2.6h-3.5v7.5h1.9v15.2h-3.8v7.8h29v-7.8h-3.7v-15.2h1.9v-7.5h-3.6V247h1.7v-3.8h-1.7v1h-1v-1H237v1h-1.2v-1h-1.6v3.8h1.6v2.6h-3.5v-8.3h1.9v-3.8h-1.9v1h-1v-1h-1.6v1h-1v-1h-1.9v3.8h2v8.3H225V247h1.7v-3.8H225v1h-1v-1h-1.8v1zm-6.4 36h29m-29-1.9h29m-29-1.9h29m-29-1.9h29m-29-2.1h29m-25.2-1.7h21.5m-21.5-1.9h21.5m-21.5-2h21.5m-21.5-2h21.5m-21.5-1.9h21.5m-21.5-1.9h21.5m-21.5-1.9h21.5m-23.4-1.9H243m-25.3-1.8H243m-25.3-2H243m-25.3-1.8H243m-21.8-2h18.2m-10.9-1.8h3.6m-3.5-2h3.5m-3.5-1.8h3.5m-3.5-1.9h3.5m-5.4-2.4h7.3m-12.8 8h3.8m-5.4-2.3h7m-7 34.8v-1.9m0-1.9v-1.9m-2 2v1.8m3.6 0v-1.9m2 3.8v-1.9m0-1.9v-1.9m0-2.1v-1.7m0-1.9v-2m-2 7.7v-2.1m-3.5 2.1v-2.1m7.3 0v2.1m1.7-2.1v-1.7m-5.5-1.9v2m3.8-2v2m3.5-2v2m-1.8-2v-2m1.8-2v2m0-5.8v2m-1.8-3.9v2m1.8-3.8v1.8m-3.5-1.9v2m-3.8-2v2m-1.6-3.8v1.9m3.5-2v2m3.6-2v2m1.9-3.8v1.9m-3.6-2v2m-3.8-2v2m-1.6-3.8v1.9m7-2v2m-3.5-5.7v1.9m16.3-2h-3.7m5.4-2.3H234m7 34.8v-1.9m0-1.9v-1.9m2 2v1.8m-3.6 0v-1.9m-1.9 3.8v-1.9m0-1.9v-1.9m0-2.1v-1.7m0-1.9v-2m2 7.7v-2.1m3.5 2.1v-2.1m-7.3 0v2.1m-1.7-2.1v-1.7m5.4-1.9v2m-3.7-2v2m-3.6-2v2m1.9-2v-2m-1.9-2v2m0-5.8v2m1.9-3.9v2m-1.9-3.8v1.8m3.6-1.9v2m3.8-2v2m1.6-3.8v1.9m-3.5-2v2m-3.6-2v2m-1.9-3.8v1.9m3.6-2v2m3.7-2v2m1.7-3.8v1.9m-7.1-2v2m3.6-5.7v1.9m-7.4 19.1v-2m0-5.8V259m0 5.7v-1.9m0-5.7v-1.8m0-2v-1.8m0-3.8v-2m0-1.8V242m-9 5h3.8m3.6-5.7h3.5m3.6 5.7h3.7"/>
<path fill="#c8b100" stroke="#000" stroke-width=".5" d="M235.3 280.1v-5c0-1-.5-3.8-5-3.8-4.3 0-4.7 2.9-4.7 3.8v5z"/>
<path fill="#c8b100" stroke="#000" stroke-width=".5" d="m227.2 275.4-2.3-.3c0-1 .2-2.3 1-2.8l2 1.7c-.2.2-.7.9-.7 1.4zm6.4 0 2.4-.3c0-1-.3-2.3-1-2.8l-2 1.7c.1.2.6.9.6 1.4zm-2.4-2.4 1.2-2.1-2-.5q-1 0-2 .5l1.2 2.1zm-4.4-6v-5c0-1.4-1-2.6-2.6-2.6s-2.6 1.2-2.6 2.6v5.2h5.2zm7.3 0v-5c0-1.4 1-2.6 2.6-2.6s2.6 1.2 2.6 2.6v5.2h-5.2zm-1.9-12.7.5-4.7h-4.5l.2 4.7zm3.5 0-.4-4.7h4.7l-.5 4.7zm-10.6 0 .2-4.7h-4.5l.5 4.7z"/>
<path fill="#0039f0" d="M233.6 280.1v-4.3c0-.7-.4-2.8-3.3-2.8a3 3 0 0 0-3 2.8v4.3zm-7.3-13.5v-4.5c0-1.2-.7-2.4-2.1-2.4s-2.2 1.2-2.2 2.4v4.5zm8.3 0v-4.5c0-1.2.7-2.4 2.1-2.4s2.1 1.2 2.1 2.4v4.5z"/>
<path fill="#ad1519" d="M239.5 287.8c0-10.4 7.5-18.8 16.6-18.8s16.7 8.4 16.7 18.7c0 10.4-7.5 18.8-16.7 18.8s-16.6-8.4-16.6-18.7"/>
<path fill="none" stroke="#000" stroke-width=".6" d="M239.5 287.8c0-10.4 7.5-18.8 16.6-18.8s16.7 8.4 16.7 18.7c0 10.4-7.5 18.8-16.7 18.8s-16.6-8.4-16.6-18.7z"/>
<path fill="#005bbf" d="M244.4 287.7c0-7.6 5.3-13.7 11.7-13.7 6.5 0 11.8 6.1 11.8 13.7s-5.3 13.7-11.7 13.7c-6.5 0-11.8-6.1-11.8-13.7"/>
<path fill="none" stroke="#000" stroke-width=".6" d="M244.4 287.7c0-7.6 5.3-13.7 11.7-13.7 6.5 0 11.8 6.1 11.8 13.7s-5.3 13.7-11.7 13.7c-6.5 0-11.8-6.1-11.8-13.7z"/>
<path fill="#c8b100" d="M250.6 278.3s-1.4 1.5-1.4 2.9.6 2.6.6 2.6a2 2 0 0 0-1.4-1 1.5 1.5 0 0 0-1.6 1.5l.3.8.5 1q.3-.6 1-.6 1 .1 1 1v.3h-1.2v1h1.1l-.8 1.7 1-.4 1 1 .8-1 1 .4-.7-1.6h1v-1.1h-1.2v-.3q.1-.9 1-1 1.2 0 1 .6l.6-1 .2-.8q0-1.4-1.5-1.5-1 0-1.4 1s.5-1.2.5-2.6-1.4-3-1.4-3"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".3" d="M250.6 278.3s-1.4 1.5-1.4 2.9.6 2.6.6 2.6a2 2 0 0 0-1.4-1 1.5 1.5 0 0 0-1.6 1.5l.3.8.5 1q.3-.6 1-.6 1 .1 1 1v.3h-1.2v1h1.1l-.8 1.7 1-.4 1 1 .8-1 1 .4-.7-1.6h1v-1.1h-1.2v-.3q.1-.9 1-1 1.2 0 1 .6l.6-1 .2-.8q0-1.4-1.5-1.5-1 0-1.4 1s.5-1.2.5-2.6-1.4-3-1.4-3z"/>
<path fill="#c8b100" d="M248.4 287.9h4.5v-1.1h-4.5v1z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M248.4 287.9h4.5v-1.1h-4.5v1z"/>
<path fill="#c8b100" d="M261.5 278.3s-1.4 1.5-1.4 2.9.6 2.6.6 2.6q-.4-1-1.4-1-1.5.2-1.6 1.5l.3.8.5 1q.2-.6 1-.6a1 1 0 0 1 1 1v.3h-1.2v1h1.1l-.8 1.7 1-.4.9 1 .9-1 1 .4-.8-1.6h1.1v-1.1h-1.2v-.3q.1-.9 1-1c.9-.1.9.2 1 .6l.6-1 .2-.8q-.1-1.4-1.5-1.5-1.1 0-1.5 1s.6-1.2.6-2.6-1.4-3-1.4-3"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".3" d="M261.5 278.3s-1.4 1.5-1.4 2.9.6 2.6.6 2.6q-.4-1-1.4-1-1.5.2-1.6 1.5l.3.8.5 1q.2-.6 1-.6a1 1 0 0 1 1 1v.3h-1.2v1h1.1l-.8 1.7 1-.4.9 1 .9-1 1 .4-.8-1.6h1.1v-1.1h-1.2v-.3q.1-.9 1-1c.9-.1.9.2 1 .6l.6-1 .2-.8q-.1-1.4-1.5-1.5-1.1 0-1.5 1s.6-1.2.6-2.6-1.4-3-1.4-3z"/>
<path fill="#c8b100" d="M259.3 287.9h4.5v-1.1h-4.5v1z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M259.3 287.9h4.5v-1.1h-4.5v1z"/>
<path fill="#c8b100" d="M256 287.6s-1.3 1.5-1.3 3c0 1.4.6 2.6.6 2.6a2 2 0 0 0-1.5-1 1.5 1.5 0 0 0-1.5 1.4l.2.8.5 1q.3-.5 1-.5 1 0 1.1 1v.3h-1.2v1h1l-.8 1.7 1.1-.5.9 1 .8-1 1.1.5-.8-1.7h1.1v-1h-1.2v-.3q0-1 1-1 .8 0 1 .5l.5-1 .3-.8q-.1-1.3-1.6-1.4a2 2 0 0 0-1.4 1s.6-1.2.6-2.7c0-1.4-1.4-2.9-1.4-2.9"/>
<path fill="none" stroke="#000" stroke-linejoin="round" stroke-width=".3" d="M256 287.6s-1.3 1.5-1.3 3c0 1.4.6 2.6.6 2.6a2 2 0 0 0-1.5-1 1.5 1.5 0 0 0-1.5 1.4l.2.8.5 1q.3-.5 1-.5 1 0 1.1 1v.3h-1.2v1h1l-.8 1.7 1.1-.5.9 1 .8-1 1.1.5-.8-1.7h1.1v-1h-1.2v-.3q0-1 1-1 .8 0 1 .5l.5-1 .3-.8q-.1-1.3-1.6-1.4a2 2 0 0 0-1.4 1s.6-1.2.6-2.7c0-1.4-1.4-2.9-1.4-2.9z"/>
<path fill="#c8b100" d="M253.8 297.2h4.5v-1h-4.5z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M253.8 297.2h4.5v-1h-4.5z"/>
<path fill="#c8b100" d="M289.4 238.3h-.3l-.3.4q-.5.4-.9 0l-.1-.4h-.5q-.5-.2-.2-.8l.1-.2v-.3h-.3l-.1.3q-.5.4-.8.1l-.1-.2h-.2c-.5.2-.7-1-.8-1.3l-.1.3v1.3l-.3 1.2q1.4.3 3 1.7a10 10 0 0 1 2.5 2.5l1.2-.6c.6-.2 1.4-.2 1.4-.2l.2-.2c-.3 0-1.6.1-1.6-.4l.1-.2h-.3q-.3-.3 0-.8h.2v-.4h-.3l-.2.1q-.5.5-.9 0v-.4h-.6a1 1 0 0 1 0-.9l.2-.3z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M289.4 238.3h-.3l-.3.4q-.5.4-.9 0l-.1-.4h-.5q-.5-.2-.2-.8l.1-.2v-.3h-.3l-.1.3q-.5.4-.8.1l-.1-.2h-.2c-.5.2-.7-1-.8-1.3l-.1.3v1.3l-.3 1.2q1.4.3 3 1.7a10 10 0 0 1 2.5 2.5l1.2-.6c.6-.2 1.4-.2 1.4-.2l.2-.2c-.3 0-1.6.1-1.6-.4l.1-.2h-.3q-.3-.3 0-.8h.2v-.4h-.3l-.2.1q-.5.5-.9 0v-.4h-.6a1 1 0 0 1 0-.9l.2-.3z"/>
<path d="M287 239h.3s.1.2 0 .2h-.2v-.2"/>
<path fill="none" stroke="#000" stroke-width=".1" d="M287 239h.3s.1.2 0 .2h-.2v-.2z"/>
<path d="m288 239.8-.3-.2v-.2h.2l.3.3.3.2s.1.1 0 .2h-.1z"/>
<path fill="none" stroke="#000" stroke-width=".1" d="m288 239.8-.3-.2v-.2h.2l.3.3.3.2s.1.1 0 .2h-.1l-.4-.3"/>
<path d="m286.3 238.6-.3-.2s-.1 0 0-.1h.1l.3.1.2.2.1.1h-.2z"/>
<path fill="none" stroke="#000" stroke-width=".1" d="m286.3 238.6-.3-.2s-.1 0 0-.1h.1l.3.1.2.2.1.1h-.2l-.2-.1"/>
<path d="M285.2 237.9h.2l.1.2h-.2z"/>
<path fill="none" stroke="#000" stroke-width=".1" d="M285.2 237.9h.2l.1.2h-.2z"/>
<path d="M289.1 240.6v-.3h-.3v.3z"/>
<path fill="none" stroke="#000" stroke-width=".1" d="M289.1 240.6v-.3h-.3v.3z"/>
<path d="m289.7 241.2.2.2q.1.1.2 0l-.2-.3-.2-.2h-.2v.1z"/>
<path fill="none" stroke="#000" stroke-width=".1" d="m289.7 241.2.2.2q.1.1.2 0l-.2-.3-.2-.2h-.2v.1l.2.2"/>
<path d="M290.7 242v-.2h-.3v.3h.3"/>
<path fill="none" stroke="#000" stroke-width=".1" d="M290.7 242v-.2h-.3v.3h.3z"/>
<path fill="#c8b100" d="M287.9 235.9h-.6l-.2.9.1.1h.2l.7-.5z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M287.9 235.9h-.6l-.2.9.1.1h.2l.7-.5-.2-.5"/>
<path fill="#c8b100" d="M286.2 236.4v.5l1 .2v-.3l-.5-.7z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M286.2 236.4v.5l1 .2v-.3l-.5-.7-.5.3"/>
<path fill="#c8b100" d="m288.2 237.5-.5.3-.6-.8v-.1h1.1z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m288.2 237.5-.5.3-.6-.8v-.1h1.1v.6"/>
<path fill="#c8b100" d="m287 236.8.3-.1.1.4h-.3z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m287 236.8.3-.1.1.4h-.3z"/>
<path fill="#c8b100" d="m284.8 235.9-.3-.8-.4-.4s.4-.2.9.1 0 .9 0 .9z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m284.8 235.9-.3-.8-.4-.4s.4-.2.9.1 0 .9 0 .9z"/>
<path fill="#c8b100" d="m285.8 236.2-.4.4-.7-.6v-.3h1z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m285.8 236.2-.4.4-.7-.6v-.3h1l.1.5"/>
<path fill="#c8b100" d="m284.6 235.8.3-.2q.2 0 .1.3 0 .3-.3.3v-.4"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m284.6 235.8.3-.2q.2 0 .1.3 0 .3-.3.3v-.4z"/>
<path fill="#c8b100" d="M290.2 237.3h-.6l-.3.8v.2h.2l.9-.4z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M290.2 237.3h-.6l-.3.8v.2h.2l.9-.4-.2-.6"/>
<path fill="#c8b100" d="m288.5 237.6-.1.6.9.2h.1v-.2l-.4-.8z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m288.5 237.6-.1.6.9.2h.1v-.2l-.4-.8-.5.2"/>
<path fill="#c8b100" d="m290.3 239-.6.2-.4-.8v-.2h.1l1 .2z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m290.3 239-.6.2-.4-.8v-.2h.1l1 .2-.1.6"/>
<path fill="#c8b100" d="M289.1 238.1q.2-.2.4 0l.1.4h-.4v-.4"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M289.1 238.1q.2-.2.4 0l.1.4h-.4v-.4z"/>
<path fill="#c8b100" d="m292.2 239.2.1.6-.9.3h-.1v-.2l.3-.8z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m292.2 239.2.1.6-.9.3h-.1v-.2l.3-.8.6.1"/>
<path fill="#c8b100" d="m292 240.8-.5.2-.3-.9v-.1h.2l.8.3z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m292 240.8-.5.2-.3-.9v-.1h.2l.8.3-.1.5"/>
<path fill="#c8b100" d="m290.5 239.3-.2.5.9.3h.1v-.1l-.2-.9z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m290.5 239.3-.2.5.9.3h.1v-.1l-.2-.9-.6.2"/>
<path fill="#c8b100" d="M291.5 240.3v-.4a.3.3 0 0 0-.5 0v.3h.4"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M291.5 240.3v-.4a.3.3 0 0 0-.5 0v.3h.4z"/>
<path fill="#c8b100" d="m292.9 242.1.8.1.5.3s.1-.5-.3-.8-.9.2-.9.2z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m292.9 242.1.8.1.5.3s.1-.5-.3-.8-.9.2-.9.2z"/>
<path fill="#c8b100" d="m292.3 241.2-.3.5.8.5v-.1h.2l-.1-1z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="m292.3 241.2-.3.5.8.5v-.1h.2l-.1-1h-.6"/>
<path fill="#c8b100" d="M293 242.2s.2-.2.1-.3h-.4q-.2 0-.1.3z"/>
<path fill="none" stroke="#000" stroke-width=".3" d="M293 242.2s.2-.2.1-.3h-.4q-.2 0-.1.3zm40.7-23.4v.6H331v-.6h1v-1.4h-.7v-.6h.6v-.5h.7v.5h.6v.6h-.6v1.4h1"/>
<path fill="none" d="M179.3 231.6v-1.3m-.3 1.3v-1.3m-.3 1.3v-1.3m-.4 1.3v-1.3"/>
<path fill="none" stroke="#000" stroke-width=".1" d="M178 231.6v-1.3m-.5 1.2v-1.2m.2 1.2v-1.2m-.7 1.2v-1.1m.2 1v-1m-.9 1v-1m.2 1v-1m.2 1v-1m-.7 1v-1m-.2.9v-.8m-.2.8v-.8m-.6.8v-.7m.3.7v-.7m-.5.6v-.6m-.2.5v-.4m-.3.3v-.3m-.3.3v-.2"/>
<path fill="none" stroke="#000" stroke-width=".2" d="M173.8 231v-.1"/>
<path fill="none" d="M180.8 231.5v-1.2m-.7 1.2v-1.2m-.4 1.3v-1.3m152.6 1.3v-1.3m-.3 1.3v-1.3m-.4 1.3v-1.3m-.4 1.3v-1.3"/>
<path fill="none" stroke="#000" stroke-width=".1" d="M331 231.6v-1.3m-.6 1.2v-1.1m.3 1.1v-1.2m-.8 1.2v-1.1m.2 1.1v-1.2m-.9 1.1v-1m.2 1v-1m.3 1v-1m-.7 1v-1m-.3 1v-.9m-.2.8v-.8m-.5.8v-.7m.2.7v-.7m-.5.6v-.5m-.2.5v-.5m-.3.4v-.4m-.2.3v-.2"/>
<path fill="none" stroke="#000" stroke-width=".2" d="M326.7 231v-.1"/>
<path fill="none" d="M333.7 231.5v-1.2m-.6 1.3v-1.3m-.5 1.3v-1.3"/>
</svg>

After

Width:  |  Height:  |  Size: 80 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-fi" viewBox="0 0 512 512">
<path fill="#fff" d="M0 0h512v512H0z"/>
<path fill="#002f6c" d="M0 186.2h512v139.6H0z"/>
<path fill="#002f6c" d="M123.2 0h139.6v512H123.1z"/>
</svg>

After

Width:  |  Height:  |  Size: 237 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-fr" viewBox="0 0 512 512">
<path fill="#fff" d="M0 0h512v512H0z"/>
<path fill="#000091" d="M0 0h170.7v512H0z"/>
<path fill="#e1000f" d="M341.3 0H512v512H341.3z"/>
</svg>

After

Width:  |  Height:  |  Size: 231 B

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-gb" viewBox="0 0 512 512">
<path fill="#012169" d="M0 0h512v512H0z"/>
<path fill="#FFF" d="M512 0v64L322 256l190 187v69h-67L254 324 68 512H0v-68l186-187L0 74V0h62l192 188L440 0z"/>
<path fill="#C8102E" d="m184 324 11 34L42 512H0v-3zm124-12 54 8 150 147v45zM512 0 320 196l-4-44L466 0zM0 1l193 189-59-8L0 49z"/>
<path fill="#FFF" d="M176 0v512h160V0zM0 176v160h512V176z"/>
<path fill="#C8102E" d="M0 208v96h512v-96zM208 0v512h96V0z"/>
</svg>

After

Width:  |  Height:  |  Size: 505 B

+16
View File
@@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-gr" viewBox="0 0 512 512">
<path fill="#0d5eaf" fill-rule="evenodd" d="M0 0h512v57H0z"/>
<path fill="#fff" fill-rule="evenodd" d="M0 57h512v57H0z"/>
<path fill="#0d5eaf" fill-rule="evenodd" d="M0 114h512v57H0z"/>
<path fill="#fff" fill-rule="evenodd" d="M0 171h512v57H0z"/>
<path fill="#0d5eaf" fill-rule="evenodd" d="M0 228h512v56.9H0z"/>
<path fill="#fff" fill-rule="evenodd" d="M0 284.9h512v57H0z"/>
<path fill="#0d5eaf" fill-rule="evenodd" d="M0 341.9h512v57H0z"/>
<path fill="#fff" fill-rule="evenodd" d="M0 398.9h512v57H0z"/>
<path fill="#0d5eaf" d="M0 0h284.9v284.9H0z"/>
<g fill="#fff" fill-rule="evenodd" stroke-width="1.3">
<path d="M114 0h57v284.9h-57z"/>
<path d="M0 114h284.9v57H0z"/>
</g>
<path fill="#0d5eaf" fill-rule="evenodd" d="M0 455h512v57H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 861 B

+56
View File
@@ -0,0 +1,56 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="flag-icons-hr" viewBox="0 0 512 512">
<path fill="#171796" d="M0 0h512v512H0z"/>
<path fill="#fff" d="M0 0h512v341.3H0z"/>
<path fill="red" d="M0 0h512v170.7H0z"/>
<path fill="red" d="M256 388.4a100 100 0 0 0 99.6-99.5V170.6H156.5V289a100 100 0 0 0 99.5 99.5z"/>
<path fill="#fff" d="M256 386.8a98 98 0 0 0 97.7-97.6V172.5H158.4v116.7a98 98 0 0 0 97.6 97.6"/>
<path fill="red" d="M199.6 176.2H162v41.3h37.6zm0 82.6h37.6v-41.3h-37.6zM162 289q0 5.6.7 11h36.9v-41.2H162zm112.8-30.2h-37.6V300h37.6zm0 82.5h37.5V300h-37.6zm37.5 22.6a95 95 0 0 0 21.5-22.6h-21.5V364zm-112.7-22.6h37.6V300h-37.6zm-21.5 0a95 95 0 0 0 21.5 22.6v-22.6zm84.4 41.3a93 93 0 0 0 12.2-1.7v-39.6h-37.5V381a93 93 0 0 0 12.2 1.7q6.6.4 13.1 0zm86.7-82.6q.6-5.4.7-11v-30.2h-37.6V300zm-74.4-41.2h37.5v-41.3h-37.6zm0-82.6h-37.6v41.3h37.6zm75 41.3v-41.3h-37.5v41.3z"/>
<path fill="#fff" d="m352 169.4 23.3-52.8L357.5 88l-29.4 11-20.6-23.7-27.2 15.6L256 71l-24.3 19.8-27.2-15.6L184 98.8 154.5 88l-17.8 28.7 23.3 52.8a232 232 0 0 1 96-20.6c34.2 0 66.7 7.4 96 20.6z"/>
<path fill="#0093dd" d="m184.5 101.2-29.2-10.8-16.3 26.4 6.3 14.2 15.8 36a234 234 0 0 1 36.9-12.8z"/>
<path fill="#fff" stroke="#000" stroke-width=".3" d="M182.9 127.2a14 14 0 0 1 1.6 6.6c0 7.9-6.4 14.3-14.3 14.3a14 14 0 0 1-14-11.5 14 14 0 0 0 12.5 7.3 14.3 14.3 0 0 0 14.2-16.7z"/>
<path d="M169.8 107.5v.2l-1 5.2 3.9 3.4.2.1-.3.1-4.9 1.7-1 5.1v.3l-.2-.2-4-3.4-4.9 1.7h-.2v-.2l1-5.1-3.9-3.4-.2-.2h.2l5-1.8 1-5v-.3l.2.1 4 3.5 4.9-1.7z"/>
<path fill="#f7db17" d="m163.9 114.8 3.7 3.2 4.6-1.6zm0-.2 8.3 1.6-3.7-3.2zm-8.9-1.7 8.3 1.6-3.7-3.2zm8.3 1.7L155 113l3.6 3.2zm.4-.3 5.6-6.3-4.6 1.5zm-6 6.9 5.6-6.4-4.6 1.6zm5.8-6.3-5.6 6.4 4.6-1.6zm5.9-6.8-5.5 6.3 4.6-1.5zm-6 6.3-2.7-8-1 4.7zm3 8.5-2.8-8-1 4.8zm-2.6-8 2.7 8 1-4.8zm-3-8.6 2.8 8 .9-4.8z"/>
<path fill="#171796" d="m232 93.2-27-15.4-20.5 23.4 13.5 53a234 234 0 0 1 38.5-6.5z"/>
<path fill="red" d="M194.7 141a248 248 0 0 1 40.7-6.8l-1.1-13.8a262 262 0 0 0-43 7.2zm-6.8-26.6a275 275 0 0 1 45.2-7.6L232 93.3a289 289 0 0 0-47.5 8l3.4 13z"/>
<g transform="translate(-256)scale(.00253)">
<path fill="#0093dd" d="m212105 36890-23 13-9517-7794-9497 7778 1788 21560c2543-210 5113-322 7709-322 2608 0 5190 113 7744 325l1795-21560z"/>
<g id="hr-a">
<path d="M202545 46585c-18-2-44 10-69 45-186 250-359 469-545 720-195 61-242 180-167 348-261-26-291 193-302 432-250-379-522-482-814-307-11-230-187-338-439-392-180-10-319-65-436-145-60-42-110-64-170-106-126-88-226-5-172 74 267 434 535 868 802 1302-14 80 6 151 88 204 47 133 93 265 140 397-11 38-21 75-32 113-221-105-443-118-664-133-170-8-287-50-361-137-54-63-91-26-92 82-3 534 162 1014 599 1492-231 4-462 11-694 21-79 6-95 39-73 104 126 304 339 579 822 766-208 112-327 285-357 520-9 224-75 382-212 455-60 32-81 65-24 106 253 185 565 193 895 112-157 270-226 553-198 850 208 56 412 15 614-52-29 61-44 175-52 309-7 115-41 229-104 343-32 33-65 84 4 102 336 91 648 52 915-47 0 243 2 487 76 727 18 58 70 102 125 26 155-214 322-396 527-517 31 90 75 168 156 215 96 55 147 170 153 343 0 30-2 60 35 90 149 7 514-380 589-597 206 121 284 246 439 461 55 76 99 29 128-25 62-243 67-481 66-724 267 99 579 138 915 47 69-19 36-70 4-102-62-114-105-250-113-365-9-133-14-226-43-287 202 68 405 108 614 52 29-297-53-579-211-850 330 80 655 73 908-112 57-41 35-74-24-106-136-73-203-231-212-455-30-235-149-409-357-520 483-187 696-463 822-766 22-66 6-99-73-104-231-10-480-24-711-27 437-478 606-961 604-1495-1-108-38-146-92-82-74 87-179 137-348 146-222 15-435 24-656 128-11-38-21-75-32-113 46-132 106-260 153-393 82-53 102-123 88-204 267-434 513-868 781-1302 54-79-46-162-171-74-60 42-110 64-170 106-117 80-257 134-437 145-251 54-417 167-428 397-293-175-564-73-814 307-11-239-41-457-302-432 75-168 17-291-178-352-186-250-458-470-644-720-31-35-51-47-69-45z"/>
<g fill="#f7db17">
<path d="M205075 47978c-51-26-124 17-162 95s-33 170 19 196c40 20 84-6 119-56l22-36c2-3 4-6 5-9 38-78 49-163-2-188zm-5008 0c52-26 124 17 162 95s39 165-13 191-103-24-141-102-60-158-9-184zm4539 905c-32 0-59 27-59 59s26 59 59 59 59-26 59-59c0-32-26-59-59-59m-4032 0a59.1 59.1 0 1 0 .2 118.2 59.1 59.1 0 0 0-.2-118.2m4294-304c-754-91-1506-133-2260-133s-1509 41-2269 115c-26 8-21 90 14 86 756-73 1507-113 2256-113 743 0 1485 40 2228 129 39 4 54-80 32-84z"/>
<path d="M200319 48495c768-75 1530-117 2289-116 754 0 1507 42 2261 133l111-184c-32 10-62 9-90-5-76-38-92-161-36-274 56-114 164-175 240-138 39 19 62 62 68 114l446-739c-204 130-328 214-581 252-281 41-409 139-368 307 38 156-57 133-201 54-314-171-541 71-652 353-73 186-159 181-168-13-4-70 0-131-7-200-21-223-89-286-216-224-161 78-175 25-137-58 28-60 86-128 66-221-9-67-66-92-151-98-182-244-467-483-649-727-182 244-374 483-556 727-86 5-142 30-152 98-20 93 52 157 80 217 38 82 23 135-137 57-127-61-186-3-207 220-7 69-10 139-13 209-9 194-95 199-168 13-111-282-352-524-667-353-145 79-203 102-182-54 23-172-107-266-388-307-253-37-377-122-581-252l419 682c12-25 29-45 53-57 76-38 184 24 240 138 56 113 40 237-36 274-10 5-21 8-32 10l100 163zm4389 911c-7 3-7 4-24 11-46 19-80 66-134 124-57 60-128 125-211 188-12 10-25 19-44-6s-7-35 6-44c80-62 149-124 204-182 30-32 56-63 77-92-95-11-190-21-284-30-79 24-157 55-222 95-59 35-107 77-137 125-8 14-16 27-44 11-27-16-19-30-11-44 35-58 91-107 158-147 33-20 69-38 106-54-107-9-214-18-321-25-22 13-42 29-61 47-20 19-39 42-56 67-9 13-18 26-44 8s-18-31-8-44c19-29 41-54 64-77l9-9c-80-5-161-10-241-14-2 2-5 5-8 7a340 340 0 0 0-93 126c-6 15-12 29-41 18-29-12-23-26-17-41 12-29 27-55 45-81 8-11 18-22 27-33-115-5-230-9-344-12-4 5-9 8-14 11q-37.5 22.5-66 51c-28.5 28.5-35 40-48 63-8 14-16 28-43 12-28-16-20-29-12-43 16-28 35-54 59-77 7-7 14-13 21-19-122-2-244-4-365-4q-180 0-360 3c8 7 15 13 22 20 23 23 42 49 59 77 8 14 16 27-12 43s-35 2-44-12q-19.5-34.5-48-63c-28.5-28.5-41-36-66-51-6-3-12-7-15-12-115 2-230 6-345 11 11 11 20 23 29 35 19 25 33 52 45 81 6 15 12 29-17 41s-35-3-41-18c-9-24-22-46-38-67-15-21-34-41-55-59-4-3-7-6-10-10-81 4-162 8-243 13 4 4 9 8 13 12 24 23 45 48 64 77 9 13 18 26-8 44s-35 5-44-8c-18-26-36-48-56-67s-41-35-64-49c-1-1-3-2-5-3-110 7-220 14-330 23 43 18 85 38 122 61 67 40 124 89 158 147 8 14 16 27-11 44-27 16-35 3-44-11-29-48-78-90-137-125-72-44-159-77-246-102h-2c-90 7-179 15-268 24 22 33 51 68 86 106 55 58 124 120 204 182 13 9 25 19 6 44s-32 15-44 6c-83-64-155-128-211-188-37-38-99-111-135-140-196-90-354-127-575-147-153-14-318-9-458-79 36 85 75 164 126 229 53 68 120 121 209 147 8 2 21 16 22 25 28 157 84 286 169 386 52 60 114 110 188 149-75-81-132-166-172-251-67-142-90-286-77-420 1-16 3-32 34-29 32 3 30 19 29 35-11 123 9 256 72 387 56 118 159 237 291 346 24 19 0 63-29 55-154-44-290-123-383-231-89-104-149-237-180-397-94-32-165-90-222-164-47-60-85-131-118-205 28 428 182 801 456 1137 61 75 165 182 255 216 92 35 95 100-20 101-34 1-69 1-105 1 84 31 164 66 233 105 127 73 217 162 224 273 1 16 2 32-29 34-32 2-33-14-34-29-6-86-82-160-192-223-113-65-259-117-402-160-154 0-312-1-459 3 39 28 80 57 131 84 82 44 188 86 343 122 89 21 166 52 233 91 71 42 130 93 177 150 10 12 20 25-5 45s-34 8-45-5c-42-52-95-98-159-135q-91.5-54-216-84c-161-38-272-81-358-128-75-40-131-82-184-123 180 393 450 573 835 689 23 7 43 13 61 19 3 1 6 1 9 2 86 21 175 40 266 55 92 15 166 28 261 37 16 1 32 3 29 34-3 32-19 30-34 29-99-9-174-22-266-38q-87-15-171-33c-26 6-64 9-107 12-232 14-420 225-435 494 0 5 0 11-1 16 88-80 179-157 273-212 117-68 239-103 364-69 15 4 31 8 22 39-8 31-23 27-39 22-106-28-212 3-316 63-108 63-213 158-315 253-24 147-82 285-205 377 61 34 104 65 163 45 86-39 172-78 261-108 91-31 184-52 282-57 16-1 32-1 33 31s-14 32-31 33c-91 4-179 24-264 53-75 26-149 58-222 91 221 47 460-1 667-79 60-22 105-42 133-41 51-30 112-53 172-79 66-28 132-51 182-57 16-2 32-4 35 28 4 32-12 33-28 35-112 13-127 21-222 79 0 21-66 57-126 96-36 24-70 52-87 67-95 86-144 181-188 287-29 70-52 145-68 224 55-108 121-211 201-303 94-108 208-201 345-265 14-7 29-13 42 15 13 29-1 35-15 42-129 60-236 147-324 250-90 103-161 222-219 345-31 64-8 1-42 86 110-122 212-224 323-307 132-100 283-157 418-133 15 3 31 6 26 37s-21 28-37 26c-116-21-250 32-369 121-121 92-244 223-366 361 184 26 366-26 542-85 91-30 183-135 239-152 19-24 38-46 57-67 33-37 67-71 102-100 12-10 24-20 45 4s8 34-4 45c-33 28-65 60-96 94-32 35-62 73-92 113-6 8-13 17-24 16-60 70-151 162-172 240-57 210-25 370-122 576 71-38 128-81 175-134 53-60 94-135 128-230 37-104 95-195 167-270 75-77 165-136 261-172 15-5 30-11 41 19s-4 35-19 41c-87 32-169 86-238 157-66 68-119 151-153 247-37 102-81 183-141 250-44 50-95 91-156 127 52-3 78-10 121-7 79-6 211-66 279-119 66-51 116-120 154-206 6-15 13-29 42-16s23 27 16 42c-42 96-99 174-173 231-56 43-121 75-196 93 161-5 311-42 467-100 65-24 87-168 127-208 32-58 66-112 105-158 47-56 101-101 164-127 15-6 29-12 41 18 12 29-3 35-17 41-52 21-98 60-139 108-36 42-68 93-98 147 10 73-51 228-53 305-7 205-2 409 53 612 53-71 107-134 162-192 0-5 0-10 1-15 18-106 33-219 40-332 7-112 7-223-6-329-2-16-4-32 27-35 32-4 34 12 35 28 14 111 14 226 7 340-6 90-16 180-30 269 54-51 53-51 77-103 37-80 59-159 67-237 9-80 5-157-13-230-4-15-7-31 24-38s35 8 38 24c19 80 25 165 14 252-8 65-24 132-49 199 56-42 114-82 178-122-4-75-5-153-3-227 2-68 7-134 18-190 4-20 7-40 47-33s37 27 33 48c-9 50-14 111-16 177-2 78 0 162 4 243 5 82 49 185 125 230 103 62 158 163 186 274 16-145 17-280 3-400-17-143-55-26Line truncated
<path d="M204649 49231c-680-88-1359-113-2041-114-684 0-1369 40-2058 112-20 6-15 33-14 46 2 28 37 35 121 27 643-60 1285-93 1932-93 674 0 1351 21 2038 102 33 9 77-85 22-81z"/>
<path fill-rule="evenodd" d="M200570 49160c683-71 1362-110 2038-110 675 0 1349 40 2025 127l31-127c-17 9-37 15-58 15a123 123 0 1 1 113-171l60-170c-724-84-1446-122-2171-122-729 0-1459 38-2193 107l58 164c22-32 59-54 101-54a123 123 0 1 1 0 246c-12 0-25-2-36-6l33 94-2 7zm3067-416a123 123 0 1 0 0 246 123 123 0 1 0 0-246m0 64a59.1 59.1 0 0 0 0 118c32 0 59-27 59-59s-26-59-59-59m-1082-91a123 123 0 1 0 123 123c0-68-55-123-123-123m0 64a59.1 59.1 0 1 0 .2 118.2 59.1 59.1 0 0 0-.2-118.2m-1064-40a123 123 0 1 0-.2 245.8 123 123 0 0 0 .2-245.8m0 64c-33 0-59 26-59 59s26 59 59 59a59.1 59.1 0 0 0 0-118"/>
</g>
<path d="M202601 47974c-14-68-49-129-100-175-51-47-116-78-187-88-33-4-39-58-7-68 60-20 114-67 157-133 45-69 79-157 95-256 5-34 64-35 69-1 15 84 51 153 97 208 55 66 125 112 193 138 31 12 25 63-8 68-59 9-105 42-141 87-50 62-81 145-100 221-8 33-62 31-69-2zm33-118c20-52 47-103 81-146 28-34 60-64 99-84-51-30-100-70-143-120-28-34-53-73-73-116-19 59-45 112-75 158-31 47-67 86-108 116 50 19 95 47 134 82 34 31 63 68 85 110m799 5115-515 206c-17 7-35 14-48-21-14-34 4-41 21-48l515-206c17-7 35-14 48 21 14 34-4 41-21 48m59-326-604 328c-16 9-33 18-51-15s-1-42 15-51l604-328c16-9 33-18 51 15s1 42-15 51m-1826-65 604 328c16 9 33 18 15 51s-34 24-51 15l-604-328c-16-9-33-18-15-51s34-24 51-15m51 322 515 206c18 7 35 14 21 48-14 35-31 28-49 21l-515-206c-17-7-34-14-21-48 14-35 31-28 48-21zm224 434c137 33 261 48 358 31 88-16 155-60 191-146v-493c-107-1-212-15-303-41-109-31-170-98-201-178-41-107-27-235-4-329 5-18 9-36 45-27s32 27 27 45c-20 82-33 194 1 284 23 60 69 110 152 133 91 25 198 38 307 38 107 0 214-13 304-40 82-24 148-69 192-123s65-117 57-176c-5-36-24-62-49-80-34-24-82-35-128-37-47-2-94 7-142 16-25 5-50 9-77 13-19 2-37 5-42-32s14-40 32-42c23-3 48-8 73-12 52-10 105-20 159-18 60 2 121 18 168 51 42 29 72 72 80 131 11 80-16 163-73 233-53 65-131 119-229 147-83 24-178 38-274 42v483c3 5 3 11 2 16 37 82 102 125 188 141 97 18 221 2 358-31 18-5 36-9 45 27 8 37-9 41-28 45-146 35-279 51-388 32-92-17-165-58-215-132-49 74-124 115-215 132-109 20-242 4-388-32-18-4-37-8-28-45 8-36 27-32 45-27zm356 210 402-9c19 0 38-1 38 37 1 38-18 38-37 38l-402 9c-19 0-37 1-38-37s18-38 37-38m593-3082c151-125 293-227 423-297 133-72 254-111 359-106 19 1 37 1 36 39-1 37-20 37-39 36-92-4-200 32-322 97-125 67-263 166-410 289-14 12-29 24-53-5s-9-41 5-53zm-605 56c-141-130-298-240-445-314-139-71-268-108-363-100-19 2-37 4-40-34-4-37 15-39 34-40 110-10 252 31 404 107 152 77 315 191 461 325 14 13 28 25 2 53-25 27-39 15-53 2zm-213 1004c37-83 83-155 136-219 53-63 112-119 174-170 14-12 29-24 52 5 24 29 9 41-5 53-59 48-114 101-164 160-49 59-91 125-125 201-8 17-15 34-49 19s-27-32-19-49m371-1734c49 66 88 139 114 223 26 82 40 175 39 279 5 80 6 165-7 249-13 86-42 170-97 246-43 60-101 97-165 113-53 13-109 10-164-7 29 100 51 208 6 308-8 18-33 27-51 18-43-22-86-43-128-62s-84-36-127-51l-1-1c-95-37-173-73-236-112-65-39-115-80-150-124l1 2c-44-49-72-106-88-170-14-55-20-114-22-174-72-39-138-78-194-116-64-43-118-87-161-131-13-14-26-27 1-53s40-12 53 1c39 40 89 80 150 121 60 40 128 81 204 121 124 13 247 51 370 109 106 50 211 115 317 192 13 7 19 16 27 20 8 6 16 13 25 19 51 22 104 28 152 16 47-11 90-39 122-84 48-66 72-139 84-214 12-77 11-157 6-234v-2c1-97-12-183-35-258-24-76-58-142-102-201-11-15-22-30 7-52s41-7 52 7zm-375 1047c-104-77-207-141-311-190-105-49-210-83-314-98q3 72 18 135c13 52 35 99 71 138l1 1c30 37 73 72 130 107 60 36 134 71 225 106l-1-1c45 16 89 34 133 54 31 14 61 28 93 44 19-83-10-179-37-267-2-8-5-15-9-29zm776-1003c-44 59-79 125-102 201-24 76-36 161-35 258v2c-5 77-6 158 6 234 12 75 37 148 84 214 32 45 75 72 122 84 48 12 101 6 152-16l25-19c6-4 13-12 27-20 105-77 211-143 317-192 123-58 246-95 370-109 75-40 144-80 204-121s111-81 149-121c13-13 26-27 53-1s14 39 0 53c-43 44-97 88-161 131-57 38-122 77-194 116-2 61-8 119-22 174-16 63-44 121-88 170l1-2c-35 44-85 85-150 124-63 38-141 75-237 112l-1 1c-43 15-85 32-127 51-43 19-85 40-128 62-18 9-43 0-51-18-45-100-23-208 6-308-55 18-111 20-164 7-64-15-122-53-165-113-55-76-84-160-97-246-13-85-12-169-7-249-1-104 13-196 39-279 26-84 65-158 114-223 11-15 22-30 52-7 30 22 19 37 7 52zm940 715c-105 15-209 49-314 98-104 49-207 113-311 190-4 13-6 21-8 29-27 88-56 184-37 267 31-15 62-30 93-44 44-20 87-38 133-54l-1 1c91-35 165-70 225-106 58-34 100-70 131-107l1-1c35-39 57-86 71-138 11-42 16-87 19-135z"/>
<path fill-rule="evenodd" d="M203459 50602a216.4 216.4 0 0 0 0 433 216.6 216.6 0 0 0 0-433m0 69c-81 0-147 66-147 147s66 147 147 147 147-66 147-147-66-147-147-147m0 60a87 87 0 1 0 .1 174.1 87 87 0 0 0-.1-174.1m-1697-124c119 0 217 97 217 216s-97 217-217 217a216.6 216.6 0 0 1 0-433m0 69c81 0 147 66 147 147s-66 147-147 147-147-66-147-147 66-147 147-147m0 60a87 87 0 1 1-.1 174.1 87 87 0 0 1 .1-174.1"/>
</g>
<use xlink:href="#hr-a" width="100%" height="100%" transform="rotate(-2.2 -55532.8 156275.8)"/>
<use xlink:href="#hr-a" width="100%" height="100%" transform="rotate(2.2 459865.8 156275.8)"/>
</g>
<path fill="#171796" d="M328.1 101.3 307.6 78l-27 15.4-4.5 54.6a235 235 0 0 1 38.5 6.4l13.5-53z"/>
<path d="M286 104.7q1.4-.5 2.7.2.6.3.9.7l1.2-1 2-1a8 8 0 0 1 2.9-.9l3-.1q1.3 0 2.5.7l2.1 1.1 2.3 1.1a10 10 0 0 0 4.8.4q.9 0 .2.5c-3.5 2.2-6.3.2-8.6-.6l2.2 1.8q1.3 1.3 3.7 2.5a9 9 0 0 0 3.8 1l1.7-.2q.4 0 .4.2l-.2.4a5 5 0 0 1-2.7.8q-2.9 0-5.6-1.4-2-1.2-3.5-2.6a8 8 0 0 0-3.2-1.5 6 6 0 0 0-3.1.1q.4 0 .6.4.8.4 2 .5.8.1-.3.8-.7.8-1.8.8c-1 .7-1.4.2-1.8-.2l-.2.8v.5l.2.8.2.4.4.7q0 .3.2.5l.7.6q.9.4 1 1.3.7.2.8.9.4.1.6.5h2.8q1.3.3 2.1 1.4h1.3q.6-.3 1.4-.4h2.5l1.3.8q.8.7 1.9.3a3 3 0 0 1 2.5 0q.6-.3 1.2-.2.4-.5 1-.5 1-.2 1 .9-.1.4-.4.4-.5.9-1.4.7l-.5 1q.4 1.3-.7 1.2-.3.5-.7.4l-1 .6.3.6c.5.7-.2 1-.8 1q.2.8.1 1.4 1 .6.1 1.2.7 1.2-.5 1.8.1.7-.4 1t-.3.6q.6 1.1-.2 1.3l-.2.1q0 .2-.2.2l-1.6 1.1h-.3q-.5 1.3-1.8 2.5a2 2 0 0 1-1 1.3q0 .3-.4.3.6.6.2 1a3 3 0 0 1-1.4 1q-1.6.4-2.2-.2-.4-.5 0-.7-1 0-.8-.8 0-.2.4-.2l1-.3.5-.6q.2-1 1.2-1.4.8-.3 1.5-1.3l1-1.5-.3-.9-.6-.5q-.7 0-.8-.5h-.3l-.7.2-1.2 1q-.2.5-.8.5c-1 .2-1.5 1.3-2 1.8l-.5.8q0 1-.5 1.1h-.7q.4.4 0 1-.3.3-.9.4l-1.7-.3q-.7-.3-.5-.7-.6-.3-.4-.5 0-.4.5-.3l.6-.2a6 6 0 0 1 2-1.5l.7-.7q0-.8 1-1.5l.2-.6v-.3q-.3-.6-.2-1.2v-.6q-1.6.9-1.7 0-.6.5-1 0h-1.3l-.8.3-.6.7a3 3 0 0 1-.5 1.5l-.7 1.7-.1.5q0 1-.5 1.1l-.5.8v.2q.3.6-.2 1.2l-1 .5q-.5.2-1 0c-.6-.2-.5-.4-.5-.6h-.5l-.4-.3q-.2-.3.2-.5l.9-.6q0-.3.4-.5.3-.6.7-.7l.7-1.6q.2-.2.1-.5l.1-.3q.2 0 0-.2a1 1 0 0 1 .3-1.2c.3-.5.6-1.6.3-2.1l-.1-1h-.3q-.4-.2-.6.3l-.4.6q-.4 1.4-1 1.7l-.2 1.2q0 .8-.2.8t-.5.6l-.1.3q.4.5 0 1-1.2.9-2.5.3-.9-.3-.7-.7c-.9-.1-.7-.8 0-1a4 4 0 0 0 2-1.5q0-1.4.7-1.5.1-.8.5-1.5t.3-1.4q-.7-.5 0-1l-.1-.3q-.4 0-.3-.6 0-.2-.2-.2c-.7 0-.5-.4-.2-.7q.2-.2 0-.4l-.1-.5q-.6-.4 0-1-.4-.2-.4-.7-1.2-.1-.7-1l.7-.7q.4-.5.3-.9c-.2-.5.5-1 1-1.4v-.4q-.5-.5 0-1v-.4q-1.4.2-.5-1.1-.8-.4.5-1.6l.1-.4-1 .4q-.6.2-1 0l-.5-.4-.2-.7c-1 0-1.2-.7-.6-1.1l.6-.9q.6-.9 1.4-1.6l.1-.6-.8-.3q0-.4-.6-.6-.3-.2-.1-.5-.6-.7-.3-1z"/>
<g fill="#f7db17">
<path d="M304 130.2h-.3l-.8.8c-.2-.3-.6 0-.2.1l-.2.2q-.2.4-.6.5h-.2v-.4l.1-.4v-.1l-.2 1c-.8.2-1.3 1.1-2 1.7l-.4.9c0 .2 0 1-.3 1h-.2q-.1-.3-.4 0h-1c-.3.2.3.1.6.3q.2.2.2.5c-.3.7-2 .5-2.5.2q-.4-.2-.3-.5h.4l.6-.2v-.2q0-.2-.2 0l-.5.1h-.5q-.2 0-.1-.1h.2l.7-.3a6 6 0 0 1 2-1.5l.8-.7q.2-.9 1-1.5 0-.4.3-.8v-.4q-.3-.6-.2-1v-1l.9-.6v.8l-.2.3v.3-.2l.3-.3q.4 0 .8-.4l.7-.7v1.2l-.6.7v.1h.1l.5-.7h.1l.1-.2.9-.4v1z"/>
<path d="m287.4 120.6.2-.2.4-.6.5-.7h.1v.1l-.5.6-.4.6v.2q0 .5.3.8l.3-.5.5-.4.3-.3.2-.3h.1l-.2.4-.4.3-.4.4-.3.3q.2.2 0 .4c-.1.3-.4.5 0 .8l.2.5q.2.3-.1.7c-.3.3 0 .2.1.2h.1l.3-.4.3-.4.4-.5.2-.6h.1l-.2.6-.4.6-.3.4-.3.4q.3.3.2.8h.2l.2-.3.2-.4h.1l-.2.5-.2.2q.3.3 0 .7-.6.4 0 .6v1.7-.4l-.1.1q-.5 1-.7 1.9c-.7.1-.6.8-.6 1.4a4 4 0 0 1-2 1.6q-.4 0-.6.3.1.3.4.2.8-.6.2.2v.3c.6.4 1.8.6 2.4.2q.7-.3.2-.9 0-.9.8-1.3.2-.1 0-.4 0-.8.2-1.4l.2-.2q.4-.1.7-1.3l.1-.4q0-.3.3-.1l.1-.4q.4-.6 1-.4l-.2-.9.1-1 .1-.2.3-.8.4-.8v.1l-.3.8-.3.8v.1a3 3 0 0 0 .2 2v.1q.3 0 .2.4v.6c.4.6 0 1.8-.3 2.3q-.2.4-.2 1 .2.2 0 .5v.1l-.3.6-.7 1.7q-.6.2-.7.8-.4 0-.4.3l-1 .7q-.2.1.3.4.3 0 .6-.4t.2 0l-.2.7c0 .2.6.3.7.3q.8-.2 1.3-.6t.1-.8h-.5l-.6-.3q0-.2 0 0l.7.1h.5v-.2l.5-.9q.5-.2.4-1l.1-.5q.5-.7.8-1.7.5-.8.5-1.5 0-.4.3-.4 0-.2.3-.5l.2-.4.1-.2v-1l-.2-.2v-.2h.1v.2l.1.1.2.6v.5l-.2.2-.1.4.7-.2.4-.5.2-.6h.1l-.2.7-.3.4 1.1-.2v-1.2l.4-.8-.2.8v1.2q.1.5.5.3l.4-.3v-.1l2-1.6-1.7 1.5v.3q-.1.7.6.4l.6-.3.3-.2 1-.7.2-.6.8-1.3.7-.6.5-.7-.4.8-.7.6a4 4 0 0 0-.9 1.8v1l.7-.4.8-.7q0-.5.3-.6l.4-.4v.2l-.4.3-.2.5v1.2l1-.6h.1v1.1q0 .5.4.8l.5-.6.4-.3.2-.2.2-.3h.1v.1l-.2.2-.3.3-.3.2v.5h.7q-.1.7.5.6v-.5l.1-.5h.1v1q.2.5.6.7l.2-.5.1-.5h.1v.5l-.3.6v.5l.2-.3.3-.4h.1l-.3.4-.2.4.2.2c-.7 1.1-1.4 2.7-2.6 3.2q-1 .3-1.1 1.3l-.6.6q-.6.3-1.3.4 0 .4.4.4l.8-.3s-.1.5-.6.8v.2c.4.6 1.4.4 2 .2.4 0 1.1-.6 1.3-1q.1-.3-.2-.6c-.8.1-.7-.6 0-.3q.3.1.3-.4 1-.2 1-1.1l1.8-2.2.1-.6.2-.4.1-.5h.1v.5l-.2.4q0 .2.2.2.7-.7 1.6-1.1 0-.4.5-.4l.1-.1q.2-.5-.2-.9 0-.5.4-.7.4-.5.3-1.1v-.2l-.1-.3.2.3v.1q.5-.2.7-.6l-.3-.9-.6.3v-.1l.7-.4.3-.2c.2-.3-.3-.6-.5-.7l-.8-.7v-.1h.1l.7.7v-1.3l-.2-.4-.5-.4-.2-.5h.1l.2.5.4.3q.5.2 1 0c.4-.2-.1-.7-.2-1l-.2-.5h.1l-.1-.2h-.2v-.1h.2l.2.3h.1q.5-.1.8-.6l-.4-.4-.4-.4.5.3.5.5q.4 0 .5-.3l-.2-.5-.3-.4q.3 0 .4.4l.2.4h.5c.3-.2 0-.8 0-1l-.2-.2h-.2v-.2h.1l.2.1.2.1.4-.6c0-.4.1-.2.5-.3q.6.1 1-.7.2 0 .3-.3.1-.5-.4-.5-.7-.1-1.1.4v.2q.2 0 0 .1l-.1-.2-1.3.2h-.1l.2.3.1.4v.1h-.1l-.1-.5-.3-.4-1-.2.1.1.2.2v.1l-.3-.2-.2-.2-.9.2-.6.2.4.5.2.6v.1h-.1l-.2-.6-.4-.5h-.6l.2.3-.3-.4-.5-.2.2 1.6h-.1v-1l-.2-.7-.3-.2-.6-.5-.2.8.1-.8-1.1-.3.6 1 .3.4v.5l-.1-.5-.3-.4-.3-.5-.4-.5h-.4.1l.1.3h-.1v-.2l-.2-.1h-.8a6 6 0 0 1 1 2.4v.1l-.5-1.3-.7-1.2-.7.2.5.4-.3-.2-.3-.2-.3.1h-.2l1.1 1.2-.6-.6-.6-.5h-.7l.5 1.9-.3-1-.4-.8h-.4l.4 1.7h-.1l-.2-1-.2-.8a4 4 0 0 0-1.4-1.1 2 2 0 0 1 .4 1.2h-.1l-.1-.7-.4-.6h-.4l-1-.1q.4.3.4.7h-.1q0-.3-.5-.7h-.7l.3.3.3.5q0 .4.2.6 0 .3.4.5l-.5-.4-.3-.7-.2-.4-.3-.5h-.7l.2 1v1l-.1-1-.3-1-.5-.4-.2.3v-.4q-.2-.7-.7-.9v.5l-.2.5q-.2 0 0 0v-.6l.1-.4q-.1-1-1-1.3v.7h-.1v-.9l-.5-.5-.1.8-.4.9h-.1l.4-1v-.8l-.1-.3-.1.3h-.1v-.3l.1-.1v-.1l-.3-.5-.3.5.2-.6-.1-.3-.1.2-.3.2.2-.3v-.1q.2 0 0-.2.1-.4-.1-.8h-.4l-.5.4v-.1q.3-.3.5-.3l.4-.1v-.3l-1.2.3h-.8v-.2l.8.1 1.2-.3.2-.6h-.6l.6-.1v-.2q.1-.4.5 0 .3 0 .5.3.4.2.9-.2h-.3v-.1h.4q.8.1 1.5-.5h-1l-.7-.2v-.1l.7.2h1l.2-.1.4-.3-2-.6-.8-.4a2 2 0 0 0-1.4.3l-.3-.3-.5-.1h-.7v-.1h.7l.6.1 1.9-.4 1.8-.2v-.2q.4-.4.3-1-.2-.4-.8-.7h-1.4l-.9.1q.4.2.6.5.4.4.5 1v.1h-.2q0-.7-.4-1t-.8-.5l-1.4.3q-.5 0-.8.3l1 .1q.3.2.6.8v.1h-.2q-.2-.6-.5-.7c-.5-.2-1.4 0-1.8.2l-.6.7h-.2v-.2l.7-.7.7-.3 1-.6 1.5-.2-.6-.6h-.7l-1.7.8h.6v.2h-.9s0 .1 0 0l-1.6 1.3q-.9 0-1 .2-.2.2-.2.6l-.2.8q-.9.7-1.4 1.6l-.3.6h.3v.1-.3l.3-.4-.1.4v.6h-.2l-.1-.3h-.3l-.4.3-.2.3q0 .4.6.3c.6 0 .1.4.5.7l.4.5h.6q0-.7.2-.7l.2-.4v.3l-.1.2v.4l1-.3q1.2-1 .5 0l-.1.2-.2.7c-.2.1-1 .8-.8 1.1q.4 0 .3.2c0 .2-.4.7-.3 1h.3l.8-.7.6-.8v-.1l.3-.8.3-.8h.1l.3.3.2.1h.3l.3-.3s0-.1 0 0l-.2.3-.4.1h-.3l-.2-.3-.3.7-.2.7v.2l-.7.9-.6.5.2.6 1-1 .9-1.1-.3.6-.1.4v.8l-.1-.8v-.2l-1.3 1.4q-.7.3-.3.7l.4-.3.4-.3h.1v.1l-.4.3-.4.3.1.4 1-.6-.8.6-.1.2c-.3.2-1.3.8-1.2 1.2q.4 0 .7-.3l.7-.5v.1l-.6.5v.3h-.2v-.2l-.5.2q0 .6-.4 1c0 .2-1 1-.7 1.2h.4z"/>
<path d="m287.9 106.9-.8-.3-.5-.6q-.3 0-.1-.3l.3-.1h.3l.2.2-.2-.3h-.8l-.2-.6.4.1.2.2-.2-.3h-.2a3 3 0 0 1 2.3.3q.5.2.8.6l-.2.2q-.8 0-1.1.2-.2.2-.3.7z"/>
</g>
<path d="m304.4 130-.4.2.4-.6zm2.1 4.5-.4.4-.5.4.5-.5zm1.4-1.7-.2.3q-.2 0 0 0zm-.7 0a1 1 0 0 1-.7.7l.4-.4.2-.4zm1.3-1.7-.1.2-.1.2h-.1l.2-.5zm1.1 0-.1.5-.2.5h-.1l.2-.5.1-.5zm-.5-6.4q.5.7.5 1.5l.1-.5a2 2 0 0 0 .3-1.3h.1v.7l-.3.6-.2 1v.1h-.2v-.1q.1-1-.4-2zm-.8 1v.3h-.1v-.2s0-.1 0 0zm-.2 1.5.2 1.5.4-.4h.1v.1l-.3.3-.2.3-.2-.9-.2-.8h.2zm1.1.6v1.2zs-.1 0 0 0m1-.2v1.8l.1.6-.3-.6v-.7l.2-.5zm.5-1.7v.3l-.1.3s0 .1-.1 0v-.3zm-.5-2.8.1.3h-.1zs-.1 0 0-.1m.3-2v.8l-.3.4v.6h-.1v-.7l.3-.4zm-2.1-.8.8.7q.3.4.3 1h-.1l-.6-.2q.2 1.2 0 2a2 2 0 0 1-1 1l-.1-.1a4 4 0 0 0 .1-1.8h.1v1.7q.5-.3.8-1 .2-.6 0-1.9l.7.2-.3-.8-.8-.7zm5.5-1zh-.1v-.2zm-1.3-.1.2.2.2.2-.2-.2-.3-.1v-.1zm-2 .5.3.6v.6s0 .1 0 0v-.6zm-6.4.7v.4h-.1zm1.2-.7v.3l.1.1v.1l-.1-.1zm2.5 1.7v.3h-.1zm.8-1.9.1.2v.2h-.1v-.3q-.2 0 0-.1m-5.9.3.1.4.2.3.2.5v.4-.4l-.3-.4-.2-.4zm2.4 1.6.2.7v.8q0 .5.2.8t.7.7l-.2-1 .4-1 .3-.4v-.5h.1v.5l-.3.5-.3 1 .1 1v.1l-1-.8a1 1 0 0 1-.1-1v-.7zm-1 1.5-.1.8-.5.6.3-.1.7-.6.4-.3-.3.4-.3.3.1.3v.1h-.1v-.4l-.5.3-.4.1s-.1 0 0 0l.5-.8zm-1.1-.1v.2h-.1v-.2z"/>
<path d="M302.4 121.3q.2.6.1 1 0 .6-.4 1l-.6.7-.1.5.2-.2q0-.2.5-.3l1.2-1h.1l-.6.6-.7.5-.5.3-.3.4h-.1l.2-.9.6-.7.4-.8-.1-1zm2.3 3.8.2.4.1.2q.3.3.3.8l-.1 1h-.1l-.4-1-.9-.7 1 .7.3.7v-.7l-.2-.8v-.1q-.4-.2-.3-.5zm1 0 .2.1v.1q.2 0 0 .1l-.1-.1zm1.3.4-.3.7-.2.7s0 .1 0 0h-.1l.2-.7.3-.8zm.7 4.1v.2h-.1v-.2zm-.8-1.2v.4l-.2.4v-.5zm-1 0v.2l-.1-.1v-.1zm-1.3-.6-.1.4h-.1l.1-.4s0-.1.1 0m-1.8 1.9-.1.2v.3h-.1v-.3zm-5 5-.1.1-.2.2h-.1v-.1l.3-.3zm.8-.5-.1.2h-.2s0 .1 0 0v-.1l.2-.1zm1-.6-.2.2v-.1l.1-.2zm1.6-4.1v.8l-.1.1-.1-.5.1-.5zm1-11v.3l-.3.4v-.1l.2-.3v-.4zm-1-1 .2.5v.5h-.1v-.5l-.2-.5zm-1.5 1.8-.4-.5-.1-.4q.2 0 0 0l.2.4zq0 .1 0 0m1.6 2.7v.3zm-2-2q.4.3.6 1v.8h.1q.2 0 .3-.4l.2-.9.2-.6.1-.6h.1l.5.9.3 1h-.1l-.3-1-.4-.7v.5l-.3.5q0 .7-.2 1 0 .3-.3.4h-.1v.5h-.1l-.1-1.3-.6-1v-.2zm1.2 5.1v.5l-.2.4v-.9zm-2.4 1 .1.4h-.1zm2-2.6-.1.6-.4.6-.3.7v.7l-.1-.8q0-.3.3-.7a2 2 0 0 0 .6-1.2zm-.5-.8v.6l-.5.6-.4.5-.3.6.2-.6.5-.6.4-.5v-.6zm-2.5 1.2q0 .6-.2 1-.2.6-.7 1-.2-.1 0-.2.4-.3.6-.8.3-.4.2-1zm-3.3 1.8v.2l.2.2h-.1l-.1-.1-.1-.2v-.1zm-1.3 0v.8q0 .3.4.7l.2.9.4-.6.1-.6h.1l-.1.7-.5.6h-.1v-.5l-.2-.5-.3-.7-.1-.8zm.2 4.5.1-.8h.1l-.1.8zm-.2 1.2v-.5h.1v.5zm-.9 2.1.3-.3.2-.3h.1l-.2.4-.3.3v-.1zm-1.2-7v.2zm-2 4.8v-.3zm5.2-8.5-.2 1q0 .6.3.8.4.3.5.7l.1-.4v-.4h.1l-.1 1h-.1l-.1-.2q-.1-.4-.5-.6-.3-.3-.3-.8t.2-1.1zm-.4-1.4v.8l-.3.8-.2 1q0 .6.3 1.1v.1a3 3 0 0 1-.2-2.2l.3-.8zm-2.4 3.5v.5l.1.5-.3-.5v-.6zm-1-.4-.2.6v.3l.1.3-.2-.3v-.4l.1-.2v-.3zm6.1-9.2a3 3 0 0 0 .3 1.6l-.4-.8zm-.8.7a4 4 0 0 1 .6 1.9h-.1a4 4 0 0 0-.6-1.8h.1zm-3.8.2q-.6.8-.6 1.3t.2 1a3 3 0 0 1 0 1.7h-.1l.2-.9-.2-.8-.2-1q0-.6.6-1.4.2 0 0 0zm3.6-1.6v.5l-.4.5-.4.5v.7q-.2-.4 0-.8l.3-.5.3-.4v-.4zm-3.8.4v.7l-.4.6q-.4.3-.4.7l-.2.8v-.9l.5-.6.4-.7zm2.1 0v.3l.1.3-.2-.2v-.3h.1zm0-.5-.5.4-.2.8.2.6.1.7h-.1v-.7l-.3-.5q-.6.6-.6 1.3a3 3 0 0 0 .5 1.6 3 3 0 0 1-.6-1.6q0-.8.7-1.4 0-.5.2-.8zm-.7-.8v.1q0 .5-.2.8l-.3.3v.4h-.1v-.4l.3-.4.2-.7zm6 6.5.3.8h-.1v-.4zm0 2v.6l-.2.7-.2.6h-.1l.2-.6.3-.7zm-1.2-2a3 3 0 0 1 .7 2.8h-.1a3 3 0 0 0-.7-2.6v-.1h.1zm0 2.3-1 1.4-.6 1-.2-.5-.2-.5q-.3-.4-.2-.9t.3-.9l.3-.6v-.6h.1l-.3 1.3-.3.8.2.9.3.7.5-.7zm-3.4-1v.7l.4.7h-.1l-.3-.6zm-1.9 1v.3zm.7-1.7-.4 1q-.2 0 0 0l.2-.5v-.5zM291 124a4 4 0 0 1-.3-1.9l.6-1.1.5-.7v-1h.1v1l-.6.8-.5 1q-.2.7.3 1.9zm-1-1.3v.8s.1 0 0 0l-.2-.4v-.4zm4.8-3.4.3.9-.2 1q-.2 0 0-.1l.1-.9-.3-.8zm1.5-1.1a3 3 0 0 1 0 1.7l-.2-.7-.5-.6q0-.1.1 0l.6 1v-.6zm.9-1.3.4.8.1 1.1v.5l.1.5-.2-.4v-.6l-.1-1q0-.5-.4-.8zm-2.4-.2-.2.6v.6h-.1v-.7l.2-.6h.1zm-4.6 3.1-.4 1.2-.8.7h-.1l.8-.8.4-1v-.1zm-.1-1.6v.5l-.3.5.1-.5v-.4l.1-.1zm3.1-.2v1.1h-.1V118zm.8-1.4q-.4.4-.4.8l.2.8q.4.6.3 1.2 0 .7-.3 1.3h-.1l.3-1.3-.3-1.2-.2-.8q0-.5.4-.9v.1zm-5-8.7 1.2-.5q.6 0 1.2.3h.8-.8v.1l-1.2.7a1 1 0 0 1-.9-.2v-.1l.9.2 1-.6-1-.2q-.5 0-1 .4z"/>
<path d="M290.2 107.8a.3.3 0 0 1 0 .6l-.3-.3q0-.3.3-.3m1.9 1.7.5-.3.3-.4q.2 0 0 0l-.2.5zm4-1.6h.2l.4.1v.1h-.1l-.3-.1zm-2.3 0 .4-.4.7-.1v.1l-.7.1zm.2.4.2-.2.3-.2v.1l-.3.1v.2zm-3.7 1.3-.2.3v.3h-.1l.2-.7q.2 0 0 0zm1 .5v.1zm-.6-1.2h.7l-.4.1h-.4v-.1zm.7-2h-.3l-.1.2h-.1l.2-.3zm-1.2 0-.2.2-.1.1v-.2zm-.7 0-.1.2-.1.2h-.1v-.2zm-.8.8-.4.4h-.1l.4-.5zm0 1-.1.1-.2.2.1-.2zm-.9.2v.4zm1.2 1.5v.6s0 .1-.1 0v-.6q.2 0 0 0zm-.7-.5v.4h-.1v-.4zm-.6-4.8.5.5v.1h-.1l-.2-.3-.2-.2s-.1 0 0 0zm5.5 7.2a2 2 0 0 1 0 1.5v-.8l-.1-.6v-.1zm-1.8 2 .3-.6.5-.6a2 2 0 0 0 .3-1.5v-.1h.1v.9l-.3.7-.5.6-.3.7q-.2 0 0 0zm-2.3-.5.2-.3.3-.2v.1l-.3.2zm-.5-.2.3-.3.4-.2-.3.3-.3.3zm2.5-2.3h.5-.6zm-1.3-.2v.2h-.1zm25.8 7.4.2.2v.2l-.1-.1-.2-.2h.1zM287 132l.4.2.5.1v.1h-.5l-.5-.4z"/>
<g fill="red">
<path d="M308.6 106.3h1.8q-1 .5-2 .7l.2-.3zm-1.5-.1 1.3.1v.3l-.3.3v.2h-1.3l.3-.5zm-11.2-3.3h2.2q.3 0 .5.4.2.3.1.8l.1.1h.1l-.1-1-.3-.3h.2q1.2 0 2.3.6l.2.6-.4.6q.2.2.2 0 .3-.2.4-.6v-.4l1.8 1v.5l-.5.3s-.1 0 0 .1q0 .2 0 0 .4 0 .7-.3v-.5l1.3.6v.4q0 .3-.4.4v.1q0 .1.1 0 .4 0 .5-.4v-.3l.5.1 1.4.4.1.4-.2.4v.2c-1.5-.2-3-1-4.4-1.5l-.5-.2-1.7-.7h-.2v-.1l-1.5-.4h-1.8q0-.5-.2-.8z"/>
<path d="m293.3 103.6 2.2-.6q.6.2.7.5.2.3.1.7a5 5 0 0 0-2 .2q-.2-.4-.6-.7h-.4zm8 4-.6-.3a7 7 0 0 0-3.3-.9q.6-.6.4-1.2l-.7-.8 1.1.1 2 .5q.2.6.1 1-.2.5-.6.7 0 .3.1.1.6-.3.7-.8v-.9l1 .7 1.2.8q0 .7-.4.9h-1z"/>
<path d="m303.4 109.3-2-1.5q.6 0 1-.2t.5-.8l1.7 1.5v.7l-.3.2z"/>
<path d="m305.7 110.8-.7-.4-1.4-1h.7l.4-.2.2-.4v-.3l2.2 1.6q0 .4-.3.4l-1 .2h-.1z"/>
<path d="m308.1 111.8-2.2-.9q.6 0 1-.2.5 0 .5-.5l1.3.6v.4q-.1.3-.5.4v.1z"/>
<path d="M313.2 111.2h.2q-2.2 1.4-5.1.6.5-.2.6-.5t0-.4l1.8.4-.1.2-.5.4s-.1 0 0 0v.2l.7-.4.1-.4zM302.9 137l-.3.4-1.3.3q0 .4.4.4l.8-.3s-.1.5-.6.8v.2c.4.6 1.4.4 2 .2.4 0 1.1-.5 1.3-1q.1-.2-.2-.6-.7 0-.6-.3-.7-.2-1.5-.1m-16.2-5.1-1.1.6q-.4 0-.6.3.1.3.4.2 1-.6.2.2v.3c.6.5 1.8.6 2.4.3q.7-.4.2-1v-.2l-.6-.1-.4-.3zm10.7 3.7h-.2c-.2.2.4.1.7.3q.3.2.2.5c-.3.7-2 .5-2.5.2q-.4-.2-.3-.5l1-.2v-.2h-.2l-.5.1h-.5q-.2 0-.1-.1h.2l.8-.2v-.2q.9 0 1.4.3m-7.7-.5-.2.3-1 .7q-.2.1.3.4.3 0 .6-.4t.2 0l-.2.7c0 .2.6.3.8.3q.7-.2 1.2-.6t.1-.8h-.5l-.6-.3v-.1zm3-28.1h.3l.7.1 1.8-.4 1.8-.2v-.2q.4-.4.3-1-.1-.3-.8-.7h-1.4q-.5 0-.9.2.4 0 .7.4.3.3.4 1v.1h-.2l-.4-1q-.5-.4-.8-.4-.8 0-1.4.2-.4 0-.8.3h1q.4.3.6.9v.1h-.2q-.2-.6-.5-.7c-.5-.2-1.4 0-1.7.2l-.7.7h-.1q1.2 0 2.3.4m-2.4-.5.7-.7.7-.3 1-.6 1.5-.2-.6-.6h-.7l-1.7.8h.6v.2h-.9s0 .1 0 0l-1.4 1.1z"/>
</g>
<path fill="#0093dd" d="m351.4 167 22.2-50.1-16.4-26.4-29 10.8-13.6 53a234 234 0 0 1 36.8 12.8z"/>
<path fill="#fff" d="M323.2 120.6a269 269 0 0 1 42.3 14.7l-8.6 19.3a248 248 0 0 0-38.9-13.4z"/>
<path fill="red" d="m358.3 151.5 5.7-12.9a265 265 0 0 0-41.7-14.4l-3.4 13.2a252 252 0 0 1 39.6 13.7z"/>
<path d="M326.4 134.2q.6-.2 1.2 0 .5-.2 1.1-.2l.7-.2v-.3l-.2-.4a3 3 0 0 1-1.1-1.6q-.6 0-.6-.3h-.6q-1-.1-1.3-.5l-.7-.5-.2-.3q-.4-.6.2-.7h.7q.4-.2 1-.2.4 0 .9-.5v-.5q0-.2.2-.1.6 0 .9.5.8.1 1.3.8 1.1.1 1.2.5t-.5.7v.1l.4.5 1.1.7q1.6-.1 5.1 2.1 2.3.4 4.4 1.3h1q3.8-.7 7.2 1.7 1.2.2 2.4.7l1.7.4q1.3 0 2.7.7 1.6.3 2.6 1.3.7.8-.2 1.2-.5 1-2 .4-1 0-2-1a10 10 0 0 1-2.7-1.4l-1.3-.6h-.9v.2q.4.3.5.8v1q0 .7.7 1l1 .5q.4 0 .4.3l.4 1.8.4.4q.8.8-.3 1-.7.8-1.4.9t-.7-.2l-.5-.3c-.5-.4 0-1 1.1-.7q0-.2.3-.2v-1l-.4-.2-1.1-.6q-1-.8-2.5-1.6-1 0-2-.6h-.7q-.4-.1-.6.1-.3.4-.8.2h-1.2l-.5.1q-.8 0-1.1.2t-.7.2l-.4-.3-.6-.2q-.7-.3-.6-.4c-.6-.2-.3-.7.1-.7l1.5.1q.7.1 1.2-.2l.6-.6a4 4 0 0 1-2-.5q-1.8-1.2-3-.3-.3.3-.6.1h-.6l-1.3-.1a4 4 0 0 1-2 0q-.9.5-1.2.1l-.7-.4q-.5 0-.5-.2-.6-.2-.5-.4-.2-.4 0-.6.5-.2 1.1 0l.5.4h.7q.4-.2 1-.2l.8-.2v-.2q-.7-.2-.9-.8a3 3 0 0 1-1.7-.6q-.6 0-1-.2H328l-.9-.1q-.4.5-1 .2l-.9-.5q-.4-.1-.4-.4-.5-.3 0-.6.4-.1 1.1.1z"/>
<path fill="#fff" d="M343.1 139.3s-.1-.2-.3 0q-1.3.1-2.4-.5t-2.2-.7l.9-.5h1.5q1.2.1 2 .5 1 .3 1.1.7h.1l.9.8h-.8z"/>
<path d="M345 101.1v.2l1 5.2-4 3.5-.2.1.3.1 5 1.7 1 5.2v.2l.2-.2 4-3.4 5 1.7h.1v-.1l-1-5.2 4-3.5.2-.1-.3-.1-5-1.7-1-5.2v-.2l-.2.1-4 3.5-5-1.7z"/>
<path fill="#f7db17" d="m342.5 109.9 3.7-3.2 4.7 1.6zm9-1.7 3.7-3.3 4.6 1.6zm8.4-1.5-3.7 3.2-4.7-1.6zm-9 1.7-3.7 3.3-4.7-1.6zm-5.4-6.8 4.6 1.6 1 4.8zm6 6.9 4.6 1.6 1 4.8zm5.4 6.5-4.6-1.6-1-4.8zm-6-6.9-4.6-1.6-1-4.8zm3.2-8.1 1 4.8-3.7 3.2zm-3 8.6 1 4.9-3.7 3.2zm-2.9 8-1-4.8 3.8-3.2zm3-8.6-1-4.9 3.8-3.2z"/>
</svg>

After

Width:  |  Height:  |  Size: 31 KiB

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-hu" viewBox="0 0 512 512">
<g fill-rule="evenodd">
<path fill="#fff" d="M512 512H0V0h512z"/>
<path fill="#388d00" d="M512 512H0V341.3h512z"/>
<path fill="#d43516" d="M512 170.8H0V.1h512z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 273 B

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-ie" viewBox="0 0 512 512">
<g fill-rule="evenodd" stroke-width="1pt">
<path fill="#fff" d="M0 0h512v512H0z"/>
<path fill="#009A49" d="M0 0h170.7v512H0z"/>
<path fill="#FF7900" d="M341.3 0H512v512H341.3z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 289 B

+12
View File
@@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-is" viewBox="0 0 512 512">
<defs>
<clipPath id="is-a">
<path fill-opacity=".7" d="M85.4 0h486v486h-486z"/>
</clipPath>
</defs>
<g fill-rule="evenodd" stroke-width="0" clip-path="url(#is-a)" transform="translate(-90)scale(1.0535)">
<path fill="#003897" d="M0 0h675v486H0z"/>
<path fill="#fff" d="M0 189h189V0h108v189h378v108H297v189H189V297H0z"/>
<path fill="#d72828" d="M0 216h216V0h54v216h405v54H270v216h-54V270H0z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 520 B

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-it" viewBox="0 0 512 512">
<g fill-rule="evenodd" stroke-width="1pt">
<path fill="#fff" d="M0 0h512v512H0z"/>
<path fill="#009246" d="M0 0h170.7v512H0z"/>
<path fill="#ce2b37" d="M341.3 0H512v512H341.3z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 289 B

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-lt" viewBox="0 0 512 512">
<g fill-rule="evenodd" stroke-width="1pt" transform="scale(.51314 1.0322)">
<rect width="1063" height="708.7" fill="#006a44" rx="0" ry="0" transform="scale(.93865 .69686)"/>
<rect width="1063" height="236.2" y="475.6" fill="#c1272d" rx="0" ry="0" transform="scale(.93865 .69686)"/>
<path fill="#fdb913" d="M0 0h997.8v164.6H0z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 439 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-lu" viewBox="0 0 512 512">
<path fill="#ed2939" d="M0 0h512v170.7H0z"/>
<path fill="#fff" d="M0 170.7h512v170.6H0z"/>
<path fill="#00a1de" d="M0 341.3h512V512H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 233 B

+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-lv" viewBox="0 0 512 512">
<g fill-rule="evenodd">
<path fill="#fff" d="M0 0h512v512H0z"/>
<path fill="#981e32" d="M0 0h512v204.8H0zm0 307.2h512V512H0z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 234 B

+71
View File
@@ -0,0 +1,71 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-md" viewBox="0 0 512 512">
<g fill-rule="evenodd" stroke-width="1pt">
<path fill="#00319c" d="M0 0h170.7v512H0z"/>
<path fill="#ffde00" d="M170.7 0h170.6v512H170.7z"/>
<path fill="#de2110" d="M341.3 0H512v512H341.3z"/>
</g>
<path fill="#ff1900" fill-rule="evenodd" stroke="#000" stroke-width="1pt" d="M173.6 691v63.7c0 3.6 0 7.1-3.5 7.1-3.6 0-7.1 7-7.1 10.6 0 7.1 3.5 10.7 7 10.7h32c3.5 0 7-3.6 7-10.7-.2-3.7-3.5-10.6-7-10.6-3.6 0-3.6-3.5-3.6-7v-63.9" transform="matrix(.46695 -.29552 .30926 .4462 -5.1 64.5)"/>
<path fill="#a77b3b" fill-rule="evenodd" stroke="#000" stroke-width="3.1" d="M177.2 696.3c0 24.4-9.6 44.3-21.3 44.3s-21.3-19.9-21.3-44.3S144.3 652 156 652s21.3 19.8 21.3 44.3z" transform="matrix(.42858 -.34452 .36055 .40954 -29.7 77.3)"/>
<path fill="#ff1900" fill-rule="evenodd" stroke="#000" stroke-width="1pt" d="M173.6 691v63.7c0 3.6 0 7.1-3.5 7.1-3.6 0-7.1 7-7.1 10.6 0 7.1 3.5 10.7 7 10.7h32c3.5 0 7-3.6 7-10.7-.2-3.7-3.5-10.6-7-10.6-3.6 0-3.6-3.5-3.6-7v-63.9" transform="matrix(.48902 .26089 -.27302 .46728 313.4 -58.3)"/>
<path fill="#a77b3b" fill-rule="evenodd" stroke="#000" stroke-width="3.1" d="M421.6 701.6h-28.3c-1 1-9 54-17.7 74.4-10.6 24.8-42.5 46.7-42.5 46.7s19 6 24.8 10c1.4-.4 31.8-7.1 35.4-46 3.5 38.9-21.3 56.6-21.3 56.6s35.5 10.6 35.5 35.5c0-24.8 35.4-35.5 35.4-35.5s-17.8-17.7-21.3-56.7c7 39 34 45.7 35.5 46 5.7-3.9 24.7-10 24.7-10S450 800.9 439.4 776c-8.7-20.3-16.8-73.5-17.7-74.4z" transform="matrix(.56007 0 0 .53518 29.7 -86.3)"/>
<path fill="#a77b3b" fill-rule="evenodd" stroke="#000" stroke-width="3.1" d="m336.6 467.7 53.2 17.7a38 38 0 0 0 35.4-35.4c.6-39.4-14.2-53.2-17.7-53.2l7-7L404 379s3.6-18.4 39-17.7 35.4 17.7 35.4 35.4c0 17.8-17.7 17.8-17.7 53.2a38 38 0 0 0 35.5 35.4l53.1-17.7V645H336.6z" transform="matrix(.56007 0 0 .53518 9.8 -56)"/>
<g fill="none" stroke="#000">
<path stroke-width=".6" d="m302.2 292.2 14.6 15 14.7-15 14.6 15 29.3-15 14.3 15.8 15-15.8 21.6 15.8 22.3-15.8 14.6 15 14.7-15" transform="matrix(.1355 0 0 .38018 203 87)"/>
<path stroke-width=".3" d="m432.3 435.8-7.1 39m10.6-39v39m7.1-39v39m7.1-39 3.5 39m3.6-39 3.5 39" transform="matrix(.56007 0 0 .53518 9.8 -56)"/>
</g>
<g stroke="#000" stroke-width="3.1">
<path fill="#a77b3b" fill-rule="evenodd" d="M318.9 361.4c35.4 17.7 35.4 53.2 35.4 70.9-1.2 16.1 0 354.3 0 354.3s-2.3-20-17.7-35.4L319 733.5l-17.7-17.7c-13-11.8-17.7-35.5-17.7-53.2v-248s0-17.8 35.4-53.2z" transform="matrix(-.56007 0 0 .53518 357.1 -56)"/>
<path fill="none" d="M283.5 574c.4 0 17.7-17.7 17.7-17.7l17.7 17.7 17.7-17.7 17.7 17.7" transform="matrix(-.56007 0 0 .53518 357.1 -131.8)"/>
<path fill="none" d="M283.5 574c.4 0 17.7-17.7 17.7-17.7l17.7 17.7 17.7-17.7 17.7 17.7" transform="matrix(-.56007 0 0 -.53518 357.1 492)"/>
<path fill="none" d="M283.5 574c.4 0 17.7-17.7 17.7-17.7l17.7 17.7 17.7-17.7 17.7 17.7" transform="matrix(-.56007 0 0 .53518 357.1 -94)"/>
<path fill="none" d="m301.4 557-.2 158.8" transform="matrix(-.56007 0 0 1.01529 357.1 -399.6)"/>
<path fill="none" d="m301.4 539.3-.2 176.5" transform="matrix(-.56007 0 0 .91125 347.3 -316)"/>
<path fill="none" d="m301.4 539.3-.2 176.5" transform="matrix(-.56007 0 0 1.0208 337.4 -384.6)"/>
</g>
<g stroke="#000" stroke-width="3.1">
<path fill="#a77b3b" fill-rule="evenodd" d="M318.9 361.4c35.4 17.7 35.4 53.2 35.4 70.9-1.2 16.1 0 354.3 0 354.3s-2.3-20-17.7-35.4L319 733.5l-17.7-17.7c-13-11.8-17.7-35.5-17.7-53.2v-248s0-17.8 35.4-53.2z" transform="matrix(.56007 0 0 .53518 158.7 -56)"/>
<path fill="none" d="M283.5 574c.4 0 17.7-17.7 17.7-17.7l17.7 17.7 17.7-17.7 17.7 17.7" transform="matrix(.56007 0 0 .53518 158.7 -131.8)"/>
<path fill="none" d="M283.5 574c.4 0 17.7-17.7 17.7-17.7l17.7 17.7 17.7-17.7 17.7 17.7" transform="matrix(.56007 0 0 -.53518 158.7 492)"/>
<path fill="none" d="M283.5 574c.4 0 17.7-17.7 17.7-17.7l17.7 17.7 17.7-17.7 17.7 17.7" transform="matrix(.56007 0 0 .53518 158.7 -94)"/>
<path fill="none" d="m301.4 557-.2 158.8" transform="matrix(.56007 0 0 1.01529 158.7 -399.6)"/>
<path fill="none" d="m301.4 539.3-.2 176.5" transform="matrix(.56007 0 0 .91125 168.5 -316)"/>
<path fill="none" d="m301.4 539.3-.2 176.5" transform="matrix(.56007 0 0 1.0208 178.4 -384.6)"/>
</g>
<path fill="#a77b3b" fill-rule="evenodd" stroke="#000" stroke-width="3.1" d="M177.2 696.3c0 24.4-9.6 44.3-21.3 44.3s-21.3-19.9-21.3-44.3S144.3 652 156 652s21.3 19.8 21.3 44.3z" transform="matrix(.51699 .20584 -.21541 .49401 290.2 -73.2)"/>
<path fill="red" fill-rule="evenodd" d="M198.4 203.8h119v56.9h-119z"/>
<path fill="#564dff" fill-rule="evenodd" d="M198.4 260.7h119V289c0 19-29.7 19-59.5 38-29.8-19-59.5-19-59.5-38z"/>
<path fill="none" stroke="#ff0" stroke-width="2.5" d="M336.6 485.4h212.6V645c0 35.4-53.1 35.4-106.3 70.9-53.1-35.5-106.3-35.5-106.3-71V485.5z" transform="matrix(.56007 0 0 .53518 9.8 -56)"/>
<path fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width="3" d="M385.6 129.9S335 185.4 335 238.5s53.1 70.9 53.1 70.9-17.7 0-17.7 70.8c0 35.5 53.1 17.8 53.1 35.5s-.7 60.5 0 88.6c0 17.7-35.4 0-35.4 17.7 0 8.8 26.6 53.1 53.2 53.1s53.1-44.3 53.1-53.1c0-17.7-35.4 0-35.4-17.7v-88.6c0-17.7 53.1 0 53.1-35.5 0-70.8-17.7-70.8-17.7-70.8s53.2-17.7 53.2-70.9-50.7-108.6-50.7-108.6 28.5 73.2 28.5 108.6c0 17.7-13.3 53.2-48.7 53.2 0 0-9-17.8-17.7 0 0 0-10.2-17.8-17.7 0-2.6 6-7.2-17.8-17.8 0-4.4 4.7-8-17.8-17.7 0-17.7 0-53.1-17.8-53.1-53.2s32.9-108.6 32.9-108.6z" transform="matrix(.39205 0 0 .2513 84.9 175)"/>
<path fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width="3" d="M382.7 248c-3.6 3.6 4.6 61.3 7 63.8 3.6 3.5 24.9 3.5 28.4 0 2.5-2.5 0-56.7-3.5-60.2-3.6-3.6-29.4-6-32-3.6z" transform="matrix(.39205 0 0 .2513 86.4 225)"/>
<path fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width="3" d="M382.7 248c-3.6 3.6 4.6 61.3 7 63.8 3.6 3.5 24.9 3.5 28.4 0 2.5-2.5 0-56.7-3.5-60.2-3.6-3.6-29.4-6-32-3.6z" transform="matrix(-.39205 0 0 .2513 429.4 225)"/>
<path fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width="3" d="M414.6 228.5a16 16 0 1 1-32 0 16 16 0 0 1 32 0z" transform="matrix(.45063 0 0 .31327 63.9 210.4)"/>
<path fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width="3" d="M414.6 228.5a16 16 0 1 1-32 0 16 16 0 0 1 32 0z" transform="matrix(.45063 0 0 .31328 92.6 210.4)"/>
<path fill-rule="evenodd" d="M270.4 311c0 1.2-1.6 2.2-3.5 2.2s-3.4-1-3.4-2.2 1.5-2.2 3.4-2.2 3.5 1 3.5 2.2m-18 0c0 1.2-1.6 2.2-3.5 2.2s-3.5-1-3.5-2.2 1.6-2.2 3.5-2.2 3.4 1 3.4 2.2z"/>
<path fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width="1pt" d="m439.4 550-7.8-10.3-12.8 1.7 1.8-12.8-10.3-7.7 10.3-7.8-1.8-12.8 12.8 1.8 7.8-10.3 7.8 10.3 12.7-1.8-1.7 12.8 10.2 7.8-10.2 7.8 1.7 12.7-12.8-1.7z" transform="matrix(.54641 0 0 .52213 17.8 -47.3)"/>
<path fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width="1pt" d="m496 591.7 21.3 10.7 21.3-10.7-21.3-10.6z" transform="matrix(.56007 0 0 .53518 9.8 -56)"/>
<path fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width="1pt" d="m496 591.7 21.3 10.7 21.3-10.7-21.3-10.6z" transform="matrix(.56007 0 0 .53518 -75.5 -56)"/>
<path fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width="1pt" d="M535 659c-3.5-7-14.1-10.6-21.2-10.6s-14.2 0-21.3 10.7c0-14.2 10.5-21.3 21.3-21.3a23 23 0 0 1 21.2 21.3z" transform="matrix(.48568 -.26652 .27892 .4641 -137.5 131.4)"/>
<path fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width="1pt" d="M386.2 652a7 7 0 1 1-14.1 0 7 7 0 0 1 14.1 0z" transform="matrix(.56007 0 0 .53518 7.9 -65.5)"/>
<path fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width="1pt" d="M386.2 652a7 7 0 1 1-14.1 0 7 7 0 0 1 14.1 0z" transform="matrix(.56007 0 0 .53518 3.9 -52.2)"/>
<path fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width="1pt" d="M386.2 652a7 7 0 1 1-14.1 0 7 7 0 0 1 14.1 0z" transform="matrix(.56007 0 0 .53518 1.9 -59.8)"/>
<path fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width="1pt" d="M386.2 652a7 7 0 1 1-14.1 0 7 7 0 0 1 14.1 0z" transform="matrix(.56007 0 0 .53518 11.8 -52.2)"/>
<path fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width="1pt" d="M386.2 652a7 7 0 1 1-14.1 0 7 7 0 0 1 14.1 0z" transform="matrix(.56007 0 0 .53518 13.8 -59.8)"/>
<path fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width="1pt" d="M386.2 652a7 7 0 1 1-14.1 0 7 7 0 0 1 14.1 0z" transform="matrix(.56007 0 0 .53518 7.9 -57.9)"/>
<g fill-rule="evenodd">
<path fill="#da4500" d="M238.7 159c-10 0-11.3 1.5-15.8 3 0-4.3 11.1-9.4 21.1-9.4 0 3.2-2.6 6.3-5.3 6.3z"/>
<path fill="#cac9c7" d="M254 148.8c0 2.1-1.8 3.8-4 3.8s-4-1.7-4-3.8 1.8-3.8 4-3.8 4 1.7 4 3.8"/>
<path fill="#ff0" stroke="#000" stroke-width="1pt" d="M361.4 357.9v10.6h17.7v53.1h10.7v-53.1h17.7v-10.6h-17.7v-14.2H379v14.2z" transform="matrix(.56007 0 0 .53518 9.8 -56)"/>
<path fill="#da4500" d="M244 152.6a64 64 0 0 0-23.8 3.2c0-5.9 6.8-12.7 18.5-12.7 2.7 0 5.3 6.3 5.3 9.5"/>
</g>
<g fill-rule="evenodd">
<path fill="#008500" stroke="#000" stroke-width=".9" d="M67.3 613c-14.2-14.2-16.6-21.4 3.6-10.1l283.7 247.5-3.4 7L67.4 613z" transform="matrix(.31554 .24102 -.11439 .19257 189.7 119)"/>
<path fill="#008f00" d="M182.3 329.6c.7-8.6-15-17.9-15.7-17.3s1 5.6 4 8.2c-5.8-2.9-11.8-4.7-12-3.4-.4 1.7 9 5.8 9.8 7.4 0 1.1-7 1-6.8 2.1.1 1.2 19.7 11 20.7 3m-15.7-25c.6-8.6-15.1-18-15.8-17.3-.6.6 1 5.6 4 8.2-5.7-3-11.7-4.8-11.9-3.5-.4 1.7 9 5.8 9.7 7.4.1 1.2-6.9 1-6.7 2.2.1 1.1 19.7 11 20.7 3m-12-22.8c.6-8.6-15.2-17.9-15.8-17.3s1 5.6 4 8.2c-5.8-3-11.8-4.7-11.9-3.4-.5 1.7 9 5.8 9.7 7.4.1 1.1-6.9 1-6.8 2.1s19.7 11 20.7 3zm-12-24.6c.7-8.6-15-18-15.7-17.3s1 5.6 4 8.2c-5.8-3-11.8-4.8-11.9-3.5-.5 1.7 8.9 5.8 9.7 7.4.1 1.2-6.9 1-6.8 2.2.1 1 19.7 11 20.7 3"/>
<path fill="#008f00" d="M146.7 256c7.7-4.6 6.2-22.2 5.3-22.3s-4.2 4-4.6 7.9c-1-6.2-3-11.9-4-11.2-1.8.7.3 10.3-.6 11.9-.9.7-5-4.7-5.8-4-.9.8 2.4 21.7 9.7 17.7m11 21.7c8.9-2 13.6-19 12.9-19.4-.8-.4-5.4 2.5-7.1 6 1.3-6.1 1.3-12.1 0-11.9-1.8.1-3.3 9.8-4.6 11-1.1.5-3-6-4.1-5.5s-5.3 21.2 3 19.8zm13.3 22.1c8-4 8.2-21.6 7.3-21.8s-4.5 3.7-5.3 7.5c-.4-6.2-1.8-12-3-11.5-1.8.5-.7 10.3-1.7 11.8-1 .6-4.4-5.2-5.4-4.5s.4 21.9 8 18.5zm14.2 29c8.4-3.2 10.5-20.8 9.6-21-.8-.4-4.9 3.1-6 6.8.3-6.2-.6-12.1-1.8-11.7-1.9.4-1.7 10.2-2.9 11.6-1 .6-3.9-5.5-4.9-5-1 .7-2 21.8 6 19.2z"/>
</g>
<path fill="#ff1900" fill-rule="evenodd" stroke="#000" stroke-width="1pt" d="M209 776c0 7.8-10.2 14.2-23 14.2s-23-6.4-23-14.2 10.3-14.2 23-14.2 23 6.4 23 14.2z" transform="matrix(.48902 .26089 -.27302 .46728 313.4 -58.3)"/>
<g fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-width=".6">
<path d="M156 414.6v-7.1h7v-7.1h7v7h7.2v7.2H170v17.7h-7v-17.7zm7 60.2h7v205.5h-7z" transform="matrix(.40549 .1277 -.14842 .38308 363.6 58)"/>
<path d="M159.4 676.8h14.2v56.7h-14.2zM156 439.4h21.3c14.1 0-3.6 39-3.6 39h-14.1s-17.8-39-3.6-39zm17.6-5.4c0 3-3.1 5.4-7 5.4s-7.1-2.4-7.1-5.3 3.1-5.4 7-5.4 7.1 2.4 7.1 5.4z" transform="matrix(.40549 .1277 -.14842 .38308 363.6 58)"/>
</g>
<path fill="#ff1900" fill-rule="evenodd" stroke="#000" stroke-width="1pt" d="M209 776c0 7.8-10.2 14.2-23 14.2s-23-6.4-23-14.2 10.3-14.2 23-14.2 23 6.4 23 14.2z" transform="matrix(.46695 -.29552 .30926 .4462 -5.1 64.5)"/>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

+118
View File
@@ -0,0 +1,118 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-me" viewBox="0 0 512 512">
<path fill="#d3ae3b" d="M0 0h512v512H0z"/>
<path fill="#c40308" d="M25.6 25.6h460.8v460.8H25.6z"/>
<path fill="#b96b29" d="M367.4 251.8c3-.8 13.5-3.9 20.8-9.8s8.8-10.7 9.4-13.3.8-4.6-1-3.2c-2 1.5-7.7 6-11.6 8.2a43 43 0 0 1-9.6 3.7c-2 .6-3.8 1-1.7.2s8.6-3.1 13.7-8.2c5.1-5.2 9.2-12.8 9.3-17.6 0-4.7-.3-4.3-1.8-3.1s-6.9 7.8-10 10.3a96 96 0 0 1-10.3 7.3c-2.4 1.4-5.8 3-1-.2s13.8-11 17.5-21 3-16 3-17c-.1-1-1-3-1.8-1.1s-6.9 14-11.8 19.2c-4.8 5.2-3.7 4.2-4.8 5s-3 2.3-.5-.6c2.3-3 7.2-9.7 9.7-16.5a55 55 0 0 0 3.3-17.3c0-3.9-1.6-9.2-2.4-10.8s-1.5-2.8-1.7-1-4.2 13.8-6.3 19.6a75 75 0 0 1-7.1 13.7c-.8 1.2-3 3.8-.7-.6a83 83 0 0 0 7.5-29.4 47 47 0 0 0-2.8-22.3c-1.6-3.3-3.1-4.5-3.1-4.5s.3 8.3-2.2 20.3-6.1 18.2-6.1 18.2-1.5 1.8-.5-1.1c.7-2 2.2-6.2 2.8-13.4.7-7.5.8-16.1-1.4-23.4-2.4-8-6.5-12-6.5-12-1.2 11.4-1 26-5.2 38-.7-.7-1.8-2-2.2.7a67 67 0 0 1-7.4 20.6c-5.2 9.4-7.3 10.6-7.3 10.6l-1.6-3.5c-.7-1.3-1-2-2-.2-.8 1.7-3.7 8.3-10 15.6s-9.8 10.8-9.6 16.2c.2 5.5 3 8.3 6.9 10.7 3.8 2.5 4.5 3.9 3.9 6.8-.6 3-4 4-7 4.1s-6.7-.1-8 .6c-1.3.8-1.4 2.7-2.8 4-1.3 1.4-1.9 2.1-3.1 2.3l-1 .2c-.4-14.4 5.2-20.8 5.2-20.8L291 217.7l-2.4 1.1-.4-.7a12 12 0 0 1-2.8-8.3c.8.1 2.3.7 3.8.4 1.4-.3.3-1.7-.1-3a28 28 0 0 1-.2-10.3s2.3 2.4 3.7 2.4 1.3-1.4 1.5-3a12 12 0 0 1 3.2-6.9s2.5 1.7 5.3 1.7c2.9 0 6.7-.7 9.7-3.6s3-3.6 3-3.6 5.6 2 10 2.2c4.2.2 8.8-.5 11-5s-.6-8.8-1.1-9.5-2-1.3-2 0 .1 4.7-2.5 6.4-4.6 1.6-7.1.8a22 22 0 0 0-14-.3c.2-.2 3.4-3.5 6.6-4.5s5.1.4 6.2 1.6c1 1.3 2 3.4 2.8.4.9-3 .4-6.4-1-8.6a8 8 0 0 0-7.7-3.2q-4.5.6-4.3.8c.2.2-1.6-4.6-5.7-5.4-5-1-10.5.8-14.8 3.2 0 0-3.4.8-6.8-.2a22 22 0 0 1-5.9-2.9l1.2-3.7 2-.7c1-.4.8-.8 1-1.6s-2-2.4-2-2.4-.3-2.6 3.1-4.3l3-1.5s2 .3 2.9-.2q1-1 .8-1c-.2 0 1.5-.5 2-1.4q.9-1.6.3-3.3c-.4-1-1-1.3-.4-1.8a5 5 0 0 0 1.2-2.5v-1s1.2-.5 1.1-2.3-1-2.4-1.6-2.6l-.9-.1s0-1.1-1-2.5l-1.5-2c-.1 0 .7-.5.3-1.7a3 3 0 0 0-2-2.1c-.7-.3-1.6 0-1.6 0l-4-2.3-1.5-.8s0-1.1-.5-1.7-1.5-.9-2-.9l-1.2.3c-.2.1-4.5-1.1-6.4-1.4s-2-.5-2-.5-4-1.9-5.5-2.2l-2-.5s1.6-2 1.7-4.2a6 6 0 0 0-3-5.4l-1.7-.8V99l3 .3.2-4.8-3 .4.5-3h-6.2l.5 2.9-3-.2.3 4.8 3-.4-.2 1.8s-1.1.2-2.1.9a6 6 0 0 0-2.9 5.1 9 9 0 0 0 1.5 4.3l-2 .4c-1.5.3-5.6 2.2-5.6 2.2s0 .2-2 .5l-6.3 1.4s-.6-.3-1.2-.3-1.6.3-2 .9c-.5.6-.5 1.7-.5 1.7l-1.6.8-4 2.3s-.8-.3-1.6 0a3 3 0 0 0-2 2.1c-.3 1.2.3 1.7.3 1.7s-.6.6-1.5 2-1 2.5-1 2.5l-.9.1c-.5.2-1.5.9-1.5 2.6-.1 1.8 1 2.2 1 2.2l.1 1q.2 1.7 1.1 2.6c.6.5 0 .7-.3 1.8a4 4 0 0 0 .2 3.3c.6.9 2 1.4 2 1.4s0 .4.9 1 2.8.2 2.8.2-.4-.3 3 1.4c3.4 1.8 3.1 4.4 3.1 4.4s-2 1.5-2 2.4c.2.8 0 1.2 1 1.6l2 .7 1.2 3.7c-1.3.9-3.5 2.3-5.8 3-3.4 1-6.8.1-6.8.1a23 23 0 0 0-14.8-3.2c-4.1.8-5.8 5.4-5.8 5.4s-1.1-.5-4.3-.8a8 8 0 0 0-7.6 3.2 11 11 0 0 0-1 8.6c.8 3 1.7 1 2.8-.4 1-1.2 3-2.6 6.2-1.6a19 19 0 0 1 6.5 4.5s-.5-.4-4-.9c-4-.5-7.4.4-10 1.2-2.4.8-4.4.9-7-.8-2.7-1.7-2.6-5.1-2.6-6.4s-1.4-.7-1.9 0-3.3 4.9-1.1 9.4 6.8 5.3 11 5c4.4-.2 10-2.2 10-2.2s0 .8 3 3.7 6.8 3.6 9.6 3.6 5.3-1.7 5.3-1.7a12 12 0 0 1 3.3 7c.2 1.5 0 3 1.5 3s3.6-2.5 3.6-2.5l.4 2.4c.2 1.7-.1 6.5-.5 7.8-.4 1.4-1.5 2.8 0 3 1.3.4 2.9-.2 3.7-.3a12 12 0 0 1-2.8 8.3l-.4.7-2.3-1.1-15.7 18.3s5.6 6.4 5.3 20.9v-.1l-1.2-.2c-1.2-.2-1.8-1-3.1-2.3s-1.4-3.2-2.8-4-5-.5-8-.6-6.4-1.1-7-4c-.5-3 .1-4.4 4-6.9 3.8-2.4 6.6-5.2 6.8-10.7s-3.3-9-9.6-16.2c-6.3-7.3-9.2-13.9-10-15.6-1-1.7-1.3-1-2 .2l-1.6 3.5s-2-1.2-7.2-10.6a67 67 0 0 1-7.5-20.7c-.4-2.6-1.4-1.3-2.2-.6-4.2-12-4-26.7-5.1-38 0 0-4.2 4-6.6 12a64 64 0 0 0-1.4 23.4c.6 7.2 2.1 11.5 2.8 13.4 1 2.9-.5 1.1-.5 1.1s-3.6-6.3-6-18.2c-2.6-12-2.3-20.3-2.3-20.3s-1.4 1.2-3.1 4.5a47 47 0 0 0-2.8 22.3c.6 12.2 5.1 25 7.5 29.4s.2 1.8-.7.5c-.8-1.2-5-7.8-7.1-13.6A242 242 0 0 1 128 165c-.3-1.8-1-.6-1.8 1s-2.4 7-2.4 10.8a55 55 0 0 0 3.3 17.3 68 68 0 0 0 9.8 16.5c2.3 3 .5 1.4-.6.6s0 .1-4.8-5a98 98 0 0 1-11.8-19.2c-.8-1.9-1.7.1-1.7 1.2-.1 1-.8 6.9 2.9 16.9a49 49 0 0 0 17.6 21c4.8 3.2 1.3 1.6-1.1.2A96 96 0 0 1 127 219c-3-2.5-8.4-9.2-9.9-10.3s-1.8-1.6-1.7 3.2c0 4.7 4 12.3 9.2 17.4 5 5.2 11.7 7.5 13.7 8.3s.4.4-1.7-.2a43 43 0 0 1-9.6-3.7c-3.9-2.2-9.6-6.7-11.5-8.2s-1.6.6-1 3.2c.5 2.5 2 7.3 9.3 13.3s17.8 9 20.8 9.8.9.9.9.9l-7.3-1.5c-6-1.4-15.3-6.2-17.8-7.8s-2.8-2.1-2.5 1.2 3.9 10.3 9.5 13.6a53 53 0 0 0 18.3 5.1c2.6.2 2 .5.8.6a55 55 0 0 1-20.6-3.5l-.5-2.1c-.2-1.3-.9-1-1.3-.8-.4.3-.6.5-2 1.2s-1.5-.1-1.5-.6l-.4-3.1q0-1.3-1.2-.7l-5 2c-1 .6 0 1.5.6 2.6l1.5 2.8-3.8 1c-1 .2-.7.9-.4 1.5l2 4.9c.4 1 1.2.4 1.2.4l3-1.8 1 4c-.1 0-1.4.3-2.9 1.3s-1 2.4.7 2.9c1.8.5 3.8 1.4 6.1 5.6s2.9 11.6 4.3 23.4 9 17.8 10 18.5c1 .8.4 1.4.4 1.4s-1 1.5-.6 3.7a6 6 0 0 0 3.5 4c1 .4.8 1.5.8 1.5s-.6 2.5 0 7c.5 4.7 4.2 9.9 5.3 10.8 1 .8 1 1.3 1 1.7-.2.3-.9 0-2.1 1q-2.1 1.5-3.6 4c-.9 1.6-.6 2.5-.3 4.7s3.6 4.3 3.6 4.3-.6.1-.8 1.8q0 2.6 2.6 4.6c1.4 1.2 4.2 1.8 4.2 1.8l.4 2.4c.2 1 2 2 3.2 2.6s3.5.3 4.4-.2q1.5-.5 2.2 1c.6 1 .4 4.7.4 6.2s-.9 3-.4 3.8 2 .2 3.4-.6 1.7-.2 3 .6 3.3 1.6 3.8 1.5c.5 0 .3-1.4.3-2.5s.2-3.7.7-4c.2-.2 2.4-.4 4-1q1.5-.4 2-1.5c0-.7-1.1-.7-3.6-2-2.4-1.3-2.8-2-4.4-3-1.5-1-.8-1.4-.8-1.9s.7-1 1-1.5.2-2 .2-2l1.8-1.9 2.2-2.4c.8-.6 2-3.8 2.9-4.9.8-1 2.6-2.1 3.7-3.5s4-3.7 5.8-4.8c1.7-1.2 6.3-3.3 6.3-3.3s-.1 2.7 1 4c1.3 1.4 2.8-1 8-4.7s9.3-5 9.3-5l2.5 3.5c1.4 1.7 2.7-.1 9.1-9 5-7 11.8-13.4 14.4-15.8l1.4.6-.4 1.2c-.6 1.8-1.5 3-2.8 5.6s-3.2 3.1-5.4 6.6Line truncated
<path fill="#d4af3a" d="M300 253.6c0-10.9 5-17.7 5-17.7l-13.7-15.6c-12.9 5-24.8 5.3-35.3 0-10.6 5.3-22.4 5-35.4 0L207 236s5 6.8 5 17.7-2 19-3.3 24.2-2.2 15 .6 22c2.7 7 5.7 13.2 17.8 18.2 12 5.1 18.4 7.7 22.6 11.2 4.2 3.6 6.3 6.4 6.3 6.4s2.1-2.9 6.3-6.4c4.2-3.4 10.5-6 22.6-11.2 12-5 15-11.2 17.9-18.2s1.7-16.8.5-22-3.3-13.3-3.3-24.2z"/>
<path fill="#b96b29" d="M295.7 258a30 30 0 0 1 4.3-19.4L288.3 225c-9 5-21.4 4.3-32.3-.7-10.8 5-23.3 5.7-32.2.7L212 238.6s6 9.1 4.3 19.5-5.4 26.8-4.5 33.4c1 6.7 5.7 14.5 10.5 18.5a61 61 0 0 0 17.2 9.4 49 49 0 0 1 12.5 7.2c2.4 1.8 4 3.4 4 3.4s1.5-1.6 3.9-3.4c2.3-1.8 7.3-5.4 12.4-7.2a62 62 0 0 0 17.3-9.3 33 33 0 0 0 10.4-18.6c1-6.7-2.7-23-4.4-33.4z"/>
<path fill="#1d5e91" d="M294.6 259.3a35 35 0 0 1 3.3-20.2l-10.5-11.7c-8.8 4.6-19.6 3.4-31.4-.7-11.7 4-22.5 5.3-31.4.7l-10.5 11.7s5 9 3.4 20.2-4.3 23.9-3.8 31.3l.2 1.6h9.5s.6-.7 1.6-1.1l1.4-.8c-.1 0 .2-2 1.4-2.3q1.5-.5 2.1-.4c.6.1.8-.1 1.4-.7s2-2 2.7-3.9 1-2.7 1-4 .5-3.2.5-3.2-.2-.6-1.2-.3c-1 .4-1.1-.6-1.2-1.6s0-2.9.5-3.8l.8-1.2-.4-1.6s-6.1 1.3-7.2-3.5l-1.4-7.5q0-.7-1.1-.7c-1.1 0-2.5-.5-3.8-3-1.2-2.4-1.3-3.4-1-4.4s1-.6 1.3-.3c.2.3 1.8 2.7 2.5 2 .6-.6.3-.6-.6-2.5-1-1.8-.6-2.4-.5-3.3 0-1-.3-2.2-.3-2.7s.5-.9 1-.6l1.4 1c.2.2.3.7.9.4.5-.3.2-2 .2-2.5q.1-1 1.4-.6a2 2 0 0 1 1.2 2q-.1 1 .4 1.1c.3 0 .7-.9.7-1.5s.4-1.5 1-.7.7 1.8.5 3 .2.6-.2 2.6-.6 3-.5 4.5 0 2.4.8 4.2c.8 2 1.4 4.1 2.8 4.2h1.8s1.6-3 2.8-3.8 3-.8 4.2-1q1.7-.1 1.7-.7.2-.4-1.9-.6c-1.4-.2-2.7-.6-2.7-1.7s.2-2.1-.7-2.2c-1 0-3.4-.8-4.2-2.4s-.7-1.9-.6-2.7 1.2-2.6 2-1 1.1 1.8 1.7 2.2c.6.3 1.4.4 1-.7a5 5 0 0 1-.5-2.6q.1-1.2 1.3-1.3l3.6-1 1.1-.3s.1-.7 1.4-1.1a10 10 0 0 1 3.2-.5c1 0 1.6.2 2.9-.4a6 6 0 0 1 3-.7 4 4 0 0 1 2.1.8c.6.4.4 1 .4 1.5s.1.8 1 .8q1.2-.1 2.4.4c1.2.5 2 .7 1.2 1.6-.7.8-.7 1.8-1.2 1.8q-.4.1-.6.7-.4.5.2.9c.5.3.5.6 1.2 1.3s1.8 1.3.7 2.4c-1 1-3 2-3 2s-1 .4.2 1.2c1.3.6 1.8 2.1 2.3 2.4l1.2.8c.3.1.2 1.2.2 1.2l-1.5.8q-1.5.6-2.8.7-1.3-.2-1 .8l1.2 2.2.4 1.3s1.4.3 2.6.3 1.9 0 4.6-.3 3.6-.4 6.3 0c2.7.2 3.1.1 3.8.4l1.4.6s3.8 0 6-.5c2-.5 2.5-1.8 2.2-2.5s-.3-1.8-3.9-2.3-5.1-.3-8-.9c-2.9-.5-7.4-2-8.2-5.6s2.1-5.2 3.6-5.9 4.6-1.8 6.1-2.4a14 14 0 0 1 7-.8c2.8.4 4.5 1.2 5.6.5s2-.2 1.8.9c-.2 1-1.3 3-4.5 4s-7 1.1-9.1.5c-2.1-.5-3.7-1.3-5-.9s-2.6 2-1.3 4c1.4 1.8 8.4 2.4 10.3 2.6s8.8-.3 10.8 3.1c2 3.5.4 7.3-2 8.2a30 30 0 0 1-6 1.7l-1.8.2s.8 1.9.8 2.6-.1 2.2.8 2.8 2 1 3.5.8 3.3.8 3.4 2.2c0 1.3.5 3.1.6 5.8.2 2.6 0 4.8 0 4.8s0 1-.4 2l-2.2 4.7h10.2l.1-1.6c.5-7.5-2.1-20.2-3.8-31.4z"/>
<path fill="#6d8c3e" d="M215 297.1c2 5.8 6.2 11.5 12.5 15.3 8.7 5.3 12.4 4.6 20.7 10 8.2 5.3 7.7 6.2 7.8 6.2s-.4-1 7.8-6.3c8.3-5.3 12-4.6 20.7-9.9a29 29 0 0 0 12.4-15.3z"/>
<path fill="#d4af3a" d="M222.2 253c1 1 1.6 1.3 3 1.1 1.5-.1 1.8 1 2 2 .3 1.2.3 3.9 1.4 6.3 1 2.5 4.4 2.6 4.4 2.6q.3-2 1-4c.2-.3.6-1.4-.6-1.4s-1.2-.5-2-1.7a23 23 0 0 1-2.4-6.3c-.4-2 .3-5 .6-6.1q.5-1.8 0-2c-.4-.3-1.2 0-1.2 0s.3.9 0 1c-.4.2-.7-.5-1-1.2-.2-.7-.5-.6-1-.5q-.7.1-.1 1c.3.5.1 1.4.1 1.4l-1.5-1c-.4-.2-1.5.2-1.6.8 0 .6.4 2 1.4 2.9s1 2.4.6 3.1c-.3.8-1.7.7-2 .3a1 1 0 0 0-1.2 0c-.4.5-.8.7.1 1.7m-.5-2.6-.8-.7-.6-.8v.9c0 .6.6 1.2.6 1.2zm2-6.8q.8-.2.5-.8l-1-1.2h-.6l.4 1.4q.1.9.7.6m2.6-2.1q-.1.7.4.4.7-.5.4-1.1c-.2-.4-.7-.7-.7-.7l-.3-.2zm3.7.6-.2-1s0 .5-.2.9q-.4.3 0 .5.3.3.4-.4m5.8 25c.7 1.7 2.5-1 4.2-3 1.7-2.2 1.6-.6 1.4 1.2a8 8 0 0 0 1.1 4.7c.7 1.2 1.3.5 1.5-.3.3-.8.5-2.6 1-3.4.7-.9 1.2-.1 1.3.6a8 8 0 0 0 1.7 3.3c.9 1 1.3-.3 1.5-1.5l.9-3.7c.2-.7 1-.1 1-.1l1.7 1.6c1 1 1.2-.6 1.3-1.4.1-.9-.2-2.7.2-3 .3-.3 1.2.4 2.7 1.1s1.4-.7 1.2-1.4a8 8 0 0 0-2.1-3.6c-1.2-1-1.4-2.2-1-2.7s1.8 0 2.7-.2q1.1 0 2-.3c.7-.1.7-.8.7-.8s-.5-.8-1.5-1.7-1.5-1.5-2.7-1.8c-1.1-.2-2.7 0-2.7 0l-.2-.3q-.4-.4-.7 0l-1.3 1.2q-.6.6-1 .4c-.3-.1.3-.5.3-.5s.6-.5 1.1-1.6q.9-1.8.3-2.7c-.4-.5-1.7 0-2.3 0q-1 .1-1.2-.2c0-.4.7-.2 1.5-.3s1.4-1.1 1.7-2q.3-1 1-.2c.7.8 1 .4 1 0l1.1-2c.6-.8 1-2 .3-2.7s-2.1-.7-2.7-.2q-.9.6-1.2 2.2c-.1 1.3-.5.6-.5.2s-.5-1-.3-1.5 0-1 0-1 0-1.1-1.2-1.4a9 9 0 0 0-3.7.4c-1.2.3-1 1.3-1 1.3l-1.8.1-3 .8q-1.3.2-1.2.7l.2 1.2s.7 0 1 .2q.6.5-.2.8-.6.1-.6.8 0 .9.7.7.7-.1 2.5.5c1 .5 1.4 1.5 1.3 2-.2.6-1.7 1.3-2.5 1.3s-1 .2-1 .7 1 .5 1 .5l2.7.2c1.9.3 2.2.6 3 1.4s.2.9-.2 1q-.7.6-1.6 1-.8.6-1.6.8c-.5.1-2 0-4.5 1s-3.4 4.5-3.4 4.5l1.5-.8 4-2.1c1.3-.8 1.3.4.6 1.6s.6 1 1 .6.9-.7 2.2-1.4.8.4.8.4-.4.8-.5 2.7c-.1 1.8 1.9 0 2.7-1.1 1-1.2 1.3 0 .7 1.3s-2 2.4-2.7 2.4-1.3-.7-1.4-1.2.3-1.8-.2-2.1-1.7 0-2.7.6-1.1.1-1.4-.4.4-.7.2-1q-.5-.3-1.2.2l-3 1.5c-1.7 1-1.6 1.4-1.6 2.7s.3 1.6 1 3.3z"/>
<path fill="#d4af3a" d="m252.5 239.1 1-.5 1.6-.3c.8 0 .6-.5.5-.9q-.2-.5-1.5-.5c-1.3 0-1.6.5-2.1.7-.6.3-1.3.4-1.3.4l.5.7q.7.9 1.3.4m4 4 .9-.2 1.3-.6c.7-.3 1-.4 1.4-1.1s-.5-.8-1.6-1.1q-1.7-.4-1.9.5.1.6-.5 1.8c-.6 1.2 0 .7.4.7m-.3 1c-1.1 0-2.4 1.7-2.9 2s-.2.6-.2.6a7 7 0 0 0 .7 3.1h.8q.8 0 1.7-.7a4 4 0 0 1 2-.8 6 6 0 0 0 2.3-.9c1-.5-.5-1.4-1.6-2.3a4 4 0 0 0-2.8-1m-15 3.9q1.5-.3 1.4-1 0-1-1.6-1c-2.8.3-5.5-.7-6-3.5 0 0-1 1.7.8 3.7 1.7 1.9 4.6 1.9 5.5 1.8zm-9.4 43.7.5.5h4.3q.9-.5.7-1.3l1-5c.7-2.8 1.7-4.8 2.1-6 .4-1.1-.4-1.5-.7-2.2s-.8-2-.9-2.6-1.1-.6-1.7-.5-.6 1-.7 1.7c0 .9-.5 3.4-.9 5.5-.4 2.2-2.8 5-3.5 5.7q-1 .9-1.7.9-1.1 0-2 .3-1.2.5-1 1.7c0 .6 1 1 1 1l1-.9q.6-.4 1.7-.6 1 0 .5.5c-.3.3-.2.4.3 1.3m-6.5-.2q-.5.1-.7.7h2.8l-.3-.7c-.3-.4-1.2-.2-1.8 0"/>
<path fill="#d4af3a" d="m229 291.4-.9.8h3q.3-.5-.2-1c-.7-.5-1.4 0-1.8.2zm26-1.2q-.4 0-1 .6t-.7 1.2v.2h1.3v-.2q0-.5.7-1.2c.6-.4 0-.6-.2-.6zm2.5 1.3q0-.6-.4-.7c-.3 0-.8.6-1.2.8l-.5.6h2z"/>
<path fill="#d4af3a" d="M269 277.7c1-.6.8-.8.9-1.5q0-1-.3-1.1c-.4-.3-1.8-.9-3-.9s-3.6.3-4.6 1c-.9.5-1.3 2.8-1.3 4q0 1.3.5 1.2c.5-.1.9-.8.9-.8l1.9 2.7c.7 1 .4 1.5 0 2.3-.3.8-1.4 3-2.4 3.5s-1.6 0-2.8-.1q-1.4-.3-2.3.8c-.7.6 0 1.1.3 1.1q.7-.1 1.4.5c.3.4 0 1.3 0 1.8h5.5c.9-.4 1.6-1.7 1.8-2.4.3-.8 1.5-1.9 2-2.4.7-.6.7-1 .7-2.1a5 5 0 0 0-.7-2.7 5 5 0 0 1-.7-2.8c.1-.7 1.3-1.5 2.2-2.1"/>
<path fill="#d4af3a" d="M260 264q.7 1-.5 1.2-1.1.3-3 .2c-1.9-.1-1.1 0-1.2.7a5 5 0 0 1-.8 2.9c-.8 1-1.7.5-2.2.2q-.9-.6-1 .4l-1.2 2.2c-.6 1-1 1-1.4 1-.4-.2-.8-.8-1.2-.8q-.7-.2-1.7-1.9c-.6-1-1 .1-1.4 1q-.5 1.4-1.6 1.4c-.8-.1-1.7-1.6-2.1-2.5q-.6-1.7-1.4-1.7c-.7 0-1.9 1.4-2.6 1.8q-1 .6-1.3-.2-.6-.6-1.3 1.3-.5 1.8.7 2.4c.6.3 1.8-.6 2.7-1.1.8-.6 1.2-.4 2-.4s.8 1.4 1.2 3.4c.4 2.1 1.6 2.4 1.6 2.4s.4.3 1.3-1.2c1-1.6 1-3.2 2-3.2s1 .2 1.8 1.5c1 1.2 1.7 2.1 2.2 1.2s1-2.3 1.6-2.8c.5-.5 1-.6.5.3s-1 1.8.4 1.5c1.2-.4 6-2.4 8-2.8l5-.5 4.4-.3c1 0 1 0 1.1-.8 0-.7-.5-.5-2.4-.5q-2.8 0-4.6.4-2.1.3-1.8-.2c.3-.3.7-.6 2.2-.8l6.4-.4c1.7 0 1.1.4 1 1.6-.1 1 .1 2.7.2 3.7s.2 1.4 1 2.8c1 1.5 4 2.4 5 2.8.9.5.7 0 .7-.8q.1-1.2 1.5-.4 1.4.6 3 1c1 .3 1 .5 1 1l.3 2.5c.1 1 0 1.3-.4 2l-2.1 2.4s-.8 0-2.5.4-2.2 1.2-2.4 1.9.3.9.4 1.1v.9h.4l.6-1c.6-.7 2-.9 3-.4q.9.6.6 1.4h3.9l2-4.2c.5-.9.7-1.5.7-2.8s.2-6.2 0-6.4 0-1.1 0-2.5c-.1-1.4 0-2.4-2.6-2.7-2.5-.2-3.3-1.3-4.2-2.2-.9-.8-.6-2.8-1.3-5.2s-2.4-2.8-5.4-3.4a25 25 0 0 0-7.5-.5c-2.2.2-5 .6-6.6.4s-1.2.3-.7 1.2z"/>
<path fill="#d4af3a" d="m274.5 291.6-.6.6h2.6l-.2-.8q-.7-.6-1.8.2m4.7-.1-1 .7h2.7v-.3c0-.4-.9-.9-1.7-.4M214 293l.6 2.5h82.8l.6-2.5zm55.8-39.6c2.7 1.8 11 1.9 14.9 2.6s3.6 3.8 2.4 5.4c-1.2 1.5-6.7 1.7-7.7 1.8.6.4 1.4 1.6 1.4 1.6l2.2-.2a12 12 0 0 0 6.5-2.2c2-1.7 1.9-4.3.1-6.1s-4.6-2-7.6-2.3l-8.5-1.1q-5-1-4.9-3.8c0-2 1.8-3 3-3.3 1.4-.4 3.4-1 5.3-.3s4 .8 7.6.3 4.4-3 4.4-3-.4.3-2.3.3-3.1-.7-6.5-.8c-3.3 0-4.5 1.2-6 1.7-1.6.6-5.8 1-7 3.7s.1 4 2.8 5.7z"/>
<ellipse cx="248.1" cy="241" fill="#b96b29" rx="1.6" ry="1.5"/>
<path fill="#b96b29" d="M281.6 243.7c-2-.2-4.8.3-4.8.3s.6.4 1.3.4q.9-.1 3.9.3c2 .3 3.5-.6 3.5-.6z"/>
<path fill="#1d5e91" d="M262 282.2q-.6-1-1.2-.2c-.6.5-1.2-1.2-1.3-2.3l.4-4.4s-2.8.5-4.3 1-3 .7-4.2 1q-1.7.6-2.5.4l-3.1-.2c-1.1 0-1 .2-2.1 1.3-1.1 1-1.4 1.7-2.3 3.7q-1 2.8-1.4 6.4-.3 2.4-.7 3.3h13l.5-1.4a3 3 0 0 1 1.5-1.4q.9-.2 1.2-.8.6-.9 1.6-1.4 1.2-.4 3 .2c1 .3 1.4-.5 1.7-.9l1-1.7c.6-.8.2-1.4.2-1.4s-.5-.4-1-1.2m20.8.4q-.1-1-.5-1-.8 0-1.9-.5c-.6-.3-.6 1.5-.6 1.5s-1.5.1-3.2 0c-1.7-.3-3.8-1.8-4.5-2.3-.7-.6-1.5-1.7-1.5-1.7l-1 .8q-1 .6-1 2.5c-.1 1 1.2 2.4 1.3 3.5.1 1-1.2 3.3-1.8 4.1-.4.6-1 2-1.3 2.7h6.2l.7-1c.6-.7 1.7-.9 1.7-.9l.3-.8q.2-1 2.4-1.9c1.6-.6 3.4-.7 3.4-.7s.8-.6 1.3-1.5.2-2 0-2.8"/>
<path fill="#d4af3a" d="M230.6 351.6c1.2.4 3.4-.4 4.5-1.8 1-1.3 1.4-3.3 2.2-4.5l1.4-2s-.2 2-1.2 4.5a17 17 0 0 0-1 7.3c.5 2.8 2.4 3.3 3.5 3q1.3-.7 3.2-3.6l1-2c.7-1.5 1.4-3.8 1.7-3.7.7.1.3 1.7 0 2.8-.6 2.2-1.6 5.4-1.7 7.3-.1 2 .1 5.5 2 5.7 2 .1 3-1.6 4.1-5.6s1.3-5.2 1.8-5.2.5 2.7.5 3.9a20 20 0 0 0 1.7 7.9c1 .8 1.7.7 1.7.7s.8.1 1.7-.7c1-.9 1.7-6.7 1.7-7.9s0-3.9.5-3.9.7 1.3 1.8 5.2c1 4 2 5.7 4 5.6s2.2-3.7 2.1-5.6c0-2-1.1-5.2-1.7-7.4q-.6-3.3 1.7.8l1.4 2.7q1.5 2.4 2.8 3c1.1.3 3-.2 3.5-3 .4-3-1.7-11.2-1.7-11.2l.9 1.4c.8 1.2 1.2 3.2 2.2 4.5 1.1 1.4 3.3 2.2 4.5 1.8s1.3-2.5.4-6.4-4.3-6.1-6.8-9.2c-2.3-2.9-4-8-4.3-8.7a29 29 0 0 0-8.4 6l-6.3 6.6s-1-1.3-6.2-6.7a29 29 0 0 0-8.5-6c-.2.7-2.4 5.6-4.7 8.4-1.1 1.5-2.7 2.6-3.9 4a13 13 0 0 0-2.5 5.6q-1.3 5.8.5 6.4z"/>
<path fill="#d4af3a" d="m230.5 364.8 2.3-2s1-1 .8.8c-.3 1.7-.9 5.3-.5 6.8.4 1.6.6 3 2.5 1.8s2.3-1.9 3.2-2.8c1-1 2-1.4 1.7.1-.2 1.5-1 3.8-.6 6.9q.6 4.6 3.8.9a34 34 0 0 0 3.7-6.3c.6-1.3 1.8-2.4 1.8 0 0 5.1 1.2 12.6 6.8 14.5 5.7-2 6.8-9.4 6.8-14.5 0-2.4 1.2-1.3 1.8 0a35 35 0 0 0 3.7 6.3q3.2 3.8 3.8-1c.4-3-.3-5.3-.6-6.8s.8-1 1.7-.1 1.4 1.6 3.3 2.8 2-.2 2.4-1.8c.4-1.5-.2-5-.5-6.8s.9-.8.9-.8l2.2 2c1.5 1.3 3.6 1.4 3.6 1.4s1-5.3-1.3-8.5l-3-4.3s-1.3 0-2.2-.4l-2-1.1v3l3.4 3.3c.7.8 2 2.1 0 .9l-3.3-2.6s-.4 2.7-1.2 3.4-1.9.8-2.3.6l-.5-.2-.1 1s1.7 3.2 2 4.5q.2 1.8-1-.5c-.8-1.7-2.3-3.8-3-5-.7-1-1.7-1.8-1.6-.4.1 1.5-.5 4.1-1 5l-.8 1.4 1.2 4.4c.1.6 0 1.4-.6.5s-2.2-4.5-2.2-4.5-2.3 0-3-.7c-.6-.6-1.6-3.1-1.6-3.1s-.9 3.1-1.6 4.1-2.6 2-2.6 2l-.2 6.5q0 1.4-.6 1.4t-.6-1.4l-.2-6.4s-1.8-1-2.5-2c-.8-1-1.7-4.2-1.7-4.2s-1 2.5-1.6 3.1-3 .7-3 .7-1.6 3.7-2.2 4.5c-.6 1-.7.1-.5-.6 0-.6 1.1-4.3 1.1-4.3l-.8-1.3a13 13 0 0 1-1-5c.1-1.5-1-.8-1.6.4-.7 1.1-2.2 3.2-3 4.9q-1.1 2.4-.9.5c.3-1.3 2-4.5 2-4.5l-.2-1-.4.2c-.5.2-1.6 0-2.4-.6s-1.1-3.4-1.1-3.4l-3.4 2.6c-2 1.2-.6 0 0-.9l3.4-3.3v-3s-1 .7-2 1l-2.2.5-3 4.3c-2.2 3.2-1.3 8.5-1.3 8.5s2.1 0 3.6-1.4m27.5 35.7-2-2.5q.3 0-1.9 2.5c-1.4 1.7-4.8 4.3-4.8 4.3A17 17 0 0 0 256 417c2.2-1.4 3.5-3.3 4.9-5.3 1.6-2.4 1.9-6.9 1.9-6.9s-3.4-2.6-4.8-4.3"/>
<path fill="#b96b29" d="M255.3 406c.1 1 0 3.6.7 3.6s.5-2.6.7-3.6l.1-3.5h-1.7s0 2.4.2 3.5"/>
<path fill="#d4af3a" d="M256 161.4a54 54 0 0 1-17-2.2l-4.2 1a55 55 0 0 0 21.2 3.4c9.3-.1 14.7-1 21.1-3.5l-4.2-.9a54 54 0 0 1-17 2.2zm21.9-5-4-2.7c-.7-.4-.1-1.4 0-1.8a18 18 0 0 1 5-1.7c1.6-.4 1.4-.8 1.4-.8s-1-1.1-7.2-1.8-17.1-.5-17.1-.5-11-.2-17.1.5-7.2 1.8-7.2 1.8-.3.4 1.4.8 4.8 1.3 5 1.7c0 .4.6 1.4 0 1.8l-4 2.7c-.5.4-.5 1 .2 1 .8 0 .8 0 3-.4a101 101 0 0 1 37.5 0c2 .5 2.1.5 2.9.4s.7-.6.2-1"/>
<path fill="#d4af3a" d="M270.8 159c-4.2-.5-7-1-14.8-1s-10.6.5-14.8 1c2.6 1 7 1.6 14.8 1.6s12.2-.5 14.8-1.6m-19.4-61 3.5-.4-.2 3 3.2-.2-.3-2.9 3.5.5.2-2.8-3.7.3.6-3h-4l.7 3-3.5-.3zm10.4 7.2h-4.4v-3.7l-1.3-.1H255v3.8h-4.5a5 5 0 0 0-.2 2.1H262v-.6l-.3-1.5z"/>
<path fill="#1d5e91" d="M256.1 112c2.6 0 4.8-1.5 5.6-3.6h-11.2c.8 2.1 3 3.6 5.6 3.6m2.4-10.2v2.6h3a6 6 0 0 0-3-2.6m-4.8 0a6 6 0 0 0-2.9 2.6h3z"/>
<path fill="#b96b29" d="m259.5 149.3-3.5-1.6-3.5 1.8c-1.3.6-1.1.4-1.5 1.4q-.5 1.1.6 1.4l4.4 2.3 4.9-2.3c.9-.4.7-.9.5-1.6q-.3-.8-2-1.4z"/>
<path fill="#d4af3a" d="m259.9 150.4-4-1.8-3.7 1.8 3.9 2zm-4-15s-.3 1.4-.7 2q-.7.7-.6 1.8c.1.7.9 1.1 1.4 1.1s1.2-.4 1.4-1.1q0-1-.7-1.8c-.4-.6-.7-2-.7-2z"/>
<circle cx="256" cy="141.7" r=".7" fill="#d4af3a"/>
<path fill="#d4af3a" d="M253.4 138s1.3-1.4 1.7-2.3l.9-1.6.8 1.6c.5.9 1.7 2.3 1.7 2.3s1.8-1 2.8-4.3c1-3.4-.3-7-.7-10.8l-.8-10.4a8 8 0 0 1-3.8 1.1 8 8 0 0 1-3.8-1.1s-.4 6.6-.9 10.4-1.7 7.4-.7 10.8 2.8 4.3 2.8 4.3"/>
<ellipse cx="256" cy="130.4" fill="#b96b29" rx="3" ry="2.9"/>
<ellipse cx="256" cy="123.5" fill="#b96b29" rx="2.9" ry="2.8"/>
<ellipse cx="256" cy="117" fill="#b96b29" rx="2.8" ry="2.7"/>
<circle cx="256" cy="129.9" r="1.6" fill="#d4af3a"/>
<ellipse cx="256" cy="123" fill="#d4af3a" rx="1.6" ry="1.5"/>
<ellipse cx="256" cy="116.5" fill="#d4af3a" rx="1.4" ry="1.3"/>
<path fill="#b96b29" d="M255.9 358.5q.3 0 .2-1.4l.4-4.3c.2-1.2-.3-1.2-.7-1-.3 0-.5 1-.5 1.5l.2 4.4q0 .8.4.8"/>
<path fill="#d4af3a" d="M224.4 383c1.4-.8 2.6-1.7 5.6-3.8a13 13 0 0 0 4.2-4.2h-1q-1.1-.2-1.2-1.7l.2-4.4c.2-2-.3-3.5-.3-3.5s-1.3 1.2-3.3 2.3-2.8.5-2.8.5l-.5-2-2 4c-1.2 2-4.5 4.4-6.8 6.2a31 31 0 0 1-6.9 4.2c-1.9.7-.8 1.6-.8 1.6s2 2 7 2.8c5 1 7.3-1 8.6-2"/>
<path fill="#d4af3a" d="M241.9 381.1c-1.8-.2-2.9-.8-3.2-2.8-.2-1.2 0-6 0-6l-1.2 1.2c-.7.9-2.2 1-2.2 1s-.2.7-.9 1.8a10 10 0 0 1-3.2 3.5l-5 3.4a30 30 0 0 1-4.5 3.3 8 8 0 0 0-3.8 5q-1 3.6 1.8 3.2c2-.2 2.2 0 5.4-.8s7.7-4.4 11-6.5c3.4-2 5.8-6.3 5.8-6.3"/>
<path fill="#d4af3a" d="M250.7 384s-1.3-1.7-1.8-3.6l-1.5-5.8-1.5 3.5c-1 2.3-3 2.9-3 2.9s0 1-1.5 2.9a23 23 0 0 1-6 5 23 23 0 0 0-7 5.6c-1.6 2.3-1.7 4.7-1 5.7.8 1 1.9-.2 3.4-1 1.5-.7 5.9-1.4 12-4.6s7.9-10.6 7.9-10.6"/>
<path fill="#d4af3a" d="M253.3 397.5c1.7-2.5 2-8.5 2-8.5l-1.5-1-2.3-3.1-2 4a16 16 0 0 1-4 4.6c-2.2 2.1-5.2 4.1-6.5 6.3s-.6 6.7.2 8.1c.9 1.5 2 1 3.3-.2l3.9-3.4c2.2-1.9 5.3-4.3 7-6.8z"/>
<path fill="#b96b29" d="M233.6 347a23 23 0 0 1 2.7-5l1.3-2.5s-2.1 2-3 3.4a15 15 0 0 0-1.7 4.2q-.6 2.4.7 0zm8.5 1.6.5-2s.4-1.2.2-1.3q-.5 0-1.7 2.7c-.6 2-1.5 4.8-1.3 5 .1 0 2-3.2 2.3-4.4m6.7 5.4.4-1s.7-2.1.7-2.6-.2-1-.8.2q-.7 1.8-.7 2.7c-.2.5-.8 2.2-.6 2.4s.6-.9 1-1.7M228 374.4l-.9-.5-1.3 1.5-2.2 2a9 9 0 0 1-2.8 2.4q-2.1 1-1.7 1.1c.3.3 1.2-.3 1.2-.3s.4 0 2.1-1 2-1.6 3.1-2.5c1.1-1 2.5-2.7 2.5-2.7m7.3 8.7c.7-.7 1.3-1.2 1-1.5q-.6-.6-1.4.1l-3 2.8-2.2 1.7c-.7.6-2.4 1.5-3.2 1.9-.8.5 0 .5 0 .5l1.3-.5 2.6-1.1 1.8-1.1zm8.4 5.8c.6-1.1 0-.8-1-.4-.8.3-2.8 2.5-4 3.3l-3.1 1.7c-1 .5-1 .7-1 1q.2.3.9 0l1.8-1 1-.2q.8-.1 2.6-1.7 2-1.3 2.8-2.7m4 7.7c-1.6.9-4.1 2.9-4.8 4.2q-1.1 2.1-.9 2.6c.2.2 1-.3 1.3-.8l1-1.4s2.5-2.5 3.4-3a9 9 0 0 0 2.9-3.3c.3-1 0-1.5 0-1.5s-1.5 2.3-3 3.2z"/>
<path fill="#c52126" d="M208 181.3a24 24 0 0 0-19-1.6q-3.4 1-6 .2c-2.8-.7-5-3.2-5.7-6.3 0 0-2.6 3.3 0 6.8a8 8 0 0 0 4.6 3.2c5.5 1 10.8-2.3 15.3-2.6 4.4-.2 7.8 2.5 7.8 2.5s1 .9 2.5 0q2.3-1.2.5-2.3z"/>
<path fill="#d4af3a" d="m192.3 338.7-1.3-.2-2.8-.9q-.9-.4-1.7.3c-.8.7-4.4 2.9-4.4 2.9h6.5c2.2 0 3.7-2.2 3.7-2.2z"/>
<path fill="#d4af3a" d="M210.5 337.6v-.7l-.8-1.8s-1 .6-2 1.6c-1.3 1.3-2.6 3.2-3.2 4-1.1 1.3-2.6 2.6-1.3.4s1.7-3.2 2.7-4.6l1.7-2.2-3.7-.6c-2.7-.3-4.4-1.4-5.6-2.1l-3.5-2s-4.6 2-6.3 2.4c-1.8.5-2.8.7-1.1 1.5s3.1 1.1 4 1.6c.7.6 3.3 1.4 4.8 1.4 1.6 0 4.2 0 3.2 1q-1.6 1.8-3.3 6.4a22 22 0 0 0-1.2 7.4l.2 2.7s1.9-2.1 7-5.3 7-4.3 7.9-4.7 1.4-.4 1.2-1.6z"/>
<path fill="#d4af3a" d="m230 322.1-1-.4h-.2c-.6.4-3.7 2.4-5 4.5s-2.5 2.2-1.1 0a19 19 0 0 1 3.5-4.4l1-1a56 56 0 0 1-7.8-4.5c-.3.7-1 2-1.7 2.7-1 1.1-3.5 2.1-3.5 2.1s2-2 2.6-3.5l.8-2.6a34 34 0 0 1-5.1-4.9 19 19 0 0 1-4.4 7.9c-4 4.5-12 6.7-12 6.7s-2.8.3-.5 1c2.2.5 3.8 1.5 8.3.8 4.4-.8 4.7-1 5.3-1.2s2.2 0 0 .8-7.4 1.6-9.3 1.4c-2-.1-4.7-.6-1.9 1s4 2 5.7 2 2.5.6 4.2.6 2.1-.3 3.3-.6q1.9-.2 2 .7c.1.9-1.6 1.8-1.6 5q0 5 .6 6.4c.3 1 1 2.5 1.5 3.4.5 1 .7 1.8 1.1 0 .5-2 1.6-4.7 2-6.6s.7-1.9.8-2.9 1.2-1.6.8.1l-1.4 5.5c-.4 1.5-1.2 4.4.2 2.1 1.5-2.2 6.8-8.3 7.7-9.3q1.4-1.6 2.3-3c.6-.9 2.5-2 3.4-3.4.8-1.2 3.2-3.5 4.2-4.3L230 322zm-74.2-137.7c.1 3.3 3.8 9.6 5.8 13 2.1 3.3 2.7 4.6 2.3 4.8-.3.3-1.2-1.5-2.3-3l-5.2-7.6c-1.9-2.6-4.6-9-5-9.5-.3-.6-.5-1-1.4-.2-1 .7-2.7 7.6-.6 12.3 2.2 4.8 5.4 8.2 6.7 9.8 1.4 1.7 3.2 4.2 2.9 4.5s-.8-.5-2.4-2.2l-6.2-6.8a49 49 0 0 1-4-6.5q-.5-.7-1-.1c-.5.6-1.4 2-1 5.7.5 5.2 3.3 8.2 5.7 10.9 2.4 2.6 4.8 4.8 4.5 5.2-.4.3-2.9-1.9-4.6-3.5s-6-5.7-6.8-6.9c-1-1.1-2.3-.6-2.2 4 0 4.4 5 9 7 11.5 2.2 2.5 4.7 4 4.5 4.5s-2.3-.8-3.6-1.7c-1.4-1-6.4-4.2-7.4-5-1-.6-1.5.7-.3 5 1.3 4.3 5 7.7 7.2 9.3s5.8 3.5 5.6 4q-.5.6-3.8-1.1c-2-1-4.5-2-6.3-2.5s-1.8.8-1.8.8-.4 3.7 2.3 6.6a14 14 0 0 0 8.5 4.6c2.8.5 3.3.6 3.2 1q0 .6-1 .5c-.7 0-3.3.3-5.7.3s-3.7.6-3.7 1.7c0 1-.1 2.5 3.5 4.9 3.7 2.4 7.7 2.8 9.5 3.1s1.7.5 1.4 1-1.2.5-3.9.8c-2.7.2-4.3 1.3-4.7 2-.4.8.2 2.9 2.4 4.4q3.1 2.2 9.4 1.7c4.3-.3 5.3-.3 5.5.4.1.7-1.3.9-3.4 1.3-2.2.3-3.8.3-5 1.3s-.3 3 1.7 4.6c2.1 1.5 7.2 1.5 9.4 1.3 2.1-.1 5.4-.9 5.6-.3s-1.5 1.4-3.8 2.2-2.8 1.3-3.2 2.2-.1 1.8 2.5 2.8c2.7 1 6.5 1 8.5 0q3-1.3 3.5-.8.3.4-.5 1.2a10 10 0 0 1-4.3 2.4c-2.2.6-2.5.6-3.2 2.4s1.2 3.2 5.2 3.3c4 .2 9.3-1.4 11-2.4q2.4-1.4 2.7-.9.6.5-.7 1.2c-.8.7-3.5 2.6-4.9 3s-1.5 1.3-1.5 2.3-.4 2.8 3.2 3.6 7.8.2 11.6-2.5a9 9 0 0 0 2.4-2.2c-.3-3.7-.1-6.2.3-8.5a14 14 0 0 1-3.6-.9c-2.2-.8-3-2.8-3.5-4q-.8-1.3-2.1-.7-1.2.6-3 .6a8 8 0 0 1-5.6-3c-1.8-2.2-1.5-4.3-1.6-5.4 0-1-1.7-.3-2.6-.3s-3.3-.3-5.6-1.9-2.3-3.7-2.5-4.6-1.2-1.4-1.9-1.7-1.8-.6-3.4-1.8-2.1-3.8-2.2-4.7c0-.8-1-1-4.2-2.6s-3-5-2.8-6.4c.1-1.4 1.6-2.5 1.6-3s-1-.6-2.1-1.3c-1-.6-3.8-1.7-3.9-5.7 0-4 2.6-4.4 2.6-4.4l-1.6-.9c-1-.6-4-2.6-4-5s1.1-3.4 1.9-4 3-1.1 3-1.1-1.4-1-2-2.8-.8-4.1.6-5.8c1.3-1.6 3.6-1.6 4.8-1.6s2.3.7 2.7.3.5-.6.1-1.6-.5-3.2-.2-4c.4-.8.5-2.3 3.5-3.3s6.3 1 7.3 1.6.6-.8.6-1.8-2-3.5-4.4-7a78 78 0 0 1-10.8-25.1c-.4-1.8-1-1-1-1s-.8.3-2.4 4.5a27 27 0 0 0-1.8 11.2"/>
<path fill="#d4af3a" d="M209.6 257.5a8 8 0 0 1-6-3.8c-1.9-2.7-4.6-3.3-9.4-3.2s-7-2.2-8.2-5.5c-1.2-3.4.2-7.1 5-9.5 5-2.4 7.1-5.1 7.3-9.2.2-4.2-4.9-9.3-9.9-15.1s-9-14-9-14-1.5 1.9-1.5 3.8c0 2 .8 4 0 4.5-.7.6-1-.8-4-2s-5.3-1.5-7.1.6 0 5.8 1.7 7.5 3 3 2.5 3.7-3-1-3.7-1.6c-.9-.5-2.8-2.6-5.7-2.4-2.8.3-3.8 1.1-4 3.5-.4 2.4 2.5 4.6 4.3 5.5q2.9 1.4 2.1 2c-.4.5-.9 0-1.7-.2s-3.1-.5-4.6 0-3.9 2.6-1.7 5c2.2 2.6 6.8 3.5 7.8 3.7s1.3-.1 1.4.6c.1.8-1.9.8-4.4.9s-3.2 2.4-2.8 4.3c.3 1.8 4.5 3.8 6.8 4.2s3 0 3.3.7q.3.8-1.6 1.2c-1.3.4-3.8.7-4.2 2.7s-.6 3 1.4 4.7c1.9 1.8 5 1.5 6 1.3s2-1.2 2.9-.3c.9 1-.8 1.7-2.4 2.8s-1.5 3.2 1.2 4.7a8 8 0 0 0 6.4.5c1.1-.3 2.6-2 3.3-1 .8 1.1-2.3 1.5-3.6 3-1.2 1.6-.8 4.2 1.8 5.8s6.8.4 7.5-.2q1.3-1.2 2.2-.4c.6.6-.2 2-.8 3.3-.5 1.3-1.5 5 2.3 6.6 3.9 1.4 7.4-1.9 8-2.5q1-1 1.8-.5c.6.3.3.8-.1 1.5a4 4 0 0 0 1.3 5.3 7 7 0 0 0 5 1q1-3 2-7.6h-.5c-.4 0-.4.5-.4.7q0 .4-.3.4c-.3 0-.3.2-.8.6q-.8.6-1.2.5c-.2-.2 1-.8 1.3-1.2q.8-.7 1-1.5 0-.6 1-1.3l.5-.5q.7-3.2 1.3-7.7l.4-5.9zM131.1 200c4 8.3 9.9 13 9.9 13s-.8-2.1-1.1-3.5-.1-3-.1-3-1.5-2-4.1-6c-2.7-4.2-4.2-10.3-4.2-10.3s2.5 6.1 4.5 9.3a50 50 0 0 0 4.2 6s.8-3 1.3-3q.8-.2 1.5.9.8.7.9.5l-1.7-3q-.9-1-1.6-2.3c-1.6-2.4-4.9-7-6.6-11.6s-5.4-16.1-6-19.5-1.3-1.6-2 1a29 29 0 0 0-.9 11.3 57 57 0 0 0 6 20.2m5.3 22.4 3.8 2.7-.6-1.9-.3-3-3.1-2.7a44 44 0 0 1-6-6.4c-3-3.8-.6-1.5 2 1.3s7.4 6.8 7.4 6.8v-1q0-1.2.7-2c.5-.6.3-.6-2.5-2.7a80 80 0 0 1-18.7-26.1s-1.6 9.5 4.2 20 11.5 13.9 13 15zm30.4 60c3.2-1.2 2.3-4.3 2.3-4.4l-3.7 1.3c-1.8.7-6.2 2-8 2s-1.7-.2-1.8-.4c0-.3 1.4 0 3.9-.5s6.9-2.8 7.7-3.3q1.1-.7-.5-.7a5 5 0 0 1-2.5-1c-.4-.3-1.6.2-4.5.9a53 53 0 0 1-23 .8c-.6-.2-1.4.2.8 3.9s10 5.7 15.4 5.6c5.3 0 10.7-3 13.9-4.1zm-14.3-7.6c5.5 0 7.6-1.6 7.6-1.6s0-.3-.7-1.4c-.8-1.1-.6-3-.6-3l-3.7.5q-3.5.8-8 .2c-2.9-.6-1.6-.9.7-.6 2.4.3 7-.6 8.4-1 1.4-.6.8-1-.2-1.4s-3.6-2-3.6-2-6.8.8-13 .1-10.2-2.3-11.5-2.5-1.2.3-1.2.3-.4.6 1.8 4a18 18 0 0 0 10 6.6 54 54 0 0 0 14 1.8m-1.4-13-.6-1.4c-.3-1.2.6-2 .6-2s-1.3-.4-5.4-1c-4.1-.4-4.4-.8-7-1.3-2.4-.6-4.1-1.3-4.1-1.6q0-.3 2.4.7c1.4.5 7.8 1.2 10.5 1.6q4 .6 4.6.4c.5-.3 2.2-.7 2.2-.7l-2.6-.6a9 9 0 0 1-3.4-1.4c-.8-.5-1-.6-4.4-1s-6.1-1.5-12.2-3.7-10.6-4.8-11.8-5.8-1.2-.3-.8 1c.3 1.2.3 2.8 3.3 6.4s4.6 5.1 12.3 8c7.7 2.8 16.4 2.4 16.4 2.4M128.3 243a43 43 0 0 0 16.5 6.8c.3-.4-.4-2 0-3 .4-1.2 1.1-1.2 2.7-1.3 1.7 0 .6-.4.2-.4l-3.2-.8c-2.7-.7-5.5-1-9.2-2.5-3.8-1.4-5-2.5-4.8-2.7 0-.3 1.7.9 5.2 2.2s7.5 1.8 9.7 2.3.3-.5-.7-1.1-2.5-2.9-2.5-2.9-2.5-.4-6.5-1.6q-5.8-1.7-10.6-4.5l-3.5-2.3-5.5-4c-1.3-1-1-.2-.8.4s1.1 3.5 3.3 6.6 2.8 4 9.7 8.8m-1.2-13.5c6.8 5.3 12.5 7 13.5 7.4s1-.1.7-.7c-.2-.6-.3-2.4-.3-2.4l-5-3c-2.8-1.5-5.7-3.6-7.7-5s-.8-1.2-.2-.7 3.4 2 6 3.8l7 4.1s0-.9.6-1.4c.6-.6 2-.4 2-.4l-1.1-1.4c-.5-.7-2.7-1.4-5.2-2.6a62 62 0 0 1-10.2-7.2c-3.3-2.8-9.7-9.8-10.1-10.3q-.7-.9-.8.2c0 .7-.3 1.2.4 4.4s3.7 9.9 10.4 15.2m23.8-50.3 2.2 3.8 1.5 2.5V184a12 12 0 0 1 0-3.7q.3-1.3.2-2.4-.1-1.4-.4-2c-.2-1-1.2-4.9-1.7-7.7a62 62 0 0 1-.9-10.2c0-3.5.5-1.7.5 0s.2 4.3.8 8.3c.5 4 2.2 10 2.2 10s0-.9.6-2.2l2-4.5c1.1-2.4.4-2 .4-2s-2.4-11.3-3-16.6-1.6-19.4-1.6-19.4c-3.5 3.5-6 12.6-6.5 21.3-.3 6.5.7 12.5 1 15a38 38 0 0 0 2.7 11.3m-7.6 17.8q0-4 2.3-5s-1.4-2.6-2.7-6.3a49 49 0 0 1-2-8.2c-.9-6-1.6-12.3.2-2 1.8 10.2 4 13.8 4 13.8l2.6 4.3a18 18 0 0 1-.3-5.3c0-2 .3-4.8 1-7 0 0-3.2-6.3-5.2-13.9a87 87 0 0 1-3.4-24.1s-3.3 2.4-4.4 14.8a74 74 0 0 0 3.8 28.8l4 10zm35.4 94.5-2-1.3c-1.5-1-1-4-1-4l-1.6 1.1q-1.7 1.3-4 2.3L167 291q-1.4.4 0-.5c.9-.5 1.1-.8 3.2-1.6 2-.8 6.1-4.4 6.1-4.4l-2.6-.1c-1.7-.1-3.9-1-3.9-1s-1.7 1.6-8.5 4.5c-6.8 3-12.6 3.7-12.6 3.7s.7 3.5 4 4.7c2.7 1.1 6.5 1.9 13.8.1a47 47 0 0 0 12.3-4.8zm9 7c.6-2.9-1-4.9-1-4.9l-1.4 1.1c-1 1-2.6 2.7-5.4 4.1-2.9 1.5-4 1.4-1.2-.1s6.9-5.7 6.9-5.7l-1.1-.4c-1-.4-3 .3-10.6 4.9-7.7 4.6-12.2 4.8-12.2 4.8s3.4 4.1 12.7 3.8c9.4-.3 12.7-4.7 13.3-7.6m17.6-3.4s-1 1.5-2.4 2.4c-1.4 1-5 1.5-5 1.5l-1 1.3a15 15 0 0 1-3.9 4.3c-1.6 1.2-4.2 2-4.3 1.7-.2-.3 1.5-1 3-2 1.7-.9 3-2.7 4.2-4 1-1.2-.5-1-.5-1h-3.7c-1.8-.2-1.5 0-2 .8q-.6 1.1-2.6 3.2l-4.7 5.4c-1 1.3-.2 1.6-.2 1.6s.4.8 4.6 1.3c2.5.2 5.3 0 8.2-1.8a25 25 0 0 0 5.6-4.8c5-5.4 4.7-9.9 4.7-9.9m2.2 11.3-1.5 1.9s.7-2.2 1.3-3.3l1-1.4a28 28 0 0 1-1.7-5c-.5 1.5-1.9 5.8-3.7 8.6-2.1 3.5-4 4.7-2.8 5.6q2.2 1.7 6.4-.2a7 7 0 0 0 3.7-5.3l-1.3-2.3q-.5.3-1.3 1.4z"/>
<ellipse cx="206.9" cy="169.2" fill="#d4af3a" rx="1.9" ry="1.8"/>
<path fill="#d4af3a" d="M203 165.9c1.7 0 2.6-.9 4.5-.7a28 28 0 0 1 9.1 3.6 16 16 0 0 0 10.5.9q1.5-.6 3-1.5c4.6-2.5 3.5-7.6 3.5-7.6a18 18 0 0 1-11.4 3.5l1 .8c.6.7 1.8 1.5 1.4 1.8s-2-1.3-3.4-2.3a21 21 0 0 0-7-3.4c-3.4-1-7.4-1.1-10 .3-2.7 1.5-2.9 3.3-2.5 4q.4.7 1.2.6zm49.2 37c-.8-.2-2.2-.5-4-2.2a76 76 0 0 1-6.7-7.3q-.9-1.5 1-2.3c1.2-.5 2-2 2-2s-2.7-1.1-4.5-2.4-6-5.2-6.6-6.1c-.6-1-.3-1.1.5-1.4 1-.3 1.1-1 1.1-1s-2-1.1-3.8-2.6l-4.3-4c-2.7 1.2-7 .7-9.3.3-4.1-.7-7.1-2.4-7.1-2.4l-.7 1.9c-.5 1.3-2.4 2-4.3.7-2-1.2-1.5-4-1.5-4s-1.5-.9-4.7-2q-4.6-1.9-8.2-.2c-2.6 1.2-3.8 4.7-3.8 7.3 0 2.7 1.4 1.6 1.6 1.2s1-2.3 4.1-2.8c3.3-.5 6.2 1 9.8 4s4.5 3.3 6.3 5.2c1.9 1.9.4 3-2.7 4-3.2 1-7.2-1-7.4-1-.6.3 1.4 3.1 4.1 4.2 2.7 1 6.2.3 8.9-.7 1.8-.8 2.2 0 2.7.5 3 3.2 3.7 6 4.2 9.7a4 4 0 0 0 2.8-3.3c.1-.6.3-1.9 1.3-1 1 1 1.9 6.3 1.9 8.7 0 2.5-.8 5.7-.8 5.7l.8-.1q.7-.2 2.5-1.2c1.1-.7 1.2 0 1.2 1.4s.4 3.8 2.2 8.3c1.7 4.4 4.3 5.9 4.3 5.9s.5-.9 1-2.7c.5-1.7 1-5.2 1-8.2s-.9-9.4-.9-9.4 3.7 4.4 7.5 5.5 7.6.5 9.2-1.4.1-2.6-.7-2.8"/>
<path fill="#d4af3a" d="M227.2 214.5s-1.2 2.5-1.8 3.4c-.6 1-.9 1-.9 1s1.2 1 2.8 1.6l3.2.8s-1.9-2.6-2.5-4.4zm22.9-1.5-1-2.3a16 16 0 0 1-8.7-1.8s1.8 3.6 3.5 4.8c1.8 1.3 2 1.3 2 1.3s-1.7.3-4-2c-2.4-2.3-3.5-5-3.5-5s.6 6.2-.4 10l-1.1 4.2s5 1 10.5-.6 6-2 6-2 .6-.2-.3-1.4a30 30 0 0 1-3-5.2"/>
<path fill="#b96b29" d="m240 199.4-1.9-2.4s-.6.6 0 1.4 2.9 3 4.5 4a12 12 0 0 0 3.3 1.2v-.3s-4.2-2-5.9-3.9m-6.8 12.9-.4-9c0-1-.7-.8-.7-.8l-.8.4 1.6 11.3c.2 1.2.8 1.1 1.1 1-.6-.2-.7-2.6-.8-3zm-10.4-33.6c-.6-.6-2-1-.7.5s3.2 3.4 3.7 5 .8 3.5 0 3c-1-.3-1.6-.3-2.5-1.1-1-.8-2.8-2.1-3.5-2.3-.7-.3-2 0-1 1.1a26 26 0 0 0 4.2 3.7l4.2 2.9 2.1 1.4s-1-6.4-2.7-9.1a28 28 0 0 0-3.8-5zm-34.1 105.9c-1.3 1-3 1.4-3 1.4s-.8 0-.8.2 1 0 1.9-.1c1-.2 2.3-1.2 2.8-1.5s1.2-.8 1-1.5c-.3-.6-.7.5-2 1.5zm11 5.9-2.4 2-1.4.6q-1 .6-.9.7 0 .2 1 0c1-.2 2.9-1.8 3.6-2.5q1.1-.8.7-1-.3-.4-.6.2M155 211.1q.7 1 1 1 .4-.3-.5-1.1l-.8-1-1.2-1.6c-.4-.4-1.1-.7-.3.4zm-3.4 7.4 1.5 1.4q.8 1.1 1.2 1c.3-.4-.8-1-1.3-1.7l-1.5-1.5-1.4-.8zm1.3 12c.8 1 2 1.2 2.2.8q.3-.4-.8-1a24 24 0 0 1-4-2.7q-.6-.7-1-.6c0 .1 1.2 1.6 1.6 1.8zm2.4 9.7q.2-.6-.6-.6l-1.7-.2s-1.4-.5-1.5-.3c0 .3 1.2.8 1.7 1a3 3 0 0 1 1.5.4q.5.2.6-.3m1 10.4c-1.4 0-2.7-.3-2.8-.1s.7.6 1.4.8c.8.3 2.2.4 3.2.4s1.1-.1 1-.6c0-.5-1.2-.5-2.7-.5zm11.8 11.5c-.2-.3-.7 0-1.6 0-.8.3-2.2.5-3 .5l-2.5-.1-1 .2q.2.3 3.2.4c1.8.2 3-.2 4-.3q1.3-.3 1-.7zm4.9 8.1q-1.4.5-2.3.4l-2.4.3s-.8.2-.7.5q.2.3 1.1-.1h2.5q1.7-.1 2.7-.6c.8-.1 1.6-.5 1.2-1s-1.2.1-2.1.5m9.5 6.2-2.6 1.9-1.2.7c-.8.4-.7.6-.6.8s.6-.3 1-.5 2-1.2 2.7-1.8 1.7-1 1.6-1.5q-.2-.6-1 .4zm-15.8-79.8 1.8 2.5c1.6 2 .8 0 .4-.5s-2.8-3.9-3.7-4.8c-.8-1-.9-.5-.5.1zm-3.4 10.5q.3-.1-1.3-1.6l-2.8-3.6s-.5-1.1-.7-1 .7 1.9 1.4 2.6c.8.8 1.8 2.3 2.3 2.9q.7 1 1 .7zm4.5 19.7c0-.6-1.9-.5-2.7-.7l-2.3-.5s-1.8-.3-1.8 0q-.1.3 1.3.6l3.5.8c1.1.1 2 .4 2-.2m-4.5-10.7 2.6 1.9c.7.3 1.2.8 1.6.4q.4-.5-1.4-1.1l-1.5-1-1.2-.5c-.5-.3-1.4-.6-.1.3m10.5-7-1.4-1s-1-.8-1-.5c-.3.3 1 1.1 1.5 1.7s1.7 2 2.2 1.7-.5-1.2-1.3-1.9m-6.9 27.5-1.7.4c-.6.2-.7.5.5.5s1.7-.3 3-.5q1.6-.3 1.3-.8t-1.3-.1zm1.9 10c-.1.1.8 0 1.4-.3l2.7-1.1c.8-.2.8-.4.8-.8s-.8-.1-1.8.2-2.2 1.3-2.2 1.3zm12.8 6q1.2-.9.7-1.3-.3-.4-1.3.4l-2 1.5-1.3.6q-1.1.5-1 1c.2.2 1.3 0 1.9-.6.5-.4 2-1.1 3-1.7zm6 8c.3-.4 1.4-.8 1.9-1.1s.8-1.4.4-1.6c-.4-.1-.6.5-1.5 1.1l-3.7 2.5-.7.3q-1 .6.2.5c.7-.1 1-.1 1.9-.7q1.1-.9 1.5-1m9 7.5c.7-.3 1.8-1.3 2.3-1.8s1.2-1.1.8-1.4q-.6-.4-1.4.7c-.7.5-2.3 2.2-2.3 2.2l-1.1.8c-.9.7 0 .6.3.3q.4-.4 1.3-.8z"/>
<path fill="#d4af3a" d="m232.3 150.9-2.7 2.2 3.3 1.4 3.6-2.5z"/>
<ellipse cx="244.4" cy="151.6" fill="#b96b29" rx="3.4" ry="3.3"/>
<ellipse cx="244.4" cy="150.8" fill="#d4af3a" rx="2.1" ry="2"/>
<path fill="#d4af3a" d="M237.3 140.2c.9.3 2 .2 2 .2s.4-1.6-.5-2.3l-2-1.8-.7-.6v2.1c-.1.8.3 2 1.2 2.4"/>
<circle cx="239.1" cy="141.8" r=".6" fill="#d4af3a"/>
<path fill="#d4af3a" d="m234.4 141.2-.8 1s.7 0 1.2.4q1 .7 2 .7a1 1 0 0 0 .9-1.2q-.1-.8-1.6-1.3c-1.1-.4-1.4 0-1.7.4"/>
<path fill="#d4af3a" d="M236.8 145.2c-2.1.2-5-2.2-5-2.2q-.4 3-3.3 3.3h.2s1.7 1 3.7 1.2q1.3.2 2.7-.2a10 10 0 0 0 3.2-1c1.3-.8.9-2.9.9-2.9s-.2 1.6-2.4 1.8m-8.4-2.1c-.9-.4-2.2-1-2.8-1s-1.3-.2-1.2.8 1.2 1.5 2.2 1.6q1.4-.1 2.2-.7 1-.4-.4-.7m-6.7-3.7c-1-.7-1.9-.9-1.9-.9s-.6 1.7-.2 2.7 1 1.3 2 1.3 2.3-.5 1.9-1.2a5 5 0 0 0-1.8-2z"/>
<ellipse cx="222.5" cy="144.1" fill="#d4af3a" rx=".8" ry=".5"/>
<path fill="#d4af3a" d="M224.6 135.8c-.6-2.9-.5-6 2.2-9.9s7.4-5.5 7.4-5.5l1.6-1.9c1.5-1.6 4.5-3.6 4.5-3.6l-5.5 1.5v.1a2.4 2.4 0 0 1-2.4 2.5 2 2 0 0 1-1.4-.4 24 24 0 0 0-5.6 3.1q.4.6.4 1.3a2.4 2.4 0 0 1-2.5 2.5q-.6 0-1-.3l-.4.5-1.7 4a3 3 0 0 1 1 2.1c0 1.4-.9 2.5-2 2.5v1.6q-.2 1.2 1.7 1.7c1.4.4 3.3 2.8 3.3 2.8.1 0 1.1-1.8.4-4.6"/>
<path fill="#d4af3a" d="M233.2 117.6q.8-.7.2-1.4-.8-.5-1.7.1c-.9.6-.6 1-.2 1.4q.8.5 1.7-.1m-9 6.1q.8-.9.2-1.8-.9-.7-1.9.2-1 1-.2 1.7c.4.5 1.3.4 1.9 0z"/>
<circle cx="218.8" cy="131.4" r="1.4" fill="#d4af3a"/>
<path fill="#d4af3a" d="M248.9 112q-1.2.2-4.1 1.7c1.4 0 2.5.9 2.5 2s-1.3 2.4-2.6 2.4a2.4 2.4 0 0 1-2.4-2.3q0-.5.2-.8l-1.9 1.2c-4.4 3-5.5 4.5-7.7 8.5s-3 8.6-2 11.2c1 2.7 4.4 3.2 4.5 3.2q-.2 0-.5-.9l.3-1.7v-2.2s.8-.1 1.3.4l1.5 1.8 1.7 1.6s.7-1 .7-2.2-.8-2.5-1-4.6 1-5.8 3-8.6a24 24 0 0 1 7-5.7 2 2 0 0 0 1.4-2l.3-2c0-1.3-1-1.2-2.2-1"/>
<path fill="#d4af3a" d="M244.5 116.8q1.4-.2 1.5-1.4-.1-1-1.4-1.1-1.3.1-1.4 1.1 0 1.2 1.3 1.4m6.6 26c1 .4 2.2.2 2.8-.2q1-.8 0-1.9a2 2 0 0 0-2.2-.2l-2 1.4s.3.5 1.4.9"/>
<path fill="#d4af3a" d="M254.5 144c-.4.6-.7 1-1.9 1s-2.5 0-3.2-.8l-1.3-1.9h-1.4s-.4 1.9-1 2.4-2.7.6-3.6 0c-.9-.8-1.7-1.6-1.9-1.5q-.3.3 1 1.6c1.3 1.3 1.5 1.3 3 1.3h8.5s1.8.1 2.3-1q.7-1.5.2-1.9-.2-.2-.7.8"/>
<path fill="#d4af3a" d="M241.5 142.6c1.3.7 2 .2 2.5-.3l.5-.9s-1.2-.4-1.8-.8q-.8-.5-1.5-.6l-.7.2s-.2 1.6 1 2.4"/>
<circle cx="235.4" cy="130" r="2.8" fill="#b96b29"/>
<path fill="#b96b29" d="M240.3 120.2c-1.1-.7-2.8-.4-3.7.7s-.8 2.7.4 3.5c1.1.7 2.8.4 3.7-.7s.7-2.7-.4-3.5"/>
<circle cx="235.3" cy="129.6" r="1.6" fill="#d4af3a"/>
<path fill="#d4af3a" d="M239.1 120.5q-1.2-.2-2 .8-.6 1.2 1 1.6c1.8.3 2.6-2 1-2.4m-43.4 219.8s-4.3 2-5.7 2.4l-1.8.4s-3 2.7-5.1 4a19 19 0 0 1-7.6 2.7c-3.5.3-12.9.2-17.1 0-4.2 0-6.8 1-8.7 3s-2.2 5 0 7.2c2.4 2.3 5 1.1 5.8-.2.9-1.4.4-3.2 0-4-.3-.8.8-1 2-1.1a26 26 0 0 1 11.4 2.5c1.4.7.6.8-.4.6l-3.7-1.2a15 15 0 0 0-4.3-1c-1 0-.7.6-.4 1l1 1.7-.4 2 .5 1 .9-1.5c.2-.6 0-1.6.2-2q.4-1 1.8.2a7 7 0 0 1 1.8 3.8c.4 2-.3 3.5-.3 3.5s.9.7 1 1.2c.2.5-.2 2.4-.2 2.4s.6.4 1.2-.7l1.3-3.8c.2-.7.6-2 1.5-1a8 8 0 0 1 1.6 2.7l.2 1s1.9-1.8 2.5-2.9a18 18 0 0 1 3.8-4.2c1.8-1.5 5-4.5 6.5-5.5l6.8-4c1.2-.7 1.4-.7 1.6-2.8s1.3-4 1.8-5.4zm-70.1-78.7c0-.3-.8-1.6-1-2.2s-.8-.3-.8-.3-1.4.8-2.4 1.1q-1.3.3-1.3-.6l-.5-3.4c-.2-1.2-.4-1.1-.9-1l-2.6 1c-.9.5-.6.9-.3 1.4l1.8 3.4c.5.7 0 1-.5 1.3l-2.4.7c-1 .4-1 .6-.9 1l1.2 2.5c.4.6.8.2.8.2s1.1-1 2-1.5c1-.5 1.1-.3 1.4.4l1.5 5.2q.3.9 1.1.4l1.8-.5c.5-.2.7-1.3.7-1.3l-2.6-4.8c-.6-1 0-1.2.4-1.2l2.7-.5c1-.3.8-1 .8-1.3m23.8 103c-.2-.9 0-1.8-.7-2.5a9 9 0 0 1-2-3.2c-.2-1.1.4-1.7.3-2.3q-.3-1-1.9 0c-.8.7-2 1.4-2 3.4s.8 4.5 3.6 5.3c2.9.9 2.8.3 2.7-.7m2.8-1s-.5-.3-.8.2-.2.8.5 2 1.2 1.5 2.1 2 .3-.5.2-.9q0-.5-.3-1-.3-.2-.3-1.4c0-1.2-1.4-.8-1.4-.8z"/>
<path fill="#d4af3a" d="M155.7 373.3c.6-.8 1-1 2.3-1.6s3.7-.9 4.5-1 2.6-1.6 2.3-3.2q-.7-2.2-2.5-2.4-1.6-.5-2.2.2a4 4 0 0 1-2 1.5c-1.2.4-1.3.8-2 1s-.2.6-.8 1.1-1.4 0-2.3-.2-1-.5-2-.5l-3.6-.2h-.7q-.7-.2-1 .7c-.2.6.1 2.2.8 3 .6.8 2.7 1.2 4 1.6l3.3.8c1.3.2 1.4 0 2-.8zm13 1.3c1.1-.7.5-2 .2-2.8s-1.8-1-2.6-1-1.2 0-1.7.4q-.5.6-2.1 1.3c-1.2.3-2.1.8-3.7 1.4s-2.1 1.7-2.8 2.2c-.7.4-2 0-2 0s-1-.3-1.3 0q-.4.4.6 1.5c1 1.1 1.9.6 3.3 1s1.6.1 2.2-.2l1.9-1.8c1-.6 3-.7 4-.8 1.1-.1 3-.4 4-1.2m0-4.9c.5.5 1 1 1.5.3s1-2.1.6-3l-1-1.6-1.2 3.1c-.4.7-.3.8.1 1.2m-4.3-7.4c0-1.4-1-3-1-3s-.3 1.2-.9 2.3l-1.2 1.7 2 .4c.5 0 1.1 0 1.1-1.4m-8 3q2.1-.6 3-1.5c.5-.5 1-2 .5-2.7s-1.5-1.6-2-1.6h-.7s-.5 1.4-1 2.1-1.3 1.2-1.3 2.1 0 1.9 1.5 1.6m3-6.8q0-1.1-.7-2l-.8-.8-.2 1.7-.2.7.8.6c.4.1 1 .5 1-.2zM141 320.4l1-6.3c-.7-6.3-4-12.3-6.6-16.5a79 79 0 0 1-6.5-14 40 40 0 0 1-2-10.7c0-2.5 1-3.8 1-3.8s.5-.6 0-1c-.3-.5-1 0-1.7.6a8 8 0 0 0-1.6 2.8l-.3 1.2s-1.4-.3-3.5-.2q-3.2.2-3.3.8c0 .5.3.9 1.9 1.5s2.5 1 3.3 2c.8.8 2.8 5.5 3.4 7.7a109 109 0 0 1 2.4 13 52 52 0 0 0 4.4 15.3c.7 1.6 4.7 9.1 8.1 7.6m4 11.1c-1.5.8-1.5 6.8-.8 10 .6 3 3.7 6.9 4.6 8 1 1 1.1 1 1.6.7l.7-.3s1.3-.4 2.3-1.2.6-2.6.4-4.3-1.4-5-3.8-9-3.6-4.7-5-3.9m1.5-4.8c0-2-1.7-3.4-3.6-3.4q-1.5 0-2.2.6c-2 1.8-.8 6.3 2 6.3 1 0 2.3-.2 3-1 .7-.5.9-1.6.9-2.5zm28.3 56.2a13 13 0 0 1-5.7-4.4c-.3-.8-.3-.8-1.4-.5s-2.7.4-3.8.4c-1.2 0 .1 1.4 1 2.6.7 1.3.5 5.4.5 5.4l-.2 1q-.2.9.3 1.2.3.2 1.3-1.1c.8-1 2.3-3.5 2.3-3.5l1.6.3c1.3.3 3.3.2 4.4-.1 1-.4.5-1.1-.2-1.3z"/>
<path fill="#d4af3a" d="M169.8 386.1q-.7-.1-1 .3l-.7 1.4q-.1.6.3 1l.7.6s.5.5 1 .7.5-.5.5-1l.3-2q-.1-.9-1-1z"/>
<path fill="#1d5e91" d="M378.6 345.8c-1.4-.3-2-.9-2-.9s-.5 0-1 .8-2.1 2-2.1 2-2.4.6-2.8 2.2.9 2.3 2 2c1.2-.1 4-.7 5.2-2.2 1.2-1.4 1.4-2.3 1.7-2.8.2-.6.3-.8-1-1.1m3.8-13.2c-1-3.7-3.3-8.3-7.9-10.6l-2.2 8c-.5 2-.5 1.9 1 2.2l7 1.7c1 .3 2.6 1 2-1.4zm-22-3.5c1.2.2 1-.2 1.4-1.7l2.3-8.7s-4.8-.2-9 1.8-6.1 5.8-6.1 5.8 1 .5 4 1.1zm-11.2 10-2.3-.5s1 4.2 2.8 6.5 3.8 3.4 7.5 3.5c3.7 0 6.5-2 7-3.6l1.2-2.8s-6.7-.9-9.5-1.5q-4.1-1.1-6.7-1.6"/>
<path fill="#d4af3a" d="m348 336.5 16.5 3.3q1.9.5 2.5.2c.3-.4.5-.6 1.7-1s1.1-1.7 1.1-1.7l.5-2.3c0-1.2.7-1.5 2 0 1.4 1.3 1.7 3.4 2 5.3.2 2 3.3 2.5 4.5 2.7s1.8-.2 2.5-1.3a16 16 0 0 0 1.3-5c.2-1.4 0-1.3-1.5-1.7l-9.9-2.3c-1.2-.3-1-1.1-.8-2l3-9.9a21 21 0 0 0-8.1-2.4s-2 9.2-2.5 10.6-1.3 1.4-2.7 1.2l-12-2.8-1 2a17 17 0 0 0-1.1 5.6c0 1.2.4 1.2 2 1.5"/>
<path fill="#d4af3a" d="M384.3 344.8c-1.4-.9-2.4-1.2-3.2.6-.7 1.7-.8 4.2-2.6 6s-4.4 3.6-7 3.4-4-.8-3.4-3.7 4.5-3.9 5.5-5.4a3.4 3.4 0 0 0-.7-4.5c-1.4-1.2-3.3-1.4-3.9-1a8 8 0 0 0-2.9 3.9c-.8 2.2-1.3 4-3 5.4a13 13 0 0 1-9.5 2c-3.4-.8-4.7-1.8-6-5.2s-2.7-9-3.4-9.6-1.6-1-3 0c-1.5 1-1.6 2.6-1.8 3.8s0 2.6 1.5 4.4c1.4 1.8 3 3.5 3.5 5.4.6 1.8 2.2 4.6-.1 4.7s-3.4.2-5.1-1.5c-1.8-1.7-8.7-6.4-10.6-8l-2.7-2q-4.8-.1-9.6-3.5s1.9 4.7 2.2 6.5q.5 2.6.3 2.7l9.7 5a177 177 0 0 1 11 6c2.7 1.8 5 4.3 9.7 3.3 4.8-1 14.5-3.9 17.6-4.8 3.1-1 11.7-3 14.9-5.3s3.5-2 4-4.2q.8-3.1-1.4-4.3zm-18.4-33 2.4-.3c1.6-.2 1 1.4.7 2q-.3 1-1.4 2.9c-.7 1.1.2 1.3.7 1.5l2.4.6c1.3.3 1-.6 1.1-1.1 0-.5.1-3 .3-4 0-1 1-.7 1.3-.5l1.8 1q1 .3 1-.4l.8-2.2c.3-1-.3-.8-1-.8h-2.6c-1 0-.4-1-.4-1l1.4-2.3c.6-1 .4-1.1-.2-1.3l-3-.7q-.8-.2-.8.3v2.9q.2 1-1 1.1c-1 0-1.5-.5-2.3-1.3s-1-.5-1.1-.2l-.8 3.3q-.2.9.7.5m5.2 23.3s-.1 1.8-.3 2.4c-.2.7-.6 1.6.1 1.9q1.2.6 2 .4c.4 0 .2-1 0-1.7a7 7 0 0 0-1.3-2.4zm11.2 7.3q.5.8 1.1.9.8.3 1-.6a3 3 0 0 0-.5-2.4c-.6-.7-.9-1.3-1.2-.2q-.7 1.7-.4 2.3m-39.1-7.4 1.5.4s0-1.7.3-3c.2-1.2.7-2 .3-2q-.6 0-1 .9c-.4.5-1.3.6-1.6 2.1-.3 1.4.2 1.5.5 1.6"/>
<circle cx="350.8" cy="331.9" r="2.5" fill="#b96b29"/>
<circle cx="357.8" cy="333.6" r="2.5" fill="#b96b29"/>
<circle cx="378.3" cy="338" r="2.5" fill="#b96b29"/>
<circle cx="364.9" cy="335.3" r="2.5" fill="#b96b29"/>
<circle cx="366.7" cy="329.2" r="2.5" fill="#b96b29"/>
<circle cx="368.5" cy="323.1" r="2.5" fill="#b96b29"/>
<circle cx="351" cy="331.7" r="1.2" fill="#d4af3a"/>
<circle cx="358" cy="333.4" r="1.3" fill="#d4af3a"/>
<circle cx="378.5" cy="337.7" r="1.3" fill="#d4af3a"/>
<circle cx="365.1" cy="335.1" r="1.3" fill="#d4af3a"/>
<circle cx="366.9" cy="328.9" r="1.3" fill="#d4af3a"/>
<circle cx="368.7" cy="322.8" r="1.3" fill="#d4af3a"/>
<path fill="#d4af3a" d="M287.5 383c-1.4-.8-2.5-1.7-5.6-3.8s-4.1-4.2-4.1-4.2h1q1-.2 1.2-1.7l-.3-4.4c-.2-2 .3-3.5.3-3.5s1.3 1.2 3.3 2.3 2.8.5 2.8.5l.5-2 2 4c1.3 2 4.5 4.4 6.9 6.2 2.3 1.7 4.9 3.6 6.8 4.2 2 .7.8 1.6.8 1.6s-2 2-6.9 2.8c-5 1-7.4-1-8.7-2"/>
<path fill="#d4af3a" d="M270 381.1c1.8-.2 3-.8 3.3-2.8.2-1.2-.1-6-.1-6l1.2 1.2c.7.9 2.2 1 2.2 1s.2.7 1 1.8a10 10 0 0 0 3.2 3.5l5 3.4a30 30 0 0 0 4.5 3.3 8 8 0 0 1 3.8 5q1 3.6-1.9 3.2c-2-.2-2.1 0-5.3-.8s-7.8-4.4-11-6.5c-3.4-2-5.8-6.3-5.8-6.3z"/>
<path fill="#d4af3a" d="M261.2 384s1.4-1.7 1.9-3.6l1.4-5.8 1.5 3.5c1.1 2.3 3 2.9 3 2.9s0 1 1.6 2.9a23 23 0 0 0 6 5c2.3 1.4 5.3 3.3 6.9 5.6s1.8 4.7 1 5.7-1.8-.2-3.4-1c-1.5-.7-5.9-1.4-11.9-4.6s-8-10.6-8-10.6"/>
<path fill="#d4af3a" d="M258.6 397.5c-1.6-2.5-1.9-8.5-1.9-8.5l1.4-1c.8-.8 2.4-3.1 2.4-3.1l2 4c1.1 1.9 1.6 2.6 3.9 4.6 2.2 2.1 5.3 4.1 6.6 6.3s.6 6.7-.3 8.1c-.8 1.5-2 1-3.3-.2l-3.8-3.4c-2.3-1.9-5.3-4.3-7-6.8"/>
<path fill="#b96b29" d="M278.4 347c-1-1.8-1.9-4-2.7-5l-1.4-2.5s2.2 2 3 3.4a15 15 0 0 1 1.8 4.2q.5 2.4-.7 0zm-8.5 1.6-.6-2s-.3-1.2-.1-1.3q.5 0 1.7 2.7c.6 2 1.5 4.8 1.3 5-.2 0-2-3.2-2.3-4.4M263 354l-.4-1s-.6-2.1-.6-2.6.2-1 .7.2q.8 1.8.8 2.7c.1.5.8 2.2.6 2.4s-.7-.9-1-1.7zm20.9 20.4.9-.5 1.3 1.5q1.3 1 2.2 2a9 9 0 0 0 2.9 2.4q2 1 1.6 1.1c-.2.3-1.2-.3-1.2-.3s-.4 0-2-1-2.1-1.6-3.2-2.5zm-7.3 8.7c-.6-.7-1.3-1.2-1-1.5q.6-.6 1.5.1l3 2.8 2.1 1.7c.8.6 2.4 1.5 3.2 1.9.9.5.1.5.1.5l-1.3-.5-2.6-1.1-1.8-1.1zm-8.4 5.8c-.5-1.1 0-.8 1-.4.9.3 2.9 2.5 4 3.3l3.2 1.7c1.4.7 1 .7 1 1q-.2.3-1 0l-1.7-1-1.1-.2q-.8-.1-2.6-1.7-1.8-1.3-2.8-2.7m-3.9 7.7c1.5.9 4 2.9 4.7 4.2q1.2 2.1 1 2.6c-.3.2-1-.3-1.3-.8l-1-1.4s-2.6-2.5-3.5-3a9 9 0 0 1-2.8-3.3c-.4-1-.1-1.5-.1-1.5s1.6 2.3 3 3.2"/>
<path fill="#c52126" d="M304 181.3a24 24 0 0 1 19-1.6q3.3 1 6 .2a8 8 0 0 0 5.6-6.3s2.6 3.3 0 6.8a8 8 0 0 1-4.6 3.2c-5.4 1-10.8-2.3-15.3-2.6-4.3-.2-7.7 2.5-7.7 2.5s-1 .9-2.5 0q-2.4-1.2-.5-2.3z"/>
<path fill="#d4af3a" d="m319.6 338.7 1.3-.2c.8-.1 2.4-.6 2.8-.9q1-.4 1.7.3c.5.5 4.4 2.9 4.4 2.9h-6.4c-2.3 0-3.8-2.2-3.8-2.2z"/>
<path fill="#d4af3a" d="M301.4 337.6v-.7l.9-1.8s1 .6 2 1.6c1.2 1.3 2.6 3.2 3.2 4 1 1.3 2.6 2.6 1.3.4s-1.7-3.2-2.8-4.6l-1.7-2.2 3.7-.6c2.7-.3 4.4-1.4 5.6-2.1l3.5-2s4.6 2 6.4 2.4c1.7.5 2.7.7 1 1.5-1.6.9-3 1.1-3.9 1.6a11 11 0 0 1-4.9 1.4c-1.5 0-4.2 0-3.1 1q1.6 1.8 3.3 6.4a22 22 0 0 1 1.2 7.4l-.2 2.7s-2-2.1-7-5.3-7-4.3-8-4.7-1.4-.4-1.2-1.6z"/>
<path fill="#d4af3a" d="m282 322.1 1-.4h.2c.6.4 3.7 2.4 5 4.5 1.2 2 2.4 2.2 1 0a19 19 0 0 0-3.4-4.4l-1.1-1q3.8-1.7 7.8-4.5c.4.7 1 2 1.8 2.7 1 1.1 3.4 2.1 3.4 2.1s-1.9-2-2.5-3.5q-.7-1.6-.9-2.6a34 34 0 0 0 5.2-4.9 19 19 0 0 0 4.4 7.9c4 4.5 12 6.7 12 6.7s2.8.3.5 1c-2.3.5-3.9 1.5-8.3.8-4.4-.8-4.7-1-5.3-1.2s-2.2 0 0 .8 7.3 1.6 9.3 1.4c2-.1 4.7-.6 1.8 1-2.8 1.4-4 2-5.7 2s-2.4.6-4.1.6-2.1-.3-3.3-.6q-1.9-.2-2 .7c-.1.9 1.6 1.8 1.5 5a28 28 0 0 1-.6 6.4c-.3 1-1 2.5-1.5 3.4-.4 1-.6 1.8-1 0-.6-2-1.6-4.7-2-6.6-.5-1.8-.7-1.9-.9-2.9s-1.2-1.6-.7.1l1.4 5.5c.3 1.5 1.2 4.4-.3 2.1-1.4-2.2-6.8-8.3-7.7-9.3q-1.3-1.6-2.2-3c-.7-.9-2.5-2-3.4-3.4a30 30 0 0 0-4.2-4.3zm74.2-137.7c-.2 3.3-3.8 9.6-5.9 13-2 3.3-2.6 4.6-2.3 4.8s1.2-1.5 2.4-3 3.3-5 5.2-7.6c1.8-2.6 4.5-9 5-9.5.3-.6.4-1 1.3-.2 1 .7 2.8 7.6.6 12.3s-5.3 8.2-6.7 9.8-3.1 4.2-2.9 4.5.8-.5 2.5-2.2l6.1-6.8c1.4-1.7 3.4-5.2 4.1-6.5q.5-.7.8-.1c.7.6 1.6 2 1.2 5.7-.6 5.2-3.3 8.2-5.7 10.9-2.5 2.6-4.9 4.8-4.5 5.2.3.3 2.8-1.9 4.5-3.5s6-5.7 6.9-6.9c1-1.1 2.3-.6 2.2 4 0 4.4-5 9-7.1 11.5s-4.7 4-4.5 4.5 2.3-.8 3.7-1.7c1.3-1 6.4-4.2 7.4-5 1-.6 1.5.7.2 5s-5 7.7-7.2 9.3-5.8 3.5-5.6 4q.5.6 3.8-1.1c2-1 4.6-2 6.4-2.5s1.8.8 1.8.8.3 3.7-2.3 6.6a14 14 0 0 1-8.5 4.6c-2.9.5-3.3.6-3.2 1q0 .6 1 .5c.6 0 3.3.3 5.7.3s3.7.6 3.7 1.7c0 1 0 2.5-3.6 4.9s-7.7 2.8-9.4 3.1-1.8.5-1.4 1c.3.5 1.1.5 3.8.8 2.7.2 4.4 1.3 4.7 2 .4.8-.2 2.9-2.4 4.4s-5 2-9.3 1.7-5.4-.3-5.5.4c-.2.7 1.3.9 3.4 1.3 2.1.3 3.8.3 5 1.3s.3 3-1.8 4.6c-2 1.5-7.2 1.5-9.3 1.3s-5.5-.9-5.7-.3 1.6 1.4 3.8 2.2 2.8 1.3 3.3 2.2 0 1.8-2.6 2.8-6.5 1-8.5 0q-2.9-1.3-3.4-.8t.4 1.2q1.1 1.4 4.4 2.4c2.2.6 2.4.6 3.2 2.4s-1.2 3.2-5.2 3.3a25 25 0 0 1-11-2.4c-1.8-1-2.4-1.2-2.7-.9q-.5.5.6 1.2c.9.7 3.6 2.6 5 3s1.4 1.3 1.4 2.3.4 2.8-3.2 3.6-7.8.2-11.6-2.5a9 9 0 0 1-2.4-2.2c.3-3.7.2-6.2-.3-8.5q1.3 0 3.7-.9c2.1-.8 3-2.8 3.5-4q.8-1.3 2-.7 1.4.6 3 .6a8 8 0 0 0 5.6-3c1.9-2.2 1.5-4.3 1.6-5.4 0-1 1.8-.3 2.6-.3s3.4-.3 5.7-1.9 2.3-3.7 2.5-4.6 1.1-1.4 1.8-1.7 1.9-.6 3.4-1.8c1.6-1.3 2.2-3.8 2.3-4.7 0-.8 1-1 4.2-2.6s2.9-5 2.8-6.4-1.7-2.5-1.7-3 1-.6 2.2-1.3c1-.6 3.7-1.7 3.8-5.7s-2.6-4.4-2.6-4.4l1.6-.9c1.1-.6 4-2.6 4-5s-1-3.4-1.8-4-3-1.1-3-1.1 1.4-1 2-2.8c.5-1.8.7-4.1-.6-5.8-1.4-1.6-3.6-1.6-4.9-1.6s-2.2.7-2.7.3-.5-.6 0-1.6.5-3.2 0-4c-.3-.8-.3-2.3-3.4-3.3-3-1-6.3 1-7.3 1.6s-.6-.8-.6-1.8 2.1-3.5 4.5-7a79 79 0 0 0 10.7-25.1c.4-1.8 1.1-1 1.1-1s.7.3 2.4 4.5a27 27 0 0 1 1.8 11.2"/>
<path fill="#d4af3a" d="M302.3 257.5a8 8 0 0 0 6-3.8c2-2.7 4.7-3.3 9.5-3.2s7-2.2 8.1-5.5c1.2-3.4-.1-7.1-5-9.5s-7.1-5.1-7.3-9.2c-.2-4.2 4.9-9.3 10-15.1s9-14 9-14 1.4 1.9 1.4 3.8c0 2-.7 4 0 4.5.8.6 1-.8 4-2 3-1.4 5.3-1.5 7.2.6s0 5.8-1.7 7.5-3 3-2.6 3.7c.5.7 3-1 3.8-1.6.8-.5 2.8-2.6 5.6-2.4 2.9.3 3.9 1.1 4.1 3.5.3 2.4-2.5 4.6-4.4 5.5q-2.7 1.4-2 2c.4.5.8 0 1.7-.2s3-.5 4.6 0c1.4.6 3.8 2.6 1.6 5-2.2 2.6-6.8 3.5-7.7 3.7s-1.4-.1-1.5.6c0 .8 2 .8 4.4.9s3.2 2.4 2.9 4.3-4.5 3.8-6.8 4.2-3.1 0-3.3.7q-.4.8 1.5 1.2c1.9.4 3.8.7 4.3 2.7s.5 3-1.4 4.7c-2 1.8-5 1.5-6 1.3s-2-1.2-3-.3c-.9 1 .9 1.7 2.5 2.8 1.5 1 1.4 3.2-1.2 4.7a8 8 0 0 1-6.5.5c-1-.3-2.6-2-3.3-1-.7 1.1 2.3 1.5 3.6 3 1.3 1.6.8 4.2-1.8 5.8-2.5 1.5-6.8.4-7.5-.2q-1.2-1.2-2.2-.4c-.5.6.3 2 .8 3.3s1.6 5-2.3 6.6c-3.8 1.4-7.3-1.9-8-2.5q-1-1-1.8-.5-.7.5.2 1.5a4 4 0 0 1-1.3 5.3 7 7 0 0 1-5 1q-1-3-2.1-7.6h.5c.4 0 .5.5.5.7q-.1.4.2.4t.8.6q.8.6 1.2.5c.3-.2-1-.8-1.3-1.2s-1-1-1-1.5-.3-.7-1-1.3l-.4-.5-1.3-7.7-.5-5.9zM381 200c-4.1 8.3-10 13-10 13l1.2-3.5c.3-1.4 0-3 0-3l4.2-6c2.7-4.2 4.1-10.3 4.1-10.3s-2.5 6.1-4.4 9.3-4.2 6-4.2 6-.8-3-1.4-3q-.8-.2-1.4.9-.9.7-1 .5l1.8-3 1.6-2.3c1.5-2.4 4.8-7 6.5-11.6s5.4-16.1 6-19.5c.7-3.4 1.3-1.6 2 1a31 31 0 0 1 1 11.3 57 57 0 0 1-6 20.2m-5.3 22.4-3.8 2.7.6-1.9.3-3 3-2.7c1.3-1.1 2.9-2.5 6-6.4 3.1-3.8.6-1.5-2 1.3a97 97 0 0 1-7.3 6.8v-1a3 3 0 0 0-.8-2c-.5-.6-.2-.6 2.5-2.7a73 73 0 0 0 18.7-26.1s1.6 9.5-4.2 20-11.5 13.9-13 15m-30.5 60c-3.1-1.2-2.3-4.3-2.3-4.4l3.8 1.3c1.8.7 6.2 2 8 2s1.7-.2 1.7-.4-1.3 0-3.8-.5-7-2.8-7.7-3.3q-1.2-.7.4-.7 1.9-.3 2.5-1c.5-.3 1.6.2 4.5.9a53 53 0 0 0 23 .8c.6-.2 1.4.2-.8 3.9s-10 5.7-15.3 5.6c-5.4 0-10.8-3-14-4.1zm14.3-7.6c-5.5 0-7.6-1.6-7.6-1.6s0-.3.8-1.4.6-3 .6-3l3.6.5q3.5.8 8 .2c4.5-.6 1.7-.9-.7-.6s-6.9-.6-8.3-1c-1.5-.6-.9-1 .1-1.4s3.7-2 3.7-2 6.7.8 13 .1 10.2-2.3 11.5-2.5c1.2-.2 1.2.3 1.2.3s.3.6-1.8 4a18 18 0 0 1-10 6.6 54 54 0 0 1-14 1.8zm1.5-13 .5-1.4c.4-1.2-.6-2-.6-2s1.3-.4 5.4-1c4.2-.4 4.4-.8 7-1.3s4.2-1.3 4.1-1.6q0-.3-2.3.7c-1.5.5-7.9 1.2-10.6 1.6q-3.9.6-4.6.4c-.5-.3-2.1-.7-2.1-.7l2.5-.6a9 9 0 0 0 3.4-1.4c.8-.5 1-.6 4.4-1s6.1-1.5 12.2-3.7 10.6-4.8 11.9-5.8c1.2-1 1.1-.3.8 1-.4 1.2-.3 2.8-3.4 6.4-3 3.6-4.5 5.1-12.3 8s-16.3 2.4-16.3 2.4m22.8-18.8a43 43 0 0 1-16.5 6.8c-.4-.4.4-2 0-3-.4-1.2-1.1-1.2-2.8-1.3-1.6 0-.6-.4-.2-.4s.5 0 3.2-.8c2.7-.7 5.5-1 9.3-2.5 3.7-1.4 4.9-2.5 4.8-2.7s-1.8.9-5.2 2.2-7.6 1.8-9.8 2.3-.3-.5.8-1.1c1-.6 2.5-2.9 2.5-2.9s2.4-.4 6.4-1.6q5.8-1.7 10.7-4.5 1.7-1 3.4-2.3l5.5-4c1.4-1 1-.2.8.4s-1 3.5-3.2 6.6-2.9 4-9.7 8.8m1.1-13.5c-6.7 5.3-12.5 7-13.5 7.4s-.9-.1-.7-.7.3-2.4.3-2.4l5.1-3c2.7-1.5 5.7-3.6 7.6-5 2-1.3.8-1.2.2-.7s-3.3 2-6 3.8l-7 4.1s0-.9-.6-1.4c-.5-.6-2-.4-2-.4l1.2-1.4c.4-.7 2.6-1.4 5.1-2.6a62 62 0 0 0 10.3-7.2c3.3-2.8 9.7-9.8 10-10.3q.8-.9.8.2c0 1.1.3 1.2-.4 4.4s-3.7 9.9-10.4 15.2M361 179.3l-2.2 3.8-1.4 2.5q-.2 0 0-1.5v-3.7l-.3-2.4q.1-1.4.5-2l1.6-7.7c.5-2.7 1-6.7 1-10.2s-.6-1.7-.6 0-.2 4.3-.7 8.3-2.2 10-2.2 10-.1-.9-.7-2.2q-.8-2.1-2-4.5c-1.2-2.4-.4-2-.4-2s2.4-11.3 3-16.6 1.6-19.4 1.6-19.4c3.5 3.5 6 12.6 6.5 21.3.4 6.5-.7 12.5-1 15q-.8 7.2-2.7 11.3m7.7 17.8q0-4-2.4-5s1.5-2.6 2.7-6.3a35 35 0 0 0 2-8.2c1-6 1.6-12.3-.2-2a44 44 0 0 1-4 13.8l-2.6 4.3c.4-2 .5-3.2.4-5.3a34 34 0 0 0-1-7s3.2-6.3 5.2-13.9a88 88 0 0 0 3.4-24.1s3.2 2.4 4.3 14.8a74 74 0 0 1-3.8 28.8c-1.6 4.5-4 10-4 10zm-35.5 94.5 2-1.3c1.6-1 1.1-4 1.1-4l5.5 3.4 3.3 1.3c1 .3.7 0-.1-.5s-1-.8-3.1-1.6c-2-.8-6.2-4.4-6.2-4.4l2.7-.1c1.7-.1 3.8-1 3.8-1s1.7 1.6 8.5 4.5c6.9 3 12.7 3.7 12.7 3.7s-.8 3.5-4 4.7c-2.8 1.1-6.5 1.9-13.8.1a47 47 0 0 1-12.4-4.8m-9 7c-.5-2.9 1.1-4.9 1.1-4.9l1.4 1.1c1 1 2.5 2.7 5.4 4.1 2.8 1.5 3.9 1.4 1.1-.1s-6.8-5.7-6.8-5.7l1-.4c1.1-.4 3 .3 10.7 4.9a29 29 0 0 0 12.2 4.8s-3.5 4.1-12.8 3.8-12.7-4.7-13.3-7.6m-17.6-3.4s1 1.5 2.4 2.4c1.4 1 5 1.5 5 1.5l1 1.3c.7 1 2.3 3.2 3.9 4.3 1.6 1.2 4.2 2 4.4 1.7.1-.3-1.5-1-3.1-2s-3-2.7-4.1-4 .4-1 .4-1h3.8c1.8-.2 1.4 0 2 .8q.6 1.1 2.5 3.2l4.7 5.4c1 1.3.3 1.6.3 1.6s-.5.8-4.7 1.3c-2.5.2-5.3 0-8.2-1.8a25 25 0 0 1-5.6-4.8c-5-5.4-4.7-9.9-4.7-9.9m-2.2 11.3 1.6 1.9s-.7-2.2-1.4-3.3l-.9-1.4a28 28 0 0 0 1.7-5c.4 1.5 1.8 5.8 3.6 8.6 2.2 3.5 4 4.7 2.8 5.6-1.2 1-3.6 1.2-6.3-.2s-3.4-3.5-3.8-5.3l1.3-2.3q.5.3 1.4 1.4"/>
<ellipse cx="-305" cy="169.2" fill="#d4af3a" rx="1.9" ry="1.8" transform="scale(-1 1)"/>
<path fill="#d4af3a" d="M309 165.9c-1.7 0-2.7-.9-4.6-.7a28 28 0 0 0-9 3.6 16 16 0 0 1-10.5.9q-1.5-.6-3-1.5c-4.6-2.5-3.5-7.6-3.5-7.6a18 18 0 0 0 11.3 3.5l-1 .8c-.6.7-1.8 1.5-1.4 1.8s2-1.3 3.4-2.3a21 21 0 0 1 7-3.4c3.5-1 7.4-1.1 10 .3 2.7 1.5 3 3.3 2.6 4q-.3.7-1.3.6m-49.3 37c.8-.2 2.2-.5 4-2.2a78 78 0 0 0 6.8-7.3q.9-1.5-1-2.3c-1.2-.5-2.1-2-2.1-2s2.7-1.1 4.5-2.4c1.9-1.4 6.1-5.2 6.7-6.1.6-1 .3-1.1-.6-1.4s-1-1-1-1 1.9-1.1 3.7-2.6l4.3-4c2.8 1.2 7 .7 9.4.3 4.1-.7 7.1-2.4 7.1-2.4l.7 1.9c.5 1.3 2.4 2 4.3.7 1.9-1.2 1.4-4 1.4-4s1.6-.9 4.7-2q4.6-1.9 8.3-.2c2.5 1.2 3.8 4.7 3.8 7.3 0 2.7-1.4 1.6-1.7 1.2s-.9-2.3-4.1-2.8-6.1 1-9.8 4-4.5 3.3-6.3 5.2-.4 3 2.8 4 7.2-1 7.3-1c.6.3-1.4 3.1-4 4.2-2.8 1-6.3.3-9-.7-1.8-.8-2.1 0-2.6.5-3 3.2-3.8 6-4.3 9.7a4 4 0 0 1-2.8-3.3c0-.6-.3-1.9-1.3-1s-1.8 6.3-1.8 8.7c0 2.5.7 5.7.7 5.7l-.7-.1q-.7-.2-2.5-1.2c-1.2-.7-1.3 0-1.3 1.4s-.4 3.8-2.2 8.3c-1.7 4.4-4.3 5.9-4.3 5.9s-.5-.9-1-2.7c-.5-1.7-.9-5.2-.9-8.2s.8-9.4.8-9.4-3.6 4.4-7.4 5.5-7.6.5-9.2-1.4-.2-2.6.6-2.8"/>
<path fill="#d4af3a" d="M284.8 214.5s1.1 2.5 1.7 3.4c.7 1 1 1 1 1s-1.2 1-2.9 1.6l-3.2.8s2-2.6 2.6-4.4zm-22.9-1.5.9-2.3a16 16 0 0 0 8.7-1.8s-1.8 3.6-3.5 4.8c-1.8 1.3-2 1.3-2 1.3s1.7.3 4.1-2 3.4-5 3.4-5-.5 6.2.4 10l1.2 4.2s-5 1-10.5-.6-6-2-6-2-.7-.2.2-1.4a30 30 0 0 0 3.1-5.2"/>
<path fill="#b96b29" d="m272 199.4 1.8-2.4s.6.6.1 1.4c-.5.9-3 3-4.6 4a13 13 0 0 1-3.3 1.2v-.3s4.2-2 6-3.9m6.7 12.9.4-9c0-1 .7-.8.7-.8l.9.4-1.7 11.3c-.1 1.2-.7 1.1-1 1 .6-.2.7-2.6.7-3zm10.4-33.6c.7-.6 2.1-1 .7.5-1.3 1.5-3.1 3.4-3.7 5-.5 1.6-.8 3.5 0 3 1-.3 1.6-.3 2.6-1.1s2.7-2.1 3.5-2.3c.7-.3 2 0 1 1.1a26 26 0 0 1-4.3 3.7l-4.2 2.9-2 1.4s.9-6.4 2.6-9.1a28 28 0 0 1 3.8-5zm34.2 105.9c1.3 1 3 1.4 3 1.4s.7 0 .7.2-.9 0-1.9-.2c-1-.1-2.3-1.1-2.7-1.5s-1.2-.8-1-1.4.6.5 1.9 1.5m-11 5.9 2.4 1.9 1.3.7 1 .7h-1c-.8-.1-3-1.8-3.6-2.5q-1.1-.8-.8-1 .4-.4.7.2M357 211q-.8 1-1.1 1-.4-.3.5-1.2l.9-.9s.7-1.2 1.1-1.6 1.1-.7.3.3l-1.8 2.4zm3.3 7.4L359 220q-.8 1.1-1.2 1c-.3-.4.8-1 1.2-1.7l1.5-1.5 1.4-.9-1.5 1.7zm-1.2 12c-.9 1-2.1 1.2-2.3.8q-.3-.4.8-1a24 24 0 0 0 4-2.7q.6-.7 1-.6c.1.1-1.2 1.5-1.6 1.8l-2 1.7zm-2.5 9.7q-.2-.6.7-.6l1.6-.2s1.4-.5 1.5-.3-1.1.8-1.7 1q-.9 0-1.5.4-.5.2-.6-.3m-1 10.4c1.5 0 2.8-.4 2.9-.1q-.1.3-1.5.8c-.8.3-2.2.4-3.1.4q-1.4 0-1.1-.7c0-.4 1.3-.4 2.8-.4M343.8 262q.4-.2 1.6.2c.9.2 2.2.4 3 .4l2.5-.1 1 .2q-.2.2-3.1.4c-1.9.2-3.1-.2-4-.3q-1.3-.3-1-.8m-4.9 8.2 2.4.4 2.3.3s.8.1.7.4-.4 0-1 0h-2.6l-2.7-.6c-.7-.1-1.6-.5-1.2-1s1.2.1 2.1.5m-9.4 6.1 3.7 2.7q1 .5.7.8c-.2.2-.7-.3-1.1-.5l-2.7-1.8c-.7-.6-1.7-1.1-1.5-1.6q.1-.4.9.5zm15.7-79.7-1.8 2.4c-1.6 2-.7.2-.3-.4l3.6-4.8c.8-1 1-.5.5.1zm3.5 10.5c-.3-.3.3-.5 1.2-1.7l2.8-3.5s.5-1.1.7-1-.6 1.9-1.4 2.6-1.7 2.2-2.3 2.9q-.7 1-1 .7m-4.6 19.7c0-.6 1.9-.5 2.7-.7l2.4-.5s1.7-.3 1.8 0q0 .3-1.4.5-1.7.5-3.5.8c-1 .2-2 .4-2-.1m4.6-10.7q-1.8 1.4-2.7 1.8c-.7.4-1.2 1-1.5.5q-.4-.5 1.3-1.2l1.6-.8 1.1-.6c.5-.3 1.4-.7.2.3m-10.6-7 1.4-1s1-.8 1.1-.5-1 1.1-1.6 1.6-1.6 2-2.2 1.8c-.5-.3.6-1.2 1.3-1.9m7 27.5 1.6.4q1.2.4-.5.5c-1.7.1-1.7-.3-2.9-.5q-1.7-.3-1.4-.8t1.3-.1zm-2 9.9c.1.2-.8 0-1.4-.2s-1.9-1-2.7-1.1q-.9-.3-.7-.8c0-.5.8-.1 1.8.2s2.2 1.3 2.2 1.3.8.4.9.6zm-12.7 6q-1.3-.8-.8-1.2.4-.5 1.3.4l2 1.5 1.3.6c.5.3 1.2.7 1 1-.1.2-1.2 0-1.8-.6zm-6 8-2-1c-.4-.4-.7-1.4-.3-1.6.3-.1.6.5 1.4 1 .8.7 3.7 2.6 3.7 2.6l.8.3c.8.3.4.6-.2.5q-1 0-2-.7zm-9 7.6c-.7-.3-1.8-1.3-2.4-1.8s-1.2-1.1-.8-1.4q.6-.4 1.5.6l2.2 2.3s.3 0 1.1.8c1 .7 0 .6-.3.3s-.5-.5-1.3-.8"/>
<path fill="#d4af3a" d="m279 154.5-3.6-2.5 4.3-1.1 2.7 2.2z"/>
<ellipse cx="-267.5" cy="151.6" fill="#b96b29" rx="3.4" ry="3.3" transform="scale(-1 1)"/>
<ellipse cx="-267.5" cy="150.8" fill="#d4af3a" rx="2.1" ry="2" transform="scale(-1 1)"/>
<path fill="#d4af3a" d="M274.7 140.2c-1 .3-2 .2-2 .2s-.4-1.6.4-2.3l2.1-1.8.6-.6.1 2.1c0 .8-.3 2-1.2 2.4"/>
<circle cx="-272.8" cy="141.8" r=".6" fill="#d4af3a" transform="scale(-1 1)"/>
<path fill="#d4af3a" d="m277.5 141.2.9 1s-.7 0-1.3.4q-1 .7-2 .7a1 1 0 0 1-.8-1.2q0-.8 1.6-1.3c1-.4 1.4 0 1.6.4"/>
<path fill="#d4af3a" d="M275.1 145.2c2.2.2 5-2.2 5-2.2q.5 3 3.3 3.3h-.2s-1.7 1-3.7 1.2q-1.3.2-2.6-.2a11 11 0 0 1-3.2-1c-1.3-.8-1-2.9-1-2.9s.3 1.6 2.4 1.8m8.4-2.1q1.7-.8 2.8-1c.5 0 1.3-.2 1.2.8s-1.2 1.5-2.2 1.6q-1.4-.1-2.2-.7-1-.4.4-.7m6.8-3.7q1.7-1 1.8-.9c.1.1.6 1.7.3 2.7s-1.1 1.3-2 1.3c-1 0-2.3-.5-2-1.2q.6-1 1.9-2z"/>
<ellipse cx="-289.4" cy="144.1" fill="#d4af3a" rx=".8" ry=".5" transform="scale(-1 1)"/>
<path fill="#d4af3a" d="M287.3 135.8c.6-2.9.5-6-2.2-9.9s-7.3-5.5-7.3-5.5l-1.7-1.9a33 33 0 0 0-4.5-3.6l5.5 1.5v.1a2.4 2.4 0 0 0 2.4 2.5 2 2 0 0 0 1.4-.4c1.1.2 4.7 2.3 5.7 3.1l-.4 1.3a2.4 2.4 0 0 0 2.4 2.5l1.1-.3.3.5 1.8 4a3 3 0 0 0-1 2.1c0 1.4.8 2.5 2 2.5v1.6q.2 1.2-1.8 1.7c-1.4.4-3.3 2.8-3.3 2.8-.1 0-1-1.8-.4-4.6"/>
<path fill="#d4af3a" d="M278.8 117.6q-.8-.7-.2-1.4.7-.5 1.6.1c.9.6.6 1 .2 1.4q-.7.5-1.6-.1m9 6.1q-1-.9-.2-1.8.8-.7 1.8.2 1 1 .2 1.7-.7.7-1.8 0z"/>
<circle cx="-293.2" cy="131.4" r="1.4" fill="#d4af3a" transform="scale(-1 1)"/>
<path fill="#d4af3a" d="M263 112q1.2.2 4.1 1.7c-1.4 0-2.5.9-2.5 2s1.3 2.4 2.7 2.4 2.3-1.2 2.3-2.3q0-.5-.2-.8l2 1.2c4.4 3 5.4 4.5 7.6 8.5s3 8.6 2 11.2c-.9 2.7-4.4 3.2-4.4 3.2s.4-.4.4-.9l-.2-1.7c-.2-1 0-2.2 0-2.2s-.9-.1-1.3.4l-1.6 1.8-1.6 1.6s-.7-1-.7-2.2.8-2.5 1-4.6-1-5.8-3-8.6a24 24 0 0 0-7-5.7 2 2 0 0 1-1.5-2l-.2-2c-.1-1.3 1-1.2 2.2-1z"/>
<path fill="#d4af3a" d="M267.5 116.8q-1.4-.2-1.5-1.4.1-1 1.4-1.1 1.3.1 1.4 1.1 0 1.2-1.3 1.4m-6.6 26a3 3 0 0 1-2.8-.2q-1-.8-.1-1.9a2 2 0 0 1 2.3-.2l2 1.4s-.3.5-1.4.9"/>
<path fill="#d4af3a" d="M257.5 144c.4.6.6 1 1.8 1s2.5 0 3.3-.8l1.3-1.9h1.3s.5 1.9 1 2.4c.7.5 2.7.6 3.6 0 1-.8 1.7-1.6 1.9-1.5q.3.3-1 1.6c-1.3 1.3-1.5 1.3-3 1.3h-8.5s-1.7.1-2.2-1q-.7-1.5-.3-1.9.2-.2.8.8"/>
<path fill="#d4af3a" d="M270.4 142.6c-1.3.7-2 .2-2.4-.3l-.6-.9s1.2-.4 1.8-.8q.8-.5 1.6-.6l.6.2s.3 1.6-1 2.4"/>
<circle cx="-276.6" cy="130" r="2.8" fill="#b96b29" transform="scale(-1 1)"/>
<path fill="#b96b29" d="M271.6 120.2a3 3 0 0 1 3.8.7c.9 1.2.7 2.7-.4 3.5a3 3 0 0 1-3.7-.7c-1-1.2-.8-2.7.3-3.5"/>
<circle cx="-276.7" cy="129.6" r="1.6" fill="#d4af3a" transform="scale(-1 1)"/>
<path fill="#d4af3a" d="M272.8 120.5q1.4-.2 2 .8.6 1.2-1 1.6c-1.8.3-2.6-2-1-2.4"/>
</svg>

After

Width:  |  Height:  |  Size: 56 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-mk" viewBox="0 0 512 512">
<path fill="#d20000" d="M0 0h512v512H0z"/>
<path fill="#ffe600" d="M0 0h86.8L256 246.9 425.2 0H512L0 512h86.8L256 265.1 425.2 512H512zm512 204.8v102.4L0 204.8v102.4zM204.8 0 256 219.4 307.2 0zm0 512L256 292.6 307.2 512z"/>
<circle cx="256" cy="256" r="82.3" fill="#ffe600" stroke="#d20000" stroke-width="18.3"/>
</svg>

After

Width:  |  Height:  |  Size: 407 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-nl" viewBox="0 0 512 512">
<path fill="#ae1c28" d="M0 0h512v170.7H0z"/>
<path fill="#fff" d="M0 170.7h512v170.6H0z"/>
<path fill="#21468b" d="M0 341.3h512V512H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 233 B

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-no" viewBox="0 0 512 512">
<path fill="#ed2939" d="M0 0h512v512H0z"/>
<path fill="#fff" d="M128 0h128v512H128z"/>
<path fill="#fff" d="M0 192h512v128H0z"/>
<path fill="#002664" d="M160 0h64v512h-64z"/>
<path fill="#002664" d="M0 224h512v64H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 318 B

+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-pl" viewBox="0 0 512 512">
<g fill-rule="evenodd">
<path fill="#fff" d="M512 512H0V0h512z"/>
<path fill="#dc143c" d="M512 512H0V256h512z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 219 B

+57
View File
@@ -0,0 +1,57 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="flag-icons-pt" viewBox="0 0 512 512">
<path fill="red" d="M204.8 0H512v512H204.7z"/>
<path fill="#060" d="M0 0h204.8v512H-.1z"/>
<g fill="#ff0" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width=".6">
<path stroke-width=".7" d="M293.8 326.6c-34.4-1-192-99.4-193-115.1l8.6-14.5C125 219.7 286.2 315.4 302 312z"/>
<path stroke-width=".7" d="M107.6 195c-3.1 8.3 41.1 35.6 94.3 68 53.2 32.3 99 52.3 102.5 49.5l1.5-2.9q-1 1.6-4.6.6c-14.4-4.2-51.9-21.4-98.3-49.5s-86.8-54.1-93-65.1a7 7 0 0 1-.7-3.3h-.2l-1.3 2.3zm187 132c-.6 1.1-1.7 1.1-3.7 1-12.9-1.5-52-20.5-98-48.1-53.8-32.2-98.2-61.5-93.3-69.1l1.3-2.4.2.1c-4.3 13 87.6 65.5 93 68.9 53.1 33 98 52.2 102 47.2z"/>
<path stroke-width=".7" d="M205 221c34.3-.3 76.8-4.7 101.2-14.4L301 198c-14.5 8-57.1 13.3-96.3 14-46.4-.4-79.1-4.7-95.5-15.7l-5 9.1c30.2 12.7 61 15.5 100.8 15.6"/>
<path stroke-width=".7" d="M307.7 206.8c-.9 1.3-16.8 6.8-40.3 10.8a416 416 0 0 1-62.6 4.6 444 444 0 0 1-60-3.8c-24.5-3.9-37.3-9.3-42-11.2l1.2-2.3a186 186 0 0 0 41.3 11 439 439 0 0 0 59.5 3.7 418 418 0 0 0 62.1-4.6c24-3.9 37.2-8.9 39-11.2zM303 198c-2.6 2-15.6 6.7-38.4 10.3a414 414 0 0 1-59.5 4.2 400 400 0 0 1-57.4-3.7c-23.3-3-35.6-8.5-40-10.1l1.3-2.3c3.4 1.8 15.4 6.6 39 10a423 423 0 0 0 57.1 3.5 409 409 0 0 0 59-4.2c23-3.2 35.4-9 37.3-10.5zM92 262.4c21.2 11.4 68.1 17.2 112.6 17.6 40.5 0 93.3-6.3 113-16.8l-.6-11.4c-6.1 9.7-62.6 19-112.8 18.6s-96.8-8.2-112.3-18.2v10.2"/>
<path stroke-width=".7" d="M318.7 260.8v2.7c-3 3.6-21.6 9-44.9 12.7a463 463 0 0 1-69.7 4.8c-27.4 0-49.2-2-66.2-4.6a165 165 0 0 1-47.3-12.7v-3.2c10.4 6.9 38.3 11.9 47.7 13.4 16.8 2.6 38.5 4.5 65.8 4.5 28.7 0 51.7-2 69.3-4.7 16.8-2.4 40.6-8.7 45.3-12.9m0-9.7v2.8c-3 3.5-21.6 8.9-44.9 12.6a463 463 0 0 1-69.7 4.8c-27.4 0-49.2-2-66.1-4.5A165 165 0 0 1 90.6 254v-3.2c10.4 6.9 38.3 12 47.7 13.4 16.9 2.6 38.6 4.6 65.8 4.6 28.7 0 51.7-2 69.3-4.8 16.8-2.4 40.6-8.7 45.3-12.9m-114.2 73.5c-48.6-.3-90.3-13.2-99.1-15.4l6.4 10c15.5 6.6 56.2 16.4 93.2 15.3s69.3-4 92-15l6.6-10.5c-15.5 7.3-68.3 15.6-99 15.6"/>
<path d="m299.5 317.1-3 4.4a259 259 0 0 1-34.7 8.9 315 315 0 0 1-57.2 5.2c-43.1-.6-78.4-9-95-16.2l-1.4-2.3.3-.4 2.2.9a306 306 0 0 0 94.1 15.5c20 .1 40-2.3 56.1-5.1 24.8-5 34.8-8.7 37.9-10.4zm5.7-9.4h.1l-2.2 3.8c-5.7 2-21.3 6.6-44 9.8-15 2-24.3 4-54 4.6a371 371 0 0 1-100.5-15l-1.2-2.5a424 424 0 0 0 101.7 15c27.2-.6 38.8-2.6 53.6-4.7 26.5-4 39.8-8.4 43.8-9.7l-.1-.2z"/>
<path stroke-width=".7" d="M305.8 253.4c.2 32-16.2 60.8-29.4 73.5a106 106 0 0 1-72.3 30c-32.3.6-62.7-20.5-70.9-29.7-16-18.1-29-41-29.4-72 2-35 15.7-59.3 35.6-76a106 106 0 0 1 68.4-24.2c25.4.7 55.2 13.2 75.7 38 13.4 16.2 19.3 33.8 22.3 60.5zM204.4 143.8c62 0 113 50.5 113 112.3a113 113 0 0 1-113 112.3c-62 0-112.6-50.4-112.6-112.3s50.6-112.3 112.6-112.3"/>
<path stroke-width=".7" d="M204.7 143.4c62 0 112.6 50.7 112.6 112.7s-50.6 112.7-112.6 112.7A113 113 0 0 1 92 256a113 113 0 0 1 112.7-112.7zM94.5 256.1c0 60.6 49.8 110.2 110.2 110.2s110.1-49.6 110.1-110.2S265.1 146 204.7 146A110.6 110.6 0 0 0 94.5 256.1"/>
<path stroke-width=".7" d="M204.8 152.8c56.5 0 103.1 46.5 103.1 103.2s-46.6 103.2-103.1 103.2A103.6 103.6 0 0 1 101.5 256c0-56.7 46.6-103.2 103.2-103.2zM104 256c0 55.4 45.5 100.7 100.8 100.7S305.5 311.4 305.5 256 260 155.3 204.7 155.3 104 200.6 104 256"/>
<path stroke-width=".7" d="M209.3 143h-9.7v226.4h9.7z"/>
<path stroke-width=".7" d="M208.3 141.7h2.5v229h-2.5zm-9.6 0h2.5v229h-2.5z"/>
<path stroke-width=".7" d="M317.4 260.5V252l-6.8-6.3-38.7-10.3-55.8-5.7-67 3.4-47.9 11.4-9.6 7.2v8.3l24.4-11 58-9h55.8l41 4.5 28.4 6.9z"/>
<path stroke-width=".7" d="M204.7 238.7a394 394 0 0 1 72.9 6.5c21.1 4.2 36 9.5 41 15.4v3c-6-7.4-26-12.8-41.5-16-20.3-3.9-46-6.4-72.4-6.4-28 0-54 2.7-74 6.6-16 3.2-37.4 9.5-40.1 15.8v-3c1.5-4.4 17.4-10.9 39.8-15.4a405 405 0 0 1 74.3-6.5m0-9.7a396 396 0 0 1 73 6.5c21 4.2 36 9.5 41 15.5v2.9c-6.1-7.4-26.2-12.8-41.6-15.9-20.3-4-46-6.5-72.4-6.5a402 402 0 0 0-73.8 6.6c-15.5 3-37.8 9.6-40.3 15.8v-3c1.5-4.3 17.8-11 39.8-15.3a405 405 0 0 1 74.3-6.6m-.5-49.3c41.9-.2 78.5 5.9 95.2 14.5l6.1 10.5c-14.5-7.8-54-16-101.3-14.7-38.5.2-79.6 4.2-100.3 15.2l7.3-12.2c17-8.8 57-13.2 93-13.3"/>
<path stroke-width=".7" d="M204.7 188.4c24 0 47 1.3 65.4 4.6 17.1 3.2 33.5 8 35.8 10.6l1.8 3.2c-5.7-3.7-19.8-7.9-38-11.3a367 367 0 0 0-65-4.5c-27 0-48 1.3-66 4.5-19 3.5-32.2 8.6-35.5 11l1.8-3.3c6.3-3.3 16.4-7.2 33.3-10.2 18.6-3.4 39.7-4.4 66.4-4.6m0-9.6a371 371 0 0 1 63.1 4.4c13.9 2.7 27.6 6.9 32.7 10.6l2.6 4.2c-4.5-5-21.4-9.7-36.4-12.3-17.4-3-39.1-4.2-62-4.4-24 0-46.2 1.5-63.4 4.6-16.4 3.2-27 6.9-31.5 9.8l2.3-3.6c6.2-3.2 16.2-6.2 28.8-8.7 17.3-3.1 39.7-4.6 63.8-4.6m56 124.1a293 293 0 0 0-56-4.2c-69.9.8-92.4 14.3-95.2 18.4l-5.2-8.5C122 295.7 160 288.5 205 289.2q35 .5 60.4 5.2l-4.8 8.5"/>
<path d="M204.3 297.5c19.4.3 38.5 1 57 4.5l-1.4 2.4a298 298 0 0 0-55.5-4.3c-25.8-.2-52 2.2-74.6 8.7-7.2 2-19 6.6-20.3 10.4l-1.3-2.2c.4-2.2 7.6-6.9 21-10.6 26-7.5 50.3-8.7 75-9zm.9-9.8a351 351 0 0 1 61.1 5.3l-1.4 2.5a319 319 0 0 0-59.6-5.2c-25.9 0-53.3 1.9-78.3 9.1-8 2.4-22 7.4-22.4 11.4l-1.3-2.3c.3-3.6 12.3-8.4 23.2-11.6a285 285 0 0 1 78.7-9.2"/>
<path stroke-width=".7" d="m304.4 309.9-8.4 13-24.1-21.4-62.6-42-70.5-38.8-36.7-12.5 7.8-14.5 2.7-1.4 22.8 5.7 75 38.7 43.3 27.3 36.3 26 14.8 17.1z"/>
<path stroke-width=".7" d="M100.8 208.5c6.5-4.3 53.7 16.7 103 46.5s96.4 63.6 92.2 70l-1.4 2.1-.7.5c.2 0 .9-1 0-3.3-2.2-6.9-35.5-33.5-91-67-54-32.2-99-51.6-103.5-46zm205.3 101.2c4-8-39.7-41-94-73.1-55.5-31.5-95.6-50-102.9-44.5l-1.6 3 .4-.5c1.3-1.1 3.5-1 4.5-1 12.6.1 48.6 16.6 99 45.6 22.1 12.8 93.4 58.6 93.1 71.4 0 1.1.1 1.3-.3 1.9z"/>
</g>
<g transform="translate(-68.3 28.4)scale(1.13778)">
<path fill="#fff" stroke="#000" stroke-width=".7" d="M180.6 211a59 59 0 0 0 17.5 41.7 59 59 0 0 0 41.8 17.6 59 59 0 0 0 42-17.4 59 59 0 0 0 17.4-41.8v-79.2l-118.7-.2z"/>
<path fill="red" stroke="#000" stroke-width=".5" d="M183 211.1a56 56 0 0 0 16.8 40 57 57 0 0 0 40.2 16.8 57 57 0 0 0 40.2-16.6 56 56 0 0 0 16.7-40v-77H183v76.8m91-53.7v48.9l-.1 5.1a33 33 0 0 1-10 24 34 34 0 0 1-24 10c-9.4 0-17.7-4-23.9-10.2a34 34 0 0 1-10-24v-54z"/>
<g id="pt-e">
<g id="pt-d" fill="#ff0" stroke="#000" stroke-width=".5">
<path stroke="none" d="M190.2 154.4c.1-5.5 4-6.8 4-6.8.1 0 4.3 1.4 4.3 6.9z"/>
<path d="m186.8 147.7-.7 6.3h4.2c0-5.2 4-6 4-6 .1 0 4 1.1 4.1 6h4.2l-.8-6.4zm-1 6.4h17q.5 0 .6.7 0 .8-.6.8h-17q-.5 0-.6-.8 0-.7.7-.7z"/>
<path d="M192 154c0-3.3 2.3-4.2 2.3-4.2s2.3 1 2.3 4.2H192m-5.8-9h16.3q.5.1.6.8 0 .5-.6.6h-16.3q-.5 0-.6-.7 0-.5.6-.6zm.4 1.5H202q.5 0 .6.7t-.6.7h-15.5q-.6 0-.6-.7t.6-.7zm5-10.6h1.2v.8h.9v-.8h1.3v.9h.9v-1h1.2v2q0 .6-.5.6h-4.4q-.5 0-.6-.5zm4.6 2.7.3 6.4h-4.3l.3-6.5h3.7"/>
<path id="pt-a" d="M191 141.6v3.4h-4v-3.4z"/>
<use xlink:href="#pt-a" width="100%" height="100%" x="10.6"/>
<path id="pt-b" d="M186.3 139h1.2v1h.9v-1h1.2v1h.9v-1h1.2v2q0 .6-.5.6h-4.3l-.6-.6z"/>
<use xlink:href="#pt-b" width="100%" height="100%" x="10.6"/>
<path fill="#000001" stroke="none" d="M193.9 140.6c0-.6.9-.6.9 0v1.6h-.9z"/>
<path id="pt-c" fill="#000001" stroke="none" d="M188.6 142.8c0-.6.8-.6.8 0v1.2h-.8z"/>
<use xlink:href="#pt-c" width="100%" height="100%" x="10.6"/>
</g>
<use xlink:href="#pt-d" width="100%" height="100%" y="46.3"/>
<use xlink:href="#pt-d" width="100%" height="100%" transform="rotate(-45.2 312.8 180)"/>
</g>
<use xlink:href="#pt-d" width="100%" height="100%" x="45.7"/>
<use xlink:href="#pt-e" width="100%" height="100%" transform="matrix(-1 0 0 1 479.8 0)"/>
<g id="pt-f" fill="#fff">
<path fill="#039" d="M232.6 202.4a8 8 0 0 0 2.2 5.7 7 7 0 0 0 5.3 2.4q3.2-.2 5.3-2.4a8 8 0 0 0 2.2-5.7v-10.8h-15z"/>
<circle cx="236.1" cy="195.7" r="1.5"/>
<circle cx="244.4" cy="195.7" r="1.5"/>
<circle cx="240.2" cy="199.7" r="1.5"/>
<circle cx="236.1" cy="203.9" r="1.5"/>
<circle cx="244.4" cy="203.9" r="1.5"/>
</g>
<use xlink:href="#pt-f" width="100%" height="100%" y="-26"/>
<use xlink:href="#pt-f" width="100%" height="100%" x="-20.8"/>
<use xlink:href="#pt-f" width="100%" height="100%" x="20.8"/>
<use xlink:href="#pt-f" width="100%" height="100%" y="25.8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.2 KiB

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-ro" viewBox="0 0 512 512">
<g fill-rule="evenodd" stroke-width="1pt">
<path fill="#00319c" d="M0 0h170.7v512H0z"/>
<path fill="#ffde00" d="M170.7 0h170.6v512H170.7z"/>
<path fill="#de2110" d="M341.3 0H512v512H341.3z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 302 B

+296
View File
@@ -0,0 +1,296 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="flag-icons-rs" viewBox="0 0 512 512">
<defs>
<clipPath id="rs-a">
<path d="M54.3 32h480v480h-480z"/>
</clipPath>
</defs>
<g clip-path="url(#rs-a)" transform="translate(-57.9 -34.1)scale(1.06667)">
<path fill="#fff" d="M-32 32h720v480H-32z"/>
<path fill="#0c4076" d="M-32 32h720v320H-32z"/>
<path fill="#c6363c" d="M-32 32h720v160H-32z"/>
<g transform="matrix(.53333 0 0 .53566 -32 31.8)">
<path fill="#21231e" d="M473.4 259.4v-.2h1v.2l-.5.5-.6-.6zm1 0v.5h-.5l.4-.6zm-93 5.2-1 .2.3-.6 4.2-.2 4-.3 4-.2 3.8-.3 4-.2 3.6-.3 3.7-.2 3.7-.2 3.5-.2h3.4l3.3-.3 3.2-.2 3.2-.2 3-.2h3l3-.2 3-.2 2.7-.2h2.8l2.7-.2 2.5-.2h2.5l2.4-.3h2.2l2.2-.2h2.2l2-.2h2l2-.2h5.3v1h-5.5l-1.8.2h-2l-2 .2h-2.2l-2.2.2-2.4.2h-2.4l-2.5.2-2.5.2H446l-2.8.3h-2.8l-3 .3-2.8.2h-3l-3 .3-3.3.2-3.3.2-3.3.2h-3.5l-3.5.3-3.6.2-3.5.3-3.8.2-3.8.2-4 .3-4 .2-4 .3-4.2.2.5-.6zm-1 .2-.3-.5h.7zm6.4 31-6.5-31 1-.2 6.5 31-.5.7zm.5.5h-.4l-.2-.4.5.3zm95-4-.2 1h.2-5.8l-3 .2h-3l-2.8.2h-3l-3 .2h-6l-3 .2h-3l-3 .2h-3l-3 .2h-3.2l-3 .2h-3l-3 .2h-3l-3 .2h-3l-3 .2h-3l-3 .2h-3l-3 .2h-3l-2.8.2h-5.8l-2.7.2h-2.7v-1h5.8l2.7-.2h5.8l3-.2h3l2.8-.2h3l3-.2h3l3-.2h3l3-.2h3l3-.2h3l3-.2h3.2l3-.2h3l3-.2h3l3-.2h3l3-.2h3l3-.2h3l2.8-.2h3l2.8-.2h.2zm-.2 0h.2zm94.5 3.4 1 .2-.5.3h-2.8l-2.8-.2h-8.8l-2.8-.2h-3l-3-.2H551l-3-.2h-3l-3-.2h-3l-3-.2h-3l-3-.2h-3l-3.2-.2h-3l-3-.2h-3l-3-.2h-3l-3-.2h-3l-3-.2h-3l-3-.2h-3l-3-.2H485l-3-.2.2-1h2.8l3 .2h3l2.8.2h3l3 .2h3l3 .2h3l3 .2h3l3 .2h3l3 .2h3l3 .2h3.2l3 .2h3l3 .2h3l3 .2h3l3 .2h3l3 .2h5.8l2.7.2h3l2.7.2h2.8l-.5.5zm1 .2v.3h-.5l.5-.4zm6.5-31.2-6.5 31h-1l6.5-31.2.6-.4zm-.4-.6h.5v.6zm-93.7-4.8h1l-.6-.5h5.4l2 .2h2l2 .2h2l2.4.2h2.4l2.4.3h5l2.6.3h2.7l3 .3 2.8.2h3l3 .3 3 .3 3.3.2 3.3.2 3.4.2h3.4l3.6.3 3.6.2 3.7.2 3.6.3 4 .2 3.8.3 4 .2 4 .3 4.2.2v1l-4.3-.2-4-.3-4-.2-4-.3-3.7-.2-3.8-.2-3.6-.3-3.6-.2-3.5-.2h-3.4l-3.3-.3-3.3-.2-3.2-.2-3-.2h-3l-3-.2-3-.2h-2.7l-2.6-.3h-2.6l-2.6-.3h-2.5l-2.4-.2-2.3-.2h-2.2l-2.2-.2h-2l-2-.2h-2l-1.8-.2h-3.3l-.5-.6zm.4.5h-.5v-.6l.4.5zm.5-.8v.2h-1v-.2l.3-.5.6.5zm-1 0v-.4h.3l-.4.4zm-8 .3.2-1h8.8l.3.2v.8h-.5v.2h-.3l-.2-1h.2v.7h.2-8.2zm-8.1.2v-1l-.2 1h-.4l-.2-.2-.3-.3v-.5l.2-.2h9.4v1h-8.8l.2-.2v-.8h-.2.4v1zm0-1v1l-.6-.5.5-.5zm-.6.5v-.5h.5l-.6.5z"/>
<path fill="#edb92e" d="M583.5 264.2q4.6-10 11.2-18.7-17.6 13.2-18.7-4-1.2-.2-2.6-.2-13.5 21-26.2-5.8-17.4 27.6-29.2-1-20 25-33.6.2v-2q.6.4-1 0l-.3-.3-1 .2-.8-.2-.2.4q-1.9.2-1 0v2q-13.8 24.6-33.7-.4-11.8 28.6-29.2 1-12.5 27-26 6-1.6 0-2.7.2-1.1 17-18.8 4c4.6 5.5 8 12 11.3 18.6q50.9-2.2 101.3-5 50.8 2.8 101.5 5z"/>
<path fill="#21231e" d="m595 246-.6-1 .7 1-.3.4-.4.5-.4.4-.5.6-.4.5-.3.6-.4.6-.4.6-.5.5-.3.6-.4.6-.4.4-.3.6-.3.6-.3.6-.4.6-.3.5-.3.6-.4.5-.3.6-.3.7-.4.6-.3.6-.3.5-.3.6-.2.8-.3.6-.4.6-.2.6-.3.6-.3.6-.3.6-1-.4.3-.6.3-.7.3-.6.2-.5.4-.6.3-.7.2-.6.3-.6.3-.6.4-.6.3-.6.3-.6.3-.6.5-.6.3-.6.4-.6.3-.6.4-.5.2-.5.4-.6.4-.7.3-.6.4-.5.4-.6.5-.6.4-.5.3-.6.4-.6.4-.6.5-.5.4-.6.4-.5.7.7zm-19.2-4 .3-1 .5.5v1l.2 1v1l.3.7.2.8.3.7.3.7.2.6.4.5.3.5.4.4.5.3.4.3.4.3.5.2h.4l.5.2h1.9l.7-.2.7-.2.8-.3.8-.3.8-.3 1-.5.8-.6 1-.5 1-.7 1-.7 1-.7 1-1 .7 1-1 .7-1 .8-1 .7-1 .6-1 .5-1 .5-1 .5-.8.4-1 .3-.7.3-.8.2h-.8l-.8.2h-2l-.7-.3-.5-.2-.6-.3-.5-.5-.6-.4-.5-.4-.5-.5-.3-.5-.4-.7-.3-.7-.2-.7-.3-.8-.2-1v-.8l-.2-1v-1l.2.3zm.3-1 .4.2v.3zm-2.2.6-.8-.6.4-.2h2v.2h.4l-.2 1h-1.2v-.2h-1.2l.4-.2zm-.8-.6v-.2h.4zm-25.3-5.2-1-.6h1l.8 1.7.8 1.4.8 1.5.8 1.2.8 1.2.8 1.2.8 1 .8 1 .8.8.8.8.8.7.7.5 1 .4.7.3.8.3.7.3h2.3l.8-.2.8-.2.8-.3.8-.4.8-.6.8-.6.8-.7.8-.6 1-1 .7-1 .8-1 .8-1 1-1.4.8.6-.8 1.3-1 1-.7 1.2-1 1-.7 1-1 .7-.8.6-.8.6-1 .6-.7.4-1 .4-.8.2-1 .2h-3l-1-.4-.7-.3-1-.5-.7-.5-1-.6-.7-.7-1-.8-.8-1-.8-1-.8-1-.8-1.2-.8-1.3-.8-1.3-.8-1.5-.8-1.6-.8-1.7h1zm-1-.6.6-.7.4.8h-1zm-28.3-.5-.8-.6 1 .2.6 1.7.7 1.5.7 1.5.8 1.4.7 1.3.8 1.2.8 1 .8 1 .8.7.8.7.8.6 1 .5.7.4.8.2 1 .2h2.5l1-.3.8-.2 1-.4.8-.6 1-.7 1-.6 1-1 1-1 1-1 1-1.2 1-1.3 1-1.6 1-1.5 1.2-1.8 1 .6-1.2 1.7-1 1.5-1.2 1.5-1 1.3-1 1.3-1 1.2-1.2 1-1 1-1 .8-1 .7-1 .6-1 .4-1 .4-1 .4h-3l-1-.2-1-.3-.8-.6-1-.5-.8-.8-1-.8-.7-.8-1-1-.8-1-.8-1.3-.8-1.4-.8-1.5-.8-1.5-.7-1.7-.8-1.7h1zm-.8-.6.5-.6.5.8h-1zm-33.8.7h1v-.2l.8 1.5 1 1.4.8 1.2 1 1.2.8 1 1 1 .8 1 1 .8.8.7 1 .6 1 .4 1 .4.8.3 1 .3 1 .2h2l1-.2 1-.3 1-.3 1.2-.4 1-.6 1.2-.6 1-.6 1.3-.8 1-1 1.3-1 1.2-1 1-1.3 1.4-1.3 1.2-1.4 1.2-1.5.8.7-1.3 1.5-1 1.5-1.3 1.3-1.2 1.3-1.2 1-1.2 1-1 1-1.3 1-1.2.7-1 .6-1.3.6-1 .5-1.3.3-1.2.3h-1l-1.2.2h-1l-1.2-.2-1-.2-1-.3-1-.4-1-.5-1-.7-1-.6-1-1-1-.8-1-1-1-1.2-.8-1.2-1-1.3-.8-1.5-1-1.5v-.3zm0 .3v-.3zm1-2.3v2h-1v-2l.8-.5.3.5zm-1 0v-.8l.8.2-.8.5zm-1 .3 1-.4-.4-.3h1l-.2.2v.4l.4-1h.2v.2l.2.2v.6h-1.8l-.5-.3zm.5.3h-.3v-.3zm.3-1 .2.3-1 .4v-.4l.2-.7.6.2zm-.6-.4.4-.2.2.4zm-1 1 .2-1h.8l.2 1h-1zm-.4-.4-1-.4.7-.3h.8v1h-1zm-1-.4.3-.4h.3zm0 .4v-.4l1 .4-.2.4-.4.3zm.8.4v.3h-.4zm-1-.3h-1l.7.4v.2h.2v-.8h-.2.2l.2-.2h.4l.2 1h-1.9v-.2h-.2v-.5h.2v-.2h.2l.8.4zm-.7-.5.7-.3v.7zm-.3 2.5v-2h1v2.3zm1 0v.2zm-33.6 0-1-.5h1l1 1.4 1.3 1.4 1.3 1.3 1.2 1.2 1.2 1 1.2 1.2 1 1 1.2.7 1 .7 1.2.7 1 .6 1.2.4 1 .3 1 .3h1l1 .2h1l1-.2 1-.2 1-.2 1-.4 1-.5 1-.7.8-.7 1-.8.8-1 1-1 .8-1 1-1.2.8-1.2.8-1.4 1-1.5.8.5-1 1.5-.8 1.4-1 1.2-.8 1.2-1 1.2-1 1-.8 1-1 .8-1 .7-1 .8-1 .5-1 .4-1 .4-1 .3-1.2.2h-2.2l-1-.2-1.3-.3-1-.3-1.2-.5-1-.6-1.2-.6-1.2-.8-1.2-.8-1.2-1-1.2-1-1.2-1-1.2-1.4-1.2-1.3-1.3-1.5-1-1.5h.8zm-1-.5.3-.8.7.7zm-28.3 1.5-1-.4h1l1 1.6 1 1.4 1.2 1.5 1 1.2 1 1.2 1 1 1 1 1 1 1 .7 1 .8 1 .6.8.4 1 .3.8.4h2.8l.8-.2.8-.3.8-.5 1-.5.7-.6 1-.7.7-.8.8-1 .8-1 .8-1.3.8-1.3.8-1.4.8-1.5.7-1.6.8-1.8 1 .4-.8 1.7-.7 1.7-.8 1.5-.8 1.4-.8 1.3-1 1.2-.7 1-1 1-.7 1-1 .7-.8.7-1 .4-.8.5-1 .2-1 .2h-3l-1-.3-1-.3-1-.4-1-.6-1-.7-1-.8-1-1-1-1-1-1-1-1.4-1-1.3-1.2-1.5-1-1.5-1.2-1.7h1zm-1-.4.5-.8.5.7h-1zm-25.6 6.5v-1l.3.2 1 1.3.7 1.2.8 1 .8 1 .8.8 1 .8.7.8 1 .6.7.5.7.3.8.3.8.2.8.2h2.3l.8-.4.8-.3.8-.4.7-.5 1-.6.7-.8.8-.8.8-.8.8-1 1-1 .7-1.2.7-1.2.8-1.3.8-1.6.8-1.5.8-1.7 1 .4-1 1.7-.7 1.5-1 1.4-.7 1.3-.8 1.3-.8 1.2-.8 1-1 1-.8 1-.8.8-.8.7-1 .6-.7.5-1 .5-1 .3-.7.3h-2.6l-1-.2-.8-.2-1-.4-.8-.4-1-.6-.8-.6-.8-.7-1-1-.7-.8-1-1-.8-1-1-1.3-.7-1.4.4.2zm0-1h.2v.2l-.3-.2zm-2.2.8h-1l.4-.5h1.2v-.2h1.5v1H389v.2h-.4zm-1 0v-.4h.4zm-18 3.6-.6.7.6-1 1 1 1.2.6 1 .7 1 .6 1 .4.8.5 1 .4.7.3.8.3.8.3.8.2h.7l.7.2h1.7l.4-.2.5-.2.4-.3.4-.3.4-.3.4-.4.3-.5.2-.5.3-.6.3-.7.3-.7.3-.8v-.8l.3-1v-.8l.2-1h1v1l-.2 1-.2 1-.2 1-.2.7-.2.8-.3.8-.4.7-.2.6-.5.6-.4.5-.6.5-.5.4-.7.2-.6.2-.6.2h-3.3l-.8-.3-.8-.3-1-.3-.8-.4-1-.5-.8-.5-1-.5-1-.6-1-.7-1-.8-1.2-.8.7-.8zm11 18.5v1l-.4-.3-.3-.6-.2-.6-.3-.6-.3-.6-.4-.6-.3-.6-.3-.7-.3-.5-.4-.6-.4-.7-.3-.6-.4-.6-.3-.5-.4-.6-.4-.7-.4-.5-.3-.6-.4-.6-.4-.6-.4-.6-.3-.5-.4-.7-.3-.6-.3-.5-.4-.6-.4-.5-.4-.5-.4-.5-.4-.6-.4-.5-.4-.6-.4-.5.7-.8.4.5.4.6.4.5.4.6.4.5.4.5.4.5.4.6.4.6.4.5.3.6.4.6.4.5.4.6.4.6.3.6.5.6.3.6.3.6.5.6.3.6.3.6.5.6.3.7.3.7.4.6.3.6.4.5.4.6.3.7.3.7.3.6-.5-.3zm0 1h-.3v-.3zm101.4-6v1l-3.2.2h-3.2l-3 .3h-3.3l-3 .3-3.3.2H460l-3 .3-3.3.3h-3.2l-3 .3H444l-3 .3h-3.3l-3.3.2-3 .2h-3.3l-3.2.3h-3l-3.3.3-3.3.2h-3l-3.3.3h-3.2l-3 .2-3.3.2h-3.3l-3.2.2h-3l-3.3.3H384l-3 .2-.2-1h3.2l3.2-.3h3l3.3-.2 3.2-.2h3l3.3-.3h3.2l3-.3h3.3l3.2-.3h3l3.3-.2h3.2l3-.3h3.3l3.2-.3 3-.2h3.3l3.2-.3h3l3.3-.3 3.2-.2h3l3.3-.3 3-.3h3.3l3.2-.3 3-.2h3.3l3.2-.3 3-.3h.2zm101.2 5v1h-3l-3.3-.2-3-.2h-3.3l-3-.3h-3.3l-3.2-.3h-3l-3.3-.2-3.3-.2h-3l-3.3-.3-3.2-.2h-3l-3.3-.3h-3.3l-3-.3h-3.3l-3.2-.3-3-.3h-3.3l-3.3-.3h-3l-3.3-.3h-3l-3.3-.2-3-.2-3.2-.2h-3.2l-3.2-.3h-3l-3.3-.2.2-1h3l3.3.3 3.2.2 3 .2 3.3.2h3l3.3.3h3.2l3 .2 3.3.2 3.2.2h3l3.3.3h3l3.3.2 3.2.2h3l3.3.3h3.3l3 .3h3.3l3.2.3h3l3.3.3h3.3l3 .3h3.3l3.2.2h3.2l3 .2 3.3.2h3.2zm0 1v-1l.5.7zm.5-.3-.2.3h-.4z"/>
<path fill="#edb92e" d="m505 276.2-23 11.4-22.6-11.4 22.7-11.5z"/>
<path fill="#edb92e" d="M474 259.2v.2q-26.4 1-93.2 5.3l6.5 31c29.6-.8 64.3-2 94.8-3 30.7 1 65.3 2.2 95 3l6.5-31q-66.9-4.2-93-5.3v-.2q2.6-.5-8.4-.2c-7-.2-10-.2-8 .2z"/>
<path fill="#edb92e" d="m597.3 236.7-3.7-.6c-7 17.5-13.4 18-14.6 1.4 1.6-.6 1-3.3 2.8-2.2 1 .5 2-1 1.3-2q-2.9-2.2-5.4.4c-.8-2.7-3-4-5.4-2.8-1 .5-.7 2.5.4 2.4 1.8-.2 1 1.6 1.6 3-12.5 16.4-19 14.4-17.4-7.3-3-.7-6.5-1.3-9.6-2.4-11.5 23.3-19.7 24.3-26.4 3.4 1.4-1 1-3.8 3-3 1.3.6 2.3-1.5 1.2-2.4-2.4-2-5-1.3-6.8 1.3-1.4-3-4-4-6.6-2.2-1.2.7-.5 3 .8 2.6 2.3-.7 1.3 2.4 3 3.5-5 19.6-30.8 21-26.6-8.2q-3.5 0-6.6.2l-6.7-.2c4.2 29-21.5 27.8-26.6 8 1.6-1 .6-4 3-3.4 1.2.3 2-2 .7-2.7-2.6-1.7-5.2-.7-6.6 2.2-1.7-2.7-4.3-3.4-6.7-1.4-1 1 0 3 1 2.5 2.2-.8 1.8 2 3.2 3-6.7 21-15 20-26.4-3.4-3 1-6.5 1.7-9.5 2.3 1.6 21.6-5 23.6-17.4 7 .6-1.2 0-3 1.7-2.8 1 0 1.5-2 .4-2.4-2.4-1-4.5 0-5.3 2.8q-2.5-2.7-5.5-.4c-.8 1 .4 2.5 1.3 2 1.8-1 1.2 1.6 2.8 2.2-1.2 16.5-7.6 16-14.6-1.3l-3.7.7c0 4 1.3 8.5 3.8 11.7 10.6 13.5 18.5 10.4 18.8-4.7 14 16.4 24.4 14.3 26.2-3 11.7 21.8 30.5 11.4 31-2 5 19.4 33.5 19.2 35.4-3 1.8 22.2 30.3 22.4 35.4 3 .4 13.4 19.2 23.8 31 2 1.7 17.3 12.3 19.4 26 3 .4 15 8.3 18.2 19 4.7 2.4-3.2 3.8-7.6 3.7-11.7z"/>
<path fill="#21231e" d="m593.7 235.6 3.7.6-.2 1-3.6-.6-.4-.7zm-.5.3v-.4h.5zm-14.3 1 .2 1 .3-.6.2 1.4v1.4l.3 1.3.2 1.2.2 1 .3 1 .3 1 .3.7.3.7.3.6.3.5.3.5.4.2.3.2h1.3l.4-.3.4-.2.5-.4.4-.3.6-.6.5-.6.6-.7.7-1 .6-.8.7-1.2.6-1.2.6-1.3.7-1.3.5-1.5.7-1.6 1 .3-.8 1.6-.6 1.4-.7 1.4-.5 1.3-.7 1.3-.6 1-.6 1-.7 1-.7.8-.6.8-.6.6-.5.5-.6.3-.7.4-.5.2h-1.2l-.6-.2-.5-.2-.5-.4-.5-.4-.4-.6-.3-.6-.3-.8-.4-.8-.3-1-.2-1-.3-1-.2-1.3-.2-1.3-.2-1.5v-1.6l.3-.5zm-.5.4v-.4h.4zm3.5-2.7-.5 1v-.2h-.4v.2h-.2v.2l-.2.2v.3l-.2.3-.2.3v.2h-.2v.3h-.3v.2h-.3l-.2.2-.3-1v-.2h.2v-.2h.2v-.2l.2-.2v-.5h.2v-.4l.2-.2v-.3l.2-.2.2-.2h.2l.2-.2h1l.2.2zm.8-1 .6-1v.2h.2l.2.3v1.6h-.2v.2h-.2v.2h-.2v.2h-.2v.2h-.5v.2h-.8l-.3-.2.5-1v.2h.4v-.2h.2v-.2h.2v-.8zm.6-1v.2zm-6.3 1 1-.3-.8-.2h.2l.2-.3.2-.2.2-.2.3-.2h.2l.2-.2h.2v-.2h.4l.2-.2h2.3l.2.2h.2l.2.2h.2l.2.2h.2l.2.2.2.2-.6.8-.3-.2h-.2l-.2-.2-.2-.2h-.3l-.2-.2h-2.1v.2h-.3v.2h-.2l-.3.2v.2h-.3v.2l-.3.2zm1 .3-.7.5-.2-.8 1 .3zm-5.6-2.7-.4-1h.5l.3-.2h2.1l.4.2h.4l.2.3h.2v.2l.3.2h.2l.2.2v.2l.2.2v.2l.2.2.2.2v.2l.2.3v.2l.2.2v.2l-1 .3v-.5h-.2v-.3l-.2-.2v-.2h-.3v-.3h-.2v-.4h-.3v-.2h-.3v-.2h-.6v-.2h-2l-.2.2zm0 1.4.2 1h-.6v-.2h-.2l-.2-.2-.2-.2-.2-.2V231l.2-.2.2-.2.3-.2.4 1h-.2v1.2h.2zm2.2 3.7-.8-.6v.5-.2h-.2v-1h-.2v-1l-.2-.2h-.7v-1.2h.6l.3.2.2.2h.2v.2l.2.3v.4h.2v1.5h.2v.8zm0-.5h.2l-.2.4zm-18-6.6.3-1 .3.6v2l-.2 1.8v4.9l.3 1.4v1.3l.3 1 .2 1 .3 1 .4.8.3.8.4.5.5.5.4.3.4.3.5.2h1l.6-.2.7-.3.7-.4.8-.5 1-.4.7-.8 1-.8 1-1 1-1 1-1 1-1.4 1-1.4 1.3-1.4.8.6-1.2 1.5-1 1.3-1.2 1.3-1 1-1 1.2-1 1-1 .8-1 .8-.8.6-1 .5-.7.4-.8.3h-.8l-.8.2h-.7l-.7-.2-.6-.3-.6-.5-.5-.5-.4-.7-.5-.7-.4-1-.2-1-.2-1-.2-1.2-.2-1.3V229l.5.6zm.3-1h.3v.6zm-9.3-1.6-1-.4.7-.3.3.2h.3l.3.2h.3l.2.2h.3l.4.2h.6l.3.2h.3l.4.2h.6l.3.2h.5l.3.2h.7l.3.2h.6l.3.2h.5l.3.2h.8l.3.2h.3l-.3 1h-.8l-.2-.2h-.6l-.3-.2h-.8l-.3-.2h-.6l-.4-.2h-.7l-.4-.2h-.3l-.3-.2h-.6l-.3-.2h-.2l-.3-.2h-.6l-.4-.2h-.3l-.4-.2h-.4l-.3-.2h-.2l.7-.4zm-1-.4.3-.4h.4l-.6.4zm-26.2 3.2.6.8.3-.6.6 2 .5 1.7.7 1.6.6 1.6.7 1.4.7 1.2.6 1 .7 1 .7 1 .7.6.6.6.7.4.7.4.7.2h1.4l1-.2.6-.2.8-.4 1-.6.7-.6 1-.8 1-1 .8-1 1-1.2 1-1.3.8-1.4 1-1.6 1-1.7 1-1.8 1-2 1.2-2 1 .3-1.2 2.2-1 2-1 1.8-1 1.8-1 1.6-1 1.5-1 1.3-1 1.2-1 1-1 1-1 1-.8.7-1 .5-.8.4-1 .2-.8.2h-1.8l-.8-.3-.8-.3-.8-.5-.8-.6-.7-.8-.8-1-.7-1-.7-1-.7-1.4-.7-1.4-.7-1.5-.7-1.7-.6-1.7-.7-1.8.2-.6zm-.2.6v-.4l.2-.2zm3.8-3.6-.3 1h-.3l-.2-.2h-.2v.2h-.2v.2h-.2v.5h-.2v.4l-.2.3-.2.2v.2l-.2.3-.3.3-.2.3h-.2l-.5-.7.2-.2.2-.2v-.5h.2v-.4h.2v-.3l.2-.3v-.2l.2-.2.2-.3.2-.2h.2v-.2h.5v-.2h.7l.2.2zm.7-1.6.6-.8.2.2.2.2v.2l.2.3v1.3l-.2.3v.2l-.2.2h-.2v.2h-.2v.2h-.2l-.2.2h-1.1l.4-1h.7v-.2h.2v-.6h.2v-.7h-.2v-.2zm-7 1 1-.3h-1l.2-.3v-.3h.3l.2-.3.2-.3.2-.2.3-.3.3-.3h.2l.2-.3h.3l.2-.2h.5l.2-.2h2.2l.3.2h.2l.3.2h.3l.3.3h.2l.3.3.3.2-.6.8-.2-.2h-.2l-.2-.3-.4-.2h-.2l-.2-.2H521v.2h-.5l-.2.3h-.2v.2h-.2l-.2.3-.2.2-.3.3v.2l-.2.3-.2.2h-1zm1 .2-.6.7-.3-1 1 .2zm-7-2-.4-1h.3l.2-.2h.3l.4-.2h.2l.3-.2h.4l.3-.2h1.6l.2.2h.2l.3.2h.2l.2.3.3.2.2.2v.2l.3.2.2.2.2.2v.2l.3.2.2.3.3.4v.3l-.8.4-.2-.4-.2-.2v-.2l-.3-.2v-.2l-.3-.2-.3-.3h-.2v-.2h-.3l-.3-.2h-.2l-.3-.2h-.4l-.2-.2h-1.2l-.2.2h-.5l-.2.2h-.2l-.2.2-.2.2zm.5 1.7.3 1h-.5l-.2-.2h-.2l-.2-.2-.2-.2-.2-.2v-.2l-.2-.2V224l.2-.2.2-.3.3-.2.5 1h-.2v1.2h.2v.2h.4zm3.7 4-1-.2.2.5h-.2l-.2-.2h-.2v-.3h-.2l-.2-.3v-.4l-.2-.2v-.3l-.2-.2v-.4l-.2-.2v-.2l-.2-.2v-.2h-.2v-.2h-.6l-.4-1h1.1l.3.2h.2v.4h.2v.3l.2.2v.2h.2v.5l.2.3v.5h.2v.4h.2l.2.2.2.2.3.6zm-.3-.5.3.2v.3zm-27-7.2v-1l.6.5-.3 2.7-.2 2.4v2.2l.2 2 .3 2 .4 1.7.5 1.5.7 1.4.6 1 .8 1.2 1 1 1 .7 1 .6 1 .5 1 .4 1.3.3h2.4l1.3-.2 1.2-.3 1.2-.5 1.2-.5 1-.7 1.2-1 1-.8 1-1 1-1.3 1-1.3.8-1.3.8-1.5.6-1.7.5-1.7 1 .2-.6 2-.7 1.6-.8 1.6-1 1.5-1 1.4-1 1.3-1 1-1.2 1-1.2 1-1.2.8-1.3.7-1.2.5-1.3.3-1.4.2h-2.5l-1.2-.3-1.3-.4-1.2-.5-1-.7-1-1-1-1-1-1-.8-1.5-.7-1.5-.6-1.6-.4-1.8-.3-2-.2-2.2V227l.2-2.6.3-2.7.5.6zm0-1h.7v.5l-.6-.5zm-6.6 1.2.2-1h4l.2-.2h2.1v1h-4.1l-.2.2h-2zm-6-.8h-1l.5-.4h5.1l.2.2h1.2v1h-4l-.3-.2h-2l.5-.6zm-1 0v-.5h.5zm-26.4 7.8.5.8.3-.5.6 1.7.5 1.7.7 1.5 1 1.4.8 1.4 1 1.2 1 1 1 1 1.2 1 1.2.6 1.2.5 1.2.5 1.2.3 1.2.2h2.4l1.2-.3 1-.3 1.2-.4 1-.7 1-1 .8-.8 1-1 .6-1.3.6-1.5.6-1.6.4-1.8.3-2v-2l.2-2.3-.2-2.5-.3-2.7h1l.3 2.6.2 2.5v2.2l-.2 2.2-.3 2-.5 1.8-.5 1.6-.7 1.5-.8 1.4-1 1.2-1 1-1 .8-1 .7-1.2.5-1.3.4-1.3.3H463l-1.2-.2-1.3-.3-1.3-.5-1.3-.6-1.3-.7-1.2-1-1.2-1-1-1-1-1.2-1-1.3-1-1.5-.7-1.6-.7-1.7-.6-2 .2-.5zm-.2.5v-.3l.2-.2zm3.7-4-.2 1-.2-.2h-.7v.2l-.2.2v.4l-.2.2v.5l-.2.2v.2l-.2.3v.2l-.2.2v.2h-.2v.3h-.3l-.2.2h-.2l-.4-.7.2-.2.2-.2h.2v-.3l.2-.2v-.5l.2-.2v-.5l.2-.3v-.3l.2-.2.3-.3.2-.2h.2l.2-.2h1.1zm.4-1.8.6-1v.2h.3v.3h.2v.2l.2.2v1.5l-.2.2v.2l-.2.2-.3.2-.2.2h-.9l.3-1h.4v-.4l.2-.2v-.8h-.2v-.2h-.2zm-6.7 2 .8-.6h-.8v-.2l.2-.3.3-.4v-.2l.3-.2.2-.2.2-.2.2-.2.2-.2.2-.2h.2l.3-.3.3-.2h.2l.3-.2h.5l.2-.2h1.6l.4.2h.2l.3.2h.2l.3.2.2.2h.3l-.6 1-.2-.2h-.2l-.2-.2h-.3l-.2-.2h-.5l-.2-.2h-1.3l-.2.2h-.3v.2h-.3l-.2.3-.2.2-.3.3-.3.3-.2.2v.2l-.2.2-.2.2v.3h-.2zm1 0-.5.7-.5-.8h1zm-7-1.2-.8-.8.2-.2.2-.2h.3l.2-.3h.2l.2-.2h.3l.3-.2h2.5l.3.2h.2l.3.2.2.2h.2l.2.3h.2l.2.2.2.2.2.3.2.2h.2v.4l.3.2-.8.6-.2-.2v-.3l-.3-.2-.2-.2-.3-.3-.2-.2h-.2l-.2-.2v-.2h-.2l-.2-.2h-.4l-.2-.2H441l-.2.2h-.2l-.2.2h-.2l-.2.3h-.2l-Line truncated
<path fill="#edb92e" d="M482 263h-22.5l-1.3.2H451l-1.3.2h-4.4l-1.2.2h-2.3l-6.3.4h-.3l-9 .4h-.8l-18.2 1.3h-.2l-26.4 2.4c-5 .6-6-5.3 0-6l26.3-2.2a984 984 0 0 1 37-2.2h2.4l15.4-.5h40.6l15.2.5h3.3a984 984 0 0 1 37 2.3l26.2 2c5.8.7 5 6.6 0 6l-26.4-2.3h-.3l-18.3-1.2h-.6l-9.2-.5h-.3q-3.3 0-6.4-.3h-2.3l-1.2-.2h-4.5l-1.3-.2H506l-1-.2z"/>
<path fill="#0c4076" d="M482 105a17.3 17.3 0 0 1 .1 34.7c-9.3 0-17-7.8-17-17.3s7.7-17.3 17-17.3z"/>
<path fill="#edb92e" d="M485.3 85c1.6-.2 3-1.5 3-3.2s-1.4-3-3-3.2c0-1.7-1.4-3-3.2-3a3 3 0 0 0-3 3c-1.6 0-3 1.5-3 3.2a3 3 0 0 0 3 3v6.5h-5.5a3 3 0 0 0-3-3c-1.8 0-3 1.3-3.2 3a3 3 0 0 0-3 3c0 1.8 1.3 3.2 3 3.2a3 3 0 0 0 3 3c1.8 0 3.2-1.2 3.2-3h5.5V119h6.3V97.6h5.5a3 3 0 0 0 3 3c1.8 0 3-1.4 3.2-3 1.7 0 3-1.5 3-3.2a3 3 0 0 0-3-3c0-1.8-1.4-3.2-3-3.2-2 0-3.2 1.4-3.2 3h-5.5V85z"/>
<path fill="#21231e" d="M487.8 81.8h1v1h-.2v.5h-.2v.3l-.2.3-.2.2v.2h-.2l-.2.2-.2.2h-.2v.2h-.2l-.2.2h-.2v.2h-.8l-.2.2h-.3v-1h.7V84h.2l.3-.2h.2v-.2h.2v-.2l.2-.2V83h.2l.2-.2v-.4l.2-.2zm-3-3.2h1l-.5-.5h.2l.3.2h.4l.3.2h.3l.2.2.2.2h.2v.2h.2l.2.2.2.3.2.2v.2h.2v.4h.2v.5l.2.2v.7h-1V81h-.2v-.4l-.2-.2V80h-.4v-.2h-.2v-.2h-.2l-.3-.2h-.2V79h-.8l-.4-.6zm.4.5h-.4v-.4zm-3-3v-1h.7l.2.2h.2l.3.2h.2l.2.2.2.2h.2v.3l.2.2.2.3.2.2v.2h.2v.4h.2v.8h.2v.3h-1V78h-.2v-.5h-.2v-.2l-.2-.2-.2-.2-.2-.2h-.2v-.2h-.2l-.2-.2h-.4zh-.4zm-3.2 3v-1l-.5.6v-.8l.2-.2V77h.2v-.6h.2v-.2l.2-.2.2-.2.2-.2h.2v-.2h.3v-.2h.3l.3-.2h.4l.2-.2h.4v1h-.5v.2h-.3l-.2.2h-.2v.2h-.2v.2h-.2v.2l-.2.2v.2h-.2v.5h-.2v1l-.6.5zm.5-.4v.5h-.5zm-3 3.2h-1V81l.2-.3v-.5l.2-.2v-.2l.2-.2.2-.3.2-.2h.2l.2-.2h.2v-.2h.3v-.2h.5l.3-.2h.7v1h-.7l-.2.2h-.2l-.2.2-.2.2-.2.2-.2.2v.2h-.2v.4l-.2.2v.8zm3 3h-1l.5.6h-1V85h-.7v-.2h-.3v-.2h-.2l-.2-.2-.2-.2V84h-.2v-.2l-.2-.2-.2-.3v-.5h-.2v-1h1v1h.2v.4h.2v.2h.2v.2l.2.2h.2v.2h.2l.3.2h.7v.2h.2zm-.5-.4h.5v.5l-.5-.6zm-.5 7V85h1v6.3l-.5.5-.5-.5zm1 0v.4h-.5l.5-.5zm-6-.6h5.5v1h-5.5l-.5-.5zm0 1h-.5v-.5zm-3-3v-1h1.2v.2h.3l.3.2.3.2.3.2v.2l.2.2.2.3.2.3.2.3v.4l.2.2v.8h-1v-.7l-.2-.2V90h-.2v-.2h-.2v-.2l-.2-.2-.2-.2h-.2V89h-.4l-.2-.2h-.8zm-3.2 3v-1l-.5.4v-.8l.2-.3V90l.2-.3v-.2h.2v-.2l.2-.2h.2v-.3h.2l.2-.2.2-.2h.2V88h.7v-.2h1.1v1h-1l-.2.2h-.2v.2h-.2v.2h-.2l-.2.2v.2h-.2v.4h-.2v.8l-.2.2v.3l-.5.5zm.5-.5v.5h-.5zm-3 3h-1V93h.2v-.2h.2v-.3l.2-.3.3-.3v-.2h.2v-.2h.2v-.2h.2l.2-.2h.2V91h.7l.2-.2h.8v1h-.7l-.2.2h-.2v.2h-.2v.2h-.2l-.2.2-.2.2v.2h-.2v.5h-.2v.7zm3 3.2h-1l.5.5h-1v-.2h-.5l-.2-.2h-.2v-.2h-.2l-.2-.2-.2-.2v-.2h-.3v-.2l-.2-.2V96h-.2v-.4l-.2-.3v-.8h1v.9h.2v.2l.2.3h.2v.2h.2v.2h.2v.2h.2l.2.2h.5v.2h.4l.6.5zm-.5-.5h.5v.5zm3 3v1h-1l-.2-.2h-.3v-.2h-.3v-.2h-.2l-.2-.2-.2-.3v-.2h-.2v-.3h-.2V99h-.2v-.5l-.2-.2V98h-.2v-.5h1v.7h.2v.4h.2v.2l.2.2v.2h.2v.2h.2v.2h.2l.2.2h.2l.3.2h.6zm3.2-3v1l.5-.4v.8l-.2.2v.3h-.2v.3l-.2.3-.2.2-.2.2-.2.2-.3.2-.2.2h-.2l-.2.2h-.2l-.3.2h-.8v-1h.9v-.2h.2l.2-.2h.2v-.2h.2l.2-.2V99h.2v-.2l.2-.3v-.2l.2-.2v-.4zm-.5.6V97h.5l-.5.6zm6 .5h-5.5v-1h5.5l.5.6zm0-1h.5v.6zm-.5 22V97.6h1V119l-.5.5-.5-.5zm.5.5h-.5v-.5zm6.3 0H479v-1h6.3l.5.5zm.5-.5v.5h-.5zm0-21.4V119h-1V97.6l.5-.5.5.6zm-1 0V97h.5l-.5.6zm6 .5h-5.5v-1h5.5l.5.6zm0-1h.4v.6zm3 3v1h-1l-.3-.2h-.2l-.3-.2-.2-.2h-.2v-.2h-.2l-.2-.2v-.2h-.2v-.2l-.2-.2V99h-.2v-.2h-.2v-1l-.2-.2h1v.4l.2.2v.2l.2.3v.2h.2v.2h.2l.2.2v.2h.2l.3.2h.2v.2h1.1zm3.2-3v1l.5-.5v.7h-.2v.5l-.2.3v.4h-.2v.3h-.2v.2h-.2v.2h-.3v.2l-.3.2h-.3l-.2.2h-.3l-.2.2h-.8v-1h.9v-.2h.2v-.2h.2l.2-.2.2-.2V99h.2v-.2l.2-.2v-.2l.2-.2v-.6l.6-.6zm-.5.5V97h.5l-.5.5zm3-3h1v.9l-.2.3v.2h-.2v.6h-.2l-.2.2v.2h-.2v.2h-.3v.2h-.2v.2h-.3l-.3.2h-.2l-.3.2h-.7v-1h.8V97h.2v-.2h.2l.2-.2.2-.2h.2V96l.2-.3v-.2h.2v-.7l.2-.3zm-3-3.2h1l-.5-.6h.7l.2.2h.4l.3.2.3.2.3.2.2.2.2.3.2.2v.5h.2v.3h.2v.7l.2.3v.4h-1v-.6h-.2v-.4l-.2-.2-.2-.2v-.2h-.2l-.2-.2-.2-.2h-.2V92h-.5l-.2-.2h-.5l-.5-.5zm.5.5h-.5v-.5zm-3-3v-1h1.1l.2.2h.4v.2h.3v.2l.3.2.2.3h.2v.3h.2v.4l.2.2v.4h.2v.7h-1v-.8h-.2V90l-.2-.2-.2-.2-.2-.2-.2-.2h-.2V89h-.5v-.2h-.6zm-3.2 3v-1l-.6.5v-.9l.2-.2V90l.2-.3.2-.3.2-.3h.2v-.2l.2-.2h.2v-.2h.2l.2-.2h.3l.2-.2h.3l.2-.2h1v1h-1l-.3.2h-.2v.2h-.2l-.2.2v.2l-.2.2-.2.2v.2l-.2.2v.7l-.7.6zm.5-.5v.5h-.6zm-6-.5h5.5v1h-5.5l-.5-.5zm0 1h-.5v-.5zm.5-7v6.5h-1V85l.4-.6.6.5zm-1 0v-.4h.4zm.5 0v-.4zm-.5 0v-.4h.4z"/>
<path fill="#21231e" d="M499.8 122.4h-1v-1.7l-.2-1v-.7l-.3-.8-.2-.8-.2-.8-.3-.8-.3-.7-.4-.6-.4-.7-.4-.7-.5-.7-.5-.6-.5-.6-.6-.5-.7-.6-.6-.6-.6-.5-.5-.6-.7-.4-.7-.4-.6-.4-.8-.3-.7-.4-1-.3-.7-.2h-.8l-.8-.2h-.8l-1-.2h-1v-1h2l.8.2h1l.8.3.8.4.8.2.8.4.8.3.8.4.7.4.7.6.7.5.7.6.6.6.6.6.6.6.6.6.5.7.5.7.5.7.4 1 .4.6.4.8.3.8.3 1 .3.7.2.8v1l.2.7v2zM482 140.2v-1h1.8l1-.2.7-.2.8-.2.8-.2 1-.3.6-.2.8-.3.7-.4.8-.3.7-.4.6-.5.7-.5.6-.5.6-.6.5-.5.5-.6.5-.6.5-.6.4-.7.4-.6.4-.8.3-.7.3-1 .3-.6.3-.8.2-.8v-1l.2-.7v-1.6h1v2.8l-.2.8-.2.8-.3 1-.3.7-.3.8-.3.8-.3 1-.4.6-.5.7-.5.7-.5.7-.6.6-.6.7-.6.6-.6.5-.7.6-.7.5-.7.6-.7.4-.8.4-.8.4-.8.3-.8.4-.8.2-1 .2-.8.2h-.8l-1 .2h-1zm-17.5-17.8h1v1.8l.2.7v.8l.3.8.2.8.3.7.3 1 .3.6.5.8.4.7.3.8.5.6.5.6.5.7.6.5.5.6.5.5.7.5.6.5.7.4.7.4.7.5.7.3.7.3.8.4.8.2.8.2.8.2h1.8l.7.2v1h-1.8l-.7-.2-1-.2-.8-.2-.8-.2-1-.3-.7-.2-.8-.4-.8-.4-.7-.4-.7-.5-.7-.4-.7-.5-.7-.4-.7-.6-.5-.7-.5-.6-.5-.7-.5-.7-.5-.7-.4-.7-.4-1-.3-.7-.5-.8-.2-.8-.3-1-.2-.7v-1l-.2-.8v-1.8zm17.6-17.8v1h-1.7l-.7.2h-.8l-.8.3-.8.3-.8.3-.7.3-.8.2-.8.4-.7.4-.7.4-.6.5-.7.4-.6.5-.6.5-.6.6-.5.7-.5.6-.5.7-.4.7-.5.7-.4.7-.2.8-.3.8-.3.8-.2.8-.2.8v.8l-.2 1v1.7h-1v-2.8l.2-1 .2-.8.3-1 .2-.8.4-.8.2-.8.4-.7.4-1 .5-.6.5-.7.5-.7.6-.6.6-.6.7-.6.6-.6.6-.5.7-.4.7-.5.7-.3.8-.4.8-.3.8-.4 1-.2.7-.3h1l.8-.2h.8l1-.2h.8z"/>
<path fill="#edb92e" d="M499 118.8a18 18 0 0 1 0 6q-8.3-.3-17-.3-8.3 0-17 .3a18 18 0 0 1 .3-6l16.8-.3q8.6 0 17 .3z"/>
<path fill="#21231e" d="M499.8 122.4h-1V120h-.2v-1l1-.2v1.7l.2.2v1.6zm-.7 3 .2-1-.6.3v-.8l.2-.2v-1.1h1v2.2h-.2zm.6-.5v.3h-.5l.6-.4zm-17.5 0v-1H494l.4.2h4.8v1h-10.6l-.5-.2h-6zm-17.4 0 1-.3-.5-.4h4.7l.4-.2H482v1h-11l-.5.2H465l-.5-.3zm.6.3h-.5v-.4l.5.3zm-.7-3h1v2.4l-1 .3v-2.6zm.8-4v1l.5-.3v.8l-.2.2v2.5h-1v-3h.2v-.4l.5-.5zm-.5.5v-.4h.5zm17.3-.8v1h-9.1l-.5.2H466l-.7.2v-1h2.5l.5-.2h9l.5-.2h4.2zm17.5.8-1 .2.4.4h-3.6l-.5-.2h-10.3l-.5-.2h-2.1v-1h10l.5.2h6.1l.5.6zm-.5-.5h.4v.5z"/>
<path fill="#edb92e" d="M468.8 133.2c-3.6-2.3-4.3 1.2-4.2 4.7.4 13.2 3 25.8-.6 42-1.4 6.4-3.7 10-1.5 11.3q8.6 5 7.4 7.7c1.5 3.2 5.7 2.6 12 1.6 6.6 1 10.7 1.6 12.4-1.6-1-1.6 1.7-4.5 7.4-7.7 2.2-1.2 0-5-1.5-11.3-3.5-16.2-1-28.8-.7-42 0-3.6-.5-7-4-4.8a29 29 0 0 1-26.8 0z"/>
<path fill="#21231e" d="M465 138h-1v-1.5l.2-.3v-1.6l.2-.3v-.3h.2v-.4l.2-.2v-.3h.2l.2-.3.2-.2.2-.2h.2l.2-.2h1.8l.4.2.4.2h.3l.4.3-.4 1-.4-.3h-.2l-.3-.2h-.3l-.2-.2h-1.2v.2h-.2v.2l-.2.2v.2l-.2.2v.4l-.2.3v.4l-.2.2v2.5zm-.5 42-1-.2.3-1.5.3-1.4.3-1.6.2-1.4.2-1.5.2-1.4v-2.5l.2-1.4V154l-.2-1.2v-2.5l-.2-1.2V148l-.2-1.2v-1.2l-.2-1.3V142l-.2-1.3V138h1v3.5l.2 1.2v2.6l.2 1.2v1.3l.2 1.2v2.5l.2 1.2v1.3l.2 1.3v13.3l-.2 1.4v1.4l-.3 1.5-.2 1.4-.2 1.6-.2 1.4-.2 1.5-.3 1.6zm-1.8 11-.4.8-.3-.2-.2-.2-.2-.2-.2-.2v-.2l-.2-.3V188l.2-.3v-.4l.2-.3v-.4l.2-.4v-.5l.3-.4.2-.4v-.5l.3-.3v-.5l.3-.5v-.6l.3-.4.2-.6v-.6l.3-.6 1 .3-.2.7v.6l-.3.5v.6l-.2.5-.2.4v.6l-.3.4v.5l-.3.4v.4l-.2.4v.4l-.2.4v.4l-.2.3v.4l-.2.4v1.9zl.2.2zm7.6 7.8-1 .4v-.4h.2v-1l-.2-.2v-.2l-.2-.2v-.4l-.3-.2-.2-.2-.2-.3h-.3l-.2-.4-.3-.2-.3-.3h-.3l-.4-.4-.4-.3-.3-.2-.5-.2-.4-.3-.3-.3-.5-.3-.5-.3-.4-.3-.5-.3-.6-.2.5-1 .6.4.5.3.5.3.4.3.5.4.4.3.5.3.5.2.3.3.4.3.4.3.3.4.2.2.3.3.3.2.2.2.2.3.3.2.2.2v.2l.3.3v.2l.3.2v.5l.2.2v1.1l-.2.3v-.5zm-1 .4v-.4zm13 1-.2 1h.2-1.2l-.5.2h-1.2l-.6.2h-1l-.5.2h-4.7l-.4-.2h-.3l-.3-.2-.3-.2-.3-.2-.2-.2-.3-.2-.2-.2-.3-.3h-.2l-.2-.4-.2-.4 1-.4v.2l.2.3.2.2.2.2.2.2h.2l.2.2h.2l.3.2h.3l.3.2h.3l.2.2h4.3l.5-.2h1l.6-.2h1.1l.5-.2h.8zm-.2 0h.2zm12-1 1-.4v.4l-.3.4-.2.3h-.2l-.3.4-.2.2-.3.2-.3.2-.3.2-.4.2h-.3l-.3.2h-.4l-.4.2H486l-.6-.2h-.5l-.6-.2h-1.2l-.5-.2h-.6l.2-1h1.8l.5.2h.6l.6.2h1.1l.5.2h4.2l.3-.2h.3l.2-.2h.3l.2-.2.2-.2.3-.3.2-.2.2-.2v-.3l.3-.2v.5zm1-.4v.4zm6.5-8 .5 1-.5.3-.5.4-.5.3-.4.2-.4.2-.4.3-.4.3-.4.3-.4.3-.3.3-.3.3h-.3l-.2.4-.3.2-.3.3h-.2l-.2.4-.2.2-.2.2v.2l-.3.2v.7h-.2v1.2l-.8.5v-.2l-.2-.2v-1.3l.2-.2v-.3l.3-.3v-.3l.3-.2.2-.3.2-.3.3-.3.2-.2.3-.3.3-.4.4-.2.3-.3.4-.2.4-.3.4-.3.4-.2.4-.3.5-.3.5-.3.5-.2.5-.3.5-.3.5-.3zm-1.7-10.7 1-.2v.6l.3.6.2.6.2.5v.7l.3.5v.5l.2.4v.6l.2.5.2.5v.4l.2.3v.4l.2.4v.5l.2.3v.7l.2.3v1.8l-.2.3v.2l-.3.3h-.2l-.2.3-.3.2-.5-1h.2l.2-.2v-.4h.2v-2.5l-.2-.3v-.3l-.2-.3v-.4l-.2-.4v-.4l-.2-.4v-.4l-.3-.5v-.6l-.2-.4v-.6l-.3-.5v-.6l-.3-.6v-.5l-.2-.6-.2-.6zm-.7-42h1v5.9l-.2 1.4v1.2l-.2 1.2v1.3l-.2 1.3v2.5l-.2 1.2v2.6l-.2 1.2v9.3l.2 1.4v1.4l.2 1.3.2 1.5.2 1.5.2 1.4.2 1.5.3 1.3.3 1.5-1 .3-.3-1.5-.3-1.5-.2-1.4-.2-1.5-.2-1.3-.2-1.5v-1.4l-.2-1.4V167l-.2-1.3v-10.3l.2-1.3v-2.5l.2-1.3V149l.2-1.2v-1.3l.2-1.2V143l.2-1.2zm-3.3-4.4-.5-1h.4l.3-.2.2-.2h.3l.4-.2h1.2l.3.2h.2l.2.3v.2l.2.2h.2v.4l.2.2v.3h.2v.7l.2.3v1.5l.2.3v1.1h-1v-2.4l-.2-.3v-.8l-.2-.3v-.4l-.2-.2v-.2h-.2v-.2h-.2v-.2h-.2v-.2h-1.1l-.2.2h-.3l-.3.2-.3.2zm-27 0 .4-1 .8.5.7.5.7.4.7.2.7.3.8.2.8.3 1 .2.7.2 1 .2h.7l1 .2h.8l1 .2h4.6l.7-.2h1l.8-.3h.8l1-.3.7-.2.8-.3.8-.2.8-.3.7-.4.8-.3.7-.4.7-.3.5 1-.7.3-.7.4-.8.4-.7.3-1 .4-.7.3-.7.3-1 .2-.7.2-1 .2h-.8l-1 .2h-1l-.8.2h-4.6l-1-.2h-.8l-1-.2-.8-.2-1-.2-.7-.2-.8-.3-.8-.3-.8-.3-.8-.2-.8-.4-.7-.4-.7-.4z"/>
<g id="rs-b">
<path fill="#edb92e" d="M363 212c-2-4-.3-9.8.3-11 .3-.8-.6-2.2-1-2.8-13-18.3-13.2-20-4.3-26.8 8-6 26.2-12 39.2-16.2 2.7-2 4.4-5 6.8-7.2-25 1.8-52 12-65.5 23.8-7.2 6.2 1.5 19 12.2 38 6.7 5 9.8 7 12.3 2.3z"/>
<path fill="#21231e" d="m362.8 200.7 1 .4v.2l-.2.2v.3l-.2.3v.5l-.2.2v.6l-.2.4v.7l-.2.3v1.6l-.2.4v2.5l.2.4v.4l.2.4v.4l.2.4v.3l.3.4-1 .3v-.4l-.3-.5v-.4l-.2-.4v-.4l-.2-.5v-.8l-.2-.6v-2.9l.2-.4v-1.2l.2-.3v-.4l.2-.2v-.6l.2-.3v-.6l.2-.2v-.2l.2-.2zm-1-2.2 1-.6v.2h.2v.4h.2v.4h.2v.2l.2.2v.4h.2v1.2l-1-.3v-.6l-.2-.2v-.2l-.2-.2v-.2l-.2-.2v-.2h-.2v-.2zm-4-27.5.5 1-.8.5-.7.6-.7.6-.5.6-.6.5-.6.5-.5.6-.5.5-.3.4-.3.5-.3.5v.5l-.3.5v1.7l.2.6.2.8.2.7.4.8.4.8.4 1 .5 1 .6 1 .7 1 .7 1.3 1 1.2.7 1.3 1 1.4 1 1.5 1 1.5 1.3 1.7-.8.5-1.3-1.7-1-1.5-1-1.5-1-1.4-1-1.3-.8-1.2-.8-1.2-.7-1-.6-1-.7-1-.4-1-.6-1-.3-.7-.2-1-.2-.7v-.7l-.2-.7v-1.4l.2-.6.2-.6.2-.6.3-.6.4-.6.5-.5.5-.5.5-.5.6-.6.7-.5.7-.7.7-.6.7-.7zm39-16.2.7.8h-.2l-1.2.5-1.2.5-1.2.4-1.4.3-1.3.4-1.4.5-1.4.4-1.3.5-1.5.5-1.4.5-1.3.5-1.3.5-1.4.5-1.4.5-1.3.5-1.4.5-1.4.5-1.3.6-1.3.6-1.3.5-1.2.7-1.2.5-1.2.6-1 .5-1.2.6-1 .4-1 .6-1 .6-1 .5-1 .7-.7.6-.7.6-.6-1 .8-.5 1-.6.8-.7 1-.6 1-.6 1-.4 1-.6 1.2-.6 1.2-.5 1-.7 1.4-.6 1.3-.5 1.3-.6 1.3-.5 1.2-.4 1.4-.5 1.3-.5 1.3-.5 1.4-.5 1.3-.5 1.4-.5 1.4-.5 1.4-.4 1.4-.5 1.3-.4 1.3-.4 1.3-.4 1.3-.5 1.2-.4 1.3-.5 1.3-.4 1.2-.3zm.7.8h-.2zm6.6-7v-1l.4.8-.2.2-.3.2-.3.3-.2.3-.2.2-.2.2v.3l-.3.2-.2.2-.2.2-.2.3-.3.3-.2.3-.2.2-.2.3v.3l-.3.2-.2.3-.2.2-.3.2-.2.3-.2.2-.2.2h-.2l-.3.4-.3.2-.2.2-.3.2-.2.2-.3.2-.2.2-.6-.8v-.2l.3-.2.3-.2.2-.2.2-.2.2-.2.3-.2.2-.2.2-.2v-.2l.3-.3.2-.2.2-.2.2-.2v-.2l.3-.2.2-.2.2-.3.2-.3v-.3l.3-.2.2-.2.2-.3.2-.2v-.2l.4-.3.2-.2.2-.2.2-.3.2-.2h.3l.2-.3.4.8zm0-1 1.4-.2-1 1-.4-1zM338.8 172l-.7-.8 1.5-1 1.4-1.2 1.4-1 1.5-1.2 1.5-1 1.7-1 1.7-1 1.7-1 2-1 1.8-1 2-1 2-1 2-.8 2-1 2.2-.7 2-.8 2.3-.8 2.3-1 2.2-.6 2.3-.7 2.3-.6 2.4-.5 2.3-.6 2.4-.7 2.4-.5 2.4-.4 2.4-.4 2.4-.4 2.3-.3 2.3-.3 2.4-.3 2.3-.2v1l-2.3.2-2.3.3-2.3.3-2.3.3-2.4.4-2.3.4-2.4.4-2.3.5-2.3.6-2.3.5-2.3.6-2.3.7-2.2.7-2.2.7-2.2.8-2.2.8-2.2.8-2 1-2 .7-2.2 1-2 1-2 1-1.8.8-1.8 1-1.8 1-1.7 1-1.6 1-1.5 1-1.6 1-1.5 1.2-1.4 1-1.2 1.2zm12.2 37.3-.5.8-.2-.2-1-1.6-1-1.8-1-1.7-1-1.7-.8-1.7-1-1.6-.8-1.5-.8-1.5-1-1.5-.7-1.5-.8-1.4-.7-1.3-.7-1.4-.5-1.3-.6-1.3-.6-1.2-.4-1.2-.5-1.2-.3-1-.3-1-.4-1.2v-1l-.2-1v-2.8l.3-.8.3-.8.4-.7.5-.8.5-.7.6-.6.8.8-.6.5-.5.6-.4.7-.3.6-.3.7-.2.8v4.5l.4 1v1l.5 1 .4 1 .4 1.3.5 1.2.4 1.2.6 1.3.7 1.3.7 1.4.7 1.4 1 1.4.7 1.5 1 1.5.8 1.5 1 1.6.8 1.7 1 1.7 1 1.7 1 2 1 1.6h-.3zm-.5.8-.2-.2.2.3zm12.5 1.3v1l.5-.2-.3.4-.2.4-.3.4-.3.3-.3.2-.2.3-.3.2-.3.2h-.3l-.5.2h-2.1l-.4-.2-.5-.2-.4-.2-.3-.2-.5-.2-.4-.3-.5-.3-.5-.3-.4-.4-.6-.3-.5-.3-.5-.4-.6-.4-.5-.4-.6-.4-.5-.5.5-.8.7.4.5.3.6.5.6.3.5.5.4.4.5.2.4.3.4.3.5.3.4.3.4.2.5.2.4.2h.5l.3.2h1.5l.2-.2h.3l.2-.3.2-.2.3-.2.2-.3v-.3l.4-.4.2-.4.4-.4zm-.4.3v-.4h.4zm.4.6v-1l.5.3zm.5-.7.3.6h-.8z"/>
<path fill="#edb92e" d="m359 213.6-1-4.7q-1-4.3.5-8.3c-3-4.2-6.4-8.8-8.8-13.3-1.7-3.3-3-7-2-10.6 1-4 4.5-6.6 7.6-9 3.7-2.8 8.6-5.3 13.6-7.5q16.6-7 26.5-7l-4.2 3.8c-12 4-26.4 9.2-33.3 14.5-9 6.8-8.6 8.4 4.3 26.7.4.6 1.3 2 1 2.7-.6 1.2-1.8 7.2 0 11.4-1 2-2.6 1-4.2 1.2z"/>
<path fill="#21231e" d="m357.4 209 1-.2v.7l.2.2v.7h.2v.8l.2.3v.3l.2.3v.7h.2v.6h.2l-1 .4v-.3l-.2-.3v-.2l-.2-.3v-.5l-.2-.3v-.6h-.2v-.5l-.2-.3v-.7l-.2-.3v-.2zm.6-8 1-.6v.5l-.2.4v.2l-.2.2v1l-.2.2v.8l-.2.2v4.7l.2.3-1 .2v-.6l-.2-.2V203h.2v-1l.2-.2v-.5l.2-.2v-.2l.2-.3v.5zm1-.6v.5zm-9.7-12.8 1-.5v.6l.3.4.3.4v.4l.4.5.2.4.3.4v.5l.4.4.3.4.2.4.2.4.3.4.2.4.3.5.3.4.3.3.3.4.2.4.2.5.3.5.3.4.3.4.3.4.3.4.2.4.3.4.2.4.3.4.3.4.3.4.3.4-1 .6-.2-.4-.3-.4-.3-.4-.3-.4-.4-.4-.3-.4-.2-.4-.2-.4-.3-.4-.3-.4-.3-.5-.4-.4-.3-.3-.3-.4-.2-.4-.3-.5-.3-.5-.3-.4-.4-.4-.3-.4-.2-.5-.2-.4-.3-.5-.2-.4-.3-.4-.3-.4-.2-.4-.3-.5-.2-.4-.2-.5-.3-.5-.2-.4zm-2-11 1 .4-.2.3v4.1l.2.4v.3l.2.3v.7l.3.3v.4l.2.4v.6l.3.3v.3l.3.3v.2l.3.3v.3l.2.3-1 .6v-.3l-.2-.3-.2-.3v-.3l-.3-.4v-.3l-.3-.3v-.3l-.3-.3-.2-.3v-.3l-.2-.2v-.4l-.2-.3v-.3l-.2-.3v-.7l-.2-.4V180l-.2-.4V178l.2-.2v-.7l.2-.3zm7.7-9.2.6.8-.3.2-.3.3-.3.2h-.3l-.3.3-.2.3-.2.2-.3.3-.3.3-.3.2-.3.3-.2.2-.3.3-.4.3-.2.2-.3.3v.3l-.4.3-.2.3-.2.2-.3.3-.3.3-.2.3-.2.4v.3l-.3.3-.2.3v.3l-.3.3v.3l-.2.3v.4l-1-.3v-.4l.2-.4v-.4l.2-.4.2-.4v-.3l.3-.4.2-.2.2-.3.2-.3v-.3l.4-.5.2-.3.2-.2.3-.3.4-.3.2-.3.3-.2.2-.2.3-.3.2-.3.3-.2.3-.3.3-.2.3-.3.2-.2.3-.2.3-.3.3-.2h.4l.3-.4.3-.2zm13.7-7.5.4.8-.4.2-.4.2-.5.2-.5.2-.4.2-.5.2-.4.3-.6.2-.5.2-.5.2h-.5l-.4.3-.5.3-.3.2-.4.2-.5.3-.4.2-.4.2-.4.3-.5.2-.3.2-.4.3-.4.2-.5.2-.4.2-.2.3-.4.2-.4.2-.4.2-.3.3-.4.3-.4.2-.6-.8.3-.3h.4l.4-.4.4-.3.4-.2.4-.2.4-.2.4-.3.4-.2.4-.2.4-.2.4-.3.5-.2.5-.2.4-.2.4-.2.4-.3h.4l.5-.3.4-.3.6-.2.4-.2.5-.2.5-.3.4-.2.5-.2h.4l.4-.3.5-.2.5-.2.4-.2h.5zm27-6.4-.6-.7.5.7H394l-.6.2h-1.8l-.7.2h-.8l-.7.2h-.7l-.8.3-.8.2h-.7l-.8.2-.8.2-1 .2-.8.2-.8.3-1 .3-.8.3-1 .3-.8.2-1 .3-.8.3-1 .3-1 .5-1 .3-.8.4-1 .4-1 .4-1 .4-1 .4-.5-1 1-.4 1-.4 1-.4 1-.4 1-.3 1-.5 1-.3 1-.4 1-.3.8-.3 1-.3.8-.4 1-.2.8-.3h1l.8-.4.8-.2.8-.2.8-.2h.8l.8-.3.8-.2h.7l.7-.2h.8l.7-.2h1.4l.5-.2h1.9l.4.8zm-.3-1h1.4l-1 1zm-4.4 4 4-3.7.8.6-4 3.8-.3.2zm.7.8-.2.2zM358.3 172l-.6-1 .7-.5.7-.5 1-.5.7-.5.8-.5 1-.5.8-.4 1-.5 1-.4.8-.5 1.2-.4 1-.5 1-.3 1-.5 1.2-.5 1-.4 1.3-.5 1-.4 1.2-.5 1-.5 1.3-.5 1-.4 1.3-.4 1.2-.5 1.2-.4 1.2-.4 1.2-.5 1-.4 1.3-.3 1.2-.4 1-.3 1.2-.4.3 1-1.2.3-1 .3-1.3.4-1 .4-1.3.5-1.2.4-1.2.3-1.2.4-1 .4-1.2.6-1.2.4-1 .4-1.3.5-1 .3-1.3.5-1 .4-1.2.5-1 .4-1 .6-1.2.5-1 .5-1 .5-1 .5-1 .5-.8.5-1 .4-.8.4-.8.5-.8.4-.7.5-.7.4zm4.4 26-.8.5-1.3-1.7-1-1.5-1-1.5-1-1.4-1-1.3-.8-1.2-.8-1.2-.7-1-.6-1-.7-1-.4-1-.5-1-.4-.7-.2-1-.2-.7v-.7l-.2-.7v-1.4l.2-.6.2-.6.2-.6.3-.6.4-.6.5-.5.5-.5.5-.5.6-.6.7-.5.7-.7.7-.6.7-.7.6 1-.8.5-.7.6-.7.6-.5.6-.6.5-.6.5-.5.6-.5.5-.3.4-.3.5-.3.5v.5l-.2.6v2.2l.3.8.3.7.4.8.4.8.4 1 .6 1 .5 1 .7 1 .7 1.3 1 1.2.7 1.3 1 1.4 1 1.5 1 1.5 1.3 1.7zm1 3-1-.3v-1h-.2v-.2l-.2-.2v-.2h-.2v-.4l.7-.7.2.2v.4h.2v.2l.2.2v.2l.2.2v.4h.2v1.4zm.2 11.6-1-.5v.6l-.2-.4-.2-.5v-.4l-.2-.4v-.6l-.2-.4v-.5l-.2-.4v-5.4l.2-.4v-.7l.2-.4v-.5l.2-.3v-.4l.2-.2 1 .3v.2l-.2.2v.6l-.2.2v.6l-.2.3v1.1l-.2.4v5.1l.2.4v.8l.3.4v.4l.2.4zv.4zm0-.4v.4zm-5 1v1zh.2l.2-.2h1.4v.2h1.5l.2-.2h.2v-.2h.2v-.2l.2-.2.2-.3 1 .6-.2.2-.2.2v.2l-.2.2h-.2v.2l-.3.2h-.4l-.2.2h-.3v.2h-3v-1zm0 1v-1l.6.2-.5.7zm.6-.8.2.7h-.7l.6-.6z"/>
<path fill="#edb92e" d="M468 132.2q.3-3.6-.3 1.6-.5-1-1.4-1-1.6-.1-1.8 5.2l.2 2.8c-33-.7-52.7 4.3-57.7 14-4.2 7.8 3 21 13.6 36 1.3 1.8 1.2 1.6 0 3-1.8 2.3-3.8 6-2.3 9.2a24 24 0 0 1-21 1.5c-1-3-3.4-4.4-5.4-5.8-.5-.2-2-1-2-1.4l-10.2-31.6c-9.5-30.7 75.3-33.5 88.3-33.5"/>
<path fill="#21231e" d="m467.3 134 1-.4-1 .2V132h.2v-1.2l.2-.2.6-.3.3.3v1.6h-1V131l.4.2h.6v-.2 1l-.2.2v1.8h-1zm1 0-.2 1.6-.7-1.5h1zm-2-.7v-1h.7v.2h.4v.2h.2v.2h.2v.2h.2v.2h.2v.2l-1 .5v-.2h-.2v-.2h-.2v-.2zM465 138h-1v-1.8l.2-.3v-.9l.2-.3v-.7h.2v-.3l.2-.3.2-.3.2-.2h.2v-.2h.2v-.2h.5v1h-.2v.2h-.2v.2l-.2.2v.3l-.2.3v.6l-.2.2v2l-.2.3v.4zm-.3 3.3v-1l-.5.5v-2.3h-.2v-.4l1-.2v1.8l.2.2v1zm.5-.5v.5h-.5zM407.4 155l-1-.5.7-1 .7-.8.7-1 .8-.7 1-.8 1-.8 1-.8 1-.7 1.3-.7 1.2-.7 1.4-.6 1.6-.6 1.5-.5 1.7-.7 1.7-.5 1.8-.4 2-.5 1.8-.5 2-.3 2.2-.4 2.2-.3 2.2-.2 2.4-.3 2.4-.2 2.5-.2h2.5l2.7-.2h2.7l2.8-.2h9v1H453l-2.8.2h-2.6l-2.6.2-2.5.2-2.4.2-2.3.3-2.2.2-2.2.3-2 .4-2 .3-2 .4-1.8.4-1.8.4-1.7.5-1.6.5-1.5.6-1.5.5-1.3.5-1.3.7-1.2.6-1 .7-1 .7-1 .7-1 .7-.6.8-.7.8-.6.8-.6 1zm13.6 35.5-.8.6-1-1.3-1-1.4-1-1.4-1-1.5-.8-1.3-.8-1.4-1-1.3-.7-1.3-.8-1.3-.8-1.4-.7-1.2-.7-1.3-.6-1-.6-1.3-.5-1.2-.5-1.2-.5-1.2-.4-1-.5-1-.3-1.2-.3-1-.3-1-.2-1.2v-1l-.2-1V158l.3-.8.3-1 .2-.7.3-.8 1 .5-.4.7-.2.7-.2.8-.2.8v4.5l.2 1 .3 1v1l.5 1 .3 1.2.4 1 .5 1.2.5 1 .5 1.2.6 1.2.6 1.2.6 1.3.7 1 .7 1.4.8 1.3.8 1.3.8 1.3 1 1.3.8 1.4 1 1.3.8 1.4 1 1.4 1 1.5zm0 3.8-.8-.7.2-.3.2-.2h.2v-.2l.2-.2v-.4l-.2-.2v-.2h-.2v-.3h-.2v-.3h-.2l.8-.7.2.3.2.3v.2h.2v.4h.2v.2l.2.2v1l-.2.2v.2h-.2v.2l-.2.2-.2.2-.2.3zm-2.5 9-.4-.8-.2.7v-.3l-.2-.5v-.3l-.2-.3v-3.5l.2-.3v-.3l.2-.4.2-.3v-.3l.2-.3.2-.3v-.3l.3-.2v-.3l.3-.2.2-.3v-.2l.3-.3.2-.2v-.3l.3-.2.2-.2.8.7-.2.2-.2.2v.2h-.3v.3l-.3.3-.2.2v.3l-.3.3v.3l-.2.2-.2.3v.7l-.2.2v.2l-.2.3v.6l-.2.4v2.7l.2.3.2.3-.3.6zm.3-.5v.4l-.3.2zm-22 1.8 1-.3-.2-.3.6.2.7.3.5.2.6.2h.8l.6.2.6.2h.7l.6.2h5.7l.7-.2h.5l.7-.3h.6l.7-.2.6-.2.7-.2.7-.2.6-.2.6-.3.6-.3.6-.2.7-.4.6-.3.5 1-.6.2-.7.4-.6.4-.7.2-.6.3-.7.2-.6.2-.6.2-.7.2-.6.2h-.6l-.7.3h-.7l-.6.2h-.7l-.7.2h-5l-.7-.2h-.7l-.6-.3h-.7l-.7-.3-.6-.3-.7-.3-.6-.2-.8-.3-.3-.4zm.4.3-.2-.2v-.2zm-5.6-5.8.6-1 .2.2.2.2h.2l.2.2.2.2h.2l.2.2v.2h.3v.3h.3l.2.3h.2l.2.3.3.3.2.2.2.2.2.2v.2l.3.2v.2l.3.2.2.2v.2l.3.3.2.2.2.2v.2l.3.3v.3l.2.3-1 .3-.2-.2v-.3h-.2v-.3l-.2-.3-.2-.2v-.2l-.2-.2-.2-.2v-.2l-.3-.2-.2-.2-.3-.3-.2-.2-.3-.3h-.2l-.2-.3v-.2l-.3-.2h-.2v-.3h-.3l-.2-.2h-.2l-.2-.2h-.2l-.2-.3h-.2zh-.2zm-2-1.7.8-.3h.2v.2h.2l.2.2h.2v.2h.4v.2h.2l.2.2h.2l-.6 1-.2-.2h-.2v-.2h-.4v-.2h-.2l-.2-.2h-.2v-.2h-.2v-.2h-.2v-.2h-.2v-.2zm-10.2-31.7 1-.3.2 1 .3 1 .2.8.3 1 .3 1 .3.8.4 1 .3 1 .3 1 .3 1 .3 1 .3.8.2 1 .4 1 .3 1 .2 1 .3 1 .3 1 .4 1 .3 1 .3 1 .3 1 .5 1 .3 1 .3 1 .5 1 .3 1 .3 1 .4 1.2.4 1 .3 1 .4 1.2-1 .3-.3-1-.2-1.2-.3-1-.4-1-.2-1-.3-1-.3-1.2-.4-1-.3-1-.3-1-.4-1-.3-1-.3-1-.3-1-.4-1-.4-1-.3-1-.4-1-.3-1-.3-.8-.3-1-.4-1-.3-1-.3-1-.3-.8-.3-1-.2-1-.3-1-.3-.8-.3-1-.4-.8-.2-1zm88.2-33.6h1l-.5.5h-5.4l-2.5.2h-2.8l-3 .2-3.3.2-3.5.2-3.7.3-3.8.3-4 .4-4 .5-4 .6-4.2.6-4 .7-4.2 1-4 .8-4 1-3.7 1-3.7 1.3-3.4 1.4-3.3 1.4-3 1.5-2.6 1.6-2.3 1.7-2 2-1.6 1.8-1.2 2.2-.8 2.2-.4 2.3v2.5l.7 2.7-1 .3-.6-2.8v-2.8l.3-2.6 1-2.4 1.2-2.2 1.8-2 2-2 2.5-2 2.7-1.6 3-1.5 3.3-1.6 3.5-1.3 3.6-1 4-1.2 3.8-1 4-1 4-.7 4.2-.6 4.2-.6 4-.6 4-.5 4-.4 4-.4 3.7-.4 3.5-.2 3.3-.2 3-.2h3l2.4-.2h5.4l-.6.4zm1 0v.5h-.5l.7-.5zm-.5 0h-.4zm.7 0v.5h-.6z"/>
<path fill="#fff" d="M405 190.2c3.5 0 6.4 2.8 6.4 6.4 0 3.5-3 6.4-6.4 6.4s-6.4-3-6.4-6.4c0-3.6 3-6.4 6.4-6.4"/>
<path fill="#21231e" d="M412 196.6h-1a6 6 0 0 0-3.4-5.3 6 6 0 0 0-2.6-.6v-1c2.3 0 4.6 1.2 5.8 3.2a7 7 0 0 1 1 3.6zm-7 7v-1c2.2 0 4.3-1.4 5.2-3.4a6 6 0 0 0 .7-2.6h1c0 2.3-1.4 4.6-3.4 6a7 7 0 0 1-3.6 1zm-7-7h1c0 2.2 1.4 4.3 3.4 5.3a6 6 0 0 0 2.6.5v1a7 7 0 0 1-5.8-3.3 7 7 0 0 1-1-3.6zm7-7v1a6 6 0 0 0-5.2 3.3 6 6 0 0 0-.7 2.6h-1c0-2.4 1.4-4.7 3.4-6a7 7 0 0 1 3.6-1z"/>
<path fill="#fff" d="M350.8 203.6c3.2 0 6 2.7 6 6s-2.8 6-6 6-6-2.7-6-6 2.7-6 6-6"/>
<path fill="#21231e" d="M357.2 209.6h-1c0-2-1-4-2.8-4.8a5 5 0 0 0-2.6-.7v-1a7 7 0 0 1 5.4 3 7 7 0 0 1 1 3.6zm-6.4 6.4v-1c2 0 4-1.2 4.8-3a6 6 0 0 0 .6-2.4h1c0 2-1.2 4.3-3 5.4a6 6 0 0 1-3.4 1m-6.5-6.4h1c0 2 1.2 4 3 4.8q1.2.6 2.5.6v1a7 7 0 0 1-5.5-3 7 7 0 0 1-1-3.4m6.5-6.5v1c-2 0-4 1.3-5 3a6 6 0 0 0-.5 2.6h-1c0-2.2 1.2-4.4 3-5.5a6 6 0 0 1 3.5-1z"/>
<path fill="#fff" d="M345 192.7c3.4 0 6 2.7 6 6s-2.6 6-6 6c-3.2 0-5.8-2.7-5.8-6s2.6-6 6-6z"/>
<path fill="#21231e" d="M351.5 198.7h-1c0-2-1.2-4-3-5a5 5 0 0 0-2.4-.5v-1q3.6.1 5.5 3a7 7 0 0 1 1 3.5zM345 205v-1c2 0 4-1 4.8-2.7a6 6 0 0 0 .7-2.6h1c0 2.2-1.2 4.3-3 5.5a6 6 0 0 1-3.4 1zm-6.3-6.3h1c0 2 1.2 4 3 4.8a5 5 0 0 0 2.4.6v1c-2 .2-4.2-1-5.3-3a7 7 0 0 1-1-3.3zm6.4-6.5v1c-1.8 0-3.7 1-4.6 2.8a6 6 0 0 0-.7 2.7h-1c0-2.2 1.2-4.4 3-5.5a6 6 0 0 1 3.4-1z"/>
<path fill="#fff" d="M339.8 181.7c3.3 0 6 2.7 6 6s-2.7 6-6 6-6-2.7-6-6 2.7-6 6-6"/>
<path fill="#21231e" d="M346.2 187.7h-1c0-2-1.2-4-3-5a5 5 0 0 0-2.4-.5v-1c2.2 0 4.3 1.2 5.4 3a7 7 0 0 1 1 3.5m-6.4 6.4v-1q3.2 0 4.7-2.7.7-1.2.7-2.6h1c0 2-1 4.3-3 5.4a6 6 0 0 1-3.4 1zm-6.4-6.3h1c0 2 1 4 3 4.8q1 .6 2.4.6v1a6 6 0 0 1-5.4-3 7 7 0 0 1-1-3.3zm6.4-6.5v1c-2 0-4 1.2-4.8 3a6 6 0 0 0-.6 2.5h-1c0-2.2 1-4.4 3-5.5a6 6 0 0 1 3.4-1"/>
<path fill="#edb92e" d="M444.3 202.2c3.4-.3 2.5 5.8 2 7.2q-1.3 2.6-3 .2c-.8-1.3-2.4-7.2 1-7.5z"/>
<path fill="#21231e" d="m446.6 209.6-1-.4h.2v-.7l.2-.3v-.5l.2-.3V204h-.2v-.3l-.2-.2v-.2l-.2-.2h-.2l-.3-.2h-.2l-.2-.2h-.3v-1h.7l.3.2h.3l.3.2v.2l.3.3.2.2.2.3v.2l.2.3v.7l.2.3v3.7l-.2.3v.5l-.2.3v.5h-.2zm-3.7.3.8-.7.2.3v.2h.2v.2h.2v.2h.7l.2-.2v-.2h.2v-.2h.2v-.3l1 .3v.2l-.2.2v.3h-.2v.2l-.2.2-.2.2h-.4v.2H444v-.2h-.2v-.2h-.2v-.2h-.2v-.3h-.2v-.3h-.3zm1.2-8.4v1h-.4v.2h-.3v.2h-.3v.3l-.2.2v.4h-.2v3.2l.2.2v.6l.2.2v.3l.2.2v.2l.2.2v.2h.2l-1 .7v-.5l-.2-.2v-.2l-.2-.4v-.2l-.2-.3v-.2l-.2-.3v-.7l-.2-.3v-3l.2-.3v-.3l.3-.3.2-.2.2-.3h.2l.2-.3.3-.2h.4l.2-.2z"/>
<path fill="#fff" d="M444.5 205.5c8-.6 6 13.8 4.4 17q-2.8 6.3-6.7.5c-2-3-5.8-17 2.2-17.5z"/>
<path fill="#21231e" d="m449.4 222.7-1-.4.2-.3.2-.4v-.4l.3-.5.2-.5v-.6l.2-.6.2-.7V217l.2-.7v-5.1l-.3-.7v-.6l-.3-.7-.3-.6-.3-.5-.3-.5-.3-.4-.3-.4-.4-.4-.5-.2-.5-.2-.5-.2h-1.4v-1h1.5l.6.2.7.2.5.4.6.4.4.4.4.5.4.7.3.6v.7l.3.6.2.7v.7l.3.8v6.3l-.3.7v.7l-.2.6v.6l-.3.6v.5l-.3.5v.4l-.3.3zm-7.5.5.8-.5.2.3.2.3.3.3.2.3h.2v.4h.3l.2.3.2.2h.4l.2.2h1v-.2h.3l.2-.3v-.2l.2-.2.2-.2h.2l.2-.4v-.3l.3-.3.3-.3.2-.4 1 .4-.3.4-.2.5-.2.3-.2.4-.2.3-.2.3-.2.2-.2.2-.2.3-.3.2h-.2v.3h-.4l-.2.2H445l-.4-.2h-.2l-.3-.3v-.2l-.4-.2-.2-.2-.2-.2-.3-.2-.3-.3-.3-.4-.2-.4zm2.5-17.2v-1zh-.6l-.7.2-.5.2-.5.3-.4.3-.5.4-.3.4-.3.4-.3.6-.2.5v.6l-.2.5v.7l-.2.7v.6l.2.7v1.4l.2.7v.8l.3.7v.6l.3.7.2.6.2.5.2.6.2.7.2.5.2.4.2.4.2.4.2.3-1 .5v-.3l-.3-.5-.2-.4-.2-.4v-.6l-.4-.5-.2-.7-.2-.6-.2-.7-.2-.7v-.7l-.3-.6v-.8l-.2-.7V213l-.2-.7v-.8l.2-.7v-.6l.2-.7v-.7l.4-.6.2-.6.4-.6.4-.5.4-.5.5-.4.6-.3.7-.3.7-.2h.8v1zm0-1v1z"/>
<path fill="#edb92e" d="M379.7 210.8c3.3-1 4 5 3.6 6.6q-.5 2.9-2.7 1c-1-1.2-4-6.5-1-7.6z"/>
<path fill="#21231e" d="m383.8 217.5-1-.2v-2.8l-.2-.3v-.7l-.2-.3v-.3l-.2-.2v-.3l-.3-.2-.2-.2-.3-.3-.3-.3h-.3l-.3-.2h-.6l-.4-1h1.5l.2.2.3.2.2.2.3.2.2.3.2.2v.3l.3.3v.4l.2.3v.3l.2.3v.3l.2.4v.6l.2.3v2.5zm-3.5 1 .7-.6h.2v.2h.2l.2.2h.2v.2h.4l.2-.2v-.2h.2v-.6h.2v-.3l1 .2v.4h-.2v.4l-.2.3v.2h-.2l-.2.2-.2.2h-.2l-.2.2h-1v-.2h-.3l-.2-.2h-.2v-.2h-.2zv-.2zm-.7-8.2.3 1h-.3l-.2.2h-.2v.2l-.2.2v.2l-.2.2v1.8l.2.4v.3l.2.3v.2l.2.3.2.3v.3l.2.3.2.3v.2l.3.2v.2l.2.2.3.3.2.2-.7.6h-.2v-.4l-.3-.2v-.2l-.3-.2v-.3l-.3-.2v-.2l-.2-.3v-.3l-.3-.3v-.4l-.2-.3v-.3l-.3-.3v-.7l-.2-.3V212l.3-.2.2-.3.2-.3.3-.2.2-.2h.2l.4-.3z"/>
<path fill="#fff" d="M380.7 214c7.7-2.5 9.2 12 8.4 15.5q-1.3 6.6-6.2 2c-2.6-2.4-9.7-15-2-17.5z"/>
<path fill="#21231e" d="m389.6 229.6-1-.2v-.8l.2-.4v-2.9l-.2-.7V223l-.3-.7v-.7l-.3-.8-.2-.7-.2-.6-.2-.7-.3-.7-.2-.6-.3-.6-.3-.4-.4-.5-.3-.4-.4-.3-.4-.4-.4-.4-.5-.2h-.5l-.5-.2h-1.1l-.6.3-.4-1 .7-.2h2.2l.7.2.7.2.5.4.5.5.5.4.4.5.4.5.4.6.3.7.3.6.3.6.3.7.2.8.2.8.2.7v.8l.3.7v1.5l.2.7v4.4zm-7 2.3.5-1 .5.4.2.2.3.3h.3l.3.3h.2l.3.3h.3l.2.2h1.4l.2-.2.2-.2.2-.3.3-.3v-.6l.2-.2v-.3l.2-.4v-.2l.2-.4 1 .2v.4l-.2.4v.4l-.2.4-.2.3v.3l-.2.3-.2.4v.3l-.3.2h-.2v.3l-.3.2h-.2l-.2.3h-.8l-.3.2h-.5l-.3-.2h-.2l-.3-.2h-.4l-.3-.3-.3-.2h-.3l-.3-.3-.3-.3-.2-.2-.3-.3zm-2-18.5.3 1-.7.2-.6.3-.4.3-.4.4-.4.4-.3.5-.2.5v.5l-.2.6v2.5l.2.6.2.7.2.6.2.7.3.7v.7l.4.6.3.7.4.6.4.6.3.6.4.6.4.5.3.4.3.4.4.4.2.4.3.3-.5 1-.3-.4-.3-.3-.4-.4-.4-.5-.3-.5-.4-.5-.4-.6-.3-.7-.5-.6-.3-.6-.4-.6-.3-.6-.3-.7-.3-.7-.3-.7-.3-.7-.2-.8-.2-.8v-.7l-.2-.7V218l.2-.7.2-.6.2-.6.3-.5.4-.5.6-.5.6-.4.7-.2.6-.3zm0 .5v-.5z"/>
<path fill="#edb92e" d="M464.2 137.8c-17.2-1.6-35 .2-52.3 7-14.8 6-13.4 23.2 4.6 47q-2.6 4.6-2.7 11h4.8c-1.3-2.8 0-6.4 1.8-9 1-1.5 1.3-1.2 0-3-10.7-15-17.8-28.2-13.6-36 5-9.7 24.6-14.7 57.7-14q0-1.4-.2-2.7l-.3-.2z"/>
<path fill="#21231e" d="m412 145.4-.3-1 1.7-.6 1.6-.6 1.7-.6 1.6-.5 1.6-.4 1.6-.5 1.6-.4 1.7-.4 1.5-.4 1.7-.4 1.6-.4 1.7-.3 1.6-.3 1.8-.3h1.6l1.7-.3 1.7-.2 1.7-.2 1.6-.2h3.3l1.6-.2h11.5l1.6.2h1.6l1.6.3v1l-1.7-.2h-4.9l-1.6-.2h-9.7l-1.6.2H443l-1.5.3-1.7.2-1.6.2-1.6.2H435l-1.7.4-1.6.3-1.7.3-1.6.4-1.6.3-1.7.5-1.5.4-1.6.4-1.8.5-1.6.6-1.6.6-1.7.6-1.6.6-1.6.6zm5 46.7-1-.4.2.5-1.7-2-1.5-2.3-1.5-2-1.3-2.2-1.3-2-1.2-2-1-2-1-2-1-2-.7-1.7-.6-1.8-.5-1.8-.6-1.7-.4-1.6-.3-1.7-.2-1.6v-4.4l.2-1.3.3-1.3.4-1.2.5-1.2.5-1.2.7-1 .8-1 .8-1 1-.7 1-.8 1.3-.8 1.4-.6 1.3-.5.4 1-1.2.5-1.2.6-1 .7-1 .8-1 1-1 .8-.6 1-.7 1-.5 1-.5 1-.3 1.2-.3 1.2-.2 1.2v3.8l.2 1.5.3 1.7.3 1.6.5 1.6.6 1.6.7 1.8.8 1.8 1 2 .8 1.8 1 2 1.2 2 1.2 2 1.4 2 1.4 2.2 1.5 2 1.7 2.3zm0-.5.2.3-.2.3v-.5zm-3 11v1l-.6-.6v-2.5l.2-.4v-1l.2-.4v-.7l.2-.5v-.4l.2-.2v-.4l.2-.3v-.3l.2-.3v-.4l.2-.3v-.3l.2-.3v-.3l.3-.3v-.3l.2-.2.2-.3v-.3l.3-.3v-.4l1 .5v.4l-.3.2v.3l-.2.2-.2.3v.3l-.2.3v.4l-.2.3v.3l-.2.4v.3l-.2.3v.3l-.2.4v.7l-.2.3v.8l-.2.4v.8l-.2.4v1.4l-.2.4v.7l-.5-.6zm0 1h-.6v-.6l.5.5zm4.3-.4 1-.4-.5.8h-4.6v-1h4.6l-.5.7zm1-.4.3.7h-.8l.4-.7zm1-9 .7.6-.2.2v.3l-.2.2-.2.2v.2l-.3.3v.4l-.2.3-.2.2v.3l-.2.3v.2l-.2.3v.7l-.2.2v.5l-.2.3v2.2l.2.3v.4l.2.2-1 .5v-.5l-.2-.3v-.7l-.2-.3v-2.7l.2-.3v-.3l.2-.2v-.3l.2-.3v-.3l.2-.4v-.3l.2-.3.2-.3v-.2l.2-.3.2-.3v-.3l.3-.3v-.3h.3l.2-.3zm0-2.5.7-.5.2.3.2.3v.2h.2v.4h.2v.4l.2.2v.5l-.2.2v.2h-.2v.2l-.2.2v.2h-.2v.3l-.2.2-.8-.6v-.2l.2-.2.2-.2v-.2h.2v-.4h.2v-.2h-.2v-.2l-.2-.2v-.3h-.2v-.3h-.2zm-13.8-36.5 1 .5-.4.7-.2.7-.2.8-.2.8v4.5l.2 1 .3 1v1l.5 1 .3 1.2.4 1 .5 1.2.5 1 .5 1.2.6 1.2.6 1.2.6 1.3.7 1 .7 1.4.8 1.3.8 1.3.8 1.3 1 1.3.8 1.4 1 1.3.8 1.4 1 1.4 1 1.5-.8.6-1-1.3-1-1.4-1-1.4-1-1.5-.8-1.3-.8-1.4-1-1.3-.7-1.3-.8-1.3-.8-1.4-.7-1.2-.7-1.3-.6-1-.6-1.3-.5-1.2-.5-1.2-.5-1.2-.4-1-.5-1-.3-1.2-.3-1-.3-1-.2-1.2v-1l-.2-1V158l.3-.8.3-1 .2-.7.3-.8zm57.7-13.7h1l-.5.5h-14.5l-2.6.2H445l-2.5.3-2.4.2-2.3.3-2.2.2-2.2.3-2 .4-2 .3-2 .4-1.8.4-1.8.4-1.7.5-1.6.5-1.5.6-1.5.5-1.3.5-1.3.7-1.3.6-1 .7-1 .7-1 .7-.8.7-.8.8-.7.8-.6.8-.6 1-1-.5.7-1 .7-.8.7-1 .8-.7 1-.8 1-.8 1-.8 1-.7 1.2-.7 1.3-.7 1.4-.6 1.6-.6 1.5-.5 1.7-.7 1.7-.5 1.8-.4 2-.5 1.8-.5 2-.3 2.2-.4 2.2-.3 2.2-.2 2.4-.3 2.4-.2 2.5-.2h2.5l2.7-.2h2.7l2.8-.2h9l-.6.6zm1 0v.5h-.5zm-1-2.3.7-.7v1.9h.2v1h-1v-2.3l-.2-.2v-.4.3zm.7-.7v.3-.2zm-1.2-.4.8.7v-.6.2h.2v.2l-.7.7v-.4h-.2v-.6zm0 .7-.3-.2.3-.4zm.8 0-.8-.6h.4zm-.4-.7h1l-.6.8-.4-.7z"/>
<path fill="#fff" d="M380.6 142.7c3.4 0 6 2.7 6 6s-2.6 6.3-6 6.3-6.2-2.7-6.2-6.2a6 6 0 0 1 6.2-6z"/>
<path fill="#21231e" d="M387.2 148.8h-1c0-2-1.2-4-3-5a6 6 0 0 0-2.6-.6v-1c2.2 0 4.5 1.2 5.6 3a7 7 0 0 1 1 3.6m-6.6 6.7v-1c2 0 4-1.2 5-3a7 7 0 0 0 .6-2.7h1a7 7 0 0 1-3 5.7 7 7 0 0 1-3.6 1m-6.7-6.7h1c0 2 1.2 4.2 3 5a6 6 0 0 0 2.6.7v1a7 7 0 0 1-5.6-3 7 7 0 0 1-1-3.7m6.6-6.7v1.2c-2 0-4 1.2-5 3a6 6 0 0 0-.6 2.6h-1c0-2.2 1-4.4 3-5.6a7 7 0 0 1 3.6-1z"/>
<path fill="#fff" d="M392.6 138.7c3.4 0 6.2 2.8 6.2 6.2 0 3.3-2.8 6-6.2 6a6 6 0 0 1-6-6c0-3.5 2.6-6.3 6-6.3z"/>
<path fill="#21231e" d="M399.3 145h-1c0-2.2-1.3-4.3-3.2-5.2a6 6 0 0 0-2.4-.6v-1a7 7 0 0 1 5.7 3 7 7 0 0 1 1 3.7zm-6.7 6.6v-1c2 0 4-1.3 5-3a6 6 0 0 0 .7-2.7h1c0 2.2-1.2 4.4-3.2 5.6a7 7 0 0 1-3.4 1zM386 145h1c0 2 1.2 4 3 5a6 6 0 0 0 2.6.6v1a7 7 0 0 1-5.6-3.2 7 7 0 0 1-1-3.5zm6.6-6.8v1c-2 0-4 1.2-5 3a6 6 0 0 0-.6 2.7h-1c0-2.4 1.2-4.7 3.2-5.8a7 7 0 0 1 3.4-1z"/>
<path fill="#edb92e" d="m394.2 144 2 2.4q-14.6 8.1-13 16.7.1 1.4 9.8 31.7 6.7 4.7 10 8.4c-.2.4.8 1.2.5 1.5.7 3-2.8 2.4-5 1.7-1.2-3-4.6-6-6.6-7.5-.5-.2-2-1-2-1.4l-10.2-31.6c-3-9.8 3.6-16.8 14.4-21.7z"/>
<path fill="#21231e" d="m396.3 147-.5-1v.7h-.2v-.2h-.2v-.2l-.2-.2h-.2v-.2l-.2-.2v-.2h-.2v-.2h-.2v-.2l-.2-.2-.2-.2v-.2h-.2l.8-.7.2.2h.2v.4h.2v.2h.2v.2l.2.2.2.2v.2h.2v.2h.2v.2l.2.2v1zm.2-1 .3.6-.5.3zm-12.7 17-1 .2v-3.9l.2-.6.2-.5.2-.6.2-.5.3-.5.2-.5.3-.6.4-.5.3-.6.4-.6.5-.5.4-.6.6-.5.5-.5.6-.5.6-.6.5-.5.7-.4.7-.5.6-.5.8-.5.8-.5 1-.5.7-.5.8-.5.5 1-1 .4-.7.5-.8.4-.8.5-.8.4-.7.5-.7.4-.6.5-.7.4-.6.5-.6.4-.5.5-.6.4-.5.6-.5.5-.4.5-.3.5-.3.5-.3.5-.2.5-.2.5-.2.5-.2.5-.2.5v.5l-.2.5v3.1zm9.5 31.3-.6.8-.2-.2-.6-1.8-.7-1.8-.5-1.8-.6-1.7-.5-1.6-.5-1.5-.5-1.5-.5-1.5-.4-1.4-.4-1.2-.4-1.3-.4-1.3-.4-1-.3-1.3-.4-1-.3-1-.3-1-.3-1-.3-.8-.2-.8-.2-.8-.2-.6-.2-.7v-.5l-.3-.5v-.5l-.2-.4v-.8h-.2v-.3h1v.3l.2.3v.4l.2.3v.5l.2.5.2.6.2.7.2.7.2.7.2 1 .3.7.2 1 .2 1 .3 1 .3 1 .4 1 .4 1.2.3 1.2.3 1.3.5 1.3.4 1.4.5 1.5.4 1.5.7 1.6.5 1.6.5 1.7.6 2 .6 1.7.5 1.8-.2-.2zm-.6.8-.2-.2.2.3zm10.7 8.4-.7-.6v.6l-.2-.2-.2-.2-.3-.3-.2-.2-.2-.2-.3-.3-.2-.2-.2-.2-.2-.3-.3-.2-.3-.2-.2-.2-.3-.3-.3-.3-.3-.2-.4-.3-.3-.2-.4-.3-.4-.3-.3-.2-.4-.3-.4-.3-.4-.3-.3-.3-.5-.3-.4-.2-.3-.3-.4-.2-.4-.3-.5-.3-.4-.3-.3-.3.6-.7.4.3.4.3h.5l.4.4.3.3.4.3.4.3.5.3.3.2.4.3.3.4.4.3.2.2.4.2.3.3.2.2.3.3.3.3.3.2.4.3.3.2.3.3.3.3.2.2.3.3.3.3.3.3.2.2.3.2.2.3.2.2.2.3v.6zm0-.6.3.3-.3.4v-.6zm.6 1.6-1 .2.2-.5v.2h-.2v.2-.2l-.2-.2v-.2h-.2v-1.2l.8.6v-.2h.2v.2l.2.2v.2l.2.2v.7l-.2.2.2-.6zm-1 .2v-.3l.2-.2-.2.6zm-5 1.8 1-.4-.4-.3h.4l.2.2h.7l.4.2h2.3v-.2h.2v-1.4l1-.2v1.6l-.2.3v.2l-.2.2h-.2l-.2.2h-.4l-.2.2h-3l-.3-.2h-.5l-.3-.2h-.5l-.3-.4zm.2.3h-.2v-.3zm-6.6-7.5.6-1 .2.3h.2l.2.3h.2l.3.3.2.3.2.2.2.2.2.2h.2l.2.3.3.2v.3l.4.2.2.3.2.2.3.3.3.2.2.3.3.3.2.2.2.3.2.4.2.3.2.3.2.2.2.3v.3l.3.3v.4l.3.3v.3l-1 .4v-.3l-.2-.4-.2-.3v-.2l-.3-.2v-.3l-.2-.2-.2-.3-.2-.3-.2-.2-.2-.3-.2-.2-.2-.3-.3-.2-.2-.3v-.2l-.3-.3-.3-.2-.2-.2-.2-.2-.3-.2-.2-.2-.2-.2h-.2l-.2-.3h-.2l-.2-.3h-.2l-.2-.3h-.2l-.2-.2zm.6-1 .3.3-.3-.2zm-2.7-.7 1-.3.2.2h.2v.2h.2v.2h.4v.2h.2l.2.2h.2l-.6 1-.2-.2h-.2v-.2h-.4v-.2h-.2l-.2-.2h-.2v-.2h-.2v-.2h-.2v-.2h-.2v-.2zm-10-31.7.8-.3.3 1 .3 1 .2.8.3 1 .3 1 .3.8.4 1 .3 1 .3 1 .3 1 .3 1 .3.8.2 1 .4 1 .3 1 .2 1 .3 1 .3 1 .4 1 .3 1 .3 1 .3 1 .5 1 .3 1 .3 1 .5 1 .3 1 .3 1 .4 1.2.4 1 .3 1 .4 1.2-1 .3-.3-1-.2-1.2-.3-1-.4-1-.2-1-.3-1-.3-1.2-.4-1-.3-1-.3-1-.4-1-.3-1-.3-1-.3-1-.4-1-.4-1-.3-1-.4-1-.3-1-.3-.8-.3-1-.4-1-.3-1-.3-1-.3-.8-.3-1-.2-1-.3-1-.3-.8-.3-1-.4-.8-.2-1zm15-22-.7.5h.6l-1 .6-1 .4-1 .5-.8.4-1 .5-.7.4-1 .5-.7.5-.8.5-.7.6-.7.6-.5.6-.7.6-.5.6-.6.7-.5.6-.4.7-.4.6-.4.7-.3.7-.3.7-.3.7v.8l-.2.7v.7l-.2.8v2.6l.3.8v1l.3.7-1 .3-.2-1v-.8l-.3-1V159l.2-1 .2-.7.2-.6.3-.8.4-.7.5-1 .4-.6.4-.7.6-.7.5-.7.6-.6.8-.6.6-.6.8-.6.7-.6.7-.5.8-.6 1-.5.7-.5 1-.5 1-.5.8-.5 1-.5 1-.5.6.2zm-.5-.3.4-.2.2.4z"/>
<path fill="#edb92e" d="m356 217-.4 2q-4.2.8-7.3.3 5.1-4.9 7.6-2.4z"/>
<path fill="#21231e" d="m355 218.8.4-2 1 .2-.3 2-.3.4-.6-.6zm1 0v.5h-.3zm-8 .2.7.7-.3-1 .2.2h4.1l.3-.2h1l.2-.2h.7l.2-.2h.3l.2 1h-.8l-.4.2h-.5l-.4.2h-1.3v.2h-3.7l-.4-1zm.2 1-1-.3.8-.7zm8.2-3-1-.2.2.5v-.2h-.6v-.2h-.6l-.2-.2H353v.2h-.6l-.2.3-.2.2h-.3l-.2.2-.3.2-.2.2-.3.2-.3.2-.2.2-.3.2-.4.3h-.3l-.3.4-.3.3-.7-.7.3-.3.3-.3.3-.3.2-.2.3-.2.3-.2.3-.3h.4l.3-.3h.3l.2-.3h.3l.3-.3h.6l.3-.2h.5l.4-.2h1.3l.2.2h.3l.2.2h.2l.2.2.3.3v.5zm0-.5v.5zm-.5.4h.4-.5zm.3-.5.2.2v.3z"/>
<path fill="#edb92e" d="M355.6 212.3c1.8.4 2 .7 2.7 1 1 0 2.4 0 3.3-1 4-2.2 4 2 2.5 5-1 2.4-.5 5 .6 7 1.2 2.2 1 3.2 0 4l-1.6 1q-1.6 1.8-2-.6c-3.8-1.6-5-5.3-6.2-8.6-1.7-4.7-7.8-5.8.8-7.7z"/>
<path fill="#21231e" d="M358.4 212.7v1h-.7v-.2h-.4l-.2-.2h-.4l-.2-.2h-.8l-.3-.2.2-1h.4l.2.2h.4l.2.2h.4v.2h.8v.2zm3-.7.5 1v-.2l-.2.2h-.3v.2h-.2l-.2.2h-.2l-.2.2h-2.1v-1h2.2l.2-.2h.2v-.2h.2zm3 5.6-.8-.4v-.3l.3-.4v-.5l.2-.2v-.6l.2-.3v-2.2h-.2v-.2h-.2v-.2h-1.2l-.3.2-.3.2-.3.2-.6-1 .4-.2.3-.2h.5l.3-.2h1.8l.2.2.2.2v.2l.2.3v.4l.2.3v2.4l-.2.3v.3l-.2.4v.3l-.2.3v.3zm.6 6.3-1 .4v-.4l-.2-.2v-.4l-.2-.2v-.2l-.2-.2v-.5l-.2-.2v-.8l-.2-.2v-2.3l.2-.2v-.3l.2-.3v-.3l.2-.2 1 .4-.2.2v.4l-.2.2v.8l-.2.2v2l.2.2v.5l.2.2v.4h.2v.2l.2.2v.4h.2zm0 4.6-.6-1h.2v-.2h.2v-1.6l-.2-.3v-.3l-.2-.2v-.2l-.2-.2v-.2l.8-.5v.2l.2.2v.2l.2.2v.2l.2.2v.2l.2.3v1.7l-.2.2v.2h-.2v.2h-.2v.2l-.2.2zm-1.6 1-.8-.7v-.2h.2l.2-.2h.2v-.2h.4v-.2h.2v-.2h.4v-.2h.2l.6.8h-.2v.2h-.4v.2h-.2l-.2.2h-.2v.2h-.2zm-.8-.7v-.2zm-1.8 0 .4-.8.3.4v.5h.2v.2h.4v-.2h.2v-.2h.2l.8.6-.2.2-.2.2-.3.2h-.2v.2h-1.1l-.2-.2v-.2l-.2-.2v-.4h-.2v-.7zm.4-.8h.3v.4zm-7-8 1-.3.2.2v.3l.2.3v.4l.2.3v.3l.3.3.2.4v.3l.2.3.2.3v.3l.3.3v.2l.2.3v.2l.3.3.2.3.2.2v.3l.3.2.2.3.2.2.2.2.2.2h.2l.3.3.3.2.3.2.3.2h.3l.2.2-.4 1-.3-.2-.4-.2-.2-.2-.4-.2-.3-.2-.2-.3-.3-.3-.2-.2-.3-.3-.3-.2-.2-.3-.2-.3-.2-.3-.3-.4-.2-.3-.2-.3-.2-.3v-.4l-.2-.3v-.3l-.3-.3v-.3l-.3-.2v-.3l-.2-.4v-.2l-.2-.3-.2-.3v-.3l-.2-.4v-.3zm1.4-8.4v1l-.6.2-.7.2h-.6l-.5.3h-.4l-.4.3h-.3v.3l-.2.2v.2h-.2v.2l.2.3.3.2.2.3.2.2.2.3.3.2v.3l.4.3.2.3.3.5.2.3.2.4.3.4.2.4v.5l.3.4-1 .3v-.4l-.3-.5-.2-.4-.2-.3-.3-.3-.2-.3v-.2l-.4-.3-.2-.3-.3-.3v-.4l-.3-.2-.3-.3-.3-.4v-.2l-.2-.3-.2-.4v-.6l.3-.3v-.2l.3-.3h.3l.4-.3.4-.3.5-.2h.4l.7-.3.8-.2zm0 1v-1zm0-1"/>
<path fill="#edb92e" d="M357 212.5c3.5 1.2 4-.7 6-.6-.8 5-1.7 7.7-7 5-3-1.6-6.7.7-7.4 2.3-.3.6-2-.6-2.6-2-2.6-5.8 6.7-6.4 11-4.8z"/>
<path fill="#21231e" d="m363.6 212-1-.2.5.6H362v.2h-.3l-.2.2h-.2l-.3.2h-.3v.2h-.7l-.2.2h-2l-.4-.2h-.3l-.3-.2.3-1h.3l.3.2h.4l.2.2h1.3l.2-.2h.2l.2-.2h.5l.2-.2h.2l.3-.2h.5l.2-.2h.4l.6.6zm-.5-.6h.7v.6zm-7.2 6 .4-1 .5.4.5.2h.4l.4.3h.3l.4.2h1.7l.2-.2.3-.3.2-.3v-.2l.2-.2.2-.3v-.3l.2-.3v-.3l.2-.2v-.4l.2-.4v-.4l.2-.4v-.9l.2-.5 1 .2v.5l-.2.5v.8l-.2.5v.4l-.2.4v.4l-.3.4v.3l-.2.4-.2.4v.2l-.3.3-.2.3-.2.2-.3.2-.2.2h-.2l-.3.2h-.3l-.3.2h-1.6l-.4-.2-.4-.2h-.4l-.4-.3-.5-.3-.5-.3zm-6.8 2-1-.3h.2v-.3h.3v-.3l.3-.2v-.2l.3-.2h.3l.2-.3.2-.2h.3l.2-.3h.3l.2-.3h.3l.3-.2h.3l.2-.2h.3l.4-.2h2.3l.3.2h.3l.3.2h.2l-.4 1h-.3l-.2-.2h-.5l-.3-.2h-1.8l-.3.2h-.3l-.3.2h-.3l-.2.3h-.2l-.3.2h-.2l-.2.2h-.2v.2l-.2.2h-.2v.3h-.2v.2h-.2v.2zm-3.5-2 1-.3v.4h.2v.4h.2v.2l.2.2h.2v.2l.2.2h.2v.2h.4v.2l.8.5v.2l-.3.2h-1v-.2h-.2l-.3-.2h-.2v-.2l-.2-.2-.2-.2h-.2v-.3h-.2v-.2h-.2v-.3h-.2v-.4h-.2zm11.8-5.4-.3 1-.4-.2h-.5l-.3-.2h-.5l-.5-.2h-5l-.5.2-.4.2h-.4l-.4.3-.4.3-.3.2v.2l-.4.2-.2.2v.3l-.3.2v1.6l.3.4.2.5-1 .5-.2-.5-.2-.6V215l.2-.6.2-.4.2-.4.3-.3.2-.4.3-.3.4-.3.4-.2.4-.2.5-.2h.5l.5-.3h1.1l.5-.2h3.3l.6.2h.5l.4.2.5.2h.3zm0 .5v-.5z"/>
<path fill="#fff" d="M458.8 124.5c3.4 0 6.2 2.7 6.2 6 0 3.5-2.8 6.3-6.2 6.3s-6-2.8-6-6.2a6 6 0 0 1 6-6z"/>
<path fill="#21231e" d="M465.5 130.6h-1c0-2-1.3-4.2-3.3-5a6 6 0 0 0-2.4-.6v-1a7 7 0 0 1 5.7 3 7 7 0 0 1 1 3.6m-6.7 6.7v-1c2 0 4-1.2 5-3a6 6 0 0 0 .6-2.7h1c0 2.3-1 4.5-3 5.7a7 7 0 0 1-3.6 1m-6.6-6.7h1c0 2 1.3 4.2 3.2 5a6 6 0 0 0 2.4.7v1a7 7 0 0 1-5.6-3.2 7 7 0 0 1-1-3.4zm6.6-6.6v1c-2 0-4 1.2-5 3a6 6 0 0 0-.6 2.6h-1c0-2.2 1.2-4.4 3.2-5.6a7 7 0 0 1 3.4-1"/>
<path fill="#fff" d="M446.3 124.5a6 6 0 0 1 6 6c0 3.5-2.6 6.3-6 6.3s-6-2.8-6-6.2 2.6-6 6-6z"/>
<path fill="#21231e" d="M453 130.6h-1c0-2-1.3-4-3.2-5a6 6 0 0 0-2.5-.6v-1c2.3 0 4.5 1.2 5.6 3a7 7 0 0 1 1 3.6zm-6.7 6.7v-1c2 0 4-1.3 5-3a7 7 0 0 0 .6-2.7h1c0 2.3-1.3 4.5-3.2 5.7a7 7 0 0 1-3.5 1zm-6.6-6.7h1c0 2 1.2 4.2 3 5a6 6 0 0 0 2.6.7v1a7 7 0 0 1-5.6-3.2 7 7 0 0 1-1-3.4zm6.6-6.6v1c-2 0-4 1.2-5 3a6 6 0 0 0-.6 2.6h-1a7 7 0 0 1 3-5.6 7 7 0 0 1 3.6-1"/>
<path fill="#fff" d="M433.8 125.5a6 6 0 0 1 6 6c0 3.5-2.6 6.3-6 6.3s-6-2.8-6-6.2 2.6-6 6-6z"/>
<path fill="#21231e" d="M440.4 131.6h-1c0-2-1.2-4-3-5a6 6 0 0 0-2.6-.6v-1a7 7 0 0 1 5.6 3 7 7 0 0 1 1 3.6m-6.6 6.7v-1c2 0 4-1.3 5-3a6 6 0 0 0 .6-2.7h1a7 7 0 0 1-3 5.7 7 7 0 0 1-3.6 1m-6.6-6.7h1c0 2.2 1.3 4.3 3.2 5.2a6 6 0 0 0 2.4.5v1a6 6 0 0 1-5.6-3.2 7 7 0 0 1-1-3.4zm6.6-6.6v1c-2 0-4 1.2-5 3a6 6 0 0 0-.6 2.6h-1c0-2.3 1.3-4.6 3.3-5.7a7 7 0 0 1 3.3-1z"/>
<path fill="#fff" d="M422.3 127.7c3.3 0 6 2.8 6 6.2 0 3.3-2.7 6-6 6s-6.2-2.7-6.2-6 3-6.3 6.3-6.3z"/>
<path fill="#21231e" d="M429 134h-1a6 6 0 0 0-3.3-5.2 6 6 0 0 0-2.4-.6v-1c2.2 0 4.4 1.2 5.6 3.2a7 7 0 0 1 1 3.5zm-6.7 6.5v-1c2 0 4-1.2 5-3q.6-1.5.6-2.6h1c0 2-1.3 4.3-3.3 5.5a7 7 0 0 1-3.4 1zm-6.7-6.6h1q.2 3.2 3 4.8a5 5 0 0 0 2.7.7v1a7 7 0 0 1-5.7-3 7 7 0 0 1-1-3.6zm6.7-6.8v1c-2 0-4.2 1.3-5 3.2a6 6 0 0 0-.7 2.5h-1q.1-3.9 3.3-6a7 7 0 0 1 3.3-.8z"/>
<path fill="#fff" d="M346.3 159.4a6 6 0 0 1 6 6.2c0 3.4-2.6 6.2-6 6.2s-6-2.8-6-6.2a6 6 0 0 1 6-6.2"/>
<path fill="#21231e" d="M353 165.6h-1c0-2-1.3-4-3.2-5a6 6 0 0 0-2.5-.7v-1c2.2 0 4.5 1 5.6 3a7 7 0 0 1 1 3.6zm-6.7 6.7v-1c2 0 4-1.2 5-3a7 7 0 0 0 .6-2.7h1c0 2.3-1.3 4.5-3.2 5.7a7 7 0 0 1-3.5 1zm-6.7-6.7h1c0 2 1.3 4.2 3.2 5a6 6 0 0 0 2.5.7v1a7 7 0 0 1-5.6-3 7 7 0 0 1-1-3.7zm6.7-6.7v1c-2 0-4 1.2-5 3a6 6 0 0 0-.6 2.6h-1a7 7 0 0 1 3-5.7 7 7 0 0 1 3.6-1z"/>
<path fill="#fff" d="M356.8 152.8c3.4 0 6.2 2.7 6.2 6 0 3.6-2.8 6.3-6.2 6.3s-6-2.6-6-6a6 6 0 0 1 6-6.2z"/>
<path fill="#21231e" d="M363.5 159h-1c0-2.2-1.3-4.2-3-5a6 6 0 0 0-2.7-.7v-1a7 7 0 0 1 5.7 3 7 7 0 0 1 1 3.6zm-6.7 6.6v-1a5.7 5.7 0 0 0 5.7-5.7h1a7 7 0 0 1-3 5.6 7 7 0 0 1-3.7 1zm-6.6-6.7h1c0 2 1.2 4 3 5a6 6 0 0 0 2.6.6v1a7 7 0 0 1-5.6-3 7 7 0 0 1-1-3.7zm6.6-6.8v1c-2 0-4 1.3-5 3.2a6 6 0 0 0-.6 2.5h-1c0-2.3 1.2-4.6 3-5.8a7 7 0 0 1 3.6-1z"/>
<path fill="#fff" d="M368.8 147c3.4 0 6 3 6 6.3 0 3.4-2.6 6.2-6 6.2s-6-2.8-6-6.2a6 6 0 0 1 6-6.2z"/>
<path fill="#21231e" d="M375.4 153.3h-1c0-2-1.2-4.2-3-5a6 6 0 0 0-2.6-.7v-1a7 7 0 0 1 5.6 3 7 7 0 0 1 1 3.7m-6.6 6.7v-1c2 0 4-1.3 5-3a6 6 0 0 0 .6-2.7h1a7 7 0 0 1-3 5.7 7 7 0 0 1-3.6 1m-6.7-6.7h1c0 2 1.4 4 3.2 5a6 6 0 0 0 2.6.7v1a7 7 0 0 1-5.7-3.2 7 7 0 0 1-1-3.5zm6.8-6.7v1c-2 0-4 1.2-5 3a6 6 0 0 0-.6 2.7h-1c0-2.3 1-4.5 3-5.7a7 7 0 0 1 3.6-1"/>
<path fill="#fff" d="M338.2 169.5a6 6 0 0 1 6 6.2c0 3.4-2.6 6.2-6 6.2s-6.2-3-6.2-6.3 2.8-6.2 6.2-6.2z"/>
<path fill="#21231e" d="M344.8 175.7h-1c0-2-1.3-4.2-3.2-5a6 6 0 0 0-2.4-.7v-1a7 7 0 0 1 5.6 3 7 7 0 0 1 1 3.7m-6.6 6.7v-1c2 0 4-1.3 5-3a6 6 0 0 0 .6-2.7h1c0 2.3-1.2 4.5-3.2 5.7a7 7 0 0 1-3.4 1m-6.7-6.7h1c0 2 1.2 4 3 5a6 6 0 0 0 2.7.7v1a7 7 0 0 1-5.7-3.2 7 7 0 0 1-1-3.5m6.7-6.7v1c-2 0-4 1.2-5 3a6 6 0 0 0-.7 2.7h-1c0-2.3 1.2-4.5 3.2-5.7a7 7 0 0 1 3.5-1"/>
<path fill="#edb92e" d="m408.8 279 22-12.8 23.4 10-22 13z"/>
<path fill="#21231e" d="m431 266.7-22 12.8-.4-1 22-12.7h.5v1zm-.4-1h.5-.4zm23.5 11-23.3-10 .4-1 23.4 10v1h-.3zm.4-1 1 .5-1 .5zm-22.4 13 22-13 .5 1-22 12.8h-.5zm.5.8-.2.2h-.3zm-23.4-11 23.4 10-.4 1-23.3-10v-1h.4zm-.3 1-1-.4 1-.4v1z"/>
<path fill="#c6363c" d="M431 270.6c5.8-.3 10.5 2.5 10.8 6.3.2 3.7-4.2 7-9.8 7.4-5.7.3-10.4-2.5-10.7-6.3-.2-3.6 4.2-7 9.8-7.4z"/>
<path fill="#21231e" d="M442.3 277h-1v-.7l-.2-.3v-.6l-.3-.3v-.2l-.3-.2-.2-.3-.2-.3-.3-.2-.3-.3-.2-.2-.3-.2h-.5l-.3-.3-.3-.2-.5-.2-.4-.2h-.3l-.4-.2h-.4l-.5-.3h-.9l-.5-.2h-.8l-.5-.2h-1l-.5.2v-1h3.6l.4.2.5.2h.5l.4.2.5.2.5.2.4.2.3.2.4.2.4.2.4.2.4.3.3.3.4.3.3.3.3.3.2.4.2.3.2.3.2.4v.3l.3.4.2.4v.8zm-10.3 8v-1l.4-.2h.9l.5-.2h.4l.4-.2h.5l.4-.3h.5l.4-.2.4-.2.4-.2.3-.2.4-.2.4-.3.4-.2.3-.2.3-.3.3-.2.3-.3v-.3l.3-.3.2-.4.2-.2v-.3l.2-.2v-.6l.2-.3v-1.1l1-.2v1.6l-.2.4v.3l-.3.5v.3l-.3.4-.3.3v.3l-.4.4-.3.3-.3.3-.3.2-.3.3-.4.3-.4.2-.4.3-.4.3-.4.2-.4.2-.5.2h-.4l-.4.2-.5.2h-.4l-.5.2h-.4l-.5.2h-1zm-11.2-6.8h1v.5l.2.3v.3l.2.3.2.3v.2l.3.3.2.2v.3l.4.2.2.3.3.2.2.2.3.2.4.2.2.2h.4l.4.3h.4l.4.2.4.2h.4l.5.2h1l.4.2h2.3v1H428l-.5-.2h-.4l-.5-.3h-.6l-.4-.3h-.4l-.5-.3-.3-.2-.3-.3-.4-.2-.4-.2-.3-.3-.3-.2-.3-.3-.3-.3-.3-.3v-.3l-.3-.3-.2-.3-.2-.4-.2-.3v-1l-.2-.4zm10.3-8 .2 1h-1.5l-.5.2h-.5l-.5.2-.4.2h-.5l-.4.3-.5.2-.4.2-.3.2-.4.2-.3.2-.3.3-.4.2-.3.3-.3.2-.2.3-.3.2-.2.3-.2.3-.2.4-.2.3v.3l-.3.3v.8l-.2.3v.6l-1 .2V277l.2-.4v-.3l.2-.4v-.5l.3-.3.2-.4.3-.3.2-.3.3-.3.2-.4.4-.3.4-.3.3-.3.4-.3.5-.2.3-.3.5-.3.4-.2.4-.2.6-.2h.4l.5-.2h.5l.5-.3h.5l.5-.2zl.5-.2z"/>
<path fill="#edb92e" d="m382.4 270 23.8 9-19.7 13c-5-1.6-9-19-4-22z"/>
<path fill="#21231e" d="m406 279.4-23.8-9 .4-1 23.7 9v1zm.3-1 1 .4-1 .5v-1zm-20 13.3 19.6-13.2.4.8-19.6 13.3h-.4zm.5 1h-.4zm-4.2-23.3-.4 1h.5l-.4.2-.4.3-.4.4-.2.5-.2.4-.2.7-.2.8v1.5l-.2.8v2.8l.3.8v1l.2.8.2 1 .2 1 .3.7v1l.5 1 .3.7.3.7.5.8.4.6.3.6.4.6.4.5.5.4.4.2.3.3.4.2-.3 1-.6-.3-.5-.3-.5-.3-.5-.5-.4-.6-.6-.6-.4-.7-.4-.7-.4-.7-.4-1-.3-.8-.3-1-.3-.8-.4-1-.2-.8-.2-1-.2-1v-.8l-.3-1v-5.2l.3-.8.2-.7.3-.6.3-.6.4-.5.4-.5.5-.4h.6zm-.5 0h.6-.5zm.4.4.2-.4zm-.3-.4h.6-.5z"/>
<path fill="#0c4076" d="M382.8 274.3c5.7-.6 10.5 2 11 5.8.3 3.8-4 7.4-9.6 8-3.6.3-6-3-6.3-6.3-.5-3.4 1-7 4.8-7.4z"/>
<path fill="#21231e" d="M394.2 280h-1v-.5l-.2-.3v-.3l-.2-.4-.2-.3-.2-.2-.2-.2-.2-.3-.2-.2-.3-.3-.2-.2-.3-.2-.3-.2-.4-.2-.3-.2-.4-.2-.3-.2h-.4l-.5-.3h-.4l-.4-.2h-.8l-.5-.2h-3.6l-.2-1h3.8l.4.2h.5l.4.2.4.2h.4l.5.3.4.2h.5l.4.3.2.2.4.3.3.2.2.3.3.3.3.3.2.2.3.3.2.3.2.3v.5l.3.4v.2l.2.4v.4zm-10 8.4v-1h1l.5-.2h.4l.6-.2.5-.2h.5l.4-.3.4-.2h.4l.4-.3.3-.3.4-.2.2-.2.4-.3.3-.2.2-.3.3-.2.2-.3.3-.3.2-.3.2-.2.2-.3v-.4l.3-.3v-.8l.2-.4v-1h1v1.6l-.2.3v.3l-.2.4-.2.3-.2.4-.2.3-.2.4-.3.4-.2.3-.3.3-.3.3-.5.3-.3.3h-.4l-.4.4-.4.2-.4.3h-.4l-.4.3-.5.2h-.5l-.4.3-.5.2h-.6l-.5.2h-.7l-.5.2h-.5zm-6.8-6.7h1v.7l.2.3v.3l.2.4v.3l.2.2v.2l.2.3.2.2v.3l.3.2.2.3v.2l.2.2h.2l.2.3h.2l.2.3.2.2h.3l.2.2h.2l.2.2h.2l.3.2h1.4v1h-2.1l-.3-.2h-.4l-.3-.3-.3-.2-.3-.2-.3-.2-.2-.2-.3-.2-.3-.2-.2-.2-.3-.3-.2-.2v-.2l-.3-.3-.2-.3v-.2l-.3-.4v-.3l-.3-.3-.2-.3v-.3l-.2-.3v-.6l-.2-.3v-.3zm5.4-8v1h-.2l-.4.2h-.8l-.3.3-.3.2-.3.2-.2.2h-.2l-.2.2v.2l-.3.2v.3h-.3v.3l-.2.3-.2.2v.7l-.2.3v.4l-.2.3v2.2h-1V279l.2-.3v-.3l.2-.2v-.3l.2-.3.2-.3v-.4l.3-.3.2-.3.2-.2v-.3l.3-.2.3-.2h.2l.3-.3.4-.2.3-.2h.3l.3-.2h.7l.4-.2h.4z"/>
<path fill="#fff" d="M457.5 280.4c1.7 0 3.2 1.5 3.2 3.2s-1.5 3.3-3.2 3.3-3.2-1.6-3.2-3.4 1.4-3.2 3.2-3.2z"/>
<path fill="#21231e" d="M461.2 283.6h-1v-.6l-.2-.2v-.2l-.2-.3v-.2h-.2v-.2h-.2v-.2h-.2l-.2-.2-.3-.2h-.2l-.2-.2h-.7v-1h1l.3.2.2.2h.2l.3.2v.2h.2v.2h.2v.3h.2v.2l.2.2v.2h.2v.2l.2.3v.5l.2.2v.2zm-3.7 3.8v-1h.4l.3-.2h.2l.2-.2h.2v-.2h.2v-.2h.2v-.2l.2-.2.2-.2v-.2l.2-.2v-1h1.2v.8l-.2.2v.3l-.2.2v.2l-.2.2-.2.3h-.2v.3h-.3l-.2.2-.3.2-.3.2h-.6v.2h-.6v.2h-.3zm-3.7-3.8h1v1h.2v.2l.2.2v.2l.2.2h.2v.2h.2v.2h.2l.2.2h.2v.2h1v1.2h-.7l-.2-.2h-.5v-.2h-.3l-.2-.2-.3-.2-.2-.2h-.2v-.3h-.2l-.2-.3-.2-.3v-.2l-.2-.3v-.3l-.2-.3zm3.7-3.7v1h-.9l-.2.2h-.2v.2h-.2v.2h-.2v.2h-.2v.2h-.2v.2l-.2.3v.5h-.2v.8h-1v-1.2l.2-.2v-.3h.2v-.3l.2-.2.2-.2v-.2h.4v-.2l.2-.2h.2v-.2h.5v-.2h.4v-.2h1z"/>
<path fill="#fff" d="M408.7 283c1.8 0 3.2 1.6 3.2 3.4s-1.5 3.2-3.3 3.2a3 3 0 0 1-3.2-3.2c0-1.8 1.4-3.3 3.2-3.3z"/>
<path fill="#21231e" d="M412.4 286.4h-1v-.9l-.2-.2v-.2l-.2-.2v-.2l-.2-.2-.2-.2h-.2v-.2h-.2v-.2h-.4l-.2-.2h-.8v-1.2h.7v.2h.7v.2h.3v.2h.3v.2h.3l.2.2.2.3h.2l.2.3.2.3v.3h.2v.6l.2.2v.9zm-3.7 3.7v-1h1v-.2h.2l.2-.2h.2v-.2h.2v-.2h.2v-.2l.2-.2v-.3h.2v-.5l.2-.2v-.4h1v.8l-.2.2v.3l-.2.2v.3h-.2v.3h-.2l-.2.3h-.2v.2h-.3l-.2.2h-.2v.2h-.3v.2h-.5l-.2.2h-.8zm-3.7-3.6h1v.8h.2v.5h.2v.2h.2v.2h.2v.2h.2l.2.2h.2v.2h.5v.2h.7v1h-1.2v-.2h-.3v-.2h-.2l-.2-.2-.2-.2h-.2v-.2h-.2v-.3h-.3v-.3h-.2v-.3l-.2-.2v-.2l-.2-.3v-.8zm3.7-3.8v1h-.7v.2h-.5v.2h-.2l-.2.2v.2h-.2l-.2.2v.2l-.2.2v.2h-.2v.7l-.2.3v.4h-1v-1l.2-.2v-.3l.2-.3.2-.3v-.3h.3v-.3h.2l.2-.2.2-.2h.2v-.2h.6l.3-.2h.5l.3-.2h.2z"/>
<path fill="#fff" d="M407 268.3c1.8 0 3.2 1.4 3.2 3.2s-1.4 3.2-3.2 3.2a3 3 0 0 1-3.2-3.2c0-1.8 1.4-3.2 3.2-3.2"/>
<path fill="#21231e" d="M410.7 271.5h-1v-.7l-.2-.2v-.3l-.2-.2h-.2v-.4h-.2v-.2h-.2l-.2-.2h-.2l-.2-.2h-.5v-.2h-.4v-1h.8v.2h.3l.3.2h.2l.3.2h.2v.2l.3.2.2.2.3.3.2.3v.3h.2v.4l.2.2v1zm-3.7 3.7v-1h1v-.2h.2l.2-.2h.2v-.2h.2v-.2h.2v-.2l.2-.2.2-.2v-.4h.2v-1h1v1.2l-.2.2-.2.3v.3h-.2l-.2.3h-.2v.3h-.3v.2h-.2v.2h-.2l-.2.2h-.5l-.3.2h-.7zm-3.7-3.7h1v.8l.2.2v.4h.2v.2l.2.2v.2h.2v.2h.2v.2h.2l.2.2h.5l.2.2h.5v1h-.9l-.3-.2h-.2l-.3-.2-.3-.2h-.2l-.2-.2-.2-.3h-.3v-.3l-.2-.3v-.3h-.2v-.4l-.2-.2v-.8zm3.7-3.7v1h-.8v.2h-.5l-.2.2h-.2v.2h-.2v.2h-.2v.2h-.2v.2l-.2.2v.3l-.2.2v.7h-1v-1.2h.2v-.6h.2v-.3h.2v-.3h.3l.2-.2v-.2h.3v-.2h.3l.2-.2h.4v-.2h.5l.2-.2z"/>
<path fill="#fff" d="M457.3 266.2c1.8 0 3.2 1.4 3.2 3.2s-1.4 3.2-3.2 3.2a3 3 0 0 1-3.2-3.2c0-1.8 1.6-3.2 3.3-3.2z"/>
<path fill="#21231e" d="M461 269.4h-1v-.8h-.2v-.3l-.2-.2v-.2h-.2v-.2h-.2v-.2l-.2-.2h-.2l-.2-.2h-.2l-.3-.2h-.7v-1h1.1l.2.2h.3l.3.2.3.2.2.3h.2v.2h.2v.2h.2v.3h.2v.3l.2.2v.5l.2.2zm-3.7 3.7v-1h1.2v-.2h.2l.2-.2.2-.2v-.2h.2v-.2h.2v-.2l.2-.2v-.5h.2v-.8h1v1.1l-.2.2v.2l-.2.2-.2.3-.2.3-.2.2-.2.2-.2.2h-.2v.2h-.3v.2h-.4l-.2.2h-1zm-3.7-3.6h1v.5l.2.2v.3l.2.2v.2h.2l.2.2v.2h.2v.2h.2l.3.2h.2l.2.2h.7v1h-1l-.3-.2h-.3l-.3-.2-.3-.2v-.2l-.3-.2-.2-.2v-.2h-.2v-.3h-.2v-.6l-.2-.2v-.7zv-.2zm3.7-3.7v1h-.7v.2h-.4l-.2.2h-.2v.2h-.2v.2l-.2.2-.2.2v.4h-.2v.8h-1.2v-.5l.2-.3v-.4l.2-.2v-.2h.2v-.3h.2v-.3h.2v-.2h.3v-.3l.3-.2.3-.2h.3l.2-.2z"/>
<path fill="#edb92e" d="M371 237.4c2.3-.8 6 4.6 7 4.5 1.2-3-1.2-10.5-5.5-16.3-3-1-3.2-3-3.8-7.3-.2-1.3-2.7-.4-2.7 2 0 2.3-.3 3.6.3 5.6q.4 1.2-.8 2.3c4.5 1.8 5.6 4 5.4 9z"/>
<path fill="#21231e" d="m377.6 241.8 1 .3-.5.4h-.4l-.3-.2-.2-.2-.3-.3-.2-.2-.2-.2-.2-.2-.3-.3-.3-.2-.2-.2-.2-.3-.3-.2-.2-.2-.3-.2-.2-.3h-.3l-.3-.3h-.2l-.3-.3-.3-.2h-.2l-.3-.2h-.4l-.2-.2h-.4l-.4-1h1.3l.3.2h.3l.3.2.2.2h.3l.3.3.2.2h.3l.3.3.3.3v.2l.4.2.2.3.3.2v.2l.4.3.2.2.2.2.2.2.2.2.2.2h.2v.2h.3v.2zm1 .3-.2.4h-.3l.5-.3zm-6.3-15.8.4-1 .2.2.3.5.4.5.4.6.4.7.4.5.3.6.5.6.3.6.3.6.4.6.3.6.2.6.2.6.2.5.2.6.2.7.2.5v.6l.3.5v.6l.2.4v.5l.2.4v3.3l-.2.3-1-.2v-.3l.2-.3v-3.6l-.3-.5v-.4l-.2-.5-.2-.5-.2-.5v-.5l-.4-.6-.2-.7-.2-.5-.3-.6-.2-.6-.3-.5-.3-.5-.4-.6-.3-.7-.4-.5-.4-.6-.4-.6-.3-.5-.5-.5-.4-.5.3.2zm.4-1 .2.2-.3-.2zm-4.5-6.7h1v.7l.2.3v1l.2.3v.5l.2.3v.5l.2.2v.4h.2v.3l.2.2v.2h.2v.3h.2l.2.2v.2h.2l.2.2h.2l.2.2h.2l.2.2h.2l.3.2-.4 1h-.2l-.2-.2-.3-.2h-.2l-.2-.2h-.2l-.2-.3-.2-.2h-.2v-.2l-.3-.2-.2-.2-.2-.2v-.2l-.2-.2v-.2l-.2-.3v-.2l-.2-.2v-.3l-.2-.2v-.9l-.2-.3v-.6l-.2-.3V219l-.2-.5zm-1.7 1.8h-1v-1l.2-.2.2-.2v-.4h.2l.2-.3h.2l.2-.2.3-.2h.2l.2-.2h1.2v.2h.2v.3l.2.2v.2h-1.6v.2h-.2v.2h-.2v.2h-.2v.3l-.2.2v.8zm.3 5.6-1 .2v-.6l-.2-.2V224h-.2v-3.6h1v4.2l.2.2v.7l.2.2zm-1 2-.5.8v-1l.2-.2v-.2h.2v-.4h.2v-.4l-.2-.2v-.2l1-.3v1.8h-.2v.4h-.2v.2h-.2v.2l-.2.2h-.2zm-.5.8-.8-.3.7-.6v.8zm5 8.6h1zv-.5l.2-.5v-2l-.2-.3v-.7l-.2-.3v-.6l-.2-.3v-.2l-.2-.3-.2-.3v-.2l-.3-.3v-.2l-.3-.2-.2-.2-.3-.2-.2-.2-.3-.2h-.3l-.3-.3-.2-.2-.3-.2-.4-.2h-.3l-.4-.2.4-1 .4.2.5.2.4.2.3.2.3.2.4.2.3.2.3.2.3.2v.2l.4.3.2.3.3.3v.2l.3.3v.4l.3.3v.3l.3.3v.7l.2.3v.7l.2.4v2.9h-1zm1 0h-1l.5-.5.6.4zm-1 0v-.4h.5l-.4.4z"/>
<path fill="#edb92e" d="M368.8 218.5c-.4 1-.6 1.8-.7 3.4q0 1.5 1.2 3 1.2 1.6 3 2.6 1.2.9 2.3 3 1.1 2.3 1.2 4c0 3.5.8 6.7 2.4 7.3 1.2.3 1.6.2 2.4 0-.2-.6 0-1.5-.7-2.4a8 8 0 0 1-1.4-3.7c0-1-.5-1.6-.2-3.3.4-1.2 1-1.6 1-2.7-.3-2-2-6-4.3-6s-3.4-.3-4.6-3.4c-.3-1-1-1.6-1.2-2z"/>
<path fill="#21231e" d="m368.6 222-1-.2v-1.2l.2-.2v-1h.2v-.7h.2v-.4l1 .3v.4h-.2v1l-.2.2v1.5zm1 2.8-.8.6v-.2h-.2v-.2l-.2-.2v-.2h-.2v-.4h-.2v-.5l-.2-.2v-.7l-.2-.2v-.7h1v1.1h.2v.7h.2v.4h.2v.4h.2v.2zv.2zm3 2.4-.6 1v-.2h-.4v-.2h-.2v-.2h-.2l-.2-.2h-.2v-.2h-.3v-.2h-.2l-.2-.2v-.2l-.2-.2h-.2v-.2h-.2v-.2h-.2v-.2l-.2-.2-.2-.2.8-.6.2.2.2.2v.2h.2l.2.2v.2h.2l.2.2.2.2h.2v.2h.2v.2h.3l.2.2.2.2h.2v.2zm2.4 3.2-1 .4v-.2l-.2-.2v-.2l-.2-.2v-.2h-.2v-.2l-.2-.2v-.2h-.2v-.2l-.2-.2-.2-.2v-.2h-.2l-.2-.2h-.2l.5-1h.2v.2h.2v.2h.2v.2l.2.2.2.2v.2h.2v.2h.2v.2l.2.2v.2l.2.2v.2h.2v.3h.2v.3h.2zm1.2 4.2h-1v-.8l-.2-.2v-.8h-.2v-.5h-.2v-.4h-.2v-.5h-.2v-.2l-.2-.2 1-.4v.4h.2v.4h.2v.5l.2.2v.3h.2v.6h.2v1h.2zm2 6.8-.3 1h-.3l-.2-.2-.3-.3v-.2l-.3-.2h-.2l-.2-.3v-.2h-.2v-.3l-.2-.2v-.3l-.2-.2v-.3l-.2-.2v-.5l-.2-.3v-.8l-.2-.3V236l-.2-.3v-1.5h1v2.1l.2.3v1.4l.2.2v.8l.2.2v.2l.2.2v.4l.2.2v.2l.2.2.2.2v.2h.2v.2h.2l.2.2zm1.7.8 1-.3-.5.5h-.4v.2h-1.4l-.2-.2h-.4l.3-1h.7v.2h1.2v-.2zm1-.3v.4h-.5l.4-.5zm-1.7-2 .8-.7h.2v.4h.2v.4h.2v.8l.2.2v1l-1 .4V241l-.2-.2v-.8h-.2v-.2zm-1.5-4h1v.8h.2v.8l.2.2v.2l.2.2v.2h.2v.5h.2v.2h.2v.2l-.7.7v-.2l-.2-.2v-.4h-.2v-.5h-.2v-.2l-.2-.3v-.2l-.2-.2v-.2l-.2-.3v-.4l-.2-.2v-.5zm-.2-3.4 1 .2v3l.2.2-1 .2v-.8l-.2-.2zm1-2.5h1v.7h-.2v.6l-.2.2v.2l-.2.2v.2h-.2v.6h-.2v.2l-1-.2v-.4h.2v-.4l.2-.2v-.2l.2-.2v-.2l.2-.2v-.9zm-4-5.5v-1h1.1l.3.2h.2l.2.2h.3l.2.2.2.2v.2l.3.2v.2l.3.2.2.3v.2l.3.3.2.2.2.3v.2l.2.3v.2l.2.3v.3l.2.2v.3l.2.2v.5l.2.3v.8h-1v-1l-.2-.2v-.4l-.2-.3-.2-.4v-.2l-.2-.2v-.3l-.3-.3v-.2l-.2-.2v-.3l-.2-.2-.3-.3-.2-.2-.3-.3-.3-.2-.3-.2h-.8zm-5-3.7 1-.4v.3l.2.3v.2l.2.2v.2l.2.2v.2l.2.2.2.2v.2h.2v.2h.2v.2h.4v.2h.7v.2h1.7v1H373l-.3-.2h-.4v-.2h-.3v-.2h-.3v-.3h-.3v-.2l-.2-.2-.2-.3-.2-.2v-.2l-.2-.2-.2-.4-.2-.2v-.3l-.2-.2zm-.4-2-1-.5h1.2v.4h.2v.2h.2v.2h.2v.4h.2v.2l.2.2v.2l.2.2-1 .4v-.2l-.2-.2v-.2l-.2-.2v-.2h-.2v-.2l-.2-.2v-.2h-.2v-.2h-.2v-.2zm-1-.5.5-1 .5 1zm.6.2.4.2zm-.5-.2.4-1 .5 1z"/>
<path fill="#edb92e" d="m360 227 2-1a6 6 0 0 1 4-.2c5.5 1.7 8 11.6 1.8 14q-1.8.2-3.4-3.3a21 21 0 0 0-4-6.8c-1-1-1-2-.4-2.6z"/>
<path fill="#21231e" d="m362 225.5.3 1h-.4v.2h-.4v.2h-.8v.2h-.2l-.2.2-.7-.7.2-.2v-.2h.4v-.2h.8v-.2h.4v-.2h.4zm4-.2-.2 1h-.5v-.2h-2.1v.2h-.7l-.2.2-.5-1h.4l.3-.2h.8v-.2h1.6l.2.2h.4zm2 15-.2-1h-.2l.5-.2h.6l.4-.4.4-.3.3-.4.3-.5.2-.4.2-.3.2-.5v-.5l.2-.5V232l-.3-.4-.2-.5-.2-.5v-.5l-.4-.4-.2-.5-.4-.3-.3-.5-.4-.3-.3-.5-.4-.3-.5-.3-.3-.4-.5-.2h-.4l.2-1h.6l.5.3.7.3.4.4.6.3.5.4.5.6.3.4.4.5.3.5.3.6.3.5.3.7.2.6v.6l.3.5v3.4l-.2.5-.2.6-.3.6-.2.5-.3.5-.4.5-.4.4-.4.3-.6.3-.6.3zm-4-3.6 1-.4v.4l.2.2.2.3.2.3v.2h.2v.5h.2v.2l.2.2.2.2h.2v.2h.2l.2.2h.8v1.2h-.8v-.2h-.5l-.2-.2-.2-.2-.2-.2-.2-.2v-.2h-.2l-.2-.2v-.2h-.2v-.3l-.2-.2v-.2h-.2v-.2l-.2-.2v-.2l-.2-.3-.3-.3zm-4-6.6.7-.6.2.2v.2h.2l.2.3v.3h.2l.2.3v.2l.2.2h.2v.3l.3.2v.2l.2.2.2.2v.4l.2.2.2.3v.3l.2.2.2.3v.3l.2.3v.3l.3.3.2.4v.3l.3.3v.3l-1 .4v-.6l-.2-.2v-.3l-.3-.2v-.3l-.2-.2v-.5l-.3-.3v-.2l-.2-.2v-.3l-.3-.2-.2-.3v-.2l-.3-.2v-.2h-.2v-.3h-.3v-.3l-.2-.2-.3-.3v-.2l-.2-.2h-.2v-.2l-.2-.2zm0-3.4v1l.3-.2v.2h-.2v.8h.2v.4l.2.2.2.2v.2l-.7.7h-.2v-.2l-.2-.2-.2-.2v-.3h-.2V227h.2v-.2h.2zm-.4 0h.4zm.4 1v-1l.3 1zm.3 0h-.2.3z"/>
<path fill="#edb92e" d="M362.8 227.7c5.4-2 9.4 8.3 4.3 10.2-2.6 1-2.8-2.4-3.4-4.3-.7-2.5-6-4-.8-6z"/>
<path fill="#21231e" d="m367.3 238.4-.4-1h.3l.3-.3.3-.2.2-.3.2-.3.2-.3v-.5l.2-.4v-2.7l-.2-.4-.2-.5-.2-.4-.2-.4-.3-.4-.3-.4-.2-.3-.4-.4-.3-.2-.3-.2-.4-.2-.4-.2h-.4l-.3-.2h-1.3l-.4.2-.4-1h.6l.5-.2h1.6l.5.3.5.2.4.2.4.4.5.4.4.4.3.4.3.5.2.4.3.6.3.5.2.6.2.6v.5l.2.5v1.6l-.2.5v.5l-.3.5-.2.4-.3.5-.4.3-.4.4-.4.2-.5.2zM363 234l1-.4.2.2v.6l.2.2v.8l.2.2v.4l.2.2v.2l.2.3.2.3v.2h.2v.2h.2l.2.2h1.2l.3.8h-.3l-.3.2h-1.2l-.2-.2h-.2v-.2l-.3-.2-.3-.3v-.2l-.2-.2v-.2h-.2v-.3l-.2-.2v-.4h-.2v-.8l-.2-.2v-.8l-.2-.2v-.2zm-.4-6.7.4 1h-.5l-.3.3h-.4l-.2.3h-.2l-.2.2v.2h-.2v.4h.2v.3l.2.2v.2h.3v.3l.3.2h.2l.2.2.2.2.2.2.2.2.2.3.2.3.2.2v.3l.3.2v.6l-1 .3v-.7l-.2-.2h-.2v-.3l-.3-.2h-.2v-.3l-.3-.2-.2-.2-.2-.2-.2-.2v-.2l-.2-.2h-.2v-.3l-.3-.3v-.2l-.2-.2v-.8l.2-.3v-.3l.3-.2.2-.2.3-.3.3-.2h.4l.4-.3.6-.2z"/>
<path fill="#0c4076" d="M363.4 229.3c2.6-1 6.2 5 3 6.5-2.3 1-4-.3-4.8-2-.7-2 0-3.8 1.7-4.5z"/>
<path fill="#21231e" d="m366.5 236.3-.4-1h.3l.2-.2h.2v-.2l.2-.2v-2l-.2-.3v-.3h-.2v-.4l-.3-.3-.2-.2-.3-.4-.2-.2-.2-.2h-.2v-.2l-.3-.2h-1.1l-.3-1h1.5l.4.3.3.2.2.3.2.2.3.2.2.2.2.3v.3l.3.3.2.4.2.3v.4l.2.4v2.6l-.2.3-.2.4-.2.3-.2.2h-.4l-.3.3zm-5.4-2.5 1-.3.2.3.2.3v.2l.2.3.2.2.2.2h.3v.2h.2l.3.2h.4v.2h1.3l.3-.2.5 1h-.7l-.2.2h-1.9l-.2-.2h-.2v-.2h-.3l-.2-.2-.3-.2-.3-.3-.3-.3h-.2v-.3l-.2-.3-.2-.3v-.2zv-.2zm2.2-5 .3 1h-.3l-.2.2-.2.2-.2.2-.2.2-.2.2v.2h-.2v.7l-.2.2v1.1l.2.2v.3l-1 .3v-.7l-.2-.3v-1.5l.2-.2v-.3l.2-.2.2-.3.2-.3v-.2l.3-.2v-.2h.3l.2-.2.3-.2h.2zm.2.5-.2-.5z"/>
<path fill="#fff" d="M400 179.7c3.6 0 6.4 2.8 6.4 6.4s-2.8 6.5-6.3 6.5-6.3-3-6.3-6.4 3-6.3 6.4-6.3z"/>
<path fill="#21231e" d="M407 186h-1c0-2-1.4-4.3-3.3-5.2a6 6 0 0 0-2.6-.6v-1c2.4 0 4.7 1.2 6 3.2a7 7 0 0 1 1 3.7zm-7 7v-1a6 6 0 0 0 5.3-3.3 6 6 0 0 0 .6-2.6h1c0 2.4-1.3 4.7-3.3 6a7 7 0 0 1-3.6 1zm-6.8-7h1a6 6 0 0 0 3.3 5.4 6 6 0 0 0 2.6.6v1a7 7 0 0 1-5.7-3.3 7 7 0 0 1-1-3.6zm7-7v1.2a6 6 0 0 0-5.3 3.2 6 6 0 0 0-.8 2.7h-1a7 7 0 0 1 3.3-5.8 7 7 0 0 1 3.6-1z"/>
<path fill="#fff" d="M395.4 169c3.5 0 6.4 3 6.4 6.4 0 3.6-3 6.4-6.4 6.4s-6.3-2.8-6.3-6.4c0-3.5 3-6.4 6.4-6.4z"/>
<path fill="#21231e" d="M402.3 175.4h-1c0-2.2-1.3-4.3-3.2-5.3a6 6 0 0 0-2.6-.5v-1q3.8.2 6 3.2a7 7 0 0 1 1 3.7zm-7 7v-1c2.3 0 4.4-1.4 5.4-3.3a6 6 0 0 0 .6-2.6h1c0 2.4-1.2 4.7-3.2 6a7 7 0 0 1-3.6 1zm-6.7-7h1a6 6 0 0 0 3.2 5.3q1.2.6 2.6.6v1a7 7 0 0 1-5.8-3.2 7 7 0 0 1-1-3.6zm6.8-7v1c-2 0-4.2 1.4-5.2 3.3a6 6 0 0 0-.6 2.7h-1c0-2.3 1.2-4.6 3.2-6a7 7 0 0 1 3.6-1"/>
<path fill="#fff" d="M410.7 131.5c3.4 0 6 2.7 6 6s-2.6 6.3-6 6.3-6.2-2.7-6.2-6.2a6 6 0 0 1 6.2-6z"/>
<path fill="#21231e" d="M417.3 137.7h-1c0-2.2-1.2-4.2-3-5a6 6 0 0 0-2.6-.7v-1a7 7 0 0 1 5.6 3 7 7 0 0 1 1 3.7m-6.6 6.6v-1c2 0 4-1.2 5-3q.6-1.5.6-2.6h1c0 2.2-1.2 4.5-3 5.6a7 7 0 0 1-3.6 1m-6.7-6.7h1c0 2.2 1.3 4.2 3.2 5a6 6 0 0 0 2.5.7v1a7 7 0 0 1-5.6-3 7 7 0 0 1-1-3.6zm6.7-6.6v1c-2 0-4 1.2-5 3a6 6 0 0 0-.7 2.6h-1a7 7 0 0 1 3-5.6 7 7 0 0 1 3.7-1"/>
<path fill="#fff" d="M400.4 136.2c3.5 0 6.3 3 6.3 6.4s-2.8 6.4-6.3 6.4-6.4-3-6.4-6.4 2.8-6.4 6.4-6.4"/>
<path fill="#21231e" d="M407.2 142.6h-1a6 6 0 0 0-3.3-5.3 6 6 0 0 0-2.6-.6v-1c2.3 0 4.6 1.2 5.8 3.2a7 7 0 0 1 1 3.6zm-6.8 7v-1c2 0 4.2-1.4 5.2-3.3a6 6 0 0 0 .6-2.7h1c0 2.3-1.2 4.7-3.2 6a7 7 0 0 1-3.6 1m-7-7h1c0 2.2 1.4 4.3 3.3 5.3a6 6 0 0 0 2.7.5v1a7 7 0 0 1-6-3.2 7 7 0 0 1-1-3.7zm7-7v1a6 6 0 0 0-5.3 3.3 6 6 0 0 0-.5 2.6h-1c0-2.4 1.2-4.7 3.2-6a7 7 0 0 1 3.7-1z"/>
<path fill="#fff" d="M392.8 145.3c3.5 0 6.3 2.8 6.3 6.4 0 3.5-2.7 6.4-6.2 6.4s-6.4-2.8-6.4-6.3c0-3.6 3-6.4 6.4-6.4z"/>
<path fill="#21231e" d="M399.6 151.7h-1a6 6 0 0 0-3.2-5.3 6 6 0 0 0-2.6-.6v-1c2.3 0 4.6 1.2 5.8 3.2a7 7 0 0 1 1 3.7m-6.8 7v-1c2 0 4.2-1.4 5.2-3.4a6 6 0 0 0 .6-2.6h1c0 2.3-1.2 4.6-3.2 6a7 7 0 0 1-3.6 1m-7-7h1c0 2 1.4 4.3 3.3 5.2a6 6 0 0 0 2.8.6v1a7 7 0 0 1-6-3.3 7 7 0 0 1-1-3.6zm7-7v1a6 6 0 0 0-5.3 3.3 6 6 0 0 0-.6 2.7h-1c0-2.4 1-4.7 3.2-6a7 7 0 0 1 3.6-1z"/>
<path fill="#fff" d="M391.5 156.7c3.6 0 6.4 2.8 6.4 6.4s-3 6.5-6.5 6.5-6.3-3-6.3-6.4 2.8-6.3 6.3-6.3z"/>
<path fill="#21231e" d="M398.4 163h-1c0-2-1.3-4.2-3.2-5.2a6 6 0 0 0-2.7-.6v-1c2.4 0 4.7 1.2 6 3.2a7 7 0 0 1 1 3.7zm-7 7v-1a6 6 0 0 0 5.4-3.3 6 6 0 0 0 .6-2.6h1c0 2.5-1.3 5-3.4 6a7 7 0 0 1-3.5 1zm-6.7-7h1c0 2.3 1.3 4.4 3.2 5.4q1.1.6 2.5.6v1a7 7 0 0 1-5.8-3.2 7 7 0 0 1-1-3.7zm6.8-6.8v1c-2 0-4.2 1.3-5.2 3.2a6 6 0 0 0-.6 2.7h-1c0-2.3 1.2-4.6 3.2-5.8a7 7 0 0 1 3.5-1z"/>
<path fill="#edb92e" d="M474.4 198q-4-7.5-8.6-9.6 6.4-19.8 2.7-51-.4-4.8-2.2-4.6-1.6-.1-1.8 5.2c.8 11.6 1.7 21.6 1.2 30.2-.5 7.6-2.3 14-4.2 21.2-.3 1 .4 1.7 3.8 3.7q4 2.4 4.7 5h1.5q3.8 1 3 0z"/>
<path fill="#21231e" d="m465.3 188.2 1 .3-.3-.6h.3l.3.2.3.2.2.2h.3l.3.3h.3l.4.4.2.2.3.2.2.3.3.3.3.3.3.3.3.2.3.3.3.3.2.3.2.5.3.3.3.4.2.3.3.4.3.3.2.4.3.4.3.5.2.5.3.4.3.4.3.5.3.5-1 .5-.3-.5-.2-.4-.3-.5-.2-.5-.3-.4-.3-.3-.2-.4-.3-.4-.3-.5-.3-.4-.2-.2-.3-.4-.4-.3-.2-.2-.3-.3v-.3l-.4-.3-.3-.4-.2-.3-.2-.2-.3-.2-.2-.2-.3-.2-.3-.2-.2-.2-.3-.2-.3-.2-.3-.2h-.3l-.3-.3-.4-.2-.3-.6zm.3.6h-.4v-.6zm2.4-51.5h1l.2 2 .2 1.8.2 2 .2 2v1.8l.2 1.8v1.8l.2 1.8v15l-.3 1.5-.2 1.5v1.5l-.3 1.5-.2 1.5-.2 1.4-.2 1.5-.2 1.3-.3 1.4-.3 1.3-.3 1.4-.3 1.3-.4 1.3-.3 1.3-.4 1.2-1-.3.4-1.2.4-1.3.4-1.3.3-1.3.3-1.2.3-1.3.3-1.4.2-1.3.3-1.4.3-1.5.2-1.4V172l.3-1.6V169l.2-1.7v-1.6l.2-1.6v-13.6l-.2-1.8v-2l-.2-1.7-.2-2-.2-1.8-.2-2-.2-2zm-1.7-4v-1h.6v.2h.3v.2h.2l.2.3h.2v.5h.2v.3l.2.2v.3l.2.2v.4l.2.4v.9l.2.3v.4h-1v-.9l-.2-.2v-.6l-.2-.2v-.5h-.2v-.5h-.2v-.2l-.2-.2h-.2v-.2h-.4zM465 138h-1v-1.7l.2-.3v-1l.2-.3v-.7h.2v-.3l.2-.3v-.3h.2l.2-.2.3-.2.2-.2h.5v1h-.2v.2h-.2v.2l-.2.2v.3l-.2.3v.6l-.2.2v1.6l-.2.4v.7zm1.2 30.2h-1V154l-.2-1v-2.8l-.2-1v-2l-.2-1v-1l-.2-1v-2l-.2-1V139l-.2-1 1-.2v1l.2 1.2v2l.2 1v2.2l.2 1v2l.2 1v2l.2 1v2.8l.2 1v12zm-4.3 21.3-1-.3.2-.6v-.7l.3-.8.2-.6.2-.7v-.7l.2-.7.2-.6.2-.7v-.6l.3-.6v-.6l.2-.6.2-.7v-.5l.2-.6.2-.8v-.6l.2-.7.2-.7v-.7l.2-.6v-.7l.2-.6v-.7l.2-.7v-.7l.2-.6V169l.2-.8h1v1.5l-.2.7v1.5l-.2.6v.7l-.2.8v.7l-.2.6v.8l-.2.7-.2.6v.8l-.2.6-.2.7v.7l-.3.7v.6l-.3.7v.6l-.3.6-.2.6v.6l-.3.7-.2.5-.2.7v.6l-.3.7-.2.7-.2.6v.7zm3.6 3-.5 1-.2-.2h-.3l-.3-.3-.3-.2h-.4l-.2-.3h-.2l-.3-.3h-.3v-.2l-.3-.2h-.2l-.2-.2-.2-.3h-.2v-.2h-.2l-.2-.2v-.2l-.2-.2v-1l1 .2v.5h.2v.2l.2.2h.2v.2h.2l.2.2.3.3h.2l.2.2.2.2h.2l.2.3h.3l.3.3.3.2h.3zm4.2 5.2.4 1-.7-.4v-.2l-.2-.2v-.3l-.2-.2v-.3l-.2-.3-.3-.3-.2-.3-.3-.2-.3-.3v-.2h-.3v-.2h-.3v-.2l-.3-.2h-.2v-.3h-.3l-.2-.2h-.3l-.2-.2-.2-.2h-.2l.6-1 .2.2h.2l.3.3.2.2.2.2h.2v.3h.4l.2.3.3.3.3.3.2.2.3.3v.3l.3.2h.2v.3l.3.2v.2h.2v.3l.2.2v.2l.2.3v.3l.2.2v.2l-.6-.3zm.4 1h-.5l-.2-.4zm1.4-1.2-.3 1h-1l-.4-.8h.2l.2-.2zm3.3.5h-1l.7-.4.2.2v.8l-.2.2h-.2v.2h-1.8l-.2-.2h-.3l-.2-.2h-.5l.3-1h.7l.2.2h1v.2h.7v.4zm-1 0v-1l.7.6-.8.4zm0 0h1l-1 .3z"/>
<path fill="#edb92e" d="M458.4 214.6c1.6-1 2-.8 2.4-1.4q.8-1.4.4-3.5c-.8-5.3 2.4-4.6 6-2.2 1.7 1 3.5 4 5 5.3s2.8 1.5 3.2 2v9.2c-.4.6-1.7.7-3.2 2-1.5 1.5-3.3 4.2-5 5.4-3.6 2.3-6.8 3-6-2.2q.4-2.1-.4-3.5c-.5-.7-.8-.4-2.4-1.4a7 7 0 0 1-2.3-2.2c-.4-.8 0-1.7 0-2.6s-.4-1.8 0-2.6q.9-1.2 2.4-2.2z"/>
<path fill="#21231e" d="m460.4 213 .8.5-.2.2-.2.2h-.4v.2h-.4l-.2.2h-.2l-.2.2h-.2v.2h-.5v.2l-.7-1h.6v-.2h.2l.2-.2h.2l.2-.2h.4v-.2h.4v-.2h.2zm.3-3.2 1-.2v2.9l-.2.3v.2h-.2v.2l-1-.5v-.2h.2v-.4h.2v-2.6zm6.7-2.8-.6 1-.3-.3-.3-.2-.3-.2-.4-.2h-.3l-.3-.2h-.3l-.3-.2h-.3v-.2h-.4l-.2-.2h-1.1v.2h-.2v.2l-.2.2v.6l-.2.3v2l-1 .2v-3l.2-.4v-.3l.3-.2.3-.2.2-.2h.2l.2-.2h.2l.2-.2h1.5v.2h.5l.3.2h.3l.4.3h.3l.3.2.4.2.3.2.3.2zm5 5.4-.6.7-.3-.2-.3-.3-.3-.3-.2-.2-.2-.2-.3-.3-.2-.2v-.2h-.2v-.3l-.3-.2-.3-.3-.2-.2v-.2l-.3-.2v-.2h-.3l-.2-.3-.3-.2-.2-.2h-.2l-.2-.2v-.2h-.3v-.2h-.2l.6-1 .2.2.3.2v.2h.3v.3h.3l.2.2.2.2v.2l.3.2h.2v.3l.3.3.2.2v.2l.3.2.3.3h.2v.3l.3.2.2.2.2.2.3.3v.2h.3v.3h.3v.3h.2zm3.5 2.4h-1.2v.3h-.2l-.2-.2h-.2v-.2h-.4l-.2-.2h-.2v-.2h-.3v-.2h-.3v-.2l-.3-.2-.3-.2-.2-.3.7-.6h.2v.2h.2v.2h.2v.2h.2v.2h.3l.2.2.2.2h.2l.2.2h.2l.2.2h.2v.2h.4v.2l.2.2v.2zm-.2-.2v.2zm0 4.8h-1v-4.5l1-.2v4.5zm-1 0h1zm1 5-1-.7v.3-4.4h1zm0-.4v.2zm-3.3 2.5-.7-.8h.2v-.2l.3-.2.3-.2h.3v-.2h.3v-.2h.2l.2-.2h.2v-.2h.4v-.2h.4v-.2l1 .5-.2.2-.2.2h-.2v.2h-.4l-.2.2h-.2v.2h-.4v.2h-.3v.2h-.2l-.2.2-.2.2v.2h-.3zm-5 5.3-.7-.8h.2v-.2l.3-.2.3-.2.2-.2.3-.3.2-.2.2-.2.2-.2v-.2h.3v-.3l.2-.3.2-.2v-.2l.3-.2.3-.2v-.2l.3-.2.2-.2v-.2h.3v-.3l.3-.2.2-.2h.2v-.3h.3v-.3l.8.8-.2.2-.2.2-.2.2v.2h-.3v.3l-.3.2-.3.2-.2.2-.2.2-.2.2v.2l-.3.2v.2l-.2.2h-.2v.3h-.3l-.2.3v.2h-.2l-.2.3-.2.2-.3.3-.3.3-.3.2zm-6.8-2.7 1 .3v2.6l.2.2v.2h.2v.2h1.7v-.2h.4l.3-.2h.3l.3-.3.3-.3h.3l.2-.3.3-.2.3-.2.6.8-.4.2-.3.3-.3.2h-.4l-.3.3-.3.2h-.3l-.2.3h-.4l-.3.2h-.4l-.3.2h-.9l-.3-.2h-.3l-.2-.3-.2-.2-.2-.2v-.3l-.2-.2v-.7l-.2-.3zm-.3-3 .8-.6v.2h.2v.4h.2v.6l.2.2v2.4l-1-.2v-2.5h-.2v-.4h-.2zm-2.3-1.3.7-.8h.2l.2.2h.2l.2.2h.2l.2.2h.4v.2h.2v.2h.2l.2.2.2.2-.8.6-.2-.2h-.2v-.2h-.4l-.2-.2h-.4v-.2h-.2l-.2-.2h-.2v-.2zm.7-.8.5.2zm-3-1.7.8-.5.2.2v.2h.2v.4h.2v.2h.2v.2h.2v.2h.2l.2.2.2.2h.2v.2h.2l-.5 1v-.2h-.2l-.2-.2-.2-.2h-.2v-.2h-.2v-.2h-.2v-.2h-.2v-.2h-.2v-.2h-.2v-.2l-.2-.2-.2-.2v-.2zm-.3-3h1v2.4l-.7.5v-.2h-.2v-.4l-.2-.2v-2.1zm.3-2.8.8.6v.4l-.2.2v1.8h-1V217h.2v-.4zm2.4-2.4.7 1h-.2v.2h-.2l-.2.2-.2.2-.2.2-.2.2-.2.2-.2.2v.2h-.2v.2h-.2v.2l-1-.5h.2v-.2l.2-.2.2-.2v-.2h.2l.2-.2v-.2h.2v-.2h.2l.2-.2h.2v-.2l.2-.2h.2v-.2h.2zm.7 1 .5-.3z"/>
<path fill="#21231e" d="M475.5 220.2v1q-5.8.7-9.7 4.3c1.8-2.7 5.7-4.7 9.7-5.3m0-1.6v-.8q-5.8-.8-9.7-4.4c1.8 2.7 5.7 4.6 9.7 5.2"/>
<path fill="#edb92e" d="M461.2 207.3q1.6.6 3.4 2c1.6 1.5.6 4-1.5 6.6q-1 1.2-1 3.5.1 2.1 1 3.5c2.2 2.5 3.2 5 1.6 6.6q-1.6 1.4-3.4 2v-2.4q.4-2.1-.4-3.5c-.5-.7-.8-.4-2.4-1.4a7 7 0 0 1-2.3-2.2c-.4-.8 0-1.7 0-2.6s-.4-1.8 0-2.6q.9-1.2 2.4-2.2c1.6-1 2-.8 2.4-1.4q.8-1.4.4-3.5v-2.4z"/>
<path fill="#21231e" d="m465 209-.8.6-.2-.2-.2-.2h-.2v-.2h-.2l-.2-.2h-.2v-.2h-.4v-.2h-.5v-.2h-.2l-.2-.2h-.2l-.2-.2h-.2l.4-1h.2l.2.2h.2l.2.2h.3l.2.2h.2v.2h.3l.2.2h.2v.2h.3v.2h.2l.2.2.2.2.2.2zm-1.5 7.2-.8-.6.2-.3v-.2h.2l.2-.3.2-.3v-.2l.3-.2v-.5l.2-.2v-.2h.2v-.3l.2-.2v-.4h.2v-1.6l-.2-.3-.2-.2-.2-.2.7-.7.3.3v.2l.2.2v.2h.2v.5l.2.2v1l-.2.2v.4l-.2.2v.5l-.2.3v.3l-.3.2v.5l-.3.2v.3l-.3.2-.2.3v.2l-.3.2-.3.3-.2.2zm-1 3.3h-1v-.7l.2-.2v-1.2h.2v-1h.2v-.4l.2-.2v-.2h.2v-.2l1 .6h-.2v.4h-.2v.2l-.2.2v.9h-.2v1.4h-.2v.5zm1 3.2-.8.6v-.2h-.2v-.2h-.2v-.4h-.2v-1.1l-.2-.3V220h-.2v-.5h1v1.1l.2.2v.4l.2.2v.4l.2.2v.2h.2v.2zm1.5 7.3-.8-.8h.2v-.2h.2v-.3l.2-.2v-1.9l-.2-.2v-.2l-.2-.2v-.2l-.2-.3v-.2l-.2-.2-.3-.3v-.3l-.3-.2-.2-.2v-.2l-.3-.3-.3-.2.8-.6.2.2h.2v.4l.2.2.2.3h.2v.3l.3.3v.5l.3.3v.3l.2.2v.5l.2.2v.5l.2.2v.7l-.2.4v.4l-.2.2v.2l-.2.2v.2l-.3.2v.2zm-4.3 1.7 1-.2-.7-.4h.7v-.2h.4l.2-.2h.2l.2-.2h.2v-.2h.4v-.2h.2l.2-.2.2-.2h.2v-.2h.2v-.2l.8.8h-.2v.2h-.2v.2h-.2l-.2.2-.2.2h-.2l-.2.2h-.2v.2h-.4v.2h-.4v.2h-.5v.2h-.2l-.2.2h-.2l-.7-.3zm.7.4-.6.3v-.6l.6.4zm-.7-3 1 .3v2l-1 .3v-2.4zm-.3-3 .8-.6v.2h.2v.4h.2v.6l.2.2v2.4l-1-.2v-2.4h-.2v-.4h-.2zm-2.3-1.3.7-.8h.2l.2.2h.2l.2.2h.2l.2.2h.4v.2h.2l.2.2.2.2.2.2-.8.6-.2-.2h-.2v-.2h-.4l-.2-.2h-.4v-.2h-.2l-.2-.2h-.2v-.2zm0 0-.3-.2zm-2.3-2.4.8-.5.2.2v.2h.2v.4h.2v.2h.2v.2h.2v.2h.2l.2.2h.2v.2h.2v.2h.2l-.5 1v-.2h-.2l-.2-.2-.2-.2h-.2v-.2h-.2v-.2h-.2v-.2h-.2v-.2h-.2v-.2h-.2v-.2l-.2-.2-.2-.2v-.2zm0 0 .3.5zm-.3-3h1v2.4l-.7.5v-.2h-.2v-.4l-.2-.2v-2.2zm.3-2.8.8.6v.4l-.2.2v1.8h-1V217h.2v-.4zm2.4-2.4.7 1h-.2v.2h-.2l-.2.2-.2.2-.2.2-.2.2-.2.2-.2.2v.2h-.2v.2h-.2v.2l-1-.5h.2v-.2l.2-.2.2-.2v-.2h.2l.2-.2v-.2h.2v-.2h.2l.2-.2h.2v-.2h.2v-.2h.2v-.2h.2zm2.4-1 .8.5-.2.2-.2.2h-.4v.2h-.4l-.2.2h-.2l-.2.2h-.2v.2h-.5v.2l-.7-1h.6v-.2h.2l.2-.2h.2l.2-.2h.4v-.2h.4v-.2h.2zm.3-3.2 1-.2v2.9l-.2.2v.2h-.2v.2l-1-.5v-.2h.2v-.4h.2zm.5-2v-1l.5.6v2.1l-1 .2V207l.5.6zm0-1h.6v.6zm0 0v1h-.2zM361 226.3l.7-.3q-2.4-3.2-1.3-6.3c-1.3 1.6-1 4.2.6 6.6"/>
<path fill="#edb92e" d="M410.7 200c1.4 1.6 1.2 2 2 2.5q1.4.8 3.3 0c5-2 5 2 3.5 6.4-.7 2-2.8 4.3-3.7 6.2-1 1.7-.7 3-1 3.5l-4 .6-4 .5c-.6-.3-1-1.6-2.6-3s-4.4-3-6-4.6c-3-3.5-4.6-6.8.2-6.7q2 .1 3-1c.4-.7 0-1 .4-3q.5-1.9 1.4-3c.6-.8 1.5-.6 2.3-.7 1-.2 1.6-.7 2.5-.2q1.6.6 2.7 2.3z"/>
<path fill="#21231e" d="m413 202-.6 1-.2-.2-.2-.2-.2-.2v-.2h-.2v-.2l-.2-.2v-.2l-.2-.2v-.2h-.2v-.2l-.2-.2-.2-.3-.3-.3.8-.6.3.2.2.3v.2h.2v.4h.2v.4h.2v.2l.2.2v.2h.2v.2l.2.2zm2.9 0 .2 1h-.5l-.2.2h-.8v.2h-1.2l-.3-.2h-.2l-.2-.2h-.2l.5-1v.2h.8v.2h1l.2-.2h.4l.2-.2zm4 7-1-.3v-.4l.2-.4v-.5l.2-.4v-.3l.2-.3v-.7l.2-.4v-1.7l-.2-.2v-.4h-.2l-.2-.3h-.2l-.3-.2H417l-.4.3h-.4l-.3-.8.3-.2h.5l.4-.2h1.8l.3.2h.3l.2.3.2.4v.2l.3.3.2.4v3.3l-.2.4v.4l-.2.4v.4l-.2.4v.4zm-3.7 6.4-1-.5v-.2l.2-.2.2-.2v-.2l.2-.2v-.4l.2-.2.2-.2v-.2l.2-.2.2-.2.2-.3.2-.2.2-.3.2-.2v-.2l.2-.2h.2v-.3l.2-.2v-.2l.2-.2.2-.3v-.2l.2-.2v-.2l.2-.3 1 .3v.2l-.2.3v.2l-.2.2-.2.3v.2l-.2.2v.3l-.3.2-.2.2v.2l-.2.2-.2.2v.2l-.2.2-.2.2v.2l-.3.2v.2l-.2.2-.2.2v.2l-.2.2v.4h-.3v.3l-.2.2-.2.2v.2zm-1.5 3.8-.2-1-.3.2v-.4h.2v-1l.2-.2v-.4l.2-.3v-.4l.2-.3v-.2h.2l1 .4-.2.2-.2.3v.3h-.2v.7h-.2v.9l-.2.2v.4l-.2.2v.2zm.3 0h-.2.3zm-4.3.6v-1h1.1v-.2h1.2v-.2h1.1l.3-.2.2 1h-.4l-.3.2h-.9l-.2.2h-1.3v.2h-.7zm0 0v-1 .5-.5zv-.5zm-4 .5.4-1h-.2 1.3l.3-.2h1.9l.2-.2.2 1h-.8v.2h-1.4v.2h-2zm.2 0h-.3.2zm-3-3 .5-1 .2.3.3.3h.2l.2.3.2.2.2.3.2.2v.2h.2v.2h.2v.2l.2.2v.2h.2v.2h.2v.2l-.4 1v-.2h-.2l-.2-.2-.2-.2v-.2h-.2v-.2l-.2-.2v-.2h-.2v-.2l-.2-.2-.2-.2-.2-.2-.2-.3v-.2h-.2v-.2h-.3v-.3zm-6-4.8.7-.6.2.2.3.3.3.3h.2v.3l.3.2h.3l.2.3h.2l.2.3.3.3.2.2.2.2h.2v.2l.3.2h.2l.2.3.2.2.3.3h.2l.2.3.3.2.2.2h.2v.2l-.5.8h-.3v-.2l-.3-.2h-.2v-.2l-.3-.2h-.3l-.2-.2-.2-.2h-.2v-.2l-.3-.2h-.2l-.2-.3h-.2v-.2h-.3l-.2-.2-.2-.2h-.2v-.3h-.3l-.2-.3-.2-.2h-.2v-.3h-.3v-.3l-.3-.2h-.2v-.3l-.3-.2zm.4-7.5v1H397l-.2.2h-.4l-.2.2v.2h-.2v1.5l.2.3v.3l.2.2.2.3.2.4.2.3.2.3.2.3.2.3.3.3v.2l.4.3.3.4-.8.5-.4-.3-.3-.3-.2-.4-.2-.4-.2-.3-.3-.4-.2-.3v-.4l-.3-.4v-.3l-.3-.3v-.3l-.3-.3V206l.2-.2.2-.2.2-.2.3-.2h.2l.3-.2h.7l.4-.2h.8zm2.5-.8.8.5-.2.2-.2.2h-.2v.2h-.2l-.2.2h-.2l-.2.2h-.5l-.2.2h-1.1v-1h1.4l.2-.2h.2l.2-.2h.2v-.2zv-.2zm.4-2.8 1 .2v.4h-.2v2h-.2v.4l-.2.2-1-.4h.2v-1.4l.2-.3v-.8zm1.4-3.2.8.6-.2.2v.2h-.2v.4h-.2v.4h-.2v.4l-.2.2v.4l-.2.2v.4l-1-.2v-.7l.2-.2v-.4l.2-.2v-.4h.2v-.4h.2v-.4h.2v-.2h.2v-.4zm.8.6.5-.7zm1.8-1.5.2 1H404v.2h-.4v.2h-.2l-.8-.5.2-.2.2-.2h.2v-.2h.4l.2-.2zm.2 1h-.7.6zm2.7-1.2-.5 1H406l-.2.2h-.4l-.2-1h.8l.2-.2h2.1zm3 3h-1v.2-.2h-.2v-.2l-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2h-.2v-.2h-.2l-.2-.2-.2-.2h-.2l-.2-.2.5-1v.2h.2l.2.2h.2v.2h.2v.2h.2l.2.2.2.2.2.2h.2v.2h.2v.2l.2.2.2.2.2.2v.2l.3.3zm-.2-.4h.2v.3-.4zm-.8.3h1l-1 .2v-.3zm0 .2v-.3.2z"/>
<path fill="#21231e" d="M410 219.4h-.7q-2.1-5.7-6.3-9.5c2.8 1.4 5.5 5.3 7 9.4zm1.4-.2.8-.2q-.8-5.9 1.5-11c-2 2.5-2.8 7-2.3 11.2"/>
<path fill="#edb92e" d="M418.3 202q-.2 2.2-1 4.3c-1 2-3.8 1.3-6.6-.7q-1.4-.9-3.4-.6t-3 1.7c-1.5 2.6-3.4 4-5.2 2.6q-1.6-1.6-2.7-3.5.8-.3 2-.3 2.1.1 3-1c.5-.7 0-1 .6-3q.2-1.9 1.2-3c.6-.8 1.5-.6 2.3-.7 1-.2 1.6-.7 2.5-.2q1.6.6 2.7 2.3c1.4 1.6 1.2 2 2 2.5q1.6.8 3.3 0 1.4-.6 2.3-.5z"/>
<path fill="#21231e" d="m417.7 206.5-1-.4.2-.2v-.5l.2-.2v-.4l.2-.2v-.9l.2-.2v-1.2h.2v-.4h1v1.1l-.2.3v1h-.2v.7h-.2v.7h-.2v.3l-.2.3zm-7.2-.5.5-.8.3.2h.2l.3.3h.2l.3.3h.2l.3.2.2.2h.2l.3.2h.4v.2h.7l.2.2h1v-.2h.2l.2-.2.2-.3.2-.2 1 .5-.2.2-.2.3-.3.3v.2h-.2l-.2.2h-.2l-.3.2h-2l-.2-.2h-.2l-.3-.2h-.2l-.2-.2h-.2l-.3-.2-.2-.2h-.2l-.3-.3-.2-.2h-.3l-.3-.3-.2-.2zm-3-.4-.3-1h1.1v-.2h1.3v.2h.6v.2h.4v.2h.2l.2.2-.5.8h-.2v-.2h-.4v-.2zm-2.7 1.3-.8-.6v-.2h.2v-.2h.2v-.2l.2-.2h.2v-.2h.2l.2-.2h.2l.2-.2h.3v-.2h.8l.2-.2h.5l.2 1h-.7v.2h-.4v.2h-.4l-.2.2h-.2v.2h-.2v.2h-.2v.2h-.2zm-6 2.7.6-.8h.3v.2h.5l.2.2h.5l.3-.2h.3v-.2h.3v-.2h.2v-.3h.3v-.3h.3v-.3l.3-.3.2-.2.2-.2v-.2h.3v-.4l.3-.2.8.5v.2l-.3.2v.3l-.3.2h-.2v.3l-.3.2-.2.2-.2.2-.3.3h-.2l-.2.3h-.2v.3h-.3l-.3.2h-.4l-.3.2h-1.2l-.2-.2h-.2l-.2-.2-.2-.2h-.2zm-2.7-4.4.5 1 .3-.8v.3h.2v.2l.2.2v.2h.2v.2l.2.2v.2h.2v.2l.2.2.2.2.2.2v.2h.2v.2h.2v.2h.2v.2h.2v.2h.2l-.6 1-.2-.2-.2-.2-.2-.2v-.2h-.2v-.2h-.2v-.2h-.2v-.2h-.2v-.3h-.2v-.2h-.2v-.2h-.2v-.3h-.2v-.2h-.2v-.4h-.2v-.2h-.2V205zm0 .8-.4-.4.5-.3v.8zm2.4-1v1H397v.2h-.4l-.5-1h1.2v-.2zm2.5-.8.8.5-.2.2-.2.2h-.2v.2h-.2l-.2.2h-.2l-.2.2h-.7l-.2.2h-1.2v-1h1.4l.2-.2h.4v-.2h.2v-.2h.2v-.2zm.4-2.8 1 .3v.3l-.2.3v1.7h-.2v.7h-.2l-1-.4h.2v-1.4h.2v-1.3zm1.4-3.2.8.6-.2.2v.2h-.2v.4h-.2v.4h-.2v.4l-.2.2v.7h-.2v.5l-1-.3v-.7l.2-.2v-.4l.2-.2v-.4h.2v-.4h.2v-.4h.2v-.2h.2v-.4zm0 0 .4-.5zm2.6-1 .2 1h-.6v.2h-1v.2h-.2l-.2.2-.8-.6.2-.2.2-.2h.2v-.2h.4l.2-.2h1.4zm0 0h.6zm3 0-.6.8H406v.2h-.5l-.2-1h.8v-.2h2.1zm-.6.8.3.2zm3.3 1.6-.6.6-.2-.2h-.2v-.2l-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2h-.2v-.2h-.2l-.2-.2h-.2v-.2h-.2l-.2-.2.5-1v.2h.2l.2.2h.2v.2h.2v.2h.2l.2.2.2.2.2.2h.2v.2h.2v.2l.2.2.2.2.2.2v.2zm2 2.5-.6 1-.2-.2-.2-.2-.2-.2v-.2h-.2v-.2l-.2-.2v-.2l-.2-.2v-.2h-.2v-.2l-.2-.2-.2-.3-.2-.3.7-.6.3.2.2.3v.2h.2v.2l.2.2v.4h.2v.2l.2.2v.2h.2v.2l.2.2zm-.6 1-.2-.2h.2zm3.5-1 .2 1h-.5l-.2.2h-.8v.2h-1.3l-.2-.2h-.2l-.2-.2h-.2l.5-1v.2h.6l.2.2h1.1l.2-.2h.4l.2-.2zm2.8 0h-1l.5.5h-1l-.2.2h-.4l-.2.2h-.2l-.3-1 .2-.2h.8v-.2h1.5l.5.4zm-.5-.5h.6l-.2.5-.5-.5z"/>
<path fill="#edb92e" d="M391.8 221.2c.7-1 1-.8 1.2-1.3q.2-1.4-1-3.2c-2.2-4.6.3-4.2 3.6-2.4q1.5.7 3 2 1.4 1.5 2.7 2.4c1.6 1.2 2.7 1.2 3 1.7q1.4 3 1.8 4.2.6 1.2 1.6 4.2c0 .4-1 .5-1.8 2-.7 1.2-1.2 3.5-2 4.7q-2 2.6-3.4 2.4-1.5 0-1.8-4.2a4 4 0 0 0-1.5-3c-.5-.6-.6-.4-2-1.2a9 9 0 0 1-2.4-2q-.7-1-1-2c-.3-1-.8-1.6-.7-2.4a4 4 0 0 1 .8-2z"/>
<path fill="#21231e" d="m392.5 219.7 1 .3v.2l-.2.2v.2h-.2v.2h-.2v.2h-.2l-.2.2v.2h-.2l-.8-.5v-.2l.2-.2.2-.2.2-.2h.2v-.2h.2zm-.8-2.7 1-.5v.4l.2.2v.4l.2.3v.2l.2.2v2l-1-.3v-1.2l-.2-.2v-.4h-.2v-.4h-.2v-.4zm4.2-3-.6.8h-.3l-.2-.3h-.3l-.3-.3h-.3l-.3-.2h-.3l-.2-.2h-.5l-.2-.2h-.6v1.5l.3.4.2.3.2.4.2.5-1 .5v-.4l-.3-.4-.2-.4v-.7l-.2-.2v-1.5l.2-.2h.2l.2-.2h.2l.2-.2h1.2l.2.2h.6l.3.3.3.2h.3l.3.2.2.2.4.2h.3zm2.8 2-.7 1v-.4h-.2l-.2-.2h-.2v-.2h-.2v-.2h-.2v-.2h-.2l-.2-.2h-.2v-.2h-.2l-.2-.2-.2-.2h-.2l-.2-.2.5-1v.2h.2v.2h.2l.2.2h.2v.2h.2l.2.2h.2v.2h.2v.2h.2l.2.2.2.2.2.2h.2v.2zm2.8 2.4-.6.8h-.2v-.2h-.2v-.2h-.2l-.2-.2h-.2v-.2h-.2v-.2h-.2v-.2h-.2l-.2-.2-.2-.2-.2-.2h-.2v-.2h-.2v-.2h-.2l.6-1v.2h.2l.2.2v.2h.2l.2.2.2.2h.2v.2h.2v.2h.2v.2h.2l.2.2.2.2h.2v.2h.2zm3.3 2-1 .3v.2-.2h-.2v-.2h-.4l-.2-.2h-.2l-.2-.2h-.3l-.2-.2h-.3v-.2h-.3v-.2h-.3v-.2h-.3v-.2l.6-.8.2.2h.2v.2h.3l.2.2h.2l.2.2h.2v.2h.4l.2.2h.4v.2h.2l.2.2h.2v.3zm-.2-.3v.2zm1.7 4.5-1 .4v-.7l-.2-.2v-.4l-.2-.2v-.5h-.2v-.4l-.2-.3v-.3h-.2v-.5h-.2v-.5h-.2v-.3l1-.4v.4l.2.3v.2l.2.3v.2l.2.3v.3l.2.3v.4h.2v.4l.2.2v.4h.2v.4zm0 0-1 .4h.3l.3.2-.5-.5.6.5-.5-.5.6.5-.5-.5.2.4-.2-.3v.2l1-.5v.2-.4.4l-.4-.5.6.5-.5-.5.6.5-.5-.5h.4v.3zm0-.2v.2zm1.6 4.7-1-.2v.3-.5l-.2-.3v-.2l-.2-.3v-.3l-.2-.3v-.2l-.2-.2v-.4l-.2-.2v-.2l-.2-.2v-.4l-.2-.2 1-.5v.4h.2v.5h.2v.5l.2.2v.3l.2.3v.5l.2.2v.3l.2.2v.2l.2.2v.6zm0-.3v.3zm-1.7 2.4-1-.4.2-.2v-.2h.2v-.2l.2-.2v-.2h.2v-.2h.2l.2-.2h.2v-.2h.2v-.2l1 .2v.4h-.2v.2h-.2v.2h-.2l-.2.2-.2.2-.2.2-.2.2-.2.2zm-2.2 5-.7-.7.2-.3v-.2h.2v-.3l.2-.2v-.4l.2-.2v-.5h.2v-.4h.2v-.5h.2v-.2l.2-.3v-.2l.2-.3v-.2l.2-.2 1 .5-.2.2v.3h-.2v.4h-.2v.5l-.2.2v.3l-.2.2v.3l-.2.2v.3l-.2.2v.3l-.2.2v.3h-.2v.3h-.2v.3l-.2.2v.2zm-3.7 2.7.2-1h.4v-.2h.2l.2-.2h.2v-.2h.2l.2-.2.2-.2.2-.2.2-.2.2-.3.2-.2v-.2h.2v-.3l1 .7h-.2v.3h-.3v.3h-.2v.3h-.4v.4h-.2v.2h-.2l-.2.2-.2.2-.2.2h-.3v.2h-.4v.2h-1zm-2.2-5h1v.3l.2.2v1.1h.2v.5l.2.2v.3l.2.2v.2h.2v.2h.2v.2h.2v1h-.8v-.2h-.2l-.2-.2-.2-.2v-.3h-.2v-.2l-.2-.2v-.3l-.2-.3v-.4h-.2v-1l-.2-.2v-1zm-1.2-2.6.7-.6.2.2v.2h.2v.2l.2.2v.2h.2v.3l.2.2v.2h.2v.7h.2v.6l-1 .2v-1h-.2v-.4l-.2-.2v-.2h-.2v-.2h-.2v-.4h-.2v-.2zm-2-1 .4-.8h.3v.2h.4v.2h.4v.2h.4v.2h.4v.2h.2v.2l-.6.7h-.2l-.2-.2h-.4v-.2h-.4l-.2-.2h-.2l-.2-.2h-.3zm-2.5-2 .7-.6.2.2.2.2.2.2.2.2h.2v.2h.2v.2h.2l.2.2h.2v.2h.2l.2.2-.5 1v-.2h-.2v-.2h-.4v-.2l-.2-.2h-.2l-.2-.2-.2-.2-.2-.2-.2-.2h-.2v-.2h-.2v-.2zm-1.2-2.3 1-.4v.2h.2v.4h.2v.5h.2v.4h.2v.2l.2.2-.7.7h-.2v-.4h-.2v-.4h-.2v-.4l-.2-.2v-.8h-.2v-.2zm-.6-2.5h1v.8h.2v.4l.2.2v.2l.2.2v.2l-1 .5v-1h-.2v-.4h-.2v-.6h-.2v-.8zm1 0v.2zm.4-1.5v-1l.3.8v.4h-.2v.2h-.2v.8h-.2v.2h-1v-.9l.2-.2v-.4l.2-.2v-.2h.2v-.4h.2v-.2h.2l.4.7zm0-1h1l-.7.8-.2-.8zm0 0v1l-.4-.8.4-.3zm0 1h-1l.6-.8.4.7z"/>
<path fill="#21231e" d="m406.5 226 .2 1q-2.1.6-3.6 1.8c-1.5 1.2-1.7 2-2.3 3.2q.4-2.1 2-3.7a7 7 0 0 1 3.8-2.2zm-.6-1.6-.5-1q-2.4 0-4.7-1t-4.4-2.8q1.6 2 4.3 3.3 2.5 1.1 5.2 1.5z"/>
<path fill="#edb92e" d="M391.4 213.8c1 .4 1.6.8 2.8 1.8q1.2 1 1.5 3 0 1.7-.3 3.8-.3 1.4.5 3.6.5 2.3 2 3.5c2.3 2.5 4 5 3.4 6.7a4 4 0 0 1-1.5 1.8q-.7-.8-1.4-2.2a8 8 0 0 0-1.5-3.5c-.5-.6-.7-1.3-2-2.2-1-.5-2-.3-2.6-1-1.2-1.6-3-5.5-1.3-7.2s2.3-2.7 1-5.6q-.6-1.5-.6-2.4z"/>
<path fill="#21231e" d="m394.5 215.2-.7.8-.2-.2-.2-.2-.2-.2h-.2v-.2h-.2v-.2h-.4v-.2h-.2l-.2-.2h-.2l-.2-.2h-.4l.3-1h.4v.2h.4v.2h.4v.2h.4v.2h.2v.2h.2l.2.2.2.2h.2v.2h.2v.2zm1.7 3.2-1 .2v-.6h-.2v-.7h-.2v-.4l-.2-.2v-.2h-.2v-.2h-.2v-.2h-.2v-.2h-.2l.7-.8h.2v.2l.2.2v.2h.2v.2l.2.2v.2h.2v.4l.2.2v.4h.2v.8h.2v.2zm-.3 4h-1V221h.2v-2.4l1-.2v3.3l-.2.2zm-1 0v-.3zm1.4 3.5-1 .2v-.5l-.2-.3v-.4l-.2-.3v-.8h-.2v-1.4h1v1.9h.2v.7h.2v.7h.2zm1.8 3.2-.7.7v-.2l-.2-.2h-.2v-.4h-.2v-.2l-.2-.3v-.2h-.2v-.2l-.2-.3v-.2h-.2v-.5l-.2-.2-.2-.3v-.4h-.2l1-.4v.2l.2.2v.2l.2.3.2.2v.3l.2.2v.2h.2v.2h.2v.4h.2v.2h.2v.2h.2v.2zm3.6 7.2-1-.4.2-.2v-1.3l-.2-.2v-.4l-.2-.2v-.2l-.2-.2-.2-.2v-.2l-.2-.2-.2-.2v-.2l-.3-.2-.2-.3v-.3l-.3-.2-.2-.2-.2-.3-.2-.2-.2-.2-.2-.2-.3-.3h-.2l.7-.8.3.2.2.2.2.3.3.4.3.2.2.2v.3l.3.3.3.2.2.3v.2l.3.2.2.3v.2l.2.2.2.2v.2l.2.2v.2l.2.3v.7l.2.2v1.2l-.2.2zm-2.4 1.8 1-.4-.8-.2.2-.2h.2v-.2h.2v-.2h.2v-.2l.2-.2v-.2l.2-.2v-.2l1 .4v.2l-.2.2v.2l-.2.2v.2h-.2v.2h-.2v.2h-.2v.2h-.2v.2h-.2l-.2.2zm.8.2-.5.3-.3-.5zm-2-2.5 1-.3v.4h.2v.4h.2v.2h.2v.2l.2.2v.2h.2v.4l-.8.4v-.2h-.2v-.2l-.2-.2v-.2h-.2v-.2h-.2v-.4l-.2-.2v-.2zv-.3zm-1.5-3.3.8-.7v.2h.2v.2l.2.2v.2l.2.2v.2h.2v.5h.2v.4l.2.2v.4l.2.3v.7l-.8.2v-.4h-.2v-.5l-.2-.2v-.5h-.2v-.2l-.2-.2v-.2l-.2-.2v-.2h-.2v-.2l-.2-.2zm-2-2.2.4-1 .3.2.2.2h.2l.2.2.2.2.2.2v.2h.2v.2h.2v.2l.2.2.2.2v.2h.2v.2l-.7.7-.2-.2v-.2h-.2v-.2h-.2v-.4h-.2v-.2h-.2v-.2h-.2v-.2h-.2v-.2h-.4v-.2zm-2.7-1.3.8-.6h.2v.2h.2v.2h.9l.2.2h.4l.2.2h.2l.2.2-.4 1v-.2h-.4l-.2-.2h-.9v-.2h-.4l-.2-.2h-.2l-.2-.2-.2-.2zm-1.2-7.8.7.7v.3h-.2v.3h-.2v2.2l.2.3v.5l.2.2v.2l.2.3v.2l.2.2v.2l.2.2v.2l.3.2v.2h.2v.3l.2.2-.7.7-.2-.3-.2-.3v-.2l-.2-.2v-.2h-.3v-.3l-.2-.3-.2-.4v-.2l-.2-.3v-.2l-.2-.2v-.6l-.2-.3v-2.1l.2-.3v-.2h.2l.2-.3.2-.3zm.7-5 1-.5v.5l.2.2v.3l.2.2v.7h.2v1.7l-.2.2v.2l-.2.2v.2h-.2v.3h-.2v.2l-.2.2-.3.3h-.2l-.2.3-.8-.6.2-.3h.2l.2-.3.2-.3.2-.2v-.3l.2-.2v-.2l.2-.3v-.7l-.2-.2v-.5l-.2-.2-.2-.4v-.2zm0-3v1l.4-.7v1.4h.2v1.1h.2l-1 .6v-.9h-.2v-.7l-.2-.2v-1l.4-.7zm-.6.5-.3-.7h.7l-.5.6zm.4.3v-1zm0-1"/>
<path fill="#edb92e" d="M434 226.2c-1.2 1-1.5 1-2 1.6q-.3 1.3.3 3.3c1.5 5-1.4 4.4-5 2.6-1.6-1-3.6-3.2-5.2-4.4-1.5-1-2.6-1-3-1.6l-1-4.3q-.1-1.2-1-4.4c.4-.7 1.4-1 2.5-2.5 1-1.7 2.2-4.7 3.6-6 3-3.2 6-4.5 6 1.3 0 1.4.3 3 1 3.6s1 .3 2.5 1q1.6 1 2.6 2c.7 1 .5 2 .7 2.8 0 1 .5 1.7.2 2.6q-.6 1.4-2 2.4z"/>
<path fill="#21231e" d="m432.6 228-1-.5h.2v-.4h.4v-.2h.4v-.2h.2l.2-.2h.2v-.2h.2v-.2h.2v-.2l.8.8-.2.2h-.2v.2h-.2l-.2.2-.2.2h-.2v.2h-.4v.2zm0 2.9-.8.3v-.2l-.2-.2v-.7h-.2v-2.3h.2v-.2l1 .4v.2h-.2v2.1h.2v.7zm-5.4 3 .5-.8h.3l.3.3h.3l.3.3h.2l.3.2h.2l.3.2h.7l.2.2h.7v-.2h.2v-.4l.2-.3v-1.1l-.2-.3v-.3l-.2-.4 1-.4v.4l.2.4v.8l.2.3v1.1l-.2.4v.2l-.3.2-.2.2h-.2l-.2.2-.4.2h-1.2l-.3-.2h-.6l-.3-.3-.2-.2h-.3l-.3-.2-.4-.2-.3-.2zm-5.4-4.3.6-1 .2.2.3.2.2.3h.2v.3h.3v.3l.3.2.2.2h.2v.3h.3l.2.3.2.3.2.2.3.3h.2v.2l.2.2h.2l.2.2v.2h.3v.2h.2l.2.2.3.2-.5 1-.2-.2h-.2v-.2l-.3-.2h-.2l-.2-.2-.2-.3h-.2l-.2-.2h-.2v-.3h-.3l-.3-.3h-.2v-.3l-.3-.3h-.2l-.2-.3-.3-.3h-.2v-.2h-.3l-.2-.3-.3-.3-.3-.2-.3-.2h-.2zm-3.4-2 1-.2v-.2h.2v.2h.4l.2.2h.4v.2h.7l.2.2h.2l.2.2.3.2h.2l.2.2-.6 1v-.2h-.3v-.2h-.2l-.2-.2-.2-.2h-.3l-.2-.2h-.2v-.2h-.4l-.2-.2h-.2l-.2-.2h-.2v-.2h-.2v-.3zm.2.3v-.3zm-.6-4.2v-1l.5.4v.4l.2.2v1h.2v1.3h.2v1h.2v.5l-1 .2v-.7l-.2-.3v-.7l-.2-.3v-.7h-.2v-.8l-.2-.2v-.6l.4.4zm0-1h.5v.4zm-.5.6 1-.2v-.2l-.5-.2v1h-.3zm-.8-4.7 1 .4v-.2 1.1h.2v1.1l.2.3v.8l.2.2v.9l-1 .2V222l-.2-.2v-.8l-.2-.3v-.7h-.2v-.8l-.2-.2v-.3zm0 .3v-.3zm2.4-2.8 1 .5-.2.2-.2.2-.2.3-.2.2-.2.2h-.2v.2h-.2l-.2.2h-.2v.2h-.2v.2h-.2v.2h-.2l-1-.3h.2v-.4h.2v-.2h.4v-.2h.2l.2-.2.2-.2.2-.2h.2v-.2l.2-.2.2-.2v-.2h.2zm3.7-6.2.8.7h-.2v.3h-.2v.3l-.3.3v.2l-.2.2v.2h-.2v.3l-.2.3v.4l-.3.2v.2l-.2.2v.2l-.2.2v.2l-.2.2v.3l-.2.3v.2l-.2.2v.2h-.2v.2l-.2.2-.2.2-1-.4.2-.2.2-.3v-.2h.2v-.3l.2-.2v-.2l.2-.2v-.2l.2-.2v-.2l.2-.2v-.3l.2-.2v-.2h.2l.2-.3v-.2l.2-.2v-.3l.2-.2v-.2l.3-.2v-.2l.2-.2.2-.3v-.2l.2-.2h.2zm6.8 1.8h-1v-1.4l-.2-.4v-.6l-.2-.2v-.4l-.2-.2h-.3v-.2h-1.2l-.3.2-.3.2h-.2l-.3.3-.2.3-.3.2-.2.2-.3.2-.2.2-.3.2-.2.3-.8-.7.3-.3.3-.3.3-.2.2-.3.3-.3.4-.2.3-.2.2-.2h.2l.3-.3h.2l.3-.2h.3l.2-.2h1.2l.3.2.3.3.2.2.2.2.2.3v.6l.2.5v.4l.2.3v1.5zm1 3.3-.8.8-.2-.2v-.2h-.2v-.2l-.2-.2v-.6l-.2-.2v-.7l-.2-.2V212h1v2h.2v.3l.2.2v.2h.2v.2zm2.2 1-.4 1-.3-.2h-.2l-.3-.2h-.4v-.2h-.9v-.2h-.4v-.2h-.2v-.2l.6-.7v.2h.4v.2h.8l.2.2h.4l.2.2h.2l.2.2zm2.8 2.2-.8.6h-.2v-.2l-.2-.2h-.2v-.4h-.2l-.2-.2h-.2v-.2h-.2v-.2h-.4v-.2h-.2l-.2-.2.3-1 .3.2h.2l.2.2.2.2h.2v.2h.2l.2.2h.2v.2h.2v.2h.2v.2h.2v.2h.2v.2h.2zm-.8.6.4.5zm1.5 2.3-1 .2V220l-.2-.2v-.8h-.2v-.4l.7-.6v.2l.2.2v.2l.2.2v2.2h.2v.2zm0 3-.8-.4v-2.1l-.2-.2v-.4h1v1l.2.2v1.8zm-1.8 2.6-.7-.8h.2v-.2l.2-.2v-.2h.2v-.2h.2v-.2h.2v-.2l.2-.2v-.2l.2-.2v-.2h.2v-.2l1 .4-.2.2v.2l-.2.2v.2h-.2v.4h-.2v.2h-.2v.2l-.2.2-.2.2v.2h-.2l-.2.2zm-.7-.8"/>
<path fill="#21231e" d="m418 222.6-.2-1a14 14 0 0 0 7.8-5.3c-1.2 3-4.3 5.3-7.7 6.3zm.2 1.5q0 .6.3 1 5 0 9.2 3c-2-2.3-5.8-3.8-9.5-4"/>
<path fill="#edb92e" d="M432.7 233.3a11 11 0 0 1-3.4-1.5c-1.6-1.3-1.2-3.8.3-6.4q.6-1.4.2-3.5a6 6 0 0 0-1.4-3.5c-2.4-2.3-3.8-4.8-2.6-6.6q1.4-1.8 2.8-2.7.4 1 .4 2.5c0 1.4.3 3 1 3.6s1 .3 2.5 1q1.6 1 2.6 2c.7 1 .6 2 .7 2.8 0 1 .5 1.7.2 2.6q-.6 1.4-2 2.4c-1.2 1-1.5 1-2 1.6q-.3 1.3.3 3.3.4 1.4.4 2.3z"/>
<path fill="#21231e" d="m429 232.2.6-.8h.2v.2h.2l.2.2h.2l.2.2h.2l.2.2h.4v.2h.4l.2.2h.4l.2.2h.2l-.3 1h-.4v-.2h-.4l-.2-.2h-.3v-.2h-.4l-.2-.2h-.2l-.2-.2h-.2v-.2h-.2l-.3-.2h-.2v-.2zm0-7 1 .5v.2h-.2l-.2.4v.2l-.2.2v.2l-.2.3v.4l-.2.2v.5l-.2.2v1.5l.2.3v.2h.2v.3l.2.2.2.2-.6.8-.2-.2-.3-.3v-.2h-.2v-.3l-.2-.2v-.4l-.2-.3V228h.2v-.7l.2-.3.2-.3v-.3l.2-.2v-.3l.3-.3v-.5zm.3-3.3 1-.2v.8h.2v1.9l-.2.2v.7h-.2v.2l-1-.4h.2v-.6h.2V222zm-1.3-3.2.7-.7v.2h.2v.4h.2v.2l.2.2v.2l.2.2v.2l.2.2v.5h.2v.7l.2.2v.8h-1v-1.2l-.2-.2v-.4h-.2v-.4h-.2v-.2l-.2-.2v-.2h-.2v-.2l-.2-.2zm-2.7-7.2 1 .6h-.2v.7l-.2.2v.7l.2.2v.4l.2.2v.2l.2.2v.2l.2.2v.2l.3.2v.2l.2.2.2.2v.2l.3.3.2.3v.2l.3.2.2.2h.2l-.7.8-.2-.2-.2-.2-.3-.2-.2-.2v-.3l-.2-.2-.2-.2-.2-.2-.2-.2v-.2l-.3-.2-.2-.3h-.2v-.3l-.2-.2v-.3l-.2-.2v-.2l-.2-.3v-.4l-.2-.2v-1l.2-.3v-.2l.2-.2v-.2zm3.8-2.5-.8.4.7.3h-.2l-.2.2h-.2l-.2.2h-.2v.2h-.2v.2h-.2l-.2.2-.2.2-.2.2-.2.2-.2.2v.2h-.2v.2l-.2.2-1-.6h.2v-.2l.2-.2.2-.2v-.2h.2v-.2h.2v-.2h.2v-.2h.2l.2-.2.2-.2h.2v-.2h.2l.2-.2.2-.2h.2v-.2zm-.6 0 .5-.5v.6h-.6zm1 2.8h-1v-2.1h-.2v-.4l1-.3v1h.2v2zm1 3.3-.7.8-.2-.2v-.2h-.2v-.2l-.2-.2v-.7l-.2-.2v-.7l-.2-.2V212h1v1.7h.2v.6l.2.2v.2h.2v.2l.2.2zm2.3 1-.4 1-.3-.2h-.2l-.3-.2h-.4v-.2h-.9v-.2h-.4v-.2h-.2v-.2l.6-.7v.2h.4v.2h.8l.2.2h.4l.2.2h.2l.2.2zm2.8 2.2-.8.6h-.2v-.2l-.2-.2h-.2v-.4h-.2l-.2-.2h-.2v-.2h-.2v-.2h-.4v-.2h-.2l-.2-.2.3-1 .3.2h.2l.2.2.2.2h.2v.2h.2l.2.2h.2v.2h.2v.2h.2v.2h.2v.2h.2v.2h.2zm-.8.6.4.5zm1.5 2.3-1 .2V220h-.2v-.8h-.2v-.4l.7-.6v.2l.2.2v.2l.2.2v2h.2v.2zm0 3-.8-.4v-2.2l-.2-.2v-.4h1v1l.2.2v1.8zm-1.8 2.6-.7-.8h.2v-.2l.2-.2v-.2h.2v-.2h.2v-.2h.2v-.2l.2-.2v-.2h.2v-.4h.2v-.2l1 .4-.2.2v.2l-.2.2v.2l-.2.2v.2h-.2v.2h-.2v.2l-.2.2-.2.2v.2h-.2l-.2.2zm-1.7 1.4-1-.5v-.2h.2v-.2h.2v-.2h.4v-.2h.2l.2-.2h.2v-.2h.2v-.2h.2v-.2l.8.8-.2.2h-.2v.2h-.2l-.2.2-.2.2h-.2l-.2.2h-.2zh-.2v.2zm0 2.9-1 .3v-.7h-.2v-3h.2l1 .4h-.2v2.6h.2v.2zm-.2 2.8.3-1-.6.5v-1h-.2v-.9l-.2-.2 1-.5v.9h.2v1h.2v.7zm.7-.5v.7l-.7-.2zm-.5 0-.2.5zm.5 0v.7l-.7-.2z"/>
<path fill="#edb92e" d="M410.6 216.4c4 0 8 3.4 8.4 7.7.6 4.4-2.2 7.7-6 7.8-4 0-7.5-3-8.3-7.3-.7-4 1.8-8 6-8z"/>
<path fill="#21231e" d="m419.5 224-1 .2v-.8l-.2-.4v-.3l-.2-.4v-.3l-.2-.4-.2-.3-.2-.3-.2-.4-.2-.3-.2-.3-.3-.2-.2-.3-.3-.3-.2-.2-.3-.3-.3-.2-.3-.2-.4-.2h-.3l-.3-.3h-.4l-.3-.3h-.3l-.4-.2h-.3l-.3-.2h-1.5v-1h1.9l.4.2h.3l.4.3h.4l.4.3.4.2.3.2.5.2.3.3.3.2.4.2.3.3.3.3.3.3.3.4.2.3.2.4.3.4.2.4.2.4.2.4v.4l.2.4v.4l.2.4v.8zm-6.6 8.3v-1h.9l.2-.2h.6l.3-.2h.4l.2-.2.3-.2h.2l.2-.3h.2l.2-.3.3-.3.3-.2v-.2l.3-.3.2-.2v-.3l.3-.3.2-.4v-.3l.2-.3v-.7l.2-.3V224l1-.2v2.5l-.2.4v.8l-.3.4v.3l-.2.3v.4l-.3.3-.2.3-.3.3h-.2l-.2.4-.3.2-.3.3h-.3l-.3.3-.3.2h-.2l-.3.3h-.4l-.2.2h-.4l-.3.2H413zm-8.7-7.7 1-.2v.7l.2.5v.3l.3.4v.3l.3.3.2.4.2.3.2.3.2.3.2.3.3.3.2.3h.3l.2.3.3.3.2.2.3.2.3.2h.4l.3.3.3.2h.3l.3.2h.7l.3.2h1.2v1h-2l-.3-.2h-.4l-.4-.3h-.4l-.4-.3-.3-.2-.4-.2-.3-.2-.4-.2-.4-.2-.3-.3-.2-.2-.2-.2-.3-.3-.2-.3-.3-.3-.2-.4-.2-.3-.2-.3-.2-.4-.2-.3-.2-.4v-.4l-.2-.4-.2-.4v-.8zm6.2-8.7v1h-1l-.3.2h-.4l-.3.2h-.3l-.3.3h-.2l-.2.3-.3.2-.2.2v.2l-.3.2-.2.2-.2.3-.2.3v.2l-.2.3v.4l-.3.3v.6l-.2.3v.7l-.2.3v.7l.2.4v.8l-1 .2v-3.3l.2-.3v-.3l.2-.4v-.3l.3-.4v-.3l.3-.3.2-.3.2-.3.2-.3h.2l.2-.4.3-.2.3-.2.3-.2.3-.2.3-.2.3-.2h.3l.4-.2h.4l.3-.2h.9z"/>
<path fill="#edb92e" d="M411 218.6c2.8-.2 5.7 2.4 6 5.5.5 3.3-1.5 5.8-4.4 5.8-2.8 0-5.5-2.3-6-5.3s1.3-5.8 4.3-6z"/>
<path fill="#21231e" d="m417.6 224-1 .2v-.6l-.2-.3v-.2l-.2-.3v-.4l-.2-.2v-.2l-.2-.3-.2-.3v-.2l-.3-.2-.2-.2-.2-.3-.2-.2-.2-.2h-.2l-.2-.3h-.2l-.3-.3h-.2l-.2-.2-.4-.2h-.5v-.2h-1.1v-1h1.1l.4.2h.3l.2.2h.2l.3.2h.3l.2.3h.3l.2.2.3.2h.2l.3.3.2.3.2.2.2.2v.2l.3.3h.2v.4l.3.3v.3l.3.2.2.3v.3l.2.3v.8l.2.3zm-5 6.3v-1h1.1l.2-.2h.4l.2-.2h.2v-.2l.3-.2h.3v-.2l.3-.2v-.2h.2l.2-.3v-.2l.2-.2.2-.3v-.7l.2-.2v-1.6h1v2.2l-.2.3v.2l-.2.3v.2l-.3.3-.2.2v.3l-.3.2-.2.2-.2.2-.3.2-.2.2-.2.2h-.2l-.2.2h-.2l-.3.2h-.2l-.2.2zm-6.5-5.8h1l.2.4.2.4v.2l.2.3.2.3v.3l.3.2.2.2.2.2v.2l.3.2.2.2.3.3.2.2.2.2h.2v.3h.3l.2.2h.7l.2.2h1.1v1H411l-.4-.2h-.2l-.3-.2h-.2l-.2-.3h-.3l-.2-.3-.4-.3-.2-.3-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.2-.3v-.2l-.3-.2-.2-.2-.2-.3v-.3l-.2-.3v-.3l-.2-.2v-.7zm5-6.4v1h-.6l-.2.2h-.5l-.2.2h-.2l-.2.2-.2.2h-.2l-.2.3v.2l-.3.2-.2.3v.2h-.2v.3l-.2.2v.2l-.2.2v.7l-.2.2v1.7h-1V222h.2v-.4l.2-.3v-.2l.2-.2v-.2l.3-.3v-.2h.2l.2-.3.2-.2.2-.2.2-.2h.2l.2-.2h.3l.2-.3h.2l.2-.2h.6l.3-.2h.6z"/>
<path fill="#0c4076" d="M411.2 220.7c2 0 3.6 1.5 4 3.5.2 2-1 3.6-3 3.6a4 4 0 0 1-3.7-3.4c-.3-2 1-3.6 2.7-3.7"/>
<path fill="#21231e" d="m415.6 224-1 .3v-.4l-.2-.2v-.4h-.2v-.3l-.2-.2-.2-.3-.2-.2-.2-.2h-.2l-.2-.2-.2-.2h-.2l-.2-.2h-.6v-.2h-.6v-1h1l.2.2h.2l.3.2h.3v.2h.3l.2.3v.2h.3l.2.2.2.2.2.3.3.2v.4h.2v.3l.2.3v.4zm-3.3 4.3v-1h.7l.2-.2h.4v-.2h.2v-.2h.2v-.2h.2v-.2l.2-.2v-.5l.2-.2v-1.1l1-.3v2h-.2v.3l-.2.3-.2.3-.2.2h-.2v.2l-.2.2h-.2v.2h-.3l-.2.2h-.4v.2h-1zm-4.3-3.8 1-.2v.5l.2.3v.4h.2v.2l.2.2.2.2.2.3.2.2.2.2h.3v.2h.4l.3.2h.8v1h-1.3l-.2-.2h-.2l-.3-.2h-.2v-.2h-.2v-.2l-.3-.2-.3-.2v-.2h-.2v-.3h-.3v-.3l-.2-.2v-.2h-.2v-.5l-.2-.2v-.5zm2.7-3.8h1l-.5.5h-.7l-.2.2h-.2v.2h-.2l-.2.2-.2.2-.2.2v.2h-.2v.5h-.2v1.3l-1 .3v-1.8h.2v-.5h.2v-.3h.2v-.3h.3v-.3h.3v-.2h.3v-.2h.3v-.2zl.2-.2h.4l-.5.5zm1 0v.5h-.5zm0 0h-1l.5-.5zm-1 0v-.5h.5z"/>
</g>
<path fill="#fff" d="M482 183c4 0 7 3 7 7s-3 6.7-7 6.7c-3.6 0-6.7-3-6.7-6.8 0-4 3-7 6.8-7z"/>
<path fill="#21231e" d="M489.5 189.8h-1c0-2.3-1.4-4.6-3.5-5.6a6 6 0 0 0-3-.7v-1q4.1.1 6.4 3.5a7 7 0 0 1 1 3.8zm-7.4 7.4v-1q4-.2 5.8-3.4a6 6 0 0 0 .7-3h1c0 2.6-1.5 5.2-3.7 6.5a7 7 0 0 1-3.7 1zM475 190h1a6.4 6.4 0 0 0 6.3 6.2v1a7 7 0 0 1-6-3.4 7 7 0 0 1-1.2-4zm7.3-7.5v1a6 6 0 0 0-5.5 3.5 6 6 0 0 0-.7 3h-1q.2-4.2 3.5-6.4a7 7 0 0 1 3.8-1z"/>
<path fill="#fff" d="M482 171c4 0 7 3 7 7a6.8 6.8 0 1 1-13.7-.2c0-3.7 3-6.7 6.8-6.7z"/>
<path fill="#21231e" d="M489.5 178h-1c0-2.4-1.4-4.7-3.6-5.8a6 6 0 0 0-3-.6v-1q4.1.1 6.4 3.4a7 7 0 0 1 1 4zm-7.4 7.3v-1c2.5 0 4.7-1.4 5.8-3.4a6 6 0 0 0 .7-3h1c0 2.5-1.5 5-3.7 6.4a7 7 0 0 1-3.7 1zM475 178h1a6.4 6.4 0 0 0 6.3 6.3v1a7 7 0 0 1-6-3.4 7 7 0 0 1-1.2-4zm7.3-7.4v1a6 6 0 0 0-5.5 3.5 6 6 0 0 0-.7 3h-1c0-2.6 1.4-5 3.5-6.3a7 7 0 0 1 3.8-1z"/>
<path fill="#fff" d="M482 159.6c4 0 7 3 7 7a6.8 6.8 0 1 1-13.7-.2c0-3.7 3-6.8 6.8-6.8z"/>
<path fill="#21231e" d="M489.5 166.5h-1c0-2.4-1.4-4.7-3.6-5.7a6 6 0 0 0-3-.7v-1c2.6 0 5 1.5 6.4 3.6a7 7 0 0 1 1 4zM482 174v-1c2.5 0 4.7-1.5 5.8-3.6q.6-1.5.7-3h1c0 2.6-1.4 5-3.5 6.4a7 7 0 0 1-4 1zm-7.2-7.5h1c0 2.4 1.4 4.7 3.6 5.7a6 6 0 0 0 2.7.7v1a7 7 0 0 1-6-3.6 7 7 0 0 1-1.2-4zm7.3-7.4v1a6 6 0 0 0-5.5 3.6 6 6 0 0 0-.7 3h-1c0-2.6 1.4-5 3.5-6.4a7 7 0 0 1 3.8-1z"/>
<path fill="#fff" d="M482 127c4 0 7 3.2 7 7s-3 6.8-7 6.8a7 7 0 0 1 .1-13.8z"/>
<path fill="#21231e" d="M489.5 134h-1c0-2.4-1.4-4.7-3.6-5.8a6 6 0 0 0-3-.6v-1q4.1.1 6.4 3.4a7 7 0 0 1 1 4zm-7.4 7.3v-1q4-.2 5.8-3.4a6 6 0 0 0 .7-3h1c0 2.5-1.5 5-3.7 6.3a7 7 0 0 1-3.7 1zM475 134h1c0 2.3 1.4 4.6 3.5 5.6a6 6 0 0 0 2.8.7v1a7 7 0 0 1-6-3.4 7 7 0 0 1-1.2-4zm7.3-7.4v1a6 6 0 0 0-5.5 3.5 6 6 0 0 0-.7 3h-1c0-2.6 1.4-5 3.5-6.3a7 7 0 0 1 3.8-1z"/>
<path fill="#fff" d="M482 137.2c4 0 7 3 7 6.8s-3 7-7 7c-3.6 0-6.7-3.2-6.7-7s3-6.8 6.8-6.8z"/>
<path fill="#21231e" d="M489.5 144h-1c0-2.3-1.4-4.6-3.5-5.7a6 6 0 0 0-3-.6v-1c2.7 0 5.2 1.4 6.5 3.6a7 7 0 0 1 1 3.7m-7.4 7.4v-1c2.5 0 4.7-1.4 5.8-3.4a6 6 0 0 0 .7-3h1c0 2.6-1.5 5-3.7 6.4a7 7 0 0 1-3.7 1zM475 144h1c0 2.4 1.4 4.7 3.5 5.7a6 6 0 0 0 2.8.7v1a7 7 0 0 1-6-3.5 7 7 0 0 1-1.2-4zm7.3-7.4v1a6 6 0 0 0-5.5 3.6q-.7 1.6-.7 2.8h-1c0-2.5 1.4-5 3.5-6.2a7 7 0 0 1 3.8-1.2z"/>
<path fill="#fff" d="M482 148.2c4 0 7 3 7 6.8s-3 7-7 7c-3.6 0-6.7-3.2-6.7-7s3-6.8 6.8-6.8z"/>
<path fill="#21231e" d="M489.5 155h-1c0-2.3-1.4-4.6-3.6-5.7a6 6 0 0 0-3-.6v-1q4.1.1 6.4 3.4a7 7 0 0 1 1 4zm-7.4 7.4v-1c2.5 0 4.7-1.4 5.8-3.4a6 6 0 0 0 .7-3h1c0 2.6-1.5 5-3.7 6.4a7 7 0 0 1-3.7 1zM475 155h1c0 2.4 1.4 4.7 3.5 5.7a6 6 0 0 0 2.8.7v1a7 7 0 0 1-6-3.4 7 7 0 0 1-1.2-4zm7.3-7.4v1a7 7 0 0 0-5.5 3.5 6 6 0 0 0-.7 3h-1c0-2.5 1.4-5 3.5-6.3a7 7 0 0 1 3.8-1z"/>
<path fill="#edb92e" d="M487 195.5c1 1.6.7 2 1.4 2.4q1.3.8 3.4.4c5.3-1 4.5 2.3 2.2 6-1 1.7-3.8 3.5-5.2 5s-1.6 2.8-2 3.2h-9.2c-.5-.4-.7-1.7-2-3.2-1.5-1.5-4.2-3.3-5.3-5-2.4-3.7-3-7 2.2-6q2 .4 3.4-.5c.6-.6.3-1 1.3-2.5a7 7 0 0 1 2.2-2.3c1-.5 1.8-.2 2.6-.2 1 0 2-.3 2.8.2a7 7 0 0 1 2.2 2.3z"/>
<path fill="#21231e" d="m488.7 197.5-.7.8-.2-.2h-.2v-.4h-.2v-.4h-.2v-.4l-.2-.2v-.2l-.2-.2-.2-.3v-.2l.8-.6v.2h.2v.3l.2.2v.2h.2v.4h.2v.4h.2v.4h.2zm-.7.8-.3-.3zm3.8-.4v1h-2.4l-.2-.2h-.2l-.2-.2h-.3l-.2-.2.7-1v.2h.2v.2h.8l.2.2h1.9zm2.6 6.6-.8-.6.2-.3.2-.3.2-.4.2-.3v-.3l.3-.3v-.2l.2-.2v-.6l.2-.2v-1.3l-.2-.2h-.2v-.2h-.5l-.2-.2h-2l-.2-1h2.8l.3.2h.2l.2.2.2.2.2.2.2.2v.3l.2.3v1.7l-.2.3v.3l-.3.2v.4l-.3.3v.2l-.3.4v.3l-.3.2-.3.4zm-5.3 5.2-.6-.7.3-.2v-.2h.3l.2-.3v-.2h.3l.2-.2h.2v-.3h.2l.2-.3.2-.2h.2l.2-.3h.2v-.3l.3-.2h.2l.2-.3v-.2l.2-.2.2-.2h.2v-.3h.3v-.4h.3v-.3h.2v-.3l1 .6-.2.2-.2.3v.3l-.2.2h-.2l-.2.3v.2l-.3.2-.3.3v.2h-.3l-.2.3-.2.2h-.2l-.2.3-.2.2-.3.3-.3.3h-.2v.3l-.3.2h-.2v.3l-.3.2h-.2v.3h-.2l-.2.3zm-2.3 3.3v-1l-.3.2v-.2h.2v-.2l.2-.2v-.2l.2-.2v-.2l.2-.2v-.2l.2-.2v-.2h.2v-.2l.2-.2.2-.3.3-.3.8.6v.2l-.2.2-.2.2-.2.3v.2h-.2v.2l-.2.2v.2l-.2.2v.2h-.2v.4h-.2v.2l-.2.2v.2h-.5zm.3 0h-.2zm-5 .2v-1h4.7v1h-4.5zm0-1h.2zm0 0v1zm-4.7.8.6-.8h-.4 4.2l.2 1h-4.7l-.3-.2zm.3 0h-.2zm-2.4-3.2.7-.7v.2l.2.2.2.3.2.3.2.2v.2h.2v.4h.2v.4h.2v.4h.2v.4h.2v.2l-.5.8-.2-.2v-.2l-.2-.2v-.2h-.2v-.4h-.2v-.4l-.2-.2v-.2h-.2v-.2l-.2-.3-.2-.2-.2-.3-.2-.2zm-5.4-5.2 1-.6v.2l.2.3h.2v.3l.2.2h.2v.3h.3v.3l.2.2h.2l.2.3.2.2v.2l.3.2h.3l.2.3h.2l.2.2v.2h.2l.2.3h.2l.2.3h.2v.3l.3.2h.2v.3h.3v.3l-.6.8-.2-.2-.3-.3-.3-.2-.3-.2v-.2l-.2-.2h-.2l-.2-.3h-.2l-.2-.2h-.2v-.3l-.3-.2h-.2l-.2-.3v-.2h-.3l-.2-.3v-.2h-.3l-.2-.3v-.2l-.3-.2h-.2v-.3l-.3-.2-.2-.2-.2-.2zm2.7-6.7v1l-.6-.2h-2.1l-.2.2h-.2v.2h-.2v.4l-.2.2v1.1l.2.2v.3l.2.3v.2l.2.3.2.4v.3l.3.3.3.4.2.3.2.3-1 .6v-.4l-.3-.3-.2-.4-.2-.4v-.3l-.3-.4v-.4l-.3-.3v-.4l-.2-.3v-.6l-.2-.3v-1l.2-.2v-.2l.3-.2.2-.2.2-.2.4-.2h.3l.3-.2zm3-.5.8.8-.2.2h-.2l-.2.2h-.4l-.2.2h-3v-1h2.5l.2-.2h.4v-.2zm1.4-2.3.7.6v.3l-.2.2v.2h-.2v.4h-.2v.8h-.2v.2h-.2v.2l-.2.2-.8-.7h.2v-.4h.2v-.4h.2v-.2l.2-.2v-.4h.2v-.3h.2v-.3zm0 0 .2-.4zm2.3-2.4.5.8-.2.2h-.2v.2h-.2v.2h-.2l-.2.2-.2.2-.2.2v.2h-.2v.2l-.2.2-.2.2v.2l-1-.6.2-.2.2-.2v-.2h.2v-.2l.2-.2h.2v-.2l.2-.2.2-.2h.2v-.2l.2-.2h.2v-.2h.2zm2.8-.3v1h-2.4l-.5-.7h.2v-.2h.4l.2-.2zm3 .3-.5.8h-.4v-.2H482v-1h2.5l.2.2h.2zm0 0 .3.2zm2 3.2v-1l-.4.8-.2-.2v-.2h-.2v-.2l-.2-.2-.2-.2v-.2h-.2v-.2h-.2v-.2h-.2v-.2h-.4v-.2h-.2v-.2l.4-.8h.2l.2.2.2.2h.2v.2h.2v.2h.2v.2h.2v.2h.2v.2l.2.2.2.2v.2h.2v.2h.2v.2zm.4-.8.5.8h-1zm-.4-.2v1l-.4-.2zm-.4.8-.5-.8h1l-.4.8z"/>
<path fill="#21231e" d="m481.4 212.8-1-.2q-.7-5.6-4.3-9.6c2.8 1.8 4.8 5.7 5.4 9.8z"/>
<path fill="#edb92e" d="M494.2 198.3q-.6 1.7-2 3.5c-1.5 1.6-4 .5-6.5-1.6q-1.4-1-3.6-1a6 6 0 0 0-3.4 1c-2.5 2-5 3.2-6.6 1.6q-1.4-1.7-2-3.5h2.5q2 .6 3.4-.4c.6-.6.3-1 1.3-2.5a7 7 0 0 1 2.2-2.3c1-.5 1.7-.2 2.6-.2s2-.3 2.8.2q1.2.8 2.2 2.3c1 1.6.7 2 1.3 2.4q1.5.8 3.5.4 1.5-.3 2.4 0z"/>
<path fill="#21231e" d="m492.6 202-.7-.6v-.2l.2-.2.2-.2v-.2h.2v-.2l.2-.2v-.2l.2-.2v-.2l.2-.2v-.2l.2-.2v-.2l.2-.3v-.4l1 .5v.4l-.2.2v.2l-.2.2v.4h-.2v.2l-.2.2v.3h-.2v.2h-.2v.2h-.2v.3l-.2.2-.2.2h-.2zm-7.3-1.4.7-.7h.2l.2.2.3.2.2.2.3.3h.3l.2.2h.2l.2.2h.2l.2.2h.2l.2.2h.4l.2.2h1.6l.2-.2.2-.2h.2v-.2l.8.7-.2.3h-.2v.3h-.3l-.3.2h-.3l-.2.2h-1.9l-.3-.2h-.3l-.2-.2h-.3l-.2-.2h-.3l-.2-.2-.2-.2h-.3l-.2-.3h-.3l-.2-.3-.2-.2-.2-.2-.2-.2-.3-.2zm.7-.7.5.3zm-4-.2v-1h2v.2h.7v.2h.4l.2.2h.2l.2.2h.2v.2h.2l-.7.8h-.2v-.2h-.2v-.2h-1v-.2h-1v-.2zm-3 .8-.7-.7v-.2h.2l.2-.2h.2v-.2h.2l.2-.2h.5v-.2h1.2v-.2h1v1h-1.5v.2h-.5l-.2.2h-.4v.2h-.2zm-7.3 1.5.7-.6.3.2.2.2h.2v.2h1.7v-.2h.5l.2-.2h.2v-.2h.3l.2-.2.2-.2h.3l.2-.3h.2l.2-.3.3-.2v-.2h.3l.7.6-.3.2-.2.2-.3.2-.2.2-.2.2h-.3l-.2.3h-.3l-.2.2h-.2l-.3.2h-.2l-.2.2h-.2l-.2.2h-.3l-.3.2H473l-.4-.2h-.2l-.2-.2-.2-.2zm-1.7-4 .2 1 .3-.7v.2l.2.2v.3l.2.2v.4l.2.2v.2h.2v.4h.2v.4h.2v.2h.2v.2h.2v.2l.2.2-.7.7h-.2v-.2h-.2v-.2h-.2v-.5h-.2v-.2h-.2v-.3l-.2-.2v-.2h-.2v-.4h-.2v-.4l-.2-.2v-.4h-.2l.4-.8zm-.4.7-.2-.6.6-.2zm3-.6-.2 1-.2-.2H470l-.2-1h2.4zm3-.5.7.8-.2.2h-.2l-.2.2h-.4l-.2.2h-2.8v-1h2.3l.2-.2h.4v-.2h.2zm.7.8-.5.4zm.6-3 .7.5v.3l-.2.2v.2h-.2v.4h-.2v.8h-.2v.2h-.2v.2l-.2.2-.8-.7h.2v-.4h.2v-.4h.2v-.2l.2-.2v-.4h.2v-.3h.2zm2.3-2.5.5.8-.2.2h-.2v.2h-.2v.2h-.2l-.2.2-.2.2-.2.2v.2h-.2v.2l-.2.2-.2.2v.2l-1-.6.2-.2.2-.2v-.2h.2v-.2l.2-.2h.2v-.2l.2-.2.2-.2h.2v-.2l.2-.2h.2v-.2h.2zm2.8-.3v1h-2.3l-.5-.7h.2v-.2h.4l.2-.2zm3 .3-.5.8h-.4v-.2H482v-1h2.5l.2.2h.2zm0 0 .3.2zm2.4 2.4-.8.6-.2-.2v-.2h-.2v-.2l-.2-.2-.2-.2-.2-.2v-.2h-.2v-.2h-.2v-.2h-.4v-.2h-.2v-.2l.4-.8h.2l.2.2.2.2h.2v.2h.2v.2h.2v.2h.2v.2h.2v.2l.2.2.2.2v.2h.2v.2h.2zm1.3 2.3-.7.8-.2-.2h-.2v-.4h-.2v-.4h-.2v-.4l-.2-.2v-.2l-.2-.2-.2-.3v-.2l.8-.6v.2h.2v.3l.2.2v.2h.2v.4h.2v.4h.2v.4h.2zm-.7.8-.3-.3zm3.8-.4v1h-2.4l-.2-.2h-.2l-.2-.2h-.4v-.2h-.2l.7-1v.2h.2v.2h.8l.2.2h1.9zm3 .5-1-.4.3.8H492l-.2-1h2.4l.5.7zm-.5-.7h.6l-.3.7zm0 .5.4.2zm0-.5h.6l-.3.7z"/>
<path fill="#edb92e" d="M482 211.7c4.4 0 8 3.4 8 7.7s-3.6 7.8-8 7.8-7.6-3.5-7.6-7.8 3.5-7.8 7.7-7.8z"/>
<path fill="#21231e" d="m483 212.8.8-.2q.8-5.6 4.3-9.6a15 15 0 0 0-5 9.8z"/>
<use xlink:href="#rs-b" width="1350" height="900" transform="matrix(-1 0 0 1 964.3 0)"/>
<path fill="#edb92e" stroke="#21231e" d="M577 293.6c2 .3 3 1.5 3 2.8s-1 2.6-3 3l-1.6.2c-60.8 5.2-125.7 5.2-186.5 0l-1.6-.3c-2-.3-3-1.6-3-3 0-1.2 1-2.4 3-2.7l1.5-.3c60.7-5.2 125.6-5.2 186.4 0q.8 0 1.5.3z"/>
<path fill="#21231e" d="M412 298.4h-.2v-.2h-.2v-1h.4v-.2.2-.2h2.3l.7-.2h3l.7-.2h3l.7-.2h3l.8-.2h3.3l.7-.2h3.8l.7-.2h.8v1.2h-2.9l-.7.2H428l-.7.2h-2.7l-.8.2H421l.7.2h3.7l.7.2h2.9l.7.2h3.7l.7.2h1.5v1.2h-3.7l-.7-.2h-3.8l-.7-.2h-2.9l-.7-.2H420l-.6-.2h-2.9l-.7-.2H413zv-.2zm46.8-3.3v1.3H453l-.7.2h-6.6l-.7.2h-5l-1 .2h-3.5v-1.2h3.5l.8-.2h5.2l.7-.2h5.9l.7-.2h6.8zm23.3 0v1h-13.7l-.7.2h-8.8v-1h1.4l.8-.2H482zm23.5 0v1.3h-11.1l-.7-.2H482v-1zm23.3 1v1h-5.2l-.8-.2h-5.2l-.7-.2h-6.5l-.8-.2h-4.3V295h.7l.7.2h7.5l.8.2h5l.8.2h5.1l.6.2h2.3zm23.4 1v.2h.4v1h-.2l-.2.2h-3l-.7.2h-2.2l-.7.2h-3.8l-.8.2h-2.8l-.7.2H534l-.8.2h-3.6l-.8.2v-1.2h2.2l.7-.2h3.7l.8-.2h3.7l.7-.2h1.8-1.4l-.8-.2h-2.7l-.7-.2H533l-.6-.2h-3.6V296h6.5l.7.2h3l.8.2h2.8l.7.2h3l.7.2h3l.7.2h1.5zm-116.7 1.4h.2l.2.2v.8h-.2v.2h-.2zm93.3 1.2h-.2l-.2-.2v-.2h-.2v-.8h.2v-.2h.4v1.2zm-50.3-36.2v-1h3.8v1h-4zm-1.2-1h1.2v1h-1.2zm-.6 0h.6v1h-.6zm-1 0h1v1h-1zm-.8 0h.6v1h-.7v-1zm-.5 0h.4v1h-.5v-1zm-.8 0h.8v1h-.8zm-1.2 0h1.2v1h-1.2zm-1 0h1v1h-1zm-.2 0h.2v1h-.2zm-1 0h1v1h-1zm-2.5 1v-1h2.6v1zm-.3-1h.2v1h-.2zm-.2 0h.2v1h-.2zm-1 0h1v1h-1zm-.5 0h.4v1h-.4zm-.4 0h.4v1h-.4zm-1.2 0h1.2v1h-1.2zm0 0v1zm0 1h-.2zm-1.2-1h1.2v1l-1.2.2v-1zm-.4 0h.4v1.2h-.4v-1zm-.8.2h.8v1h-.8zm0 0h.3-.2zm-.3 0h.3v1h-.3zm0 1h-.5zm-1-1h1v1h-1zm-1 0h1v1h-1zm-.2 0v1zm-1 0h1v1h-1zm-.6 0h.5v1h-.4v-1zm0 0v1zm-4.2 1.2v-1h3.5v-.2h.4v1h-2.7l-.2.2h-.8zm-.6-1h.5v1h-.6v-1zm-1.7 0h1.6v1h-1.7zm-.2 0h.3v1h-.2v-1zm-1.3 0h1.4v1h-1.3zm-1 0h1v1h-1zm-.6 0h.7v1h-.6zm0 0v1.2-1zm-1.6.2h1.5v1h-1.5zm0 0v1zm-1.2 0h1.2v1h-1.2zm0 0v1zm-1.2 0h1l.2 1H444v-1zm-.8 0h.8v1h-.7zm-1.6.2h1.6v1h-1.5zm0 0v1zm-6.2 1.3v-1h1.7l.2-.2h3.9v1H436l-.2.2zm-.4-1h.3v1h-.2zm-9 1.4v-1h1.3l.3-.2h3.2l.3-.2h3.5v1h-5.1l-.3.2H426zm-.3-1h.2v1h-.3v-1zm-.5 0h.5v1h-.4zm-18.2 2.2v-1h1.8l.5-.2h1.7l.5-.2h2.4l.6-.2h2.6l.6-.2h2.2l.6-.2h2.8l.6-.2h1.2v1h-2.1l-.6.2h-2.7l-.6.2h-2.3l-.6.2h-2.8l-.6.2h-2.2l-.5.2H408l-.6.2h-.6zm-.3-1h.3v1h-.2zm0 0v1zm-26.3 3.4v-1h.7l1-.2h.8l.8-.2h1.6l.8-.2h1l.7-.2h1.6l.8-.2h1.8l.8-.2h.8l1-.2h1.7l.7-.2h1.7l.8-.2h1.8l.7-.2h1.6l1-.2h1.5l1-.2v1H405l-.7.2h-1.7l-.8.2H400l-.7.2h-.8l-1 .2H396l-.8.2h-1.7l-.8.2H391l-.8.2h-.8l-.8.2H387l-1 .2h-.7l-.8.2H383l-1 .2h-.8l-.8.2zm0-7v1h-.5l-.5.2h-.5l-.3.2-.4.2-.3.2h-.2l-.3.3-.2.2-.3.3v.5l-.2.2v1.1h.2v.3l.2.2.2.2.3.3.3.2h.2l.3.2h.3l.4.2h1v1h-1.6l-.4-.2-.4-.2-.3-.2-.3-.2-.3-.2-.4-.2-.2-.3-.2-.2v-.3l-.3-.3-.2-.3v-1.6l.2-.3.2-.3.2-.4.2-.3.2-.3.4-.3.3-.2.4-.2.3-.2h.4l.5-.2h.6l.5-.2zm26.3-2.3v1H405l-.7.2h-1.7l-.8.2H400l-.7.2H396l-.8.2h-1l-.7.2H392l-1 .2h-1.6l-.8.2h-.8l-.8.2h-1.7l-.8.2h-.8l-.8.2H381l-.8.2v-1h1.7l.8-.2h.8l.8-.2h.8l.8-.2h1.7l.8-.2h1.6l1-.2h.8l.8-.2h1.8l.7-.2h1.7l1-.2h.7l.8-.2h1.8l.7-.2h1.6l1-.2h2.5zm0 1v-1zm37-3.2v1.2H439l-1 .2h-2.3l-1.3.2H431l-1.2.2h-2.2l-1.3.2H424l-1.2.2h-2.3l-1 .2H417l-1.2.2h-1.2l-1 .2h-2.3l-1.3.2h-1l-1.2.2h-1.2v-1h2.2l1.2-.2h1l1.2-.2h2.2l1.3-.2h1l1.2-.2h2.3l1-.2h2.3l1.3-.2h2.4l1.2-.2h2.3l1-.2h3.5l1.2-.2h3.5l1-.2h2.5zm1 1-1 .2v-1h1v1zm.2 0h-.3v-1l.2 1zm.2 0h-.3l-.2-1h.4v1zm1.2 0h-1.2v-1h1.2zm0 0v-1zm15.4-1.4v1h-5.5l-.5.2h-6.5l-.4.2h-2.6v-1h5l.5-.2h7.7l.5-.2zm.8 1h-.8v-1h.8zm0 0v-1zm1.4 0h-1.4v-1h1.4zm.2 0h-.2v-1h.2zm0 0h-.2zm0 0v-1zm1.2 0h-1.2v-1h1.2zm.5 0h-.6v-1h.4v1zm.6 0h-.7l-.2-1h.8zm1 0h-1v-1h1zm.2 0h-.3v-1h.2v1zm.4 0h-.4v-1h.4zm3-1 .2 1H468v-1h3.3zm1.2 1h-1v-1l1-.2v1zm0 0v-1.2 1zm1.3-.2h-1.2v-1h1.2zm3.5-1v1h-3.5v-1zm0 1v-1zm1.3 0h-1.2v-1h1.2zm3.6-1v1h-3.5v-1h3.7zm3.8 0v1H482v-1zm1 1h-1v-1h1.2v1zm.2 0v-1zm3.6-1v1H487v-1h4zm1 1h-1v-1h1.2v1zm.2 0v-1zm1 0h-1v-1h1zm3.3-1v1H493v-1h3zm.5 1h-.4v-1h.5zm.3 0h-.3v-1h.3zm1 0h-1v-1h1zm.6 0h-.7v-1h.8zm.5.2h-.6v-1h.5v1zm1 0h-1v-1h1zm0 0v-1zm0 0h.3zm.3 0h-.2v-1h.3zm1.3 0h-1.3v-1h1.4zm0 0v-1zm0 0h.2zm1 0h-1v-1h1zm15.2-.6v1h-6l-.4-.2H504l-.6-.2h-.9v-1h6l.4.2h6.6l.4.2h1.7zm0 1v-1zm1.3 0h-1v-1h1zm.4 0h-.3v-1h.5v1zm.2 0h-.2v-1h.2zm1 .2h-1v-1h1zm37 1v1h-2.3l-1.2-.2h-1l-1.2-.2h-2.2l-1.3-.2H546l-1-.2h-1.3l-1-.2h-2.3l-1.3-.2H537l-1-.2h-4l-1-.2h-2.6l-1-.2H524l-1-.2h-2.4v-1h4.7l1.2.2h3.3l1.3.2h2.3l1.3.2h2.3l1 .2h2.4l1 .2h2.3l1.3.2h2.3l1 .2h2.3l1.2.2h1.2l1 .2h1.3l1 .2h1.3zm0 1v-1zm26.4 1.4v1H582l-.8-.2h-.8l-.8-.2H578l-.7-.2h-.8l-.8-.2H574l-.8-.2h-.8l-.8-.2h-1.8l-.7-.2h-1.5l-.8-.2H565l-.8-.2h-1.7l-.8-.2H560l-.8-.2h-1.6v-1h3.5l.8.2h1.6l1 .2h1.7l.7.2h1.7l.8.2h1.8l.7.2h.8l.8.2h1.8l.8.2h.8l.8.2h1.8l.7.2h.7l.8.2h1.8zm0 7v-1h1.6l.3-.2h.3l.3-.2.2-.2.2-.2h.2v-.3l.2-.2v-.2h.2v-1.4l-.2-.3v-.2h-.3l-.2-.3-.3-.2h-.2l-.3-.3-.4-.2h-.4l-.4-.2h-.4l-.5-.2v-1h.5l.6.2h.5l.5.3.4.3.4.2.3.2.4.3.3.3.2.3v.3l.3.2v.3l.2.3v1.3l-.3.3v.3l-.3.3-.3.4-.3.2-.3.2-.2.2-.3.2-.4.2h-.3l-.4.2H584zm-26.5-2.4v-1h1.8l.8.2h1.8l.8.2h1.8l.7.2h1.7l1 .2h.7l.8.2h1.8l.7.2h1.6l.8.2h1l.8.2h1.6l.8.2h1l.7.2h1.5l.8.2h1l.7.2v1h-1l-.8-.2h-1.6l-.8-.2h-.8l-.8-.2h-1.7l-.8-.2h-.8l-1-.2h-1.6l-.8-.2h-.8l-1-.2h-1.4l-.8-.2H566l-.7-.2h-1.6l-1-.2H561l-1-.2h-1.6zm0-1v1zm-.2 0h.3v1h-.4v-1zM539 265v-1h2.9l.5.2h3l.5.2h2.3l.6.2h2.2l.6.2h2.3l.5.2h2.4l.5.2v1h-1.7l-.5-.2h-2.3l-.6-.2H550l-.7-.2H547l-.6-.2h-2.9l-.6-.2H540l-.6-.2h-.6zm-.4-1h.5v1h-.4v-1zm-.2 0h.2v1h-.2zm-9.2.5v-1h4l.3.2h3.2l.3.2h1.3v1h-1.6l-.3-.2H533l-.4-.2h-3.3zm-.3-1h.2v1h-.3zm-6Line truncated
<path fill="#0c4076" d="M482 269c5.8 0 10.4 3.2 10.4 7s-4.6 7-10.3 7-10-3.2-10-7 4.5-7 10-7z"/>
<path fill="#21231e" d="M493 276h-1v-.3l-.2-.3v-.5l-.2-.3v-.3l-.3-.3-.2-.4v-.3l-.3-.2-.2-.2-.2-.3-.3-.2-.3-.3-.3-.2-.3-.2-.2-.2-.4-.2-.4-.2-.3-.2-.4-.2h-.5l-.4-.3h-.4l-.5-.2h-.8l-.5-.2h-1.9v-1.2h1.7l.6.2h.5l.5.2h.5l.5.2h.4l.5.3.4.2.5.2h.5l.4.3.3.2.4.2.3.3.4.3.3.2.3.3.3.3.2.4.3.3.2.4.2.4.2.4v.3l.2.5v.4l.2.2v.8zm-11 7.4v-1h1.6l.5-.2h1.1l.5-.2h.5l.4-.3h.4l.5-.3h.4l.3-.3h.4l.4-.3.3-.2.4-.3.3-.2.3-.2.3-.3.2-.3.2-.2.3-.3v-.3l.3-.3h.2v-.4l.2-.3v-.7l.2-.3v-.3h1v.4l-.2.4v.4l-.2.4v.3l-.2.3-.2.3-.2.4-.2.3-.3.3-.2.3-.3.2-.3.3-.3.3-.4.3-.3.3-.4.2-.4.3-.5.2-.4.2-.4.2h-.4l-.5.3h-.4l-.5.3h-.5l-.5.2h-1.1l-.5.2zm-10.6-7.4h1v1l.2.3v.3l.2.2.2.3v.4l.3.3.2.3.3.2.2.3.3.3.3.2.3.2.2.3.3.2.4.2h.2l.4.3h.4l.4.3h.5l.3.3h.9l.5.2h1.5l.6.2h.5v1h-1.9l-.5-.2h-.5l-.5-.2-.5-.2h-.4l-.5-.3h-.4l-.4-.3-.4-.2-.4-.2-.4-.3-.4-.2-.3-.2-.4-.2-.4-.3-.3-.3-.3-.3-.2-.4-.3-.3-.2-.3-.2-.4v-.3l-.2-.4-.2-.4v-.8l-.2-.4v-.4zm10.7-7.4v1h-1.3l-.5.2h-.3l-.5.2h-.5l-.4.2h-.4l-.6.3h-.4l-.4.3-.4.2-.3.2-.5.2-.3.2-.3.2-.4.2-.3.3-.3.2-.2.3-.3.3-.2.3-.2.3v.3l-.2.2v.3l-.2.3v.7l-.2.3v.3h-1V275l.2-.5.2-.4v-.2l.3-.4.3-.3.2-.3.3-.3.2-.3.3-.2.3-.3.3-.2.3-.3.3-.3.4-.2.4-.2.4-.2h.4l.4-.3.5-.2.5-.2h.5l.5-.2h1l.5-.2h1.1l.6-.2h.5z"/>
<path fill="#edb92e" d="M482 211.7c4.4 0 8 3.4 8 7.7s-3.6 7.8-8 7.8-7.6-3.5-7.6-7.8 3.5-7.8 7.7-7.8z"/>
<path fill="#21231e" d="M490.4 219.4h-1v-1l-.2-.3v-.4l-.2-.3v-.4l-.2-.4v-.3l-.3-.3-.2-.3-.2-.3v-.3l-.3-.2-.2-.3-.2-.2-.3-.2-.3-.2-.2-.2-.3-.2-.3-.2-.4-.2h-.3l-.3-.3h-.4l-.3-.2h-.4l-.4-.2H482V211l.6.2h1.2l.4.2h.4l.4.2.3.2.4.2h.4l.4.3.3.3.4.2.4.2.3.3.3.3.2.3.3.2.2.3.3.3.2.3.2.5.2.3v.4l.3.4v.8l.2.4v.8l.2.4zm-8.3 8.3v-1h1.5l.3-.2h.3l.3-.2.4-.2h.3l.3-.2h.3l.2-.3.3-.2.2-.2.3-.2.3-.2.2-.3.2-.2.2-.2v-.3l.3-.3.2-.3.2-.4v-.3l.2-.4v-.7l.2-.4v-.8l.2-.4v-.4h1v1.2l-.2.4v.5l-.2.4v.3l-.3.4v.3l-.3.4-.2.3-.2.4-.3.4-.2.3-.3.3-.2.3-.3.3-.3.2-.3.3-.3.3-.3.2-.3.2-.3.2h-.4l-.3.2-.4.2h-.4l-.4.2H482zm-8-8.3h1v1.8l.2.3.2.3v.3l.2.3.2.3.2.2.2.3.2.3.2.3.2.3.2.3.3.2.2.3.3.3.3.2.4.2h.3l.3.3h.3l.4.3h.3l.3.2h.7l.4.2h.7v1h-1.6l-.4-.2h-.3l-.4-.3h-.4l-.4-.3-.4-.3-.3-.2-.5-.2-.3-.2-.3-.2-.4-.2-.3-.3-.3-.3-.2-.3-.3-.3-.2-.3-.2-.3v-.3l-.3-.4v-.3l-.3-.4v-.4l-.2-.5v-.4l-.2-.3zm8-8.3v1.2h-1.3l-.4.2h-.3l-.3.2h-.4l-.3.3h-.3l-.3.2-.3.2-.2.2-.3.2-.2.3-.3.3-.2.2-.2.3-.2.3-.2.4-.2.3-.2.3-.2.3v.3l-.2.3-.2.3v.7l-.2.3v1.1h-1v-1.6l.2-.4v-.4l.2-.4.2-.4v-.4l.3-.3v-.4l.3-.2.2-.3.3-.3.2-.3.3-.4.3-.3.3-.3.2-.2.3-.2.4-.3.2-.2h.4l.3-.2.3-.2h.4l.4-.2h.5l.4-.2h1.1z"/>
<path fill="#edb92e" d="M482 213.7c3.3 0 5.8 2.6 5.8 5.7 0 3.2-2.5 5.8-5.7 5.8-3 0-5.5-2.6-5.5-5.8 0-3 2.5-5.7 5.6-5.7z"/>
<path fill="#21231e" d="M488.3 219.4h-1V218h-.2v-.7l-.2-.2v-.2l-.2-.3-.2-.2v-.2l-.3-.2-.2-.2-.2-.2-.2-.2h-.2l-.2-.3h-.4l-.2-.3h-.2l-.3-.2h-.6l-.2-.2H482v-1h1.8l.3.2h.3l.2.2h.3l.3.3h.4l.2.3h.2l.3.3.3.2.2.2.2.2.2.3v.2l.3.3v.2l.3.3v.2l.2.3.2.3v.6l.2.2v1.3zm-6.2 6.3v-1h1.1l.2-.2h.3l.2-.2h.2l.2-.2h.4l.2-.2.2-.2h.2l.2-.3.2-.2h.2v-.2l.3-.2v-.2l.3-.3.2-.3v-.2l.2-.3v-.2l.2-.3v-1.3h1v2l-.2.3-.2.3-.2.4-.2.3v.2l-.3.2v.2l-.3.2-.2.3h-.2l-.2.3h-.2l-.2.3-.3.2h-.2l-.2.3-.3.2h-.2l-.3.2h-.3l-.3.2h-1.4zm-6-6.3h1v1.3l.2.3v.2l.2.3v.2l.2.2.2.4.2.2v.2h.3l.2.3.2.3v.2h.3l.2.3h.3l.2.2h.2v.2h.4l.2.2h.2l.3.2h.9v1h-1.5l-.3-.2h-.3l-.3-.2h-.2l-.3-.3-.3-.2-.3-.2-.3-.2h-.2l-.2-.3h-.2l-.2-.4-.2-.2-.2-.2-.2-.3-.2-.3v-.3l-.2-.3h-.2v-.4l-.2-.3v-.6l-.2-.3v-.9zm6-6.2v1H481l-.2.2h-.4l-.3.2-.3.3h-.5l-.2.3h-.2v.3l-.3.2h-.2l-.2.3v.3l-.2.2v.2l-.2.3v.2l-.2.2v.2l-.2.3v.4l-.2.2v.7h-1V218l.2-.4v-.3l.2-.3.2-.3v-.2l.2-.3.2-.2.2-.3.2-.2.2-.3.2-.2.2-.2.2-.2.2-.2h.3l.2-.3h.2l.3-.2h.2l.3-.2h.3l.3-.2h.5l.3-.2h.6z"/>
<path fill="#0c4076" d="M482 215.8c2 0 3.7 1.6 3.7 3.6S484 223 482 223c-1.8 0-3.4-1.6-3.4-3.6s1.6-3.6 3.5-3.6z"/>
<path fill="#21231e" d="M486.2 219.4h-1v-.8h-.2v-.3l-.2-.2v-.2l-.2-.2-.2-.2-.2-.3h-.2l-.3-.2h-.2l-.2-.2h-.2v-.2H482v-1h1.4v.2h.5v.2h.3v.2h.3v.3h.3v.2l.2.2.2.3.2.3v.2l.2.2.2.3v.4l.2.2v.6zm-4 4.2v-1h.6v-.2h.5l.3-.2h.2l.2-.2v-.2h.2v-.2h.2v-.2h.2v-.2l.2-.2v-.2l.2-.2v-.4h.2v-1h1v1l-.2.2v.2l-.2.2v.2l-.2.2-.2.3-.2.2-.2.2-.3.2-.3.3h-.3l-.3.2-.3.2h-1l-.3.2zm-4-4.2h1v1.3l.2.2v.2l.2.2.2.2.2.2.2.2.2.2h.2v.2h.4l.2.2h.8v1.2h-.7l-.2-.2h-.3v-.2h-.5l-.2-.2-.3-.3h-.2v-.2l-.2-.2h-.2v-.2l-.2-.3-.2-.3v-.2l-.2-.2-.2-.3v-1.4zm4-4v1h-1l-.2.2h-.2l-.2.2h-.2v.2h-.2l-.2.3-.2.2-.2.2-.2.3v.4h-.2v1h-1V218l.2-.2.2-.3v-.2l.2-.2.2-.2.3-.3.2-.2.2-.2h.2l.2-.2h.2l.2-.2h.3l.3-.2h.9z"/>
</g>
<path fill="#c6363c" d="M135.8 192.6v144.7c0 26 10 49.4 26.2 66.5a87 87 0 0 0 63 27.6c24.8 0 47-10.6 63.3-27.6a96 96 0 0 0 26.2-66.5V192.6z"/>
<path fill="#fff" d="M135 192v145.3l.2 2.5v2.4l.2 2.4.2 2.4.3 2.4.2 2.3.3 2.3.5 2.4.5 2.3.5 2.2.6 2.2.6 2.2.7 2.2.6 2.2.8 2.2.8 2 1 2.2.8 2 1 2.2 1 2 1 2 1.2 2 1 2 1.3 1.8 1.3 2 1.2 1.7 1.4 1.7 1.3 1.8 1.4 1.7 1.6 1.7 1.4 1.6 1.5 1.6 1-1-1.5-1.5-1.5-1.6-1.4-1.6-1.3-1.7-1.3-1.8-1.3-1.8-1.2-2-1.2-1.7-1.2-2-1-1.8-1.2-2-1-2-1-2-1-2-1-2-.8-2-.8-2.2-.8-2-.7-2.3-.6-2-.6-2.4-.6-2.2-.5-2.2-.5-2.3-.4-2.2-.4-2.3-.3-2.3v-2l-.3-2.5-.2-2.4V193.4h177.4v144l-.2 2.4v2.4l-.2 2.5-.2 2.3-.2 2.4-.3 2.3-.5 2.3-.4 2.3-.4 2.4-.5 2.2-.5 2.2-.6 2.3-.8 2.2-.7 2.2-.8 2-.8 2.2-1 2-1 2.2-.8 2-1 2-1 2-1.2 2-1 1.8-1.3 2-1.2 1.7-1.3 2-1.3 1.6-1.4 1.7-1.4 1.7-1.4 1.7-1.5 1.7-1.5 1.6-1.5 1.6-1.6 1.4-1.6 1.5-1.5 1.4-1.6 1.4-1.8 1.3-1.8 1.5-1.7 1.3-1.8 1.2-2 1.2-1.8 1-1.8 1.2-2 1-1.8 1-2 1-2 1-2 .8-2 1-2 .6-2 .7-2.2.7-2 .6-2.3.5-2 .5-2.2.5-2.2.4-2.2.3-2.2.3-2.2.2h-2.3l-2.3.2H225v1.3h4.8l2.3-.3 2.3-.2 2.3-.3 2.2-.3 2.2-.5 2.2-.4 2.2-.4 2.2-.6 2.2-.6 2-.7 2.2-.7 2-.8 2-.8 2-1 2-.8 2-1 2-1 2-1 2-1.2 1.8-1 1.8-1.4 1.8-1.2 1.8-1.3 1.7-1.4 1.7-1.2 1.7-1.5 1.6-1.4 1.6-1.7 1.6-1.5 1.5-1.6 1.5-1.6 1.5-1.7 1.5-1.8 1.4-1.7 1.3-1.8 1.2-1.8 1.3-2 1.2-1.8 1.2-2 1-2 1.2-1.8 1-2 1-2 1-2 1-2.2 1-2 .7-2.2.7-2.2.7-2.2.7-2.2.7-2.2.6-2.3.5-2.3.5-2.4.4-2.3.4-2.3.4-2.3.3-2.4.2-2.4V192z"/>
<g fill="#fff" stroke="#21231e" stroke-width=".5">
<path d="M226 424c.7-.2 2 0 3-1 1.4-1 .8-5 .7-7.7q-.7-20.3-1.8-68.3h-5.6q-1 48-1.8 68.3c0 2.6-.7 6.8.7 7.8 1 1 2.3.8 3 1h1.7z"/>
<path d="M234.4 423.5c-.8 0-2 .2-3-.5-1.5-1-1.6-5.2-1.7-7.8q-1-20.3-4-68 1.5-.4 2.6-.3l.4-.2c5 31.6 7 54 10.4 67.5.6 1.8 1.6 6.5 0 8-1 1-2.2 1-3 1l-1.6.2z"/>
<path d="M244.4 422c-.8 0-2 .5-3.2 0-1.5-1-1.4-5.2-2-7.7-3.5-13.5-5.5-36-10.6-67.5q1.6-.4 2.7-.4c8.2 30.6 10.6 52.2 17 65.6.5 2 2 6.8.6 8.5-1 1-2.3 1-3 1.3l-1.6.3z"/>
<path d="M254.4 419.2c-.8 0-2 1-3.3.4-1.4-.6-1.7-5.2-2.8-7.6-6.3-13.4-8.7-35.2-17-66q1.7-.8 2.7-.8c.7-.3.5-.5 1.6-.7 9.5 30.6 12.6 51.8 21.6 65 1.4 2 2.5 6.4 1.5 7.7-.7 1-2 1.3-2.8 1.6l-1.6.4zm-38.5 4.3c.7 0 2 .2 3-.5 1.4-1 1.5-5.2 1.6-7.8q1-20.3 4-68-1.5-.4-2.6-.3l-.4-.2c-5 31.6-7 54-10.4 67.5-.5 1.8-1.6 6.5 0 8 1 1 2.3 1 3 1l1.7.2z"/>
<path d="M206 422c.7 0 2 .5 3 0 1.6-1 1.5-5.2 2.2-7.7 3.4-13.5 5.4-36 10.4-67.5q-1.6-.4-2.6-.4h-.2c-8 30.6-10.5 52.2-16.7 65.6-.5 2-2 6.8-.6 8.5 1 1 2.2 1 3 1.3l1.5.3z"/>
<path d="M196 419.2c.7 0 2 1 3.2.4 1.5-.6 1.8-5.2 3-7.6 6.2-13.4 8.6-35.2 16.8-66q-1.6-.8-2.7-.8c-.7-.3-.5-.5-1.7-.7-9.5 30.6-12.5 51.8-21.5 65-1.3 2-2.4 6.4-1.4 7.7.7 1 2 1.3 2.7 1.6zm53-23c-.6 0-1.7.5-2.8 0-1.5-.8-2.5-5-3.3-7.5-6.4-12.5-12.2-34.8-21.8-65.8q1.4-.7 2.4-.7.9-.4 2.3-.6c10.2 30.7 14.8 53 24.8 65 1.7 2 3 6.5 2 7.8-.5 1-1.7 1-2.3 1.3l-1.4.4z"/>
<path d="M241 397.8c-.7 0-2 .3-3-.3-1.3-.8-1.8-5-2.3-7.6q-4-20.3-14-67.4l2.4-.4q1.1-.4 2.5-.4c8 31.3 9.8 54.7 17.3 66.7 1.3 2.2 2 6.7 1.2 8-.7.8-2 .8-2.6 1z"/>
<path d="M232.7 398.7c-.7 0-1.8.2-2.8-.5-1.4-1-1.4-5-1.6-7.8q-1.6-20.3-6.2-68 1.4-.4 2.4-.2 1-.3 2.5-.3c4.4 31.7 7 54.7 9.6 67.8.5 2.5 1.3 6.7.3 7.8s-2 .8-2.8 1h-1.5z"/>
<path d="M201.2 396.2c.7 0 1.8.5 3 0 1.4-.8 2.4-5 3.2-7.5 6.3-12.5 12-34.8 21.6-65.8q-1.4-.7-2.3-.7-.8-.4-2.4-.6c-10.2 30.7-14.8 53-24.8 65-1.7 2-3 6.5-2 7.8.5 1 1.7 1 2.3 1.3l1.4.4z"/>
<path d="M209.3 397.8c.7 0 1.8.3 3-.3 1.3-.8 1.8-5 2.3-7.6q4-20.3 14-67.4l-2.4-.4q-1-.4-2.4-.4c-8 31.3-9.8 54.7-17.3 66.7-1.4 2.2-2 6.7-1.2 8 .7.8 2 .8 2.6 1z"/>
<path d="M217.6 398.7c.7 0 1.8.2 2.8-.5 1.3-1 1.3-5 1.5-7.8q1.5-20.3 6-68-1.4-.4-2.3-.2-1-.3-2.5-.3c-4.3 31.7-6.8 54.7-9.5 67.8-.5 2.5-1.3 6.7-.3 7.8.8 1 2 .8 2.7 1h1.6z"/>
<path d="M226 399c.6 0 1.8 0 2.7-.8 1-1 .7-5.2.6-7.8q-.8-20.4-1.7-68.3-1.5 0-2.5.2-.8-.3-2.3 0-.8 47.9-1.7 68.2c0 2.6-.5 6.8.6 7.8 1 .8 2 .7 2.8.8z"/>
<path d="M243.5 377.6c-.6 0-1.4.5-2.2 0-1.2-.8-2-5-2.5-7.5-5-12.4-9.4-34.7-16.6-65.7q1-.5 1.8-.6.6-.4 1.8-.6c7.8 30.8 11.3 53 19 65.2 1.3 2 2.2 6.4 1.6 7.7-.4.8-1.4 1-1.8 1.2l-1 .4z"/>
<path d="M237.3 379.2c-.6 0-1.4.3-2.2-.3-1-1-1.4-5-1.8-7.7q-3-20-10.7-67.3 1-.4 2-.3.6-.5 1.7-.5c6 31.3 7.5 54.7 13.2 66.8 1 2 1.6 6.6 1 7.8-.6 1-1.5 1-2 1l-1 .4z"/>
<path d="M231 380c-.6 0-1.5.3-2.2-.4-1-1-1-5-1.2-7.8q-1.2-20.3-4.7-68 1-.4 1.7-.2a4 4 0 0 1 2-.2c3.2 31.7 5 54.7 7.2 67.8.3 2.6 1 6.7 0 7.8-.5 1-1.4.8-2 1h-1z"/>
<path d="M206.8 377.6c.5 0 1.4.5 2.2 0 1.2-.8 2-5 2.5-7.5 5-12.4 9.3-34.7 16.6-65.7q-.8-.5-1.7-.6-.7-.4-1.8-.6c-7.8 30.8-11.3 53-19 65.2-1.3 2-2.2 6.4-1.6 7.7.3.8 1.2 1 1.7 1.2l1 .4z"/>
<path d="M213 379.2c.6 0 1.4.3 2.2-.3 1-1 1.5-5 2-7.7a2735 2735 0 0 1 10.6-67.3q-1-.4-2-.3-.6-.5-1.7-.5c-6 31.3-7.4 54.7-13 66.8-1.2 2-1.8 6.6-1 7.8.5 1 1.4 1 2 1l1 .4z"/>
<path d="M219.3 380c.6 0 1.5.3 2.2-.4 1-1 1-5 1.2-7.8q1.1-20.3 4.7-68-1-.4-2-.2a3 3 0 0 0-1.7-.2c-3.3 31.7-5.2 54.7-7.3 67.8-.4 2.6-1 6.7-.2 7.8.6 1 1.5.8 2 1h1z"/>
<path d="M225.7 380.4c.5 0 1.4 0 2-.8 1-1 .7-5.2.6-7.8q-.6-20.3-1.3-68.3h-3.7q-.8 48-1.3 68.3c0 2.6-.4 6.8.5 7.8.6.8 1.6.7 2 .8z"/>
<path d="M221.3 330.2v7.4l-5.8 1.2c0 2.6 6.4 29.6 9.6 29.6 3.4 0 9.8-27 9.8-29.6l-5.7-1.2v-7.4c-1.2 1-2.5 2.7-4 4.3a27 27 0 0 0-3.7-4.3z"/>
</g>
<g transform="translate(-32 32)scale(.53333)">
<g id="rs-d">
<path fill="#edb92e" stroke="#21231e" d="M412 584.5c-3 .2-7 2-18.5 12-5 10.2-10 20.5-17 29.4q-3.4 2.1-6 3.2a84 84 0 0 1-17-.5c-4.4-4-11.3-1.2-9 3.2-1.8 1.6 2.2 7.8 5.3 5.2 3-2.4 13-.2 16.4-1.4-1.3 3-10.4 5-16.8 5.5-5.8.2-5.4 6-3 10.5 2.7 1.8.5-.4 1.4.8 2.6 4 8.2 3.4 8.4-.4.2-4 13.8-9 15.8-12-2.5 6-8.2 11.5-11 17.3-3 3-5 3.7-1 10 4.4-.6 4.6-1.7 7.3.8 6-.6 7-2.4 6-7.2-1-5 3.2-14 4.6-16.6 1.2-2.4 1.5-4.8 2.8-6.3 2.2-2.5 12.6-7.7 15.2-6.3 5 2.7 8.7 1 9.3-3.7-1.6-1.2-.4-8-3.8-8.2-2.8-.3-4.4.6-7 2.7-4 3.2-6 5-7.4 4.6-3-.7 5.8-5 13.8-15.6 11-14.5 11.8-22 11.3-27z"/>
<use xlink:href="#rs-c" width="1350" height="900" transform="matrix(-1 0 0 1 801.6 0)"/>
<path fill="#edb92e" stroke="#21231e" d="M345.2 634.5c-4-2.3-6.3-2.2-8-.5-.7 1-1.8.5-1.2-1 2.7-6.3 7-7 10.7-4.2l2.8 2.7c-.6 1-3.8 2.3-4.3 3zm57.4-5.6c4.3-3 8.3-3.6 10.5-2 1.3 1 2.5.3 1.4-1.2-4.4-6.2-9.6-6.5-13.5-3q-1.7 1.5-2.8 3c1.3 1.6 4.3 3.2 4.4 3zM369 664.4c.2-.2-1-5.4-2.6-7q-2.2 1.4-4.3 3.5c-4.2 4.5-4 11 2.5 16.7 1.6 1.5 2.4 0 1.7-1.7-1-2.7.3-6.3 3-11.5zM352.6 651c-4 1.6-5.4 3.7-5.2 6.4 0 1.5-1 2-1.5.3-4.8-11.2.2-13.3 7.5-13 .4 2-.7 6.2-.8 6.2z"/>
<path fill="#21231e" d="m384 621.3 1 .6h-.2v1.8h.2v.4h.2v.2h.2l.2.3.3.2v.2h.4l.2.3h.2l-.6 1h-.2l-.3-.2h-.2l-.2-.2-.2-.2-.3-.3-.3-.3v-.2h-.2v-.3l-.2-.2v-.2h-.2v-.2l-.2-.2V622l.2-.3v-.2zm6.5.8-.8 1-.2-.2-.3-.2-.2-.2-.2-.2h-.3l-.2-.3-.2-.3-.3-.2-.2-.2-.3-.2h-.7l-.2-.2h-.7v.2h-.2l-.2.2v.2h-.2v.3l-.2.2-1-.7v-.3l.2-.2.2-.2.2-.2.3-.3h.3l.2-.2h.4v-.2h.8l.2.2h.4l.2.2h.2l.2.2h.2l.2.3h.2l.2.3h.2l.3.3.2.3.2.2.3.2.2.2h.3z"/>
<path fill="#21231e" d="m387.3 617.6 1 .6v.4h-.2v.8l.2.2v.2l.2.2v.2l.2.2.2.3.3.2h.2l.2.2h.2l.2.2.2.2h.2l-.6 1h-.2l-.3-.2-.3-.3h-.2l-.2-.2-.2-.2-.2-.3v-.2h-.2l-.2-.2v-.2h-.2v-.5h-.2V618h.2v-.3zm6.5.8-.7 1-.2-.3h-.2l-.2-.3-.3-.2-.3-.3h-.2l-.2-.3-.2-.2-.3-.2-.3-.2h-.3v-.2h-.8l-.2.2-.2.2-.2.2v.2l-.3.2-1-.6.2-.3v-.2h.3v-.3h.3l.3-.3h.2l.2-.2h.2v-.2h1.4l.2.2h.2v.2h.3l.3.3h.2l.2.2h.2l.2.3h.2l.3.3v.2l.3.2.3.2z"/>
<path fill="#21231e" d="m391 612.8 1 .6-.2.2v.6h-.2v1l.2.3v.3h.2v.4h.2l.2.3v.2h.2l.2.2.2.2.3.3.3.2h.2l.2.2-.6 1-.3-.2-.2-.2-.2-.2-.3-.2-.2-.2v-.2l-.3-.2v-.2l-.3-.2v-.2l-.3-.2v-.4l-.2-.3v-.2h-.2v-.7h-.2v-1l.2-.3v-.4l.2-.3zm7 1-.8 1-.3-.3-.3-.2-.3-.3-.3-.2v-.2l-.3-.2-.3-.2-.2-.2-.2-.2-.2-.2h-.2l-.2-.2-.3-.2h-.2l-.2-.2h-.7l-.2.2-.2.2-.3.3v.2h-.2v.4l-1-.6v-.3l.2-.2.2-.3v-.2l.3-.2.2-.2v-.2h.3l.2-.2h.3l.2-.2h1.2l.2.2h.2l.2.2.3.2h.3l.2.3.2.2h.3l.2.3.3.2.2.2.3.2.2.2.3.2.2.3.3.2z"/>
<path fill="#21231e" d="m394.8 607.7 1 .5v.5l-.2.3v1.7l.2.2v.3l.2.2v.2l.2.2.3.3v.2l.3.2.2.2h.2l.2.3.2.2.3.2v.2l-.6.8-.3-.2v-.2l-.4-.2-.2-.3-.3-.3v-.2l-.3-.3-.2-.2v-.2l-.3-.3v-.2l-.3-.2-.2-.2v-.2l-.2-.2v-.3l-.2-.3v-2.1l.2-.2v-.2l.2-.3zm7.6 1.3-1 .8-.2-.3-.3-.3-.3-.2-.3-.3-.3-.3v-.2l-.4-.2-.2-.2-.2-.2-.2-.2-.2-.2h-.2l-.2-.2h-.2l-.2-.2h-.3v-.2h-.7v.2l-.3.2-.2.3-.2.2v.2l-.3.2v.2l-1.2-.5.2-.3.2-.3v-.2l.3-.3.2-.2.2-.2.3-.2.3-.2h.5l.3-.2h.8l.3.2h.2l.3.2h.2l.2.3.3.3.2.2.3.2.2.2h.3l.2.3.3.3.2.2.3.3.3.4.3.3.4.3z"/>
<path fill="#21231e" d="m399 602.6 1.2.6v.2l-.2.2-.2.3v2.1l.2.2v.2l.2.2.2.2v.2l.2.2.2.2.2.2v.2l.3.2.2.2.2.2.3.2.2.2.3.2-.8 1-.3-.3-.2-.3-.3-.2-.3-.3-.2-.2-.3-.2-.2-.3v-.2l-.3-.2-.2-.2v-.2l-.3-.2v-.3h-.2v-.4l-.2-.2v-.2l-.2-.3v-2.6l.2-.2v-.2l.2-.2v-.2zm7.7 1.4-1 .8-.2-.3-.3-.3-.2-.3-.3-.3-.3-.3-.2-.2-.2-.3-.3-.3-.2-.2h-.2l-.2-.3-.2-.2h-.2v-.2h-1.3l-.3.2v.2h-.2v.3l-.3.2-.2.3v.2l-1.2-.6.3-.3.2-.3.2-.2.2-.3v-.2l.4-.2h.2l.2-.2h.2l.2-.2h1.7l.2.2.2.2h.2l.2.3h.3l.3.3.2.3h.3l.2.3.3.3.2.2.3.3.3.4.4.3.3.3z"/>
<path fill="#fff" stroke="#21231e" d="m462.6 580.6-9.5-5.4c-4 3-6.8 13.5 0 22.2 8.5 11 12 18.7 14 27.5 6.2-8 8.3-16.3 4.4-24.5-5.3-11-8.7-17-8.8-20z"/>
<path fill="#fff" stroke="#21231e" d="m470.4 573-9.5-5.4c-4 3-12.5 13.2-5.6 22 8.5 10.8 17.3 19 19.4 27.7 6.2-8 8.8-16.2 5-24.4-5.4-11-9.4-17.2-9.4-20z"/>
<path fill="#fff" stroke="#21231e" d="m449.4 569.2-9.5-5.4c-4 3-7 13.5-.2 22.2a65 65 0 0 1 14 27.5c6.2-8 8.4-16.3 4.4-24.4-5.3-11-8.7-17-8.8-19.8z"/>
<path fill="#fff" d="M405.5 469c.2 8.7-1.4 66.5-1.8 74.7s-4 13.7-8 17q-5.3-7.5-6-19.3c-.4-4 .4-58.7.7-70q9.4-25.5 15-2.4z"/>
<path fill="#21231e" d="M404 543.8h-1l.2-1v-2.6l.2-1.7v-4l.2-2.3v-5l.2-2.7v-2.8l.2-3v-3l.2-3v-6.2l.2-3v-6.2l.2-3v-5.8l.2-2.7v-7.4l.2-2V469h1v11.7l-.2 2.5v8.3l-.2 2.8v6l-.2 3.2v3l-.2 3.2v6l-.2 3v3l-.2 2.8v5.3l-.2 2.5v2.3l-.2 2v3.6l-.2 1.5v2zm-8.7 17 .8-.5h-.6l.3-.4.4-.4.4-.3.4-.3.3-.4.5-.4.3-.3.3-.5.4-.4.4-.4.3-.4.4-.5.3-.4.2-.5.2-.5.3-.5.3-.5.2-.6.2-.5.3-.6.2-.5.2-.5v-.7l.3-.6v-.6l.3-.7v-.7l.2-.7v-.7l.2-.8v-1.5h1v2.3l-.2.7v.8l-.3.6v.8l-.3.7-.2.6-.2.8-.2.6-.2.6-.2.6-.3.6-.4.5-.2.6-.3.5-.2.5-.3.5-.3.5-.3.5-.4.4-.4.5-.3.4-.5.5-.3.4-.4.3-.3.4-.4.3-.2.4-.4.3-.4.3h-.7zm.7.2-.4.3-.3-.4h.7zm-7-19.5h1v.6l.2.8v1.4l.2.7v.6l.2.7v.6l.3.6v1.5l.3.5v.7l.3.6.2.6.2.6.2.6.2.5.2.7.2.6.2.5.3.6.2.5.3.4.2.6.3.5.3.5.3.5.2.4.3.4.3.5.3.3-.7.6-.3-.6-.4-.4-.3-.5-.3-.5-.3-.5-.3-.6-.2-.6-.3-.5-.4-.7-.2-.5-.3-.6v-.6l-.3-.5-.3-.5-.2-.6-.2-.7-.2-.6v-.7l-.3-.6-.2-.6v-.7l-.3-.5v-.7l-.2-.7-.2-.6v-.6l-.2-.7v-1l-.2-.8v-1.5zm1-70.2.8.3v8l-.2 2.3V492l-.2 2.7v11.6l-.2 3v19l-.2 2.2v11h-1v-20.9l.2-2.7v-14.6l.2-2.8V489l.2-2.6v-8.9l.2-2v-4.2zm16-2.3h-1l-.4-1.3-.3-1.3-.4-1-.5-1.2-.4-1-.2-1-.4-.7-.4-.8-.4-.6-.4-.4-.4-.4-.4-.3-.3-.3h-.3l-.4-.2h-.7l-.4.3-.4.3-.5.5-.5.4-.5.5-.5.7-.5.7-.5.8-.5 1-.6 1-.5 1.2-.6 1.3-.6 1.3-.6 1.5-.6 1.6-1-.3.7-1.6.6-1.5.7-1.3.6-1.4.5-1.2.6-1 .5-1 .5-1 .5-.8.6-.7.5-.7.6-.6.6-.4.5-.4.6-.3.5-.2h1.1l.5.3.5.3.5.5.5.5.4.6.4.6.5.8.4.8.4 1 .5 1 .3 1 .4 1.4.4 1.3.4 1.4zm0 0"/>
<path fill="#fff" d="m368 454.8-2.6 79.6c-.8 7 8.4 49 13.5 57.4 12.3-5.3 15-33.8 12.6-61.6s.4-51.8 2.3-56.8c0-6.3-1-12.8-1-19.3-8 .5-17.2.4-25 .8z"/>
<path fill="#21231e" d="m365 534.4 2.4-79.6h1l-2.5 79.6h-1zm13.7 57 .3.8-.6-.2-.5-1-.6-1-.5-1.2-.7-1.4-.5-1.6-.6-1.6-.6-1.8-.6-2-.5-2-.6-2-.7-2.2-.6-2.2-.6-2.3-.4-2.3-.6-2.3-.5-2.3-.6-2.3-.6-2.3-.4-2.2-.5-2.2-.4-2.2-.3-2-.4-2.2-.3-2-.3-1.8-.3-1.7-.2-1.6v-1.4l-.3-1.3v-2.8h1v4.1l.2 1.5.2 1.6.3 1.7.3 1.8.3 2 .4 2 .4 2.2.5 2.2.4 2.2.4 2.3.5 2.2.4 2.3.6 2.3.5 2.4.6 2.3.7 2.2.5 2.2.6 2 .6 2.2.6 2 .6 2 .5 1.7.7 1.5.6 1.5.5 1.4.5 1.2.5 1 .5 1-.6-.3zm.3.8-.4.2-.2-.4zm12-62h1l.3 2.5v2.7l.3 2.6v2.6l.2 2.6v12.5l-.3 2.4-.2 2.5-.2 2.3v2.3l-.4 2.3-.4 2.2-.3 2-.6 2-.4 2-.6 2-.5 1.7-.8 1.7-.6 1.5-.7 1.5-1 1.5-.7 1.3-1 1.2-1 1-1 1-1 1-1 .6-1.3.6-.3-1 1-.4 1-.7 1-.7 1-1 1-1 .7-1 .8-1.3.8-1.4.7-1.5.6-1.5.6-1.6.5-2 .5-1.7.5-2 .4-2 .3-2 .3-2 .3-2.3v-2.3l.4-2.3V558l.3-2.3V538l-.2-2.6-.2-2.6-.2-2.6zm2.4-56.8h1v.2l-.2.5-.2.7-.2.7-.2 1-.2.8-.2 1-.2 1.2v1.2l-.3 1.3-.2 1.3-.2 1.4v1.6l-.3 1.6v1.7l-.3 1.7v2l-.2 1.8v2l-.2 2V520l.2 2.5.2 2.5.2 2.6v2.5l-1 .2v-2.6l-.3-2.5-.2-2.5V520l-.2-2.5v-20.1l.2-2v-2l.3-2v-1.7l.2-1.7.2-1.8.2-1.6v-1.4l.3-1.5.2-1.3v-1.2l.3-1V477l.3-1 .2-.8.2-.7.2-.7.2-.5zm1 0v.2zm-1.5-18.8v-1l.4.4v3.7l.2.6v2.5l.2.6v1.8l.2.6v2.4l.2.6v3.6l.2.6v2.4h-1V468l-.2-.5V465l-.2-.5v-1.9l-.2-.6v-1.7l-.2-.6v-3l-.2-.6V454l.5.6zm0-1h.4v.4l-.5-.4zm-24.6 1.2h-1l.4-.5h3.9l.8-.2h12.8l.8-.2h4.7l.8-.2h1.7v1h-4.1l-.7.2h-8l-.8.2h-7.1l-.8.2h-3.9l.4-.4zm-1 0v-.4h.4zm.5 0h.4-.5zm-.6 0v-.4h.4z"/>
<path fill="#fff" d="m353 468 1.8 79.5c-.4 7 11 48.5 16.4 56.5 12.6-9.8 10-49.8 8.2-62-4-24-3.2-52-2-56.5 0-6.3-.2-13.8-.6-20.4q-12 1.6-23.7 2.8z"/>
<path fill="#21231e" d="m354.3 547.5-1.7-79.6 1-.2 1.7 79.6h-1zm16.6 56 .5 1-.7-.2-.5-1-.6-1-.6-1.2-.5-1.2-.7-1.6-.6-1.6-.7-1.8-.7-1.8-.7-2-.5-2-.7-2.2-.7-2.2-.6-2.2-.7-2.3-.7-2.2-.7-2.3-.6-2.3-.6-2.3-.5-2.3-.6-2.2-.6-2.2-.5-2-.6-2-.4-2-.4-2-.4-1.6-.3-1.6-.3-1.3-.2-1.3v-1.2l-.2-1v-.8h1v1.8l.2 1 .2 1.3.2 1.5.2 1.5.3 1.7.4 2 .4 1.8.4 2 .5 2 .6 2.2.4 2.2.6 2.3.7 2.3.6 2.3.7 2.2.6 2.3.7 2.3.7 2.3.7 2.2.7 2 .7 2.2.8 2 .7 1.8.6 1.7.8 1.7.6 1.4.6 1.3.6 1.2.5 1 .6.7h-.7zm.5 1-.4.2-.2-.4h.7zM379 542l1-.2v1.2l.2 1.4.2 1.5.2 1.8.2 1.7v2l.3 2 .2 2v2l.2 2.3v12l-.2 2.4v2.3l-.3 2.4-.4 2.4-.3 2.4-.3 2.2-.4 2.2-.5 2.2-.4 2-.6 2-.7 2-.8 1.6-.8 1.7-1 1.5-1 1.3-1 1.4-1.2 1-.6-.8 1-1 1-1 1-1.4.8-1.4.8-1.6.8-1.7.6-1.8.6-2 .5-2 .6-2 .4-2.2.4-2.3.3-2.3.2-2.4v-2.3l.3-2.4V569l.2-2.2V560l-.2-2.3v-2.2l-.2-2v-2l-.2-2-.2-1.6-.2-1.8-.2-1.5v-1.3l-.3-1.2zm-2-56.7h1v.6l-.2.7-.2.7v1l-.2.8v2.4l-.2 1.3v2.8l-.2 1.6v15.2l.2 2v2.3l.3 2v2.4l.3 2.3v2.2l.3 2.2.4 2.3.2 2.4.3 2.2.2 2.3.3 2.2.4 2.3-1 .2-.5-2.3-.3-2.4-.3-2.3-.4-2.3-.2-2.4-.2-2.3-.2-2.3-.2-2.3-.2-2.2v-2.3l-.3-2.2V512l-.2-2v-16l.2-1.4v-1.3l.2-1.2v-2l.3-1v-.8l.2-.6v-.7.2zm-.2-20v-1l.5.6v3.4l.2.7v3.8l.2.6v6l.2.6v5.3h-1V480l-.2-.7v-5.7l-.2-.6v-4.5l-.2-.7v-2.4l.4.4zm0-1h.4v.6l-.5-.4zm-23.7 4v-1l.8-.2h.8l.7-.2h2.2l.7-.2h.8l.7-.2h.8l.7-.2h1.4l.7-.2h.8l.7-.2h.6l.8-.2h1.7l.6-.2h.7l.8-.2h.8l.7-.2h1.5l.8-.2h.7l.7-.2h.8l.7-.2v1h-.6l-.6.2h-.8l-.7.2h-1.6l-.7.2h-.8l-.8.2h-.8l-.7.2h-1.5l-.7.2h-.8l-.7.2h-.7l-.8.2H362l-.7.2h-.7l-.8.2h-.7l-.6.2H357l-1 .2h-.6l-.7.2h-.8zm.2-1v1l-.6-.6.5-.6zm-.6.4v-.6h.5l-.4.5z"/>
<path fill="#fff" d="m342.2 486.7 21-.5c-2 8.6-.5 35.6 3.2 56.2 3.3 19.3 8 69.3-12 81.3-12.5-26.4-3-52-9.2-75-5-24.3-6-44.6-3-62"/>
<path fill="#21231e" d="m363 486.7-20.8.5v-1l21-.5.4.6zm0-1h.7v.6zm3.8 56.6-1 .2-.3-2-.3-2-.3-2-.4-2-.3-2-.2-2-.2-2.2-.2-2-.2-2.2-.2-2-.2-2-.2-2-.2-2.2v-2l-.3-2v-2l-.2-2V499l-.2-1.7v-4.5l.2-1.4v-1.2l.2-1.2v-1l.3-1v-1l1 .3v.8l-.2 1v1l-.2 1.3v5.4l-.2 1.6v4.9l.2 1.8v4l.2 1.8v2l.3 2v2l.3 2 .2 2v2l.3 2.2.3 2 .2 2.2.3 2 .3 2 .3 2 .3 2.2.2 2 .3 2 .3 2zM354 624l.8-.6-.7-.2 2-1.2 1.5-1.4 1.5-1.6 1.4-1.8 1.3-2 1-2 1-2.3 1-2.6 1-2.5.6-2.8.6-2.7.4-2.8.4-3 .4-3 .3-3 .2-3v-3l.2-3v-6.2l-.2-3-.2-3v-3l-.4-3-.2-2.7-.3-2.7-.2-2.5-.4-2.5-.2-2.4-.3-2.2-.3-2-.3-2h.8l.4 1.8.3 2 .3 2.3.3 2.3.4 2.5.3 2.7.3 2.7.2 2.8.2 3 .2 2.8.2 3v15.5l-.3 3-.3 3.2-.4 3-.4 2.8-.5 3-.8 2.7-.7 2.7-.8 2.6-1 2.4-1 2.4-1.2 2.2-1.3 2-1.4 2-1.6 1.5-1.7 1.5-1.8 1.3zm.7 0-.5.4-.3-.5h.7zm-10-75.2 1-.2.5 2.2.4 2.2.4 2.2.3 2.2.3 2.2.2 2.3v2l.2 2.4v25.4l.2 2.4v2.4l.3 2.4.3 2.4.3 2.4.5 2.4.4 2.4.5 2.4.7 2.5.7 2.4.8 2.5 1 2.5 1 2.4-.8.5-1.2-2.6-1-2.5-.8-2.6-.8-2.5-.7-2.5-.5-2.5-.5-2.4-.4-2.5-.2-2.3-.3-2.5-.2-2.4V594l-.2-2.4V564l-.2-2.3-.2-2.3-.2-2.2-.4-2.2-.3-2-.5-2.3-.5-2v-.2zm-2.5-62.6v1l.5-.4-.3 1.6-.2 1.7-.2 1.7-.2 1.7-.2 1.7v1.8l-.3 1.8v3.5l-.2 2v7.3l.2 2v1.8l.2 2v2l.2 2 .2 2 .2 2 .2 2 .3 2 .2 2 .3 2.3.3 2 .3 2.2.4 2.2.4 2.2.4 2 .4 2.4.4 2.2-1 .2-.4-2.2-.4-2.3-.4-2.2-.4-2-.3-2.3-.4-2.2-.3-2-.3-2.2-.2-2-.3-2.2-.2-2-.2-2-.2-2v-2l-.2-2v-2l-.2-1.8v-13l.2-1.8v-1.8l.2-1.7.2-1.7.2-1.7.2-1.7.2-1.7.3-1.7.5-.4zm-.5.4v-.4h.5zm.5 0v-.4zm-.5 0v-.4h.5z"/>
<path fill="#fff" d="M422 454.4c0 8.7-3.2 66.5-4 74.6s-4.5 13.6-8.4 16.6q-5.1-7.5-5.5-19.3c0-4 2.3-58.7 3-70 7-17 11.8-17.4 15-2z"/>
<path fill="#21231e" d="M418.5 529h-1v-1l.2-1v-1.5l.2-1.7v-2l.2-2v-2.3l.3-2.4v-2.5l.3-2.7.2-2.8v-3l.3-3 .2-3 .2-3v-3l.3-3.2.2-3 .2-3.2v-3l.3-3V474l.3-3v-2.5l.2-2.4V464l.2-2v-2l.2-1.8v-3.7h1v5.6l-.2 2v2l-.2 2.3v2.6l-.3 2.6-.2 2.7v2.8l-.3 3-.2 3v3l-.3 3-.2 3v3.2l-.3 3-.2 3.2-.2 3v3l-.2 2.7-.2 2.6v2.6l-.3 2.4v2.3l-.3 2v2l-.2 1.5v1.5l-.2 1.2v1zm-9.3 17 .8-.6-.7-.2.4-.2.3-.3.4-.4.3-.3.4-.3.4-.4.4-.3.3-.4.4-.4.4-.4.3-.5.4-.4.3-.6.3-.4.3-.5.3-.5.3-.5v-.5l.4-.6.2-.5.3-.7v-.6l.3-.6.2-.5.2-.7.2-.6V532l.3-.8v-.8l.2-.7v-.7h1v1.6l-.2.7-.2.7v.7l-.2.7-.2.7-.2.8-.2.6-.2.6-.2.6-.3.6-.2.6-.3.6-.3.5-.2.5-.3.5-.3.5-.5.5-.3.5-.3.4-.4.4-.4.4-.3.4-.5.4-.4.4-.2.4-.4.3-.4.4-.3.4-.4.3-.4.3h-.8zm.7 0-.5.4-.3-.5h.7zm-6.4-19.7h1v2.8l.2.8v.7l.2.7v1.2l.3.6v.8l.2.6.2.7v.7l.3.6v.6l.3.5.2.6.2.6.2.6v.6l.3.5.3.6.2.4.2.5.3.5.3.5.2.5.3.4.4.4.3.5.3.4-.8.5-.3-.6-.4-.4-.3-.5-.3-.6-.3-.6-.3-.5-.3-.6v-.6l-.4-.5-.2-.6-.2-.6-.2-.4-.2-.6-.2-.6-.2-.6-.2-.6-.2-.7-.2-.6v-.7l-.3-.7v-.6l-.2-.7v-.6l-.2-.7v-1.4l-.2-.7v-1.5l-.2-.7v-1.5zm3-70 .8.3v-.2 2.6l-.2 1.6v2l-.2 2v2l-.2 2.4v2.5l-.2 2.6v2.8l-.3 2.8v2.8l-.2 3v2.8l-.2 3v3l-.2 2.8v3l-.3 2.7v2.7l-.2 2.7v7.3l-.2 2v3.8l-.2 1.6v3.3h-1v-6.8l.2-2V513l.2-2.4V508l.2-2.6.2-2.8v-2.8l.2-3V494l.2-3 .2-2.8v-3l.2-2.8v-3l.3-2.7V474l.2-2.5V469l.2-2.4v-4.2l.2-1.8V459l.2-1.5v-1.2zm16-2h-1v.2l-.3-1.4-.3-1.2-.3-1.2-.4-1-.3-1-.4-1-.3-1-.4-.6-.5-.6-.4-.5-.2-.5-.4-.4h-.4l-.3-.2h-1.1l-.4.2-.5.2-.4.4-.5.5-.5.6-.6.7-.5.7-.5 1-.6.8-.5 1-.6 1.2-.7 1.2-.6 1.4-.6 1.4-.6 1.6-1-.4.7-1.6.8-1.4.6-1.4.6-1.2.6-1.2.6-1 .6-1 .6-1 .6-.7.5-.7.6-.6.6-.6.6-.4.5-.3h.6l.5-.3h1.2l.5.3.5.4.5.4.4.5.4.6.4.5.4.8.3 1 .4.8.3 1.2.3 1 .4 1.3.3 1.4.3 1.3zm-.5 0h.6-.5zm.6 0"/>
<path fill="#fff" d="M385 407.2c-.6 18.7-1 59-.8 62.6a51 51 0 0 0 6.7 22.6c4-3 7.7-8.5 8.4-16.6.6-6.7.8-39.5 1-56-4.3-2.6-8.7-6-12.2-9.7l-3.2-2.8z"/>
<path fill="#21231e" d="M384.7 469.8h-1v-23.4l.2-2.4v-19.6l.2-2.4v-9l.2-2v-3.8h1v7.8l-.2 2.4v9.4l-.2 2.5v12.5l-.2 2.4v25.4zm6 22.2.5.8h-.7l-.3-.6-.3-.5-.4-.6-.4-.4-.3-.6-.4-.6-.3-.7-.3-.6-.2-.6-.3-.7-.3-.7-.3-.7-.3-.7-.3-.8-.2-.7-.3-.7-.3-.8-.2-.8-.2-.7-.2-.8v-.8l-.3-.8v-.8l-.3-.8v-.8l-.2-.8v-.8l-.2-.8v-.7l-.2-.7v-1.5h1v2.5l.2.8v.8l.3.7v.8l.2.8.2.8.2.8v.7l.2.7.3.8.2.7.2.8v.8l.4.7.2.7.3.7v.7l.4.6.3.7.3.7.2.6.3.6.3.5.3.6.4.6.3.6.3.5.3.4h-.7zm.5.8-.4.3-.3-.3zm7.7-17h1l-.2.8v.8l-.2.7v.8l-.3.7-.2.7v.7l-.2.5-.2.7-.2.6-.3.6v.6l-.4.6-.2.6-.3.5-.2.5-.3.6-.3.5-.3.5-.4.4-.4.5-.3.4-.5.6-.3.4-.4.4-.3.4-.4.4-.3.3-.3.4-.4.2-.4.3-.4.3-.6-.8.4-.3.3-.3.4-.3.4-.2.4-.4.4-.3.3-.3.4-.4.4-.4.3-.5.4-.4.3-.3.3-.5.3-.5.3-.4.3-.5.2-.6.3-.5.2-.5.3-.6.2-.6.2-.5.2-.6.2-.8.2-.6.2-.6v-.7l.3-.7v-.7l.2-.8v-.7l.2-.8zm1-55.5.6-.8.2.4v18.8l-.2 2.2v14.6l-.2 2v8.9l-.2 1.5v4.3l-.2 1v2.6h-1V471l.2-1.5v-6.3l.2-1.8v-12l.2-2v-20.8l.2-1.7v-5.1l.2.3zm.6-.8h.2v.4l-.2-.5zm-12.4-9.8v1l.4-1 .3.4.2.5.4.3.3.3.3.5.3.3.4.3.3.4.4.4.3.3.4.4.4.3.4.3.3.3.4.3.3.4.4.3.4.3.5.3.3.2.4.2.4.3.4.3.4.3.4.3.4.3h.4l.4.4.4.3.4.2.4.2.4.3-.6.8-.4-.3-.4-.2-.4-.3-.4-.3-.4-.2-.4-.3-.4-.3-.4-.3-.4-.2-.4-.3-.4-.3-.4-.3-.4-.4-.3-.3-.4-.3-.3-.3-.4-.3-.4-.3-.5-.2-.4-.3-.2-.3-.4-.4-.4-.3-.3-.3-.4-.3-.4-.5-.4-.3-.4-.3-.3-.5-.5-.3-.3-.4-.3-.3.2-.8zm-.3.8-1-.8h1.2l-.3.8zm-2.5-3.3h-1l1-.3.2.2.2.2v.2h.3v.3h.4v.2l.3.2.3.2v.2h.3v.2h.2v.2h.3l.2.2v.2h.2v.2l-.2.8v-1l-.3 1h-.2v-.2h-.2v-.2h-.2v-.2h-.2l-.2-.2v-.2h-.2l-.2-.2-.3-.3h-.3v-.3h-.3v-.2l-.2-.2h-.2v-.2h-.2v-.2h-.2v-.2h-.2l1-.4zm-1 0v-1.4l1 1z"/>
<path fill="#fff" d="M400 419.3c-.4 20-.2 51.7 0 54.3a34 34 0 0 0 5.4 19.3c4-3.2 8-8.8 8.8-17 .5-5 2-26.4 2-42.8-5.3-1.7-12-10.4-16.3-14z"/>
<path fill="#21231e" d="M400.4 473.5h-1v-12.9l-.2-1.7v-33.7l.2-2v-4h1v14.5l-.2 2v37.1l.2.5v.3zm4.7 19 .7.8h-.7l-.3-.6-.3-.5-.3-.5-.2-.5-.3-.5-.3-.5-.2-.6-.3-.5-.2-.5-.3-.5-.2-.6-.2-.6-.2-.6-.2-.6-.2-.6-.2-.6-.2-.6v-.6l-.3-.7v-.6l-.3-.8v-.6l-.2-.7v-.8l-.2-.6v-.7l-.2-.8v-1.5l-.2-.7v-1.4h1v2.8l.2.7v.7l.2.7v.7l.2.7v.7l.2.6v.7l.3.6v.6l.3.5v.6l.3.7.3.6.2.6.2.5.2.5v.6l.4.5.2.7.3.5v.5l.4.5.2.5.3.5.2.5.3.5.3.4zm.7.8-.4.3-.3-.4zm8-17.3h1v1.7l-.3.7v.7l-.3.8v.7l-.2.7-.2.7-.2.5-.3.7v.6l-.4.6-.2.6-.3.5-.2.6-.3.6-.4.6-.2.5-.3.5-.4.5-.2.4-.4.6-.3.4-.3.5-.3.4-.4.3-.4.3-.4.4-.3.3-.5.4-.4.3-.3.3-.6-.8.5-.3.3-.3.4-.4.4-.3.3-.4.3-.4.3-.4.4-.4.3-.4.4-.4.3-.5.3-.4.4-.4.3-.5.3-.3.3-.6.3-.4.2-.5.3-.5.2-.5.3-.6.2-.6.2-.6.2-.6.2-.7.2-.7.2-.7v-.7l.3-.8v-.7l.2-.7v-.8zm2.4-42.3.4-1 .3.5v7.9l-.2 1.6v5.1l-.2 1.6v1.7l-.2 1.7v4.6l-.2 1.6v2.9l-.2 1.3v1.4l-.2 1.3v2.5l-.2 1v2.2l-.2 1v1.6l-.2.7v1.1h-1v-2l.2-.8v-1.8l.2-1v-2.2l.2-1.2v-2.7l.2-1.3v-1.5l.2-1.4V457l.2-1.6v-1.6l.2-1.6V449l.2-1.6V443l.2-1.6V433l.5.5zm.4-1h.3v.5zm-16-13.4h-1l.8-.4.5.2.4.4.5.4.5.4.5.5.4.4.4.4.5.5.4.6.5.4.4.5.5.4.5.6.5.5.5.5.5.6.6.5.5.6.7.5.5.6.5.5.6.5.5.5.5.4.6.4.4.4.5.3.4.3.5.3.4.3.5.2.4.2-.3 1-.5-.2-.5-.3-.5-.2-.6-.3-.6-.4-.6-.3-.5-.4-.6-.4-.5-.4-.6-.5-.5-.5-.5-.5-.5-.5-.6-.5-.5-.5-.7-.5-.5-.6-.5-.5-.6-.5-.5-.6-.5-.4-.5-.5-.5-.5-.5-.5-.5-.5-.5-.4-.4-.4-.5-.4-.4-.5-.6-.4-.4-.3-.4-.4.8-.3zm-1 0v-1l.8.6-.8.2z"/>
<path fill="#fff" d="M387 405.6 373 385c-2.8 10.2-6.3 82.8-2.2 88.8a36 36 0 0 0 6.4 19.3c4-3 9.8-8.5 8-16.7-1.6-8.2.4-62.3 2-70.7z"/>
<path fill="#21231e" d="m373.3 384.7 14.2 20.6-.8.5-14.3-20.5v-.4zm-1 .2.4-1 .5.7-.8.2zm-1.2 88.7h-1l.2.3-.5-.8-.3-1.2-.3-1.5v-1.8l-.3-2-.2-2.5v-2.6l-.2-2.8v-20.3l.2-3.7V431l.2-4 .2-3.6v-3.8l.3-3.7.2-3.7.2-3.4.3-3.5.2-3.2.3-3 .2-3 .3-2.5.3-2.4.2-2 .3-2 .3-1.3.4-1 1 .2-.3 1-.2 1.5-.3 1.8-.3 2-.2 2.4-.3 2.5-.3 2.8-.2 3-.3 3.3-.3 3.3-.2 3.4-.2 3.6-.2 3.7v3.7l-.3 3.8v3.8l-.2 3.7v3.8l-.2 3.6v19.6l.2 2.6.2 2.3.2 2v1.8l.4 1.5.3 1 .3.7zm0-.2v.2zm5.7 19.2.6.8-.7-.2-.3-.4-.3-.6-.3-.5-.3-.6-.3-.5-.2-.6-.3-.6-.3-.5-.3-.6-.4-.5-.2-.6-.3-.6v-.6l-.4-.6-.2-.6-.2-.6-.3-.6-.3-.6-.2-.7v-.6l-.3-.5-.2-.7v-.7l-.3-.6v-.6l-.2-.7v-.6l-.2-.7v-1.5l-.2-.7v-.7h1v1.4l.2.7v.6l.2.6v.7l.2.6v.7l.2.6.2.6v.6l.3.6.2.7.2.6.2.7v.6l.3.6.2.5.3.6.2.6.3.6.2.5.3.6.3.5.3.5.3.6.3.4.2.5.3.4.3.4.3.5.4.5h-.7zm.6.8-.4.3-.4-.5zm7.4-17 1-.3v.8l.2.7v3l-.2.7-.2.7v.7l-.3.7-.2.6-.2.6-.2.6-.3.6-.3.5-.4.6-.3.4-.4.5-.5.4-.3.5-.4.4-.4.4-.4.4-.5.5-.4.4-.3.5-.4.3-.4.4-.5.3-.4.3-.3.4-.4.3-.6-.8.4-.3.5-.3.4-.2.3-.4.3-.3.4-.3.4-.4.4-.3.4-.4.4-.5.4-.3.4-.4.4-.5.3-.5.5-.5.3-.5.3-.5.4-.5.3-.5.2-.6v-.6l.3-.5.2-.5.2-.7v-.6l.2-.6v-3.1l-.2-.7zM387 406v-1l.6.7-.2 1-.2 1v1.4l-.3 1.7-.2 2-.2 2v2l-.3 2.4v2.5l-.3 2.6v2.8l-.2 2.7-.2 2.8v3l-.2 2.8v3l-.2 3v8.5l-.2 2.8v13.5l.2 2v1.5l.2 1.4v1l.2 1-1 .2v-1l-.2-1v-1.5l-.2-1.7v-4l-.2-2v-15.5l.2-3V441l.2-3v-2.8l.2-3 .2-2.7v-2.8l.2-2.7.2-2.5V419l.3-2.3v-2.2l.3-2v-2l.3-1.5.3-1.4v-1.2l.3-1 .5.7zm0-1h.7v.7zm0 0v1l-.3-.2.4-.7zm0 1h-.2v-.2l.3.3z"/>
<path fill="#fff" d="M358 451.2q-1.2 17-1 23 .3 11.6 5.5 19.2c4-3 9-8.5 8.4-16.6-2-31.5 1.4-61 5.4-89.6-3.4-2.5-9-5-12.5-7.6q-10.4 57.3-6 71.6z"/>
<path fill="#21231e" d="M357.4 474h-1v-7.4l.2-.7V463l.2-.7V459l.2-1v-1.8l.2-1v-3l.2-1h1v2l-.2 1v2l-.2 1v2.8l-.2.7v3.2l-.2.7v4.2l-.2.6v4.3zm4.8 19 .6.8h-.7l-.3-.6-.3-.5-.3-.5-.2-.5-.2-.5-.3-.5-.3-.6-.2-.4-.3-.6-.2-.5-.3-.6-.2-.7-.2-.6-.2-.6-.2-.5-.2-.6v-.7l-.3-.6v-.7l-.3-.6v-.7l-.2-.6-.2-.6v-.7l-.2-.7v-1.4l-.2-.7v-1.5l-.2-.7v-.7h1v2.2l.2.7v1.2l.2.7v.6l.2.6v.7l.2.5.2.7v.6l.3.6v.6l.3.6.2.6.2.6.2.6.2.6.2.5.2.6.2.6.3.6.2.5.2.5.2.5.3.5.3.5.3.5.3.5.3.4zm.6.8-.4.3-.3-.3h.8zm7.6-17h1v3.7l-.3.7v.6l-.2.7v.7l-.4.6-.2.6-.2.6-.3.6-.3.6-.3.5-.2.6-.3.5-.4.5-.2.5-.4.4-.4.5-.4.4-.3.6-.4.4-.5.4-.4.4-.3.4-.4.3-.4.3-.5.4-.4.3-.2.3-.6-.8.3-.3.4-.3.3-.3.3-.2.4-.4.4-.3.4-.3.4-.4.3-.4.4-.5.3-.4.3-.4.4-.4.3-.5.3-.5.3-.5.2-.5.3-.5.3-.5.2-.6.3-.6.2-.5.2-.6.2-.8v-.6l.2-.6v-.7l.2-.6zm5.7-89.2.7-.8.2.5-.5 2.6-.4 2.6-.3 2.7-.3 2.7-.4 2.7-.3 2.7-.3 2.7-.4 2.8-.3 2.8-.3 2.7-.3 2.8-.2 2.8-.2 2.8-.3 2.7-.2 2.8v3l-.3 2.7-.2 2.8-.2 2.8v2.8l-.2 3v8.5l-.2 3v8.6l.2 3v3l.2 2.8.2 3h-1l-.2-3v-3l-.2-2.8v-5.8l-.2-3V451l.2-2.8v-3l.2-2.7v-2.7l.3-3 .2-2.7.2-2.8V428l.3-2.7.3-2.8.3-2.8V417l.4-2.8.3-2.7.3-2.8.4-2.7.3-2.7.4-2.7.4-2.7.4-2.8.3-2.7.5-2.7.4-2.7v.6zm.7-.8.2.2v.3l-.3-.5zm-12.3-7-1-.3.8-.3.3.2.4.2.2.3h.3l.4.3.3.3.4.2.4.2.5.3.4.2.3.2.4.3.4.2.5.3.5.2.4.2.4.2.4.2.5.3.4.2.5.2.4.2.3.2.4.3h.4l.5.4.4.2.3.2.3.3.4.3.3.3.4.2-.6.8-.2-.2-.4-.3h-.3l-.3-.3-.3-.3-.4-.2-.4-.2-.4-.3-.4-.2-.4-.2-.4-.3-.4-.2-.4-.3-.5-.2-.4-.2-.4-.2-.5-.2-.5-.3-.4-.2-.4-.2-.4-.2-.4-.2-.4-.3h-.4l-.4-.4-.4-.2-.4-.2-.4-.3-.4-.3-.3-.3-.4-.2-.4-.2.8-.3zm-1-.3.2-.8.6.5zm-6 71.4.8.6-.8-.2-.3-1v-1l-.3-1-.2-1.3v-1l-.2-1.4V443l-.2-1.6v-5l.2-1.8v-2l.2-2 .2-2 .2-2.3.2-2.3.2-2.5.3-2.4.3-2.5.3-2.6.4-2.8.4-2.8.4-3 .4-2.8.5-3 .6-3.2.5-3.2.6-3.3.6-3.5.6-3.5.6-3.5 1 .2-.6 3.5-.6 3.5-.6 3.4-.5 3.3-.4 3.3-.5 3-.4 3-.4 3-.4 3-.4 2.7-.3 2.7-.3 2.7-.3 2.5-.2 2.4-.3 2.4-.3 2.3v2.2l-.3 2v2l-.2 2v9.8l.2 1.4v1.2l.3 1 .2 1.2v1l.4 1-1-.3zm.8.6-.5.6-.3-.8zm0 0-.7-.7 1 .3zm-.7-.7 1-1v1.3z"/>
<path fill="#fff" d="m343.6 471.8 4 14.7c.2 7.7 5 14 8.3 19 4-3 7.5-8 6.5-16-5.8-46.5-3.8-77.3 6-115-22 15-32.3 46.6-25 97.3z"/>
<path fill="#21231e" d="m347 486.6-3.8-14.7 1-.3 3.8 14.6zm8.6 18.7.6.7h-.7l-.3-.6-.3-.5-.4-.5-.4-.5-.3-.5-.5-.6-.3-.6-.4-.5-.3-.7-.4-.5-.2-.6-.4-.5-.3-.6-.2-.5-.4-.6-.3-.7-.2-.6-.3-.6-.3-.5-.3-.7-.3-.6-.3-.7-.2-.7-.2-.6-.2-.7-.2-.7-.2-.7v-.6l-.2-.7v-.8l-.2-.8v-.7h1v1.4l.2.7v.7l.2.7.2.6v.6l.3.7v.5l.4.7.2.6.3.6v.6l.4.7.3.6.3.6.3.4.3.6.4.6.3.6.3.5.4.6.3.5.4.5.3.6.3.4.4.5.3.4.4.5.3.4.3.5.4.3h-.8zm.6.7-.4.3-.3-.4h.8zm5.8-16.5h1v5.5l-.2.6v.7l-.3.6v.4l-.3.6-.2.6-.3.5-.2.6-.2.5-.3.6-.3.5-.3.6-.3.4-.2.4-.3.4-.4.5-.2.3-.3.4-.4.4-.3.3-.3.4-.4.4-.4.3-.3.3-.7-.8.4-.3.4-.4.3-.3.4-.3.4-.3.3-.4.4-.3.4-.4.3-.4.3-.4.3-.4.3-.4.3-.4v-.5l.4-.3.2-.5.2-.5.2-.5.2-.5.2-.5.2-.6v-.6l.2-.5v-.6l.2-.7v-5.1zm6.8-114.7-.6-1 .8.7-1 3.5-.8 3.5-.8 3.4-.7 3.4-.7 3.4-.7 3.3-.6 3.5-.6 3.4-.4 3.2-.5 3.3-.3 3.4-.4 3.2-.4 3.4-.4 3.3-.2 3.3-.2 3.4-.2 3.4v3.6l-.2 3.5v14.7l.3 3.7.3 4 .2 3.8.3 4 .4 3.8.3 4 .5 4.2.4 4.3.6 4.4h-1l-.6-4.2-.4-4.3-.5-4.2-.3-4-.4-4-.3-4-.2-3.8-.2-3.8v-3.7l-.2-3.7v-14.3l.2-3.4.2-3.4.2-3.4.2-3.4.3-3.3.3-3.4.4-3.3.4-3.3.6-3.4.5-3.3.7-3.4.6-3.3.7-3.4.7-3.4.8-3.5.8-3.4.8-3.5 1-3.6.8.6zm-.6-1 1-.6-.2 1.3zm-24 98h-1l-.7-4.6-.5-4.6-.5-4.5-.3-4.3-.3-4.2-.2-4.2v-8l.2-3.8.2-3.7.3-3.7.4-3.4.5-3.4.6-3.3.8-3.3.7-3 1-3 1-3 1-2.8 1-2.8 1.2-2.5 1.3-2.5 1.4-2.4 1.5-2.3 1.4-2 1.6-2.2 1.7-2 1.7-2 2-1.6 1.8-1.7 2-1.6 2-1.5.6.8-2 1.4-2 1.6-1.8 1.6-1.8 1.7-1.8 2-1.6 2-1.6 2-1.5 2-1.4 2.3-1.4 2.4-1.4 2.4-1.2 2.6-1 2.7-1 2.7-1 3-1 3-.7 3-.7 3-.6 3.4-.5 3.3-.5 3.5-.3 3.6-.3 3.7-.2 3.8v12l.4 4.4.3 4.3.5 4.5.5 4.6.6 4.7zm-.6 0h.5-.4zm-.4 0"/>
<path fill="#fff" d="m344.8 486.2-20.3-6.7c-2.5 20.2 1.4 45.6 7 79 4.6 29 2 51.6-1.5 66.2 21.6-3 30.7-30.7 20-83-3-13.7-5.8-31.3-5.2-55.5"/>
<path fill="#21231e" d="m324.7 479 20.2 6.7-.4 1-20.2-6.7-.3-.6zm-.6.4v-.6l.7.2zm8 79-1 .3-.6-3-.5-3.2-.6-3-.5-3-.5-3-.5-2.8-.4-3-.4-2.7-.4-2.7-.4-2.7-.4-2.7-.3-2.7-.4-2.6-.3-2.6-.3-2.4-.2-2.5-.3-2.3-.2-2.4-.2-2.4v-2.4l-.3-2.3V500l-.2-2v-10.7l.2-2 .2-2v-2l.4-2 1 .3-.2 2-.2 1.8v2l-.2 2v4l-.2 2v4.3l.2 2.3v2.3l.2 2.3.2 2.3.2 2.2.2 2.4.3 2.4.2 2.5.3 2.5.3 2.5.3 2.6.4 2.8.4 2.6.3 2.7.4 3 .6 2.7.4 2.8.4 3 .5 3 .4 2.8.5 3 .4 3 .5 3.2zm-2 65.8v1l-.5-.6.4-1.4.2-1.4.3-1.5.3-1.5.3-1.6.4-1.6.3-1.7.2-1.8.2-1.7.2-1.8.2-2 .2-1.8v-2l.3-2 .2-2v-2l.2-2v-13.4l-.2-2.3-.2-2.4-.2-2.4-.2-2.5-.3-2.5-.3-2.6-.3-2.6-.4-2.6-.4-2.7 1-.2.3 2.7.4 2.7.3 2.5.3 2.6.3 2.6.2 2.5.2 2.6v2.4l.3 2.4v6.8l.2 2.3v4.3l-.2 2v2l-.2 2v2l-.2 2-.2 2-.2 1.8-.3 1.8v1.8l-.4 1.7-.2 1.8-.3 1.6-.2 1.6-.3 1.5-.3 1.5-.4 1.5-.3 1.4-.5-.8zm0 1h-.6v-.6zm19.4-83.5 1-.2 1 5 .8 4.6.7 4.6.5 4.5.5 4.3.4 4 .3 4 .2 4v7.2l-.2 3.4-.2 3.2-.4 3-.4 3-.6 3-.6 2.6-.7 2.6-1 2.4-1 2.3-1 2.2-1 2-1.2 1.8-1.3 1.7-1.4 1.5-1.4 1.4-1.5 1.3-1.5 1-1.8 1-1.8.7-2 .7-2 .5-2 .2v-1l2-.3 1.8-.6 1.8-.6 1.7-.8 1.6-1 1.5-1 1.5-1 1.4-1.5 1.3-1.5 1.3-1.6 1-1.8 1.2-2 1-2 1-2.2.7-2.3.6-2.4.7-2.7.5-3 .4-2.8.4-3 .2-3.3v-3.5l.2-3.5v-3.7l-.3-3.8-.3-4-.3-4-.4-4.3-.7-4.4-.8-4.5-.8-4.7-1-5zm-4.8-55 .3-1 .3.5V503l.2 2 .2 1.8v2l.2 1.8v1.8l.2 1.8.2 1.7.2 1.8.2 1.7.2 1.7.2 1.6.2 1.6.2 1.6.2 1.5.3 1.5.3 1.5.3 1.5.2 1.4.3 1.4.3 1.4.3 1.4.3 1.3v1.3l.4 1.2-1 .2-.2-1.3-.3-1.3-.4-1.2-.2-1.4-.3-1.4-.2-1.4-.2-1.4-.3-1.5-.2-1.5v-1.5l-.4-1.6-.2-1.5-.2-1.6-.2-1.7-.2-1.7-.2-1.7-.2-1.8-.2-1.8v-1.7l-.3-2-.2-1.7v-2l-.3-1.8v-4l-.2-2v-13l.3.5zm.3-1 .3.2v.2l-.4-.5z"/>
<path fill="#21231e" d="M343.6 584h1v.7h-.8v-.2h-.2v-.4zm-4.3-40 1-.4.4 1.2.2 1.2v1l.4 1.3.2 1.3.2 1.2.2 1.2.2 1.2.2 1.3.2 1.3.2 1.2.2 1.3.2 1.3.2 1.2.2 1.3v1.4l.3 1.3v2.6l.3 1.3v1.3l.2 1.2v2.6l.2 1.3v9.1h-1v-7.6l-.2-1.2v-2.7l-.2-1.3V570l-.2-1.3v-1.3l-.2-1.3v-1l-.3-1.4v-1.3l-.3-1.3-.2-1.3v-1.2l-.3-1.3-.2-1.3-.2-1.3-.2-1.3v-1.2l-.4-1.2-.2-1.2-.2-1.2-.2-1.2-.3-1.2-.2-1.2-.2-1.2zm-5.5-50.4h1.2v6.4l.2 1.5v3.3l.2 1.5v1.6l.2 1.5v1.6l.3 1.5v3.1l.3 1.5.2 1.7v1.5l.3 1.6.2 1.5.2 1.6.2 1.4.2 1.6.3 1.5v1.6l.4 1.6.2 1.6.3 1.6.2 1.5.3 1.6.3 1.5.3 1.5.4 1.6-1 .3-.5-1.7-.4-1.6-.3-1.6-.3-1.5-.3-1.5-.2-1.6-.3-1.6-.2-1.5-.3-1.6-.2-1.6-.2-1.4-.3-1.6-.2-1.5-.2-1.6v-1.7l-.3-1.5-.2-1.6v-1.5l-.2-1.6v-1.4l-.2-1.6-.2-1.6V508l-.2-1.7V503l-.2-1.4v-6.4l-.2-1.6zm1.2 0h-1.2v-.2h.2v-.2h.2v-.2h.8v.2h.2v.4z"/>
<path fill="#fff" d="m344 367.3 13.2 2.2-4.6 23.3c-5 24.3-8.2 53-4.5 84.2q2.2 17.5 7.6 28.5c-14.6-1.6-24-15.8-22.7-40.6q-3.9-43.4 3.2-69.4c1.4-5 5.8-24.2 7.8-28.3z"/>
<path fill="#21231e" d="m357 370-13-2.3v-1l13.3 2.3.4.6zm.3-1h.5v.6zm-4.2 24-1-.3.2-.3v-.4l.2-.5v-.6l.2-.7v-.6l.3-.7v-.8l.2-.8v-1l.3-.7.2-1 .2-1v-.8l.2-1 .2-1 .2-1 .2-1 .2-1 .2-.8v-1l.3-.7.2-1v-.7l.3-.7v-.7l.3-.6v-.6l.2-.5v-.4l.2-.3v-.3l1 .2v.6l-.2.5v.5l-.3.6v.5l-.2.7-.2.8-.2.8v1l-.3.7-.2 1v.8l-.2 1-.2 1-.2 1-.2.8-.2 1-.2 1v1l-.3 1-.2.7-.2 1v.7l-.2.7v1l-.2.5-.2.6v.7l-.2.5v.7zm-4.4 84h-1l-.3-2.8-.3-3-.3-3-.2-2.8v-2.8l-.3-3V457l-.2-3v-11l.2-2.7v-2.7l.2-2.7.2-2.8.2-2.6.2-2.6.3-2.6.2-2.6.3-2.6.3-2.5.4-2.5.4-2.5.4-2.5.3-2.4.4-2.4.3-2.4.5-2.4.4-2.3.5-2.3.4-2.3 1 .2-.4 2.2-.4 2.3-.5 2.3-.4 2.4-.4 2.4-.5 2.4-.4 2.4-.2 2.4-.4 2.5-.3 2.5-.2 2.5-.3 2.6-.3 2.5-.2 2.5-.2 2.7-.2 2.6-.2 2.6v2.6l-.2 2.7v2.7l-.2 2.7v11.5l.2 3v2.7l.3 3 .2 2.7.3 3 .3 2.8.3 3zm7 29v-1l-.4.8-.4-.7-.3-.6-.3-.8-.4-.7-.3-1-.3-.6-.3-.8-.4-.8-.3-.8-.2-.8-.2-.8-.3-1-.2-.7-.3-1-.2-.8-.3-1-.2-1-.2-.8v-1l-.3-1-.2-.8-.2-1-.2-1v-1l-.3-1-.2-1v-1l-.3-1-.2-1v-1l-.2-1.2-.2-1 1-.2v1l.3 1v1.2l.2 1v1l.3 1 .2 1 .2 1v1l.2 1 .2 1 .2 1 .2 1 .3.8.3 1 .2.8.2 1 .3.7.2 1 .3.7.2.8.3 1 .3.7.3.8.3.7v.8l.4.8.4.7.3.7.4.7.3.6.3.7-.5.7zm.4-.7.4.8h-1l.6-.7zM332.4 465l1-.2v8.8l.2 2 .2 2 .3 2 .4 1.8.4 1.7.4 1.8.5 1.7.5 1.5.6 1.5.6 1.5.7 1.3.8 1.3.7 1.3.8 1 1 1 .8 1.2 1 1 1 .8 1 .8 1 .8 1 .7 1.2.6 1.2.4 1.2.5 1.2.3 1.2.3 1.3.3h1.4l-.2 1h-1.3l-1.4-.4-1.3-.4-1.3-.4-1.2-.5-1.2-.5-1.2-.7-1-.6-1.2-.8-1-.8-1-1-1-1-1-1-1-1.2-.7-1.2-.8-1.3-.8-1.2-.7-1.4-.7-1.5-.5-1.6-.6-1.6-.5-1.7-.4-1.6-.4-1.8-.3-2-.2-1.8-.2-2-.2-2v-8.9zm3.3-69.6 1 .3-.5 1.6-.4 1.7-.4 1.7-.3 1.7-.3 1.8-.3 1.8-.3 1.8-.2 2-.2 1.8-.3 2-.2 2v2l-.3 2v2l-.2 2-.2 2.3v4.3l-.2 2.2v9.6l.2 2.5v2.4l.2 2.5v2.5l.2 2.6.2 2.6.2 2.5.2 2.6.2 2.8h-1l-.2-2.6-.2-2.6-.2-2.7-.2-2.7v-2.5l-.2-2.6v-2.5l-.2-2.4v-18.5l.3-2v-2.2l.3-2v-2.2l.3-2 .3-2 .3-2 .2-1.8.3-2 .4-1.8.4-1.8.3-1.8.5-1.7.4-1.7.3-1.7.4-1.6zm8.3-28.6v1l.4-.3-.2.4-.2.4-.2.6-.2.6-.3.7-.2.8-.2 1-.2.8-.3 1-.3 1-.2 1-.3 1-.3 1-.3 1.2-.4 1-.3 1.2-.3 1-.2 1.2-.3 1-.3 1.2-.3 1-.3 1-.3 1-.2 1-.3 1-.3 1-.2.8-.2.8-.2.7v.6l-.2.6v.5l-1-.3v-.5l.2-.7.2-.6.2-.8v-1l.4-.7.2-1 .2-.8.3-1 .2-1 .3-1 .2-1.2.3-1 .3-1.2.3-1 .4-1 .2-1.2.3-1 .2-1.2.3-1 .3-1 .3-1 .4-1 .2-1 .3-1v-.8l.4-.8.2-.7.3-.7v-.6l.3-.5.2-.5.5-.2zm-.5.2.2-.3h.3zm.5.3v-.5zm-.5-.3.2-.3h.3z"/>
<path fill="#fff" d="m336 370.4 6.4 7.4c-1.8 1.4 1.3 7-.4 18-1 6.4-4.8 13.8-5.6 22-2.5 26.5-2.5 59.8 5.4 81-14.5-1.6-19.5-14.8-20-39.6-.4-20.6-.4-44.7 4.7-72.7q1.5-9.7 9.4-16z"/>
<path fill="#21231e" d="m342 378.2-6.5-7.5.8-.6 6.5 7.5v.7h-.7zm.8-.7.4.4-.5.2v-.7zm-.3 18.5h-1l.2-1.2v-1l.2-1V385l-.2-.6v-1.2l-.2-.6v-1l-.2-.4v-2.8l.2-.3.3-.4v-.2l.7.8v.2h-.2v.5h-.2v2.2l.2.4v1.1l.2.6v1.1l.2.7v8.1l-.2 1v1l-.3 1zm-5.6 21.7h-1v-1.8l.2-.7.2-.7v-.7l.3-1v-.6l.3-.8.2-.7.2-.8.2-.7.2-.7.2-.7.2-.6.2-.7.2-.7.3-.7v-.7l.3-.6.2-.7.2-.7.2-.6v-.7l.3-.6.2-.6.2-.5.2-.7v-.6l.2-.6v-.6l.2-.6v-.5h1v1.2l-.3.6v.7l-.2.6v.7l-.3.7-.2.6-.2.6v.7l-.3.7-.2.6-.3.7-.2.6-.2.6-.2.7-.2.7-.2.7-.3.7-.3.7-.2.8-.2.7-.2.7v.7l-.2.6-.2.7v.7l-.3.8v.7l-.2.7v1.5zm4.8 81.6v-1l-.4.7-.8-2-.6-2-.7-2.3-.6-2.2-.5-2.3-.5-2.4-.5-2.4-.4-2.4-.4-2.5-.4-2.5-.3-2.5-.3-2.6-.2-2.7-.2-2.7-.2-2.6v-2.7l-.2-2.7V455l-.2-2.8v-10.9l.2-2.7V436l.2-2.8v-2.7l.3-2.6.3-2.7.2-2.6.2-2.6.2-2.4h1l-.3 2.6-.2 2.6-.2 2.5-.2 2.6v2.6l-.2 2.6v2.7l-.2 2.6v2.7l-.2 2.7V455l.2 2.7v2.7l.2 2.7.2 2.5.2 2.7.2 2.6.3 2.5.3 2.6.4 2.4.4 2.4.4 2.5.4 2.3.5 2.4.7 2.2.6 2.2.6 2.2.6 2 .7 2-.5.7zm.5-.6.3.7h-.8zm-21-39.5h1v2.2l.2 2.3v2l.2 2.2.2 2v2l.3 1.7.3 1.8.3 1.8.2 1.6.4 1.5.4 1.6.4 1.5.5 1.4.4 1.2.6 1.3.6 1.2.6 1 .7 1 .6 1 .8 1 .8 1 .8.6 1 .7 1 .7 1 .6 1 .5 1 .4 1 .4 1.3.3 1.3.2 1.3.2-.2 1-1.4-.2-1.3-.3-1-.4-1.3-.4-1.2-.5-1-.6-1.2-.5-1-.7-1-.7-.8-.7-1-1-.7-1-.7-1-.6-1-.7-1.2-.6-1-.5-1.4-.5-1.3-.5-1.5-.5-1.5-.4-1.5-.3-1.7-.4-1.5-.4-1.8-.3-1.8-.2-2v-2l-.3-2v-2l-.2-2.3v-2.2l-.2-2.3zm4.7-72.8 1 .2-.5 2.6-.4 2.6-.3 2.5-.4 2.6-.3 2.4-.4 2.5-.3 2.4-.3 2.4-.2 2.4-.2 2.5-.3 2.3v2.4l-.3 2.4-.2 2.3v2.4l-.2 2.2v2.3l-.2 2v4.5l-.2 2.2V459h-1v-26.9l.2-2.2v-2l.2-2.4v-2.3l.2-2.3.2-2.3.2-2.4.2-2.3.2-2.4.2-2.5.3-2.3.3-2.4.3-2.5.4-2.5.3-2.6.4-2.5.4-2.6.6-2.6.4-2.6zm10.3-16.3-.8.7h.7l-.4.5-.5.4-.5.4-.4.4-.4.5-.4.3-.4.4-.4.5-.4.4-.4.5-.3.5-.4.5-.3.5-.3.4-.3.4-.3.5-.2.4-.3.5-.2.4-.3.5-.2.4-.2.6-.2.5-.2.5-.2.6-.2.5-.2.7v.5l-.3.6v.6l-.2.6v.6l-1-.2v-.6l.2-.6.2-.6v-.6l.3-.6v-.6l.3-.5.2-.6.2-.6.2-.4.3-.6v-.5l.4-.5.2-.6.3-.5.2-.6.3-.5.3-.6.4-.5.3-.6.4-.5.2-.6.4-.4.4-.5.4-.4.4-.4.5-.4.4-.5.5-.4.4-.4.5-.6.6-.4h.7zm-.7 0 .4-.3.3.4z"/>
<path fill="#fff" d="m372.3 390-13.4-1.6c-2.6 12.7-4.5 21.7-5 26.2-1 9 1.8 17 5 23 5-3 7.2-9.4 9.2-18.6s2.7-19.2 4-29z"/>
<path fill="#21231e" d="m359 388 13.3 1.5v1l-13.5-1.6-.4-.7.5-.4zm-.6.3v-.4h.5l-.6.3zm-4 26.4h-1l.2-.6v-.8l.2-.6v-1l.2-.6v-.7l.3-.6v-.7l.2-.7v-.7l.3-.7v-1l.2-.7.2-.8.2-1v-.7l.3-1 .2-.8v-1l.2-1 .2-1 .2-1 .2-1 .2-1 .3-1 .2-1 .2-1.2.2-1.2v-1l.4-1.3 1 .2-.3 1.2v1l-.3 1.3-.3 1-.2 1.2-.2 1-.2 1-.2 1-.2 1-.2 1-.2 1v1l-.3 1-.2.8-.2.8v1l-.3.7v.8l-.3.7v.8l-.2.7-.2.7v.6l-.2.7v1.3l-.2.5v1.1l-.2.5v.9zm4.3 22.6.5.8h-.7l-.3-.7-.3-.6-.4-.6-.3-.5-.3-.6-.2-.7-.3-.7-.2-.6-.3-.7-.2-.7-.3-.7-.2-.8-.2-.7v-.7l-.3-.7-.2-.7-.2-.7v-.8l-.3-.7v-.7l-.2-.8v-.8l-.2-.7v-.8l-.2-.8v-6.1h1v6.6l.2 1v1.4l.3.7v1.6l.3.8.2.7v.8l.3.7.2.7.3.7.2.6.2.7.2.6.2.6.2.6.3.7.3.5.2.6.3.7.3.6.3.6.3.5-.7-.2zm.5.8-.5.4-.2-.5h.7zm8.6-19h1l-.3 1-.2.8-.2 1v.7l-.3.8-.2.7-.2.8-.2.7v.8l-.4.7-.2.7-.3.6v.7l-.4.6-.2.7-.3.6-.2.5-.3.5-.3.6-.3.5-.4.7-.3.5-.4.5-.5.4-.3.6-.4.4-.4.4-.4.4-.5.3-.4.5-.4.3-.4.3-.5-.7.4-.3.5-.3.4-.3.3-.4.4-.3.4-.4.4-.4.4-.5.3-.4.4-.4.4-.5.3-.4.4-.5.2-.4.3-.6.2-.5.3-.6.2-.7.3-.7.2-.6.3-.7.2-.6.2-.7v-.8l.3-.7.3-.7.2-.8.2-.8.2-.8.2-.8.2-.8.2-1zm4.5-28.5v-1l.5.5v1l-.3 1v.8l-.2 1v1l-.2.8v1l-.2.8v1l-.2 1v.8l-.2 1v1l-.2.8v1l-.2.8v1l-.2.8v1l-.2 1-.2.8v1l-.2.8-.2 1v.8l-.2 1-.2.8-.2.8v1l-.3.8v1l-.3.7h-1l.3-1v-.8l.3-1 .2-.7v-1l.3-.8v-1l.3-.8.2-1v-1l.3-.8v-1l.2-.8v-1l.2-.8v-1.8l.2-1v-1l.2-.8v-1l.2-.8v-1l.3-1v-1.8l.2-1v-.8l.2-1v-.8l.3-1v-1l.6.7zm0-1h.6l-.2.5zm0 0v1zm0 1"/>
<path fill="#fff" d="M407 418.6h-11.8q-.7 16.6-.5 22.3c.4 7.5 2.3 14 5.5 18.7 3.6-3 7-8.3 7.6-16.2.6-8-.6-16.5-.7-25z"/>
<path fill="#21231e" d="M395.2 418.2h12v1h-12l-.5-.5zm-.5.5v-.5h.5zm.5 22.2h-1v-11.4l.2-.8v-4.4l.2-.8v-5h1v7.8l-.2.7v5.6l-.2.7v7.7zm4.7 18.4.6.7h-.8l-.3-.5-.3-.4-.3-.4-.4-.5-.2-.4-.3-.5v-.4l-.4-.6-.2-.5-.3-.5v-.6l-.3-.6-.2-.5-.2-.6-.2-.6v-.5l-.2-.6-.2-.7-.2-.6v-.6l-.2-.6-.2-.6v-.7l-.2-.5v-.7l-.2-.7v-.5l-.2-.7v-2.6l-.2-.7h1v1.1l.2.7v1.4l.2.7v.7l.2.6v.7l.2.6v.6l.3.6v.7l.3.6v.7l.3.5v.6l.2.6.2.5.2.5.2.5.3.6.3.5.2.6.3.5.2.6.3.5.2.6.3.5.3.6.4.4.2.5h-.7zm.6.7-.5.5-.2-.5h.8zm6.7-16.6h1v1.6l-.2.7v1.4l-.3.8v.6l-.3.7-.2.7-.2.6-.2.6-.2.5-.2.5-.3.6v.5l-.4.7-.2.5-.3.5-.2.5-.3.4-.3.5-.3.5-.4.4-.3.3-.4.4-.4.4-.3.5-.4.3-.4.4-.4.3-.3.3-.4.3-.7-.6.2-.3.4-.2.3-.3.2-.4.3-.2.4-.3.2-.4.3-.3.3-.4.3-.4.4-.5.3-.4.2-.4.2-.4.3-.5.2-.5.3-.5.2-.5.3-.5.2-.6.2-.4v-.6l.3-.6v-.6l.3-.6v-.7l.3-.6v-1.4l.2-.7V444zm0-24.3v-1l.4.6v5.6l.2 1v4.6l.2.8v2.8l.2.8v9.2h-1v-11.8l-.2-.8V429l-.2-1v-3l-.2-1v-5.3l.4.5zm0-1h.4v.6l-.5-.5z"/>
<path fill="#fff" d="m420 424.2-12 .6q0 16.5.3 22.2a37 37 0 0 0 6.2 18.6c3.5-3 6.8-8.6 7-16.5s-1-16.3-1.5-24.8z"/>
<path fill="#21231e" d="m408 424.3 12-.6v1l-12 .6-.4-.5.5-.5zm-.4.5v-.5h.5l-.4.5zm1.2 22.2h-1v-4l-.2-.6v-17.8h1V445l.2.4zm5.4 18.2.6.8h-.7l-.2-.5-.3-.5-.3-.5-.3-.5-.4-.5-.3-.5-.3-.5-.2-.5-.3-.5-.3-.5-.2-.6-.2-.5-.3-.7-.2-.6-.2-.6v-.4l-.3-.6-.2-.6v-.7l-.3-.6-.2-.5v-.6l-.3-.8v-.6l-.2-.7v-.8l-.2-.6v-.7l-.2-.8v-2h.8v.7l.2.7v1.4l.2.7.2.7v.7l.2.7v.6l.3.6v.7l.2.6v.5l.3.6.2.7.2.5v.6l.3.6.2.5.2.5.2.5.2.5.2.6.2.6.3.5.2.6.2.4.3.5.3.5.3.4.3.5.3.3h-.8zm.6.8-.4.4-.3-.5h.8zm6.2-17h1v2.3l-.2.7v.7l-.2.7-.2.6v.7l-.3.6v.6l-.2.5-.2.6-.2.7-.2.6-.3.5-.3.6-.3.5-.2.4-.3.5-.4.4-.3.4-.3.5-.3.4-.3.4-.3.5-.2.4-.3.3-.3.4-.4.3-.3.4-.3.3-.4.3-.6-.8.3-.3.3-.4.3-.3.4-.3.3-.4.4-.3.4-.4.2-.5.3-.4.2-.3.3-.4.3-.5.2-.4.3-.5.2-.6.3-.5.2-.6.2-.5.2-.6.2-.6.2-.6.2-.5.2-.6v-.5l.3-.7v-.6l.2-.7v-.6l.2-.8zm-1-25.3v1l.5-.5v2.4l.2.8v1.5l.2.7v3.4l.2.7v1.5l.2.8v.8l.2.8v2.5l.2.7v2.3l.2.8v5.3h-1v-7.4l-.2-.7v-1.6l-.2-.8V437l-.2-1v-1.5l-.2-.7v-1.6l-.2-.8v-1.6l-.2-.8v-1.6l-.2-.8v-2.2l.4-.6zm-.5.6v-.6h.5zm.5.4v-1z"/>
<path fill="#fff" d="m395 412.4-12-.8q-1.8 16.4-2.2 22-.4 11.6 4 19.3c3.8-2.8 7.7-8 8.8-15.7 1.2-8 .8-16.4 1.4-25z"/>
<path fill="#21231e" d="m383 411 12 1v1l-12-1-.4-.5.5-.4zm-.4.5v-.5h.5l-.4.5zm-1.3 22.2h-1V431l.2-.4V429l.2-.6v-1.2l.2-.6v-2.2l.2-.7v-1.4l.2-.8v-.8l.2-.8v-1l.2-.8v-1l.2-.8v-1l.3-1v-1l.2-1v-1l1 .2v2l-.3 1v1l-.2 1v.8l-.2 1v.7l-.2 1v.8l-.2.8v.8l-.2.8v1.3l-.2.7v1.4l-.2.6v1.1l-.2.6v1.7l-.2.5v2.7zm3.2 18.8.5.8-.7-.2-.2-.4-.2-.5-.2-.4-.3-.5-.2-.4v-.5l-.3-.5-.3-.5v-.6l-.3-.5v-.7l-.3-.6v-.6l-.3-.4v-.6l-.3-.7V443l-.2-.5v-.7l-.2-.6V440l-.2-.8v-5.5h1v6.8l.2.7v.7l.2.6v.6l.2.5v.6l.2.7.2.6v.6l.3.5v.5l.3.6.2.5.2.7.2.5.2.5.2.5.2.5.3.5.2.5.2.5.2.4h-.7zm.5.8-.4.3-.3-.5.8.3zm8.2-16h1l-.2.8v.8l-.3.7v.7l-.3.7-.2.6-.2.6-.2.6-.3.6-.2.6-.3.6-.2.6-.3.5-.3.6-.3.5-.4.5-.3.5-.3.4-.3.5-.3.4-.4.6-.3.4-.4.4-.3.3-.4.4-.3.5-.4.3-.5.3-.3.4-.4.3-.4.3-.3.3-.5-.8.3-.3.4-.2.3-.3.4-.3.2-.3.4-.2.3-.4.3-.3.3-.3.3-.4.2-.4.4-.5.3-.4.2-.3.3-.5.3-.5.3-.4.4-.5.2-.5.3-.6v-.5l.4-.6.2-.5.2-.5.2-.6.2-.7.2-.7.2-.6.2-.7v-.7l.2-.7.2-.8zm1.8-24.4v-1l.5.5v1.5l-.2.8v5.6l-.2.7v9l-.2.8v2.2l-.2.8v.7l-.2.8v1l-.2.6v.8l-1-.2v-.7l.2-.8v-1.5l.2-.7V432l.2-.8V428l.2-.8V421l.2-.7v-4.8l.2-.8v-2.3l.6.5zm0-1h.5v.5z"/>
<path fill="#fff" d="m384 399.6-13.2-5.4c-2.2 8.8-5.2 37.8 0 50 4.5-3 9-8.4 10.3-17 1.6-9 2-18.2 3-27.6z"/>
<path fill="#21231e" d="m371 393.7 13 5.4-.3 1-13-5.4-.4-.6zm-.7.3.2-.5.5.2zm.3 50 .6.7-.7-.2-.5-1.2-.5-1.3-.3-1.4-.4-1.5-.3-1.5-.3-1.6-.2-1.7-.2-1.7v-1.8l-.2-1.8v-3.6l-.2-2V418l.2-2v-1.8l.2-1.8.2-1.8V409l.3-1.8.2-1.7V404l.3-1.6.2-1.5.3-1.4.2-1.3.2-1.2.2-1v-1l.3-1 1 .3-.2 1v.8l-.3 1.2-.3 1.2-.2 1.3-.2 1.4-.2 1.5-.2 1.6-.2 1.6v1.7l-.3 1.7v1.7l-.2 1.8v1.8l-.2 1.8v3.8l-.2 2v5.4l.2 1.8v1.7l.2 1.8.2 1.7.2 1.6.3 1.6.3 1.5.3 1.3.5 1.4.4 1.2.4 1h-.8zm.6.7-.5.3-.2-.5zm9.4-17.7h1v1l-.3.8-.2.8v.7l-.3.8-.2.8-.3.7-.2.7-.3.7-.3.5-.3.7-.2.6-.3.6-.3.6-.3.6-.5.5-.3.7-.4.5-.4.5-.3.5-.3.4-.4.5-.4.5-.5.4-.4.3-.3.4-.4.4-.4.4-.5.4-.5.3-.4.4-.4.3-.6-.8.4-.4.4-.3.4-.3.4-.3.4-.4.4-.3.4-.4.4-.4.4-.4.3-.4.4-.4.3-.5.3-.4.4-.4.3-.5.4-.4.3-.6.3-.5.3-.6.3-.6.2-.6.3-.7.3-.5.2-.6.3-.8.2-.7.2-.7.3-.7v-.7l.3-.7.2-.8v-.8zm3-27 .4-1 .4.6v1l-.2.8v1.7l-.2 1v1l-.2.8v1.8l-.2.8v1.7l-.2 1v1.7l-.2 1v1.6l-.2 1v.7l-.2 1v.8l-.2.8v1l-.2.7v.8l-.2 1v.8l-.2 1v.7l-.3.8v.8h-1v-.8l.2-1v-1.5l.2-.8v-1l.2-.8v-1l.2-.7v-1l.2-.7v-1l.2-.7v-1.6l.2-1v-.7l.2-1V410l.2-.8v-1.8l.2-.8v-1.8l.2-1v-1.5l.2-1v-.8l.2-1zm.4-1 .4.3v.3l-.4-.5zm0 .6-.3.4.2-.4zm0-.5.4.3v.3l-.4-.5z"/>
<path id="rs-c" fill="#edb92e" stroke="#21231e" d="M387.8 701.2c8 6.3 15.2-8.3 8-27.6-5-14.2-30.6-8.7-16.4 10.5.7 1 1.6.6 1.5-.4-1-4 1.6-6.3 5.5-5.5 10.5 2 11 22-.6 17.6-2.2-.2-.4 4 1.7 5.6z"/>
<path fill="#edb92e" stroke="#21231e" d="M400 639.2c-1 3.4-5 7.6-8 10.8-4.5 4.8-3.4 12.2-.2 16 3.5 4.4 5 9.2 5.8 13 .5 2.3 1.5 7.4.8 15.5-.4 4-2.7 6-5 7.7q-1.5 1.5 4.3 6c.4.2 1.5 1 2 3 .2.4 2 .4 2.2 0 .4-2 1.6-2.8 2-3 3.7-3 5.4-5 4.2-6-2.2-1.7-4.6-3.8-5-7.7-.6-8 .3-13.2.8-15.5.8-3.8 2.3-8.6 6-13 3-3.8 4.2-11.2-.5-16-3-3.2-7-7.4-8-10.7q0-1.1-.7-1-.6-.1-.7 1z"/>
<path fill="#edb92e" d="M395 685.5h11.6c2 0 3.6 1.6 3.6 3.5 0 2-1.6 3.5-3.6 3.5H395c-2 0-3.5-1.5-3.5-3.5s1.6-3.5 3.6-3.5z"/>
<path fill="#21231e" d="M406.6 686H395v-1h11.6zm4 3h-1v-1l-.2-.2v-.2l-.2-.2v-.2h-.2v-.2h-.2v-.2h-.3v-.2h-.2v-.2h-.3l-.2-.2h-.5v-.2h-.6v-1h1l.2.2h.4v.2h.3l.2.2h.2v.2h.2v.2l.3.2.2.2v.2l.3.2.2.3v.3l.2.3v.4l.2.2zm-1 0h1zm-3 4v-1h.8l.3-.2h.2l.2-.2.2-.2h.3v-.2l.2-.2v-.2l.2-.2.2-.3v-.3l.2-.2v-.8h1v1.2l-.2.2v.4h-.2v.3l-.2.3h-.2v.3h-.2v.3h-.3l-.3.2v.2h-.3l-.2.2h-.2l-.3.2h-.4l-.2.2h-.8zm-11.5-1h11.6v1H395v-1zm-4-3h1v1l.2.2v.3h.2v.2h.2v.2h.2v.2h.2v.2h.2l.3.2h.2l.2.2.3.2h.6v1h-1.2v-.2h-.3l-.2-.2h-.2l-.2-.2-.2-.2-.3-.2-.3-.3-.2-.3-.2-.3-.2-.2v-.2l-.2-.2v-.4l-.2-.2zm1 0h-1zm3-4v1H394v.2h-.3l-.2.2h-.2v.2h-.2v.2l-.2.2-.2.2-.2.2v.2l-.2.2v.5h-.2v.6h-1v-1.2l.2-.2v-.2h.2v-.3h.2v-.2l.2-.2v-.2h.2l.2-.2v-.2h.3v-.2h.3v-.2h.3l.3-.2h.2l.2-.2h.5l.2-.2h.7z"/>
<path fill="#fff" d="m417 579.2.5-11c-4.4-2.2-15.2 0-19.7 10.2a65 65 0 0 1-18 25.2c10 1.8 18.4-.2 23.7-7.4 7.3-9.8 11.2-15.7 13.6-17z"/>
<path fill="#21231e" d="m418 568.3-.4 11h-1l.4-11 .7-.5zm-.3-.5.3.2v.3zm-19.5 10.8-1-.4.6-1 .5-.8.5-1 .6-.7.5-.8.5-.8.7-.7.6-.6.7-.7.7-.5.7-.6.6-.4.7-.5.8-.4.8-.4.7-.3.8-.3.7-.2.7-.3h.7l.8-.3h1.2l.7-.2h2l.7.2h.5l.6.2.5.2.4.2-.4 1-.4-.3h-.5l-.5-.2h-.5l-.5-.2h-3l-.7.2h-.6l-.7.3-.7.2-.7.2-.7.2-.8.3-.7.3-.7.4-.7.4-.5.5-.7.5-.7.6-.5.6-.6.6-.7.7-.6.6-.5.7-.6.8-.5 1-.3.7zM380 603l-.2 1-.2-.8.6-.6.6-.5.7-.5.6-.6.7-.6.6-.6.5-.6.6-.6.6-.7.6-.7.5-.6.7-.7.5-.7.6-.7.5-.7.6-.8.4-.8.5-.7.5-.8.5-1 .5-.8.6-.8.6-1 .5-.8.6-1 .6-1 .5-1 .5-1 .5-1 .6-1 .5-1.2.5-1.2 1 .4-.6 1.2-.5 1-.6 1.2-.5 1-.4 1-.6 1-.5 1-.5 1-.6 1-.5 1-.6.8-.6.8-.5.8-.5.8-.6.8-.5.8-.6.7-.4.7-.6.8-.6.6-.5.7-.7.7-.6.6-.6.7-.4.6-.6.5-.6.6-.7.7-.6.5-.5.6-.6.6-.8.5-.2-1zm-.2 1h-1l.8-.8zm23.4-8 .8.5-.6.7-.5.6-.7.6-.6.6-.6.6-.5.5-.6.6-.7.5-.7.5-.7.4-.8.3-.7.4-.7.3-.7.3-.7.2-.7.3-.8.2-.8.2h-.8l-.8.2h-.8l-1 .2h-6.1l-1-.2-.8-.2-1-.2.2-1 1 .2.8.2h1l.8.2h6.6l.8-.3h.8l.7-.3.8-.2.7-.2.7-.3.7-.2.7-.2.8-.4.6-.3.7-.3.7-.4.6-.5.6-.5.5-.5.5-.5.6-.5.5-.6.7-.6.5-.7zm13.4-16.8h1l-.2.4-.2.2h-.2l-.3.3-.2.3-.3.2-.2.3-.3.3-.3.4-.3.3-.2.4-.4.5-.3.4-.3.3-.4.5-.3.5-.4.5-.5.6-.3.5-.4.5-.5.7-.5.6-.5.7-.5.7-.5.7-.5.6-.6.8-.6.8-.5.8-.6 1-.7.7-.7 1-.6.8-.8-.6.6-1 .7-1 .6-.7.7-1 .6-.7.6-.8.5-.7.5-.7.5-.7.5-.7.5-.8.5-.6.5-.6.4-.6.4-.6.4-.6.4-.5.4-.5.3-.5.3-.4.4-.5.3-.4.3-.4.3-.3.4-.3.3-.3.2-.2.3-.3.3-.2.4-.2h.2l.3-.2zm1 0v.3h-.2z"/>
<path fill="#fff" d="m425.2 580.6-11.8-5q-7.5 14.9-9.5 20.2c-2.8 7-3.5 13.8-2.3 19.5a22 22 0 0 0 14-11.6c3.8-7 6-15.3 9.5-23z"/>
<path fill="#21231e" d="m413.6 575.2 11.7 5-.3 1-11.8-5-.3-.8.6-.2zm-.7.2v-.4l.6.2zm-8.7 20.6-1-.4.2-.3.2-.4.2-.5v-.4l.2-.3.2-.5.2-.4.2-.5.2-.5.3-.5.2-.5.3-.6.2-.5.3-.6.3-.5.3-.7.2-.6.3-.6.3-.7.4-.8.3-.7.4-.8.2-.7.4-.8.4-.8.4-.8.4-.8.4-.8.4-1 .4-.8.5-.8.4-1 .8.5-.4.8-.5 1-.5.8-.4.8-.3 1-.4.7-.4 1-.5.7-.4.7-.3.8-.3.7-.4.6-.3.7-.3.7-.3.6-.2.7-.3.6-.3.5-.3.6-.3.6-.3.6-.2.5-.3.5-.3.5-.2.5-.2.4-.2.5v.5l-.2.4-.2.3v.3l-.3.4zm-2.7 18.8.2 1-.6-.4v-.5l-.2-.7v-.6l-.2-.5v-1.7l-.2-.5v-3.7l.2-.6v-1.2l.2-.7v-.6l.2-.5v-.7l.2-.6.2-.7v-.6l.3-.8v-.6l.3-.7.2-.7.2-.7.2-.7.2-.7.2-.7 1 .4-.3.6v.7l-.4.6-.2.6-.2.6-.2.7v.5l-.3.6v.8l-.3.6v.6l-.2.7v.6l-.2.6v.5l-.2.6v1.9l-.2.5v3.5l.2.5v1.2l.2.5v.7l.2.5-.6-.4zm.2 1h-.5v-.4zm13.5-12.4 1 .5-.5.6-.3.6-.4.6-.3.6-.4.6-.4.5-.5.6-.5.6-.4.5-.4.6-.5.4-.4.5-.5.4-.5.3-.4.4-.6.4-.5.4-.5.4-.5.3-.5.4-.5.3-.4.2-.5.2-.4.2-.5.2-.4.3h-.4l-.5.2-.5.2h-.5l-.4.3h-.5l-.2-1h.9l.4-.3h.4l.4-.3h.5l.4-.3.5-.2.4-.2.5-.2.5-.2.5-.3.5-.3.4-.3.4-.4.4-.3.5-.4.4-.4.4-.4.6-.4.4-.5.4-.4.5-.6.3-.4.4-.5.4-.6.5-.6.4-.5.2-.7.4-.6.4-.6.3-.6zM425 581l.3-.8.3.6-.3.7-.3.8-.3.7-.3.7-.3.8-.2.7-.3.7-.2.7-.3.7-.3.8-.3.7-.2.6-.3.8-.4.7-.3 1-.2.6-.2.7-.3.8-.3.8-.2.7-.3.7-.3.8-.3.7-.2.7-.3.7-.3.8-.3.7-.5.7-.3.7-.3.6-.5.6-.3.7-1-.6.5-.6.3-.7.3-.6.3-.6.4-.7.3-.6.3-.7.3-.7.2-.7.3-.7.2-.7.3-1 .3-.6.3-.7.3-.7v-.8l.4-.7.3-.7.3-.8.2-.7.3-.7.3-.8.3-.7.3-.7.3-.7.3-.7.2-1 .3-.6.3-.8.3-.7.4-.8.3-.8zm.3-.8.5.2-.2.4z"/>
<path fill="#fff" d="m428.6 580.6-12.7-2q-3.7 16.1-4.4 22-1.4 11.3 2.7 19.4c4.3-2.3 8.8-7 10.7-14.7 2-7.8 2.2-16.3 3.6-24.7z"/>
<path fill="#21231e" d="m416 578.2 12.6 2v1l-12.8-2-.4-.6zm-.6.4v-.5l.6.2-.6.4zm-3.3 22h-1l.2-.5V599l.2-.6v-.5l.2-.6v-.5l.2-.6v-.6l.2-.5v-.6l.2-.6v-.6l.2-.6.2-.7v-.6l.3-.7v-.7l.2-.8v-.8l.3-.8.2-.8v-.8l.3-1 .2-.7.2-1 .2-.8.2-1 .2-1 .2-1 .2-1 1 .3-.2 1-.2 1-.2 1-.2 1-.2.8-.2 1-.2.7-.2 1-.2.7v.8l-.3.8-.2.8v.8l-.2.7v.6l-.2.7-.2.7v.6l-.2.6-.2.7v.4l-.2.6v.6l-.2.5v1.1l-.2.6v.4l-.2.4v1.2zm2 19 .5.8-.7-.2-.2-.5-.3-.5-.2-.5v-.6l-.3-.4-.2-.5-.2-.5-.2-.6v-.6l-.2-.6v-.6l-.3-.6v-.6l-.2-.6v-.6l-.2-.6v-2.8l-.2-.6v-5.4l.2-.7v-1.5h1v3.1l-.2.7v5.1l.2.6v1.2l.2.6v.6l.2.6v.6l.3.6v.5l.2.6v.7l.3.5v.5l.3.6.2.5.2.5.2.5.3.5.2.5-.7-.2zm.5.8-.5.3-.2-.5zm10-15.2 1 .2-.2.7-.2.8v.7l-.3.7-.3.7-.2.5-.3.6-.4.7-.3.6-.3.6-.3.4-.3.6-.4.5-.3.5-.4.5-.4.5-.4.4-.4.5-.4.3-.4.4-.4.4-.4.5-.4.3-.4.4-.4.3-.4.3-.4.3-.4.4-.5.3-.4.3-.4.2-.5.2-.5-.8.4-.2.4-.3h.4l.4-.4.4-.3.4-.3.4-.3.4-.3.4-.3.4-.3.3-.3.4-.4.4-.4.5-.4.3-.4.4-.5.3-.4.4-.6.2-.5.3-.6.3-.5.3-.6.4-.6.3-.5.3-.6.2-.6.3-.5.2-.6.3-.8.2-.7.2-.6zm4-25v1l.5-.5v.8l-.2.8v.7l-.2.8v.8l-.2.8v.8l-.2.8v.7l-.2.8v.8l-.2.8v1.7l-.2.7v.8l-.2.8v.8l-.2.8v.7l-.2.8v1l-.2.6v.8l-.2.8-.2.7v.7l-.2.7-.2.8v.7l-.3.7-.2.7-1-.2.2-.8.2-.7v-.7l.2-.8v-.7l.3-.7v-.8l.2-.8v-.7l.2-.8v-1.5l.2-.8v-.7l.2-.8v-1l.2-.7v-.7l.2-.8v-1.6l.2-.8v-.8l.2-.7v-1l.2-.7v-.8l.2-.8v-.8l.2-1v-.7l.3-.8.5-.4zm-.4.3v-.4h.5l-.4.5zm.5.6v-1z"/>
<path fill="#fff" d="M430.4 563.4h7.6c4.4 2 9 12.2 3.7 22a66 66 0 0 0-9.5 29.2c-7.4-6.8-10.8-14.7-8.2-23.3 3.4-11.7 6.8-25.2 6.4-28z"/>
<path fill="#21231e" d="M438 564h-7.6v-1h7.8zm0-1h.2zm4 22.5-.8-.5.5-1 .4-.8.4-.8.3-1 .3-.8.2-1v-.7l.3-1V574l-.2-1v-.6l-.3-.8-.2-.7-.3-.8-.2-.7-.3-.6-.3-.7-.3-.6-.3-.6-.3-.4-.3-.5-.4-.3-.4-.4-.3-.4-.4-.4-.5-.3-.4-.3-.3-.2.5-1 .4.4.5.2.5.4.4.4.4.4.4.4.4.5.4.6.3.6.3.6.3.6.3.7.2.7.3.7.2.6.2.8v.7l.3 1v.8l.2.8v3.5l-.2 1v1l-.4.8-.3 1-.3 1-.4.8-.4 1-.5 1zM432 615l.5-.7-.8.3v-.8l.2-1v-2.3l.3-1v-.7l.2-.8.2-1 .2-.8v-1l.2-.7.3-1 .2-.8.2-1 .2-.7.3-1 .3-.8.3-1 .4-1 .4-.8.4-1 .4-1 .4-1 .4-1 .5-1 .4-1 .5-1 .5-1 .5-1.2.6-1 .6-1.2 1 .5-.7 1-.6 1.2-.7 1-.5 1-.5 1.2-.5 1-.4 1-.5 1-.5.8-.4 1-.3 1-.3 1-.4.8-.3 1-.3.8-.2.8-.3 1-.4.8-.2.8-.2 1-.2.7-.2 1v.7l-.3.8v1l-.3.7v.8l-.2.8v1l-.2.7v1.8l-1 .2zm.7-.3v1l-.8-.7.7-.3zm-9.2-23.6 1 .4-.3.8-.2.8v.8l-.2.7v.8l-.2.8v3l.2.8.2.8v.7l.3.7.3.7.2.8.3.7.4.7.4.6.3.7.5.7.4.7.4.7.5.6.4.7.5.7.4.6.6.7.6.6.6.7.7.6.5.7-.6.7-.8-.6-.7-.7-.6-.7-.7-.6-.6-.7-.6-.7-.4-.7-.6-.7-.4-.7-.5-.8-.3-.7-.5-.7-.3-.8-.5-.7-.3-.7-.3-.8-.4-.7-.2-.7-.2-.8-.2-.7v-.8l-.2-.8v-.8l-.2-.8v-2.5l.2-.8v-.8l.3-.8.3-1 .2-.7zm7-28v1l.4-.7v1.8l-.2.5v1.1l-.2.7-.2.7v.8l-.3.8v.8l-.2 1-.2.8-.2 1-.3 1v1l-.4 1-.2 1-.3 1-.2 1-.2 1-.3 1.2-.3 1-.3 1.2-.3 1-.3 1.2-.3 1.2-.3 1-.3 1.2-.2 1-.4 1.2-1-.3.4-1 .3-1 .5-1.2.3-1 .3-1.2.4-1.2.3-1 .3-1.2.3-1 .3-1.2.3-1 .2-1 .2-1 .3-1.2.2-1 .2-1 .2-1 .2-.8.2-1 .2-.8.2-.8v-.8l.3-.7v-.8l.2-.7v-.6l.2-.6v-2l.4-.6zm-.6.5v-.6h.4l-.5.5zm.4 0v-.6.4zm-.5 0v-.6h.4l-.5.5z"/>
<path fill="#fff" d="m433.8 558.2-12-4.3q-6.5 15-8.4 20.5-3.4 11-1 19.6a21 21 0 0 0 14-11.6c3.3-7.3 4.5-16.3 7.4-24.2"/>
<path fill="#21231e" d="m422 553.4 12 4.3-.4 1-12-4.4-.3-.6zm-.7.3.2-.4h.4l-.7.4zm-7.4 21-1-.3v-.4l.2-.4v-.4l.3-.4v-.4l.3-.5.2-.5v-.5l.3-.5.2-.5.2-.6.3-.6.2-.5.2-.6.3-.6.2-.6.2-.6.3-.7.3-.6.3-.7.4-.7.3-.8.3-.8.3-.7.4-.8.3-1 .4-.8.3-1 .4-.8.5-1 .4-.8.3-1 1 .5-.5 1-.4 1-.4.8-.3 1-.4.8-.4.8-.4.8-.3.8-.4.8-.4.8-.3.7-.3.8-.3.8-.3.7-.3.6v.8l-.4.6-.2.6-.3.6v.6l-.3.6-.2.5-.2.5-.2.5v.5l-.3.5-.2.4v.5l-.3.4v.3l-.2.3v.4zm-1.8 19 .3 1-.6-.4-.3-.6v-.5l-.2-.6v-.5l-.2-.5v-.6l-.2-.7V583l.2-.7V581l.3-.6v-.7l.2-.6v-.6l.3-.6.2-.7v-.6l.3-.7.2-.6.2-.6 1 .3-.3.6-.2.7-.2.7-.2.6v.7l-.2.6v.7l-.2.6-.2.6v.6l-.2.6v1l-.2.7v6.5l.2.6v1.1l.2.4.2.6v.5l.2.5zm.3 1h-.5v-.4l.5.3zM426 582l.8.6-.3.6-.4.7-.2.5-.4.6-.4.7-.4.6-.4.5-.4.5-.4.5-.5.5-.5.5-.5.4-.4.4-.5.4-.4.4-.4.4-.5.3-.5.5-.5.3-.5.3-.5.4-.4.2-.5.3h-.5l-.5.4-.5.2-.5.2-.5.2h-.4l-.6.3-.4.2h-.5l-.3-.8.4-.2h.5l.5-.3.5-.2h.4l.5-.3.4-.2.4-.3.5-.2.5-.2.5-.3.4-.3.5-.3.5-.4.4-.3.6-.3.4-.4.5-.3.4-.4.4-.5.4-.4.4-.4.4-.4.4-.5.4-.5.4-.5.4-.5.4-.6.3-.6.3-.6.3-.6.3-.7zm7.6-23.4.4-1 .3.7-.3.8-.3.8-.2.8-.3.7-.2.8-.2 1-.2.6-.2.8-.3.8v.8l-.3.7-.2.8-.2.8-.2.8v1l-.3.6-.2.8-.2.8-.2.8v.7l-.3.8-.2.8-.3.7-.2.8-.2.7-.3.8-.3.7-.2.7-.3.8-.3.7-.3.7-.2.6-1-.5.4-.5.3-.7.3-.7.3-.6.3-.7.3-.8.2-.8.2-.7.3-.8.2-.7.2-.8.2-.7v-.8l.4-.8.2-.8.2-.8.2-.8.2-.8.2-.7.2-.7.2-.8.2-.8.2-.8.2-1 .2-.6.2-.8.3-.8.3-.8.2-.7.3-.8.3-.8.3-.7.3.6zm.4-1 .4.3v.3zm-.2.6-.2.4zm.2-.5.4.2v.3l-.4-.6z"/>
<path fill="#fff" d="m425.6 549.7-2.6-16.4c-2.8-.7-6.5 5.8-10 9.5q-1.6 1.3-2.6 2.8a23 23 0 0 0-3.4 8 62 62 0 0 1-13 27.6c10.2-.2 18-3.8 21.8-12 5-11 7.7-17.7 9.8-19.5"/>
<path fill="#21231e" d="m423.4 533.3 2.7 16.4h-1l-2.5-16.3.6-.6.4.5zm-.3-.4h.4v.2l-.3-.4zm-9.7 10.2-.8-.7.4-.4.2-.2.3-.4.4-.4.2-.4.3-.4.4-.4.2-.5.3-.4.4-.5.2-.4.3-.3.4-.5.2-.4.3-.4.4-.3.2-.3.3-.4.3-.3.4-.3.3-.4.3-.2.3-.2.4-.2.4-.3h.3l.4-.3h.3l.4-.2h1.1l-.2 1h-1l-.3.2-.2.2-.3.2-.3.2-.3.2-.3.3v.4l-.5.3-.3.3-.3.3-.4.4-.3.4-.3.5-.4.4-.3.3-.3.4-.3.4-.4.5-.3.5-.3.4-.4.4-.3.4-.4.4-.3.4-.4.4-.4.4-.3.4zm-2.5 2.7-.8-.7v-.2h.2l.2-.2v-.2h.2v-.2h.2v-.2h.2v-.2h.2v-.2l.2-.2h.2v-.2l.2-.2h.2v-.2h.2v-.2h.2v-.2l1 .6h-.2l-.2.2v.2h-.2v.2h-.2l-.2.2v.2h-.2l-.2.2v.2h-.2v.2h-.2v.2h-.2v.2h-.2v.2l-.2.2v.2zm-3.3 7.7-1-.2v-.6l.2-.4v-.3l.2-.3v-.8l.2-.3v-.3l.2-.3v-.3h.2v-.4l.2-.3v-.2l.2-.2v-.2l.3-.3v-.2l.2-.2v-.2l.3-.2v-.3h.2v-.3l.3-.3v-.2l.3-.2v-.2l.2-.3.2-.2.8.6-.3.3v.2l-.2.2-.2.2v.4l-.2.2-.2.2v.3l-.2.3v.2l-.2.3-.2.2v.2l-.2.3v.2l-.2.3v.2l-.2.3v.2l-.2.3v.5l-.2.3v.2l-.2.3v.5l-.2.3v.7zm-13.4 27v1l-.3-.8.5-.8.5-.7.5-.6.5-.8.5-.7.5-.7.4-.6.6-.7.4-.7.5-.8.4-.7.4-.7.4-.8.4-.7.4-.7.4-.8.4-.8.4-.8.4-1 .4-1 .3-.8.3-1 .3-.8.4-1 .3-1 .4-1 .3-1 .3-1.2.3-1 .3-1.3.2-1.3.3-1.2 1 .2-.3 1.2-.3 1-.4 1.3-.3 1.2-.4 1-.4 1-.3 1.2-.4 1-.4 1-.4 1-.3 1-.5.8-.4 1-.3.8-.4.8-.4 1-.5.8-.4.8-.3.7-.5.8-.4.8-.5.8-.4.7-.6.7-.5.7-.5.7-.5.7-.5.8-.5.7-.5.6-.5.8-.5.7-.4-.8zm0 1h-1l.7-.8zm21.3-12.8 1 .4-.5.7-.4 1-.4.6-.4.7-.5.7-.4.6-.5.6-.5.6-.5.6-.6.5-.6.4-.6.5-.7.4-.6.4-.8.4-.7.4-.7.4-.7.3-.7.3-.8.3-.8.2-.8.2-1 .2-.7.2-1 .2-.7.2h-1l-.8.2h-1l-.8.2h-2v-1h2.8l1-.2h.8l.8-.2 1-.2h.7l1-.3.7-.2.7-.3.8-.2.7-.3.7-.3.7-.3.6-.3.7-.3.6-.4.7-.5.6-.4.6-.4.5-.4.6-.6.5-.5.5-.4.5-.6.5-.6.4-.7.5-.6.4-.6.3-.7.3-.8zm9.8-19.2h1v.3l-.3.3v.2l-.3.2-.2.2-.2.2-.2.3-.3.4-.2.2-.2.4v.4l-.4.5-.2.5-.3.5-.2.5-.3.6-.2.6-.3.6-.3.6-.4.7-.3.8-.3.8-.4.7-.3.8-.4 1-.4.7-.4 1-.4.8-.4 1-.4 1-.5.8-.3 1-.5 1-1-.4.6-1 .4-1 .5-1 .4-1 .5-1 .4-.8.3-1 .4-.7.4-.8.4-.8.4-1 .3-.6.4-.7.4-.7.3-.6.4-.7.3-.6.2-.4.2-.6.3-.5.2-.5.3-.4.2-.5.3-.3.2-.4.2-.3.2-.4.2-.3.2-.3.2-.2.3-.2.3-.2-.2.4zm1 0v.3z"/>
</g>
<use xlink:href="#rs-d" width="1350" height="900" transform="matrix(-1 0 0 1 964.3 0)"/>
<path fill="#fff" stroke="#21231e" d="m536.4 415 4.8-1.5a66 66 0 0 1-21.4-22c-7.8-12 3.3-33 8-44.3a53 53 0 0 0 21.2-31c1-7.3-19-4.7-33 2-17 8-19.3 5.7-25.4 7-2.2 10.5 2.4 11.4 6.7 11-9.4 15-13.3 29.8-15 51.4-2-21.6-6-36.5-15.3-51.5 4.3.6 9-.3 6.7-10.7-6-1.4-8.4.8-25.4-7.2-14-6.5-34-9-33-1.8 3 13.7 11.8 24 21.3 31 4.6 11.2 15.7 32.4 8 44.2a67 67 0 0 1-21.5 22q2.5 1 5 1.5c-1.2 1.5-11 4.5-12.3 3.7-7.6-5.3-15-18-21.4-25.2-18.2-20.8-27.3-36.7-24-49.6 4.5-14 20.8-29.6-.8-27-21.7 2.8-39.6 32.5-45.4 68.3l-4.7 33.5c11.8-4.3 17-8.5 20.2-13.7q-2.1 7.5-3.2 14.2c9.7-1.7 16.7-6.4 19.2-15q1.6-5.3 3.6-9c3 1 7 1 11.6 0 1.7 4 15 19 22.2 30 8 12.2 20.2 21.6 24.2 22 2 .4 2.7-4 2.2-10.2 21 .2 42.3.3 63-.4q31.1.9 63 .4c-.6 6 0 10.6 2 10.3 4-.5 16.2-10 24.3-22.2 7-10.8 20.5-25.7 22.2-30a20 20 0 0 0 11.6.2q2 3.7 3.5 9c2.5 8.6 9.5 13.3 19.2 15q-1-6.6-3.2-14c3.2 5 8.4 9.3 20.2 13.6-1.4-9-2.7-20.3-4.8-33.5-5.8-35.8-23.7-65.5-45.4-68.2-21.6-2.6-5.3 13-.7 27 3.3 12.8-5.8 28.7-24 49.5-6.5 7.3-13.8 20-21.4 25.2-1.2.8-11-2.2-12.2-3.8z"/>
<g id="rs-e">
<path fill="#edb92e" d="M440.6 356.8c-2 1.8-8.8 1.8-18 2.4q-22.3.7-25.3-13.5c5.6 6.6 12.2 10 19.7 8 10.2-2.5 16-4.3 18.3-3.8 1.6.4 4 3.3 5.3 6.8z"/>
<path fill="#21231e" d="M422.6 359.7v-1h1.8l.7-.2h2.5l.8-.2h2.8l.8-.2h3l.5-.2h1l.4-.2h.5l.4-.2h.4l.5-.2h.3l.3-.2h.4l.3-.2h.2v-.3h.3l.6.7h-.3l-.3.3-.3.2h-.2l-.3.3h-.4l-.3.2h-.4l-.4.2h-.5l-.5.2h-1l-.5.2h-1.5l-.6.2H432l-.6.2h-2.8l-.8.2h-2.3l-1 .2H423zm-25-14.3-.7.6.8-.4.2 1 .2.7.3.8.3 1 .3.6.5.7.4.7.4.6.5.6.4.6.6.6.6.5.6.4.7.5.6.3.8.5.8.4.8.3 1 .4.8.2 1 .3 1 .2 1 .2h1l1 .3h1.2l1.2.3h6.6v1H416l-1-.2h-1.3l-1-.3h-1.2l-1-.3-1-.3-1-.3-1-.2-1-.4-.8-.3-.8-.4-1-.4-.7-.5-.7-.5-.7-.5-.7-.6-.6-.5-.6-.6-.4-.8-.5-.7-.3-.7-.4-.8-.4-.7-.4-1-.3-.7-.3-1-.2-.8 1-.4zm19.3 8 .2 1h-.8l-.7.2h-1.4l-.7.2h-2.8l-.6-.2-.7-.2h-.7l-.6-.3h-.7l-.6-.3-.8-.3-.6-.3-.6-.2-.6-.3-.6-.4-.6-.3-.6-.4-.6-.4-.6-.6-.6-.4-.6-.5-.5-.6-.6-.6-.4-.6-.6-.5-.5-.6-.6-.7.7-.6.5.6.5.6.6.6.5.5.5.5.6.5.4.5.6.5.6.4.5.5.7.4.6.3.6.3.4.3.6.2.6.3.6.2.7.2h.5l.6.3.7.2h.6l.7.2h4.7l.6-.3h.7zm18.5-4-.3 1h-2.6l-.4.2h-.9l-.5.2-.5.2h-.5l-.6.2h-.5l-.6.3h-.5l-.7.3-.7.2h-.6l-.7.3-.7.2-.8.2-.8.2h-.8l-.8.3-1 .3-.8.2-1 .2-.8.3-.3-1 1-.2.8-.2 1-.2.7-.2 1-.2.7-.2.8-.2.7-.2.8-.2.7-.2.7-.2.6-.2h.6l.6-.3h.6l.6-.3h.6l.5-.2h.6l.5-.2h.6l.4-.2h.9l.3-.2zm5.4 7.8-.7-.8-.2.6v-.7l-.3-.3v-.3l-.3-.3v-.3l-.3-.2v-.3l-.2-.2-.2-.3v-.3l-.3-.2-.2-.3v-.2l-.2-.2-.2-.3v-.2l-.3-.2h-.2v-.3h-.2l-.2-.3v-.2h-.3l-.2-.2v-.2h-.2v-.2h-.4v-.2h-.2l.3-1h.2l.2.2.2.2h.2l.2.2.2.2h.2v.3l.3.2.2.2h.2l.2.3v.2l.2.2.2.2.2.2.2.2.2.3v.2l.3.2.2.3.2.3v.3l.3.4.2.3v.3l.3.3v.3l.3.3v.3l.2.3v.6zm0-.6.2.3-.3.2v-.6zm-21.5-35.4v1.5h-.4v-.4h-.2v-.7l.2-.2h.2v-.2zm15.3 4-.5 1.3-.6-.2-.5-.2h-.6l-.5-.2-.4-.2-.5-.2-.4-.2-.5-.2-.4-.2h-.5l-.4-.3-.5-.2h-.4l-.4-.3h-.5l-.4-.3h-.5l-.4-.2h-.4l-.5-.2h-.4l-.3-.2h-1.3l-.4-.2H420v-2h2.9l.5.2h1l.4.2h.5l.3.2.5.2h.5l.4.2.5.2h.5l.4.3h.6l.5.3.6.2h.5l.6.3.5.2.6.2h.5l.6.3.6.2.5.2.6.2h.5zm9 2.5v1.5H442l-.3-.2h-.4l-.3-.2h-.3l-.4-.2h-.3l-.4-.2h-.4l-.3-.2h-.5l-.3-.2-.4-.2h-.3l-.4-.2h-.2l-.3-.2h-.3l-.3-.3h-.7l-.2-.2h-.4l-.2-.2.4-1.5h.2l.2.2h.2l.2.2h.3v.2h.4l.3.2h.3l.3.2h.4l.3.2.3.2h.4l.3.2h.4l.3.2h.4l.4.2h.3l.4.2h.4l.3.2h.6l.3.2zm0 1.5v-1.5h.4v.2h.2v.2h.2v.9h-.2v.2h-.2v.2h-.2zm23.4 7.5.2-1.2h.2v.2h.2v.8h-.6zm-10-2 .4-1.2h.5l.3.2h.4l.3.2h1.1l.2.2h.6l.2.2h.6l.3.2h.7l.4.2h.8l.3.2h.9l.2.2h.9l.5.2h.8l-.2 1.3h-.9l-.4-.2h-.6l-.4-.2h-.7l-.4-.2h-1.4l-.3-.2h-.7l-.3-.2h-.6l-.3-.2h-.5l-.4-.2h-.5l-.3-.2h-.5l-.2-.2h-.5l-.2-.2zm.4-1.2-.3 1h-.2v-.8h.8z"/>
<path fill="#21231e" d="m431.5 332-.7 1.3-.4-.3-.4-.2-.4-.3-.3-.2-.4-.3-.4-.3-.3-.3-.4-.3-.4-.2-.3-.4-.3-.3-.2-.3-.3-.3-.3-.4-.2-.3-.3-.4-.2-.3-.3-.4-.2-.4-.2-.3-.3-.5-.2-.4-.2-.2v-.4l-.3-.4-.2-.3-.2-.4-.2-.3v-.4l-.2-.3-.2-.3-.2-.4 1.4-.7.2.2.2.4v.3l.3.2.2.4.2.3v.3l.3.3.2.4.2.3.2.4v.3l.3.4.3.3.2.4.2.4.2.4.3.3.2.4.3.4.2.3.3.4.3.3.3.3.3.2.3.3.3.3.2.2.4.3.3.2.2.2.3.2zm7.6-5.3 1.5.8-.2.4-.2.3-.2.4-.2.4-.3.5-.3.4-.2.2-.3.4-.3.3-.3.2-.3.3-.3.3-.3.3-.2.4-.3.2-.3.2-.4.2-.3.2-.3.2h-.3l-.5.2h-.3l-.3.2h-2.2l-.4-.2-.3-.2h-.2l.7-1.5h.5l.2.2h1.7l.3-.2h.2l.3-.2h.2l.3-.3.2-.2.3-.2h.2l.3-.3.2-.3.3-.2.2-.3.3-.4.2-.3.3-.3.2-.4.2-.3.3-.4.2-.5.2-.4v-.3z"/>
<path fill="#21231e" d="m429.6 331-2.2-2.3q-1.6-1.9 2-5.4l4.2 2q-1.4 4.5-4 5.6zm-6.3 82-.4 1h-.4v-1zm23.8-3.6 1 1-.7.5-.6.4-.7.5-.6.4-.7.5-.7.3-.7.4-.7.4-.7.4-1 .3-.6.3-.8.2-.7.2-1 .2-.7.2h-.8l-.8.2h-5l-1-.2h-.8l-.8-.3h-1l-.8-.4h-1l-.7-.3-1-.3-.8-.3.3-1 .8.2 1 .3 1 .3.7.2 1 .2.7.2h.8l1 .2h.7l.7.2h4.8l.7-.2h1l.6-.3.7-.2h.7l.7-.4.7-.3.7-.3.8-.3.6-.4.7-.4.7-.5.6-.5.6-.5.5-.5zm3-2.8 1 .8h-.2v.2h-.2l-.2.2v.2h-.2v.2h-.2v.2h-.2l-.2.2-.2.2v.2h-.2v.2h-.2l-.2.2-.2.2-.2.2-.2.2v.2h-.2l-1-.8h.2v-.2h.2v-.2h.2l.2-.2.2-.2.2-.2v-.2h.2v-.2h.2l.2-.2.2-.2.2-.2v-.2h.2l.2-.2.2-.2v-.2zm1 .8-1-.8.2-.2h.7v.2h.2z"/>
<path fill="#21231e" d="m452.2 401.3-1.2-.2v-.2h.2l.2-.2h.6v.4h.2zm-5.5 16 .3 1-.7-.8.2-.4.2-.4.2-.5v-.4l.3-.4.2-.5.2-.5v-.5l.3-.4.2-.5.2-.5v-.5l.3-.5v-.5l.3-.5v-.5l.3-.5v-.5l.3-.5v-.5l.2-.5.2-.6v-.5l.2-.6v-.5l.2-.4v-.6l.2-.6v-.5l.2-.7v-.6l.2-.6 1.2.3v.6l-.2.5v.6l-.2.6v.6l-.2.6v.5l-.2.6-.2.4v.6l-.2.5v.6l-.3.6v.5l-.3.6v.6l-.3.5v.5l-.2.5-.2.5v.5l-.3.5-.2.5v.5l-.2.4-.2.5-.2.6-.2.5-.2.6-.2.5-.2.5-.2.5-.7-.8zm-.4.2 1 .5v.2h-.2v.2h-.4l-.2-.2v-.2h-.2v-.4zm15.2-9.5 1 .7-.3.4-.4.6-.3.4-.4.4-.2.4-.4.4-.4.4-.4.4-.4.3-.4.4-.5.3-.4.4-.6.3-.4.3-.5.3-.5.3-.5.3-.5.2-.5.3-.5.3-.6.2-.5.3-.7.2-.5.3-.6.2-.6.2-.6.2-.6.2-.6.2-.6.2-.6.2-.6.2-.3-1.2.6-.2h.6l.5-.3.6-.2.6-.2.6-.2h.6l.5-.3.6-.3.4-.2.5-.2.4-.3.5-.2.4-.3.5-.3.4-.4.5-.3.3-.3.5-.3.4-.3.4-.3.4-.2.4-.4.4-.3.4-.3.4-.3.3-.4.3-.4.3-.4.3-.4.2-.4.3-.4zm1 .7-1-.7h.2v-.2h.7v.2h.2z"/>
<path fill="#21231e" d="M461.3 400.2H460v-.2h.2v-.2h1v.4zm4.4 15.7.7 1-.8-.3-.3-.4-.3-.4-.2-.5-.3-.5-.2-.4-.3-.4-.2-.5-.3-.5-.2-.4-.2-.5v-.5l-.3-.5-.2-.5-.2-.5-.2-.5v-.5l-.2-.5-.2-.5v-.6l-.3-.5v-.5l-.3-.6v-.4l-.2-.6v-.6l-.2-.5v-.7l-.2-.6v-.6l-.2-.5v-1.2h1v.5l.2.6v.6l.2.5v1.4l.2.5.2.6v.5l.2.5v.6l.3.5v.4l.2.5.2.4v.5l.2.4.2.5.2.4.2.5.2.4.2.4.2.5.2.4.2.5.3.4.3.4.2.4.3.5.2.3.3.4.3.3h-1zm0 .7 1-.7v.8l-.2.2h-.2v.2h-.4v-.2h-.2zm7.6-12.6 1 .4v.6l-.2.5v.5l-.2.5-.2.5-.2.5-.2.5-.2.5-.2.4-.2.4-.2.4-.3.5v.4l-.4.4-.2.5-.3.4v.3l-.4.3-.3.4-.3.4-.2.3-.3.3-.3.4-.3.3-.4.3-.3.3-.3.3-.3.2-.3.3-.3.4-.3.2-.3.3-.7-1 .3-.3.3-.2.3-.3.3-.2.2-.3.3-.3.2-.2.3-.3.3-.4.3-.3.2-.4.3-.4.4-.3.2-.4.3-.4v-.4l.4-.3.2-.5.3-.4v-.3l.3-.4.2-.4.2-.6.2-.4v-.5l.3-.4.2-.4.2-.5v-.4l.3-.5v-.4zm1 .4-1-.3v-.2h.8v.2h.2z"/>
<path fill="#edb92e" d="M406 317.8c-16.7 1.8-16 12.6-.4 28 3 3 4 3 4.6-.2 1.2-5.3 7-8.5 10.2-4.4 2 2.7 1.6 4.3 8.6 3.3 9 7.5 16.2 12.8 4.5 12.3-5-.2-9 2.8-15.7 2.5 2 4 2.3 4.3 3.4 4.6 6.5 1.2 13.3-2.8 19.8-1.6 14.3 2.6-23-38.6-22.4-40.3 1-4-9-11.5-12.7-4.2z"/>
<path fill="#21231e" d="m406 345.5-.7.7-1.4-1.5-1.5-1.4-1.2-1.4-1.2-1.4-1-1.3-1-1.3-.8-1.3-.8-1.2-.8-1.2-.6-1.2-.5-1-.5-1.2-.3-1-.3-1v-1l-.2-1v-1l.2-1 .2-.8.4-.8.4-.8.6-.7.6-.7.8-.6.8-.6 1-.5 1-.5 1-.4 1.4-.4 1.3-.3 1.3-.2 1.6-.2v1l-1.5.2-1.4.2-1.2.3-1.2.3-1 .4-1 .5-1 .4-.6.5-.7.7-.6.6-.4.6-.4.6-.4.7-.2.8-.2 1v1.7l.2.8.2 1 .4 1 .4 1 .5 1 .5 1.3.7 1 .8 1.3 1 1.4.8 1.2 1 1.3 1.2 1.3 1.2 1.3 1.4 1.4 1.4 1.5zm3.8 0 1 .2v.3l-.2.3v.5l-.2.2v.2l-.2.2v.2l-.2.2-.3.3v.2h-.3l-.2.2H408l-.2-.2h-.2l-.2-.2h-.2l-.2-.3-.2-.2h-.2l-.3-.4h-.2l-.2-.3-.3-.3-.2-.2.7-.7.2.2.3.3.2.2.3.2.2.2.2.2h.2l.2.2.2.2h.3v.2h.6l.2-.2v-.2l.2-.2v-.2l.2-.4v-.4l.2-.3zm11-4.6-.8.5-.3-.4h-.3l-.3-.4-.2-.2-.3-.2h-.3l-.3-.2h-.5l-.3-.2h-1.5l-.3.2-.4.2h-.2l-.4.3-.3.2-.2.2-.4.2-.3.2-.2.3-.3.3-.2.4-.3.3-.2.4-.3.5-.2.4-.2.3v.5l-.2.4v.5l-1-.2v-.5l.2-.5.2-.5.2-.5.3-.5.2-.4.2-.4.3-.4.3-.4.3-.4.4-.3.4-.3.4-.3.4-.2.3-.2.3-.2.5-.2h.4l.4-.2h.4l.4-.2h1l.4.2h.6l.4.3.4.3.3.2.4.3.4.5.4.4zm8.6 3.2-.7.7h.4-.5l-.6.2h-4.5l-.2-.2h-.3l-.2-.2h-.2l-.2-.2-.2-.2-.2-.2h-.2v-.3l-.3-.3v-.2l-.3-.2v-.2h-.3l-.2-.3-.2-.3v-.2l-.3-.2v-.3l-.3-.2.8-.6h.2v.4l.3.2.2.3.3.3v.2l.2.2.2.2.2.2.2.2.2.2h.2v.2h.3l.2.2h.2l.2.2h5.4zm-.4 0 .2-.2.2.2zm4.5 13v-1h4.1l.5-.2h.4l.3-.3h.2v-1l-.2-.3-.2-.4-.3-.5-.4-.4-.5-.4-.4-.4-.4-.5-.6-.5-.6-.6-.6-.6-.7-.5-.6-.6-.7-.7-.7-.7-.8-.6-.8-.7-.8-.7-1-.7.8-.8.8.7.8.5.8.7.8.7.7.5.8.6.8.7.7.6.6.6.7.4.6.6.5.5.5.5.4.5.4.4.4.4.3.4.2.4v2.3l-.4.3-.3.2-.4.3-.6.2h-.6l-.7.2h-3.6zm-15.2 2-1 .4.5-.8h3.4l.6-.2h.5l.5-.2h.5l.5-.2h.5l.4-.2h.5l.5-.2.4-.2h.6l.4-.2.5-.2h.4l.4-.2h.5l.3-.2h.5l.4-.2h.5l.5-.2h2.6v1H431l-.4.2h-.9l-.4.3h-.8l-.4.2h-.5l-.4.3h-.6l-.5.2h-.5l-.5.3h-.5l-.5.2h-.5l-.5.2h-.5l-.6.2h-.6l-.6.2h-3l.5-.7zm-1 .4-.3-.8h.8l-.4.8zm4 4-.2.8h-.4v-.2h-.2l-.2-.2h-.2v-.2h-.2v-.2h-.2v-.2l-.2-.3-.2-.2-.3-.3-.2-.2v-.2h-.2v-.4l-.3-.2v-.3h-.3v-.4l-.3-.3v-.4l-.3-.4 1-.5v.5l.2.3.2.3v.4l.3.3.2.2v.2l.3.2v.2l.2.2v.2h.2v.3l.2.2v.2l.2.2h.2v.2h.4v.2h.4zm19.8-1.7v1l-.7-.2h-4.7l-.6.2h-.7l-.6.2h-.7l-.6.2-.6.2h-.6l-.6.2h-.7l-.7.3-.6.2h-.6l-.6.2h-.6l-.6.2h-4.6l-.6-.2.3-1 .6.2h4.8l.6-.2h.6l.5-.2h.6l.7-.2.7-.2h.6l.6-.2.6-.2h.7l.5-.2h.6l.7-.2h.7l.6-.2h4.9zm-23-40 1 .3.3.3.5.7.6.8.8 1.2 1 1.2 1 1.3 1 1.5 1.3 1.5 1.3 1.7 1.4 1.8 1.4 1.8 1.5 1.8 1.5 2 1.5 1.8 1.4 2 1.4 2 1.3 1.7 1.3 2 1.2 1.7 1 1.7 1 1.6.8 1.5.6 1.4.4 1.3.3 1.2v2l-.6.7-.8.5H441v-1h2l.4-.3.3-.4V360l-.3-1.2-.4-1.2-.6-1.3-.8-1.5-1-1.6-1-1.7-1-1.8-1.3-1.8-1.4-2-1.4-2-1.4-1.8-1.5-2-1.4-1.8-1.5-1.8-1.4-1.8-1.3-1.8-1.3-1.6-1.2-1.6-1-1.5-1.2-1.3-1-1.2-.7-1-.6-1-.5-.7-.3-.4v-.6zm-12-3.7v-1l-.5.2.4-.6.3-.7.5-.6.5-.4.5-.3.6-.3.5-.2.5-.2h2.6l.6.2.6.2.5.3.6.2.6.3.4.4.5.2.4.4.4.4.5.5.4.4.3.4.3.4.3.5.2.5.2.5v.5l.2.5v1l-1-.3v-1l-.2-.4v-.4l-.3-.4-.2-.4-.3-.4-.3-.4-.5-.4-.3-.4-.5-.4-.4-.4-.5-.3-.4-.3-.5-.3h-.7l-.5-.3-.5-.2h-.5l-.6-.2h-2l-.4.3-.5.2-.4.3-.5.5-.4.4-.3.4-.3.6-.4.3zm.4-.3-.2.2h-.2zm-.5-.2v.5zm.4.2-.2.2h-.2z"/>
<path fill="#21231e" d="m407 317.2-1.3.4v-.6h.2v-.2h.8v.2h.2v.2zm7.6 10.6-.8 1-.4-.4-.3-.4-.3-.3-.3-.3-.4-.3-.3-.2-.3-.4-.3-.3-.2-.2-.3-.4-.3-.3-.3-.2-.4-.4-.3-.3-.2-.2-.2-.4-.2-.3-.3-.3-.2-.3v-.4l-.4-.3-.2-.4-.2-.4-.2-.4-.2-.4v-.4l-.3-.3-.2-.4v-.3l-.3-.3v-.4l-.3-.4 1.2-.4v.7l.3.3v.3l.3.4v.3l.3.4v.3l.3.4.2.3.2.3.2.4v.3l.3.3.2.4.3.3.2.3.3.4.2.3.3.3.3.3.4.4.2.3.3.3.2.3.3.3.4.2.2.3.3.3.4.4.2.3.4.3zm-.8 1 .8-1v.2h.2v.7h-.4v.2zm-9.5-4.6q1.3.1 1.2 1.5c-.1 1.4-.8 1.3-1.5 1.2q-1.3-.4-1.2-1.6c.1-1.2.8-1.3 1.5-1.2zm-45.9 38.4h.2v-.2h.4v.2h.2v.2l.2.2v.4h-.2zm-22.7 56 .2-1V416l.4-1.5.3-1.5.4-1.7.6-1.8.5-2 .7-2 .6-2 .6-2 .6-2.2.8-2.2.7-2.2 1-2 .7-2.3 1-2.3.7-2.2 1-2.2.8-2 1-2.2.8-2 1-2 .8-2 1-1.7.8-1.5 1-1.6.7-1.5 1-1.3.7-1.2.8-1 .8-.8.8-.6.7 1-.6.5-.7.8-.7 1-.8 1-1 1.3-.7 1.5-1 1.5-.7 1.7-1 1.7-.8 2-1 1.8-.8 2-1 2-.8 2.3-1 2-.7 2.3-1 2.3-.7 2.3-.8 2.2-.7 2.2-.8 2.2-.6 2-.6 2-.6 2.2-.6 2-.5 1.8-.4 1.8-.4 1.6-.5 1.6-.2 1.4-.2 1.3v1H336zm5.6 80.5-.7-2-.7-2-.7-2.2-.6-2.2-.6-2.2-.4-2.4-.4-2.3-.5-2.4-.4-2.5-.3-2.4-.3-2.5-.3-2.7-.2-2.6-.3-2.6-.2-2.5-.2-2.6v-3l-.2-2.7v-18.5l.3-2.7v-2.5l.2-2.6v-2.7l.3-2.6.2-2.5.2-2.5h1.2l-.3 2.6-.2 2.5-.2 2.6-.2 2.6v2.6l-.2 2.6v2.6l-.2 2.7v18.8l.2 2.6v2.6l.3 2.6.3 2.6.3 2.6.3 2.5.2 2.5.3 2.5.4 2.4.3 2.5.5 2.3.5 2.3.5 2.3.6 2.2.6 2 .7 2.2.7 2-1 .4zm1-.4v.8h-.8v-.2l1-.6z"/>
</g>
<use xlink:href="#rs-e" width="1350" height="900" transform="matrix(-1 0 0 1 964.3 0)"/>
<path fill="#21231e" d="M473 398.4h-.2v.5h-.2v.8l.2.7v1.6l.2.8.2.8v.7l.3.8v.8l.3.7.2.8.3.7.2.7.2.7.3.7.3.8.3.7.3.7.2.7.3.6.4.6.2.7.4.5.4.7.4.7.4.5.5.6.4.8.5.6.4.6.5.6.6.6.2.2h.8v-.2l.6-.6.5-.6.5-.6.4-.6.5-.7.5-.5.4-.6.3-.8.4-.6.3-.7.4-.8.4-.6.3-.7.4-.8.3-.7.3-.7.3-.7.3-.6.2-.7.3-.7.3-.7.2-.8v-.7l.3-.7.2-.7v-.7l.3-.8v-1.4l.2-.8v-2.1h-1v.4l-.2 1v1.4l-.2.7v.7l-.2.7-.2.7v.8l-.3.7-.2.7-.2.7v.6l-.3.7-.3.7-.2.7-.3.7-.4.6-.2.7-.4.7-.3.6-.3.7-.4.6-.4.7-.3.6-.4.6-.5.6-.4.6-.4.7-.4.7-.4.6-.5.6h-.2l-.5-.7-.4-.6-.4-.6-.4-.6-.4-.6-.4-.6-.4-.6-.4-.6-.3-.7-.4-.6-.4-.7-.3-.6-.3-.7-.4-.7-.2-.6-.3-.7-.2-.7-.2-.7-.2-.7-.2-.7-.2-.8-.2-.7-.2-.7v-.7l-.3-.6v-.8l-.2-.7v-2.3l-.2-.8v-.4h-.2v-.2h-.5z"/>
</g>
<g transform="translate(-32 32)scale(.53333)">
<path fill="#c6363c" d="M549.2 422v108.6a72 72 0 0 1-19.7 49.8 65 65 0 0 1-94.7.1 73 73 0 0 1-19.7-49.8V422z"/>
<use xlink:href="#rs-f" width="1350" height="900" transform="matrix(-1 0 0 1 964.3 -90)"/>
<path fill="#fff" stroke="#21231e" d="M549.2 488.6v28h-53v83a64 64 0 0 1-14 1.5 59 59 0 0 1-14-1.5v-83h-53v-28h53V422h28v66.6z"/>
<use xlink:href="#rs-f" width="1350" height="900" transform="translate(0 -90)"/>
<path id="rs-f" fill="#fff" stroke="#21231e" d="M459 567.3V528c-8.4-2.3-29.3-10.6-30.3 7.6-.5 8.4 10.4 14 13.3 6.5 1.4-3.4 0-6-2-6.7-2.4-.8-4.6 1-4 3.6-8.8-4.7 8-14.6 15.5-1.7 2.2 3.7-3.7 7.6-3.7 10.4 0 2.7 5.8 7 3.7 10.3-7.7 12.8-24.3 3-15.5-1.6-.6 2.7 1.6 4.5 4 3.6 2-.8 3.4-3.3 2-6.8-3-7.5-13.8-2-13.3 6.5 1 18.2 22 10 30.4 7.6z"/>
<use xlink:href="#rs-f" width="1350" height="900" transform="matrix(-1 0 0 1 964.3 0)"/>
<path fill="#21231e" d="M414 421v113.3l.2 1.7v2l.4 1.7.2 1.8.3 1.7.4 1.8.3 1.8.4 1.7.6 1.7.5 1.7.6 1.5.6 1.7.5 1.6.7 1.6.7 1.6.7 1.6.8 1.6.8 1.5.8 1.5 1 1.5.8 1.5 1 1.4.8 1.4 1 1.4 1 1.4 1 1.3 1 1.5 1.2 1.2 1 1.3 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1 1.3 1.3 1 1 1.4 1 1.3 1 1.4 1 1.5 1 1.4 1 1.3.8 1.4.8 1.5.8 1.4.8 1.6.7 1.5.6 1.5.7 1.5.6 1.6.5 1.6.5 1.5.5 1.6.5 1.8.4 1.6.4 1.7.4 1.8.2 1.7.3 1.7.2h1.7l1.6.2h8.9l1.7-.3 1.8-.3 1.7-.3 1.7-.2 1.7-.4 1.5-.4 1.7-.4 1.6-.5 1.6-.5 1.6-.5 1.5-.6 1.6-.7 1.6-.7 1.6-.7 1.5-.8 1.4-.8 1.6-.8 1.4-1 1.5-.7 1.4-1 1.2-1 1.4-1 1.3-1 1.2-1 1.3-1 1.2-1.3 1.2-1 1-1.3 1.3-1.2 1.2-1.2 1-1.3 1.2-1.2 1-1.4 1-1.2 1-1.4 1-1.4 1-1.4 1-1.4.7-1.5 1-1.5.7-1.5.8-1.5.8-1.6.7-1.6.6-1.6.6-1.6.6-1.6.5-1.7.5-1.6.5-1.8.4-1.7.6-1.7.3-1.8.2-1.8.3-1.7.3-1.8v-.9l.3-2 .2-1.7V421zm2.3 2.2H548V536l-.3 1.6-.2 1.8-.2 1.7-.3 1.8-.3 1.7-.4 1.7-.3 1.7-.5 1.5-.4 1.7-.4 1.6-.5 1.6-.5 1.6-.6 1.5-.8 1.6-.7 1.6-.7 1.5-.7 1.6-.7 1.4-.8 1.5-.8 1.4-1 1.3-.8 1.4-1 1.3-1 1.3-1 1.3-1 1.3-1 1.2-1.2 1.2-1 1.2-1.2 1-1.2 1.3-1.2 1-1.2 1-1.2 1-1.3 1-1.2 1-1.4 1-1.4 1-1.3.8-1.4 1-1.5.7-1.4.8-1.3.7-1.5.8-1.5.6-1.4.7-1.5.7-1.6.5-1.5.6-1.5.5-1.6.4-1.6.4-1.6.5-1.6.3-1.6.3-1.7.4H489l-1.8.3h-1.7l-1.6.2h-3.6l-1.6-.2H477l-1.6-.3h-1.6l-1.7-.4-1.5-.2-1.6-.3-1.7-.4-1.6-.3-1.6-.4-1.4-.5-1.6-.6-1.5-.5-1.5-.6-1.5-.6-1.4-.6-1.4-.8-1.4-.7-1.4-.8-1.4-.8-1.4-1-1.3-.7-1.4-1-1.3-1-1.2-1-1.3-1-1.2-1-1.2-1-1-1-1.3-1.3-1-1-1.2-1.3-1-1.2-1-1.3-1.2-1.4-1-1.3-1-1.3-1-1.3-.8-1.4-.8-1.4-1-1.5-.7-1.5-.8-1.4-.7-1.5-.8-1.4-.6-1.5-.6-1.5-.6-1.5-.5-1.6-.6-1.6-.5-1.6-.5-1.7-.4-1.6-.4-1.8-.4-1.7-.3-1.7-.3-1.7-.2-1.6-.2-1.8-.2-1.7v-5.4z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 177 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-ru" viewBox="0 0 512 512">
<path fill="#fff" d="M0 0h512v170.7H0z"/>
<path fill="#0039a6" d="M0 170.7h512v170.6H0z"/>
<path fill="#d52b1e" d="M0 341.3h512V512H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 233 B

+4
View File
@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-se" viewBox="0 0 512 512">
<path fill="#005293" d="M0 0h512v512H0z"/>
<path fill="#fecb00" d="M134 0v204.8H0v102.4h134V512h102.4V307.2H512V204.8H236.4V0z"/>
</svg>

After

Width:  |  Height:  |  Size: 223 B

+18
View File
@@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-si" viewBox="0 0 512 512">
<defs>
<clipPath id="si-a">
<path fill-opacity=".7" d="M60.2 0h497.3v497.3H60.2z"/>
</clipPath>
</defs>
<g fill-rule="evenodd" stroke-width="1pt" clip-path="url(#si-a)" transform="translate(-62)scale(1.0295)">
<path fill="#fff" d="M0 0h994.7v497.3H0z"/>
<path fill="#d50000" d="M0 331.6h994.7v165.7H0z"/>
<path fill="#0000bf" d="M0 165.8h994.7v165.8H0z"/>
<path fill="#d50000" d="M282 90.3c-3.9 59.9-6.1 92.7-15.2 107.9-9.9 16.3-19.5 28.2-58 42.6-38.4-14.4-48-26.3-57.9-42.6-9-15.2-11.3-48-15.2-107.9l5.7-1.9c11.4-3.5 20-6.3 26.3-7.5 9-2 16.7-4.1 41-4.6 24.3.4 32 2.7 41 4.6q9.6 2.1 26.6 7.5z"/>
<path fill="#0000bf" d="M276.4 88.3c-3.7 59.8-6.7 87.2-11.6 100.3-9.3 22.6-24.1 35-56 46.7-31.8-11.8-46.6-24.1-56-46.7-4.8-13.1-7.9-40.4-11.4-100.3q16.8-5.4 26.3-7.5c9-1.9 16.7-4.2 41-4.6 24.3.4 32.1 2.7 41.1 4.6q9.6 2.1 26.6 7.5"/>
<path fill="#ffdf00" d="m208.8 106.6 1.5 3.7 6.7.9-4.3 2.6 4.2 2.8-6.1 1-1.9 3.3-2-3.4-6-.8 4-2.9-4-2.6 6.4-1z"/>
<path fill="#fff" d="m262.5 174.5-3.7-3-2.7-4.4-5.2-4.6-2.8-4.6-5.2-4.7-2.6-4.6-2.8-2.3-1.9-1.7-4.7 4.1-2.6 4.6-3.3 2.9-3.5-2.8-2.7-4.7-10-17.7-10 17.7-2.6 4.7-3.6 2.8-3.2-3-2.6-4.5-4.7-4.1-1.9 1.7-2.8 2.3-2.6 4.6-5.2 4.7-2.8 4.6-5.3 4.6-2.6 4.4-3.7 3a64 64 0 0 0 18 35.2c6.4 6.1 19.5 14.4 35.5 19.9a101 101 0 0 0 35.7-20 64 64 0 0 0 18.1-35.1"/>
<path fill="#ffdf00" d="m224.8 81.5 1.5 3.6 6.7 1-4.3 2.5 4.2 2.9-6.1 1-1.9 3.3-2-3.4-5.9-.8 4-3-4.1-2.5 6.4-1zm-32 0 1.5 3.5 6.7 1-4.3 2.6 4.2 2.8-6.1 1-1.9 3.3-2.1-3.4-5.8-.8 4-2.9-4.1-2.6 6.4-1 1.5-3.6z"/>
<path fill="#0000bf" d="M254.2 197.2H247l-6.7-.5-8.1-4-9.2.1-7.9 3.9-6.2.5-6.3-.5-7.9-3.9h-9.1l-8.1 4-6.7.4h-7.4l-3.5-6 .1-.2 10.9 1.8 6.6-.5 8.1-4h9.2l8 4 6.2.5 6.2-.6 8-3.8h9l8.2 3.9 6.7.5 10.5-1.9.2.3zm-84 9.3 7.2-.5 8.1-4h9.1l8 3.9 6.2.6 6.2-.6 8-3.9h9.1l8.1 4 7.3.5 4.7-5.8-.2-.2-5 1.5-6.7-.5-8.1-4h-9.1l-8 4-6.2.5-6.2-.5-8-4h-9.1l-8.1 4-6.7.5-5-1.2v.2z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+9
View File
@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-sk" viewBox="0 0 512 512">
<path fill="#ee1c25" d="M0 0h512v512H0z"/>
<path fill="#0b4ea2" d="M0 0h512v341.3H0z"/>
<path fill="#fff" d="M0 0h512v170.7H0z"/>
<path fill="#fff" d="M203.2 395.5c-45.9-22-111.5-66-111.5-152.8s4.1-126.2 4.1-126.2h214.8s4.2 39.4 4.2 126.2S249 373.4 203.2 395.5"/>
<path fill="#ee1c25" d="M203.2 384c-42.1-20.3-102.3-60.5-102.3-140.2s3.8-115.8 3.8-115.8h197s3.8 36.2 3.8 115.8-60.2 120-102.3 140.2"/>
<path fill="#fff" d="M212.2 223c11.4.2 33.7.6 53.5-6 0 0-.6 7-.6 15.3s.6 15.3.6 15.3a172 172 0 0 0-53.5-6v44h-18v-44a172 172 0 0 0-53.5 6s.6-7 .6-15.3-.6-15.3-.6-15.3c19.9 6.6 42.1 6.2 53.5 6v-27.7a128 128 0 0 0-42.3 6.1s.5-7 .5-15.3-.5-15.4-.5-15.4c17 5.7 31.9 6.2 42.2 6-.5-17.4-5.6-39.4-5.6-39.4s10.5.8 14.7.8 14.7-.8 14.7-.8-5.1 22-5.7 39.5a126 126 0 0 0 42.3-6s-.5 7-.5 15.3.5 15.3.5 15.3c-17-5.7-31.9-6.1-42.3-6z"/>
<path fill="#0b4ea2" d="M203.2 280.8c-21.2 0-32.6 29.4-32.6 29.4s-6.3-14-23.6-14c-11.7 0-20.3 10.5-25.8 20.2 21.3 33.8 55.3 54.7 82 67.6 26.7-12.9 60.7-33.8 82-67.7-5.5-9.6-14.1-20-25.8-20-17.3 0-23.6 14-23.6 14s-11.4-29.5-32.6-29.5"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-ua" viewBox="0 0 512 512">
<g fill-rule="evenodd" stroke-width="1pt">
<path fill="gold" d="M0 0h512v512H0z"/>
<path fill="#0057b8" d="M0 0h512v256H0z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 232 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-xk" viewBox="0 0 512 512">
<path fill="#244AA5" d="M0 0h512v512H0z"/>
<path fill="#D0A650" d="m202.3 245.7 1.3-.7 1.6-.5s.8-.4 1.2-.4 1.3.5 1.5.9c.3.4 1.7 1 1.7 1s1 .4 1.1 0q.3-.4 1-.5c.7-.1.6-.4.6-.7q0-.5.5-1.1c.3-.4 1-.6 1-.6s1-.4 1-1 1.1-1 1.7-1c.5-.1 0-.4 1.3-.2 1.4.1 1.6-.3 1.7-.7 0-.5 0-.9.9-.8q1.3.3 1.3-.4c0-.4.8-.7-.6-1-1.4-.5-1.3-.2-1.4-.8s0-.6-1-.7-.4-.5-.5-1q-.1-.6-.5-1c-.2-.4-.7-.4-.7-.8q.2-.8-.6-.8c-.8 0-.7 0-.7-.4q0-.8.6-.9.9-.2.7-.9v-1.5l.6-.8 2.3-2c.2-.3.9-.6 1.2 0q.4.9.8 1.2c.2.3 1 0 1.2-.2.2-.4.2-1.5.7-2.2q.8-.9.9-1.4 0-.9.9-1c.9-.1.9-.7.9-1.1s.2-.9 1-1c.6 0 1-.5 1.2.1s.4.7.9.9q.7.5 1.4.2c.4-.3.5-.8 1-.5q.8.4 1-.6l.2-1.5s.1-.4 1-.4.2-.5.6-.8c.5-.4.5-.7 1-.5s1.5-.2 1-.7c-.4-.6-1.4-1.4-.9-2 .6-.6.8-1.7.3-1.8s-1.4.1-1.5-.5-.3-1 .3-1.2c.7 0 1.9 0 2.2-.4s1.5-.5 1.5-1.4c0-1 .3-1 .4-1.6.1-.5.1-1.6-.3-2.1l-1.3-1.6a2 2 0 0 0-1.2-1q-1.2-.2-1.3-.8c0-.6.5 0 .5-1.3s-1-1.6-1-1.6l-1.3-.8s-2.4-.6-3-.6-1.4-.7-.7-1.1q1.2-.8.7-1.8c-.5-1-.5-1-1.5-1.3q-1.5-.3-.9-1.1c.5-.6.6-1 1.2-.6q.9.7 2.2.2 1-.6 1.4-.2c.3.3.8.7 1.4.2.5-.6 1.5-.6 2-.4.5.3 1.6.2 2 0s1-.8 1-1.1.5-1 1-1.2c.4-.3 1-1.1 1.5-1.1s.6-.5.6-.9.4-1 .5-1.2c0-.3 1-.7 1.6-.1s1.5.7 1.5.7h1.4q.8-.4 1.8 0c.6.5 1.6.5 1.6.5l.1-1q.2-.7-.1-1.2c-.4-.3-.9-.6-.1-1.2.7-.5.7-.4 1.4-.4l1.8.1c.6 0 1.5.5 1.5 1s.4.9.8 1.1q.9.4.9 1-.4.6.3.7.9 0 .8.6-.2.7.7.9t.8 1l.1 1c.1.4.8 1.1.8 1.1s1 1.2-.3.6-1.6-.8-2-.7l-.8.3-1 .2c-.6 0-1 1-.3 1.1q1.1.1 1 1c-.1.9-.2.4-.6.8s-.7.2-1.3.2q-1 .1-.8 1c.2.9.2.4.5.8q.5.7 1.2.1c.5-.4.9-.7 1.1.1s.7.8 1.2.8q.8 0 1.2-.3.8-.3 1.2.7.1.9 1 1 .6.4.8.9.2.7.8.3.9-.4 1.5 0l.8 1v.8l1.8.6.2.8q0 .6.7.4h1.3s.7-.3.7-.8.3-.6.7-.6c.5 0 1.5.3 1.8-.2q.6-.8 1.7-.4l2.4.9s-.2 0 .3 1c.6.8 1.6.8 1.6.8l.3 1.1c.2.3 1 .5 1.5.2q.6-.7 1.6-.8 1 0 1-.3c0-.3-.6-.6-.6-1.2s.6-.5.7-1 .6 0 1 .3q.6.4.8 1c.2.6.8 1.5 1.2 1.7.5.2 1.7.3 2-.2s1.3-.6 1.3.5c-.1 1-.3 1 .3 1.4s.8 1.6.2 1.9q-.7.3-.7 1-.2 1.1.2 1.6.8.5.8 1c0 .5.5 1.9.5 1.9s.3 1.5.2 1.8-.2 1 .6.9q1.1-.3 1 .6c-.1.9.3 1-.2 1.2s-.7 1-.3 1.3q.8.2 1 .7c0 .4.8 1 1.3.6q.4-.5.9-.6.7 0 .3-.7-.6-.7-.1-1.2c.4-.2.5-1 .5-1s.6-.8 1.2 0c.7.7.8.4 1.2.4q.7.1.7.9c0 .8 1 .3 1 1l.1 2.3s0 1 .6 1.3.4.4.1.9q-.2.7-.1 1.4c.1.7.1.5-.3.9q-.8.5-.4 1.2c.3.6.2.9 1 1.5.7.6.6.9.6 1.3s.7 1 .7 1.4c0 .5.6 1 1 1s1 .9 1 1.3l.2 1.6s-.1.2.4.2 1 .6 1.1 0q.5-.9 1.1-1c.4-.2 1.2-.5 1.5-.3q.7.4 1.2.3h2.2s.4 0 .7.7 1.1 1.4.7 1.8c-.5.3-.5 1 0 1q1-.1 1.2.4-.1.8.5.5.8-.4 1 0t1 .6q.5.4.9-.2c.3-.4 1.4-.7 1.4-.7s1.5-.3 2-.2l1.3.5s.4.9.2 1.4-.4.4-.2 1.2q.1 1-.5.8-.7-.3-.8.6c-.1.9-.4.8-.4 1.4s0 .5-.3.8q-.7.5 0 .8c.6 0 .4.6.4 1v1s0 .5-.6.5q-1.1-.1-1.3.4c-.2.5-.8 1-.2 1.5q.9.6.1.8c-.4.2-.6 1 0 1.3q1 .4.3.9c-.5.3-1.4.6-1.4 1q0 .7-.8.7-1.2.1-.1 1.6c.6.9.8.7 1.3.7s.4-.7.4-.7h2q.9 0 1.5-.2c.4-.2 1.4-.7 1.4.1s.2.7.7 1 .5.1 1 .6q.4.6.6-.5c.3-.6.9-1.2 1.3-.5s.5.5 1 .5q.9 0 .8.7c-.1.7.6.4 1.2.3s.7.4 1 .8q.3.5.8.4.5.1 1-.4c.3-.3.6-.8 1-.2s1.1.4 1.3-.2 1-1.1 1.5-.4q.6.7 1.3.7t1.4.5c.3.5 1.2 1.2.5 1.7s-1.4 1.2-.8 1.3q.9.2 1.3.8c.4.4 1.6.6 2.1.7s1 .2 1.7-.4c.6-.5 1.3-.5 1.2.2s.3 1.5.3 1.5.4 1 .4 1.5q-.2.4.8 1c1 .6.7.9 1.4.4q.9-.8.8-1.2v-1.4s1-.2 1.3-.4 1.9-1 2.2-.7.9.2 1.2 0h1.5q.6.2 1.8-.6c.7-.6.7-.4 1.2 0s.4 1 .2 1.3 0 1 .6 1q1 0 .8.9l.2 1.3c.1.4.1.5 1.1.8 1 .2.9.8 1 1.3q.4.6-.3.7-.9 0-.8.7c-.1.4-1 .6-1 .6l-.8-.2s-.6 0-.8.4c-.3.3-.9 1-.5 1.6q.6.9 0 1.2c-.4.3-.6 1.5-1 1.3s-.8 0-1.1.2-.3 1.4.4 1.8q1.1.9 1 1l.8 1.3-.5.7c-.2.4-.7 1.3-.2 1.5s.3 1-.2 1-1.2-.2-1.3.5-.4.5-1 .4-2-.4-2.3.3q-.3 1-1 .8c-.7 0-.5 1-.3 1.5s.9 1 .9 1 .5.4.5 1.3-.4.8-.7.2-1.1-.5-1.2.1-.2 1.7-.9 1.7q-.8 0-1.2.6c-.2.3-.7.9-.7 1.2s-.1.7-.6.8c-.4 0-.5 1-.5 1s-1.1.2-1.2.6 0 1.1-.9 1.2q-1.3.3-1.7 1.1-.5.7 0 1.2c.4.4.6 1.8 1 2q1 .3.8 1c0 .8-.6 1.3.1 1.3q1.2 0 1 .8c-.3.6-.3.6-.9.9-.5.3-.8.3-.8 1s.2.6-.3.9q-.6.4-.5 1c0 .6-.1.4-.7 1s-1.3.6-1.8.4q-.5 0-.6-.6c-.1-.6-1-.6-1.4-.5-.5.1-1.1.6-1.1.6s-.8.5-.5 1q.5.8-.4 1c-.7 0-2.2.7-2.6 0-.5-.9-1.8-1.4-2-.3s.6.9.5 2c-.1 1-.3 1-.7 1.3q-.4.4-.4 1c-.1.4-.2 1.4.4 1.7s1 1.3 1 1.8 0 1 .6 1q1.1.2 1.3-.7c.1-.6 1.4-.9 1.5.3s0 1.8.6 2.3l1.2 1.5c.6.6 1 2.4 1 2.4-1 .2-1.2 1.4-1.8 1.6l-1 .2-.5.7c-.7.3-.5-.8-1.4-.4-.7.3-.8 1.2-1.8.8-.6-.2-1-2.3-1.1-2.8 0-.3-.7-1.2-.9-1.5-.6-1-1.8 0-2.2-.3-.7-.4-.4-1.2-1.3-1.2-2-.2-.6 1.1-1.4 1.4-1.5.6-1.5-1.4-2.7-.5-.4.3.7.6.4 1.2-.2.4-1.4 1.2-1.3 1.8.1.8 1 1 1.2 1.7.7 1.7-.4 3-2.2 1.6-1-.8-1.1-2.2-2.6-2.1l-.9.4q-.4-.2-1-.2c-.5.2 0 .6-.1.9l-.9.8c-.4.5-.3 1-.9 1.5-.5.3-.9.1-1.4.7-.6.6-.7 1.5-1.4 2.1-.4.3-.6-.9-1 0q-.2 0-.3.2v.6c1 2-1 2.6-1.7 4-.3.5.5 1 .2 1.4l-1.2 1.4q0 .4-.3.8c-.2.2-.7 0-.8.3 0 .3.6.6.8.8s-.1.5 0 .6c1 1 .4.7.9 1.6 0 .2.4 0 .5.3l-.1.6.8 1.1c0 .3-1.5 1-1.8 1-.9 0 .8-1.8-.7-1.8-.6 0-.6 1.4-.8 1.6h-.8c-.9 0-1.5 1.1-1.9 1.2h-1.1c-.4 0-.8.4-1.2.4q-.2 0-.5-.3l-1.6-.5c-.3 0-.8.4-1 .2-.2-.1.3-.7-.4-1l-.6-1.4q.4-1.2.4-2.5c-.2-1-1.5-1.7-2-2.4-.2-.5-.4-2-1-2.3a5 5 0 0 1-1.4-1.7q.2-.3 0-.8-.5-.3-.8-.8c-.1-.4 0-1.5-.4-1.7-.4-.3-3.3-.6-4-.7q-.5 0-.9-.3l-.4-.5-.9.1h-.7c-1 .6-1.1 1.4-2 2-.9.8-1.8.7-2.7 1.5-.6.5-1 1.7-1.5 2.2-.2.3-.6 0-.7.1l-1.6 1.5s0 .3-.2.4l-1 .2h-1c-.4.2-.4.7-2 1l-.3.2-.6.5h-.6q-.6.1-1 .4c-.9 0-2.2-.4-2.8-.1-.4.1-1.5 1.3-2 1.4h-.6c-.2 0-.5 1.4-.6 1.7l-2 1.7-.5.8q-.3.4-.8.4-.7-.1-1.3-.4c-.7 0-2.7-.2-3.3 0-.6 0-.4 1.9-2Line truncated
<path fill="#FFF" d="m281.4 124.5 12.9 39.7-33.8-24.5h41.7l-33.7 24.5zm50.2 8.9 12.9 39.7-33.8-24.5h41.8L318.7 173zm47.9 17.4 13 39.7-33.8-24.5h41.7l-33.8 24.5zm-149.1-26.3-13 39.7 33.8-24.5h-41.7l33.8 24.5-13-39.7zm-50.2 8.9-13 39.7 33.8-24.5h-41.7L193 173l-13-39.7zm-47.7 17.4 12.9 39.7-33.8-24.5h41.7l-33.7 24.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 7.6 KiB

File diff suppressed because it is too large. Load diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

File diff suppressed because it is too large. Load diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

+1
View File
@@ -0,0 +1 @@
{"version":8,"sources":{"ne2_shaded":{"maxzoom":6,"tileSize":256,"tiles":["https://tiles.openfreemap.org/natural_earth/ne2sr/{z}/{x}/{y}.png"],"type":"raster"},"openmaptiles":{"type":"vector","url":"https://tiles.openfreemap.org/planet"}},"sprite":"https://tiles.openfreemap.org/sprites/ofm_f384/ofm","glyphs":"https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf","layers":[{"id":"background","type":"background","paint":{"background-color":"#f8f4f0"}},{"id":"natural_earth","type":"raster","source":"ne2_shaded","maxzoom":7,"paint":{"raster-opacity":["interpolate",["exponential",1.5],["zoom"],0,0.6,6,0.1]}},{"id":"park","type":"fill","source":"openmaptiles","source-layer":"park","paint":{"fill-color":"#d8e8c8","fill-opacity":0.7,"fill-outline-color":"rgba(95, 208, 100, 1)"}},{"id":"park_outline","type":"line","source":"openmaptiles","source-layer":"park","paint":{"line-color":"rgba(228, 241, 215, 1)","line-dasharray":[1,1.5]}},{"id":"landuse_residential","type":"fill","source":"openmaptiles","source-layer":"landuse","maxzoom":12,"filter":["==",["get","class"],"residential"],"paint":{"fill-color":["interpolate",["linear"],["zoom"],9,"hsla(0,3%,85%,0.84)",12,"hsla(35,57%,88%,0.49)"]}},{"id":"landcover_wood","type":"fill","source":"openmaptiles","source-layer":"landcover","filter":["==",["get","class"],"wood"],"paint":{"fill-antialias":false,"fill-color":"hsla(98,61%,72%,0.7)","fill-opacity":0.4}},{"id":"landcover_grass","type":"fill","source":"openmaptiles","source-layer":"landcover","filter":["==",["get","class"],"grass"],"paint":{"fill-antialias":false,"fill-color":"rgba(176, 213, 154, 1)","fill-opacity":0.3}},{"id":"landcover_ice","type":"fill","source":"openmaptiles","source-layer":"landcover","filter":["==",["get","class"],"ice"],"paint":{"fill-antialias":false,"fill-color":"rgba(224, 236, 236, 1)","fill-opacity":0.8}},{"id":"landcover_wetland","type":"fill","source":"openmaptiles","source-layer":"landcover","minzoom":12,"filter":["==",["get","class"],"wetland"],"paint":{"fill-antialias":true,"fill-opacity":0.8,"fill-pattern":"wetland_bg_11","fill-translate-anchor":"map"}},{"id":"landuse_pitch","type":"fill","source":"openmaptiles","source-layer":"landuse","filter":["==",["get","class"],"pitch"],"paint":{"fill-color":"#DEE3CD"}},{"id":"landuse_track","type":"fill","source":"openmaptiles","source-layer":"landuse","filter":["==",["get","class"],"track"],"paint":{"fill-color":"#DEE3CD"}},{"id":"landuse_cemetery","type":"fill","source":"openmaptiles","source-layer":"landuse","filter":["==",["get","class"],"cemetery"],"paint":{"fill-color":"hsl(75,37%,81%)"}},{"id":"landuse_hospital","type":"fill","source":"openmaptiles","source-layer":"landuse","filter":["==",["get","class"],"hospital"],"paint":{"fill-color":"#fde"}},{"id":"landuse_school","type":"fill","source":"openmaptiles","source-layer":"landuse","filter":["==",["get","class"],"school"],"paint":{"fill-color":"rgb(236,238,204)"}},{"id":"waterway_tunnel","type":"line","source":"openmaptiles","source-layer":"waterway","filter":["==",["get","brunnel"],"tunnel"],"paint":{"line-color":"#a0c8f0","line-dasharray":[3,3],"line-gap-width":["interpolate",["linear"],["zoom"],12,0,20,6],"line-opacity":1,"line-width":["interpolate",["exponential",1.4],["zoom"],8,1,20,2]}},{"id":"waterway_river","type":"line","source":"openmaptiles","source-layer":"waterway","filter":["all",["==",["get","class"],"river"],["!=",["get","brunnel"],"tunnel"]],"layout":{"line-cap":"round"},"paint":{"line-color":"#a0c8f0","line-width":["interpolate",["exponential",1.2],["zoom"],11,0.5,20,6]}},{"id":"waterway_other","type":"line","source":"openmaptiles","source-layer":"waterway","filter":["all",["!=",["get","class"],"river"],["!=",["get","brunnel"],"tunnel"]],"layout":{"line-cap":"round"},"paint":{"line-color":"#a0c8f0","line-width":["interpolate",["exponential",1.3],["zoom"],13,0.5,20,6]}},{"id":"water","type":"fill","source":"openmaptiles","source-layer":"water","filter":["!=",["get","brunnel"],"tunnel"],"paint":{"fill-color":"rgb(158,189,255)"}},{"id":"landcover_sand","type":"fill","source":"openmaptiles","source-layer":"landcover","filter":["==",["get","class"],"sand"],"paint":{"fill-color":"rgba(247, 239, 195, 1)"}},{"id":"aeroway_fill","type":"fill","source":"openmaptiles","source-layer":"aeroway","minzoom":11,"filter":["match",["geometry-type"],["MultiPolygon","Polygon"],true,false],"paint":{"fill-color":"rgba(229, 228, 224, 1)","fill-opacity":0.7}},{"id":"aeroway_runway","type":"line","source":"openmaptiles","source-layer":"aeroway","minzoom":11,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["==",["get","class"],"runway"]],"paint":{"line-color":"#f0ede9","line-width":["interpolate",["exponential",1.2],["zoom"],11,3,20,16]}},{"id":"aeroway_taxiway","type":"line","source":"openmaptiles","source-layer":"aeroway","minzoom":11,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["==",["get","class"],"taxiway"Line truncated
+15
View File
@@ -0,0 +1,15 @@
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).mlcontour=e()}(this,(function(){"use strict";var t,e,i;function r(r,s){if(t)if(e){var n="var sharedChunk = {}; ("+t+")(sharedChunk); ("+e+")(sharedChunk);",o={};t(o),i=s(o),"undefined"!=typeof window&&(i.workerUrl=window.URL.createObjectURL(new Blob([n],{type:"text/javascript"})))}else e=s;else t=s}return r(0,(function(t){class e{constructor(t,e){this.start=t,this.end=e,this.points=[],this.append=this.append.bind(this),this.prepend=this.prepend.bind(this)}append(t,e){this.points.push(Math.round(t),Math.round(e))}prepend(t,e){this.points.splice(0,0,Math.round(t),Math.round(e))}lineString(){return this.toArray()}isEmpty(){return this.points.length<2}appendFragment(t){this.points.push(...t.points),this.end=t.end}toArray(){return this.points}}const i=[[],[[[1,2],[0,1]]],[[[2,1],[1,2]]],[[[2,1],[0,1]]],[[[1,0],[2,1]]],[[[1,2],[0,1]],[[1,0],[2,1]]],[[[1,0],[1,2]]],[[[1,0],[0,1]]],[[[0,1],[1,0]]],[[[1,2],[1,0]]],[[[0,1],[1,0]],[[2,1],[1,2]]],[[[2,1],[1,0]]],[[[0,1],[2,1]]],[[[1,2],[2,1]]],[[[0,1],[1,2]]],[]];function r(t,e,i,r){return(e=2*e+r[0])+(i=2*i+r[1])*(t+1)*2}function s(t,e,i){return(e-t)/(i-t)}function n(t,n,o=4096,a=1){if(!t)return{};const h=o/(n.width-1);let l,c,d,u,f,p;const w={},g=new Map,m=new Map;function b(t,e,i){0===t[0]?i(h*(p-1),h*(f-s(d,e,l))):2===t[0]?i(h*p,h*(f-s(u,e,c))):0===t[1]?i(h*(p-s(c,e,l)),h*(f-1)):i(h*(p-s(u,e,d)),h*f)}for(f=1-a;f<n.height+a;f++){c=n.get(0,f-1),u=n.get(0,f);let s=Math.min(c,u),o=Math.max(c,u);for(p=1-a;p<n.width+a;p++){l=c,d=u,c=n.get(p,f-1),u=n.get(p,f);const a=s,h=o;if(s=Math.min(c,u),o=Math.max(c,u),isNaN(l)||isNaN(c)||isNaN(u)||isNaN(d))continue;const y=Math.min(a,s),v=Math.max(h,o),P=Math.ceil(y/t)*t,x=Math.floor(v/t)*t;for(let s=P;s<=x;s+=t){const t=l>s,o=c>s,a=d>s,h=u>s;for(const l of i[(t?8:0)|(o?4:0)|(h?2:0)|(a?1:0)]){let t=g.get(s);t||g.set(s,t=new Map);let i=m.get(s);i||m.set(s,i=new Map);const o=l[0],a=l[1],h=r(n.width,p,f,o),c=r(n.width,p,f,a);let d,u;if(d=i.get(h))if(i.delete(h),u=t.get(c))if(t.delete(c),d===u){if(b(a,s,d.append),!d.isEmpty()){let t=w[s];t||(w[s]=t=[]),t.push(d.lineString())}}else d.appendFragment(u),i.set(d.end=u.end,d);else b(a,s,d.append),i.set(d.end=c,d);else if(d=t.get(c))t.delete(c),b(o,s,d.prepend),t.set(d.start=h,d);else{const r=new e(h,c);b(o,s,r.append),b(a,s,r.append),t.set(h,r),i.set(c,r)}}}}}for(const[t,e]of g.entries()){let i=null;for(const r of e.values())r.isEmpty()||(null==i&&(i=w[t]||(w[t]=[])),i.push(r.lineString()))}return w}
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */function o(t,e){var i={};for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&e.indexOf(r)<0&&(i[r]=t[r]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols){var s=0;for(r=Object.getOwnPropertySymbols(t);s<r.length;s++)e.indexOf(r[s])<0&&Object.prototype.propertyIsEnumerable.call(t,r[s])&&(i[r[s]]=t[r[s]])}return i}function a(t,e,i,r){return new(i||(i=Promise))((function(s,n){function o(t){try{h(r.next(t))}catch(t){n(t)}}function a(t){try{h(r.throw(t))}catch(t){n(t)}}function h(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i((function(t){t(e)}))).then(o,a)}h((r=r.apply(t,e||[])).next())}))}function h(t){const e=Object.entries(t);return e.sort((([t],[e])=>t<e?-1:t>e?1:0)),e}function l(t){return h(t).map((([t,e])=>[t,..."number"==typeof e?[e]:e].join("*"))).join("~")}function c(t){return h(t).map((([t,e])=>`${encodeURIComponent(t)}=${encodeURIComponent(e)}`)).join(",")}let d=null;function u(){return null==d&&(d="undefined"!=typeof OffscreenCanvas&&new OffscreenCanvas(1,1).getContext("2d")&&"function"==typeof createImageBitmap),d||!1}let f=null;function p(t,e,i){let r=()=>{};const s=setTimeout((()=>{r(new Error("timed out")),null==i||i.abort()}),t);w(i,(()=>{r(new Error("aborted")),clearTimeout(s)}));const n=new Promise(((t,e)=>{r=e}));return Promise.race([n,e.finally((()=>clearTimeout(s)))])}function w(t,e){e&&(null==t||t.signal.addEventListener("abort",e))}function g(t){var e;return Boolean(null===(e=null==t?void 0:t.signal)||void 0===e?void 0:e.aborted)}let m,b,y,v,P=0;class x{constructor(t=100){this.size=()=>this.items.size,this.get=(t,e,i)=>{let r=this.items.get(t);if(r)r.lastUsed=++P,r.waiting++;else{const i=new AbortController,s=e(t,i);r={abortController:i,item:s,lastUsed:++P,waiting:1},this.items.set(t,r),this.prune()}const s=this.items,n=r.item.then((t=>t),(e=>(s.delete(t),Promise.reject(e))));let o=!1;return w(i,(()=>{var e;r&&r.abortController&&!o&&(o=!0,--r.waiting<=0&&(null===(e=r.abortController)||void 0===e||e.abort(),s.delete(t)))})),n},this.clear=()=>this.items.clear(),this.maxSize=t,this.items=new Map}prune(){if(this.items.size>this.maxSize){let t,e=1/0;this.items.forEach(((i,r)=>{i.lastUsed<e&&(e=i.lastUsed,t=r)})),void 0!==t&&this.items.delete(t)}}}function F(t,e){return m||(m=new OffscreenCanvas(t.width,t.height),b=m.getContext("2d",{willReadFrequently:!0})),V(t,e,m,b)}const k=function(){if(null==f&&(f=!1,u()&&"undefined"!=typeof VideoFrame)){const t=5,e=new OffscreenCanvas(5,5).getContext("2d",{willReadFrequently:!0});if(e){for(let i=0;i<t*t;i++){const r=4*i;e.fillStyle=`rgb(${r},${r+1},${r+2})`,e.fillRect(i%t,Math.floor(i/t),1,1)}const i=e.getImageData(0,0,t,t).data;for(let e=0;e<t*t*4;e++)if(e%4!=3&&i[e]!==e){f=!0;break}}}return f||!1}()?function(t,e,i){return a(this,void 0,void 0,(function*(){var r,s,n;const o=yield createImageBitmap(t);if(g(i))return null;const a=new VideoFrame(o,{timestamp:0});try{if(!((null===(r=null==a?void 0:a.format)||void 0===r?void 0:r.startsWith("BGR"))||(null===(s=null==a?void 0:a.format)||void 0===s?void 0:s.startsWith("RGB"))))throw new Error(`Unrecognized format: ${null==a?void 0:a.format}`);const t=null===(n=null==a?void 0:a.format)||void 0===n?void 0:n.startsWith("BGR"),i=a.allocationSize(),h=new Uint8ClampedArray(i);if(yield a.copyTo(h),t)for(let t=0;t<h.length;t+=4){const e=h[t];h[t]=h[t+2],h[t+2]=e}return M(o.width,o.height,e,h)}catch(t){return g(i)?null:F(o,e)}finally{a.close()}}))}:u()?function(t,e,i){return a(this,void 0,void 0,(function*(){const r=yield createImageBitmap(t);return g(i)?null:F(r,e)}))}:"undefined"!=typeof WorkerGlobalScope&&"undefined"!=typeof self&&self instanceof WorkerGlobalScope?function(t,e,i){return self.actor.send("decodeImage",[],i,void 0,t,e)}:function(t,e,i){return a(this,void 0,void 0,(function*(){y||(y=document.createElement("canvas"),v=y.getContext("2d",{willReadFrequently:!0}));const r=new Image;w(i,(()=>r.src=""));return V(yield new Promise(((e,s)=>{r.onload=()=>{g(i)||e(r),URL.revokeObjectURL(r.src),r.onload=null},r.onerror=()=>s(new Error("Could not load image.")),r.src=t.size?URL.createObjectURL(t):""})),e,y,v)}))};function V(t,e,i,r){if(i.width=t.width,i.height=t.height,!r)throw new Error("failed to get context");r.drawImage(t,0,0,t.width,t.height);const s=r.getImageData(0,0,t.width,t.height).data;return M(t.width,t.height,e,s)}function M(t,e,i,r){const s="mapbox"===i?(t,e,i)=>.1*(256*t*256+256*e+i)-1e4:(t,e,i)=>256*t+e+i/256-32768,n=new Float32Array(t*e);for(let t=0;t<r.length;t+=4)n[t/4]=s(r[t],r[t+1],r[t+2]);return{width:t,height:e,data:n}}class S{constructor(t,e,i){this.split=(t,e,i)=>{if(0===t)return this;const r=1<<t,s=e*this.width/r,n=i*this.height/r;return new S(this.width/r,this.height/r,((t,e)=>this.get(t+s,e+n)))},this.subsamplePixelCenters=t=>{const e=(t,e,i)=>isNaN(t)?e:isNaN(e)?t:t+(e-t)*i;if(t<=1)return this;const i=.5-1/(2*t);return new S(this.width*t,this.height*t,((r,s)=>{const n=r/t-iLine truncated
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Steve Vigneau
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
File diff suppressed because it is too large. Load diff
Binary file not shown.
@@ -1,16 +0,0 @@
"use strict";var protomaps_themes_base=(()=>{var f=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames,x=Object.getOwnPropertySymbols;var j=Object.prototype.hasOwnProperty,$=Object.prototype.propertyIsEnumerable;var z=(a,e,i)=>e in a?f(a,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):a[e]=i,b=(a,e)=>{for(var i in e||(e={}))j.call(e,i)&&z(a,i,e[i]);if(x)for(var i of x(e))$.call(e,i)&&z(a,i,e[i]);return a};var l=(a,e)=>f(a,"name",{value:e,configurable:!0});var C=(a,e)=>{for(var i in e)f(a,i,{get:e[i],enumerable:!0})},P=(a,e,i,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of T(e))!j.call(a,r)&&r!==i&&f(a,r,{get:()=>e[r],enumerable:!(n=D(e,r))||n.enumerable});return a};var A=a=>P(f({},"__esModule",{value:!0}),a);var W={};C(W,{default:()=>S,labels:()=>I,labelsWithCustomTheme:()=>K,language_script_pairs:()=>m,layers:()=>B,layersWithCustomTheme:()=>V,layersWithPartialCustomTheme:()=>F,namedTheme:()=>H,noLabels:()=>E,noLabelsWithCustomTheme:()=>G});function t(a,e){let i="script";return a==="name"?i="script":a==="name2"?i="script2":a==="name3"&&(i="script3"),[["coalesce",["get",`pgf:${a}`],["get",a]],{"text-font":["case",["==",["get",i],"Devanagari"],["literal",["Noto Sans Devanagari Regular v1"]],["literal",[e||"Noto Sans Regular"]]]}]}l(t,"get_name_block");function c(a,e,i){let n="name";return i==="name"?n="":i==="name2"?n="2":i==="name3"&&(n="3"),e==="Latin"?["has",`script${n}`]:a==="ja"?["all",["!=",["get",`script${n}`],"Han"],["!=",["get",`script${n}`],"Hiragana"],["!=",["get",`script${n}`],"Katakana"],["!=",["get",`script${n}`],"Mixed-Japanese"]]:["!=",["get",`script${n}`],e]}l(c,"is_not_in_target_script");function o(a){return a==="Devanagari"?{"text-font":["literal",["Noto Sans Devanagari Regular v1"]]}:{}}l(o,"get_font_formatting");function v(a){let e=m.find(i=>i.lang===a);return e===void 0?"Latin":e.script}l(v,"get_default_script");function L(a,e){let i=e||v(a),n;return i==="Devanagari"?n="pgf:":n="",["format",["coalesce",["get",`${n}name:${a}`],["get","name:en"]],o(i)]}l(L,"get_country_name");function s(a,e,i){let n=e||v(a),r;return n==="Devanagari"?r="pgf:":r="",["case",["all",["any",["has","name"],["has","pgf:name"]],["!",["any",["has","name2"],["has","pgf:name2"]]],["!",["any",["has","name3"],["has","pgf:name3"]]]],["case",c(a,n,"name"),["case",["any",["is-supported-script",["get","name"]],["has","pgf:name"]],["format",["coalesce",["get",`${r}name:${a}`],["get","name:en"]],o(n),`
`,{},["case",["all",["!",["has",`${r}name:${a}`]],["has","name:en"],["!",["has","script"]]],"",["coalesce",["get","pgf:name"],["get","name"]]],{"text-font":["case",["==",["get","script"],"Devanagari"],["literal",["Noto Sans Devanagari Regular v1"]],["literal",[i||"Noto Sans Regular"]]]}],["get","name:en"]],["format",["coalesce",["get",`${r}name:${a}`],["get","pgf:name"],["get","name"]],o(n)]],["all",["any",["has","name"],["has","pgf:name"]],["any",["has","name2"],["has","pgf:name2"]],["!",["any",["has","name3"],["has","pgf:name3"]]]],["case",["all",c(a,n,"name"),c(a,n,"name2")],["format",["get",`${r}name:${a}`],o(n),`
`,{},...t("name"),`
`,{},...t("name2")],["case",c(a,n,"name2"),["format",["coalesce",["get",`${r}name:${a}`],["get","pgf:name"],["get","name"]],o(n),`
`,{},...t("name2")],["format",["coalesce",["get",`${r}name:${a}`],["get","pgf:name2"],["get","name2"]],o(n),`
`,{},...t("name")]]],["case",["all",c(a,n,"name"),c(a,n,"name2"),c(a,n,"name3")],["format",["get",`${r}name:${a}`],o(n),`
`,{},...t("name"),`
`,{},...t("name2"),`
`,{},...t("name3")],["case",["!",c(a,n,"name")],["format",["coalesce",["get",`${r}name:${a}`],["get","pgf:name"],["get","name"]],o(n),`
`,{},...t("name2"),`
`,{},...t("name3")],["!",c(a,n,"name2")],["format",["coalesce",["get",`${r}name:${a}`],["get","pgf:name2"],["get","name2"]],o(n),`
`,{},...t("name"),`
`,{},...t("name3")],["format",["coalesce",["get",`${r}name:${a}`],["get","pgf:name3"],["get","name3"]],o(n),`
`,{},...t("name"),`
`,{},...t("name2")]]]]}l(s,"get_multiline_name");var m=[{lang:"ar",full_name:"Arabic",script:"Arabic"},{lang:"cs",full_name:"Czech",script:"Latin"},{lang:"bg",full_name:"Bulgarian",script:"Cyrillic"},{lang:"da",full_name:"Danish",script:"Latin"},{lang:"de",full_name:"German",script:"Latin"},{lang:"el",full_name:"Greek",script:"Greek"},{lang:"en",full_name:"English",script:"Latin"},{lang:"es",full_name:"Spanish",script:"Latin"},{lang:"et",full_name:"Estonian",script:"Latin"},{lang:"fa",full_name:"Persian",script:"Arabic"},{lang:"fi",full_name:"Finnish",script:"Latin"},{lang:"fr",full_name:"French",script:"Latin"},{lang:"ga",full_name:"Irish",script:"Latin"},{lang:"he",full_name:"Hebrew",script:"Hebrew"},{lang:"hi",full_name:"Hindi",script:"Devanagari"},{lang:"hr",full_name:"Croatian",script:"Latin"},{lang:"hu",full_name:"Hungarian",script:"Latin"},{lang:"id",full_name:"Indonesian",script:"Latin"},{lang:"it",full_name:"Italian",script:"Latin"},{lang:"ja",full_name:"Japanese",script:""},{lang:"ko",full_name:"Korean",script:"Hangul"},{lang:"lt",full_name:"Lithuanian",script:"Latin"},{lang:"lv",full_name:"Latvian",script:"Latin"},{lang:"ne",full_name:"Nepali",script:"Devanagari"},{lang:"nl",full_name:"Dutch",script:"Latin"},{lang:"no",full_name:"Norwegian",script:"Latin"},{lang:"mr",full_name:"Marathi",script:"Devanagari"},{lang:"mt",full_name:"Maltese",script:"Latin"},{lang:"pl",full_name:"Polish",script:"Latin"},{lang:"pt",full_name:"Portuguese",script:"Latin"},{lang:"ro",full_name:"Romanian",script:"Latin"},{lang:"ru",full_name:"Russian",script:"Cyrillic"},{lang:"sk",full_name:"Slovak",script:"Latin"},{lang:"sl",full_name:"Slovenian",script:"Latin"},{lang:"sv",full_name:"Swedish",script:"Latin"},{lang:"tr",full_name:"Turkish",script:"Latin"},{lang:"uk",full_name:"Ukrainian",script:"Cyrillic"},{lang:"ur",full_name:"Urdu",script:"Arabic"},{lang:"vi",full_name:"Vietnamese",script:"Latin"},{lang:"zh-Hans",full_name:"Chinese (Simplified)",script:"Han"},{lang:"zh-Hant",full_name:"Chinese (Traditional)",script:"Han"}];function _(a,e){return[{id:"background",type:"background",paint:{"background-color":e.background}},{id:"earth",type:"fill",filter:["==","$type","Polygon"],source:a,"source-layer":"earth",paint:{"fill-color":e.earth}},...e.landcover?[{id:"landcover",type:"fill",source:a,"source-layer":"landcover",paint:{"fill-color":["match",["get","kind"],"grassland",e.landcover.grassland,"barren",e.landcover.barren,"urban_area",e.landcover.urban_area,"farmland",e.landcover.farmland,"glacier",e.landcover.glacier,"scrub",e.landcover.scrub,e.landcover.forest],"fill-opacity":["interpolate",["linear"],["zoom"],5,1,7,0]}}]:[],{id:"landuse_park",type:"fill",source:a,"source-layer":"landuse",filter:["in","kind","national_park","park","cemetery","protected_area","nature_reserve","forest","golf_course","wood","nature_reserve","forest","scrub","grassland","grass","military","naval_base","airfield"],paint:{"fill-opacity":["interpolate",["linear"],["zoom"],6,0,11,1],"fill-color":["case",["in",["get","kind"],["literal",["national_park","park","cemetery","protected_area","nature_reserve","forest","golf_course"]]],e.park_b,["in",["get","kind"],["literal",["wood","nature_reserve","forest"]]],e.wood_b,["in",["get","kind"],["literal",["scrub","grassland","grass"]]],e.scrub_b,["in",["get","kind"],["literal",["glacier"]]],e.glacier,["in",["get","kind"],["literal",["sand"]]],e.sand,["in",["get","kind"],["literal",["military","naval_base","airfield"]]],e.zoo,e.earth]}},{id:"landuse_urban_green",type:"fill",source:a,"source-layer":"landuse",filter:["in","kind","allotments","village_green","playground"],paint:{"fill-color":e.park_b,"fill-opacity":.7}},{id:"landuse_hospital",type:"fill",source:a,"source-layer":"landuse",filter:["==","kind","hospital"],paint:{"fill-color":e.hospital}},{id:"landuse_industrial",type:"fill",source:a,"source-layer":"landuse",filter:["==","kind","industrial"],paint:{"fill-color":e.industrial}},{id:"landuse_school",type:"fill",source:a,"source-layer":"landuse",filter:["in","kind","school","university","college"],paint:{"fill-color":e.school}},{id:"landuse_beach",type:"fill",source:a,"source-layer":"landuse",filter:["in","kind","beach"],paint:{"fill-color":e.beach}},{id:"landuse_zoo",type:"fill",source:a,"source-layer":"landuse",filter:["in","kind","zoo"],paint:{"fill-color":e.zoo}},{id:"landuse_aerodrome",type:"fill",source:a,"source-layer":"landuse",filter:["in","kind","aerodrome"],paint:{"fill-color":e.aerodrome}},{id:"roads_runway",type:"line",source:a,"source-layer":"roads",filter:["==","kind_detail","runway"],paint:{"line-color":e.runway,"line-width":["interpolate",["exponential",1.6],["zoom"],10,0,12,4,18,30]}},{id:"roads_taxiway",type:"line",source:a,"source-layer":"roads",minzoom:13,filter:["==","kind_detail","taxiway"],paint:{"line-color":e.runway,"line-width":["interpolate",["exponential",1.6],["zoom"],13,0,13.5,1,15,6]}},{id:"landuse_runway",type:"fill",source:a,"source-layer":"landuse",filter:["any",["in Line truncated
//# sourceMappingURL=protomaps-themes-base.js.map
+22
View File
@@ -0,0 +1,22 @@
Copyright (c) 2026, Volodymyr Agafonkin
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.
+533
View File
@@ -0,0 +1,533 @@
// Vendored from github.com/mourner/suncalc (BSD-2-Clause, see LICENSE in
// this directory) — used for public/js/sun.js's sunrise/sunset readout.
// Only getTimes (and its own helpers below) is actually used; the
// moon-position/-phase/-times exports below it are unused dead weight here,
// left in rather than hand-trimmed so this stays a straight, verifiable
// copy of the upstream file.
// shortcuts for easier to read formulas
const {PI, sin, cos, tan, asin, atan2: atan, acos, sqrt, abs, round} = Math;
const rad = PI / 180;
// date/time constants and conversions
const dayMs = 1000 * 60 * 60 * 24;
const J1970 = 2440588;
const J2000 = 2451545;
const earthRadius = 6378.14; // equatorial radius in km, for the Moon's topocentric parallax
function fromJulian(j) {
return new Date((j + 0.5 - J1970) * dayMs);
}
function toDays(date) {
return date.valueOf() / dayMs - 0.5 + J1970 - J2000;
}
// ΔT = TT − UT in seconds (Espenak & Meeus polynomial fits, good ~1900–2150). The Meeus position
// series are defined in Terrestrial Time, but SunCalc's input Dates are UT — so the position math
// runs on days-since-J2000 shifted by deltaT, while sidereal time stays on UT. ~69 s today;
// negligible for the Sun (<0.001°), real for the Moon. d only needs ~month accuracy here (ΔT
// changes <1 s/yr), so the decimal year is derived arithmetically from d rather than from the Date.
function deltaT(d) {
const y = 2000 + d / 365.2425;
let t;
if (y < 1920) { t = y - 1900; return -2.79 + t * (1.494119 + t * (-0.0598939 + t * (0.0061966 - t * 0.000197))); }
if (y < 1941) { t = y - 1920; return 21.20 + t * (0.84493 + t * (-0.076100 + t * 0.0020936)); }
if (y < 1961) { t = y - 1950; return 29.07 + t * (0.407 + t * (-1 / 233 + t / 2547)); }
if (y < 1986) { t = y - 1975; return 45.45 + t * (1.067 + t * (-1 / 260 - t / 718)); }
if (y < 2005) { t = y - 2000; return 63.86 + t * (0.3345 + t * (-0.060374 + t * (0.0017275 + t * (0.000651814 + t * 0.00002373599)))); }
if (y < 2050) { t = y - 2000; return 62.92 + t * (0.32217 + t * 0.005589); }
t = (y - 1820) / 100; return -20 + 32 * t * t - 0.5628 * (2150 - y);
}
function toDaysTT(d) {
return d + deltaT(d) / 86400;
}
// general calculations for position
// north-based clockwise azimuth in degrees (0 = N, 90 = E, 180 = S, 270 = W)
function azimuth(H, phi, dec) {
return (atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)) / rad + 540) % 360;
}
function altitude(H, phi, dec) {
return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H));
}
// Greenwich mean sidereal time, formula 12.4 of Meeus (linear term; sub-arcsec T^2/T^3 dropped)
function siderealTime(d, lw) {
return rad * (280.46061837 + 360.98564736629 * d) - lw;
}
function astroRefraction(h) {
if (h < 0) h = 0; // formula valid for positive altitudes only
// Meeus 16.4: 1.02 / tan(h + 10.26 / (h + 5.10)), h in degrees, arcmin result — folded into rad
return 0.0002967 / tan(h + 0.00312536 / (h + 0.08901179));
}
// general sun calculations
// Sun's apparent equatorial coordinates, Meeus ch. 25. d = days since J2000 (TT); t = Julian centuries.
function sunCoords(d) {
const t = d / 36525;
const L0 = rad * (280.46646 + t * (36000.76983 + t * 0.0003032)); // 25.2 geometric mean longitude
const M = rad * (357.52911 + t * (35999.05029 - t * 0.0001537)); // 25.3 mean anomaly
const sinM = sin(M);
const cosM = cos(M);
const C = rad * ((1.914602 - t * (0.004817 + t * 0.000014)) * sinM + // equation of center
(0.019993 - 0.000101 * t) * 2 * sinM * cosM + 0.000289 * sinM * (3 - 4 * sinM * sinM));
const Om = rad * (125.04 - 1934.136 * t); // longitude of the ascending node
const L = L0 + C - rad * (0.00569 + 0.00478 * sin(Om)); // apparent longitude (nutation + aberration)
// 22.2 mean obliquity + 25.8 correction for apparent position
const e = rad * (23.439291 - t * (0.0130042 + t * (0.00000016 - t * 0.000000504))) + rad * 0.00256 * cos(Om);
return {
ra: atan(cos(e) * sin(L), cos(L)), // 25.6
dec: asin(sin(e) * sin(L)) // 25.7
};
}
// calculates sun position for a given date and latitude/longitude
export function getPosition(date, lat, lng) {
const lw = rad * -lng;
const phi = rad * lat;
const d = toDays(date);
const c = sunCoords(toDaysTT(d)); // position series run on Terrestrial Time
const H = siderealTime(d, lw) - c.ra; // sidereal time stays on UT
const h = altitude(H, phi, c.dec);
return {
azimuth: azimuth(H, phi, c.dec),
// apparent (refraction-corrected) altitude in degrees
altitude: (h + astroRefraction(h)) / rad
};
}
// sun times configuration (angle, morning name, evening name)
export const times = [
[-0.833, 'sunrise', 'sunset'],
[-0.3, 'sunriseEnd', 'sunsetStart'],
[-6, 'dawn', 'dusk'],
[-12, 'nauticalDawn', 'nauticalDusk'],
[-18, 'nightEnd', 'night'],
[6, 'goldenHourEnd', 'goldenHour']
];
// adds a custom time to the times config
export function addTime(angle, riseName, setName) {
times.push([angle, riseName, setName]);
}
// calculations for sun times — Meeus ch.15 (rising, transit, setting), solving the Sun's
// local hour angle directly off the same apparent coordinates (sunCoords) and sidereal time
// used by getPosition. Day offsets d are in UT days since J2000; the position series run on TT.
const J0 = 0.0009;
function observerAngle(height) {
return -2.076 * sqrt(height) / 60;
}
// wrap an angle to (-PI, PI]
function wrapPi(a) {
return a - 2 * PI * round(a / (2 * PI));
}
// refines a transit time so the Sun's local hour angle is zero (Meeus 15.2; dH/dd ~= 2*PI/day,
// the sidereal excess and the Sun's own motion cancelling to one solar day).
function solarTransit(dt, lw) {
for (let i = 0; i < 3; i++) {
const H = wrapPi(siderealTime(dt, lw) - sunCoords(toDaysTT(dt)).ra);
dt -= H / (2 * PI);
}
return dt;
}
// time the Sun reaches altitude h0 on the given side of transit (sign -1 = rise, +1 = set);
// starts from the hour angle at transit and converges with Meeus' altitude correction (15.2).
function getSetJ(h0, dt, sign, lw, phi, decT) {
const cosH0 = (sin(h0) - sin(phi) * sin(decT)) / (cos(phi) * cos(decT));
if (cosH0 < -1 || cosH0 > 1) return NaN; // sun stays above / below this altitude all day
let d = dt + sign * acos(cosH0) / (2 * PI);
for (let i = 0; i < 2; i++) {
const c = sunCoords(toDaysTT(d));
const H = wrapPi(siderealTime(d, lw) - c.ra);
const h = altitude(H, phi, c.dec);
const sinH = cos(phi) * cos(c.dec) * sin(H);
if (abs(sinH) < 1e-6) break; // grazing the horizon — correction is ill-conditioned
d += (h - h0) / (2 * PI * sinH);
}
return d;
}
// calculates sun times for a given date, latitude/longitude, and, optionally,
// the observer height (in meters) relative to the horizon
export function getTimes(date, lat, lng, height = 0) {
const lw = rad * -lng;
const phi = rad * lat;
const dh = observerAngle(height);
// Anchor to the input date's UTC solar day regardless of its time-of-day, killing the historical
// "always pass noon" footgun where an early-morning Date returned the previous day's events:
// round to that day's noon, offset to the nearest local solar noon, then let solarTransit refine.
const d = round(toDays(date) - J0 - lw / (2 * PI));
const dt = solarTransit(d + J0 + lw / (2 * PI), lw);
const dec = sunCoords(toDaysTT(dt)).dec; // declination at transit, shared by every rise/set solve
const result = {
solarNoon: fromJulian(dt + J2000),
nadir: fromJulian(dt + J2000 - 0.5)
};
for (const [angle, riseName, setName] of times) {
const h0 = (angle + dh) * rad;
const jrise = getSetJ(h0, dt, -1, lw, phi, dec);
const jset = getSetJ(h0, dt, 1, lw, phi, dec);
// a NaN means the Sun never reaches this altitude on this day — report null, not Invalid Date
result[riseName] = Number.isNaN(jrise) ? null : fromJulian(jrise + J2000);
result[setName] = Number.isNaN(jset) ? null : fromJulian(jset + J2000);
}
// polar day/night: when the Sun never crosses the standard rise/set altitude, flag which side it
// stays on by comparing its altitude at solar noon (its daily maximum) against that threshold.
if (result.sunrise === null) {
const noonAlt = altitude(0, phi, dec);
const riseSetAlt = (times[0][0] + dh) * rad;
result.alwaysUp = noonAlt > riseSetAlt;
result.alwaysDown = noonAlt <= riseSetAlt;
}
return result;
}
// moon calculations, based on Meeus ch. 47 (truncated ELP-2000/82 series)
// Nutation in longitude (Δψ) and true obliquity of the ecliptic, both in degrees,
// from the abridged series of Meeus ch. 22 (sub-arcsecond, ample for our needs).
function nutationObliquity(t) {
const om = rad * (125.04452 - 1934.136261 * t); // longitude of the Moon's ascending node
const ls = rad * (280.4665 + 36000.7698 * t); // mean longitude of the Sun
const lm = rad * (218.3165 + 481267.8813 * t); // mean longitude of the Moon
const dpsi = (-17.20 * sin(om) - 1.32 * sin(2 * ls) - 0.23 * sin(2 * lm) + 0.21 * sin(2 * om)) / 3600;
const deps = (9.20 * cos(om) + 0.57 * cos(2 * ls) + 0.10 * cos(2 * lm) - 0.09 * cos(2 * om)) / 3600;
const eps0 = 23.439291 - t * (0.0130042 + t * (0.00000016 - t * 0.000000504)); // 22.2 mean obliquity
return {dpsi, eps: rad * (eps0 + deps)};
}
// Meeus table 47.A — periodic terms for the Moon's longitude (Σl, ×1e-6 deg) and
// distance (Σr, ×1e-3 km). Flat rows of 6: D, M, M', F, Σl, Σr.
const moonLon = new Int32Array([
0, 0, 1, 0, 6288774, -20905355,
2, 0, -1, 0, 1274027, -3699111,
2, 0, 0, 0, 658314, -2955968,
0, 0, 2, 0, 213618, -569925,
0, 1, 0, 0, -185116, 48888,
0, 0, 0, 2, -114332, -3149,
2, 0, -2, 0, 58793, 246158,
2, -1, -1, 0, 57066, -152138,
2, 0, 1, 0, 53322, -170733,
2, -1, 0, 0, 45758, -204586,
0, 1, -1, 0, -40923, -129620,
1, 0, 0, 0, -34720, 108743,
0, 1, 1, 0, -30383, 104755,
2, 0, 0, -2, 15327, 10321,
0, 0, 1, 2, -12528, 0,
0, 0, 1, -2, 10980, 79661,
4, 0, -1, 0, 10675, -34782,
0, 0, 3, 0, 10034, -23210,
4, 0, -2, 0, 8548, -21636,
2, 1, -1, 0, -7888, 24208,
2, 1, 0, 0, -6766, 30824,
1, 0, -1, 0, -5163, -8379,
1, 1, 0, 0, 4987, -16675,
2, -1, 1, 0, 4036, -12831,
2, 0, 2, 0, 3994, -10445,
4, 0, 0, 0, 3861, -11650,
2, 0, -3, 0, 3665, 14403,
0, 1, -2, 0, -2689, -7003,
2, 0, -1, 2, -2602, 0,
2, -1, -2, 0, 2390, 10056,
1, 0, 1, 0, -2348, 6322,
2, -2, 0, 0, 2236, -9884,
0, 1, 2, 0, -2120, 5751,
0, 2, 0, 0, -2069, 0,
2, -2, -1, 0, 2048, -4950,
2, 0, 1, -2, -1773, 4130,
2, 0, 0, 2, -1595, 0,
4, -1, -1, 0, 1215, -3958,
0, 0, 2, 2, -1110, 0,
3, 0, -1, 0, -892, 3258,
2, 1, 1, 0, -810, 2616,
4, -1, -2, 0, 759, -1897,
0, 2, -1, 0, -713, -2117,
2, 2, -1, 0, -700, 2354,
2, 1, -2, 0, 691, 0,
2, -1, 0, -2, 596, 0,
4, 0, 1, 0, 549, -1423,
0, 0, 4, 0, 537, -1117,
4, -1, 0, 0, 520, -1571,
1, 0, -2, 0, -487, -1739,
2, 1, 0, -2, -399, 0,
0, 0, 2, -2, -381, -4421,
1, 1, 1, 0, 351, 0,
3, 0, -2, 0, -340, 0,
4, 0, -3, 0, 330, 0,
2, -1, 2, 0, 327, 0,
0, 2, 1, 0, -323, 1165,
1, 1, -1, 0, 299, 0,
2, 0, 3, 0, 294, 0,
2, 0, -1, -2, 0, 8752
]);
// Meeus table 47.B — periodic terms for the Moon's latitude (Σb, ×1e-6 deg).
// Flat rows of 5: D, M, M', F, Σb.
const moonLat = new Int32Array([
0, 0, 0, 1, 5128122,
0, 0, 1, 1, 280602,
0, 0, 1, -1, 277693,
2, 0, 0, -1, 173237,
2, 0, -1, 1, 55413,
2, 0, -1, -1, 46271,
2, 0, 0, 1, 32573,
0, 0, 2, 1, 17198,
2, 0, 1, -1, 9266,
0, 0, 2, -1, 8822,
2, -1, 0, -1, 8216,
2, 0, -2, -1, 4324,
2, 0, 1, 1, 4200,
2, 1, 0, -1, -3359,
2, -1, -1, 1, 2463,
2, -1, 0, 1, 2211,
2, -1, -1, -1, 2065,
0, 1, -1, -1, -1870,
4, 0, -1, -1, 1828,
0, 1, 0, 1, -1794,
0, 0, 0, 3, -1749,
0, 1, -1, 1, -1565,
1, 0, 0, 1, -1491,
0, 1, 1, 1, -1475,
0, 1, 1, -1, -1410,
0, 1, 0, -1, -1344,
1, 0, 0, -1, -1335,
0, 0, 3, 1, 1107,
4, 0, 0, -1, 1021,
4, 0, -1, 1, 833,
0, 0, 1, -3, 777,
4, 0, -2, 1, 671,
2, 0, 0, -3, 607,
2, 0, 2, -1, 596,
2, -1, 1, -1, 491,
2, 0, -2, 1, -451,
0, 0, 3, -1, 439,
2, 0, 2, 1, 422,
2, 0, -3, -1, 421,
2, 1, -1, 1, -366,
2, 1, 0, 1, -351,
4, 0, 0, 1, 331,
2, -1, 1, 1, 315,
2, -2, 0, -1, 302,
0, 0, 1, 3, -283,
2, 1, 1, -1, -229,
1, 1, 0, -1, 223,
1, 1, 0, 1, 223,
0, 1, -2, -1, -220,
2, 1, -1, -1, -220,
1, 0, 1, 1, -185,
2, -1, -2, -1, 181,
0, 1, 2, 1, -177,
4, 0, -2, -1, 176,
4, -1, -1, -1, 166,
1, 0, 1, -1, -164,
4, 0, 1, -1, 132,
1, 0, -1, -1, -119,
4, -1, 0, -1, 115,
2, -2, 0, 1, 107
]);
// geocentric apparent equatorial coordinates of the Moon, Meeus ch. 47. d = days since J2000 (TT).
function moonCoords(d) {
const t = d / 36525;
// fundamental arguments (degrees), 47.1–47.6
const Lp = 218.3164477 + t * (481267.88123421 + t * (-0.0015786 + t * (1 / 538841 - t / 65194000)));
const D = 297.8501921 + t * (445267.1114034 + t * (-0.0018819 + t * (1 / 545868 - t / 113065000)));
const M = 357.5291092 + t * (35999.0502909 + t * (-0.0001536 + t / 24490000));
const Mp = 134.9633964 + t * (477198.8675055 + t * (0.0087414 + t * (1 / 69699 - t / 14712000)));
const F = 93.2720950 + t * (483202.0175233 + t * (-0.0036539 + t * (-1 / 3526000 + t / 863310000)));
const A1 = 119.75 + 131.849 * t;
const A2 = 53.09 + 479264.290 * t;
const A3 = 313.45 + 481266.484 * t;
const E = 1 - t * (0.002516 + t * 0.0000074); // eccentricity factor for solar-anomaly terms
const Dr = rad * D, Mr = rad * M, Mpr = rad * Mp, Fr = rad * F;
let sl = 0, sr = 0, sb = 0;
for (let i = 0; i < moonLon.length; i += 6) {
const m = moonLon[i + 1];
const arg = moonLon[i] * Dr + m * Mr + moonLon[i + 2] * Mpr + moonLon[i + 3] * Fr;
const f = m === 1 || m === -1 ? E : m === 2 || m === -2 ? E * E : 1;
sl += moonLon[i + 4] * f * sin(arg);
sr += moonLon[i + 5] * f * cos(arg);
}
for (let i = 0; i < moonLat.length; i += 5) {
const m = moonLat[i + 1];
const arg = moonLat[i] * Dr + m * Mr + moonLat[i + 2] * Mpr + moonLat[i + 3] * Fr;
const f = m === 1 || m === -1 ? E : m === 2 || m === -2 ? E * E : 1;
sb += moonLat[i + 4] * f * sin(arg);
}
// additive terms (Venus, Jupiter and flattening of the Earth), 47 p.342
const A1r = rad * A1, Lpr = rad * Lp;
sl += 3958 * sin(A1r) + 1962 * sin(Lpr - Fr) + 318 * sin(rad * A2);
sb += -2235 * sin(Lpr) + 382 * sin(rad * A3) + 175 * sin(A1r - Fr) + 175 * sin(A1r + Fr) +
127 * sin(Lpr - Mpr) - 115 * sin(Lpr + Mpr);
const {dpsi, eps} = nutationObliquity(t);
const l = rad * (Lp + sl / 1e6 + dpsi); // apparent ecliptic longitude
const b = rad * (sb / 1e6); // ecliptic latitude
return {
ra: atan(sin(l) * cos(eps) - tan(b) * sin(eps), cos(l)), // 13.3
dec: asin(sin(b) * cos(eps) + cos(b) * sin(eps) * sin(l)), // 13.4
dist: 385000.56 + sr / 1000 // distance to the Moon in km
};
}
export function getMoonPosition(date, lat, lng) {
const lw = rad * -lng;
const phi = rad * lat;
const d = toDays(date);
const c = moonCoords(toDaysTT(d)); // position series run on Terrestrial Time
const H = siderealTime(d, lw) - c.ra; // sidereal time stays on UT
// geocentric parallax (Meeus ch.40) lowers the moon along its vertical circle, leaving
// azimuth unchanged; sin(parallax) = (Earth radius / distance) * cos(geocentric altitude).
const hGeo = altitude(H, phi, c.dec);
const h = hGeo - asin(earthRadius / c.dist * cos(hGeo));
// parallactic angle, Meeus 14.1
const pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H));
return {
azimuth: azimuth(H, phi, c.dec),
// apparent (refraction-corrected) altitude in degrees
altitude: (h + astroRefraction(h)) / rad,
distance: c.dist,
parallacticAngle: pa / rad
};
}
// moon illumination parameters, Meeus ch. 48 (and idlastro's mphase.pro)
export function getMoonIllumination(date = new Date()) {
const d = toDaysTT(toDays(date));
const s = sunCoords(d);
const m = moonCoords(d);
const sdist = 149598000; // distance from Earth to Sun in km
const phi = acos(sin(s.dec) * sin(m.dec) + cos(s.dec) * cos(m.dec) * cos(s.ra - m.ra));
const inc = atan(sdist * sin(phi), m.dist - sdist * cos(phi));
const angle = atan(cos(s.dec) * sin(s.ra - m.ra), sin(s.dec) * cos(m.dec) -
cos(s.dec) * sin(m.dec) * cos(s.ra - m.ra));
const waxing = angle < 0; // bright limb leads → illuminated fraction is growing (new → full)
return {
// illuminated fraction, 0 (new) → 1 (full); reaches the exact extrema only at perfect
// syzygy (eclipses), so a "full" moon typically peaks a hair under 1 — this is correct
fraction: (1 + cos(inc)) / 2,
// phase, 0 → 1: 0 new, 0.25 first quarter, 0.5 full, 0.75 last quarter (waxing for phase < 0.5)
phase: 0.5 + 0.5 * inc * (waxing ? -1 : 1) / PI,
// position angle of the bright limb, degrees (v2: all angles emitted in degrees) — subtract
// getMoonPosition().parallacticAngle, also degrees, to get the zenith-relative tilt
angle: angle / rad,
waxing // true while the Moon is waxing (new → full), false while waning (full → new)
};
}
function hoursLater(date, h) {
return new Date(date.valueOf() + h * dayMs / 24);
}
// height of the moon's upper limb above the rise/set horizon (deg): topocentric centre altitude plus
// the moon's semidiameter (0.2725 * equatorial horizontal parallax, so it tracks distance: ~0.25° at
// apogee, ~0.28° at perigee) plus the residual horizon refraction our model under-bends (~0.09°,
// tuned vs USNO). Crossing zero == upper-limb rise/set, the USNO convention.
function moonHeight(date, lat, lng) {
const p = getMoonPosition(date, lat, lng);
return p.altitude + 0.2725 * asin(earthRadius / p.distance) / rad + 0.09;
}
// polish a crossing time (ms): the quadratic sampler's parabola root sits up to ~0.2° off the true
// altitude curve, so Newton-refine against the real moonHeight. Two central-difference steps drop the
// mean error from ~0.65 to ~0.28 min; more don't help (near grazing dh/dt is small either way).
function refineMoonCross(tMs, lat, lng) {
for (let i = 0; i < 2; i++) {
const h = moonHeight(new Date(tMs), lat, lng);
const dh = (moonHeight(new Date(tMs + 30000), lat, lng) - moonHeight(new Date(tMs - 30000), lat, lng)) / 60000;
tMs -= h / dh; // dh is degrees per ms, so h/dh is ms
}
return tMs;
}
export function getMoonTimes(date, lat, lng) {
// scan the UTC calendar day of the given date; the date is treated as a UTC instant like
// everywhere else in the API. For a local-civil-day window, pass a date at local midnight.
const t = new Date(date);
t.setUTCHours(0, 0, 0, 0);
let h0 = moonHeight(t, lat, lng);
let rise, set, hMax = h0;
// go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set)
for (let i = 1; i <= 24; i += 2) {
const h1 = moonHeight(hoursLater(t, i), lat, lng);
const h2 = moonHeight(hoursLater(t, i + 1), lat, lng);
hMax = Math.max(hMax, h1, h2);
const a = (h0 + h2) / 2 - h1;
const b = (h2 - h0) / 2;
const xe = -b / (2 * a);
const d = b * b - 4 * a * h1;
let roots = 0, x1 = 0, x2 = 0;
const ye = (a * xe + b) * xe + h1;
if (d >= 0) {
const dx = sqrt(d) / (abs(a) * 2);
x1 = xe - dx;
x2 = xe + dx;
if (abs(x1) <= 1) roots++;
if (abs(x2) <= 1) roots++;
if (x1 < -1) x1 = x2;
}
if (roots === 1) {
if (h0 < 0) rise = i + x1;
else set = i + x1;
} else if (roots === 2) {
rise = i + (ye < 0 ? x2 : x1);
set = i + (ye < 0 ? x1 : x2);
}
if (rise !== undefined && set !== undefined) break;
h0 = h2;
}
const result = {};
// compare against undefined, not truthiness: a crossing at exactly hour 0 (midnight) is a real
// event whose numeric value is 0, which a truthy check would wrongly treat as "no event".
if (rise !== undefined) result.rise = new Date(refineMoonCross(hoursLater(t, rise).valueOf(), lat, lng));
if (set !== undefined) result.set = new Date(refineMoonCross(hoursLater(t, set).valueOf(), lat, lng));
// no crossing all day: flag which side the moon stays on by testing its highest sampled height
// against the rise/set threshold (already baked into moonHeight), setting both like getTimes does
if (rise === undefined && set === undefined) {
result.alwaysUp = hMax > 0;
result.alwaysDown = hMax <= 0;
}
return result;
}
+4
View File
@@ -0,0 +1,4 @@
{
"label": "Test plugin",
"command": "./run.sh"
}
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
# A fixture plugin for test_app.rb's /api/plugins route tests — no
# network, just echoes a single fixed point back as GeoJSON so those tests
# stay deterministic and offline like the rest of the suite.
echo '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"name":"Test POI"},"geometry":{"type":"Point","coordinates":[17.0,48.0]}}]}'
+196
View File
@@ -18,11 +18,53 @@ class AppTest < Minitest::Test
assert_includes response.body, "livetrack-panel" assert_includes response.body, "livetrack-panel"
end end
# Every public/js/*.js module map.js (or something it imports) can reach
# needs its own versioned importmap entry (views/layout.erb) or it skips
# ASSET_VERSION's whole cache-busting story — easy to forget when adding a
# new module, since the app still works fine locally either way (a plain
# unmapped import just resolves straight to the unversioned file).
# map.js itself is excluded: it's the one entry point loaded directly by
# its own <script> tag, not imported by anything, so it has no importmap
# entry of its own by design.
def test_every_own_js_module_has_a_versioned_importmap_entry
response = request.get("/")
modules = Dir.glob(File.join(__dir__, "..", "public", "js", "*.js")).map { |path| File.basename(path) } - ["map.js"]
modules.each do |name|
assert_match(%r{"/js/#{Regexp.escape(name)}":\s*"/js/#{Regexp.escape(name)}\?v=\d+"}, response.body, "#{name} is missing from the importmap")
end
end
def test_offline_tiles_reports_unavailable_when_no_pmtiles_present def test_offline_tiles_reports_unavailable_when_no_pmtiles_present
response = request.get("/api/offline-tiles") response = request.get("/api/offline-tiles")
assert_equal({ "available" => false }, json_body(response)) assert_equal({ "available" => false }, json_body(response))
end end
def test_hiking_trails_reports_no_countries_when_none_extracted_yet
response = request.get("/api/hiking-trails")
assert_equal({ "countries" => [] }, json_body(response))
end
def test_hiking_trails_file_404s_for_a_country_with_no_extract
assert_equal 404, request.get("/tiles/hiking_trails/SK.geojson").status
end
def test_hiking_trails_file_404s_for_a_malformed_country_code
assert_equal 404, request.get("/tiles/hiking_trails/../../etc/passwd.geojson").status
end
def test_kiwix_reports_unavailable_when_no_url_configured
response = request.get("/api/kiwix")
assert_equal({ "available" => false, "url" => "" }, json_body(response))
end
def test_kiwix_proxy_404s_when_no_url_configured
assert_equal 404, request.get("/kiwix/search").status
end
def test_kiwix_nearby_404s_when_no_url_configured
assert_equal 404, request.get("/api/kiwix/nearby", params: { south: "48", west: "17", north: "48.1", east: "17.1" }).status
end
def test_gnss_position_unavailable_with_no_fix def test_gnss_position_unavailable_with_no_fix
response = request.get("/api/gnss/position", **logged_in_env) response = request.get("/api/gnss/position", **logged_in_env)
assert_equal({ "available" => false }, json_body(response)) assert_equal({ "available" => false }, json_body(response))
@@ -40,6 +82,12 @@ class AppTest < Minitest::Test
assert_equal 401, request.delete("/api/gpx/file/x.gpx").status assert_equal 401, request.delete("/api/gpx/file/x.gpx").status
assert_equal 401, request.delete("/api/gpx/folder/x").status assert_equal 401, request.delete("/api/gpx/folder/x").status
assert_equal 401, request.post("/api/gpx/move").status assert_equal 401, request.post("/api/gpx/move").status
assert_equal 401, request.post("/api/plugins/test-plugin/run").status
assert_equal 401, request.post("/api/offline-tiles/build").status
assert_equal 401, request.post("/api/terrain-tiles/build").status
assert_equal 401, request.delete("/api/offline-tiles").status
assert_equal 401, request.delete("/api/offline-tiles/cache/SK").status
assert_equal 401, request.delete("/api/terrain-tiles").status
end end
# --- GPX/FIT upload and the tree --- # --- GPX/FIT upload and the tree ---
@@ -281,6 +329,154 @@ class AppTest < Minitest::Test
assert_equal 404, response.status assert_equal 404, response.status
end end
# --- Import plugins (lib/maptool/plugins.rb) ---
def test_plugins_lists_whatever_is_on_disk
response = request.get("/api/plugins")
assert_equal 200, response.status
assert_equal [{ "name" => "test-plugin", "label" => "Test plugin" }], json_body(response)
end
def test_plugins_run_saves_the_output_as_a_new_geojson_file
response = request.post(
"/api/plugins/test-plugin/run",
params: { south: "48.0", west: "17.0", north: "48.1", east: "17.1" },
**logged_in_env,
)
assert_equal 200, response.status
body = json_body(response)
assert_match(/\Atest-plugin_48\.05_17\.05_\d{6}_\d{4}\.geojson\z/, body["path"])
saved = json_body(request.get("/api/gpx/file/#{body["path"]}"))
assert_equal "Test POI", saved["features"][0]["properties"]["name"]
end
def test_plugins_run_requires_a_bbox
response = request.post("/api/plugins/test-plugin/run", **logged_in_env)
assert_equal 400, response.status
end
def test_plugins_run_unknown_plugin_is_502
response = request.post(
"/api/plugins/nope/run",
params: { south: "48.0", west: "17.0", north: "48.1", east: "17.1" },
**logged_in_env,
)
assert_equal 502, response.status
end
# --- offline regions ---
def test_offline_regions_lists_available_and_selected
body = json_body(request.get("/api/offline-regions"))
assert_operator body["available"].size, :>, 0
assert_includes body["available"], { "code" => "SK", "name" => "Slovakia" }
assert_equal [], body["selected"]
end
def test_offline_regions_post_requires_login
assert_equal 401, request.post("/api/offline-regions").status
end
def test_offline_regions_post_saves_the_selection
response = request.post("/api/offline-regions", params: { "codes" => %w[SK AT] }, **logged_in_env)
assert_equal 200, response.status
assert_equal %w[SK AT], json_body(request.get("/api/offline-regions"))["selected"]
end
def test_offline_regions_post_rejects_an_unknown_code
response = request.post("/api/offline-regions", params: { "codes" => ["XX"] }, **logged_in_env)
assert_equal 400, response.status
end
# --- pmtiles regeneration ---
#
# The full build (network + go-pmtiles) is covered in isolation, with
# fakes injected, by test_pmtiles_builder.rb — same "keep this offline"
# reasoning as the rest of this file. What's route-specific and worth
# covering here is the empty-selection validation and the
# 409-while-running guard, neither of which needs a real build to
# actually run.
def test_offline_tiles_build_status_defaults_to_idle
assert_equal({ "state" => "idle" }, json_body(request.get("/api/offline-tiles/build-status")))
assert_equal({ "state" => "idle" }, json_body(request.get("/api/terrain-tiles/build-status")))
end
def test_check_update_is_null_before_any_build
assert_nil json_body(request.get("/api/offline-tiles/check-update"))["update_available"]
assert_nil json_body(request.get("/api/terrain-tiles/check-update"))["update_available"]
end
def test_offline_tiles_build_is_409_with_no_selection
response = request.post("/api/offline-tiles/build", **logged_in_env)
assert_equal 409, response.status
end
def test_terrain_tiles_build_is_409_with_no_selection
response = request.post("/api/terrain-tiles/build", **logged_in_env)
assert_equal 409, response.status
end
# download_extract blocks on a Queue, called directly (not through the
# route, which has no way to inject a fake) so the build is
# deterministically still "running" when the route call below happens.
def test_offline_tiles_build_is_409_when_one_is_already_running
Maptool::PmtilesBuilder.set_selected_regions(Maptool::App::DATA_DIR, ["SK"])
gate = Queue.new
thread = Maptool::PmtilesBuilder.build_offline(data_dir: Maptool::App::DATA_DIR, download_extract: ->(_url, _dest) { gate.pop })
response = request.post("/api/offline-tiles/build", **logged_in_env)
assert_equal 409, response.status
ensure
gate.push("unused")
thread&.join
end
def test_offline_tiles_delete_is_ok_when_nothing_was_built
assert_equal 200, request.delete("/api/offline-tiles", **logged_in_env).status
end
def test_offline_tiles_delete_removes_the_file_and_cache
path = File.join(Maptool::App::DATA_DIR, "offline.pmtiles")
cache_dir = File.join(Maptool::App::DATA_DIR, "geofabrik_cache")
File.write(path, "fake")
FileUtils.mkdir_p(cache_dir)
File.write(File.join(cache_dir, "SK.osm.pbf"), "fake")
response = request.delete("/api/offline-tiles", **logged_in_env)
assert_equal 200, response.status
refute_path_exists path
refute_path_exists cache_dir
end
def test_offline_tiles_cache_lists_and_deletes_one_country
cache_dir = File.join(Maptool::App::DATA_DIR, "geofabrik_cache")
FileUtils.mkdir_p(cache_dir)
File.write(File.join(cache_dir, "SK.osm.pbf"), "fake")
extracts = json_body(request.get("/api/offline-tiles/cache"))["extracts"]
assert_equal ["SK"], extracts.map { |e| e["code"] }
response = request.delete("/api/offline-tiles/cache/SK", **logged_in_env)
assert_equal 200, response.status
refute_path_exists File.join(cache_dir, "SK.osm.pbf")
ensure
FileUtils.remove_entry(cache_dir) if cache_dir && Dir.exist?(cache_dir)
end
def test_offline_tiles_delete_is_409_when_a_build_is_running
Maptool::PmtilesBuilder.set_selected_regions(Maptool::App::DATA_DIR, ["SK"])
gate = Queue.new
thread = Maptool::PmtilesBuilder.build_offline(data_dir: Maptool::App::DATA_DIR, download_extract: ->(_url, _dest) { gate.pop })
assert_equal 409, request.delete("/api/offline-tiles", **logged_in_env).status
ensure
gate.push("unused")
thread&.join
end
# --- LiveTrack webhook --- # --- LiveTrack webhook ---
def test_livetrack_webhook_requires_the_configured_secret def test_livetrack_webhook_requires_the_configured_secret
+7
View File
@@ -14,6 +14,11 @@ require "json"
ENV["MAPTOOL_DATA_DIR"] = Dir.mktmpdir("maptool-test-data") ENV["MAPTOOL_DATA_DIR"] = Dir.mktmpdir("maptool-test-data")
Minitest.after_run { FileUtils.remove_entry(ENV["MAPTOOL_DATA_DIR"]) } Minitest.after_run { FileUtils.remove_entry(ENV["MAPTOOL_DATA_DIR"]) }
# A fixture plugin (test/fixtures/plugins/test-plugin), not the real
# plugins/ — keeps /api/plugins route tests offline/deterministic instead
# of actually running plugins/overpass-pois against the real Overpass API.
ENV["MAPTOOL_PLUGINS_DIR"] = File.join(__dir__, "fixtures", "plugins")
$LOAD_PATH.unshift(File.expand_path("../lib", __dir__)) $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
require_relative "../app" require_relative "../app"
@@ -61,6 +66,8 @@ module AppTestHelper
def teardown def teardown
FileUtils.rm_rf(Dir.glob(File.join(Maptool::App::DATA_DIR, "gpx", "*"))) FileUtils.rm_rf(Dir.glob(File.join(Maptool::App::DATA_DIR, "gpx", "*")))
File.write(File.join(Maptool::App::DATA_DIR, "livetrack.json"), "[]") File.write(File.join(Maptool::App::DATA_DIR, "livetrack.json"), "[]")
FileUtils.rm_f(File.join(Maptool::App::DATA_DIR, "offline_regions.json"))
Maptool::PmtilesBuilder.reset!
super super
end end
+125
View File
@@ -0,0 +1,125 @@
require_relative "test_helper"
require "maptool/hiking_trails"
# No real osmium calls — extract() is a thin subprocess-plus-parse wrapper
# (same "not independently tested" reasoning OverpassPois.fetch gets), but
# parse_opl is pure text in, GeoJSON out, and that's the part actually worth
# protecting: the OPL escaping rules and the way-id -> relation-member
# stitching are easy to get subtly wrong and osmium isn't installed in every
# environment this test suite runs in.
class HikingTrailsTest < Minitest::Test
def test_parse_opl_builds_a_multilinestring_from_member_way_geometry
opl = <<~OPL
w1 Thighway=path Nn10x20.087y49.179,n11x20.088y49.18
w2 Thighway=path Nn11x20.088y49.18,n12x20.089y49.181
r1 Troute=hiking,type=route,name=Rysy Mw1@,w2@
OPL
features = Maptool::HikingTrails.parse_opl(opl)["features"]
assert_equal 1, features.size
feature = features.first
assert_equal "MultiLineString", feature["geometry"]["type"]
assert_equal [[[20.087, 49.179], [20.088, 49.18]], [[20.088, 49.18], [20.089, 49.181]]], feature["geometry"]["coordinates"]
assert_equal "Rysy", feature["properties"]["name"]
end
def test_parse_opl_skips_relations_that_are_not_route_hiking
opl = <<~OPL
w1 Thighway=path Nn10x20.087y49.179,n11x20.088y49.18
r1 Ttype=multipolygon Mw1@outer
OPL
assert_empty Maptool::HikingTrails.parse_opl(opl)["features"]
end
def test_parse_opl_falls_back_to_description_when_there_is_no_name
opl = <<~OPL
w1 Thighway=path Nn10x20.087y49.179,n11x20.088y49.18
r1 Troute=hiking,type=route,description=Rázc.%20%pri%20%Žabom%20%potoku%20%-%20%Rysy Mw1@
OPL
feature = Maptool::HikingTrails.parse_opl(opl)["features"].first
assert_equal "Rázc. pri Žabom potoku - Rysy", feature["properties"]["name"]
end
def test_parse_opl_unescapes_commas_and_equals_in_tag_values
opl = <<~OPL
w1 Thighway=path Nn10x20.087y49.179,n11x20.088y49.18
r1 Troute=hiking,type=route,name=Salt%2c%%20%Pepper%3d%Co Mw1@
OPL
feature = Maptool::HikingTrails.parse_opl(opl)["features"].first
assert_equal "Salt, Pepper=Co", feature["properties"]["name"]
end
def test_parse_opl_carries_over_colour_network_operator_ref
opl = <<~OPL
w1 Thighway=path Nn10x20.087y49.179,n11x20.088y49.18
r1 Troute=hiking,type=route,name=Trail,colour=red,network=rwn,operator=KST,ref=0933 Mw1@
OPL
properties = Maptool::HikingTrails.parse_opl(opl)["features"].first["properties"]
assert_equal "red", properties["colour"]
assert_equal "rwn", properties["network"]
assert_equal "KST", properties["operator"]
assert_equal "0933", properties["ref"]
end
def test_parse_opl_computes_distance_from_member_way_geometry
# Roughly 111.2m per 0.001 degree of latitude at the equator.
opl = <<~OPL
w1 Thighway=path Nn10x0.0y0.0,n11x0.0y0.001
r1 Troute=hiking,type=route,name=Trail Mw1@
OPL
distance = Maptool::HikingTrails.parse_opl(opl)["features"].first["properties"]["distance_meters"]
assert_in_delta 111.2, distance, 1.0
end
def test_parse_opl_drops_a_relation_whose_member_ways_are_all_missing
opl = <<~OPL
r1 Troute=hiking,type=route,name=Ghost Mw999@
OPL
assert_empty Maptool::HikingTrails.parse_opl(opl)["features"]
end
def test_parse_opl_carries_the_osm_relation_id_for_cross_country_dedup
opl = <<~OPL
w1 Thighway=path Nn10x20.087y49.179,n11x20.088y49.18
r1246205 Troute=hiking,type=route,name=Trail Mw1@
OPL
feature = Maptool::HikingTrails.parse_opl(opl)["features"].first
assert_equal 1246205, feature["properties"]["id"]
end
def test_parse_opl_rounds_coordinates_to_5_decimal_places
opl = <<~OPL
w1 Thighway=path Nn10x20.0876543210y49.1791234567,n11x20.0880000001y49.1800000009
r1 Troute=hiking,type=route,name=Trail Mw1@
OPL
coords = Maptool::HikingTrails.parse_opl(opl)["features"].first["geometry"]["coordinates"]
assert_equal [[[20.08765, 49.17912], [20.088, 49.18]]], coords
end
def test_parse_opl_ignores_a_dangling_member_reference_but_keeps_the_rest
opl = <<~OPL
w1 Thighway=path Nn10x20.087y49.179,n11x20.088y49.18
r1 Troute=hiking,type=route,name=Trail Mw1@,w999@
OPL
features = Maptool::HikingTrails.parse_opl(opl)["features"]
assert_equal 1, features.size
assert_equal 1, features.first["geometry"]["coordinates"].size
end
end
Loaded 100 of 107 files, more files were not shown because too many files have changed in this diff. Show more