From 04689a29bd40ff94207dc872452e318ff9573e86 Mon Sep 17 00:00:00 2001 From: owain Date: Tue, 9 Jun 2026 11:52:52 +0100 Subject: [PATCH] Cut Garmin sync API volume; dashboard/health/records/UI improvements Garmin Connect sync: - Incremental syncs now re-fetch only a 1-day buffer (yesterday + today) instead of the full lookback window every run. Full lookback applies on the first sync only. Cuts steady-state API calls ~10x. - Beat interval is now configurable via GARMIN_SYNC_INTERVAL_MINUTES and surfaced to the UI; the sync toggle is relabelled to the real cadence. Frontend: - Collapsible sidebar; clearer logged-in user + role display. - Unified Body Battery colouring between dashboard and health (shared util). - Sleep score trend chart on health page. - Segments + medals on the dashboard's most-recent activity. - Segments tab on the Records page. Repo hygiene: add .gitignore, untrack committed __pycache__/*.pyc. Co-Authored-By: Claude Opus 4.8 --- .gitignore | 14 + CLAUDE.md | 12 +- .../app/__pycache__/__init__.cpython-313.pyc | Bin 143 -> 0 bytes backend/app/__pycache__/main.cpython-313.pyc | Bin 10495 -> 0 bytes .../__pycache__/activities.cpython-313.pyc | Bin 14827 -> 0 bytes .../api/__pycache__/routes.cpython-313.pyc | Bin 24033 -> 0 bytes backend/app/api/garmin_sync.py | 5 + backend/app/core/config.py | 2 + .../models/__pycache__/user.cpython-313.pyc | Bin 11572 -> 0 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 152 -> 0 bytes .../__pycache__/route_matcher.cpython-313.pyc | Bin 15426 -> 0 bytes .../wellness_parser.cpython-313.pyc | Bin 13990 -> 0 bytes backend/app/services/garmin_connect_sync.py | 51 +- .../workers/__pycache__/tasks.cpython-313.pyc | Bin 30646 -> 0 bytes backend/app/workers/tasks.py | 3 +- frontend/package-lock.json | 3468 +++++++++++++++++ frontend/src/components/ui/Layout.jsx | 80 +- frontend/src/pages/DashboardPage.jsx | 106 +- frontend/src/pages/HealthPage.jsx | 47 +- frontend/src/pages/ProfilePage.jsx | 18 +- frontend/src/pages/RecordsPage.jsx | 99 +- frontend/src/utils/bodyBattery.js | 36 + 22 files changed, 3832 insertions(+), 109 deletions(-) create mode 100644 .gitignore delete mode 100644 backend/app/__pycache__/__init__.cpython-313.pyc delete mode 100644 backend/app/__pycache__/main.cpython-313.pyc delete mode 100644 backend/app/api/__pycache__/activities.cpython-313.pyc delete mode 100644 backend/app/api/__pycache__/routes.cpython-313.pyc delete mode 100644 backend/app/models/__pycache__/user.cpython-313.pyc delete mode 100644 backend/app/services/__pycache__/__init__.cpython-313.pyc delete mode 100644 backend/app/services/__pycache__/route_matcher.cpython-313.pyc delete mode 100644 backend/app/services/__pycache__/wellness_parser.cpython-313.pyc delete mode 100644 backend/app/workers/__pycache__/tasks.cpython-313.pyc create mode 100644 frontend/package-lock.json create mode 100644 frontend/src/utils/bodyBattery.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..46220e2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Python +__pycache__/ +*.py[cod] + +# Node / frontend build artifacts +node_modules/ +dist/ + +# Environment / secrets +.env +.env.* + +# OS noise +.DS_Store diff --git a/CLAUDE.md b/CLAUDE.md index baa7048..c6be4a9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -38,6 +38,8 @@ There are no automated tests. Verification is done by running the app and observ The Gitea Actions workflow (`.gitea/workflows/build.yml`) auto-builds and pushes images on push to `main`. Deployment machines only need `docker-compose.deploy.yml` and `nginx.conf`. +`./deploy.sh ""` is the normal dev loop here: it commits everything, pushes to `main` (triggering the image build), and stops the running stack in `../milevault_docker`. After the build finishes, run `docker compose pull && docker compose up -d` there. This matches the repo rule: fix files in `~/milevault`, push to git — never patch the running containers in `~/milevault_docker`. + ```bash # Rebuild and restart from source: docker compose build --no-cache @@ -66,13 +68,13 @@ docker compose -f docker-compose.deploy.yml up -d - `main.py` — FastAPI app, DB init on startup (creates tables, seeds admin user, creates TimescaleDB hypertable) - `core/` — `config.py` (pydantic-settings from env), `database.py` (async engine for FastAPI + sync engine for Celery), `security.py` (JWT, bcrypt) -- `api/` — routers: `auth`, `activities`, `routes`, `health`, `records`, `upload`, `profile`, `garmin_sync` -- `models/user.py` — all SQLAlchemy models: `User`, `Activity`, `ActivityDataPoint`, `ActivityLap`, `NamedRoute`, `RouteSegment`, `PersonalRecord`, `HealthMetric`, `WeightLog`, `GarminConnectConfig` +- `api/` — routers: `auth`, `activities`, `routes`, `health`, `records`, `upload`, `profile`, `garmin_sync`, `users`, `segments` +- `models/user.py` — all SQLAlchemy models: `User`, `Activity`, `ActivityDataPoint`, `ActivityLap`, `NamedRoute`, `Segment`, `SegmentEffort`, `PersonalRecord`, `HealthMetric`, `WeightLog`, `GarminConnectConfig` (the old `RouteSegment` model was removed in the segments rewrite; a new GPS-geometry `Segment`/`SegmentEffort` pair replaces it) - `services/fit_parser.py` — parses Garmin FIT and GPX files; handles raw FIT timestamps (FIT epoch offset 631065600s) and semicircle→degree conversion - `services/wellness_parser.py` — parses Garmin wellness FIT files (metrics, sleep, HRV, SPO2, etc.) - `services/route_matcher.py` — bounding-box pre-filter + DTW (Dynamic Time Warping) for GPS track similarity - `services/garmin_connect_sync.py` — Garmin Connect API integration; `authenticate_garmin()` tries stored OAuth token first, falls back to email/password; Garmin credentials stored Fernet-encrypted using `SECRET_KEY` as the key -- `workers/tasks.py` — Celery tasks: `process_activity_file`, `parse_wellness_fit`, `detect_route`, `compute_personal_records`, `process_garmin_health_zip`, `sync_all_garmin_connect` (beat-scheduled) +- `workers/tasks.py` — Celery tasks: `process_activity_file`, `parse_wellness_fit`, `detect_route`, `compute_personal_records`, `match_segment`, `match_activity_segments`, `process_garmin_health_zip`, `sync_garmin_connect_user`, `sync_all_garmin_connect` (beat-scheduled), `recalculate_hr_zones_for_user` ### Key design decisions @@ -91,8 +93,8 @@ docker compose -f docker-compose.deploy.yml up -d - `utils/api.js` — Axios instance with JWT interceptor and 401→redirect handler - TanStack Query (`@tanstack/react-query`) handles all server-state fetching and caching; Zustand is used only for auth state - `utils/format.js` — shared formatting helpers: `formatDuration`, `formatPace`, `formatDistance`, `formatCadence`, `hrZoneColor`, `sportIcon`, `sportColor`, etc. -- `pages/` — one file per route; includes `SegmentsPage` for route segment management -- `components/activity/` — `ActivityMap` (Leaflet), `MetricTimeline` (Recharts), `HRZoneBar`, `LapTable` +- `pages/` — one file per route: `Dashboard`, `Activities`, `ActivityDetail`, `Routes`, `Records`, `Health`, `Upload`, `Profile`, `Users`, `Login` +- `components/activity/` — `ActivityMap` (Leaflet), `MetricTimeline` (Recharts), `HRZoneBar`, `LapTable`, `SegmentsPanel` (per-activity segment efforts) - `components/ui/RouteMiniMap` — small Leaflet map used in route/segment cards The Vite dev server proxies `/api` to `http://backend:8000` (for use inside the Docker Compose network). The production build bakes `VITE_API_URL` at build time. diff --git a/backend/app/__pycache__/__init__.cpython-313.pyc b/backend/app/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 978b0b44fac65843a12878a1e4dfda6d524eb5e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 143 zcmey&%ge<81i2w9Ss?l`h=2h`DC08=kTI1Zok5e)ZzV$!6Oi{ABy~$qKO;XkRX-&^ zIXksTKQ}WcwJfnTr$j#~5h#$CqMuk$pdTNfnU`4-AFo$Xd5gm)H$SB`C)KWq6{sC# Rd@+dek(rT^v4|PS0suDaAZh>r diff --git a/backend/app/__pycache__/main.cpython-313.pyc b/backend/app/__pycache__/main.cpython-313.pyc deleted file mode 100644 index 05011ed7498890a78687c84ebbe887e3bcf0bf4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10495 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 NxRmHJmr``r{ug1L9H#&P diff --git a/backend/app/api/__pycache__/activities.cpython-313.pyc b/backend/app/api/__pycache__/activities.cpython-313.pyc deleted file mode 100644 index 1fd0da4e024077a1e74f2752b031af8bb9f596dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14827 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 diff --git a/backend/app/api/garmin_sync.py b/backend/app/api/garmin_sync.py index 967037b..65e5362 100644 --- a/backend/app/api/garmin_sync.py +++ b/backend/app/api/garmin_sync.py @@ -7,6 +7,7 @@ from datetime import datetime from app.core.database import get_db from app.core.security import get_current_user +from app.core.config import settings from app.models.user import User, GarminConnectConfig router = APIRouter() @@ -27,6 +28,7 @@ class GarminConfigOut(BaseModel): sync_activities: bool sync_wellness: bool sync_lookback_days: int + sync_interval_minutes: int # how often the automatic sync runs last_sync_at: Optional[datetime] last_sync_status: Optional[str] connected: bool @@ -48,6 +50,7 @@ async def get_config( return GarminConfigOut( email="", sync_enabled=False, sync_activities=True, sync_wellness=True, sync_lookback_days=30, + sync_interval_minutes=settings.garmin_sync_interval_minutes, last_sync_at=None, last_sync_status=None, connected=False, ) return GarminConfigOut( @@ -56,6 +59,7 @@ async def get_config( sync_activities=cfg.sync_activities, sync_wellness=cfg.sync_wellness, sync_lookback_days=cfg.sync_lookback_days if cfg.sync_lookback_days is not None else 30, + sync_interval_minutes=settings.garmin_sync_interval_minutes, last_sync_at=cfg.last_sync_at, last_sync_status=cfg.last_sync_status, connected=True, @@ -121,6 +125,7 @@ async def save_config( sync_activities=cfg.sync_activities, sync_wellness=cfg.sync_wellness, sync_lookback_days=cfg.sync_lookback_days if cfg.sync_lookback_days is not None else 30, + sync_interval_minutes=settings.garmin_sync_interval_minutes, last_sync_at=cfg.last_sync_at, last_sync_status=cfg.last_sync_status, connected=True, diff --git a/backend/app/core/config.py b/backend/app/core/config.py index 55b4ec2..23652f9 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -22,6 +22,8 @@ class Settings(BaseSettings): pocketid_client_id: Optional[str] = Field(None, env="POCKETID_CLIENT_ID") pocketid_client_secret: Optional[str] = Field(None, env="POCKETID_CLIENT_SECRET") pocketid_allowed_group: Optional[str] = Field(None, env="POCKETID_ALLOWED_GROUP") + # Garmin Connect — how often the beat scheduler runs the automatic sync + garmin_sync_interval_minutes: int = Field(30, env="GARMIN_SYNC_INTERVAL_MINUTES") # Files file_store_path: str = Field("/data/files", env="FILE_STORE_PATH") # Environment diff --git a/backend/app/models/__pycache__/user.cpython-313.pyc b/backend/app/models/__pycache__/user.cpython-313.pyc deleted file mode 100644 index 13c219ae8069b18dbe56c6f51c54f3c3b56a79a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11572 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 K{Rh6|asM0fak6Lt diff --git a/backend/app/services/garmin_connect_sync.py b/backend/app/services/garmin_connect_sync.py index eb4e945..50a0b64 100644 --- a/backend/app/services/garmin_connect_sync.py +++ b/backend/app/services/garmin_connect_sync.py @@ -17,6 +17,13 @@ from typing import Optional, Tuple logger = logging.getLogger(__name__) +# On incremental syncs (last_sync_at is set) only re-fetch the last day or two +# rather than the full configured lookback window. A 1-day buffer means the +# window is "yesterday + today", which catches late-arriving / revised data +# (sleep finalised next morning, body battery, manual weight, HRV status, the +# midnight boundary) without re-pulling the same N days on every scheduled run. +INCREMENTAL_BUFFER_DAYS = 1 + # ── Password encryption ───────────────────────────────────────────────────── @@ -78,9 +85,12 @@ def sync_activities(garmin, user_id: int, since: Optional[datetime], List activities from Garmin Connect, skip any already in the DB, download FIT ZIPs for new ones, and queue them for processing. - lookback_days controls the start date on every sync: - -1 → full history back to 2010 on first sync, then incremental (since-1d) - N → incremental (since-1d) when since is set; else last N days on first sync + lookback_days only sets the window on the FIRST sync (since is None): + -1 → full history back to 2010 + N → last N days + Every subsequent (incremental) sync re-fetches only the last + INCREMENTAL_BUFFER_DAYS days, regardless of lookback_days, to avoid + re-pulling the whole window on every scheduled run. Returns the number of new activities queued. """ import time @@ -88,15 +98,11 @@ def sync_activities(garmin, user_id: int, since: Optional[datetime], from app.models.user import Activity from sqlalchemy import select, func - if lookback_days == -1: - # All-time: full pull on first sync, incremental thereafter - start_date = (since - timedelta(days=1)).date() if since else date(2010, 1, 1) - elif since: - # Use whichever is earlier: one day before last sync OR the configured lookback - # window. This ensures increasing lookback_days actually fetches older data. - incremental = (since - timedelta(days=1)).date() - lookback = date.today() - timedelta(days=max(lookback_days, 1)) - start_date = min(incremental, lookback) + if since: + # Incremental: just the recent buffer (cheap, dedup skips already-imported) + start_date = (since - timedelta(days=INCREMENTAL_BUFFER_DAYS)).date() + elif lookback_days == -1: + start_date = date(2010, 1, 1) else: start_date = date.today() - timedelta(days=max(lookback_days, 1)) end_date = date.today() @@ -195,21 +201,20 @@ def sync_wellness(garmin, user_id: int, since: Optional[datetime], db, Fetch daily stats / sleep / HRV from the Garmin Connect JSON API for each day in the window and upsert into health_metrics. - lookback_days controls the window on every sync: - -1 → full history back to 2010 on first sync, then incremental (since-1d) - N → incremental (since-1d) when since is set; else last N days on first sync + lookback_days only sets the window on the FIRST sync (since is None): + -1 → full history back to 2010 + N → last N days + Every subsequent (incremental) sync re-fetches only the last + INCREMENTAL_BUFFER_DAYS days so late-finalised data (sleep, body battery, + weight) is corrected without re-pulling the whole window each run. Returns the number of days upserted. """ from sqlalchemy import text - if lookback_days == -1: - start_date = (since - timedelta(days=1)).date() if since else date(2010, 1, 1) - elif since: - # Use whichever is earlier: one day before last sync OR the configured lookback - # window. This ensures increasing lookback_days actually fetches older data. - incremental = (since - timedelta(days=1)).date() - lookback = date.today() - timedelta(days=max(lookback_days, 1)) - start_date = min(incremental, lookback) + if since: + start_date = (since - timedelta(days=INCREMENTAL_BUFFER_DAYS)).date() + elif lookback_days == -1: + start_date = date(2010, 1, 1) else: start_date = date.today() - timedelta(days=max(lookback_days, 1)) days = (date.today() - start_date).days + 1 diff --git a/backend/app/workers/__pycache__/tasks.cpython-313.pyc b/backend/app/workers/__pycache__/tasks.cpython-313.pyc deleted file mode 100644 index dc77078a640115f15aa65a3efc75fcba021c2ace..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30646 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" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@react-leaflet/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz", + "integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==", + "license": "Hippocratic-2.1", + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@remix-run/router": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.3.tgz", + "integrity": "sha512-4An71tdz9X8+3sI4Qqqd2LWd9vS39J7sqd9EU4Scw7TJE/qB10Flv/UuqbPVgfQV9XoK8Np6jNquZitnZq5i+Q==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.61.1.tgz", + "integrity": "sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.61.1.tgz", + "integrity": "sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.61.1.tgz", + "integrity": "sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.61.1.tgz", + "integrity": "sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.61.1.tgz", + "integrity": "sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.61.1.tgz", + "integrity": "sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.61.1.tgz", + "integrity": "sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.61.1.tgz", + "integrity": "sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.61.1.tgz", + "integrity": "sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.61.1.tgz", + "integrity": "sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.61.1.tgz", + "integrity": "sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.61.1.tgz", + "integrity": "sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.61.1.tgz", + "integrity": "sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.61.1.tgz", + "integrity": "sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.61.1.tgz", + "integrity": "sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.61.1.tgz", + "integrity": "sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.61.1.tgz", + "integrity": "sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.61.1.tgz", + "integrity": "sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.61.1.tgz", + "integrity": "sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.61.1.tgz", + "integrity": "sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.61.1.tgz", + "integrity": "sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.61.1.tgz", + "integrity": "sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.61.1.tgz", + "integrity": "sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.61.1.tgz", + "integrity": "sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.61.1.tgz", + "integrity": "sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tanstack/query-core": { + "version": "5.101.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.101.0.tgz", + "integrity": "sha512-cQetA74EB+seWySv1TTKr828TnP0u39m6LykwDXIo84SNortpDkp30TMEjkqtYCNP9c40uT/iwl6MLiufEt0Ow==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.101.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.101.0.tgz", + "integrity": "sha512-rLlJXSpkqfizLWgkR5+eLeIk0MvTx/meEIR7LRjxic+qxiQP8zVjq7BqQkiCMNLQBlLfuOLqqr6KO5GtrDlmSg==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.101.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/attr-accept": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz", + "integrity": "sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/autoprefixer": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/axios": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.17.0.tgz", + "integrity": "sha512-J8SwNxprqqpbfenehxWYXE7CW+wM1BB4w3+N+g+/Wx40xM4rsLrfPmHHxSWIxJLYDgSY/HqlFPIYb2/S3rxafw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.34", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.34.tgz", + "integrity": "sha512-IMDedajPifLnHNY0X9n8hKxRTQ6/eTHwr5bDo04WnuqxyKw6LYtQywCuuqPZwhl3aBXMvQpJov42GLCwRRdQzw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001797", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001797.tgz", + "integrity": "sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.368", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.368.tgz", + "integrity": "sha512-7RckJJK4uESJF9PxvfMWd3TGqIiieUTG4HxnKaKuIpGbcr+r2ZEB3g2gAhCP3Fqm42vJSzLfgab9eva/C4/XVw==", + "dev": true, + "license": "ISC" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-selector": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-2.1.2.tgz", + "integrity": "sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==", + "license": "MIT", + "dependencies": { + "tslib": "^2.7.0" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/leaflet": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", + "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", + "license": "BSD-2-Clause" + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", + "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-dropzone": { + "version": "14.4.1", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.4.1.tgz", + "integrity": "sha512-QDuV76v3uKbHiH34SpwifZ+gOLi1+RdsCO1kl5vxMT4wW8R82+sthjvBw4th3NHF/XX6FBsqDYZVNN+pnhaw0g==", + "license": "MIT", + "dependencies": { + "attr-accept": "^2.2.4", + "file-selector": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "react": ">= 16.8 || 18.0.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-leaflet": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.2.1.tgz", + "integrity": "sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==", + "license": "Hippocratic-2.1", + "dependencies": { + "@react-leaflet/core": "^2.1.0" + }, + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.30.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.4.tgz", + "integrity": "sha512-SVUsDe+DybHM/WmYKIVYhZh1o5Dcuf16yM6WjG02Q9XVFMZIJyHYhwrr6bFBXZkVP6z69kNkMyBCujt8FaFLJA==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.4.tgz", + "integrity": "sha512-q4HvNl+mmDdkS0g+MqiBZNteQJCuimWoOyHMy4T/RQLAn9Z29+E91QXRaxOujeMl2HTzRSS0KFPd7lxX3PjV0Q==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.3", + "react-router": "6.30.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-smooth": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", + "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==", + "license": "MIT", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recharts": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz", + "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==", + "deprecated": "1.x and 2.x branches are no longer active. Bump to Recharts v3 to receive latest features and bugfixes. See https://github.com/recharts/recharts/wiki/3.0-migration-guide", + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^18.3.1", + "react-smooth": "^4.0.4", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "license": "MIT", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/recharts/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.61.1.tgz", + "integrity": "sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.61.1", + "@rollup/rollup-android-arm64": "4.61.1", + "@rollup/rollup-darwin-arm64": "4.61.1", + "@rollup/rollup-darwin-x64": "4.61.1", + "@rollup/rollup-freebsd-arm64": "4.61.1", + "@rollup/rollup-freebsd-x64": "4.61.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.61.1", + "@rollup/rollup-linux-arm-musleabihf": "4.61.1", + "@rollup/rollup-linux-arm64-gnu": "4.61.1", + "@rollup/rollup-linux-arm64-musl": "4.61.1", + "@rollup/rollup-linux-loong64-gnu": "4.61.1", + "@rollup/rollup-linux-loong64-musl": "4.61.1", + "@rollup/rollup-linux-ppc64-gnu": "4.61.1", + "@rollup/rollup-linux-ppc64-musl": "4.61.1", + "@rollup/rollup-linux-riscv64-gnu": "4.61.1", + "@rollup/rollup-linux-riscv64-musl": "4.61.1", + "@rollup/rollup-linux-s390x-gnu": "4.61.1", + "@rollup/rollup-linux-x64-gnu": "4.61.1", + "@rollup/rollup-linux-x64-musl": "4.61.1", + "@rollup/rollup-openbsd-x64": "4.61.1", + "@rollup/rollup-openharmony-arm64": "4.61.1", + "@rollup/rollup-win32-arm64-msvc": "4.61.1", + "@rollup/rollup-win32-ia32-msvc": "4.61.1", + "@rollup/rollup-win32-x64-gnu": "4.61.1", + "@rollup/rollup-win32-x64-msvc": "4.61.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/zustand": { + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", + "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.2.2" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + } + } +} diff --git a/frontend/src/components/ui/Layout.jsx b/frontend/src/components/ui/Layout.jsx index bf761fa..8ce11da 100644 --- a/frontend/src/components/ui/Layout.jsx +++ b/frontend/src/components/ui/Layout.jsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react' +import { useEffect, useState } from 'react' import { Outlet, NavLink, useNavigate } from 'react-router-dom' import { useAuthStore } from '../../hooks/useAuth' import { useSyncStore, syncProgressPct } from '../../hooks/useSync' @@ -18,44 +18,61 @@ export default function Layout() { const { user, logout } = useAuthStore() const navigate = useNavigate() const { inProgress, status, startPolling, stopPolling } = useSyncStore() + const [collapsed, setCollapsed] = useState(() => localStorage.getItem('navCollapsed') === '1') useEffect(() => { startPolling() return () => stopPolling() }, []) + const toggleCollapsed = () => { + setCollapsed(c => { + const next = !c + localStorage.setItem('navCollapsed', next ? '1' : '0') + return next + }) + } + const handleLogout = () => { logout() navigate('/login') } + const role = user?.is_admin ? 'Administrator' : 'Member' + return (

-
+ {metrics.some(d => d.sleep_score != null) && ( +
+

Sleep Score

+ Math.round(v)} + domain={[0, 100]} + connectNulls showDots + selectedDate={selDateForCharts} onDayClick={handleDayClick} + referenceLines={[ + { y: 80, stroke: '#22c55e', strokeDasharray: '3 3', label: { value: 'Good', position: 'insideTopRight', fill: '#22c55e', fontSize: 9 } }, + ]} + /> +
+ )} +
@@ -306,8 +316,8 @@ export default function ProfilePage() { {/* Garmin Connect Sync */}

- Connect your Garmin account to automatically import new activities and wellness data every hour. - Credentials are encrypted at rest. + Connect your Garmin account to automatically import new activities and wellness data + {' '}{formatSyncInterval(garminConfig?.sync_interval_minutes)}. Credentials are encrypted at rest.

{garminConfig?.connected && ( @@ -340,7 +350,7 @@ export default function ProfilePage() {
{[ - ['sync_enabled', 'Enable hourly sync'], + ['sync_enabled', `Enable automatic sync (${formatSyncInterval(garminConfig?.sync_interval_minutes)})`], ['sync_activities', 'Sync activities (FIT download)'], ['sync_wellness', 'Sync wellness data'], ].map(([key, label]) => ( @@ -353,7 +363,7 @@ export default function ProfilePage() { ))}
- + setGcForm(f => ({ ...f, sync_lookback_days: e.target.value }))} /> {(() => { const n = parseInt(gcForm.sync_lookback_days, 10); return n > 365 && n !== -1 })() && ( diff --git a/frontend/src/pages/RecordsPage.jsx b/frontend/src/pages/RecordsPage.jsx index 9b66efd..adc800f 100644 --- a/frontend/src/pages/RecordsPage.jsx +++ b/frontend/src/pages/RecordsPage.jsx @@ -1,4 +1,4 @@ -import { useState } from 'react' +import { useState, Fragment } from 'react' import { useQuery } from '@tanstack/react-query' import { Link, useNavigate } from 'react-router-dom' import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts' @@ -14,7 +14,9 @@ const DISTANCE_ORDER = [ 'Half marathon', 'Marathon', '50k', '100k', ] -const TABS = ['Distance PRs', 'Route Records'] +const TABS = ['Distance PRs', 'Route Records', 'Segments'] + +const MEDALS = { 1: '🥇', 2: '🥈', 3: '🥉' } function DistancePRs() { const [sport, setSport] = useState('running') @@ -212,6 +214,98 @@ function RouteRecords() { ) } +function SegmentLeaderboard({ segmentId }) { + const { data } = useQuery({ + queryKey: ['segment', segmentId], + queryFn: () => api.get(`/segments/${segmentId}`).then(r => r.data), + }) + if (!data) return

Loading…

+ if (!data.leaderboard?.length) return

No efforts yet — still matching.

+ return ( +
+ {data.leaderboard.map((e, i) => ( +
+ {MEDALS[e.rank] || i + 1} + {formatDuration(e.duration_s)} + + {e.activity_name} + + {e.date && {formatDate(e.date)}} +
+ ))} +
+ ) +} + +function SegmentRecords() { + const [open, setOpen] = useState(null) + const { data: segments, isLoading } = useQuery({ + queryKey: ['segments'], + queryFn: () => api.get('/segments/').then(r => r.data), + }) + + if (isLoading) return

Loading…

+ + if (!segments?.length) return ( +
+

🏅

+

No segments yet — create one from an activity's detail page

+
+ ) + + return ( +
+ + + + + + + + + + + {segments.map(seg => ( + + setOpen(open === seg.id ? null : seg.id)} + className={`border-b border-gray-800/50 cursor-pointer transition-colors ${ + open === seg.id ? 'bg-blue-900/20' : 'hover:bg-gray-800/40' + }`} + > + + + + + + + {open === seg.id && ( + + + + )} + + ))} + +
+ SegmentDistanceBest timeEfforts
+ + + {seg.sport_type && {seg.sport_type}} + {seg.name} + + {formatDistance(seg.distance_m)} + + {seg.best_s != null ? formatDuration(seg.best_s) : '--'} + + {seg.effort_count} +
+ +
+
+ ) +} + export default function RecordsPage() { const [tab, setTab] = useState('Distance PRs') @@ -237,6 +331,7 @@ export default function RecordsPage() { {tab === 'Distance PRs' && } {tab === 'Route Records' && } + {tab === 'Segments' && }
) } diff --git a/frontend/src/utils/bodyBattery.js b/frontend/src/utils/bodyBattery.js new file mode 100644 index 0000000..e6f164f --- /dev/null +++ b/frontend/src/utils/bodyBattery.js @@ -0,0 +1,36 @@ +// Shared Body Battery rendering helpers, used by both the Health page chart and +// the Dashboard mini chart so they colour bars identically. + +// Colour per inferred state (matches the Health page legend) +export const BB_INFERRED_COLOR = { + sleep: '#4f46e5', + rest: '#0d9488', + activity: '#f97316', + stable: '#374151', +} +export const BB_INFERRED_LABEL = { + sleep: 'Sleep', + rest: 'Rest', + activity: 'Active/Stress', + stable: 'Stable', +} + +// Colour a single battery level by magnitude (used for the headline number) +export function bbLevelColor(level) { + if (level == null) return '#6b7280' + if (level >= 75) return '#3b82f6' + if (level >= 50) return '#22c55e' + if (level >= 25) return '#f59e0b' + return '#ef4444' +} + +// Classify a sample as sleep / rest (charging) / activity (draining) / stable. +export function inferBBType(tsMs, level, prevLevel, sleepStartMs, sleepEndMs) { + const inSleep = sleepStartMs != null && sleepEndMs != null && tsMs >= sleepStartMs && tsMs <= sleepEndMs + if (inSleep) return 'sleep' + if (prevLevel != null) { + if (level > prevLevel + 0.3) return 'rest' + if (level < prevLevel - 0.3) return 'activity' + } + return 'stable' +}