From ebc33a78b78e131588b83aea35fdf560b7652f11 Mon Sep 17 00:00:00 2001 From: karim Date: Mon, 1 Jun 2026 15:07:03 +0200 Subject: [PATCH] Initial commit: X-Plane G1000 web cockpit + bridge + Tauri desktop app - server/: Node bridge (datarefs/commands, navdata, CIFP procedures, flight plan) - web/: React cockpit (PFD/MFD/Map, VFR six-pack, AFCS, FMS CDU), PWA, collapsible sidebar - desktop/: Tauri 2 launcher (Bun sidecar, system tray, updater) + Linux build via Docker - scripts/: prep-desktop, build-linux, Gitea release + latest.json Co-Authored-By: Claude Opus 4.8 --- .gitignore | 26 + README.md | 76 + check.mjs | 15 + debug-svt.mjs | 21 + desktop/.tauri-signing.key.pub | 1 + desktop/Dockerfile.linux | 31 + desktop/README.md | 71 + desktop/icon-src.png | Bin 0 -> 18323 bytes desktop/package-lock.json | 247 + desktop/package.json | 12 + desktop/src-tauri/Cargo.lock | 6153 +++++++++++++++++ desktop/src-tauri/Cargo.toml | 33 + desktop/src-tauri/build.rs | 3 + desktop/src-tauri/capabilities/default.json | 22 + desktop/src-tauri/icons/128x128.png | Bin 0 -> 6412 bytes desktop/src-tauri/icons/128x128@2x.png | Bin 0 -> 12963 bytes desktop/src-tauri/icons/32x32.png | Bin 0 -> 1502 bytes desktop/src-tauri/icons/64x64.png | Bin 0 -> 3153 bytes desktop/src-tauri/icons/Square107x107Logo.png | Bin 0 -> 5547 bytes desktop/src-tauri/icons/Square142x142Logo.png | Bin 0 -> 7372 bytes desktop/src-tauri/icons/Square150x150Logo.png | Bin 0 -> 7994 bytes desktop/src-tauri/icons/Square284x284Logo.png | Bin 0 -> 15375 bytes desktop/src-tauri/icons/Square30x30Logo.png | Bin 0 -> 1401 bytes desktop/src-tauri/icons/Square310x310Logo.png | Bin 0 -> 17169 bytes desktop/src-tauri/icons/Square44x44Logo.png | Bin 0 -> 2184 bytes desktop/src-tauri/icons/Square71x71Logo.png | Bin 0 -> 3588 bytes desktop/src-tauri/icons/Square89x89Logo.png | Bin 0 -> 4550 bytes desktop/src-tauri/icons/StoreLogo.png | Bin 0 -> 2530 bytes .../android/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../icons/android/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2255 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 8663 bytes .../android/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 1966 bytes .../icons/android/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2241 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 5520 bytes .../android/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 1987 bytes .../android/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4765 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 11535 bytes .../mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 4127 bytes .../android/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7167 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 17864 bytes .../mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 6628 bytes .../android/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 10012 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 24611 bytes .../mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 9226 bytes .../android/values/ic_launcher_background.xml | 4 + desktop/src-tauri/icons/icon.icns | Bin 0 -> 105229 bytes desktop/src-tauri/icons/icon.ico | Bin 0 -> 22114 bytes desktop/src-tauri/icons/icon.png | Bin 0 -> 23974 bytes .../src-tauri/icons/ios/AppIcon-20x20@1x.png | Bin 0 -> 893 bytes .../icons/ios/AppIcon-20x20@2x-1.png | Bin 0 -> 1915 bytes .../src-tauri/icons/ios/AppIcon-20x20@2x.png | Bin 0 -> 1915 bytes .../src-tauri/icons/ios/AppIcon-20x20@3x.png | Bin 0 -> 2957 bytes .../src-tauri/icons/ios/AppIcon-29x29@1x.png | Bin 0 -> 1373 bytes .../icons/ios/AppIcon-29x29@2x-1.png | Bin 0 -> 2886 bytes .../src-tauri/icons/ios/AppIcon-29x29@2x.png | Bin 0 -> 2886 bytes .../src-tauri/icons/ios/AppIcon-29x29@3x.png | Bin 0 -> 4477 bytes .../src-tauri/icons/ios/AppIcon-40x40@1x.png | Bin 0 -> 1915 bytes .../icons/ios/AppIcon-40x40@2x-1.png | Bin 0 -> 4144 bytes .../src-tauri/icons/ios/AppIcon-40x40@2x.png | Bin 0 -> 4144 bytes .../src-tauri/icons/ios/AppIcon-40x40@3x.png | Bin 0 -> 6396 bytes .../src-tauri/icons/ios/AppIcon-512@2x.png | Bin 0 -> 15898 bytes .../src-tauri/icons/ios/AppIcon-60x60@2x.png | Bin 0 -> 6396 bytes .../src-tauri/icons/ios/AppIcon-60x60@3x.png | Bin 0 -> 9733 bytes .../src-tauri/icons/ios/AppIcon-76x76@1x.png | Bin 0 -> 3857 bytes .../src-tauri/icons/ios/AppIcon-76x76@2x.png | Bin 0 -> 8209 bytes .../icons/ios/AppIcon-83.5x83.5@2x.png | Bin 0 -> 8889 bytes desktop/src-tauri/src/lib.rs | 269 + desktop/src-tauri/src/main.rs | 6 + desktop/src-tauri/tauri.conf.json | 64 + desktop/ui/index.html | 83 + desktop/ui/main.js | 194 + desktop/ui/styles.css | 89 + package-lock.json | 900 +++ package.json | 20 + scripts/build-linux.sh | 39 + scripts/prep-desktop.sh | 27 + scripts/release-gitea.mjs | 119 + server/bridge.js | 305 + server/config.js | 141 + server/flightplan.js | 100 + server/navdata.js | 226 + server/procedures.js | 141 + shot.mjs | 17 + web/index.html | 29 + web/package-lock.json | 1973 ++++++ web/package.json | 21 + web/public/icons/apple-touch-icon.png | Bin 0 -> 2078 bytes web/public/icons/icon-192.png | Bin 0 -> 2548 bytes web/public/icons/icon-512-maskable.png | Bin 0 -> 6658 bytes web/public/icons/icon-512.png | Bin 0 -> 7541 bytes web/public/manifest.webmanifest | 16 + web/public/sw.js | 31 + web/src/App.jsx | 115 + web/src/api/useXplane.js | 88 + web/src/components/AutopilotPanel.jsx | 83 + web/src/components/Bezel.jsx | 225 + web/src/components/CDU.jsx | 135 + web/src/components/DirectTo.jsx | 91 + web/src/components/FMS.jsx | 121 + web/src/components/MFD.jsx | 210 + web/src/components/MapView.jsx | 208 + web/src/components/Nearest.jsx | 77 + web/src/components/PFD.jsx | 589 ++ web/src/components/Proc.jsx | 116 + web/src/components/SVT.jsx | 177 + web/src/components/TimerRef.jsx | 90 + web/src/components/VFR.jsx | 304 + web/src/main.jsx | 6 + web/src/styles.css | 491 ++ web/vite.config.js | 15 + 110 files changed, 14671 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 check.mjs create mode 100644 debug-svt.mjs create mode 100644 desktop/.tauri-signing.key.pub create mode 100644 desktop/Dockerfile.linux create mode 100644 desktop/README.md create mode 100644 desktop/icon-src.png create mode 100644 desktop/package-lock.json create mode 100644 desktop/package.json create mode 100644 desktop/src-tauri/Cargo.lock create mode 100644 desktop/src-tauri/Cargo.toml create mode 100644 desktop/src-tauri/build.rs create mode 100644 desktop/src-tauri/capabilities/default.json create mode 100644 desktop/src-tauri/icons/128x128.png create mode 100644 desktop/src-tauri/icons/128x128@2x.png create mode 100644 desktop/src-tauri/icons/32x32.png create mode 100644 desktop/src-tauri/icons/64x64.png create mode 100644 desktop/src-tauri/icons/Square107x107Logo.png create mode 100644 desktop/src-tauri/icons/Square142x142Logo.png create mode 100644 desktop/src-tauri/icons/Square150x150Logo.png create mode 100644 desktop/src-tauri/icons/Square284x284Logo.png create mode 100644 desktop/src-tauri/icons/Square30x30Logo.png create mode 100644 desktop/src-tauri/icons/Square310x310Logo.png create mode 100644 desktop/src-tauri/icons/Square44x44Logo.png create mode 100644 desktop/src-tauri/icons/Square71x71Logo.png create mode 100644 desktop/src-tauri/icons/Square89x89Logo.png create mode 100644 desktop/src-tauri/icons/StoreLogo.png create mode 100644 desktop/src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png create mode 100644 desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png create mode 100644 desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png create mode 100644 desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png create mode 100644 desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png create mode 100644 desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png create mode 100644 desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png create mode 100644 desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png create mode 100644 desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png create mode 100644 desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 desktop/src-tauri/icons/android/values/ic_launcher_background.xml create mode 100644 desktop/src-tauri/icons/icon.icns create mode 100644 desktop/src-tauri/icons/icon.ico create mode 100644 desktop/src-tauri/icons/icon.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-512@2x.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png create mode 100644 desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png create mode 100644 desktop/src-tauri/src/lib.rs create mode 100644 desktop/src-tauri/src/main.rs create mode 100644 desktop/src-tauri/tauri.conf.json create mode 100644 desktop/ui/index.html create mode 100644 desktop/ui/main.js create mode 100644 desktop/ui/styles.css create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 scripts/build-linux.sh create mode 100755 scripts/prep-desktop.sh create mode 100644 scripts/release-gitea.mjs create mode 100644 server/bridge.js create mode 100644 server/config.js create mode 100644 server/flightplan.js create mode 100644 server/navdata.js create mode 100644 server/procedures.js create mode 100644 shot.mjs create mode 100644 web/index.html create mode 100644 web/package-lock.json create mode 100644 web/package.json create mode 100644 web/public/icons/apple-touch-icon.png create mode 100644 web/public/icons/icon-192.png create mode 100644 web/public/icons/icon-512-maskable.png create mode 100644 web/public/icons/icon-512.png create mode 100644 web/public/manifest.webmanifest create mode 100644 web/public/sw.js create mode 100644 web/src/App.jsx create mode 100644 web/src/api/useXplane.js create mode 100644 web/src/components/AutopilotPanel.jsx create mode 100644 web/src/components/Bezel.jsx create mode 100644 web/src/components/CDU.jsx create mode 100644 web/src/components/DirectTo.jsx create mode 100644 web/src/components/FMS.jsx create mode 100644 web/src/components/MFD.jsx create mode 100644 web/src/components/MapView.jsx create mode 100644 web/src/components/Nearest.jsx create mode 100644 web/src/components/PFD.jsx create mode 100644 web/src/components/Proc.jsx create mode 100644 web/src/components/SVT.jsx create mode 100644 web/src/components/TimerRef.jsx create mode 100644 web/src/components/VFR.jsx create mode 100644 web/src/main.jsx create mode 100644 web/src/styles.css create mode 100644 web/vite.config.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a06dda4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# dependencies +node_modules/ +web/node_modules/ +desktop/node_modules/ + +# build output +web/dist/ +desktop/src-tauri/target/ +target-linux/ +desktop/src-tauri/gen/ +desktop/latest.json +fms-out/ + +# generated bundle inputs (recreated by scripts/prep-desktop.sh) +desktop/src-tauri/binaries/ +desktop/src-tauri/resources/web/ + +# SECRETS — never commit the updater signing private key / password +desktop/.tauri-signing.key +desktop/.tauri-signing.pw + +# local agent + editor + misc +.claude/ +screenshots/ +*.log +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..1189296 --- /dev/null +++ b/README.md @@ -0,0 +1,76 @@ +# X-Plane Glass Cockpit (Web) + +Bring X-Plane 12 instruments — a G1000-style **PFD**, an **MFD**, and an +**autopilot** panel — to any iPad, tablet or laptop on your network. Pure web, +no app install on the tablets. Just open a browser. + +``` + X-Plane 12 Node bridge (this repo) your devices + ┌──────────┐ ws ┌────────────────────┐ ws/http ┌──────────┐ + │ Web API │◀──────▶│ resolves dataref │◀───────────▶│ iPad │ + │ :8086 │ REST │ IDs, streams values │ │ laptop │ + │ (local) │ │ serves the React UI │ │ phone │ + └──────────┘ └────────────────────┘ └──────────┘ + binds 0.0.0.0:8080 +``` + +## Why a bridge? +X-Plane's built-in web server (v12.1.1+) only listens on `localhost`, dataref +IDs change every session, and CORS blocks browsers. The bridge runs **on the +same PC as X-Plane**, talks to it locally, and re-broadcasts everything to your +LAN — to as many tablets as you like at once. + +## Requirements +- **X-Plane 12.1.1 or newer** (the web API ships built-in; nothing to enable). +- **Node.js 18+** on the PC running X-Plane (`node --version`). + +## Setup (run these on the X-Plane PC) +```bash +cd X-PLANE-MOD +npm install # also installs the web app's deps +npm run build # builds the React UI into web/dist +npm start # starts the bridge on http://0.0.0.0:8080 +``` + +## Open it +1. Make sure X-Plane is running and you're in a flight. +2. On a tablet/laptop on the **same Wi-Fi**, open: + `http://:8080` + - Find the IP: macOS `ipconfig getifaddr en0` · Windows `ipconfig` (IPv4). +3. The status pill top-right shows **X-PLANE** (green) when data is flowing, + **NO SIM** if the bridge is up but X-Plane isn't reachable, **OFFLINE** if + the tablet can't reach the bridge. +4. Tip: on iPad, "Add to Home Screen" → it opens full-screen like a real app. + +## Development (hot reload) +```bash +npm run dev:bridge # terminal 1 — the bridge on :8080 +npm run dev:web # terminal 2 — Vite dev server with HMR (proxies to bridge) +``` +Open the URL Vite prints. Edits to `web/src/**` reload instantly. + +## Configuration +All env vars are optional (defaults shown): +| Var | Default | Meaning | +|-----|---------|---------| +| `BRIDGE_PORT` | `8080` | Port the UI/LAN server listens on | +| `XPLANE_HOST` | `localhost` | Where X-Plane's web API is | +| `XPLANE_PORT` | `8086` | X-Plane web API port | + +## Adding instruments / datarefs +Everything is driven by [`server/config.js`](server/config.js): +- **`DATAREFS`** — values streamed to the UI (alias → `sim/...` name). +- **`WRITABLE_DATAREFS`** — values the UI may set (knobs/bugs). +- **`COMMANDS`** — buttons the UI may press (mode toggles). + +Add a `sim/...` name there, then read `values.` in any component. For +**G1000-specific** gauges, add that aircraft's `laminar/...` or +`sim/cockpit2/...` datarefs the same way. + +## Notes & limits +- Update rate is X-Plane's (~10–20 Hz) — fine for instruments, this isn't a + scenery stream. +- The autopilot buttons fire X-Plane's own commands, so the sim stays the + source of truth. Mode-highlight bits (`AP_BITS` in `AutopilotPanel.jsx`) are + best-effort and can differ per aircraft. +- LAN only by design. Don't expose port 8080 to the public internet. diff --git a/check.mjs b/check.mjs new file mode 100644 index 0000000..622c302 --- /dev/null +++ b/check.mjs @@ -0,0 +1,15 @@ +import { chromium } from 'playwright'; +const b = await chromium.launch(); +const p = await b.newPage({ viewport: { width: 1180, height: 820 } }); +const errs = []; +p.on('pageerror', e => errs.push('PAGEERR: ' + e.message)); +p.on('console', m => { if (m.type() === 'error') errs.push('CONSOLE: ' + m.text()); }); +await p.goto('http://localhost:8099', { waitUntil: 'networkidle' }); +await p.getByRole('button', { name: 'MFD', exact: true }).click(); +await p.waitForTimeout(1500); +const apKeys = await p.$$eval('.ap-key', els => els.map(e => e.textContent)); +const title = await p.$eval('.bezel-title', e => e.textContent).catch(() => null); +console.log('AP keys on MFD:', JSON.stringify(apKeys)); +console.log('Bezel title:', title); +console.log('Errors:', errs.length ? errs.join(' | ') : 'NONE'); +await b.close(); diff --git a/debug-svt.mjs b/debug-svt.mjs new file mode 100644 index 0000000..9c24548 --- /dev/null +++ b/debug-svt.mjs @@ -0,0 +1,21 @@ +import { chromium } from 'playwright'; +const browser = await chromium.launch(); +const page = await browser.newPage({ viewport: { width: 1180, height: 820 } }); +page.on('console', (m) => console.log('[console]', m.type(), m.text())); +page.on('pageerror', (e) => console.log('[pageerror]', e.message)); +await page.goto('http://localhost:8099', { waitUntil: 'networkidle' }); +await page.getByRole('button', { name: 'PFD', exact: true }).click(); +await page.waitForTimeout(5000); +// report canvas presence + size +const info = await page.evaluate(() => { + const c = document.querySelector('.svt-canvas canvas'); + const f = document.querySelector('.svt-pos'); + return { + hasCanvas: !!c, + canvasSize: c ? [c.width, c.height] : null, + svtPos: f ? f.getBoundingClientRect() : null, + webgl: (() => { try { return !!document.createElement('canvas').getContext('webgl2'); } catch { return false; } })(), + }; +}); +console.log('[info]', JSON.stringify(info)); +await browser.close(); diff --git a/desktop/.tauri-signing.key.pub b/desktop/.tauri-signing.key.pub new file mode 100644 index 0000000..7b8cd91 --- /dev/null +++ b/desktop/.tauri-signing.key.pub @@ -0,0 +1 @@ +dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDU5MzFGQTUzOEUyOURFOTkKUldTWjNpbU9VL294V1ZWZllVMzc5MGR6OVFVcGRkSTVkcG1LUDJXODJzT2psbFZoY2JYT0E3dEIK \ No newline at end of file diff --git a/desktop/Dockerfile.linux b/desktop/Dockerfile.linux new file mode 100644 index 0000000..bf3e304 --- /dev/null +++ b/desktop/Dockerfile.linux @@ -0,0 +1,31 @@ +# Linux build image for the Tauri app (x86_64). Used to cross-build an AppImage +# + .deb from the macOS dev machine via Docker (linux/amd64). The Node bridge +# sidecar is compiled on the host by Bun, so this image only needs the Rust / +# Tauri / GTK / WebKit toolchain. +FROM rust:1-bookworm + +RUN apt-get update && apt-get install -y --no-install-recommends \ + libwebkit2gtk-4.1-dev \ + libgtk-3-dev \ + libayatana-appindicator3-dev \ + librsvg2-dev \ + libssl-dev \ + libxdo-dev \ + patchelf \ + file \ + wget \ + curl \ + xz-utils \ + ca-certificates \ + fuse \ + desktop-file-utils \ + xdg-utils \ + && rm -rf /var/lib/apt/lists/* + +# Node + a GLOBAL Tauri CLI (so we never touch the mounted node_modules, which +# holds the host/macOS CLI binary). +RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ + && apt-get install -y nodejs && rm -rf /var/lib/apt/lists/* \ + && npm install -g @tauri-apps/cli@2 + +WORKDIR /work/desktop diff --git a/desktop/README.md b/desktop/README.md new file mode 100644 index 0000000..78b28cd --- /dev/null +++ b/desktop/README.md @@ -0,0 +1,71 @@ +# X-Plane Cockpit — Desktop App + +A small launcher (Tauri) that runs the G1000 web cockpit's server on your PC and +shows the LAN address tablets/laptops open. The Node "bridge" server is bundled +as a Bun-compiled sidecar, so **nothing else needs to be installed**. + +## Using it (for a tester) + +1. Install & open **X-Plane Cockpit**. + - macOS: open the `.dmg`, drag the app to Applications. It's **ad-hoc signed** + (no Apple Developer ID), so on first launch use **right-click → Open** and + confirm, or run `xattr -dr com.apple.quarantine "/Applications/X-Plane Cockpit.app"`. + - Linux: make the `.AppImage` executable (`chmod +x`) and run it, or install the `.deb`. +2. Point it at your **X-Plane 12 folder** (it auto-detects common locations). + No X-Plane handy? Tick **Demo-Modus** to try the cockpit with synthetic data. +3. Make sure X-Plane's Web API is on: X-Plane → Settings → Network → + *Enable web server / API* (X-Plane 12.1.1+). +4. Click **Server starten**. Open the shown URL (e.g. `http://192.168.1.27:8080`) + on any tablet/laptop on the same Wi-Fi. The PFD/MFD/Map/FMS buttons open pages directly. + +Updates: **Nach Updates suchen** in the footer pulls the latest release from Gitea. + +> LAN only by design. Don't expose the port to the public internet. + +## Building (for the developer) + +From the repo root: + +```bash +# 1. prep: build the web cockpit + compile the Bun sidecars (mac + linux) +bash scripts/prep-desktop.sh + +# 2a. macOS app (native, ad-hoc signed) + updater artifacts +APPLE_SIGNING_IDENTITY="-" \ +TAURI_SIGNING_PRIVATE_KEY="$(cat desktop/.tauri-signing.key)" \ +TAURI_SIGNING_PRIVATE_KEY_PASSWORD="$(cat desktop/.tauri-signing.pw)" \ + npx --prefix desktop tauri build --target aarch64-apple-darwin + +# 2b. Linux AppImage + .deb (x86_64) via Docker +bash scripts/build-linux.sh + +# 3. publish to Gitea + refresh the updater's latest.json +GITEA_URL=https://git.kgva.ch GITEA_REPO=karim/xplane-cockpit \ +GITEA_TOKEN=$(cat /tmp/gitea_token) \ + node scripts/release-gitea.mjs +``` + +## Testing the auto-updater (two versions) + +The updater only fires when `latest.json` advertises a version **newer** than the +installed one. So to test it end-to-end: + +```bash +# 1. publish the baseline the tester installs +# (version 0.1.0 in tauri.conf.json) → release-gitea.mjs uploads assets + latest.json +# 2. install that 0.1.0 build on the test machine +# 3. bump the version, rebuild, re-release: +# edit desktop/src-tauri/tauri.conf.json "version": "0.1.1" +bash scripts/prep-desktop.sh +APPLE_SIGNING_IDENTITY="-" TAURI_SIGNING_PRIVATE_KEY="$(cat desktop/.tauri-signing.key)" \ +TAURI_SIGNING_PRIVATE_KEY_PASSWORD="$(cat desktop/.tauri-signing.pw)" \ + npx --prefix desktop tauri build --target aarch64-apple-darwin +bash scripts/build-linux.sh +GITEA_TOKEN=$(cat /tmp/gitea_token) node scripts/release-gitea.mjs +# 4. in the installed 0.1.0 app: launch → silent check shows the update banner, +# or click "Nach Updates suchen" → Installieren → app relaunches as 0.1.1. +``` + +The updater signing keypair lives in `desktop/.tauri-signing.key(.pub/.pw)` — +**keep the private key + password safe; they never go into the bundle or Gitea.** +The matching public key is embedded in `tauri.conf.json` (`plugins.updater.pubkey`). diff --git a/desktop/icon-src.png b/desktop/icon-src.png new file mode 100644 index 0000000000000000000000000000000000000000..b974627ae27795d110aea6dc409a3a10302dc98a GIT binary patch literal 18323 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 Ppz)aUiK9t}O|Jhh&diVt literal 0 HcmV?d00001 diff --git a/desktop/package-lock.json b/desktop/package-lock.json new file mode 100644 index 0000000..7fe9ee1 --- /dev/null +++ b/desktop/package-lock.json @@ -0,0 +1,247 @@ +{ + "name": "xplane-cockpit-desktop", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "xplane-cockpit-desktop", + "version": "0.1.0", + "devDependencies": { + "@tauri-apps/cli": "^2" + } + }, + "node_modules/@tauri-apps/cli": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.2.tgz", + "integrity": "sha512-bk3HemqvGRoy+5D/dVMUQHKMYLglD0jVnMm/0iGMH6ufZ+p8r14m6BpIixwij3PBvZdvORUp1YifTD8QxVZ1Nw==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "bin": { + "tauri": "tauri.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + }, + "optionalDependencies": { + "@tauri-apps/cli-darwin-arm64": "2.11.2", + "@tauri-apps/cli-darwin-x64": "2.11.2", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.2", + "@tauri-apps/cli-linux-arm64-gnu": "2.11.2", + "@tauri-apps/cli-linux-arm64-musl": "2.11.2", + "@tauri-apps/cli-linux-riscv64-gnu": "2.11.2", + "@tauri-apps/cli-linux-x64-gnu": "2.11.2", + "@tauri-apps/cli-linux-x64-musl": "2.11.2", + "@tauri-apps/cli-win32-arm64-msvc": "2.11.2", + "@tauri-apps/cli-win32-ia32-msvc": "2.11.2", + "@tauri-apps/cli-win32-x64-msvc": "2.11.2" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.11.2.tgz", + "integrity": "sha512-+4UZzLt+eOAEQCwgd+TqKgyUJMrvx+BgdXLLaqJYmPqzP+nE6YZr/hY6CWLYGQb8jFn99jEkmC6uA3tNvamA1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-darwin-x64": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.11.2.tgz", + "integrity": "sha512-VjYYtZUPqDMLutSfJEyxFE3Bz+DPi7c8wC3imckgvciLDZLq4qwKJxBicg0BXGhXjJsl8vKWgWRFNMPELQ+Xyg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.11.2.tgz", + "integrity": "sha512-yMemD6f4i95AQriS8EazyOFzbE34yjnP16i3IOzpHGQvBoy2DjypFMFBq0NtPuITURv/cOGguRtHR5d79/9CSA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.11.2.tgz", + "integrity": "sha512-cgI91D2wL8GSgoWwZXDqt+DwnuZCP2/bz03QAE4TrhgAKIsrB4hX26W/H1EONPUUNkqrsgeCD0wU6pcNjV/5kw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.11.2.tgz", + "integrity": "sha512-X1rm0BERqAAggtYTESSgXrS3sz4Sb/OiPiz54UqISlXW+GkR3vNIGnsy/lejNmoXGVqri3Q53BCfQiclOIyRPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.11.2.tgz", + "integrity": "sha512-usbMLJbT3KtkOrBMDVeGYNM35aTHXx38SJSzTMSqqjeUIOQ+iVPjb2yAGNAE+KqmBbAx4FOFIyMeKXx2M/JKGQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.11.2.tgz", + "integrity": "sha512-Ru4gwJKPG0ctVGchRGpRup4Y4lW2SSfFnrbQcyHhCliKy4g8Qz97TrUgCur4CbWyAgKxvGh3SjrkA0LDYzDGiw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.11.2.tgz", + "integrity": "sha512-eUm7T6clN1MMmNSRQ9gaWsQdyehQx2Gmn5hht/QUlqZQI/qcP2OJK5dnaxqwFzCr2HdsEo9ydxaqcS1oJzMvUw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.11.2.tgz", + "integrity": "sha512-HeeZW80jU+gVTOEX4X/hC6NVSAdDVXajwP5fxIZ/3z9WvUC7qrudX2GMTilYq6Dg0e0sk0XgsAJD1hZ5wPBXUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.11.2.tgz", + "integrity": "sha512-YhjQNZcXfbkCLyazSv1nPnJ9iRFE1wm6kc51FDbU10/Dk09io+6PAGMLjkxnX2GdM0qMnDmTjstY8mTDVvtKeA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-x64-msvc": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.11.2.tgz", + "integrity": "sha512-d2JchlFIpZevZVReyqhQOekJmb1UH3rhZ5VX6sH3ty9ETE0TKQavpihvoScUXfKKpW6HZC0MrFGRU0ZtD+w3gA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + } + } +} diff --git a/desktop/package.json b/desktop/package.json new file mode 100644 index 0000000..6a91faf --- /dev/null +++ b/desktop/package.json @@ -0,0 +1,12 @@ +{ + "name": "xplane-cockpit-desktop", + "version": "0.1.0", + "private": true, + "scripts": { + "tauri": "tauri", + "build": "tauri build" + }, + "devDependencies": { + "@tauri-apps/cli": "^2" + } +} diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock new file mode 100644 index 0000000..2ccd62e --- /dev/null +++ b/desktop/src-tauri/Cargo.lock @@ -0,0 +1,6153 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "arboard" +version = "3.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf" +dependencies = [ + "clipboard-win", + "image", + "log", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "parking_lot", + "percent-encoding", + "windows-sys 0.60.2", + "wl-clipboard-rs", + "x11rb", +] + +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +dependencies = [ + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "async-signal" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "atk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" +dependencies = [ + "atk-sys", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +dependencies = [ + "serde_core", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + +[[package]] +name = "blocking" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "brotli" +version = "8.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8119e4516436f5708bbc474a9d395bf12f1b5395e93a92a56e647ac3388c8610" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5962523e1b92ce1b5e793d9169b9943eece10d39f62550bc04bb605d75b94924" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +dependencies = [ + "serde", +] + +[[package]] +name = "cairo-rs" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +dependencies = [ + "bitflags 2.11.1", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror 1.0.69", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "cargo_toml" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" +dependencies = [ + "serde", + "toml 0.9.12+spec-1.1.0", +] + +[[package]] +name = "cc" +version = "1.2.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link 0.2.1", +] + +[[package]] +name = "clipboard-win" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" +dependencies = [ + "error-code", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" +dependencies = [ + "bitflags 2.11.1", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.11.1", + "core-foundation", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cssparser" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "ctor" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98" +dependencies = [ + "ctor-proc-macro", + "dtor", +] + +[[package]] +name = "ctor-proc-macro" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core 0.23.0", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dbus" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b942602992bb7acfd1f51c49811c58a610ef9181b6e66f3e519d79b540a3bf73" +dependencies = [ + "libc", + "libdbus-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.117", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.117", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.11.1", + "block2", + "libc", + "objc2", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dlopen2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dom_query" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89" +dependencies = [ + "bit-set", + "cssparser", + "foldhash 0.2.0", + "html5ever", + "precomputed-hash", + "selectors", + "tendril", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" +dependencies = [ + "serde", +] + +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dtor" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "embed-resource" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31a88c8d26de40ed18fe748c547845aa39de1db3afd958f8cb91579f3644bcb" +dependencies = [ + "cc", + "memchr", + "rustc_version", + "toml 1.1.2+spec-1.1.0", + "vswhom", + "winreg", +] + +[[package]] +name = "embed_plist" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "endi" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" + +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "error-code" +version = "3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "fax" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "gdk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" +dependencies = [ + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" +dependencies = [ + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", + "once_cell", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkwayland-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" +dependencies = [ + "gdk-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkx11" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" +dependencies = [ + "gdk", + "gdkx11-sys", + "gio", + "glib", + "libc", + "x11", +] + +[[package]] +name = "gdkx11-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps", + "x11", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "gethostname" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" +dependencies = [ + "rustix", + "windows-link 0.2.1", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + +[[package]] +name = "getset" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf0fc11e47561d47397154977bc219f4cf809b2974facc3ccb3b89e2436f912" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "gio" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "glib" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" +dependencies = [ + "bitflags 2.11.1", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "glib-macros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" +dependencies = [ + "heck 0.4.1", + "proc-macro-crate 2.0.2", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gtk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" +dependencies = [ + "atk", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk3-macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "html5ever" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2" +dependencies = [ + "log", + "markup5ever", +] + +[[package]] +name = "http" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ico" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" +dependencies = [ + "byteorder", + "png 0.17.16", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "moxcms", + "num-traits", + "png 0.18.1", + "tiff", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "infer" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" +dependencies = [ + "cfb", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "javascriptcore-rs" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" +dependencies = [ + "bitflags 1.3.2", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link 0.2.1", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.117", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "js-sys" +version = "0.3.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "jsonptr" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.11.1", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libappindicator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" +dependencies = [ + "gtk-sys", + "libloading", + "once_cell", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libdbus-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libredox" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" +dependencies = [ + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "local-ip-address" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa08fb2b1ec3ea84575e94b489d06d4ce0cbf052d12acd515838f50e3c3d63e3" +dependencies = [ + "libc", + "neli", + "windows-sys 0.61.2", +] + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" + +[[package]] +name = "markup5ever" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862" +dependencies = [ + "log", + "tendril", + "web_atoms", +] + +[[package]] +name = "memchr" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minisign-verify" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f9645cb765ea72b8111f36c522475d2daa0d22c957a9826437e97534bc4e9e" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "muda" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47a2e3dff89cd322c66647942668faee0a2b1f88ea6cbb4d374b4a8d7e92528c" +dependencies = [ + "crossbeam-channel", + "dpi", + "gtk", + "keyboard-types", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "once_cell", + "png 0.18.1", + "serde", + "thiserror 2.0.18", + "windows-sys 0.61.2", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.11.1", + "jni-sys 0.3.1", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys 0.3.1", +] + +[[package]] +name = "neli" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f9786d56d972959e1408b6a93be6af13b9c1392036c5c1fafa08a1b0c6ee87" +dependencies = [ + "bitflags 2.11.1", + "byteorder", + "derive_builder", + "getset", + "libc", + "log", + "neli-proc-macros", + "parking_lot", +] + +[[package]] +name = "neli-proc-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d8d08c6e98f20a62417478ebf7be8e1425ec9acecc6f63e22da633f6b71609" +dependencies = [ + "either", + "proc-macro2", + "quote", + "serde", + "syn 2.0.117", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", + "objc2-exception-helper", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +dependencies = [ + "bitflags 2.11.1", + "block2", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" +dependencies = [ + "bitflags 2.11.1", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.11.1", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.11.1", + "dispatch2", + "objc2", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-location" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.11.1", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-exception-helper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" +dependencies = [ + "cc", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.11.1", + "block2", + "libc", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.11.1", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-osa-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0" +dependencies = [ + "bitflags 2.11.1", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.11.1", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +dependencies = [ + "bitflags 2.11.1", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-core-location", + "objc2-core-text", + "objc2-foundation", + "objc2-quartz-core", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-web-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" +dependencies = [ + "bitflags 2.11.1", + "block2", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "open" +version = "5.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fbaa89d2ddc8473c78a3adf69eea8cffa28c483b8e02a971ef31527cd0fc92c" +dependencies = [ + "dunce", + "is-wsl", + "libc", + "pathdiff", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "os_pipe" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "osakit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b" +dependencies = [ + "objc2", + "objc2-foundation", + "objc2-osa-kit", + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "pango" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" +dependencies = [ + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link 0.2.1", +] + +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap 2.14.0", +] + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_codegen" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "piper" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plist" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092791278e026273c1b65bbdcfbba3a300f2994c896bd01ab01da613c29c46f1" +dependencies = [ + "base64 0.22.1", + "indexmap 2.14.0", + "quick-xml", + "serde", + "time", +] + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.11.1", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit 0.25.12+spec-1.1.0", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pxfm" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.39.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.11.1", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "reqwest" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "serde", + "serde_json", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", +] + +[[package]] +name = "rfd" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672" +dependencies = [ + "block2", + "dispatch2", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "log", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.60.2", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.11.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni 0.22.4", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "indexmap 1.9.3", + "schemars_derive", + "serde", + "serde_json", + "url", + "uuid", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.117", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.11.1", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "selectors" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" +dependencies = [ + "bitflags 2.11.1", + "cssparser", + "derive_more", + "log", + "new_debug_unreachable", + "phf", + "phf_codegen", + "precomputed-hash", + "rustc-hash", + "servo_arc", + "smallvec", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-untagged" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" +dependencies = [ + "erased-serde", + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_with" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" +dependencies = [ + "base64 0.22.1", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b90c488738ecb4fb0262f41f43bc40efc5868d9fb744319ddf5f5317f417bfac" +dependencies = [ + "darling 0.23.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serialize-to-javascript" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" +dependencies = [ + "serde", + "serde_json", + "serialize-to-javascript-impl", +] + +[[package]] +name = "serialize-to-javascript-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "servo_arc" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shared_child" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e362d9935bc50f019969e2f9ecd66786612daae13e8f277be7bfb66e8bed3f7" +dependencies = [ + "libc", + "sigchld", + "windows-sys 0.60.2", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "sigchld" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47106eded3c154e70176fc83df9737335c94ce22f821c32d17ed1db1f83badb1" +dependencies = [ + "libc", + "os_pipe", + "signal-hook", +] + +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "simd_cesu8" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "softbuffer" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" +dependencies = [ + "bytemuck", + "js-sys", + "ndk", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "objc2-quartz-core", + "raw-window-handle", + "redox_syscall", + "tracing", + "wasm-bindgen", + "web-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "soup3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" +dependencies = [ + "futures-channel", + "gio", + "glib", + "libc", + "soup3-sys", +] + +[[package]] +name = "soup3-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "string_cache" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + +[[package]] +name = "string_cache_codegen" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "swift-rs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml 0.8.2", + "version-compare", +] + +[[package]] +name = "tao" +version = "0.35.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1c93047acf68669466a34690ac58cca7010bd1b201e1ec86f1fd0a75d3dd4a9" +dependencies = [ + "bitflags 2.11.1", + "block2", + "core-foundation", + "core-graphics", + "crossbeam-channel", + "dbus", + "dispatch2", + "dlopen2", + "dpi", + "gdkwayland-sys", + "gdkx11-sys", + "gtk", + "jni 0.21.1", + "libc", + "log", + "ndk", + "ndk-sys", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "once_cell", + "parking_lot", + "percent-encoding", + "raw-window-handle", + "tao-macros", + "unicode-segmentation", + "url", + "windows", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "tao-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tar" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tauri" +version = "2.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "437404997acf375d85f1177afa7e11bb971f274ed6a7b83a2a3e339015f4cc28" +dependencies = [ + "anyhow", + "bytes", + "cookie", + "dirs", + "dunce", + "embed_plist", + "getrandom 0.3.4", + "glob", + "gtk", + "heck 0.5.0", + "http", + "image", + "jni 0.21.1", + "libc", + "log", + "mime", + "muda", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", + "percent-encoding", + "plist", + "raw-window-handle", + "reqwest", + "serde", + "serde_json", + "serde_repr", + "serialize-to-javascript", + "swift-rs", + "tauri-build", + "tauri-macros", + "tauri-runtime", + "tauri-runtime-wry", + "tauri-utils", + "thiserror 2.0.18", + "tokio", + "tray-icon", + "url", + "webkit2gtk", + "webview2-com", + "window-vibrancy", + "windows", +] + +[[package]] +name = "tauri-build" +version = "2.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa1f9055fc23919a54e4e125052bed16ed04aef0487086e758fe01a67b451c7" +dependencies = [ + "anyhow", + "cargo_toml", + "dirs", + "glob", + "heck 0.5.0", + "json-patch", + "schemars 0.8.22", + "semver", + "serde", + "serde_json", + "tauri-utils", + "tauri-winres", + "walkdir", +] + +[[package]] +name = "tauri-codegen" +version = "2.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a0319528a025a38c4078e7dae2c446f4e63620ddb0659a643ede1cb38f90e9" +dependencies = [ + "base64 0.22.1", + "brotli", + "ico", + "json-patch", + "plist", + "png 0.17.16", + "proc-macro2", + "quote", + "semver", + "serde", + "serde_json", + "sha2", + "syn 2.0.117", + "tauri-utils", + "thiserror 2.0.18", + "time", + "url", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-macros" +version = "2.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae6cb4e3896c21d2f6da5b31251d2faea0153bba56ed0e970f918115dbee4924" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.117", + "tauri-codegen", + "tauri-utils", +] + +[[package]] +name = "tauri-plugin" +version = "2.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e126abc9e84e35cdfd01596140a73a1850cdb0df0a23acf0185776c30b469a6e" +dependencies = [ + "anyhow", + "glob", + "plist", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri-utils", + "walkdir", +] + +[[package]] +name = "tauri-plugin-clipboard-manager" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206dc20af4ed210748ba945c2774e60fd0acd52b9a73a028402caf809e9b6ecf" +dependencies = [ + "arboard", + "log", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.18", +] + +[[package]] +name = "tauri-plugin-dialog" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65981abb771e74e571a38196c3baa11c459379164791eba0e67abc1a5fac9884" +dependencies = [ + "log", + "raw-window-handle", + "rfd", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-plugin-fs", + "thiserror 2.0.18", + "url", +] + +[[package]] +name = "tauri-plugin-fs" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ecc274121aca0c036a2b42d1cbe83d368d348f54e0bb8a735c2b1548e8f371" +dependencies = [ + "anyhow", + "dunce", + "glob", + "log", + "objc2-foundation", + "percent-encoding", + "schemars 0.8.22", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "tauri-utils", + "thiserror 2.0.18", + "toml 1.1.2+spec-1.1.0", + "url", +] + +[[package]] +name = "tauri-plugin-opener" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17e1bea14edce6b793a04e2417e3fd924b9bc4faae83cdee7d714156cceeed29" +dependencies = [ + "dunce", + "glob", + "objc2-app-kit", + "objc2-foundation", + "open", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.18", + "url", + "windows", + "zbus", +] + +[[package]] +name = "tauri-plugin-process" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55511a7bf6cd70c8767b02c97bf8134fa434daf3926cfc1be0a0f94132d165a" +dependencies = [ + "tauri", + "tauri-plugin", +] + +[[package]] +name = "tauri-plugin-shell" +version = "2.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8457dbf9e2bab1edd8df22bb2c20857a59a9868e79cb3eac5ed639eec4d0c73b" +dependencies = [ + "encoding_rs", + "log", + "open", + "os_pipe", + "regex", + "schemars 0.8.22", + "serde", + "serde_json", + "shared_child", + "tauri", + "tauri-plugin", + "thiserror 2.0.18", + "tokio", +] + +[[package]] +name = "tauri-plugin-updater" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806d9dac662c2e4594ff03c647a552f2c9bd544e7d0f683ec58f872f952ce4af" +dependencies = [ + "base64 0.22.1", + "dirs", + "flate2", + "futures-util", + "http", + "infer", + "log", + "minisign-verify", + "osakit", + "percent-encoding", + "reqwest", + "rustls", + "semver", + "serde", + "serde_json", + "tar", + "tauri", + "tauri-plugin", + "tempfile", + "thiserror 2.0.18", + "time", + "tokio", + "url", + "windows-sys 0.60.2", + "zip", +] + +[[package]] +name = "tauri-runtime" +version = "2.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48222d7116c8807eaa6fe2f372e023fae125084e61e6eca6d70b7961cdf129ef" +dependencies = [ + "cookie", + "dpi", + "gtk", + "http", + "jni 0.21.1", + "objc2", + "objc2-ui-kit", + "objc2-web-kit", + "raw-window-handle", + "serde", + "serde_json", + "tauri-utils", + "thiserror 2.0.18", + "url", + "webkit2gtk", + "webview2-com", + "windows", +] + +[[package]] +name = "tauri-runtime-wry" +version = "2.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b83849ee63ecb27a8e8d0fe51915ca215076914aca43f96db1179f0f415f6cd9" +dependencies = [ + "gtk", + "http", + "jni 0.21.1", + "log", + "objc2", + "objc2-app-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "softbuffer", + "tao", + "tauri-runtime", + "tauri-utils", + "url", + "webkit2gtk", + "webview2-com", + "windows", + "wry", +] + +[[package]] +name = "tauri-utils" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092379df9a707631978e6c56b1bc2401d387f01e2d4a3c123360d167bbb9aa95" +dependencies = [ + "anyhow", + "brotli", + "cargo_metadata", + "ctor", + "dom_query", + "dunce", + "glob", + "http", + "infer", + "json-patch", + "log", + "memchr", + "phf", + "plist", + "proc-macro2", + "quote", + "regex", + "schemars 0.8.22", + "semver", + "serde", + "serde-untagged", + "serde_json", + "serde_with", + "swift-rs", + "thiserror 2.0.18", + "toml 1.1.2+spec-1.1.0", + "url", + "urlpattern", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-winres" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6" +dependencies = [ + "dunce", + "embed-resource", + "toml 1.1.2+spec-1.1.0", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "tendril" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4790fc369d5a530f4b544b094e31388b9b3a37c0f4652ade4505945f5660d24" +dependencies = [ + "new_debug_unreachable", + "utf-8", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tiff" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap 2.14.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "indexmap 2.14.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.3", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap 2.14.0", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.25.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "winnow 1.0.3", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow 1.0.3", +] + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags 2.11.1", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tray-icon" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15edbb0d80583e85ee8df283410038e17314df5cba30da2087a54a85216c0773" +dependencies = [ + "crossbeam-channel", + "dirs", + "libappindicator", + "muda", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "once_cell", + "png 0.18.1", + "serde", + "thiserror 2.0.18", + "windows-sys 0.61.2", +] + +[[package]] +name = "tree_magic_mini" +version = "3.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8765b90061cba6c22b5831f675da109ae5561588290f9fa2317adab2714d5a6" +dependencies = [ + "memchr", + "nom", + "petgraph", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "uds_windows" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" +dependencies = [ + "memoffset", + "tempfile", + "windows-sys 0.61.2", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-ucd-ident" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "urlpattern" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +dependencies = [ + "regex", + "serde", + "unic-ucd-ident", + "url", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "version-compare" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.14.0", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasm-streams" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.1", + "hashbrown 0.15.5", + "indexmap 2.14.0", + "semver", +] + +[[package]] +name = "wayland-backend" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2857dd20b54e916ec7253b3d6b4d5c4d7d4ca2c33c2e11c6c76a99bd8744755d" +dependencies = [ + "cc", + "downcast-rs", + "rustix", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" +dependencies = [ + "bitflags 2.11.1", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f" +dependencies = [ + "bitflags 2.11.1", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" +dependencies = [ + "bitflags 2.11.1", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web_atoms" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7cff6eef815df1834fd250e3a2ff436044d82a9f1bc1980ca1dbdf07effc538" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + +[[package]] +name = "webkit2gtk" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup3", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pkg-config", + "soup3-sys", + "system-deps", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webview2-com" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows", + "windows-core 0.61.2", + "windows-implement", + "windows-interface", +] + +[[package]] +name = "webview2-com-macros" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "webview2-com-sys" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" +dependencies = [ + "thiserror 2.0.18", + "windows", + "windows-core 0.61.2", +] + +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "window-vibrancy" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" +dependencies = [ + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "raw-window-handle", + "windows-sys 0.59.0", + "windows-version", +] + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" + +[[package]] +name = "winnow" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" +dependencies = [ + "cfg-if", + "windows-sys 0.59.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap 2.14.0", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.1", + "indexmap 2.14.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.14.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "wl-clipboard-rs" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9651471a32e87d96ef3a127715382b2d11cc7c8bb9822ded8a7cc94072eb0a3" +dependencies = [ + "libc", + "log", + "os_pipe", + "rustix", + "thiserror 2.0.18", + "tree_magic_mini", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-wlr", +] + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "wry" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186f9871daa55fd9c016578b810d149de58367113db7fb72b462d2323ce19514" +dependencies = [ + "base64 0.22.1", + "block2", + "cookie", + "crossbeam-channel", + "dirs", + "dom_query", + "dpi", + "dunce", + "gdkx11", + "gtk", + "http", + "javascriptcore-rs", + "jni 0.21.1", + "libc", + "ndk", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "sha2", + "soup3", + "tao-macros", + "thiserror 2.0.18", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" +dependencies = [ + "gethostname", + "rustix", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "xplane-cockpit" +version = "0.1.3" +dependencies = [ + "local-ip-address", + "serde", + "serde_json", + "tauri", + "tauri-build", + "tauri-plugin-clipboard-manager", + "tauri-plugin-dialog", + "tauri-plugin-opener", + "tauri-plugin-process", + "tauri-plugin-shell", + "tauri-plugin-updater", +] + +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zbus" +version = "5.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee682d202a77e4a9f3b2c2bdf48a7b28af5c08c34ddf66f98c93e5e39464285" +dependencies = [ + "async-broadcast", + "async-executor", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-lite", + "hex", + "libc", + "ordered-stream", + "rustix", + "serde", + "serde_repr", + "tracing", + "uds_windows", + "uuid", + "windows-sys 0.61.2", + "winnow 1.0.3", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "5.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adf1bd45a81a103745b1757754762a26e8cd01e4532e4d6c8ec431624b80d1d6" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.117", + "zbus_names", + "zvariant", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7074f3e50b894eac91750142016d30d0a89be8e67dbfd9704fb875825760e52d" +dependencies = [ + "serde", + "winnow 1.0.3", + "zvariant", +] + +[[package]] +name = "zerocopy" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zip" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1" +dependencies = [ + "arbitrary", + "crc32fast", + "indexmap 2.14.0", + "memchr", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zune-core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" + +[[package]] +name = "zune-jpeg" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] + +[[package]] +name = "zvariant" +version = "5.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a192a0bde63360d77a7523c833d4b4ce6070a927e2c53246e4c540b1a3e27be0" +dependencies = [ + "endi", + "enumflags2", + "serde", + "winnow 1.0.3", + "zvariant_derive", + "zvariant_utils", +] + +[[package]] +name = "zvariant_derive" +version = "5.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc6cde9c01c511074be97f7ccb6c19d0da89e3f8662e812e999dcfd4638737" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.117", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e8535915cfa75547e559d8c68e8139909a4aeee076831e4ef7fc59d8172c4d6" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn 2.0.117", + "winnow 1.0.3", +] diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml new file mode 100644 index 0000000..a7a2b9c --- /dev/null +++ b/desktop/src-tauri/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "xplane-cockpit" +version = "0.1.3" +description = "Desktop launcher for the X-Plane G1000 web cockpit" +authors = ["karim"] +edition = "2021" +rust-version = "1.77" + +[lib] +name = "xplane_cockpit_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +[build-dependencies] +tauri-build = { version = "2", features = [] } + +[dependencies] +tauri = { version = "2", features = ["tray-icon", "image-png"] } +tauri-plugin-shell = "2" +tauri-plugin-dialog = "2" +tauri-plugin-opener = "2" +tauri-plugin-updater = "2" +tauri-plugin-process = "2" +tauri-plugin-clipboard-manager = "2" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +local-ip-address = "0.6" + +[profile.release] +panic = "abort" +codegen-units = 1 +lto = true +opt-level = "s" +strip = true diff --git a/desktop/src-tauri/build.rs b/desktop/src-tauri/build.rs new file mode 100644 index 0000000..d860e1e --- /dev/null +++ b/desktop/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build() +} diff --git a/desktop/src-tauri/capabilities/default.json b/desktop/src-tauri/capabilities/default.json new file mode 100644 index 0000000..0c90573 --- /dev/null +++ b/desktop/src-tauri/capabilities/default.json @@ -0,0 +1,22 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "Capabilities for the control panel window", + "windows": ["main"], + "permissions": [ + "core:default", + "core:event:default", + "core:window:allow-start-dragging", + { + "identifier": "shell:allow-execute", + "allow": [{ "name": "binaries/xpbridge", "sidecar": true, "args": true }] + }, + "shell:allow-spawn", + "shell:allow-kill", + "dialog:allow-open", + "opener:allow-open-url", + "updater:default", + "process:allow-restart", + "clipboard-manager:allow-write-text" + ] +} diff --git a/desktop/src-tauri/icons/128x128.png b/desktop/src-tauri/icons/128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..9897107695739a95410319b21ed13d8a83900045 GIT binary patch literal 6412 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�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 IMMT*D0i0)>X#fBK literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/32x32.png b/desktop/src-tauri/icons/32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..a817ff03427d6fb2a037f4e4e9ff95f568258cb3 GIT binary patch literal 1502 zcmV<41tI#0P)3S|I8aVV zaE22cfF8<2NJI^lTGRwWN?OP9JF&f9@6Pa>+4ZA|?L;MPH1T>oGv7Dg?=im-=s%2_ zpr-KuJ_6f7yPpPl^1$qKOsTVqv13q5>Sf5xDd=&Em1ChY_Eihj3=iuR(JIUgZ`#^%XOg$I}rB zHDWPs5zOl^R>+vVow3n!leDs3!Nfx^V*12+B<9XQOw16cShV2|q+3So?k}hzV9WY4^B!2PYf>0?}s2oe_lMq~V~yGYHyiR|+q(i&Sk$qqbxH29{mxt3k; zoQc@pQ;vw!oC2m!oI~>PD`q2M%GoOcBfm5br){p3y5AIx>5~@*O}+;LER1s#8c8= zf|?bL@=c!#BfrwkXtX;dD-40OxP>?`nHX?`8A{qIB1cJzq@EB(qlPCls0YUk0ZAQBB8Fn? z29~%3J5p>c0i9ed%fkA40k;zS?J-=rh%XZp^J^Tz4C z%jaEE%Npv;*0B5}XjfI2Be0T4*sL!bQ%3S|nCPEdhT}lLO7+a?Q+LHBpJIMge(Vwj z8cPuCYAe7$We*mool9vlq9RS{)inLyYie6Rjn#AX+_g#@m4**Xu%Us-$DNxCt1Yv8 zcE3fC(rdV5YpbCIG-%vnSSfX|aNC7rlR4zxarIa|=h~W!KQ}zs78_Zsj8s5R&=arx z(ZJ1o85JZnj(b%Q+Hom{vKx_>7uE%k=H2wP8CN|p=Pvs~hT9ksw znIttPeFLnCSY&fyQ`+`C{I)6$xDG=~qW4e0R9j*Ff^QdVSUx?EXEHu=aUThCFwdEU z<+(=ln(d&rlE(tFSo(dLcFuPN?-S5<`zR86hi)6r$;Yvp%3`%xM=F~}CYOdRR}o7) z@Q6%tqlqBV8_ed zSNA>`q%*ls>C$kXnETtVZBf}zDs+5Pa#2=6FY|PFsf|rXunGdI4`b$i2)LqSI!1@o z=k@Z&JCTd^?_uf8>}9Ig&kettu?S2dI)ld)vTFEzm@L@^?*;Nbm($dA_9b&^pt?OO zofZB=GVD1V*_<=}MXj{{-S*4rAVt2TV%YzO58N5?FSm)X204MbYybcN07*qoM6N<$ Eg57%2JOBUy literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/64x64.png b/desktop/src-tauri/icons/64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..338d3e7f9d62f4c03661a99c93f1320d4911a60c GIT binary patch literal 3153 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 literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/Square107x107Logo.png b/desktop/src-tauri/icons/Square107x107Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1a01181fc4ab841aaf9e1b32367de28c7b2f2c5a GIT binary patch literal 5547 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 literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/Square142x142Logo.png b/desktop/src-tauri/icons/Square142x142Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..523565e82df1a802cc03a437c6e8a66070b18e86 GIT binary patch literal 7372 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

t0(A_4OKTyEIFly-p|| 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 literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/Square30x30Logo.png b/desktop/src-tauri/icons/Square30x30Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..672fd5629c3d833cfb28be58d3a68442cb418b6d GIT binary patch literal 1401 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 KMNUMnLSTY_nlpv~ literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/Square71x71Logo.png b/desktop/src-tauri/icons/Square71x71Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..0ce56603a2b0a436637bc0178b787afb294a110f GIT binary patch literal 3588 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 KMNUMnLSTYAGvV?8 literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/Square89x89Logo.png b/desktop/src-tauri/icons/Square89x89Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5ab5a6598da5a3bef3a0a22ff28a716d31f2a6fa GIT binary patch literal 4550 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 + + + + \ No newline at end of file diff --git a/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png b/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d2a7f3511d5dd8e811c9c63037a4aedaf768b9fa GIT binary patch literal 2255 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 z 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

cP_BD;R zx4uZM8deBP0B7tty!&5*cjz?ip=kq@*bw-2M3n{jOBb*)e-1%;h6v{%_`X(6((2v| zqD{8hoge|@$zy*N`SDXIJ@zvcj+}wz9Y}Q_CsyW1ITrYN8ZK@uqjvp$tX}**>bEYy za*M_Y36VXIkVrTk5lHjAwJQMz6Z=LIrN`dH=#y^~kYSQgCDHiS$W1}3H{;qeme(Y= zV+s;<}!Csk_74MfYlZ=2nMkqxbQbe~r?~*GbzqjYLfL>C^@+ z85&15R^d%Q3wv-18?*1yb-9;K8I$F@g^PY;IWB_11!DlAVRDbFhve^1ezm6}hqbU&^4TcL4wvYcTI9Dar7 zswJ&QHY+k=@-yqQFi90wQp>O-KT$B61QE56veWDQnesfs?@I?ewa%CaCQf686N9M< zA{zp%QQ;KOu9q=2;nmctri?U^Sm;S>C^9fT~@>8z#R5++N^ zAV6SEK;(v!7(@H)X1CATG%XD#sZu_EVhW|n0;0g)N}U=GisA}JpdLNKS+~htHSc{IM z5JF*5b zG@Pdi^p5!24q}l4WVaWa2<6jWZ1b1+S&yD9?3l;31r~iDLA(MlC(r@@&Iqtv*cuDV z4ICS%c7kJA=$0Nyw0w{6u*__}ubQ4=2?_IUk>-e%PFnD+2q@!Tfor!TG$P6|VmsGo zwVqiqZzaOjatO!n%)K4g;&l9L%OP&9Mdq{888>r09>o>T z&(+CN+Qda>2aOdG;`3MQJ4DwtfxY%B*-C8rn`g7HQ!H8<*^Z{ zv|e;>2$szz_`hAQm<<5S>Yl*97WGUbj?I=8o;vE`=_7g5c9 zryd|{m&&kCJz~5RU;F~rvrj><(jsT}8sviyK#r9Vz5gNf%_Yjs&c3YQ`}=`S5=Gji zWl3CLNUnL*eUhv&K`nHhcJY>1AP*fh_tgAN$f=1W8PIhjpMJg{XiJ2(OC+=(KnxA0 z;YN~jXuEKO7Uwoe#q$gy%{8P@pk?VsGVy?y#8SWC(6o>U?nr`9?z44T(Ui%x$#*Wf zcDl>J@xs@WVzL`}r{8ZW^={jRcl&i~Z|{jq<3Gu&Azfcx`s-bP(T#h5D{+qiz5{_R VW8F8$U8n#6002ovPDHLkV1mm0#w`E< literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png b/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..63afabc94240179cb8a94344775399e03247779f GIT binary patch literal 4765 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 B0y_Wz literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png b/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..bd9544887c743f25ba930b65a9792a0b99cff9c8 GIT binary patch literal 4127 zcmV+)5a92LP)Nkl->NH9d5+^MNRY_eag%k-W5~5X+iiA|EqN=Ub0!3Yr zAS$hdM4Pli0s?A6(llf-P8#AgR${W?#*S-y;u+hq$FtA8?JlR^f9@Txcs%jkH}^jC zuJkld^X_uazkL6C&UMf}QazkD3EB*3GoXE>ci5M}98`Potua2`)`0erO&icNuCC&zru6gH zmO~+T46(IWA-(wteIxlw7-Hv0a3|&y&k5?Jwa4$FVU}`B{FLK+_~y4}GvZ>jKxK>g zG2uzT(3?eApE3k=I#wgscO7!Q*TCso3%fJ`JKsYlj=Ru6`y3a7hD)dC>=rA=VsPu?$bKb;mVtvO|ThafXze2u$1GQkv zV7j5RR;Lksu`aCUt#Sr}8j}Yw`ofpUjPFxP3Whn!YlE&Yq_C3;0|ZtC=f%D3zvWNS z`zxO_1Q6mI=xCaej9gfY-jU@LG4a~B$cQge1E&pR^hr-CV+@GOh$^2L@#_=xWR_$3 zd%up3t3Lq0GGbuB;C<7(M-&k)iXq&N6_|Z%JB~f|NA#WsVHf%mWP+{>%`OB*OHvU# zhxp}HSb6sY5%H%FN3rda5PuGeB3IX&8b)c&uVK~JZyOgksEx(rKz90qV(1BskGNRO z_h*f?*Hr|9M0b0xMsf9Rs2tjkpmN-JNC_BbL$hM3 zYoJ!0`LA>}fRh!2E0`~^Q(AN9DdMNxv?j4ZFnbh*<-d#-@Be4of^G^*_1s(&TDT}L zj}dQ24DLzTIZ6D~6HbN+A`s=ZccK6Gzor*fUoxSvn%%Kxf-L&^;%bVwBL-Le@@yr? zv~fkfnPceL_$hQ<|8YXocy@>l@rtJ2 z`sa+o*YkTN9&1ZNkT!N((hCyd&IMUZ=j~jacO;otw`&c0Z~i>L&m`#}sHJ6q6(!ar zw2T3t(Oxu3d#%K4#SHP4QR68y z0ZA#Ftfp?Ql|(x57_qNJY5mlo6$p)vAXu zz%C9T*M9?Hs5$8gt2x^1o9v=JR|s##Ly~ozheXJt1*fWQD$9%XRNTvB!Djb@mIP{8 z5vMf4J^_7thROU5&$vb`<3Fp%;{^n1d)-gA)5rE1y;Ma;Yz=g=6NH{m-BujrLvw|qu_JP}1G$KH{t*1Y!Y2lP7e#v#|N8br z&~_iLP>>xXFQe%{YJJ2oe48>pinyTd<$j{+`~<&n7*J1h+EU5;-*mq(*ohwD)H zg5;XJoFs!V%b=!Z2zsmi2;SrD!=zJzZO;!sTH6Lb*0}$Uyn370pPhS=b6iUK1SWzZ zTpzM)E}X#S)~j%=2JW%`kuzC?0qZ}|Z?g$YcT*U=v!)`=TOKv12W!19GN6NPr1Sgs z0Y}nlm+-nhi0=>{X%TpjFi}J7oF6FP`4NUvSm&jo!lU2$7GC=iQ1=%QgXsvq+(Iv} zUtv1j)VXZpDcuPCy$BkgM?m~vxvGzFSHh9Q_t97~?alm+?XESRm-@L=Q06zk{uQE2 zcwrO3Q}U$H5hg`FUlH!?s4+OpTNMbg{g538CW2jMc#`sK?cs9sMx{Kc^0EseP z@!-(_`+m4^TvHeFmXzs!mJFq!uoFX@JV!0)`k3ZkW5MlQ9vM4bX;9<%JU98E-bp^P zQ)ZA;wUCT}k(#g>LDCt$x#}WXA{QEwC^Hw)>LRZTbmr61+7NwoHh>rCh&Zj73W|lt zCzoX|&8i3_&H#~mhpzJIjE|WHeIg4jdr0_FZD@>4`*3a56gg@N17xtGwkM_oV-s3+ zFEKGOqcZ`6i=_)LB@X%1F11}<8V z=ZFuG0aMigwxwEXXFcQ1kutM{(0#`nMx#S4ZCi?7EDYty08!ojBbsIcL z)-je&RYN?tZ}y}womC!)pbOqVzrSK!=$x&R6d0XKd%CD}F{iNmXq}i^Lr0!fvW#Jo zK)hhSjO~93mp>);8|cv~x2Gq$sVVCic=pX%9HeX7S+rPC(OIdzqrtIslK4j_JZ#%D z8?6~n(C`NS`Llo4l3^>MNCKM2e>Q`+Cs__Dq|XGQv5cuq;)~1tpRdnghWPI$3q8oh zBE7lbY=RU0;VaYhjskQR>{OXBC;5{c)5EV$V}u@?cx$1~*lsCFE>jgByT-Vnr)1-v zjU8CmpEFXYfFZj#HKKCug&(Km z!pu2P%ZD0pNAe%MmC^4_1ZLm%ep5Lt?s`!U&9apFCp5+HojoFU=FVB&5vR4c6 zGfMrAw;IOJ7fnbzO6voTrNgR9U+p9Gb*W4>P?$<8QNu zobM`=@TzHHVdA@`G>r)ae?2(^``Y!$f9P)1yL;e`PNMtCC$N5e2v@EwqGxp4@FJou^ay&fJfro$n6WDgkR_y4$2D^6+Vdsr^;eR&04~1>d;P_Y#+dlFc3?81w zE-o#7a?8i?@(-TFi`(D8QT^eiF_dw?L1LOR_4} z1eJ3!+)YFa;&4;fW|9B&#}K^m66$~dH3JB>M;}A+-rqs*hIMEhJ%NdbpF(lZehkxn z-8AE{mxbI)^%2Pjv&OL$pKYb0~@7@GmT94d+?}YQnqvk&On{R}B+q;d~$38vkT zwm^C8tX{PO&If-3s;d*>;1KG6_YJ60w>eMh%%P=B3#9a$7H!i66E*j$$dx$#@&tAp>h9r zjiE0-@O8Mq#Wl;vP9XQmd-=@oMcucqV;Hv>ZCK1!_A2!atc@Ew4SN%b{?Xrt>f=s^ z?8EmSdJO)vFGQ{)3Fy*=45=ypW826S7w+$UgpArqiJpb`Zx15ev(NbdHW}yMvxUK! z5AS=AAb9Cj^WFN@n~?kH2hH>RXLi6Bn^P`hvGvBqzDGc1Vi$3dJ`&d)CGI0stwsKM zNBI<}`|)Z^39_gWx<&(DDlw(mh#*9+<29PsDtbNUdfF86fK1+FrYfx(CK047Jf~dD z#7i8q^9Bto&Iy=AkQHyjtrfq zeuqrDZ&R`^l~)3`>Z`1*OX)qay+x`L$IFY!$GrJkz&8ryW?Gc}y<>0kAY ztPy@<^yp{ti}+6Y`S#UpdP>S)z>>*JodGG0ClgR;1KD3GbSV+M)fjNeA5NPDZ3eU% d&_2>T{vT7PNrrP$(HH;#002ovPDHLkV1k`Z4J-fv literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png b/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..ca9edf6b53f7280fe0dcefe28e13c2ad2e6a27c7 GIT binary patch literal 7167 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 literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png b/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..54fff5e0e6541b5e9ca1af6b3f7068a710a3e01e GIT binary patch literal 6628 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 g<;+x!@eb>wNj2J3p|J{4k^%yIbDFE4j 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 literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png b/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..b5e1229dc3d45a3930d48e7c8d5c550debde6448 GIT binary patch literal 9226 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 + + #fff + \ No newline at end of file diff --git a/desktop/src-tauri/icons/icon.icns b/desktop/src-tauri/icons/icon.icns new file mode 100644 index 0000000000000000000000000000000000000000..4cb4669662a6a1fa30ac99ce59fded493991f47f GIT binary patch literal 105229 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 LNkvXXu0mjf%Ne~l literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/icon.png b/desktop/src-tauri/icons/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9cee42327d6dfae80e45791bdacccdc5f0c02903 GIT binary patch literal 23974 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 literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png b/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..1bf70282277528ed1c2975b7fd03cf8fd414cc51 GIT binary patch literal 893 zcmV-@1A_dCP)LgCGE-P3bre#_vDC zc4~$^_*K$I$&UZ;b!l*JU}&%puU@_YTU=U}mo8taLdKM91chH36*uekUf??V&F!>` zw~Sb!RQjJj&Os>7DvT-q2&wc6NS?ihWXA~1#&&(=9&RAF_6E+^DFSN|G?Q!wW&O-< z2BPu;LSrhlmcb`Tb&hHjGH~^2;&d-kT{m&G{2JN0ha^k;Oq7uth5=Et=h1{vhxRNvg-@N>IJ zcitdMu7^BFm!&SKDzjj zHrvj$BYDy%dKen`I-Pj%S!2kNJcJ}Pj^9eM9vqV0w~}ERu?mB-^fb_$eS}uOfe?B~ z8sD@*4=1!!0|#0qM+Qy0fZc;UKBKa#L_AxH6zb;2I_i%t3Q=N@S>%NH!(L3>BhRZy zm<*elqSmoZR!$vJT}o?v3>Vw#;IaS)i}KTql^%mH6EH1KvTjW&^1p=+*n(j#bBy_& zJd(Cj3}+yrXS7ylizKr`vPvgj7c~eCN{`tE2aGyLcZ;coWeJ>aO7x!Jb}_S*rwCY0 zqY&}3le*9ek>_J_i(xg@jE+VID;FRgV`2bGQv|9%%)=m2S3ZrEYd$kwuEYqs-I2IexO!XDs&;>Z|}g$ z=OKUW1IY%hY%7NpcaU>b;cDWQF*OJJ`_R*KA?$}oM@P6jejn2_?_(V&pbVje6-M|S z=Y`5o6IzODaG)R0pG_d0PJ_jN0bdptbPG~lLnBp&qjzQR*QgX{Dolke`UU&}XV;XG Tg=Pi$00000NkvXXu0mjfaD|SW literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png b/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png new file mode 100644 index 0000000000000000000000000000000000000000..2affed96e00fb7a2c08eef29db1d20a0197bfd72 GIT binary patch literal 1915 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 literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png b/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png new file mode 100644 index 0000000000000000000000000000000000000000..99f21400f546bdd87ae9da6739f2c9073f7d6799 GIT binary patch literal 2886 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 literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png b/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..99f21400f546bdd87ae9da6739f2c9073f7d6799 GIT binary patch literal 2886 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 literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png b/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..623d678da4dce16ce1e8e2fe84b058750035ff97 GIT binary patch literal 4477 zcmV-@5rXcCP)ZG~z|6>FP!NP1DrtDINcDnQNM+dJO~u zXAA@Rni(ct*Zl#Pe;~gXj~zRXceifEw(akuv9S^DiNq=Qa4~HRM=TnZwY9Zk@+T&t zu5K!-tE#%-&|hNp3tYo6I(qGum9OGI|LbY_#_BgkJRav$oW`6bpkpz7^6Edw(wmpy z`gzxN;K2a*MW$ZC<*)dU8M}VNM%?!g|AckxH*|dGYSL*7Ep231gbU)7DHq}42fu?^ zpPH%Ov(4%4`g;U7|G-Bc`vD&M-Xn^m^h1(=&DGvBVIv&WH8Uo>-F??``Ot&k5q-%- zx8S<0q!psfz_R!Ig^2P zMl-XQ@X)aGwN;pZ(?aQh-mOcjb!WVIXO;pN*jz4mHX_K|ayc^a1n{cY-w^kH>;4{z z*F_dw{b1wunZLY_DSQ^mK4gM6@$7GYjlYhjHryE`QHj%ONdCUi|(nYx~b$#%t|6>qJAtJ_WAp4{L6~z#HcZIHWB;(u!{W zic5Q$jO#aSKt7&YzF*5p7;gCBhO`8nptxPr)vJ0hsj!${NDDSFK)&}k=UzffmqpwMol z#Qp;ZdIp!%hJ^-IaCBqlU}fzLn_fB^;i@SJ*IbHFAN+pwW37DA{ z80{Y+*Rl)grY*=ezlU7ge(oLWh!O%iO#7Mz@zoupCKBz5jwJg@;1*JAg%%(jvM^Ka z2t=z;HvU?aPPiVCk(VP-GE#w~7^tMcRG@Vpd=7&7l3-N%-?EVJ-wt@1X8@?GA!MeGDG)2`mZ5y|62($xuH@lP%(Sv?PGg081^FY; zmIp}3Y1g2IhoR*B&(hyK0=0%kHhF2o<+@^#}x=>s@XP7JiG^F^+m@yY`JMBt*%7%%zs7g zjekI>>SFrrXhA&-tx&ENUs&k{H==gIONgC2TfJuxY~2)Ii=a9$8%l#fj*Pqlwe$ao z@{4bUMI8)L7++cQA6TI-sB-$(G3wg?P?p?GANL2;9za%}2zBr|*Zc${u6lsvBc87> zLlj)nO^bjWKI2{*o)0S{)xp++iamQ2rt0JoSKf!JnGZUE`^#X>SL5X{w(6>HE4{TN zS8cGuDD~S$vI)bd|Gmv%>UclfqxosPN-vy`s;j@NWS~$w*LTpu`hNt&ulOd0U2=ya zfL|j?^F<2C-3nDsLd~ZivqM?PB1*Ohb=j=DRWttukx^GDxw5^8qGzsDer)xu@2kkm zqCCK$NkMNCL4L7DIg9F9kE+~-%29Ys0L|-=)=Iaae9BV9&ihQKS5S-_yN6`dqN8S@ z;?l1uCUg6X6kMS^0Tt3xHaRQC&sdauq3Zrp-(DQ1h;#q+{833ON`1 z(onzj*CoWTOKx`vp%ojrLPbNYv7ChATtTt3wu_XJK`Xm(0rc|oh!h#mv{&=eL*THM zvs-dVur{9<8R%tWP(o=>&d3RmW@0?mT+YW1#U-Um3MgAvI^lCPqY?IOwY=t8&(jP7 zC%SFcYC{cO!ZwL;^(6=nJ6}yBc`@=dFC>8j1)iE=!@ve&=&@HQ<_03eX?m&734FA{ z2UpD&P{Vl6%bvHgfFZfK!zN0kW}15Ag~`ypxQBopay3muzz)@gI;z=35_Thb7TF8k z9eDV}fYKx&&(eOJ5Yk?yE_usFD9HOxibyFl65j};m zk^PEUy)o}dx(4k=8Ag>H#9b4f!i#&a!``;>h!MzRA`QJl`PXo_94`emGX z5>tVz=G*iEtu4_9s#6Ayp3;!O6So2*Mp(4!x-VluLmN>Hlk0K5v5elw)Mwp8o5ODX z=Qt)liLu7>7#X`43zKcwqkk9Wawje{ZlQe)$1b0U0!N5(>DY z<)bzJ4P>$*l*E##n>rcw+nz^D>#GQd46G^7I6HQ?B9n%=2qE775Ym~)6mxqUC7ooE zNX3uP01OUzNt8ao%&qbca)yNihni6trD+taA7((SXiM{`A=*TPY6Dl3uBnaX4Dcn-Se&9Yw23+6JQZD~ufSNA}x z1|w<18heBYay(%XxWW^8)4W;iIp* zIkb>LP{V2nfy=}u1G}yvH6+-}tPKYRHZ`Wv+-BN=L$NMr>S*k~ zG#ZcP5GH^vS-c)XNV$+E-r18>WbnGJnjh087PWHa_Jp#$fg+9C+-P#;_I9KV2|sQc z)qG(DvEU#@ImW7nN*?x&#(~@g$oiG z#8;`4Sqk{~3lXO4g^Jyyj*G_Gv$>N?F`5$V3^1oD{Q#LkWlx2*pWQ9?3fOo>3n))| zA@z;D@0QJ3G@D^L3q|aIB;TNCbq$oA}7U}&vyA#UYiiHa6ck6=@$1@;nwzXhe{b5`>HjInLm7~0>jPApu zsd)y9ilPOx8Dzr|`z}a2HqstfVCTY77@?4TGNODa(FTp`d6~4YD2X9JAh%PExvlRt zW8=e;s}hCN#ts3 z@X@5H7`t~nO?VnK0V+{H^RsBHtik!4-$K>Fy|AKDh;#;f|71rz7B*aWSm#J&EYDC0Oy! zF@z_chd{U*C3k)mM_c1)za@ber_X`0q8{3qi(%aMw~$8<1I@JW?Tdgn*CKMmT%`W) z0hl{?z}&tQ;fKBj@*p34K$p2uH9C4=E|-$_HJHz2p-niCD^0>&{We53tthOi zhHPm?a``>52t4cYCn4VdfSl48f;pPmn0x`mj$LSK&Eh~gt^3+o4?&WEX>|xt!6U1U z7+Et4)(5+2VIr-vp;2KqQMrMGP0-F61FP|X8ZFwnv4M~UGhXz4Fia7xi~`tmaS z9)>;p)aMGo6s;MHlD7~E!`ihMqGFiSd1=*Y47fZ>cg+WN->UKRHhubK$j4K2naewH zRe3Ic?$jce-lxlgunr!E`Su3V!TU%vM?of22!7!P#V&Kxd&JtPGaXAyqe@F)tXT(b z{JGF)+jYW2cPxgvWgE=3n-s%?^XEaPDC+w1&9FXfAm(qOb0!g7dJ`l`Mu>D+9&U!! zKsCSEh4a{GJ0-Vq`SfYvYNT$B_bw$~-P*6uzxWcC-g>*gQ(Q9!Ux$t8>jK|KBh>!IOC@H`Z^r60;9JJY&VPF28*0r zSvzrO-hrQkz~%b6nL(e7fW5Fx*t43hRqxHqP-8IQ?3?$wni=$qPYXvM5^Tfx?oFohRv|jMV#j2`27eD7B=x4W1U^&q=?Xo)g+AIGnPQ?fRb_XwGnUs;L!|MAzBJ?%~j>O_&L|;w*BCtxUR9kYd7ud;sD|1 z#fz|H@j|e>b>id82K+p<6Wt6he$F+zxs)_lJm$i@r_1xuIJ?D37|s=NNXwB|PdIq? zBtMtM+-s-vqq=&!?*2RjZ9tDn%-3TpZ;tD9d#r>D%Rq=E&OSZWzwQ44LcXfU=M#v( P00000NkvXXu0mjf0+7_4 literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png b/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..2affed96e00fb7a2c08eef29db1d20a0197bfd72 GIT binary patch literal 1915 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 literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/ios/AppIcon-512@2x.png b/desktop/src-tauri/icons/ios/AppIcon-512@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..609b53b3eea439b5182103b484e7bcbb86183727 GIT binary patch literal 15898 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 IYwgbcKN(ITBLDyZ literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png b/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..88caacdda1cd9467ae06099740ebd5dfd5d07728 GIT binary patch literal 6396 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 literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png b/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a69f16937b05aa0e07bee7da19150757695691be GIT binary patch literal 9733 zcmV+gCi>ZlP)H^gipjA^%0a`WH3J}mr(tE3Enx+8l0GD5;X|{I^ zzl0D9B_3+d7&=765cHY^+M3NhXg(CA{+vL&N*jc?y0Asq@<*M{BtcU za{_3-B+p7-lDKW(z8w!e{3srM>r|-Z2Py=+b}J9MEP0 zeNaUOE;xUo^^I@*i#BD_q;|&Ebv-9iBOi}2H%{}p9rWm#wItN_~aUhs{rTlWF3xbkXj_-G>> zAoESDrdkKE1u6y(uzq*v9om`m&uDkyWYv? z=#W6&CqT2z;3a~=OcKLdzy2f5Fm!1Ys-{|Ro8vHGBXQ;OS5aME-DgmXz8HXxcxPs| z!7LP*RqJzeJRRY180UZGYluW563kAXPfh{tdQK55o|fxJF5v@X_#u&@GPJ|aoX1(p+7U4jpMClXoO;TfgR->f2|IIgKIbzlc2?~O$PP)O_ucgj#_1D8BdZTNpO1x?7KjI2b$g9zfnUB{WTy!BY)KDvvr&(dZ>h zmmbvPAr4mXg*UYF9ze})6-87-0lD!k-h=x5lBMm&Vy^)0_yPGR@6P6n^(9e6HPw)v z>H#uwdi8s2tlC|>y3O$r-LW&*&EQf4&K4QfR6CO1j%YNhaUGZLWQXWZKl6vv+hY`( zRda#2L&LkPR$1M7JGyn-aYZAgpH*{{j^+wm-33`hcNHb=4_i>~4b@x#XbH+qH8oOC zv*)8LSQ^~{nrqFeuIyP!EV~+%X8$##GE|pu=ih72dz=DjmMVePgEGr|_cqF6o}7t? zo|Mydwpek79T!ea3l;_J%o=X#aBF0+vZxiI$lLD7{Y@X>fNoQW72S zkhvr$pRY18@Eychc>WqP#jKX9P z6ZnL$7)DVg^y0zrl@5a*8VI9wxCE!KY=jN!Oy;FaCBmQ4B#0vw*@w@RZ(p=KEYl5`#`j5p`umSXaPSEz zI_irER!$=TR};93Y%nrorxNzhSS&*mJ9@gSe(n4oA+P7}KMsM4$tW4KkggdeFz-UV z{vT-l>=m@tzKwXp2ADLlG+Gse5hz&J?#@S{(&sXO%mA|zEhHzR(2J^2di2=@t_28H z&xRfx(81OwfxRu-VE{Ttq13-UR4|_#CDP(#w^+&6v^EqlLKX0h{4$D(;*!lW&!>MEFbW@3zzqA_eGnM%D;0EfT1K%41PF_5zfQJ_o+?(GtWagFM#Q z;pt?fQ0O@^HZuWlv%k&y{C!2kPNr32E@|%VXxZ{NG;e$oZ97)Vdldds1?<8Gv<*r# z9wA1KOFdjZ^>Vq~i$Fh{sbftY?5*iXNXK`uKHn>QKLqLZe#b0A*~E)Uj=YSfwRfX+ z`*M4_`ODh1xdL>-kg_gyZ>p`47@2@P?TR#zOQms^BF}@y06rohKDfRoT|)P`SFS9@ zqvoS%#Ft2hykrA=+w0OhBFKQ0ZbSv>{CB^lqD|zjs6fTc>xtvj$B?rg zq@c%9GN{1=?tVt@A+Sk~$jRv|LFK&PV(5a$WpGEzlXl;?0<^a!1`TquwNAR;hW*nr zX-Kihg57W0fkM+BpS-NGldbjS6*&dNzOoFZ6Tc=wEsaG@C_sDGugvEp5;G5&aUH4` zJVBx9qa=elY?j|199oq~hG+&Ij(Nsn3_9(0k{zjxiL3zaspVIOs)>;XpZ*67nsck| z(@nPJ^VrK94VyzN)sqMeoS3(u7Wt+hIpU{N_S?{fPf0fx4`e=S<=*#=PwHqN<)u`g z|12d}9Y^lV#=HZy$R}pzNSa<;C9V6wz)5z1MEIau=7evSVe+BpJ|YvY@(t7?Uo^9s zXzc*=fQiz-tiaqgsM(g_5P1ivoAL(KA|JdNJV2ZcH}u@cGQh0zuDUmx9Z)|?;s0rQ z(`Ul-1`oNScp$1y|8GjXKZXXTQGvM^s~U&L2Y-37%<<-bd);srUiY_}$re=3y#vJ~ z&rq7VkD8h{77RJ_e!1O?3Bt<;wD5E|n}Q_$kGrPbHK)Mb$9|0NMR3T8BJQ$Q=`{6cC!-X2wu5x|@n*a?|xT1j~y zatFKRJv}Wv7d#>NQpxCZQ8wWsPcMyb^?amg$4;pFWVwsScID{`(79R^dD|54G~wiY z-sZ1lMs7%hZIb@SeILO=)1(aX(h4ZN71|C{M_(;>n&gAe)V0Jx8G5`eZNL|PLYs0^ zilK864P>U^4XwNf(2GlKU#Qr^k!T^=zIg=bC_CC>)yI$2^s?vGP)Blk>gqWswJ zr42+=0Xlo^+#>5{aH#<^kCW3~mm@<#me9~I$Q|V@_q@Q;!W&ExmqlQ>ZiZ#5l2?bF zrKf$@Gb}CK&k`-NJeSSRVWpjq6iZW$Juk4daJP0A(mltu<~p>qYDc1#P54@Sd0_?U zKKq^HvI-~{PGqLmG{w$GB+ZmOOd%>1$)$cdkJ`=dQsHW2FcF~yqN(!^&88Hgby-Jkfx*A+LpDP}z z1SEHCbK{N2p&>KVQCeLAx>p%>1ZdvCDJ$ozK#B{FfiUHX0ZcIR%omr+Kf}$ez-O8$ zx#1>{Q;dwmQ(WzF60SUb%1p@9rucv!yQG(r8}5)DF_M8}=;W_a65MW-fx?ygIc4i- z-igdnLgn3Xi|!zAhrb`~uAe5s?M4|W+?j}!kmmsMQD^pEcghZGy!+n% zyQRDw-FKD+qjY$tqbLt-DJ#uxT7H~eN`|{pS}jB2mZboF5KpJpzGqO&u|CuIP)Y(@ zwuZ#CKEL1z%|txqr{8G^8nFYuCtGx2@>At{;>ck#T$#^dxK5uDnEm}m@Bzj=(m4}F zJQRtP50OMb0y`U^F7`*E6F9Am2@{T$U|8u+1oRj-H;tnAw93b_ob`yn*ODlffX@b) z13CqzjCk(WHkyzE2?WZj4Cfb1MNOZsx>@mS8q@RG03-i9@## zu#I+Ea42o{&T(jrha{*qdbK7?uxRR2xaq{(C7|#5;8Og@n^(f8wb`|;3B-m-VrKP+ z@DmUvvub@M12WX~B(^jS#>R$W@X>Xx97Vn~!=&0MTDl&dyBr;^0yHyMOTxkr&n?01 zxgkWFbqFDH0O%Ab-i6`TD;S%)g8pMb7NTAz-qV*MtPP`1jlt3av~8>ov(4L}>r~0p z3gGgozr!(8&Okgc9hyb&fuG*njFVE=(eHQDefZI5OPKSMtp?PJA7O*Ik*>_w*K@Lp z`U5^}-&%(6ECG`3x>^Cc%a)=Uf7}QY#}BuSkKD}uGYTN1fH5W*jC{|Qz;T#9HSl@r5*pAz z487HE{ja?1+XzPtk`b01};>xJCp5 zv>EjfYK~Y|0)9HKt!C@vSpUfj^mj8S#vwDbPZwy2#Hmhq%8u^3$kX9U4c!{9N0YA! zu_SvTw49mh>-Xwdw=R3jvftPvwX?&FJkZZC^oMnT+-HbG|Gw zoCaM)Xu>q1El0vuPC`Mtw{6q+36Brzj(viz-NWVdbdn7^bNMdWDxeC^4ibTw8sVJBxK%U2{?<@+d^R zW#!bQyRNY%MJchGEB(;It=lj;3iWA2+=bgP3s*mLQqs1)3EF^R$(0kT6j<+c^p3_P zrFL4%AMKj$%fM%Q6Rsv1;Z`>ANgbUe~q&G)Ha!vpQp?k9oH>)QMp-L=08){K$GYNcw%eEAD!75w2e5 zgq;M#pk{_J6-^&8c4p~UOR)jJ%jKVNyLMxCSYI2H(L)tvIdTU21{#B;2gX3SogG+q zupzR!o(c~b$~ZjSU}kpS6Hbxbh{>^V`zq-fWx9H68`S9(N5JoFTJmp;y zURwh9Ql{4m0=4pZ^<0|QTm3A&*4ZpK)@_gB({yJm>5+Xyuz^Tp z<>po?^SnkH!jnfL5MTfA`Us^lD(R7JslmqIOY2*ttTQ~=x5CRT^72P5^6v`K*^?T~ z%$#cARl{3&x${5V5hJ%!6d}Ko9@*$m1~MDnUiKmhFAoBD{A(Lqu$A0-A?3>Jb3d|H zZlc05%RY?AgPOdYGb6lS#fK%xl6B3fqfNB|WhC}#TUCr~k>}Pn%T3AbN%FGyNO<2W z2byUho`1ht8i^{+wC8;%4;dp?c!8LCM^iE{2tnk-lF9D7I@+%F)O%rB6HkG*>fVBxbItR~{t)?Qsb_*(Y3k4S5&P{k!CaJQ9wL#C z?x$J;^%JYYa+k77WZK`Gk)X;)&#Vn&!>;@TbKU_u)19}QsxCdgYM*3mXW*;?_cJ#~ zQ+RT9n0C^~^VZEN@^t`NQ@6w{32IKX;Q z1oi2Yig8qbzw}v~X^TJKo|%)3n1wmtg%gdO+zffNT%NB`29W<-iTDp5V6JA$#^UiK zLYO%+BxMM1F9N(@BEgXtPM-LxEm4_h#94FgHbeo)EdwYlE1w5-1uemwD41~am?Dg= z^2`6@%0ONOwv~~A$Wc??HpM$lI60r6x6r&i22fZ=65uSyN$I{CR~5hsBZ8>z@ADL} z9Y$s#v#r3pvw1@+?*Zg(Q~ZqloMEMEjq>wEyCoHrDQl7D5A6I`J5LHMmR?TOKhg;Tkv_; z2cU9`j_}gx_r7>k{to{M*nY_2mFklOvo31p{X18XVSoCCgzFA$3n2Q*g%t! zCuD254FQ-4a@{#Uz29fpCod^L7f9pt;^J{wZ82z76%f^VB!VFc*3Qh!p!K)4A`u9pZrEtVLd6KSG^79S z?J$zD_Rn?BgAKGs5a~A%O%+23%sNUN>(Q^i7Dmty)8|8D#4fhOWw~mb>HAx$#DHd^ zc+63t8-^95XWFt2R{dURr6nlDUBpH~g1MD^vQ?D`Ty`;xGfsszw2G*Y={Skdo_Zu- zUXH!Le-N*)-HCU~i&0%FFnpjNBL)RAFd0Uqaxhjd_$GFZo`}hB{tYL*@F=1LTAPUl zf>AQcCZB+}&i*>;h9522S)`Jv+OiR|p8peueewZf!6G=d%>+#je!V^aBCJ2{9K;3; zlo&VYK1Z!yjsf@Hi>)>F*xo|XzBW3rhp5^Yr&@C(2E%v#RWRnxCc_{k0c>usMdIE+ zBk|{_$>rf!fX;s~w?T{_gW#RNfIekBQfod$@`2Z3HZ(#jFM~1b1Q?h8GfGdIf!OzN zLSp?V*qjWJSEL#KHG5EX{ydmB{20w8J;P=0Vm^2QF2cJZ0#k&CAzyIP3 z5d786(E61jcGtZ&Qx{NCK;ytxG#f=`ejQRx42*uI2>$2I5MxFn_8)g5{y&evinPEH z$#Ie%{_kB1|MxG0@85rf(=76AN&k&oVN(cpI?t~T^rh( zB50T~3)|;kfY3`XBYe$`XrlWuH67aHe??%&PL$qoHT>VX7_r;_8)mS-)cnD#z6CLD zGGaI0iufP?MA4%l-8`M`xa<{#?)eS;*U)#o`7ToLeE_YvD6c?mbt9$3fqvnmB{&oc zNg!zXP?(w6*^0En_my*@&o~zGdml#Zw|CoEFYgDfzy0Fpjs5!nBk}Z781v`CchPw; z8|$D=orJ*Ei(oB&0I`d{i^ST0Knn!O8)C|GzaNm7Vfos6yj(dI(J^Czhn~QT53a!C zPyG1fx&#()^5d0zUx9ey8AK*c#$STtvFx2ac&#Ren%SpAPb7#@??bXR3TwasxmuvC z6tR0AM)Lg)&=<~!Hn@_u=R_bz9R=g8FA*!hgT%v6LmN0iGO@-wn)Gx0clVLp2*7v# znPeQM+<8J~ADd3LMKBoXIiMN5JOhF>;|Et&S+-@bdEdHVmMtxoAT@XHM&h9-p_LSK z57~pxFShzfpK75X5_kUz@&8&3YhN?XZZa76h0*ryA0m3o?XdV-^jXWa4{&D}T8Ljk zGUQI30gYr$;?*}LGxMrormr10e2BmF2I*;H@;NgQG!rNuUWuZaQ;~ZAA22`OWZx5k zTdpR4@{Kp`L-Ms15F>{}Odb!bH4OdO$z%fzBCY?1G;F2C%HKg!gn=!uwXp{J%;|En z%EM~%q*{DAJx}GJLG4)W5ks5l<*B^9T+17|LCY~SoESY4sdejN?bsz*tbHlg(i&T) zrv=Hl+KK3mzeMt>zmgs;C4g*3;>A~?4Jfw(WTw(SW80ZvlAFxpWq;HNSiAPX+PMqD zZ~L_E+BlRD#Q@#517>{#v@xS#@~XjuQ!!9ppS>*mC6}aW#QcbWZWs_p9|d+G@-y&# zo1fI!_ma5;(*(7`5ty4kg*Id`v_S)DawPI#2yK6UX=$k?l|yeNhoey@O`IS{TJyT* zVBj&UvaBGMwszFQViwdg^|dM4*b39DF-%O@28}%*?Wuc)&7SPvwYr!vJTVB+%!pP~ zI1SEDU}FHcw8`(06N9f=Mn+qJfKDK{qaj+S>?-=q-X{D02lThUjwA-yMc25mV-jW_ zC`j*>t~;8T8p#$b56<&omB3FhX7p&9+Xg*is!N9M*2^(|{5Z5*OZgD@W_iH?ATZb< zNJsIaF^I9F;J@y>_HyskM_?>(+lly{_uBoC23WV7^(djjVn#H(0#O?H36c{eKWyI| z4FUPB<^LV@8MgsIb2cOh@9quQZ zENm>cYjcrVsw|zP&Hmw*RvVP;f|KkXIKc6(d~bdmoOJ*4Qv4k0>sXGY${+wY_LA_n++c%@fWQW!e#}G}kdXdoU#B^3aNvSi zZAg{$B$#A8S{&*=*iHZj905~$D(G`!)Nnfh;(U&^FkP1oI&ENonCmyn`(gvqBm+{X z`}tfDB%M4WrcRXJ40F?F`Y#ncLaI>FSYIR2^bN3P0eCM7nnK|{w+j5mK32>>EtE5Yg z{o|5Rc{N}VlHXhm8wz9I$x`~HC~B#d^@B-nIcv*jFupvOCP%q_&pa{d#h=$tIZ>_> zDY_T=eEeJ<*U#MlXPr4ez0jq4A6Ri_z}!<$!Jvu?N%`LPLz|KTlYe^+$-le+-?U3?vT7 z_%1wKdK;|9Ci(LH%Y`t`KMTp1{*KhU?~{A5NNW4Uqt8lB9k~8VieQeCD~Z*xS5CaZ zkFSClUM+JoB-klu!>rvcKcgQr0f8S}A@7Z)l(oAa`f*bcxb{18Wl20uF2`WN^HD+u zutibpbI&=uTe;D#m&1`AB_$=e;QWQwAMW`d>U+)m1|qQ)2S->}8t2W2aq29jKG-1j zF6&#CB4RKFE#6*(=uN*OmW|nAAhh^41n>FS{d&xvGZ%St5_{SW#)EI1eL5v8jkfb0h@s7`+mU?r4Fb>- zfS2n~ConT;iA@DX>w>?z1&PO=MVz9F?fTcr<{L4bz;+3YlV^ZfK}H%=udk%Miw8+J z@22a9GJ-lJhv=Hd7w5qLt$&u_mzsQAtpu`Ua4CsIhi8T(i6muwm;4ia3%_g|m88*A z>oy>9-=C3Ox!U%ddz_sayo|#?-nSU%EnFZ;mW{(c0otK^zUVg>U5;m;dtL(E^DLcq z)v?Ur2pngrNmm=W^kiU#@+qXuFpTa2;ee~FtUh+JaVVM$G-gZ=)Nmj~eh<6tI$xKK zM#|IR`;kEx{x?km2D+Rq8NTt%V2*qS&f{SAX0OTKM*Ft%AR)9O#2++%kuL_3hv_wRgfo`CtJStm*`^WS@dJFO?~I2nziP78;_ zIBv!)tFFF5vsb_Z-HEB%VQX)a)R;VJ;z5nUUe&g9JRW6bW%%8lccc@aG=*l>a?+TI zSqa?o)0-uj8GCvUed(e%U&0qYbN(5)`pWOhtVo~FP`$5ORvT|DVK)BK7w6&!|L>X} zOO0Mhj?QVNOwngAI3FwCe2Zp|t+7>8EnB*I2<36FdTRyk#4m1lO5~)RuCtqk+vATs zgbCxv%Gs1RMxts*6wE0ynkj)F&p-2&1Tzz5Z*z#WzT{{)?vp)rbvWS*v!$`fH>8+a zwL<|jx0hc0D`uQ%UG_`7d(abC>$|x{&s9^3h zLw9ECNF;*uF8nH1tzH9Ll~|f`>8aKeVr0q6nwez=ZLc~cFdy=f6b@5!0@F(`F2$m6 zT>=NpN>{7aoy35Q8JXnGm?sUuY=HTY85*6!1UpUQ`dtZL;+g?nHz_*Z~M<* z%Akq!f7#j*rDc03O6E*k@#ae0`m0~dpAP7Gx#92h{DuM5dIaLkas!+-cf*galern$ zWaXR!+L0ic5uVroz8v@6{{WUPdy!Ih?M$-tzA($)o^B~a65cKXlR#_W1e1uIk zHQHWEPH%2*roE+c1rm>VE4bDim*?V&MjVgex*1$*VAQCQ-HyMf0o_@OFk^Q%0{Avs zY3ou0Z4M1bnrXL@t{5BcE@{hEKsmU^wdOj5)o~JZHP(3p=+D)kPHQQaCA!DA+826r zSlIDc9H}}knp^5^IJco#*@IO<0oRlp(=3G`)u7H;QB5@kXw_6xfL2YlUbO!M*Z1pR T*IiIZ00000NkvXXu0mjfN0#Zx literal 0 HcmV?d00001 diff --git a/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png b/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..36586f1e1e3511ea95061eb712323d05273a89f1 GIT binary patch literal 3857 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, + port: Mutex, + url: Mutex, +} + +#[derive(Serialize, Clone)] +struct ServerInfo { + ip: String, + port: u16, + url: String, +} + +fn lan_ipv4() -> String { + local_ip_address::local_ip() + .map(|ip| ip.to_string()) + .unwrap_or_else(|_| "127.0.0.1".to_string()) +} + +#[tauri::command] +fn lan_ip() -> String { + lan_ipv4() +} + +// Can we bind this TCP port on the LAN interface? (i.e. is it free) +fn is_port_free(port: u16) -> bool { + TcpListener::bind(("0.0.0.0", port)).is_ok() +} + +#[tauri::command] +fn port_free(port: u16) -> bool { + is_port_free(port) +} + +// First free port at/after `start` (so the UI can offer an alternative). +#[tauri::command] +fn suggest_port(start: u16) -> u16 { + let mut p = start.max(1024); + for _ in 0..200 { + if is_port_free(p) { + return p; + } + p = p.saturating_add(1); + } + start +} + +#[tauri::command] +fn default_xplane_path() -> Option { + let home = std::env::var("HOME") + .or_else(|_| std::env::var("USERPROFILE")) + .unwrap_or_default(); + let candidates = [ + format!("{home}/X-Plane 12"), + format!("{home}/Desktop/X-Plane 12"), + "/Applications/X-Plane 12".to_string(), + "C:/X-Plane 12".to_string(), + "D:/X-Plane 12".to_string(), + ]; + candidates + .into_iter() + .find(|c| PathBuf::from(c).join("Resources").join("default data").is_dir()) +} + +#[tauri::command] +fn valid_xplane_path(path: String) -> bool { + !path.is_empty() + && PathBuf::from(&path) + .join("Resources") + .join("default data") + .is_dir() +} + +#[tauri::command] +fn server_running(state: State) -> bool { + state.child.lock().unwrap().is_some() +} + +#[tauri::command] +async fn start_server( + app: tauri::AppHandle, + state: State<'_, ServerState>, + xplane_path: String, + port: u16, + demo: bool, +) -> Result { + if state.child.lock().unwrap().is_some() { + let p = *state.port.lock().unwrap(); + let ip = lan_ipv4(); + return Ok(ServerInfo { url: format!("http://{ip}:{p}"), ip, port: p }); + } + if !is_port_free(port) { + return Err(format!("Port {port} ist belegt — wähle einen anderen.")); + } + + let web_dist = app + .path() + .resolve("web", tauri::path::BaseDirectory::Resource) + .map_err(|e| format!("resource path: {e}"))?; + + let mut cmd = app + .shell() + .sidecar("xpbridge") + .map_err(|e| format!("sidecar: {e}"))? + .env("BRIDGE_PORT", port.to_string()) + .env("BRIDGE_HOST", "0.0.0.0") + .env("WEB_DIST", web_dist.to_string_lossy().to_string()); + + if !xplane_path.is_empty() { + cmd = cmd.env("XPLANE_ROOT", xplane_path); + } + if demo { + cmd = cmd.env("DEMO", "1"); + } + + let (mut rx, child) = cmd.spawn().map_err(|e| format!("spawn: {e}"))?; + + let app2 = app.clone(); + tauri::async_runtime::spawn(async move { + while let Some(event) = rx.recv().await { + let line = match event { + CommandEvent::Stdout(b) | CommandEvent::Stderr(b) => { + String::from_utf8_lossy(&b).to_string() + } + CommandEvent::Terminated(_) => { + let _ = app2.emit("server-exited", ()); + break; + } + _ => continue, + }; + let _ = app2.emit("server-log", line); + } + }); + + let ip = lan_ipv4(); + let url = format!("http://{ip}:{port}"); + *state.child.lock().unwrap() = Some(child); + *state.port.lock().unwrap() = port; + *state.url.lock().unwrap() = url.clone(); + + Ok(ServerInfo { url, ip, port }) +} + +#[tauri::command] +fn stop_server(state: State) -> Result<(), String> { + if let Some(child) = state.child.lock().unwrap().take() { + child.kill().map_err(|e| format!("kill: {e}"))?; + } + *state.url.lock().unwrap() = String::new(); + Ok(()) +} + +fn kill_sidecar(app: &tauri::AppHandle) { + if let Some(state) = app.try_state::() { + if let Some(child) = state.child.lock().unwrap().take() { + let _ = child.kill(); + } + } +} + +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::Builder::default() + .plugin(tauri_plugin_shell::init()) + .plugin(tauri_plugin_dialog::init()) + .plugin(tauri_plugin_opener::init()) + .plugin(tauri_plugin_clipboard_manager::init()) + .plugin(tauri_plugin_updater::Builder::new().build()) + .plugin(tauri_plugin_process::init()) + .manage(ServerState::default()) + .invoke_handler(tauri::generate_handler![ + lan_ip, + port_free, + suggest_port, + default_xplane_path, + valid_xplane_path, + server_running, + start_server, + stop_server + ]) + .setup(|app| { + build_tray(app.handle())?; + Ok(()) + }) + // Closing the window hides it instead of quitting, so the server keeps + // serving tablets in the background. Quit from the tray. + .on_window_event(|window, event| { + if let tauri::WindowEvent::CloseRequested { api, .. } = event { + api.prevent_close(); + let _ = window.hide(); + } + }) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} + +fn build_tray(app: &tauri::AppHandle) -> tauri::Result<()> { + let show = MenuItem::with_id(app, "show", "Panel anzeigen", true, None::<&str>)?; + let open = MenuItem::with_id(app, "open", "Cockpit öffnen", true, None::<&str>)?; + let copy = MenuItem::with_id(app, "copy", "URL kopieren", true, None::<&str>)?; + let toggle = MenuItem::with_id(app, "toggle", "Server starten / stoppen", true, None::<&str>)?; + let quit = MenuItem::with_id(app, "quit", "Beenden", true, None::<&str>)?; + let sep = PredefinedMenuItem::separator(app)?; + let menu = MenuBuilder::new(app) + .item(&show) + .item(&open) + .item(©) + .item(&sep) + .item(&toggle) + .item(&sep) + .item(&quit) + .build()?; + + TrayIconBuilder::with_id("main") + .icon(app.default_window_icon().unwrap().clone()) + .tooltip("X-Plane Cockpit") + .menu(&menu) + .show_menu_on_left_click(false) + .on_menu_event(|app, event| match event.id().as_ref() { + "show" => show_main(app), + "open" => { let _ = app.emit("tray-open", ()); } + "copy" => { + if let Some(state) = app.try_state::() { + let url = state.url.lock().unwrap().clone(); + if !url.is_empty() { + let _ = app.clipboard().write_text(url); + } + } + } + "toggle" => { let _ = app.emit("tray-toggle", ()); } + "quit" => { kill_sidecar(app); app.exit(0); } + _ => {} + }) + .on_tray_icon_event(|tray, event| { + if let TrayIconEvent::Click { .. } = event { + show_main(tray.app_handle()); + } + }) + .build(app)?; + Ok(()) +} + +fn show_main(app: &tauri::AppHandle) { + if let Some(win) = app.get_webview_window("main") { + let _ = win.show(); + let _ = win.set_focus(); + } +} diff --git a/desktop/src-tauri/src/main.rs b/desktop/src-tauri/src/main.rs new file mode 100644 index 0000000..9afb3a1 --- /dev/null +++ b/desktop/src-tauri/src/main.rs @@ -0,0 +1,6 @@ +// Prevents an extra console window on Windows in release. +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + xplane_cockpit_lib::run() +} diff --git a/desktop/src-tauri/tauri.conf.json b/desktop/src-tauri/tauri.conf.json new file mode 100644 index 0000000..f363e17 --- /dev/null +++ b/desktop/src-tauri/tauri.conf.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://schema.tauri.app/config/2", + "productName": "X-Plane Cockpit", + "version": "0.1.3", + "identifier": "ch.kgva.xplanecockpit", + "build": { + "frontendDist": "../ui" + }, + "app": { + "withGlobalTauri": true, + "windows": [ + { + "title": "X-Plane Cockpit", + "width": 480, + "height": 720, + "minWidth": 420, + "minHeight": 560, + "resizable": true + } + ], + "security": { + "csp": null + } + }, + "bundle": { + "active": true, + "targets": [ + "app", + "dmg", + "appimage", + "deb" + ], + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ], + "externalBin": [ + "binaries/xpbridge" + ], + "resources": { + "resources/web": "web" + }, + "createUpdaterArtifacts": true, + "macOS": { + "minimumSystemVersion": "10.15" + }, + "linux": { + "appimage": { + "bundleMediaFramework": false + } + } + }, + "plugins": { + "updater": { + "endpoints": [ + "https://git.kgva.ch/karim/xplane-cockpit/releases/download/updater/latest.json" + ], + "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDU5MzFGQTUzOEUyOURFOTkKUldTWjNpbU9VL294V1ZWZllVMzc5MGR6OVFVcGRkSTVkcG1LUDJXODJzT2psbFZoY2JYT0E3dEIK" + } + } +} diff --git a/desktop/ui/index.html b/desktop/ui/index.html new file mode 100644 index 0000000..052d8c6 --- /dev/null +++ b/desktop/ui/index.html @@ -0,0 +1,83 @@ + + + + + + X-Plane Cockpit + + + +

+ + + diff --git a/desktop/ui/main.js b/desktop/ui/main.js new file mode 100644 index 0000000..d3b5e3a --- /dev/null +++ b/desktop/ui/main.js @@ -0,0 +1,194 @@ +// Control-panel logic. Uses the global Tauri API (withGlobalTauri). +const T = window.__TAURI__ || {}; +const invoke = T.core.invoke; +const listen = T.event.listen; + +const $ = (id) => document.getElementById(id); +const xpPath = $('xpPath'), portEl = $('port'), demoEl = $('demo'); +const startBtn = $('startBtn'), liveCard = $('liveCard'), urlEl = $('url'); +const statusEl = $('status'), statusText = $('statusText'), logEl = $('log'); + +let running = false, healthTimer = null; + +function setStatus(kind, text) { + statusEl.className = 'status ' + kind; + statusText.textContent = text; +} + +async function validatePath() { + const p = xpPath.value.trim(); + const hint = $('xpHint'); + if (!p) { hint.textContent = ''; hint.className = 'hint'; return false; } + const ok = await invoke('valid_xplane_path', { path: p }); + hint.textContent = ok ? '✓ X-Plane erkannt' : '⚠ kein „Resources/default data“ — Demo-Modus nutzen oder Pfad prüfen'; + hint.className = 'hint ' + (ok ? 'ok' : 'bad'); + return ok; +} + +// Is the chosen port free? If not, offer the next free one. +async function validatePort() { + const hint = $('portHint'); + const port = parseInt(portEl.value, 10) || 0; + if (port < 1024 || port > 65535) { hint.textContent = '⚠ Port 1024–65535'; hint.className = 'hint bad'; return false; } + const free = await invoke('port_free', { port }); + if (free) { hint.textContent = '✓ Port frei'; hint.className = 'hint ok'; return true; } + const alt = await invoke('suggest_port', { start: port + 1 }); + hint.innerHTML = `⚠ Port ${port} belegt — ${alt} verwenden`; + hint.className = 'hint bad'; + const a = $('usePort'); + if (a) a.onclick = (e) => { e.preventDefault(); portEl.value = alt; validatePort(); }; + return false; +} + +async function init() { + try { $('ver').textContent = 'v' + (await T.app.getVersion()); } catch {} + try { + const def = await invoke('default_xplane_path'); + if (def) { xpPath.value = def; validatePath(); } + } catch {} + validatePort(); + checkUpdate(true); // silent on launch +} + +xpPath.addEventListener('change', validatePath); +xpPath.addEventListener('blur', validatePath); +portEl.addEventListener('change', validatePort); +portEl.addEventListener('blur', validatePort); + +$('browse').addEventListener('click', async () => { + try { + const dir = await T.dialog.open({ directory: true, multiple: false, title: 'X-Plane 12 Ordner wählen' }); + if (dir) { xpPath.value = dir; validatePath(); } + } catch (e) { appendLog('dialog: ' + e); } +}); + +startBtn.addEventListener('click', async () => { + if (running) return stop(); + if (!(await validatePort())) return; // refuse a busy port up front + startBtn.disabled = true; + try { + const info = await invoke('start_server', { + xplanePath: xpPath.value.trim(), + port: parseInt(portEl.value, 10) || 8080, + demo: demoEl.checked, + }); + running = true; + urlEl.textContent = info.url; + liveCard.classList.remove('hidden'); + startBtn.textContent = 'Server stoppen'; + startBtn.classList.add('stop'); + setStatus('warn', 'Server läuft · warte auf Sim'); + pollHealth(info.port); + } catch (e) { + appendLog('Fehler: ' + e); + setStatus('off', 'Fehler'); + } finally { + startBtn.disabled = false; + } +}); + +async function stop() { + startBtn.disabled = true; + try { await invoke('stop_server'); } catch (e) { appendLog('stop: ' + e); } + resetUi(); + startBtn.disabled = false; +} + +function resetUi() { + running = false; + liveCard.classList.add('hidden'); + startBtn.textContent = 'Server starten'; + startBtn.classList.remove('stop'); + setStatus('off', 'Gestoppt'); + if (healthTimer) { clearInterval(healthTimer); healthTimer = null; } +} + +function pollHealth(port) { + if (healthTimer) clearInterval(healthTimer); + const dXp = $('dXp'), dClients = $('dClients'), dNav = $('dNav'), dRefs = $('dRefs'); + const check = async () => { + try { + const r = await fetch(`http://127.0.0.1:${port}/api/health`, { cache: 'no-store' }); + const d = await r.json(); + const sim = d.xpConnected; + if (sim) setStatus('run', demoEl.checked ? 'Demo läuft' : 'X-Plane verbunden'); + else setStatus('warn', 'Server läuft · kein Sim'); + dXp.textContent = sim ? (demoEl.checked ? 'Demo' : 'verbunden') : 'kein Sim'; + dXp.className = sim ? 'ok' : 'warn'; + dClients.textContent = d.clients ?? 0; + const n = d.nav || {}; + dNav.textContent = n.loaded ? `${n.airports ?? 0} APT · ${n.navaids ?? 0} Navaids` : 'lädt…'; + dRefs.textContent = d.datarefs ?? 0; + } catch { setStatus('warn', 'Server läuft'); } + }; + check(); + healthTimer = setInterval(check, 3000); +} + +$('copy').addEventListener('click', async () => { + try { await navigator.clipboard.writeText(urlEl.textContent); $('copy').textContent = '✓'; setTimeout(() => ($('copy').textContent = '⧉'), 1200); } catch {} +}); + +const openUrl = (u) => { try { T.opener.openUrl(u); } catch (e) { appendLog('open: ' + e); } }; +$('openBtn').addEventListener('click', () => openUrl(urlEl.textContent)); +document.querySelectorAll('.quick .btn').forEach((b) => + b.addEventListener('click', () => openUrl(urlEl.textContent + '/#' + b.dataset.page))); + +function appendLog(line) { + logEl.textContent += line; + if (logEl.textContent.length > 8000) logEl.textContent = logEl.textContent.slice(-6000); + logEl.scrollTop = logEl.scrollHeight; +} +listen('server-log', (e) => appendLog(e.payload)); +listen('server-exited', () => { appendLog('\n[Server beendet]\n'); resetUi(); }); + +// Tray actions routed to the panel (which holds the current URL + start logic). +listen('tray-open', () => { if (urlEl.textContent && urlEl.textContent !== '—') openUrl(urlEl.textContent); }); +listen('tray-toggle', () => startBtn.click()); + +/* ---------------- updates ---------------- */ +let pendingUpdate = null; +async function checkUpdate(silent) { + const btn = $('updateBtn'); + if (!silent) { btn.disabled = true; btn.textContent = 'Suche…'; } + try { + const update = await T.updater.check(); + if (update) { + pendingUpdate = update; + $('ubTitle').textContent = `Update ${update.version} verfügbar`; + $('ubNotes').textContent = update.body || ''; + $('updateBanner').classList.remove('hidden'); + if (!document.querySelector('.update-badge')) { + const dot = document.createElement('span'); dot.className = 'update-badge'; btn.after(dot); + } + if (!silent) { btn.textContent = 'Nach Updates suchen'; btn.disabled = false; } + } else if (!silent) { + btn.textContent = 'Aktuell ✓'; + setTimeout(() => { btn.textContent = 'Nach Updates suchen'; btn.disabled = false; }, 2500); + } + } catch (e) { + if (!silent) { + appendLog('update: ' + e); + btn.textContent = 'Update fehlgeschlagen'; + setTimeout(() => { btn.textContent = 'Nach Updates suchen'; btn.disabled = false; }, 2500); + } + } +} + +async function installUpdate() { + if (!pendingUpdate) return; + $('ubInstall').disabled = true; $('ubInstall').textContent = 'Lädt…'; + try { + await pendingUpdate.downloadAndInstall(); + await T.process.relaunch(); + } catch (e) { + appendLog('install: ' + e); + $('ubInstall').disabled = false; $('ubInstall').textContent = 'Installieren'; + } +} + +$('updateBtn').addEventListener('click', () => checkUpdate(false)); +$('ubInstall').addEventListener('click', installUpdate); +$('ubDismiss').addEventListener('click', () => $('updateBanner').classList.add('hidden')); + +init(); diff --git a/desktop/ui/styles.css b/desktop/ui/styles.css new file mode 100644 index 0000000..b81d13c --- /dev/null +++ b/desktop/ui/styles.css @@ -0,0 +1,89 @@ +/* macOS-style dark theme: neutral graphite surfaces, SF system font, subtle + separators, a single green accent for the running/start state. No blue. */ +:root { + --bg: #1c1c1e; /* system background (dark) */ + --bg2: #2c2c2e; /* elevated surface */ + --bg3: #3a3a3c; /* control fill */ + --line: #48484a; /* separators / borders */ + --line-soft: #38383a; + --txt: #ffffff; + --txt2: #ebebf5; + --mut: #8e8e93; /* secondary label */ + --green: #30d158; /* system green */ + --green-d: #248a3d; + --amber: #ffd60a; + --red: #ff453a; +} +* { box-sizing: border-box; } +html, body { margin: 0; height: 100%; } +body { + background: var(--bg); + color: var(--txt); + font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, sans-serif; + font-size: 13px; user-select: none; -webkit-font-smoothing: antialiased; +} +.panel { display: flex; flex-direction: column; height: 100vh; padding: 16px; gap: 14px; } +.hd { display: flex; align-items: center; justify-content: space-between; } +.brand { font-weight: 700; letter-spacing: .2px; font-size: 17px; } +.brand span { color: var(--mut); font-weight: 500; } +.status { display: flex; align-items: center; gap: 7px; font-size: 12px; padding: 4px 10px; border-radius: 999px; border: 1px solid var(--line-soft); background: var(--bg2); color: var(--txt2); } +.status .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--mut); transition: background .2s; } +.status.run .dot { background: var(--green); box-shadow: 0 0 8px var(--green); } +.status.warn .dot { background: var(--amber); box-shadow: 0 0 8px var(--amber); } + +main { flex: 1; display: flex; flex-direction: column; gap: 12px; overflow-y: auto; } +.card { background: var(--bg2); border: 1px solid var(--line-soft); border-radius: 12px; padding: 14px; display: flex; flex-direction: column; gap: 9px; } +.lbl { color: var(--mut); font-size: 11px; font-weight: 600; } +.row { display: flex; gap: 8px; align-items: center; } +.row.gap { gap: 16px; margin-top: 2px; } +.field { display: flex; flex-direction: column; gap: 6px; } +.field input { width: 96px; } +input[type="text"], input[type="number"] { + flex: 1; background: var(--bg); border: 1px solid var(--line); color: var(--txt); + border-radius: 7px; padding: 8px 10px; font-size: 13px; font-family: inherit; +} +input:focus { outline: none; border-color: var(--green); box-shadow: 0 0 0 3px rgba(48,209,88,.2); } +.toggle { display: flex; align-items: center; gap: 8px; color: var(--txt2); cursor: pointer; align-self: flex-end; padding-bottom: 8px; } +.toggle input { width: 15px; height: 15px; accent-color: var(--green); } +.hint { font-size: 12px; min-height: 16px; color: var(--mut); } +.hint.ok { color: var(--green); } .hint.bad { color: var(--amber); } +.hint a { color: var(--green); } + +.btn { border: 1px solid var(--line); background: var(--bg3); color: var(--txt); border-radius: 8px; padding: 8px 14px; font-size: 13px; font-family: inherit; cursor: pointer; transition: filter .12s, background .12s; } +.btn:hover { filter: brightness(1.18); } +.btn:active { transform: translateY(1px); } +.btn.ghost { background: transparent; color: var(--txt2); border-color: var(--line); } +.btn.sm { padding: 5px 10px; font-size: 12px; } +.btn.big { padding: 13px; font-size: 15px; font-weight: 600; } +.btn.primary { background: var(--green); color: #042b10; border-color: transparent; font-weight: 600; } +.btn.big.stop { background: var(--red); color: #2a0603; } +.btn.ok { background: var(--green); color: #042b10; border-color: transparent; font-weight: 600; } +.btn:disabled { opacity: .45; cursor: default; } + +.update-banner { display: flex; gap: 10px; align-items: center; justify-content: space-between; background: rgba(48,209,88,.10); border: 1px solid var(--green-d); border-radius: 12px; padding: 10px 12px; } +.update-banner.hidden { display: none; } +.ub-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; } +.ub-text b { color: var(--green); font-size: 13px; } +.ub-text span { color: var(--mut); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 230px; } +.ub-actions { display: flex; gap: 6px; flex: 0 0 auto; } + +.live.hidden { display: none; } +.url-row { display: flex; gap: 8px; align-items: center; } +.url-row code { flex: 1; background: var(--bg); border: 1px solid var(--line); color: var(--green); border-radius: 7px; padding: 10px 12px; font-size: 16px; font-weight: 600; letter-spacing: .3px; user-select: text; font-family: ui-monospace, "SF Mono", Menlo, monospace; } +.quick { display: flex; gap: 6px; } +.quick .btn { flex: 1; } + +.diag { margin-top: 10px; border-top: 1px solid var(--line-soft); padding-top: 8px; display: flex; flex-direction: column; gap: 5px; } +.diag-row { display: flex; justify-content: space-between; font-size: 12px; color: var(--mut); } +.diag-row b { color: var(--txt2); font-weight: 600; } +.diag-row b.ok { color: var(--green); } .diag-row b.warn { color: var(--amber); } + +.log-wrap { background: var(--bg2); border: 1px solid var(--line-soft); border-radius: 12px; padding: 6px 12px; } +.log-wrap summary { color: var(--mut); font-size: 12px; cursor: pointer; padding: 4px 0; } +#log { margin: 6px 0 2px; max-height: 140px; overflow-y: auto; font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 11px; color: var(--mut); white-space: pre-wrap; } + +.ft { display: flex; align-items: center; justify-content: space-between; color: var(--mut); font-size: 12px; } +.link { background: none; border: none; color: var(--green); cursor: pointer; font-size: 12px; font-family: inherit; } +.link:hover { text-decoration: underline; } +.link:disabled { color: var(--mut); cursor: default; text-decoration: none; } +.update-badge { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--green); margin-left: 6px; box-shadow: 0 0 6px var(--green); vertical-align: middle; } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6e725a6 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,900 @@ +{ + "name": "xplane-glass-cockpit", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "xplane-glass-cockpit", + "version": "0.1.0", + "hasInstallScript": true, + "dependencies": { + "express": "^4.21.2", + "ws": "^8.18.0" + }, + "devDependencies": { + "playwright": "^1.60.0" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "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/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.5", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.15.1", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "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/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/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/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/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "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/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "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.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" + }, + "node_modules/playwright": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", + "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.60.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", + "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/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/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..ce27569 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "xplane-glass-cockpit", + "version": "0.1.0", + "description": "Bring X-Plane 12 instruments (PFD/MFD, G1000-style, autopilot) to any tablet or laptop on your LAN via React.", + "type": "module", + "scripts": { + "postinstall": "cd web && npm install", + "build": "cd web && npm run build", + "start": "node server/bridge.js", + "dev:bridge": "node --watch server/bridge.js", + "dev:web": "cd web && npm run dev" + }, + "dependencies": { + "express": "^4.21.2", + "ws": "^8.18.0" + }, + "devDependencies": { + "playwright": "^1.60.0" + } +} diff --git a/scripts/build-linux.sh b/scripts/build-linux.sh new file mode 100644 index 0000000..6df42bf --- /dev/null +++ b/scripts/build-linux.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Build the Linux AppImage + .deb (x86_64) in Docker. Run from the repo root, +# AFTER scripts/prep-desktop.sh has produced the linux sidecar + web resources. +# On Apple Silicon this runs under qemu (linux/amd64) and is slow but works. +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +IMG=xpcockpit-linux-builder +echo "==> building docker image ($IMG)" +docker build --platform linux/amd64 -f desktop/Dockerfile.linux -t "$IMG" desktop >/dev/null + +# The updater signing key is a secret and is NOT in the repo. If it's present +# locally we sign + emit updater artifacts; otherwise we build plain installable +# bundles (appimage + deb) with updater artifacts disabled via a config override. +SIGN_ENV=(); BUNDLES="appimage,deb,updater"; CFG="" +if [[ -f desktop/.tauri-signing.key && -f desktop/.tauri-signing.pw ]]; then + SIGN_ENV=(-e "TAURI_SIGNING_PRIVATE_KEY=$(cat desktop/.tauri-signing.key)" + -e "TAURI_SIGNING_PRIVATE_KEY_PASSWORD=$(cat desktop/.tauri-signing.pw)") + echo "==> signing key found — emitting signed updater artifacts" +else + BUNDLES="appimage,deb"; CFG='--config {"bundle":{"createUpdaterArtifacts":false}}' + echo "==> no signing key — building plain appimage + deb (no updater artifacts)" +fi + +echo "==> tauri build (x86_64-unknown-linux-gnu) in container — this takes a while under emulation" +docker run --rm --platform linux/amd64 \ + -v "$ROOT":/work \ + -e CARGO_TARGET_DIR=/work/target-linux \ + -e APPIMAGE_EXTRACT_AND_RUN=1 \ + -e ARCH=x86_64 \ + "${SIGN_ENV[@]}" \ + -w /work/desktop \ + "$IMG" \ + bash -c "export PATH=/usr/local/cargo/bin:\$PATH; tauri build --target x86_64-unknown-linux-gnu --bundles $BUNDLES $CFG" + +echo "==> artifacts:" +find target-linux/x86_64-unknown-linux-gnu/release/bundle -maxdepth 2 -type f \ + \( -name '*.AppImage' -o -name '*.deb' -o -name '*.AppImage.sig' -o -name '*.tar.gz' -o -name '*.sig' \) 2>/dev/null diff --git a/scripts/prep-desktop.sh b/scripts/prep-desktop.sh new file mode 100755 index 0000000..86337c0 --- /dev/null +++ b/scripts/prep-desktop.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Prepare the Tauri bundle inputs: build the web cockpit, copy it in as a +# resource, and compile the Node bridge into Bun single-file sidecars named with +# the Tauri target triples. Run from the repo root. +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" +export PATH="$HOME/.bun/bin:$PATH" + +echo "==> building web cockpit" +( cd web && npm run build >/dev/null ) + +echo "==> copying cockpit into desktop resources" +rm -rf desktop/src-tauri/resources/web +mkdir -p desktop/src-tauri/resources/web +cp -R web/dist/. desktop/src-tauri/resources/web/ + +echo "==> compiling bridge sidecars (Bun)" +mkdir -p desktop/src-tauri/binaries +bun build --compile --target=bun-darwin-arm64 server/bridge.js \ + --outfile desktop/src-tauri/binaries/xpbridge-aarch64-apple-darwin +bun build --compile --target=bun-linux-x64-baseline server/bridge.js \ + --outfile desktop/src-tauri/binaries/xpbridge-x86_64-unknown-linux-gnu +chmod +x desktop/src-tauri/binaries/xpbridge-* + +echo "==> done" +ls -lh desktop/src-tauri/binaries/ diff --git a/scripts/release-gitea.mjs b/scripts/release-gitea.mjs new file mode 100644 index 0000000..16b63aa --- /dev/null +++ b/scripts/release-gitea.mjs @@ -0,0 +1,119 @@ +#!/usr/bin/env node +// Publish a release to Gitea and (re)write the updater's latest.json. +// +// Reads the built artifacts (macOS .app.tar.gz + .sig, Linux .AppImage + .sig, +// plus .dmg / .deb for manual install), creates a versioned release with those +// assets, then builds latest.json (Tauri v2 updater format) pointing at the +// release download URLs and uploads it to a fixed-tag "updater" release so the +// app's updater endpoint URL stays constant. +// +// Env: GITEA_URL (e.g. https://git.kgva.ch), GITEA_REPO (owner/name), +// GITEA_TOKEN (or a token file at /tmp/gitea_token). +import fs from 'node:fs'; +import path from 'node:path'; + +const ROOT = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..'); +const GITEA_URL = (process.env.GITEA_URL || 'https://git.kgva.ch').replace(/\/$/, ''); +const REPO = process.env.GITEA_REPO || 'karim/xplane-cockpit'; +const TOKEN = process.env.GITEA_TOKEN + || (fs.existsSync('/tmp/gitea_token') ? fs.readFileSync('/tmp/gitea_token', 'utf8').trim() : ''); +const VERSION = JSON.parse(fs.readFileSync(path.join(ROOT, 'desktop/src-tauri/tauri.conf.json'), 'utf8')).version; +const UPDATER_TAG = 'updater'; + +if (!TOKEN) { console.error('No GITEA_TOKEN (env or /tmp/gitea_token).'); process.exit(1); } + +const api = (p, opts = {}) => fetch(`${GITEA_URL}/api/v1${p}`, { + ...opts, + headers: { Authorization: `token ${TOKEN}`, Accept: 'application/json', ...(opts.headers || {}) }, +}); + +// Collect built artifacts that exist (mac and/or linux builds may have run). +function findArtifacts() { + const macBundle = path.join(ROOT, 'desktop/src-tauri/target/aarch64-apple-darwin/release/bundle'); + const linBundle = path.join(ROOT, 'target-linux/x86_64-unknown-linux-gnu/release/bundle'); + const out = { assets: [], updater: {} }; + const add = (file, platformKey) => { + if (!fs.existsSync(file)) return; + out.assets.push(file); + if (platformKey) { + const sig = file + '.sig'; + if (fs.existsSync(sig)) out.updater[platformKey] = { file, sig: fs.readFileSync(sig, 'utf8').trim() }; + } + }; + const glob1 = (dir, re) => fs.existsSync(dir) ? fs.readdirSync(dir).filter((f) => re.test(f)).map((f) => path.join(dir, f)) : []; + // macOS + glob1(path.join(macBundle, 'macos'), /\.app\.tar\.gz$/).forEach((f) => add(f, 'darwin-aarch64')); + glob1(path.join(macBundle, 'dmg'), /\.dmg$/).forEach((f) => out.assets.push(f)); + // Linux + glob1(path.join(linBundle, 'appimage'), /\.AppImage$/).forEach((f) => add(f, 'linux-x86_64')); + glob1(path.join(linBundle, 'deb'), /\.deb$/).forEach((f) => out.assets.push(f)); + return out; +} + +async function getReleaseByTag(tag) { + const r = await api(`/repos/${REPO}/releases/tags/${encodeURIComponent(tag)}`); + return r.ok ? r.json() : null; +} + +async function ensureRelease(tag, name, body) { + let rel = await getReleaseByTag(tag); + if (rel) return rel; + const r = await api(`/repos/${REPO}/releases`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ tag_name: tag, name, body, draft: false, prerelease: false }), + }); + if (!r.ok) throw new Error(`create release ${tag}: ${r.status} ${await r.text()}`); + return r.json(); +} + +async function uploadAsset(rel, file, asName) { + const name = asName || path.basename(file); + // delete an existing asset with the same name first (Gitea won't overwrite) + for (const a of rel.assets || []) { + if (a.name === name) await api(`/repos/${REPO}/releases/${rel.id}/assets/${a.id}`, { method: 'DELETE' }); + } + const blob = new Blob([fs.readFileSync(file)]); + const fd = new FormData(); + fd.append('attachment', blob, name); + const r = await api(`/repos/${REPO}/releases/${rel.id}/assets?name=${encodeURIComponent(name)}`, { method: 'POST', body: fd }); + if (!r.ok) throw new Error(`upload ${name}: ${r.status} ${await r.text()}`); + console.log(' ↑', name); + return r.json(); +} + +const dlUrl = (tag, name) => `${GITEA_URL}/${REPO}/releases/download/${encodeURIComponent(tag)}/${encodeURIComponent(name)}`; + +async function main() { + const { assets, updater } = findArtifacts(); + if (!assets.length) { console.error('No build artifacts found — run the builds first.'); process.exit(1); } + console.log(`Release v${VERSION} → ${GITEA_URL}/${REPO}`); + console.log('Artifacts:', assets.map((a) => path.basename(a)).join(', ')); + + const verTag = `v${VERSION}`; + const rel = await ensureRelease(verTag, `X-Plane Cockpit ${verTag}`, `Automated release ${verTag}.`); + for (const f of assets) await uploadAsset(rel, f); + const relFresh = await getReleaseByTag(verTag); // refresh asset list + + // Build latest.json referencing this release's updater artifacts. + const platforms = {}; + for (const [key, { file, sig }] of Object.entries(updater)) { + platforms[key] = { signature: sig, url: dlUrl(verTag, path.basename(file)) }; + } + const latest = { + version: VERSION, + notes: `X-Plane Cockpit ${verTag}`, + pub_date: new Date().toISOString(), + platforms, + }; + const latestPath = path.join(ROOT, 'desktop/latest.json'); + fs.writeFileSync(latestPath, JSON.stringify(latest, null, 2)); + console.log('latest.json platforms:', Object.keys(platforms).join(', ') || '(none)'); + + // Upload latest.json to the fixed "updater" release (constant endpoint URL). + const upd = await ensureRelease(UPDATER_TAG, 'Updater channel', 'Rolling pointer used by the in-app updater.'); + await uploadAsset(upd, latestPath, 'latest.json'); + console.log('Updater endpoint:', dlUrl(UPDATER_TAG, 'latest.json')); +} + +main().catch((e) => { console.error(e); process.exit(1); }); diff --git a/server/bridge.js b/server/bridge.js new file mode 100644 index 0000000..d9f718d --- /dev/null +++ b/server/bridge.js @@ -0,0 +1,305 @@ +// X-Plane Glass Cockpit — Bridge +// ------------------------------------------------------------------------- +// Connects to X-Plane 12's built-in web API (localhost only), resolves +// dataref/command names to per-session IDs, subscribes to live values, and +// fans them out over a LAN-facing WebSocket to any number of tablets/laptops. +// Also serves the built React UI. + +import express from 'express'; +import { WebSocketServer, WebSocket as WsClient } from 'ws'; +import http from 'node:http'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { CONFIG, DATAREFS, WRITABLE_DATAREFS, COMMANDS } from './config.js'; +import { loadNavData, search as navSearch, navStatus, nearest as navNearest, bbox as navBbox, runwaysNear as navRunways } from './navdata.js'; +import { parseProcedures, procedureLegs as procLegs } from './procedures.js'; +import * as fp from './flightplan.js'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +// WEB_DIST can be overridden (e.g. the desktop app points it at the cockpit +// files it bundles as a resource); otherwise default to ../web/dist. +const WEB_DIST = process.env.WEB_DIST || path.join(__dirname, '..', 'web', 'dist'); +const REST = `http://${CONFIG.xplaneHost}:${CONFIG.xplanePort}${CONFIG.xplaneApiBase}`; +const WS_URL = `ws://${CONFIG.xplaneHost}:${CONFIG.xplanePort}${CONFIG.xplaneApiBase}`; + +const log = (...a) => console.log(new Date().toISOString().slice(11, 19), ...a); + +// ---- shared state --------------------------------------------------------- +const state = { + xpConnected: false, + values: {}, // alias -> latest value + drefIdToAlias: new Map(), // X-Plane dataref id -> our alias + drefNameToId: new Map(), // sim/... -> id + cmdNameToId: new Map(), // sim/... -> id + xpSocket: null, + reqId: 1, +}; + +const clients = new Set(); // connected browser sockets + +// ---- helpers -------------------------------------------------------------- +function broadcast(obj) { + const msg = JSON.stringify(obj); + for (const c of clients) { + if (c.readyState === WsClient.OPEN) c.send(msg); + } +} + +function broadcastPlan() { + broadcast({ type: 'flightplan', data: fp.getPlan() }); +} + +async function fetchAllByName(resource, names) { + // X-Plane's list endpoints can be filtered by name. We query each name so we + // don't pull the full ~15k dataref catalogue. + const map = new Map(); + await Promise.all( + [...new Set(names)].map(async (name) => { + try { + const url = `${REST}/${resource}?filter[name]=${encodeURIComponent(name)}`; + const res = await fetch(url, { headers: { Accept: 'application/json' } }); + if (!res.ok) return; + const body = await res.json(); + const item = (body.data || []).find((d) => d.name === name); + if (item) map.set(name, item.id); + else log(`! ${resource} not found: ${name}`); + } catch (e) { + log(`! lookup failed for ${name}: ${e.message}`); + } + }) + ); + return map; +} + +// ---- X-Plane connection --------------------------------------------------- +async function resolveIds() { + const drefNames = Object.values(DATAREFS); + const cmdNames = Object.values(COMMANDS); + state.drefNameToId = await fetchAllByName('datarefs', [ + ...drefNames, + ...Object.values(WRITABLE_DATAREFS), + ]); + state.cmdNameToId = await fetchAllByName('commands', cmdNames); + + // build reverse map id -> alias for incoming updates + state.drefIdToAlias.clear(); + for (const [alias, name] of Object.entries(DATAREFS)) { + const id = state.drefNameToId.get(name); + if (id != null) state.drefIdToAlias.set(id, alias); + } + log(`resolved ${state.drefNameToId.size} datarefs, ${state.cmdNameToId.size} commands`); +} + +function subscribeValues() { + const datarefs = []; + for (const id of state.drefIdToAlias.keys()) datarefs.push({ id }); + if (!datarefs.length) return; + state.xpSocket.send( + JSON.stringify({ + req_id: state.reqId++, + type: 'dataref_subscribe_values', + params: { datarefs }, + }) + ); + log(`subscribed to ${datarefs.length} datarefs`); +} + +function connectXPlane() { + log(`connecting to X-Plane @ ${WS_URL} ...`); + let sock; + try { + sock = new WsClient(WS_URL); + } catch (e) { + log('X-Plane connect threw, retrying in 3s:', e.message); + return setTimeout(connectXPlane, 3000); + } + state.xpSocket = sock; + + sock.on('open', async () => { + try { + await resolveIds(); + subscribeValues(); + state.xpConnected = true; + broadcast({ type: 'status', xpConnected: true }); + log('X-Plane connected ✓'); + } catch (e) { + log('setup after connect failed:', e.message); + } + }); + + sock.on('message', (raw) => { + let msg; + try { msg = JSON.parse(raw); } catch { return; } + if (msg.type === 'dataref_update_values' && msg.data) { + const patch = {}; + for (const [id, value] of Object.entries(msg.data)) { + const alias = state.drefIdToAlias.get(Number(id)); + if (alias) { state.values[alias] = value; patch[alias] = value; } + } + if (Object.keys(patch).length) broadcast({ type: 'values', data: patch }); + } + }); + + const onDown = (why) => { + if (state.xpConnected) log(`X-Plane disconnected (${why})`); + state.xpConnected = false; + broadcast({ type: 'status', xpConnected: false }); + if (state.xpSocket === sock) state.xpSocket = null; + setTimeout(connectXPlane, 3000); + }; + sock.on('close', () => onDown('close')); + sock.on('error', (e) => onDown(e.message)); +} + +// ---- commands coming FROM the browser ------------------------------------ +function handleClientMessage(msg) { + // --- flight plan (works even without a sim connection) --- + if (msg.type === 'fp_set') { fp.setPlan(msg.plan); return broadcastPlan(); } + if (msg.type === 'fp_add') { + const r = fp.addWaypoint(msg.ident); + if (!r.ok) return; // silently ignore unknown idents + return broadcastPlan(); + } + if (msg.type === 'fp_remove') { fp.removeWaypoint(msg.index); return broadcastPlan(); } + if (msg.type === 'fp_active') { fp.setActiveLeg(msg.index); return broadcastPlan(); } + if (msg.type === 'fp_clear') { fp.setPlan({ waypoints: [] }); return broadcastPlan(); } + if (msg.type === 'fp_export') { + const r = fp.exportFms(msg.name || 'WEBFPL'); + broadcast({ type: 'fp_export_result', ...r }); + return; + } + + // --- everything below talks to X-Plane; needs a live sim socket --- + if (!state.xpSocket || state.xpSocket.readyState !== WsClient.OPEN) return; + + if (msg.type === 'command') { + const name = COMMANDS[msg.name]; + const id = name && state.cmdNameToId.get(name); + if (id == null) return log(`! unknown command alias: ${msg.name}`); + state.xpSocket.send( + JSON.stringify({ + req_id: state.reqId++, + type: 'command_set_is_active', + params: { commands: [{ id, is_active: true, duration: msg.duration ?? 0 }] }, + }) + ); + } else if (msg.type === 'setDataref') { + const name = WRITABLE_DATAREFS[msg.name]; + const id = name && state.drefNameToId.get(name); + if (id == null) return log(`! unknown writable dataref alias: ${msg.name}`); + state.xpSocket.send( + JSON.stringify({ + req_id: state.reqId++, + type: 'dataref_set_values', + params: { datarefs: [{ id, value: Number(msg.value) }] }, + }) + ); + } +} + +// ---- HTTP + LAN WebSocket server ----------------------------------------- +const app = express(); +// Allow the desktop launcher (a different origin) to read the JSON API. LAN-only +// by design, so a wildcard here is harmless and keeps tablets/the app simple. +app.use('/api', (_req, res, next) => { res.set('Access-Control-Allow-Origin', '*'); next(); }); +app.get('/api/health', (_req, res) => + res.json({ xpConnected: state.xpConnected, datarefs: state.drefIdToAlias.size, clients: clients.size, nav: navStatus() }) +); +// Waypoint / navaid / airport search from X-Plane's own nav database. +app.get('/api/nav/search', (req, res) => res.json(navSearch(req.query.q || '', 25))); +// NEAREST airports/navaids to a point (NRST page). +app.get('/api/nav/nearest', (req, res) => + res.json(navNearest(+req.query.lat, +req.query.lon, { count: +req.query.count || 15, type: req.query.type || 'apt' })) +); +// Features inside a map window (airports/navaids/fixes) for the moving map. +app.get('/api/nav/bbox', (req, res) => + res.json(navBbox(+req.query.s, +req.query.w, +req.query.n, +req.query.e, + (req.query.types || 'apt,vor,ndb').split(','), +req.query.limit || 800)) +); +// Runways near a point — drawn in the PFD synthetic-vision view. +app.get('/api/nav/runways', (req, res) => + res.json(navRunways(+req.query.lat, +req.query.lon, +req.query.radius || 12)) +); +// PROC: an airport's procedures (SIDs/STARs/approaches) and the resolved leg +// fixes for a chosen procedure+transition (from X-Plane's CIFP data). +app.get('/api/nav/procs', (req, res) => { + const p = parseProcedures(String(req.query.icao || '')); + if (!p) return res.status(404).json({ error: 'no procedures for ' + req.query.icao }); + res.json({ icao: p.icao, runways: p.runways, sids: p.sids, stars: p.stars, approaches: p.approaches }); +}); +app.get('/api/nav/proc', (req, res) => + res.json(procLegs(String(req.query.icao || ''), req.query.type, req.query.name, req.query.trans)) +); +app.use(express.static(WEB_DIST)); +// SPA fallback so client-side routes work. +app.get('*', (_req, res) => res.sendFile(path.join(WEB_DIST, 'index.html'))); + +const server = http.createServer(app); +const wss = new WebSocketServer({ server, path: '/ws' }); + +wss.on('connection', (ws) => { + clients.add(ws); + log(`browser connected (${clients.size} total)`); + // send current snapshot immediately so the UI isn't blank + ws.send(JSON.stringify({ type: 'status', xpConnected: state.xpConnected })); + ws.send(JSON.stringify({ type: 'values', data: state.values })); + ws.send(JSON.stringify({ type: 'flightplan', data: fp.getPlan() })); + + ws.on('message', (raw) => { + try { handleClientMessage(JSON.parse(raw)); } catch { /* ignore */ } + }); + ws.on('close', () => { clients.delete(ws); log(`browser left (${clients.size} total)`); }); + ws.on('error', () => clients.delete(ws)); +}); + +// ---- demo mode: synthetic values when there's no X-Plane (for previews) --- +function startDemo() { + log('DEMO mode — emitting synthetic values, not connecting to X-Plane'); + state.xpConnected = true; + Object.assign(state.values, { + airspeed: 124, altitude: 5500, vspeed: 320, pitch: 4.5, roll: -12, + heading: 87, slip: 0.3, gForce: 1.04, oat: 9, + apState: (1 << 0) | (1 << 1) | (1 << 14), // FD + HDG + ALT + apEngaged: 1, apHdgBug: 90, apAltBug: 6000, apVsBug: 500, apSpdBug: 120, + lat: 47.45, lon: -122.31, track: 90, groundspeed: 64, gpsDistNm: 18.4, gpsBearing: 92, + // radios (XP freq units: nav/com in 10 kHz, e.g. 11030 = 110.30) + nav1: 11030, nav1Sb: 11150, nav2: 11380, nav2Sb: 10890, + com1: 12190, com1Sb: 13000, com2: 12475, com2Sb: 12180, + // HSI / data fields + obsCrs: 175, hsiDef: -0.6, hsiToFrom: 1, navBearing: 168, gsDef: 0.7, + baro: 29.92, tas: 131, windSpd: 14, windDir: 240, + xpdrCode: 1200, xpdrMode: 2, fdPitch: 5, fdRoll: -10, + // engine strip (arrays, like the sim) + engRpm: [2410], fuelFlow: [0.0072], oilTemp: [88], oilPress: [52], egt: [720], + fuelQty: [60, 58], volts: [28.0], amps: [12], + }); + // a sample plan so the map/FMS show something in demo mode + fp.setPlan({ name: 'DEMO', waypoints: [ + { id: 'KSEA', lat: 47.449, lon: -122.309, type: 'APT' }, + { id: 'SEA', lat: 47.435, lon: -122.310, type: 'VOR', alt: 4000 }, + { id: 'KPDX', lat: 45.589, lon: -122.597, type: 'APT', alt: 1200 }, + ]}); + let t = 0; + setInterval(() => { + t += 0.1; + state.values.roll = -12 + Math.sin(t) * 4; + state.values.pitch = 4.5 + Math.cos(t * 0.7) * 1.5; + state.values.heading = (87 + Math.sin(t * 0.3) * 3 + 360) % 360; + state.values.track = state.values.heading; + state.values.altitude = 5500 + Math.sin(t * 0.5) * 40; + state.values.airspeed = 124 + Math.sin(t * 0.4) * 3; + // creep south-east so the aircraft visibly moves on the map + state.values.lat -= 0.0006; + state.values.lon -= 0.0009; + broadcast({ type: 'status', xpConnected: true }); + broadcast({ type: 'values', data: state.values }); + }, 100); +} + +server.listen(CONFIG.bridgePort, CONFIG.bridgeHost, () => { + log(`Bridge UI: http://${CONFIG.bridgeHost}:${CONFIG.bridgePort}`); + log(`On tablets: http://:${CONFIG.bridgePort}`); + loadNavData(); // async; FMS resolves idents once ready + if (process.env.DEMO) startDemo(); + else connectXPlane(); +}); diff --git a/server/config.js b/server/config.js new file mode 100644 index 0000000..46f14cb --- /dev/null +++ b/server/config.js @@ -0,0 +1,141 @@ +// Central configuration: which X-Plane datarefs/commands the cockpit needs. +// +// These are *universal* datarefs that work on virtually every aircraft. +// To add a G1000- or aircraft-specific instrument, just add its dataref name +// here under DATAREFS (read) and/or WRITABLE_DATAREFS / COMMANDS (interact). + +export const CONFIG = { + // Where X-Plane's built-in web server listens (on the same PC). X-Plane 12.1.1+. + xplaneHost: process.env.XPLANE_HOST || 'localhost', + xplanePort: Number(process.env.XPLANE_PORT || 8086), + xplaneApiBase: '/api/v3', + + // Where THIS bridge serves the UI + relays data. 0.0.0.0 => reachable from the LAN. + bridgeHost: process.env.BRIDGE_HOST || '0.0.0.0', + bridgePort: Number(process.env.BRIDGE_PORT || 8080), + + // How often X-Plane pushes value updates (it caps near 10–20 Hz anyway). + updateHz: Number(process.env.UPDATE_HZ || 20), +}; + +// Datarefs we SUBSCRIBE to and stream to every client. Keyed by a short alias +// the frontend uses, so the long sim/... names live in exactly one place. +export const DATAREFS = { + // --- primary flight data --- + airspeed: 'sim/cockpit2/gauges/indicators/airspeed_kts_pilot', + altitude: 'sim/cockpit2/gauges/indicators/altitude_ft_pilot', + vspeed: 'sim/cockpit2/gauges/indicators/vvi_fpm_pilot', + pitch: 'sim/cockpit2/gauges/indicators/pitch_AHARS_deg_pilot', + roll: 'sim/cockpit2/gauges/indicators/roll_AHARS_deg_pilot', + heading: 'sim/cockpit2/gauges/indicators/heading_AHARS_deg_mag_pilot', + slip: 'sim/cockpit2/gauges/indicators/slip_deg', + gForce: 'sim/flightmodel/forces/g_nrml', + + // --- position / navigation (for the moving map) --- + lat: 'sim/flightmodel/position/latitude', + lon: 'sim/flightmodel/position/longitude', + groundspeed: 'sim/flightmodel/position/groundspeed', // m/s + track: 'sim/cockpit2/gauges/indicators/ground_track_mag_pilot', // deg + gpsDistNm: 'sim/cockpit2/radios/indicators/gps_dme_distance_nm', + gpsBearing: 'sim/cockpit2/radios/indicators/gps_bearing_deg_mag', + + // --- engine / misc (handy on an MFD) --- + fuelTotal: 'sim/cockpit2/fuel/fuel_quantity', // array + oat: 'sim/cockpit2/temperature/outside_air_temp_degc', + + // --- G1000 PFD: radios (NAV/COM active + standby) --- + nav1: 'sim/cockpit2/radios/actuators/nav1_frequency_hz', + nav1Sb: 'sim/cockpit2/radios/actuators/nav1_standby_frequency_hz', + nav2: 'sim/cockpit2/radios/actuators/nav2_frequency_hz', + nav2Sb: 'sim/cockpit2/radios/actuators/nav2_standby_frequency_hz', + com1: 'sim/cockpit2/radios/actuators/com1_frequency_hz', + com1Sb: 'sim/cockpit2/radios/actuators/com1_standby_frequency_hz', + com2: 'sim/cockpit2/radios/actuators/com2_frequency_hz', + com2Sb: 'sim/cockpit2/radios/actuators/com2_standby_frequency_hz', + + // --- G1000 PFD: HSI / CDI --- + obsCrs: 'sim/cockpit2/radios/actuators/nav1_obs_deg_mag_pilot', + gsDef: 'sim/cockpit/radios/nav1_vdef', // glideslope vertical deflection (dots) + hsiDef: 'sim/cockpit2/radios/indicators/hsi_hdef_dots_pilot', + hsiToFrom: 'sim/cockpit2/radios/indicators/hsi_flag_from_to_pilot', + navBearing: 'sim/cockpit2/radios/indicators/hsi_bearing_deg_mag_pilot', + + // --- G1000 PFD: data fields --- + baro: 'sim/cockpit2/gauges/actuators/barometer_setting_in_hg_pilot', + tas: 'sim/cockpit2/gauges/indicators/true_airspeed_kts_pilot', + windSpd: 'sim/cockpit2/gauges/indicators/wind_speed_kts', + windDir: 'sim/cockpit2/gauges/indicators/wind_heading_deg_mag', + xpdrCode: 'sim/cockpit2/radios/actuators/transponder_code', + xpdrMode: 'sim/cockpit2/radios/actuators/transponder_mode', + fdPitch: 'sim/cockpit2/autopilot/flight_director_pitch_deg', + fdRoll: 'sim/cockpit2/autopilot/flight_director_roll_deg', + + // --- G1000 MFD: engine strip (arrays — UI reads index 0/1) --- + engRpm: 'sim/cockpit2/engine/indicators/engine_speed_rpm', + fuelFlow: 'sim/cockpit2/engine/indicators/fuel_flow_kg_sec', + oilTemp: 'sim/cockpit2/engine/indicators/oil_temperature_deg_C', + oilPress: 'sim/cockpit2/engine/indicators/oil_pressure_psi', + egt: 'sim/cockpit2/engine/indicators/EGT_deg_C', + fuelQty: 'sim/cockpit2/fuel/fuel_quantity', + volts: 'sim/cockpit2/electrical/bus_volts', + amps: 'sim/cockpit2/electrical/battery_amps', + + // --- autopilot readouts (live values, so the panel reflects reality) --- + apState: 'sim/cockpit2/autopilot/autopilot_state', // bitfield of active modes + apHdgBug: 'sim/cockpit2/autopilot/heading_dial_deg_mag_pilot', + apAltBug: 'sim/cockpit2/autopilot/altitude_dial_ft_pilot', + apVsBug: 'sim/cockpit2/autopilot/vvi_dial_fpm', + apSpdBug: 'sim/cockpit2/autopilot/airspeed_dial_kts_mach', + apEngaged: 'sim/cockpit2/autopilot/servos_on', + navHdef: 'sim/cockpit2/radios/indicators/hsi_relative_bearing_vor_pilot', +}; + +// Datarefs the frontend may WRITE (e.g. turning the heading bug knob). +export const WRITABLE_DATAREFS = { + apHdgBug: 'sim/cockpit2/autopilot/heading_dial_deg_mag_pilot', + apAltBug: 'sim/cockpit2/autopilot/altitude_dial_ft_pilot', + apVsBug: 'sim/cockpit2/autopilot/vvi_dial_fpm', + apSpdBug: 'sim/cockpit2/autopilot/airspeed_dial_kts_mach', + xpdrMode: 'sim/cockpit2/radios/actuators/transponder_mode', // 0 off,1 stby,2 on,3 alt + xpdrCode: 'sim/cockpit2/radios/actuators/transponder_code', // 4-digit squawk +}; + +// Commands the frontend may TRIGGER (autopilot mode buttons etc.). +export const COMMANDS = { + apToggle: 'sim/autopilot/servos_toggle', + fdToggle: 'sim/autopilot/fdir_toggle', + hdg: 'sim/autopilot/heading', + nav: 'sim/autopilot/NAV', + apr: 'sim/autopilot/approach', + altHold: 'sim/autopilot/altitude_hold', + vs: 'sim/autopilot/vertical_speed', + flc: 'sim/autopilot/level_change', + vnav: 'sim/autopilot/vnav', + backCourse:'sim/autopilot/back_course', + noseUp: 'sim/autopilot/nose_up', + noseDown: 'sim/autopilot/nose_down', + altUp: 'sim/autopilot/altitude_up', + altDown: 'sim/autopilot/altitude_down', + hdgUp: 'sim/autopilot/heading_up', + hdgDown: 'sim/autopilot/heading_down', + xpdrIdent: 'sim/transponder/transponder_ident', +}; + +// Every clickable G1000 bezel control maps to a real X-Plane command. The PFD +// is unit n1, the MFD is unit n3 (the default C172 layout). Aliases are +// prefixed pfd_/mfd_ so the frontend just says e.g. command('mfd_fpl'). +const G1000_KEYS = [ + ...Array.from({ length: 12 }, (_, i) => `softkey${i + 1}`), + 'direct', 'menu', 'fpl', 'proc', 'clr', 'ent', 'cursor', + 'fms_outer_up', 'fms_outer_down', 'fms_inner_up', 'fms_inner_down', + 'range_up', 'range_down', 'pan_push', 'pan_up', 'pan_down', 'pan_left', 'pan_right', + 'hdg_up', 'hdg_down', 'hdg_sync', + 'alt_outer_up', 'alt_outer_down', 'alt_inner_up', 'alt_inner_down', + 'crs_up', 'crs_down', 'crs_sync', 'baro_up', 'baro_down', + 'nav_outer_up', 'nav_outer_down', 'nav_inner_up', 'nav_inner_down', 'nav12', 'nvol_up', 'nvol_dn', + 'com_outer_up', 'com_outer_down', 'com_inner_up', 'com_inner_down', 'com12', 'cvol_up', 'cvol_dn', + 'ap', 'fd', 'hdg', 'alt', 'nav', 'vnv', 'apr', 'bc', 'vs', 'flc', 'nose_up', 'nose_down', +]; +for (const [unit, prefix] of [['n1', 'pfd'], ['n3', 'mfd']]) { + for (const k of G1000_KEYS) COMMANDS[`${prefix}_${k}`] = `sim/GPS/g1000${unit}_${k}`; +} diff --git a/server/flightplan.js b/server/flightplan.js new file mode 100644 index 0000000..6b0e5ce --- /dev/null +++ b/server/flightplan.js @@ -0,0 +1,100 @@ +// Shared flight plan: one plan, synced to every connected tablet. Can resolve +// idents via navdata, and export an X-Plane .fms file the sim can load. + +import fs from 'node:fs'; +import path from 'node:path'; +import { lookup, xplaneRoot } from './navdata.js'; + +// waypoint: { id, lat, lon, type, alt? } +// activeLeg = index of the waypoint the active (magenta) leg flies TO. The leg +// runs from waypoints[activeLeg-1] to waypoints[activeLeg]. Defaults to 1. +let plan = { name: 'ACTIVE', waypoints: [], activeLeg: 1 }; + +const clampLeg = (i) => Math.max(1, Math.min(plan.waypoints.length - 1, i | 0)); + +export const getPlan = () => plan; + +export function setPlan(next) { + const wps = Array.isArray(next?.waypoints) + ? next.waypoints + .filter((w) => isFinite(w.lat) && isFinite(w.lon)) + .map((w) => ({ id: String(w.id || 'WPT'), lat: +w.lat, lon: +w.lon, type: w.type || 'WPT', alt: w.alt ?? null })) + : []; + const wantLeg = Number.isFinite(next?.activeLeg) ? next.activeLeg : 1; + plan = { name: next?.name || 'ACTIVE', waypoints: wps, activeLeg: Math.max(1, Math.min(wps.length - 1, wantLeg)) || 1 }; + return plan; +} + +export function setActiveLeg(index) { + if (plan.waypoints.length >= 2) plan.activeLeg = clampLeg(index); + return plan; +} + +// Add a waypoint by ident (resolved against navdata) or raw "lat,lon". +export function addWaypoint(input) { + const raw = String(input || '').trim(); + const m = raw.match(/^(-?\d+(?:\.\d+)?)[ ,]+(-?\d+(?:\.\d+)?)$/); + if (m) { + plan.waypoints.push({ id: 'USR', lat: +m[1], lon: +m[2], type: 'USR', alt: null }); + return { ok: true, plan }; + } + const hit = lookup(raw); + if (!hit) return { ok: false, error: `unknown ident: ${raw}` }; + plan.waypoints.push({ ...hit, alt: null }); + return { ok: true, plan }; +} + +export function removeWaypoint(index) { + if (index >= 0 && index < plan.waypoints.length) plan.waypoints.splice(index, 1); + if (plan.waypoints.length >= 2) plan.activeLeg = clampLeg(plan.activeLeg); + return plan; +} + +// ---- great-circle helpers (nm + degrees) ---- +const R_NM = 3440.065; +const rad = (d) => (d * Math.PI) / 180; +const deg = (r) => (r * 180) / Math.PI; + +export function legDistanceNm(a, b) { + const dLat = rad(b.lat - a.lat), dLon = rad(b.lon - a.lon); + const s = Math.sin(dLat / 2) ** 2 + Math.cos(rad(a.lat)) * Math.cos(rad(b.lat)) * Math.sin(dLon / 2) ** 2; + return 2 * R_NM * Math.asin(Math.min(1, Math.sqrt(s))); +} + +export function legBearing(a, b) { + const y = Math.sin(rad(b.lon - a.lon)) * Math.cos(rad(b.lat)); + const x = Math.cos(rad(a.lat)) * Math.sin(rad(b.lat)) - + Math.sin(rad(a.lat)) * Math.cos(rad(b.lat)) * Math.cos(rad(b.lon - a.lon)); + return (deg(Math.atan2(y, x)) + 360) % 360; +} + +// ---- X-Plane .fms (v1100) export ---- +function fmsType(t) { + return { APT: 1, NDB: 2, VOR: 3, WPT: 11, USR: 28 }[t] || 11; +} + +export function exportFms(name = 'WEBFPL') { + const wp = plan.waypoints; + if (wp.length < 2) return { ok: false, error: 'need at least 2 waypoints' }; + + const lines = ['I', '1100 Version', 'CYCLE 2501']; + lines.push(`ADEP ${wp[0].id}`); + lines.push(`ADES ${wp[wp.length - 1].id}`); + lines.push(`NUMENR ${wp.length}`); + for (const w of wp) { + const alt = w.alt ?? 0; + lines.push(`${fmsType(w.type)} ${w.id} ${alt.toFixed(6)} ${w.lat.toFixed(6)} ${w.lon.toFixed(6)}`); + } + const content = lines.join('\n') + '\n'; + + const root = xplaneRoot(); + const dir = root ? path.join(root, 'Output', 'FMS plans') : path.join(process.cwd(), 'fms-out'); + try { + fs.mkdirSync(dir, { recursive: true }); + const file = path.join(dir, `${name}.fms`); + fs.writeFileSync(file, content); + return { ok: true, file, intoXplane: !!root }; + } catch (e) { + return { ok: false, error: e.message }; + } +} diff --git a/server/navdata.js b/server/navdata.js new file mode 100644 index 0000000..405b199 --- /dev/null +++ b/server/navdata.js @@ -0,0 +1,226 @@ +// Reads X-Plane's own navigation data so the FMS can resolve real waypoint / +// VOR / NDB / airport identifiers to coordinates — the same database the sim +// uses. Runs on the X-Plane PC (where the bridge lives), so the files are local. +// +// Everything degrades gracefully: if X-Plane / the files can't be found, the +// FMS still works with map-clicks and raw "LAT,LON" entry. + +import fs from 'node:fs'; +import path from 'node:path'; +import readline from 'node:readline'; + +// Common install locations to probe. Override with XPLANE_ROOT. +function candidateRoots() { + const env = process.env.XPLANE_ROOT; + const home = process.env.HOME || process.env.USERPROFILE || ''; + return [ + env, + 'C:/X-Plane 12', 'D:/X-Plane 12', 'E:/X-Plane 12', + 'C:/X-Plane 11', 'D:/X-Plane 11', + path.join(home, 'X-Plane 12'), + path.join(home, 'Desktop', 'X-Plane 12'), + '/Applications/X-Plane 12', + ].filter(Boolean); +} + +function findRoot() { + for (const root of candidateRoots()) { + try { + if (fs.existsSync(path.join(root, 'Resources', 'default data'))) return root; + } catch { /* ignore */ } + } + return null; +} + +// alias -> { lat, lon, type } ; type: WPT | VOR | NDB | APT +const index = new Map(); +// Geographic stores for the moving map (bbox queries) and NEAREST search. +// Airports + navaids stay in flat arrays (small enough to scan); the far more +// numerous fixes go into 1°×1° buckets so a bbox query only scans nearby cells. +const airports = []; // { id, lat, lon, name, elev } +const navaids = []; // { id, lat, lon, type:'VOR'|'NDB', freq, name } +const fixCells = new Map(); // "ilat,ilon" -> [{ id, lat, lon, type:'FIX' }] +const rwyByApt = new Map(); // ICAO -> [{ n1, la1, lo1, n2, la2, lo2, w }] (runway ends + width m) +const state = { root: null, loaded: false, count: 0 }; + +function add(id, lat, lon, type) { + if (!id || !isFinite(lat) || !isFinite(lon)) return; + const key = id.toUpperCase(); + if (!index.has(key)) index.set(key, { id: key, lat, lon, type }); +} + +function pushFix(f) { + const k = `${Math.floor(f.lat)},${Math.floor(f.lon)}`; + let a = fixCells.get(k); + if (!a) { a = []; fixCells.set(k, a); } + a.push(f); +} + +const R_NM = 3440.065; // earth radius in nautical miles +const rad = (d) => (d * Math.PI) / 180; +function distNm(la1, lo1, la2, lo2) { + const dLat = rad(la2 - la1), dLon = rad(lo2 - lo1); + const a = Math.sin(dLat / 2) ** 2 + Math.cos(rad(la1)) * Math.cos(rad(la2)) * Math.sin(dLon / 2) ** 2; + return 2 * R_NM * Math.asin(Math.min(1, Math.sqrt(a))); +} +function bearingDeg(la1, lo1, la2, lo2) { + const y = Math.sin(rad(lo2 - lo1)) * Math.cos(rad(la2)); + const x = Math.cos(rad(la1)) * Math.sin(rad(la2)) - Math.sin(rad(la1)) * Math.cos(rad(la2)) * Math.cos(rad(lo2 - lo1)); + return (Math.atan2(y, x) * 180 / Math.PI + 360) % 360; +} + +async function parseFixes(file) { + if (!fs.existsSync(file)) return; + const rl = readline.createInterface({ input: fs.createReadStream(file), crlfDelay: Infinity }); + for await (const line of rl) { + const t = line.trim(); + if (!t || t === '99' || /^[IA]\b/.test(t) || /Version/.test(t)) continue; + const p = t.split(/\s+/); + const lat = parseFloat(p[0]), lon = parseFloat(p[1]), id = p[2]; + add(id, lat, lon, 'WPT'); + if (id && isFinite(lat) && isFinite(lon)) pushFix({ id: id.toUpperCase(), lat, lon, type: 'FIX' }); + } +} + +async function parseNav(file) { + if (!fs.existsSync(file)) return; + const rl = readline.createInterface({ input: fs.createReadStream(file), crlfDelay: Infinity }); + for await (const line of rl) { + const t = line.trim(); + if (!t || t === '99' || /^[IA]\b/.test(t) || /Version/.test(t)) continue; + const p = t.split(/\s+/); + const code = parseInt(p[0], 10); + if (code !== 2 && code !== 3) continue; // 2 = NDB, 3 = VOR/DME + const lat = parseFloat(p[1]), lon = parseFloat(p[2]), id = p[7]; + const type = code === 2 ? 'NDB' : 'VOR'; + add(id, lat, lon, type); + if (id && isFinite(lat) && isFinite(lon)) { + // p[4] = frequency (VOR in 10 kHz e.g. 11630 → 116.30; NDB in kHz); + // name is everything after the airport/region columns. + navaids.push({ id: id.toUpperCase(), lat, lon, type, freq: parseInt(p[4], 10) || 0, name: p.slice(10).join(' ') }); + } + } +} + +// Airports: derive a reference point from each airport's first runway (row 100) +// in apt.dat. The "1" header row carries the ICAO but no coordinates. +async function parseAirports(file) { + if (!fs.existsSync(file)) return; + const rl = readline.createInterface({ input: fs.createReadStream(file), crlfDelay: Infinity }); + let icao = null, name = '', elev = 0, placed = false; + const place = (lat, lon) => { + if (!isFinite(lat) || !isFinite(lon)) return; + add(icao, lat, lon, 'APT'); + airports.push({ id: icao.toUpperCase(), lat, lon, name, elev }); + placed = true; + }; + for await (const line of rl) { + const p = line.trim().split(/\s+/); + const code = parseInt(p[0], 10); + if (code === 1 || code === 16 || code === 17) { // land/sea/heliport header + icao = p[4]; elev = parseInt(p[1], 10) || 0; name = p.slice(5).join(' '); placed = false; + } else if (icao && code === 100) { // land runway (both ends) + const r = { n1: p[8], la1: parseFloat(p[9]), lo1: parseFloat(p[10]), n2: p[17], la2: parseFloat(p[18]), lo2: parseFloat(p[19]), w: parseFloat(p[1]) }; + if (isFinite(r.la1) && isFinite(r.lo1) && isFinite(r.la2) && isFinite(r.lo2)) { + const key = icao.toUpperCase(); + let a = rwyByApt.get(key); if (!a) { a = []; rwyByApt.set(key, a); } a.push(r); + if (!placed) place((r.la1 + r.la2) / 2, (r.lo1 + r.lo2) / 2); + } + } else if (!placed && icao && (code === 101 || code === 102)) { // water/heli pad + place(parseFloat(p[code === 101 ? 4 : 5]), parseFloat(p[code === 101 ? 5 : 6])); + } + } +} + +export async function loadNavData() { + const root = findRoot(); + state.root = root; + if (!root) { + console.log('navdata: X-Plane root not found (set XPLANE_ROOT) — FMS works with map-clicks / LAT,LON only'); + state.loaded = true; + return; + } + console.log(`navdata: X-Plane at ${root} — parsing nav data ...`); + const dd = path.join(root, 'Resources', 'default data'); + const cd = path.join(root, 'Custom Data'); // user nav data overrides if present + const pick = (name) => (fs.existsSync(path.join(cd, name)) ? path.join(cd, name) : path.join(dd, name)); + try { + await parseFixes(pick('earth_fix.dat')); + await parseNav(pick('earth_nav.dat')); + // apt.dat is large; parse the global airports file in the background. + parseAirports(path.join(root, 'Global Scenery', 'Global Airports', 'Earth nav data', 'apt.dat')) + .then(() => { state.count = index.size; console.log(`navdata: airports done (${index.size} total entries)`); }) + .catch((e) => console.log('navdata: airport parse skipped:', e.message)); + } catch (e) { + console.log('navdata: parse error:', e.message); + } + state.count = index.size; + state.loaded = true; + console.log(`navdata: ${index.size} fixes/navaids ready`); +} + +export function lookup(id) { + return index.get(String(id).toUpperCase()) || null; +} + +export function search(q, limit = 20) { + const needle = String(q || '').toUpperCase().trim(); + if (!needle) return []; + const exact = [], prefix = []; + for (const v of index.values()) { + if (v.id === needle) exact.push(v); + else if (v.id.startsWith(needle)) prefix.push(v); + if (exact.length + prefix.length > 400) break; + } + return [...exact, ...prefix].slice(0, limit); +} + +// NEAREST: closest airports (default) or navaids to a point, with range/bearing. +export function nearest(lat, lon, { count = 15, type = 'apt' } = {}) { + if (!isFinite(lat) || !isFinite(lon)) return []; + const src = (type === 'vor' || type === 'ndb' || type === 'nav') ? navaids : airports; + return src + .filter((f) => (type === 'vor' || type === 'ndb') ? f.type.toLowerCase() === type : true) + .map((f) => ({ ...f, dist: distNm(lat, lon, f.lat, f.lon), brg: Math.round(bearingDeg(lat, lon, f.lat, f.lon)) })) + .sort((a, b) => a.dist - b.dist) + .slice(0, count) + .map((f) => ({ ...f, dist: +f.dist.toFixed(1) })); +} + +// BBOX: every feature inside a lat/lon window, for the moving map to draw. +// types ⊆ { apt, vor, ndb, fix }. Output is capped so a wide view stays light. +export function bbox(s, w, n, e, types = ['apt', 'vor', 'ndb'], limit = 800) { + const out = []; + const inB = (f) => f.lat >= s && f.lat <= n && f.lon >= w && f.lon <= e; + if (types.includes('apt')) for (const f of airports) { if (inB(f)) { out.push({ ...f, type: 'APT' }); if (out.length >= limit) return out; } } + for (const f of navaids) { if (types.includes(f.type.toLowerCase()) && inB(f)) { out.push(f); if (out.length >= limit) return out; } } + if (types.includes('fix')) { + for (let la = Math.floor(s); la <= Math.floor(n); la++) + for (let lo = Math.floor(w); lo <= Math.floor(e); lo++) { + const a = fixCells.get(`${la},${lo}`); + if (!a) continue; + for (const f of a) { if (inB(f)) { out.push(f); if (out.length >= limit) return out; } } + } + } + return out; +} + +// Runways of every airport within radiusNm — for the PFD's synthetic-vision view. +export function runwaysNear(lat, lon, radiusNm = 12) { + if (!isFinite(lat) || !isFinite(lon)) return []; + const out = []; + for (const a of airports) { + if (distNm(lat, lon, a.lat, a.lon) > radiusNm) continue; + const rs = rwyByApt.get(a.id); + if (rs) for (const r of rs) out.push({ apt: a.id, ...r }); + } + return out; +} + +export function navStatus() { + return { root: state.root, loaded: state.loaded, entries: index.size, airports: airports.length, navaids: navaids.length }; +} + +export function xplaneRoot() { + return state.root; +} diff --git a/server/procedures.js b/server/procedures.js new file mode 100644 index 0000000..d47042b --- /dev/null +++ b/server/procedures.js @@ -0,0 +1,141 @@ +// Parses X-Plane's CIFP procedure data (SIDs / STARs / approaches) on demand — +// one small file per airport in Resources/default data/CIFP/.dat, in the +// ARINC-424-derived "XP CIFP" format. Fix idents are resolved to coordinates +// via the shared navdata index; runway thresholds come from the RWY records. +// +// Used by the G1000 PROC page: list a destination's procedures, then load a +// chosen procedure+transition's leg fixes into the active flight plan. + +import fs from 'node:fs'; +import path from 'node:path'; +import { lookup, xplaneRoot } from './navdata.js'; + +// "N47274972" -> 47.4638.. / "W122183954" -> -122.3109.. +function parseCoord(s) { + if (!s || s.length < 8) return null; + const hemi = s[0]; + const neg = hemi === 'S' || hemi === 'W'; + const digits = s.slice(1); + // lat = DDMMSSss (8) ; lon = DDDMMSSss (9) + const degLen = (hemi === 'E' || hemi === 'W') ? 3 : 2; + const dd = parseInt(digits.slice(0, degLen), 10); + const mm = parseInt(digits.slice(degLen, degLen + 2), 10); + const ss = parseInt(digits.slice(degLen + 2, degLen + 4), 10); + const hh = parseInt(digits.slice(degLen + 4, degLen + 6) || '0', 10); + if (!isFinite(dd) || !isFinite(mm)) return null; + const val = dd + mm / 60 + (ss + hh / 100) / 3600; + return neg ? -val : val; +} + +function cifpFile(icao) { + const root = xplaneRoot(); + if (!root) return null; + const f = path.join(root, 'Resources', 'default data', 'CIFP', `${icao.toUpperCase()}.dat`); + return fs.existsSync(f) ? f : null; +} + +// Parse one airport's procedures into a structured summary + leg store. +// Returns null if the airport has no CIFP file. +export function parseProcedures(icao) { + const file = cifpFile(icao); + if (!file) return null; + + const runways = {}; // RW16C -> { lat, lon, elev } + const groups = { SID: {}, STAR: {}, APPCH: {} }; + // groups[type][procName] = { order:[trans...], legs:{ trans:[{fix,term,alt}] } } + + const ensure = (type, name, trans) => { + const g = groups[type]; + if (!g[name]) g[name] = { order: [], legs: {} }; + if (!(trans in g[name].legs)) { g[name].legs[trans] = []; g[name].order.push(trans); } + return g[name].legs[trans]; + }; + + for (const raw of fs.readFileSync(file, 'utf8').split('\n')) { + const line = raw.trim().replace(/;$/, ''); + if (!line) continue; + const colon = line.indexOf(':'); + if (colon < 0) continue; + const type = line.slice(0, colon); + const f = line.slice(colon + 1).split(','); + + if (type === 'RWY') { + // RWY:RW16C, , ,00429, ,ISZI,3, ;N47274972,W122183954,0000 + const id = f[0]; + const tail = line.split(';')[1] || ''; // "N47274972,W122183954,0000" + const [latS, lonS] = tail.split(','); + const lat = parseCoord(latS), lon = parseCoord(lonS); + if (lat != null && lon != null) runways[id] = { lat, lon, elev: parseInt(f[3], 10) || 0 }; + continue; + } + if (type !== 'SID' && type !== 'STAR' && type !== 'APPCH') continue; + + // f[0]=seqno, f[1]=route type, f[2]=proc, f[3]=transition, f[4]=fix, + // f[11]=path/termination, f[22]=alt flag (+/-), f[23]=altitude. + const procName = f[2]; // BANGR9 / CHINS5 / I16C + const trans = (f[3] || '').trim(); // RW16C / PDT / ERYKA / '' (common) + const fix = (f[4] || '').trim(); // OTLIE / ANVIL / RW16C + const term = (f[11] || '').trim(); // path/termination: IF TF CF DF VA CA ... + const altFlag = (f[22] || '').trim(); + const altVal = parseInt((f[23] || '').trim(), 10); + const alt = isFinite(altVal) && altVal > 0 ? altVal : null; + + const legs = ensure(type, procName, trans || '(common)'); + legs.push({ fix, term, alt, altFlag }); + } + + // Build the client-facing summary (names + their transitions). + const summarize = (g) => Object.entries(g).map(([name, v]) => ({ + name, transitions: v.order.filter((t) => t !== '(common)'), + })); + + return { + icao: icao.toUpperCase(), + runways: Object.keys(runways), + sids: summarize(groups.SID), + stars: summarize(groups.STAR), + approaches: summarize(groups.APPCH), + _groups: groups, + _rwy: runways, + }; +} + +// Resolve a chosen procedure+transition to a list of waypoints with coordinates. +// type: 'sid' | 'star' | 'approach'. Fixes are resolved via the navdata index; +// runway "fixes" (RWxx) and unresolved fixes fall back to the RWY threshold. +export function procedureLegs(icao, type, name, trans) { + const parsed = parseProcedures(icao); + if (!parsed) return []; + const TYPE = { sid: 'SID', star: 'STAR', approach: 'APPCH' }[String(type).toLowerCase()]; + const g = parsed._groups[TYPE]; + if (!g || !g[name]) return []; + const node = g[name]; + + // Compose the leg list: chosen transition first, then the common segment. + // (SID: runway/enroute transition then common climb-out; STAR: enroute entry + // then common arrival; approach: IAF transition then final-approach segment.) + const seq = []; + const wantTrans = trans && node.legs[trans] ? trans : node.order.find((t) => t !== '(common)'); + if (wantTrans && node.legs[wantTrans]) seq.push(...node.legs[wantTrans]); + if (node.legs['(common)']) seq.push(...node.legs['(common)']); + + const out = []; + const seen = new Set(); + for (const leg of seq) { + if (!leg.fix) continue; // heading/altitude legs w/o a fix + if (seen.has(leg.fix)) continue; // de-dupe repeated fixes + let pt = null; + const isRwy = /^RW/.test(leg.fix); + if (isRwy && parsed._rwy[leg.fix]) pt = parsed._rwy[leg.fix]; + else { + const hit = lookup(leg.fix); + if (hit) pt = { lat: hit.lat, lon: hit.lon }; + } + if (!pt) continue; // unresolved fix → skip + seen.add(leg.fix); + out.push({ id: leg.fix, lat: pt.lat, lon: pt.lon, type: isRwy ? 'APT' : 'WPT', alt: leg.alt }); + // An approach ends at the runway threshold — drop the missed-approach legs. + if (TYPE === 'APPCH' && isRwy) break; + } + return out; +} diff --git a/shot.mjs b/shot.mjs new file mode 100644 index 0000000..1be4c15 --- /dev/null +++ b/shot.mjs @@ -0,0 +1,17 @@ +import { chromium } from 'playwright'; + +const PORT = process.env.BRIDGE_PORT || 8099; +const base = `http://localhost:${PORT}`; +const browser = await chromium.launch(); +const page = await browser.newPage({ viewport: { width: 1180, height: 820 }, deviceScaleFactor: 2 }); + +await page.goto(base, { waitUntil: 'networkidle' }); + +const tabs = [['pfd', 'PFD'], ['mfd', 'MFD'], ['map', 'Map'], ['fms', 'FMS'], ['ap', 'Autopilot']]; +for (const [tab, label] of tabs) { + await page.getByRole('button', { name: label, exact: true }).click(); + await page.waitForTimeout(tab === 'map' || tab === 'pfd' ? 4000 : 700); // tiles/terrain + await page.screenshot({ path: `/tmp/cockpit-${tab}.png` }); + console.log(`shot: /tmp/cockpit-${tab}.png`); +} +await browser.close(); diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..c976c20 --- /dev/null +++ b/web/index.html @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + X-Plane Glass Cockpit + + + + + +
+ + + + diff --git a/web/package-lock.json b/web/package-lock.json new file mode 100644 index 0000000..6d58eab --- /dev/null +++ b/web/package-lock.json @@ -0,0 +1,1973 @@ +{ + "name": "xplane-glass-cockpit-web", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "xplane-glass-cockpit-web", + "version": "0.1.0", + "dependencies": { + "leaflet": "^1.9.4", + "maplibre-gl": "^5.24.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.3.4", + "vite": "^5.4.11" + } + }, + "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/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/@mapbox/jsonlint-lines-primitives": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", + "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@mapbox/point-geometry": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-1.1.0.tgz", + "integrity": "sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ==", + "license": "ISC" + }, + "node_modules/@mapbox/tiny-sdf": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.2.0.tgz", + "integrity": "sha512-LVL4wgI9YAum5V+LNVQO6QgFBPw7/MIIY4XJPNsPDMrjEwcE+JfKk1LuIl8GnF197ejVdC9QdPaxrx5gfgdGXg==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/vector-tile": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-2.0.5.tgz", + "integrity": "sha512-pXj8m7KTsqZt+1jsE0xIpGvqTSbblfkuEJL/NJmNePMtEwxO8V3XMDo9WMSfDeqHvCtBI9Lmt4mGcGR10zecmw==", + "license": "BSD-3-Clause", + "dependencies": { + "@mapbox/point-geometry": "~1.1.0", + "@types/geojson": "^7946.0.16", + "pbf": "^4.0.2" + } + }, + "node_modules/@mapbox/whoots-js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", + "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", + "license": "ISC", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@maplibre/geojson-vt": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-6.1.0.tgz", + "integrity": "sha512-2eIY4gZxeKIVOZVNkAMb+5NgXhgsMQpOveTQAvnp53LYqHGJZDidk7Ew0Tged9PThidpbS+NFTh0g4zivhPDzQ==", + "license": "ISC", + "dependencies": { + "kdbush": "^4.0.2" + } + }, + "node_modules/@maplibre/maplibre-gl-style-spec": { + "version": "24.8.5", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-24.8.5.tgz", + "integrity": "sha512-EzEJmMt6thioRH7GI9LWS7ahXTcAhAPGWCe6oTP2Ps4YnsXOOAfeqx854lZaiDnwURfHmcCKV1mr6oo0i23x6w==", + "license": "ISC", + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "~2.0.2", + "@mapbox/unitbezier": "^0.0.1", + "json-stringify-pretty-compact": "^4.0.0", + "minimist": "^1.2.8", + "quickselect": "^3.0.0", + "tinyqueue": "^3.0.0" + }, + "bin": { + "gl-style-format": "dist/gl-style-format.mjs", + "gl-style-migrate": "dist/gl-style-migrate.mjs", + "gl-style-validate": "dist/gl-style-validate.mjs" + } + }, + "node_modules/@maplibre/mlt": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.1.11.tgz", + "integrity": "sha512-dKvjKdITw9d0y3ndGkSqLUEpWCizMtdq8NB06cHohH/JZ2sJoM7dClR9wzJLUWykjbw9RXDFmhjjNBnNW27mzw==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@mapbox/point-geometry": "^1.1.0" + } + }, + "node_modules/@maplibre/vt-pbf": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@maplibre/vt-pbf/-/vt-pbf-4.3.0.tgz", + "integrity": "sha512-jIvp8F5hQCcreqOOpEt42TJMUlsrEcpf/kI1T2v85YrQRV6PPXUcEXUg5karKtH6oh47XJZ4kHu56pUkOuqA7w==", + "license": "MIT", + "dependencies": { + "@mapbox/point-geometry": "^1.1.0", + "@mapbox/vector-tile": "^2.0.4", + "@maplibre/geojson-vt": "^5.0.4", + "@types/geojson": "^7946.0.16", + "@types/supercluster": "^7.1.3", + "pbf": "^4.0.1", + "supercluster": "^8.0.1" + } + }, + "node_modules/@maplibre/vt-pbf/node_modules/@maplibre/geojson-vt": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-5.0.4.tgz", + "integrity": "sha512-KGg9sma45S+stfH9vPCJk1J0lSDLWZgCT9Y8u8qWZJyjFlP8MNP1WGTxIMYJZjDvVT3PDn05kN1C95Sut1HpgQ==", + "license": "ISC" + }, + "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.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz", + "integrity": "sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.4.tgz", + "integrity": "sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.4.tgz", + "integrity": "sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.4.tgz", + "integrity": "sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.4.tgz", + "integrity": "sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.4.tgz", + "integrity": "sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.4.tgz", + "integrity": "sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.4.tgz", + "integrity": "sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.4.tgz", + "integrity": "sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.4.tgz", + "integrity": "sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.4.tgz", + "integrity": "sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.4.tgz", + "integrity": "sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.4.tgz", + "integrity": "sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.4.tgz", + "integrity": "sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.4.tgz", + "integrity": "sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.4.tgz", + "integrity": "sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.4.tgz", + "integrity": "sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.4.tgz", + "integrity": "sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.4.tgz", + "integrity": "sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.4.tgz", + "integrity": "sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.4.tgz", + "integrity": "sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.4.tgz", + "integrity": "sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.4.tgz", + "integrity": "sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.4.tgz", + "integrity": "sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.4.tgz", + "integrity": "sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "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/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/supercluster": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz", + "integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "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/baseline-browser-mapping": { + "version": "2.10.33", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", + "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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/caniuse-lite": { + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "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/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/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/earcut": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.2.tgz", + "integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==", + "license": "ISC" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.364", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.364.tgz", + "integrity": "sha512-G/dYE3+AYhyHwzTwg8UbnXf7zqMERYh7l2jJ3QujhFsH8agSYwtnGAR2aZ7f0AakIKJXd5En/Hre4igIUrdlYw==", + "dev": true, + "license": "ISC" + }, + "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/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/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/gl-matrix": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.4.tgz", + "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==", + "license": "MIT" + }, + "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/json-stringify-pretty-compact": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", + "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==", + "license": "MIT" + }, + "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/kdbush": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.1.0.tgz", + "integrity": "sha512-e9vurzrXJQrFX6ckpHP3bvj5l+9CnYzkxDNnNQ1h2QTqdWsUAJgXiKdGNcOa1EY85dU8KbQ+z/FdQdB7P+9yfQ==", + "license": "ISC" + }, + "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/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/maplibre-gl": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.24.0.tgz", + "integrity": "sha512-ALyFxgtd5R+65UqZ/++lOqwWcC0SNho9c27fYSyLmG7AfnAul2o46F05aDJGPbFU57wos9dgcIySHs0Xe6ia3A==", + "license": "BSD-3-Clause", + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "^2.0.2", + "@mapbox/point-geometry": "^1.1.0", + "@mapbox/tiny-sdf": "^2.1.0", + "@mapbox/unitbezier": "^0.0.1", + "@mapbox/vector-tile": "^2.0.4", + "@mapbox/whoots-js": "^3.1.0", + "@maplibre/geojson-vt": "^6.1.0", + "@maplibre/maplibre-gl-style-spec": "^24.8.1", + "@maplibre/mlt": "^1.1.8", + "@maplibre/vt-pbf": "^4.3.0", + "@types/geojson": "^7946.0.16", + "earcut": "^3.0.2", + "gl-matrix": "^3.4.4", + "kdbush": "^4.0.2", + "murmurhash-js": "^1.0.0", + "pbf": "^4.0.1", + "potpack": "^2.1.0", + "quickselect": "^3.0.0", + "tinyqueue": "^3.0.0" + }, + "engines": { + "node": ">=16.14.0", + "npm": ">=8.1.0" + }, + "funding": { + "url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/murmurhash-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", + "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==", + "license": "MIT" + }, + "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.46", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz", + "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/pbf": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.2.tgz", + "integrity": "sha512-J0ajxARhZfpUEebxYs1vhMGMuLSXtBe1e+fFPDrf2uA2hgo+UshKfNUWOz92HJNz6/NFEXseQPddnHkTreWRqg==", + "license": "BSD-3-Clause", + "dependencies": { + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, + "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/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/potpack": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.1.0.tgz", + "integrity": "sha512-pcaShQc1Shq0y+E7GqJqvZj8DTthWV1KeHGdi0Z6IAin2Oi3JnLCOfwnCo84qc+HAp52wT9nK9H7FAJp5a44GQ==", + "license": "ISC" + }, + "node_modules/protocol-buffers-schema": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.1.tgz", + "integrity": "sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ==", + "license": "MIT" + }, + "node_modules/quickselect": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", + "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", + "license": "ISC" + }, + "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-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/resolve-protobuf-schema": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", + "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "license": "MIT", + "dependencies": { + "protocol-buffers-schema": "^3.3.1" + } + }, + "node_modules/rollup": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.4.tgz", + "integrity": "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.4", + "@rollup/rollup-android-arm64": "4.60.4", + "@rollup/rollup-darwin-arm64": "4.60.4", + "@rollup/rollup-darwin-x64": "4.60.4", + "@rollup/rollup-freebsd-arm64": "4.60.4", + "@rollup/rollup-freebsd-x64": "4.60.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.4", + "@rollup/rollup-linux-arm-musleabihf": "4.60.4", + "@rollup/rollup-linux-arm64-gnu": "4.60.4", + "@rollup/rollup-linux-arm64-musl": "4.60.4", + "@rollup/rollup-linux-loong64-gnu": "4.60.4", + "@rollup/rollup-linux-loong64-musl": "4.60.4", + "@rollup/rollup-linux-ppc64-gnu": "4.60.4", + "@rollup/rollup-linux-ppc64-musl": "4.60.4", + "@rollup/rollup-linux-riscv64-gnu": "4.60.4", + "@rollup/rollup-linux-riscv64-musl": "4.60.4", + "@rollup/rollup-linux-s390x-gnu": "4.60.4", + "@rollup/rollup-linux-x64-gnu": "4.60.4", + "@rollup/rollup-linux-x64-musl": "4.60.4", + "@rollup/rollup-openbsd-x64": "4.60.4", + "@rollup/rollup-openharmony-arm64": "4.60.4", + "@rollup/rollup-win32-arm64-msvc": "4.60.4", + "@rollup/rollup-win32-ia32-msvc": "4.60.4", + "@rollup/rollup-win32-x64-gnu": "4.60.4", + "@rollup/rollup-win32-x64-msvc": "4.60.4", + "fsevents": "~2.3.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/supercluster": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", + "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", + "license": "ISC", + "dependencies": { + "kdbush": "^4.0.2" + } + }, + "node_modules/tinyqueue": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", + "license": "ISC" + }, + "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/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" + } + } +} diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..e097ce6 --- /dev/null +++ b/web/package.json @@ -0,0 +1,21 @@ +{ + "name": "xplane-glass-cockpit-web", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "leaflet": "^1.9.4", + "maplibre-gl": "^5.24.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.3.4", + "vite": "^5.4.11" + } +} diff --git a/web/public/icons/apple-touch-icon.png b/web/public/icons/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6769486cc85f2b212631d6b6ab2b8c1ce2730798 GIT binary patch literal 2078 zcmd5-SvVVr7EU{sQd?2dlp0GJT5BmnN`%JJXc4BAsFXHht6eN{B}H`X#+a5?P%WlH zZLu%4Ra?ZqlxR?D3CX0?lHr<}Z{~jYeIDlFob&x}=U>iul5W_-g#|%^002PP%F^8a zXx98*C-{y!q@Pa*0O0>*We!C~Ljejy&@`TSsDvaR;s#I`>hUiI zfkrI=61Q4Z#h96)@4rs-8tP$5Wq0MFPN=h$A7;Erh2FF53Im1*0YefJX2d&fg@^;J z^jqjjzdJN%@gN(a{ndzRjgxl<59|f$F3DDN=EAzA>4_V9aRBCcj&Sd5JJ6rf9!oVlZ`@ERgk3F9?6!_5a+g0d`uN z3C!j$avA!u&9Jm?FaJw3ZSb3{Ts*5|yH`aAp~JDvsHjKMSm{NIQ}K^|+ke#h%U{{P zjhp(2-u6)taRZ~i;PqZsaJy!9cx7dGe#^|OaoMO+VyQrS-Mgt*`OE#tQ#z>IADp4z zM7@cte>JQM*gI(FLx8n0gx6#NL89_^G-wf?-QaZWf4lFHGfYqprvQJ_L-M4wes7I5 z?bs(PV1{7`8fe?rZ>Z`|S$NC6G>dU9j=bf53s_h8P^i!Jn`7tKRHuo`u2|yLxhUTD zKcvpkj|7CYh!=n{T`6*aTlt=)q99cQ;7z3KNj_n5Se<5UWBUP0M7?c`CrWg^D*x)ChNBx zIl=HY`iq#*W3txYERR6@flXCdGNpU|k&a!^CQy~~)C(=SrxeL3G{-~K3I^MLqDjw@ zy4EZ7&UDAySKd!uOf9cGXlq2Tj;Vw+bq7xvu&+H)qFni;kRU%K@j|JdeM!K7N<%!! zv&TTIj3U_xr>oIVpX~lTFCh@G6uFn&wYu8vIPR95Ng3D8D1+HI?HDGxmH6vjp`ss1 zUc}XSyEKtgjME~%hp2BbVCCrwDz-@;!1>049MZe<49Nbous)7L2f1iLtW;nc;!D~= z;hfCT!>n)@9LE|&()JnZuAJ43s!08h2*f4QqrP`Q=I;8-6tJI^=VBXog4 z<7g#UK0l{fHVjb>YS%$~KEE?b4{F^GOG|w|fo01O%`tuAcph^$dqn_m+X7KoU|0 zc9wV7o;A9lpaENTqGa0yR0K#>t2Vb;W93j6hZa=M_s+Thde>ECEcj6O!V-&~|7=&1`;8dY|^&O+@+VfID3>r!Sh>xSKuxg0M`tVna$`3pYwnfWxoF*GGnAu{K)9 z1FK|%J0~h49nEgFiFdBGa3Ab)#@3#N(RGpzLZ35nDQCT6-skpGUU8&dAaam!6d||H zWn?i`jyY+71QX6lA0EFKV~BduU8qNGCr*XPh++@ zlP&sJn3eLWDX?M%4ChV*`=oo~;M!i*PBY%b!w9iRU0{2^ivnL3$$mHzcGWv+3%F0+ zf(LCZzB7M4rJnoFv~CNhHF?d&Z0jRM*#;c39Yrk@_lW* zQ3XsRi$Xj0wI+w;;Wd}Rq9|{!rjstHEugC)ums8Dhk8wM->nMGhjkF(N{0oH(2_lA z7t|9xW|tXJF||O8c=5fUoCmQlt-YO=#tb=T3AlzC>T`S77)pIvI82jGarSp>5b~eF z&KfU{8X&P7pR^hRwTx@la+Kiy)QM6*Z_>U?u(sR0s=3X@JW1T~lrK^Z%!TxRM? xvW#CL*7X<(6hdJC@9zH@V3p1lRf-6_H4pc7KKlCrD+^n5irH<#e*qN;;j;h$ literal 0 HcmV?d00001 diff --git a/web/public/icons/icon-192.png b/web/public/icons/icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..3289bb2ca1ff263c486d12db166518db54ee12b2 GIT binary patch literal 2548 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 literal 0 HcmV?d00001 diff --git a/web/public/icons/icon-512.png b/web/public/icons/icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..124ee1b08e89def94a271734a270a941ba109317 GIT binary patch literal 7541 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 a2W+Y#ig4-);^{nF(ihL`pDR$ez4I^d-wmVy literal 0 HcmV?d00001 diff --git a/web/public/manifest.webmanifest b/web/public/manifest.webmanifest new file mode 100644 index 0000000..15253fe --- /dev/null +++ b/web/public/manifest.webmanifest @@ -0,0 +1,16 @@ +{ + "name": "G1000 Glass Cockpit", + "short_name": "G1000", + "description": "X-Plane 12 G1000 glass cockpit — PFD / MFD / FMS over your LAN", + "start_url": "/", + "scope": "/", + "display": "standalone", + "orientation": "landscape", + "background_color": "#000000", + "theme_color": "#000000", + "icons": [ + { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" }, + { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" }, + { "src": "/icons/icon-512-maskable.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" } + ] +} diff --git a/web/public/sw.js b/web/public/sw.js new file mode 100644 index 0000000..30a599c --- /dev/null +++ b/web/public/sw.js @@ -0,0 +1,31 @@ +// Minimal service worker: caches the app shell so the cockpit launches fast and +// survives brief network blips. Live data (the bridge WebSocket, /api, and map +// tiles) is never cached — only same-origin GET app assets. +const CACHE = 'g1000-shell-v1'; + +self.addEventListener('install', () => self.skipWaiting()); + +self.addEventListener('activate', (e) => { + e.waitUntil( + caches.keys().then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k)))) + .then(() => self.clients.claim()) + ); +}); + +self.addEventListener('fetch', (e) => { + const url = new URL(e.request.url); + // Only same-origin GET app shell; skip the API and let the WS pass through. + if (e.request.method !== 'GET' || url.origin !== location.origin) return; + if (url.pathname.startsWith('/api') || url.pathname === '/ws') return; + + // Stale-while-revalidate: serve cache fast, refresh in the background. + e.respondWith( + caches.open(CACHE).then(async (cache) => { + const cached = await cache.match(e.request); + const network = fetch(e.request) + .then((res) => { if (res && res.ok) cache.put(e.request, res.clone()); return res; }) + .catch(() => cached); + return cached || network; + }) + ); +}); diff --git a/web/src/App.jsx b/web/src/App.jsx new file mode 100644 index 0000000..0aaee80 --- /dev/null +++ b/web/src/App.jsx @@ -0,0 +1,115 @@ +import React, { useState } from 'react'; +import { useXplane } from './api/useXplane.js'; +import PFD from './components/PFD.jsx'; +import AutopilotPanel from './components/AutopilotPanel.jsx'; +import MFD from './components/MFD.jsx'; +import MapView from './components/MapView.jsx'; +import CDU from './components/CDU.jsx'; +import VFR from './components/VFR.jsx'; +import Bezel from './components/Bezel.jsx'; +import DirectTo from './components/DirectTo.jsx'; +import Proc from './components/Proc.jsx'; + +// Compact line icons for the nav rail (stroke = currentColor). +const ICONS = { + pfd: 'M11 3a8 8 0 100 16 8 8 0 000-16zM3.5 11h15M7 8l1.5 1M15 8l-1.5 1', + mfd: 'M3 6l5-2 6 2 5-2v12l-5 2-6-2-5 2zM8 4v12M14 6v12', + map: 'M11 2c-3.3 0-6 2.6-6 5.9 0 4.4 6 11.1 6 11.1s6-6.7 6-11.1C17 4.6 14.3 2 11 2z', + fms: 'M4 6h14M4 11h14M4 16h9', + ap: 'M11 4a7 7 0 100 14 7 7 0 000-14zM11 4v3M11 15v3M4 11h3M15 11h3', + vfr: 'M11 4a7 7 0 100 14 7 7 0 000-14zM11 11l4.5-3', +}; +function Icon({ name }) { + return ( + + + {name === 'map' && } + + ); +} + +const TABS = [ + { id: 'pfd', label: 'PFD' }, + { id: 'mfd', label: 'MFD' }, + { id: 'map', label: 'Map' }, + { id: 'fms', label: 'FMS' }, + { id: 'vfr', label: 'VFR' }, + { id: 'ap', label: 'Autopilot' }, +]; + +export default function App() { + const xp = useXplane(); + const [tab, setTab] = useState(() => location.hash.replace('#', '') || 'pfd'); + // Collapsible nav rail: narrow (icons) ↔ wide (icons + labels), remembered. + const [navWide, setNavWide] = useState(() => localStorage.getItem('navWide') === '1'); + const go = (id) => { setTab(id); history.replaceState(null, '', `#${id}`); }; + const toggleNav = () => setNavWide((w) => { localStorage.setItem('navWide', w ? '0' : '1'); return !w; }); + // Synthetic-terrain (3D) vs. classic blue/brown attitude — toggled by the + // PFD → SYN TERR softkey, exactly like the real XPLANE 1000. + const [svt3d, setSvt3d] = useState(true); + // The PFD INSET map (bottom-left) is off by default and toggled by its softkey. + const [inset, setInset] = useState(false); + // INSET map options (base layer + declutter), set from the INSET submenu. + const [insetMode, setInsetMode] = useState({ base: 'topo', dcltr: 0 }); + // The NRST (nearest airports/navaids) window, toggled by the PFD NRST softkey. + const [nrst, setNrst] = useState(false); + // The TMR/REF (timer / references) window, toggled by the PFD TMR/REF softkey. + const [tmr, setTmr] = useState(false); + // MFD map mode (base layer), switched via the Map-Opt softkeys. + const [mapMode, setMapMode] = useState({ base: 'topo' }); + // Direct-To (D→) dialog — opened from the bezel on either GDU. + const [dto, setDto] = useState(false); + // PROC (procedures: SID/STAR/approach) dialog — opened from the bezel. + const [proc, setProc] = useState(false); + + const connKind = xp.xpConnected ? 'ok' : xp.connected ? 'warn' : 'bad'; + const connText = xp.xpConnected ? 'X-PLANE' : xp.connected ? 'NO SIM' : 'OFFLINE'; + + return ( +
+ + +
+ {tab === 'pfd' && ( + setSvt3d((v) => !v)} + inset={inset} onSetInset={setInset} insetMode={insetMode} onInsetMode={setInsetMode} + nrst={nrst} onToggleNrst={() => setNrst((v) => !v)} onDirect={() => setDto(true)} + tmr={tmr} onToggleTmr={() => setTmr((v) => !v)} onProc={() => setProc(true)}> + setNrst(false)} + tmr={tmr} onCloseTmr={() => setTmr(false)} flightPlan={xp.flightPlan} fp={xp.fp} /> + + )} + {tab === 'mfd' && ( + setDto(true)} onProc={() => setProc(true)}> + + + )} + {tab === 'map' && } + {tab === 'fms' && } + {tab === 'vfr' && } + {tab === 'ap' && } +
+ {dto && setDto(false)} />} + {proc && setProc(false)} />} +
+ ); +} diff --git a/web/src/api/useXplane.js b/web/src/api/useXplane.js new file mode 100644 index 0000000..93580d1 --- /dev/null +++ b/web/src/api/useXplane.js @@ -0,0 +1,88 @@ +import { useEffect, useRef, useState, useCallback } from 'react'; + +// Single WebSocket connection to the bridge. Streams dataref values + the +// shared flight plan in; sends commands / dataref writes / flight-plan edits +// out. Auto-reconnects. +export function useXplane() { + const [values, setValues] = useState({}); + const [flightPlan, setFlightPlan] = useState({ name: 'ACTIVE', waypoints: [] }); + const [exportMsg, setExportMsg] = useState(null); + const [connected, setConnected] = useState(false); // socket to bridge + const [xpConnected, setXpConnected] = useState(false); // bridge <-> X-Plane + const wsRef = useRef(null); + + useEffect(() => { + let closed = false; + let retry; + // Coalesce incoming value bursts into a single React update per animation + // frame — keeps the gauges smooth instead of re-rendering ~20×/sec. + let pending = null; + let raf = 0; + const flush = () => { + raf = 0; + if (pending) { const p = pending; pending = null; setValues((prev) => ({ ...prev, ...p })); } + }; + + const connect = () => { + const proto = location.protocol === 'https:' ? 'wss' : 'ws'; + const ws = new WebSocket(`${proto}://${location.host}/ws`); + wsRef.current = ws; + + ws.onopen = () => setConnected(true); + ws.onmessage = (ev) => { + const msg = JSON.parse(ev.data); + if (msg.type === 'values') { + pending = pending ? Object.assign(pending, msg.data) : { ...msg.data }; + if (!raf) raf = requestAnimationFrame(flush); + } + else if (msg.type === 'status') setXpConnected(!!msg.xpConnected); + else if (msg.type === 'flightplan') setFlightPlan(msg.data); + else if (msg.type === 'fp_export_result') setExportMsg(msg); + }; + ws.onclose = () => { + setConnected(false); + setXpConnected(false); + if (!closed) retry = setTimeout(connect, 2000); + }; + ws.onerror = () => ws.close(); + }; + + connect(); + return () => { closed = true; clearTimeout(retry); wsRef.current?.close(); }; + }, []); + + const send = useCallback((obj) => { + const ws = wsRef.current; + if (ws && ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify(obj)); + }, []); + + const command = useCallback((name, duration = 0) => send({ type: 'command', name, duration }), [send]); + const setDataref = useCallback((name, value) => send({ type: 'setDataref', name, value }), [send]); + + // flight-plan actions + const fp = { + add: (ident) => send({ type: 'fp_add', ident }), + addLatLon: (lat, lon) => send({ type: 'fp_add', ident: `${lat},${lon}` }), + remove: (index) => send({ type: 'fp_remove', index }), + setActive: (index) => send({ type: 'fp_active', index }), + clear: () => send({ type: 'fp_clear' }), + set: (plan) => send({ type: 'fp_set', plan }), + export: (name) => send({ type: 'fp_export', name }), + }; + + return { values, flightPlan, exportMsg, connected, xpConnected, command, setDataref, fp }; +} + +// Search X-Plane's nav database (waypoints/VOR/NDB/airports) via the bridge. +export async function navSearch(q) { + if (!q) return []; + try { + const r = await fetch(`/api/nav/search?q=${encodeURIComponent(q)}`); + return r.ok ? r.json() : []; + } catch { + return []; + } +} + +// Convenience: read a numeric value with a fallback. +export const num = (v, d = 0) => (typeof v === 'number' && isFinite(v) ? v : d); diff --git a/web/src/components/AutopilotPanel.jsx b/web/src/components/AutopilotPanel.jsx new file mode 100644 index 0000000..2b4f82b --- /dev/null +++ b/web/src/components/AutopilotPanel.jsx @@ -0,0 +1,83 @@ +import React from 'react'; +import { num } from '../api/useXplane.js'; + +// Autopilot / AFCS mode-control panel — styled like a Garmin GMC-710 mode +// controller: an annunciator bar on top (active = green, armed = white), a row +// of lit mode keys, and selectors (HDG / ALT / VS / IAS) with knob steppers. +// Buttons fire X-Plane's own autopilot commands; the sim stays the source of truth. + +const AP_BITS = { + fd: 1 << 0, hdg: 1 << 1, vs: 1 << 4, flc: 1 << 6, + nav: 1 << 8, apr: 1 << 9, vnav: 1 << 11, altHold: 1 << 14, bc: 1 << 18, +}; +const on = (s, b) => (num(s) & b) !== 0; + +export default function AutopilotPanel({ xp }) { + const { values: V, command, setDataref } = xp; + const s = num(V.apState); + const eng = num(V.apEngaged) > 0; + + const lateral = on(s, AP_BITS.apr) ? 'APR' : on(s, AP_BITS.nav) ? 'NAV' : on(s, AP_BITS.hdg) ? 'HDG' : 'ROL'; + const vertical = on(s, AP_BITS.flc) ? 'FLC' : on(s, AP_BITS.vs) ? 'VS' : on(s, AP_BITS.vnav) ? 'VNV' : on(s, AP_BITS.altHold) ? 'ALT' : 'PIT'; + + const Key = ({ label, cmd, active }) => ( + + ); + + const Sel = ({ label, value, unit, alias, step, dn, up, pad }) => ( +
+
{label}
+
{pad ? String(((Math.round(value) % 360) + 360) % 360).padStart(3, '0') : Math.round(value)}{unit}
+
+ + + +
+
+ ); + + return ( +
+
+ {/* annunciator bar */} +
+ AP + FD + + {lateral} + + {vertical} + {Math.round(num(V.apAltBug))}FT +
+ + {/* mode keys */} +
+ + + + + + + + + + +
+ + {/* selectors */} +
+ + + + +
+ +
+ PITCH + + +
+
+
+ ); +} diff --git a/web/src/components/Bezel.jsx b/web/src/components/Bezel.jsx new file mode 100644 index 0000000..3196b28 --- /dev/null +++ b/web/src/components/Bezel.jsx @@ -0,0 +1,225 @@ +import React, { useState } from 'react'; +import { num } from '../api/useXplane.js'; + +// The physical GDU bezel of X-Plane's "XPLANE 1000" (its G1000 clone): +// title bar, knob columns, the 12 softkeys along the bottom — and, on the MFD, +// the autopilot mode controller built into the left bezel (just like the sim). +// +// EVERY control is clickable and fires the matching real X-Plane command +// (sim/GPS/g1000n1_* on the PFD, g1000n3_* on the MFD) via xp.command(). +// +// The PFD softkeys are a two-level menu, exactly like the real unit: +// root → [INSET · PFD · CDI · DME · XPDR · IDENT · TMR/REF · NRST · CAUTION] +// PFD → [PATHWAY · SYN TERR · HRZN HDG · APTSIGNS · … · BACK] +// SYN TERR toggles the 3D synthetic-vision terrain on/off. +const PFD_MENU = { + root: ['', 'INSET', '', 'PFD', '', 'CDI', 'DME', 'XPDR', 'IDENT', 'TMR/REF', 'NRST', 'CAUTION'], + pfd: ['PATHWAY', 'SYN TERR', 'HRZN HDG', 'APTSIGNS', '', '', '', '', '', '', '', 'BACK'], + // XPDR submenu: standby/on/alt modes, VFR (1200), CODE entry, IDENT. + xpdr: ['STBY', 'ON', 'ALT', 'VFR', '', 'CODE', 'IDENT', '', '', '', '', 'BACK'], + // CODE entry turns the softkeys into the octal squawk keypad (digits 0–7). + xpdrcode: ['0', '1', '2', '3', '4', '5', '6', '7', 'BKSP', '', 'BACK', ''], + // INSET submenu: on/off, declutter, base layer, OFF, back. + inset: ['INSET', 'DCLTR', '', 'TOPO', 'TERRAIN', '', '', '', '', '', 'OFF', 'BACK'], +}; +// MFD softkeys are a two-level menu like the real unit. MAP opens the Map-Opt +// page; TOPO/TERRAIN/OSM switch the base map; BACK returns. (OSM is our tuned +// extra layer in an otherwise-empty slot.) +const MFD_MENU = { + root: ['SYSTEM', 'MAP', '', '', '', '', '', '', '', 'DCLTR', '', ''], + mapopt: ['TRAFFIC', 'PROFILE', 'TOPO', 'TERRAIN', 'AIRWAYS', '', 'NEXRAD', 'OSM', '', '', 'BACK', ''], + system: ['DEC FUEL', 'INC FUEL', 'RST FUEL', '', '', '', '', '', '', '', 'BACK', ''], +}; + +// autopilot_state bitfield (best-effort; tweak per aircraft) +const AP_BITS = { fd: 1 << 0, hdg: 1 << 1, vs: 1 << 4, flc: 1 << 6, nav: 1 << 8, apr: 1 << 9, vnav: 1 << 11, altHold: 1 << 14, bc: 1 << 18 }; + +export default function Bezel({ variant = 'pfd', xp, svt3d, onToggleSvt, inset, onSetInset, insetMode, onInsetMode, nrst, onToggleNrst, tmr, onToggleTmr, onDirect, onProc, mapMode, onMapMode, children }) { + const u = variant === 'mfd' ? 'mfd' : 'pfd'; // command prefix + const fire = (suffix) => xp && xp.command(`${u}_${suffix}`); + const [page, setPage] = useState('root'); // softkey menu page + const [squawk, setSquawk] = useState(''); // XPDR code being typed + + const menu = variant === 'mfd' ? MFD_MENU : PFD_MENU; + const keys = menu[page] || menu.root; + const setBase = (b) => onMapMode && onMapMode((m) => ({ ...m, base: m.base === b ? 'dark' : b })); + const xpdrMode = num(xp?.values?.xpdrMode); + const setMode = (m) => xp && xp.setDataref('xpdrMode', m); + + const typeDigit = (d) => { + const next = (squawk + d).slice(-4); + setSquawk(next); + if (next.length === 4) { // 4 octal digits → write & exit + xp && xp.setDataref('xpdrCode', parseInt(next, 10)); + setSquawk(''); setPage('xpdr'); + } + }; + + const onSoftkey = (i, label) => { + fire(`softkey${i + 1}`); // mirror to the in-sim G1000 + if (variant === 'mfd') { + if (label === 'MAP') setPage('mapopt'); + else if (label === 'SYSTEM') setPage('system'); + else if (label === 'BACK') setPage('root'); + else if (label === 'TOPO') setBase('topo'); + else if (label === 'TERRAIN') setBase('terrain'); + else if (label === 'OSM') setBase('osm'); + else if (label === 'DCLTR') onMapMode && onMapMode((m) => ({ ...m, dcltr: m.dcltr ? 0 : 1 })); + } else { + if (label === 'PFD') setPage('pfd'); + else if (label === 'BACK') setPage(page === 'xpdrcode' ? 'xpdr' : 'root'); + else if (label === 'SYN TERR') onToggleSvt && onToggleSvt(); + else if (label === 'INSET') { + if (page === 'root') { onSetInset && onSetInset(true); setPage('inset'); } + else onSetInset && onSetInset(!inset); // toggle from within the submenu + } + else if (label === 'OFF') { onSetInset && onSetInset(false); setPage('root'); } + else if (label === 'DCLTR') onInsetMode && onInsetMode((m) => ({ ...m, dcltr: m.dcltr ? 0 : 1 })); + else if (label === 'TOPO') onInsetMode && onInsetMode((m) => ({ ...m, base: 'topo' })); + else if (label === 'TERRAIN') onInsetMode && onInsetMode((m) => ({ ...m, base: 'terrain' })); + else if (label === 'NRST') onToggleNrst && onToggleNrst(); + else if (label === 'TMR/REF') onToggleTmr && onToggleTmr(); + else if (label === 'XPDR') setPage('xpdr'); + else if (label === 'STBY') setMode(1); + else if (label === 'ON') setMode(2); + else if (label === 'ALT') setMode(3); + else if (label === 'VFR') xp && xp.setDataref('xpdrCode', 1200); + else if (label === 'CODE') { setSquawk(''); setPage('xpdrcode'); } + else if (label === 'IDENT') xp && xp.command('xpdrIdent'); + else if (label === 'BKSP') setSquawk((s) => s.slice(0, -1)); + else if (page === 'xpdrcode' && /^[0-7]$/.test(label)) typeDigit(label); + } + }; + // which softkey is "lit" right now + const isOn = (label) => { + if (variant === 'mfd') return (label === 'TOPO' && mapMode?.base === 'topo') + || (label === 'TERRAIN' && mapMode?.base === 'terrain') || (label === 'OSM' && mapMode?.base === 'osm') + || (label === 'DCLTR' && mapMode?.dcltr > 0); + return (label === 'SYN TERR' && svt3d) || (label === 'INSET' && inset) || (label === 'NRST' && nrst) || (label === 'TMR/REF' && tmr) + || (label === 'STBY' && xpdrMode === 1) || (label === 'ON' && xpdrMode === 2) || (label === 'ALT' && xpdrMode === 3) + || (page === 'inset' && label === 'TOPO' && insetMode?.base === 'topo') + || (page === 'inset' && label === 'TERRAIN' && insetMode?.base === 'terrain') + || (label === 'DCLTR' && insetMode?.dcltr > 0); + }; + + return ( +
+
+ + + {variant === 'mfd' && xp && } + +
+ +
+
XPLANE 1000
+
{children}
+ {page === 'xpdrcode' && ( +
SQUAWK {squawk.padEnd(4, '_')}
+ )} +
+ {keys.map((s, i) => ( + + ))} +
+
+ +
+ + + +
+ D→MENU + FPLPROC + CLRENT +
+ +
+
+ ); +} + +function BtnG({ fire, cmd, onClick, children }) { + return ; +} + +// Autopilot mode controller (left bezel of the MFD). Buttons fire real X-Plane +// commands; active modes light up from autopilot_state / servos_on. +function APController({ xp }) { + const st = num(xp.values.apState); + const on = (bit) => (st & bit) !== 0; + const eng = num(xp.values.apEngaged) > 0; + const B = ({ label, cmd, active }) => ( + + ); + return ( +
+ + + + + + + + + + + + +
+ ); +} + +// Concentric G1000 knob. The outer ring rotates via the side arrows (‹ ›) and +// the mouse wheel; the inner ring via the top/bottom arrows (˄ ˅) and shift+wheel. +// Clicking the knob centre fires the push action (PUSH …). The RANGE knob also +// pans with a directional cross. +function Knob({ label, sub, outer, inner, push, big, joy, pan, fire }) { + const onWheel = (e) => { + if (!outer) return; + e.preventDefault(); + const set = (e.shiftKey && inner) ? inner : outer; + fire(e.deltaY < 0 ? set[0] : set[1]); + }; + return ( +
+ {label} +
+ {inner && } + {outer && } + + {outer && } + {inner && } +
+ {pan && ( +
+ + + + +
+ )} + {sub && {sub}} +
+ ); +} diff --git a/web/src/components/CDU.jsx b/web/src/components/CDU.jsx new file mode 100644 index 0000000..8222b35 --- /dev/null +++ b/web/src/components/CDU.jsx @@ -0,0 +1,135 @@ +import React, { useState } from 'react'; +import { num, navSearch } from '../api/useXplane.js'; + +// FMS as an X-Plane-style CDU/FMC: a green screen showing the active flight plan +// as legs, six line-select keys per side, a scratchpad, and an alphanumeric +// keypad. Edits go through the shared flight plan (the same one the PFD/MFD use). +// +// LSK (left, per row): +// • scratchpad has an ident → insert that waypoint at the row +// • DEL armed → delete the leg at the row +// • otherwise → make that leg the active (magenta) leg (Direct-To) +// EXEC exports the plan to X-Plane as an .fms file. + +const R_NM = 3440.065, rad = (d) => d * Math.PI / 180, deg = (r) => r * 180 / Math.PI; +function distNm(a, b) { + const dLat = rad(b.lat - a.lat), dLon = rad(b.lon - a.lon); + const s = Math.sin(dLat / 2) ** 2 + Math.cos(rad(a.lat)) * Math.cos(rad(b.lat)) * Math.sin(dLon / 2) ** 2; + return 2 * R_NM * Math.asin(Math.min(1, Math.sqrt(s))); +} +function brng(a, b) { + const y = Math.sin(rad(b.lon - a.lon)) * Math.cos(rad(b.lat)); + const x = Math.cos(rad(a.lat)) * Math.sin(rad(b.lat)) - Math.sin(rad(a.lat)) * Math.cos(rad(b.lat)) * Math.cos(rad(b.lon - a.lon)); + return (deg(Math.atan2(y, x)) + 360) % 360; +} + +const ROWS = 5; // legs visible per page + +export default function CDU({ xp }) { + const { flightPlan, fp, exportMsg } = xp; + const wps = flightPlan.waypoints || []; + const active = Math.max(1, Math.min(wps.length - 1, flightPlan.activeLeg ?? 1)); + const [scr, setScr] = useState(''); + const [del, setDel] = useState(false); + const [msg, setMsg] = useState(''); + const [page, setPage] = useState(0); + + const pages = Math.max(1, Math.ceil((wps.length + 1) / ROWS)); + const start = page * ROWS; + + const type = (ch) => { setMsg(''); setScr((s) => (s + ch).slice(0, 8)); }; + const clr = () => { if (scr) setScr((s) => s.slice(0, -1)); else { setDel(false); setMsg(''); } }; + + // resolve an ident and splice it into the plan at `index` + const insertAt = async (ident, index) => { + const hits = await navSearch(ident); + const hit = hits[0]; + if (!hit) { setMsg('NOT IN DATABASE'); return; } + const next = wps.slice(); + next.splice(index, 0, { id: hit.id, lat: hit.lat, lon: hit.lon, type: hit.type || 'WPT', alt: null }); + fp.set({ name: 'ACTIVE', waypoints: next, activeLeg: flightPlan.activeLeg ?? 1 }); + setScr(''); + }; + + const lsk = (rowIdx) => { + const i = start + rowIdx; + if (scr) { insertAt(scr, Math.min(i, wps.length)); return; } + if (del) { if (i < wps.length) fp.remove(i); setDel(false); return; } + if (i >= 1 && i < wps.length) fp.setActive(i); + }; + + const exec = () => { if (wps.length >= 2) fp.export('WEBFPL'); else setMsg('NEED 2 WAYPOINTS'); }; + + // build the visible rows + const rows = []; + for (let r = 0; r < ROWS; r++) { + const i = start + r; + if (i < wps.length) { + const w = wps[i], prev = wps[i - 1]; + const d = prev ? distNm(prev, w) : 0; + const dtk = prev ? Math.round(brng(prev, w)) : null; + rows.push({ i, id: w.id, type: w.type, d, dtk, orig: i === 0, act: i === active }); + } else if (i === wps.length) { + rows.push({ i, empty: true }); + } else { + rows.push({ i, blank: true }); + } + } + + const A = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''); + const KEYS = [A.slice(0, 7), A.slice(7, 14), A.slice(14, 21), A.slice(21, 26).concat([' ']), ['1', '2', '3', '4', '5'], ['6', '7', '8', '9', '0']]; + + const Lsk = ({ side, r }) => + + + + + + +
+ {KEYS.map((rowK, ri) => ( +
+ {rowK.map((k) => ( + + ))} +
+ ))} +
+ + + ); +} diff --git a/web/src/components/DirectTo.jsx b/web/src/components/DirectTo.jsx new file mode 100644 index 0000000..d3af2d7 --- /dev/null +++ b/web/src/components/DirectTo.jsx @@ -0,0 +1,91 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { num, navSearch } from '../api/useXplane.js'; + +// G1000 Direct-To (D→) dialog. Type or pick a waypoint ident; ACTIVATE flies a +// direct magenta leg from the present position to it. We model that by setting +// the shared flight plan to [PPOS → target] (the map/HSI already draw the leg) +// and also firing the in-sim "direct" command so the real G1000 follows along. +const R_NM = 3440.065; +const rad = (d) => (d * Math.PI) / 180; +function distBrg(la1, lo1, la2, lo2) { + const dLat = rad(la2 - la1), dLon = rad(lo2 - lo1); + const a = Math.sin(dLat / 2) ** 2 + Math.cos(rad(la1)) * Math.cos(rad(la2)) * Math.sin(dLon / 2) ** 2; + const dist = 2 * R_NM * Math.asin(Math.min(1, Math.sqrt(a))); + const y = Math.sin(rad(lo2 - lo1)) * Math.cos(rad(la2)); + const x = Math.cos(rad(la1)) * Math.sin(rad(la2)) - Math.sin(rad(la1)) * Math.cos(rad(la2)) * Math.cos(rad(lo2 - lo1)); + const brg = (Math.atan2(y, x) * 180 / Math.PI + 360) % 360; + return { dist, brg }; +} + +export default function DirectTo({ xp, onClose }) { + const { values, fp, command } = xp; + const [entry, setEntry] = useState(''); + const [hits, setHits] = useState([]); + const [sel, setSel] = useState(null); // chosen { id, lat, lon, type } + const inputRef = useRef(null); + + useEffect(() => { inputRef.current?.focus(); }, []); + + // Live ident search against X-Plane's nav database. + useEffect(() => { + const q = entry.trim(); + if (q.length < 2 || /[,\s]/.test(q)) { setHits([]); return; } + let alive = true; + navSearch(q).then((r) => alive && setHits(r.slice(0, 6))); + return () => { alive = false; }; + }, [entry]); + + const lat = num(values.lat), lon = num(values.lon); + const preview = sel && isFinite(lat) ? distBrg(lat, lon, sel.lat, sel.lon) : null; + + const activate = () => { + if (!sel) return; + fp.set({ name: 'ACTIVE', waypoints: [ + { id: 'PPOS', lat, lon, type: 'USR' }, + { id: sel.id, lat: sel.lat, lon: sel.lon, type: sel.type || 'WPT' }, + ] }); + command('direct'); // mirror to the in-sim G1000 + onClose(); + }; + + return ( +
+
e.stopPropagation()}> +
D→ DIRECT TO
+
+ + { setEntry(e.target.value.toUpperCase()); setSel(null); }} + onKeyDown={(e) => { if (e.key === 'Enter' && sel) activate(); if (e.key === 'Escape') onClose(); }} + placeholder="IDENT (z.B. KSEA, SEA, ELN)" + autoCapitalize="characters" autoCorrect="off" spellCheck="false" + /> + {hits.length > 0 && ( +
+ {hits.map((h) => ( + + ))} +
+ )} + {sel && ( +
+ {sel.id} + {sel.type} + {preview && {String(Math.round(preview.brg)).padStart(3, '0')}° · {preview.dist.toFixed(1)} NM} +
+ )} +
+
+ + +
+
+
+ ); +} diff --git a/web/src/components/FMS.jsx b/web/src/components/FMS.jsx new file mode 100644 index 0000000..3357766 --- /dev/null +++ b/web/src/components/FMS.jsx @@ -0,0 +1,121 @@ +import React, { useState, useEffect } from 'react'; +import { num, navSearch } from '../api/useXplane.js'; + +const R_NM = 3440.065; +const rad = (d) => (d * Math.PI) / 180; +const deg = (r) => (r * 180) / Math.PI; +function distNm(a, b) { + const dLat = rad(b.lat - a.lat), dLon = rad(b.lon - a.lon); + const s = Math.sin(dLat / 2) ** 2 + Math.cos(rad(a.lat)) * Math.cos(rad(b.lat)) * Math.sin(dLon / 2) ** 2; + return 2 * R_NM * Math.asin(Math.min(1, Math.sqrt(s))); +} +function bearing(a, b) { + const y = Math.sin(rad(b.lon - a.lon)) * Math.cos(rad(b.lat)); + const x = Math.cos(rad(a.lat)) * Math.sin(rad(b.lat)) - + Math.sin(rad(a.lat)) * Math.cos(rad(b.lat)) * Math.cos(rad(b.lon - a.lon)); + return (deg(Math.atan2(y, x)) + 360) % 360; +} + +export default function FMS({ xp }) { + const { flightPlan, fp, values, exportMsg } = xp; + const wps = flightPlan.waypoints || []; + const [entry, setEntry] = useState(''); + const [hits, setHits] = useState([]); + + // live ident search against X-Plane's nav database + useEffect(() => { + const q = entry.trim(); + if (q.length < 2 || /[,\s]/.test(q)) { setHits([]); return; } + let alive = true; + navSearch(q).then((r) => alive && setHits(r.slice(0, 6))); + return () => { alive = false; }; + }, [entry]); + + const add = (id) => { fp.add(id || entry.trim()); setEntry(''); setHits([]); }; + + let total = 0; + const rows = wps.map((w, i) => { + const prev = wps[i - 1]; + const d = prev ? distNm(prev, w) : 0; + const brg = prev ? bearing(prev, w) : null; + total += d; + return { w, i, d, brg }; + }); + + const gs = num(values.groundspeed) * 1.94384; + const ete = gs > 20 ? total / gs : null; // hours + const active = Math.max(1, Math.min(wps.length - 1, flightPlan?.activeLeg ?? 1)); + + return ( +
+
+ FLIGHT PLAN + + {total.toFixed(0)} NM{ete ? ` · ETE ${fmtHrs(ete)}` : ''} + +
+ +
+
+ #WPTDTKDIST +
+ {rows.length === 0 &&
Kein Flugplan — Wegpunkt eingeben oder auf der Map tippen.
} + {rows.map(({ w, i, d, brg }) => ( +
i >= 1 && fp.setActive(i)} title={i >= 1 ? 'Als aktives Bein setzen' : ''}> + {i + 1} + {w.id}{w.type} + {brg == null ? '—' : `${String(Math.round(brg)).padStart(3, '0')}°`} + {i === 0 ? 'ORIG' : `${d.toFixed(1)}`} + +
+ ))} +
+ +
+ {hits.length > 0 && ( +
+ {hits.map((h) => ( + + ))} +
+ )} +
+ setEntry(e.target.value.toUpperCase())} + onKeyDown={(e) => e.key === 'Enter' && add()} + placeholder="IDENT (z.B. KSEA, SEA) oder LAT,LON" + autoCapitalize="characters" autoCorrect="off" spellCheck="false" + /> + +
+
+ + +
+ {exportMsg && ( +
+ {exportMsg.ok + ? (exportMsg.intoXplane + ? `✓ Gespeichert in X-Plane: ${shorten(exportMsg.file)} — im Flieger-FMS unter „Load" wählen.` + : `✓ Datei geschrieben: ${shorten(exportMsg.file)} (X-Plane-Ordner nicht gefunden — XPLANE_ROOT setzen).`) + : `✗ ${exportMsg.error}`} +
+ )} +
+
+ ); +} + +function fmtHrs(h) { + const m = Math.round(h * 60); + return `${Math.floor(m / 60)}:${String(m % 60).padStart(2, '0')}`; +} +function shorten(p) { + return p && p.length > 48 ? '…' + p.slice(-46) : p; +} diff --git a/web/src/components/MFD.jsx b/web/src/components/MFD.jsx new file mode 100644 index 0000000..3f44aaf --- /dev/null +++ b/web/src/components/MFD.jsx @@ -0,0 +1,210 @@ +import React, { useState } from 'react'; +import { num } from '../api/useXplane.js'; +import MapView from './MapView.jsx'; + +const arr = (v, i = 0, d = 0) => (Array.isArray(v) ? num(v[i], d) : num(v, d)); +const KG_PER_GAL = 2.72; // avgas +const navF = (v) => (num(v) / 100).toFixed(2); +const comF = (v) => (num(v) / 100).toFixed(3); + +// G1000 MFD — full-width NAV/COM bar on top, the engine instrument strip (EIS) +// down the left as real bar gauges, and the moving map (X-Plane nav data) with +// G1000 chrome (compass rose, range, NORTH UP, mode) filling the rest. +export default function MFD({ values: V, flightPlan, fp, mapMode }) { + const [rangeNm, setRangeNm] = useState(8); + return ( +
+ +
+ +
+ setRangeNm(rangeNm)} /> + +
+
+
+ ); +} + +/* ---------------- top NAV/COM bar ---------------- */ +function MfdTopBar({ V }) { + const gs = Math.round(num(V.groundspeed) * 1.94384); + const trk = String(Math.round(num(V.track)) % 360).padStart(3, '0'); + const swap = (x, y) => ; + return ( + + + {[300, 660].map((x) => )} + + {/* NAV1 / NAV2 */} + NAV1 + + {navF(V.nav1)} + {swap(150, 27)} + {navF(V.nav1Sb)} + NAV2 + {navF(V.nav2)} + {navF(V.nav2Sb)} + {/* centre: GS/DTK/TRK/ETE + active mode line */} + GS + {gs} + KT + DTK + TRK + {trk}° + ETE + NAV – DEFAULT NAV + {/* COM1 / COM2 */} + {comF(V.com1)} + {swap(818, 27)} + + {comF(V.com1Sb)} + COM1 + {comF(V.com2)} + {comF(V.com2Sb)} + COM2 + + ); +} + +/* ---------------- engine instrument strip (EIS) ---------------- */ +function EisStrip({ V }) { + const rpm = arr(V.engRpm); + const ffGph = (arr(V.fuelFlow) * 3600) / KG_PER_GAL; + const oilPsi = arr(V.oilPress); + const oilF = arr(V.oilTemp) * 9 / 5 + 32; + const egtF = arr(V.egt) * 9 / 5 + 32; + const fuelL = arr(V.fuelQty, 0) / KG_PER_GAL; + const fuelR = arr(V.fuelQty, 1) / KG_PER_GAL; + const volts = arr(V.volts, 0, 28); + const amps = arr(V.amps); + return ( + + + + + + + + + + ENG + 0.0 HRS + – ELECTRICAL – + M + BUS + E + {volts.toFixed(1)} + VOLTS + {volts.toFixed(1)} + M + BATT + S + {amps >= 0 ? '+' : ''}{amps.toFixed(1)} + AMPS + +0.0 + + ); +} + +function Bar({ y, label, val, min, max, value, zones }) { + const x0 = 8, x1 = 182, bw = x1 - x0; + const px = (v) => x0 + bw * Math.max(0, Math.min(1, (v - min) / (max - min))); + const p = px(value); + return ( + + {label} + {val != null && {val}} + + {zones.map((z, i) => )} + + + ); +} + +// Fuel quantity: one bar per the C172's two tanks, with L and R pointers on a +// shared 0–10–20–F (gal) scale; yellow/red caution zone at the low end. +function FuelBar({ y, left, right }) { + const x0 = 8, x1 = 182, bw = x1 - x0, max = 26.5; + const px = (g) => x0 + bw * Math.max(0, Math.min(1, g / max)); + const tick = (g, lbl) => ( + + + {lbl} + + ); + const ptr = (g, lbl) => ( + + + {lbl} + + ); + return ( + + FUEL QTY GAL + + + + + {tick(0, '0')}{tick(8.83, '10')}{tick(17.66, '20')}{tick(max, 'F')} + {ptr(left, 'L')}{ptr(right, 'R')} + + ); +} + +function RpmArc({ rpm }) { + const max = 2700, frac = Math.max(0, Math.min(1, rpm / max)); + const a0 = -210, a1 = 30, ang = a0 + (a1 - a0) * frac; + const cx = 95, cy = 62, r = 42; + const pt = (deg, rr) => [cx + rr * Math.cos((deg * Math.PI) / 180), cy + rr * Math.sin((deg * Math.PI) / 180)]; + const arc = (s, e, color, w) => { + const [x0, y0] = pt(s, r), [x1, y1] = pt(e, r); + return 180 ? 1 : 0} 1 ${x1} ${y1}`} fill="none" stroke={color} strokeWidth={w} />; + }; + const [nx, ny] = pt(ang, r - 2); + return ( + + {arc(a0, a1, '#2a2a2a', 7)} + {arc(a0, -30, '#0c0', 7)} + {arc(0, a1, '#c00', 7)} + + + RPM + {Math.round(rpm)} + + ); +} + +/* ---------------- map chrome overlay (compass rose / range / mode) ---------------- */ +const NICE = [0.5, 1, 1.5, 2, 2.5, 4, 5, 7.5, 10, 15, 20, 25, 40, 50, 75, 100, 150, 200, 250, 500]; +function niceRange(nm) { let r = NICE[0]; for (const s of NICE) if (nm >= s) r = s; return r; } + +function MapChrome({ V, rangeNm }) { + const gs = Math.round(num(V.groundspeed) * 1.94384); + const rng = niceRange(rangeNm); + const cx = 160, cy = 160, r = 150; + const ticks = []; + for (let d = 0; d < 360; d += 10) { + const a = ((d - 90) * Math.PI) / 180; + const big = d % 30 === 0; + const r2 = r - (big ? 12 : 7); + ticks.push(); + if (big) { + const lbl = d === 0 ? 'N' : d === 90 ? 'E' : d === 180 ? 'S' : d === 270 ? 'W' : d / 10; + ticks.push({lbl}); + } + } + return ( +
+ {ticks} +
{gs} KTNORTH UP
+
{rng} NM
+
NAV
+
+ ); +} diff --git a/web/src/components/MapView.jsx b/web/src/components/MapView.jsx new file mode 100644 index 0000000..f61f281 --- /dev/null +++ b/web/src/components/MapView.jsx @@ -0,0 +1,208 @@ +import React, { useEffect, useRef, useState } from 'react'; +import L from 'leaflet'; +import 'leaflet/dist/leaflet.css'; +import { num } from '../api/useXplane.js'; + +const PLANE_SVG = + ''; + +// A single nav feature rendered as G1000-style symbology: cyan airport, green +// VOR hexagon, brown NDB dot-ring, light fix triangle — with an optional label. +function navSymbol(f, label) { + const t = (f.type || '').toUpperCase(); + let g, color; + if (t === 'APT') { + color = '#19d3ff'; + g = ``; + } else if (t === 'VOR') { + color = '#19ff5a'; + g = ``; + } else if (t === 'NDB') { + color = '#d59a5a'; + g = ``; + } else { + color = '#cfe3ff'; + g = ``; + } + const lbl = label ? `${f.id}` : ''; + const html = ``; + return L.marker([f.lat, f.lon], { + icon: L.divIcon({ className: 'nav-divicon', html, iconSize: [18, 18], iconAnchor: [9, 9] }), + interactive: false, + }); +} + +// Selectable base layers — switched by the MFD's Map-Opt softkeys. 'dark' draws +// no tiles (pure black, like the G1000 with TOPO off); 'terrain' is a relief +// hillshade; 'topo' is shaded relief; 'osm' is our tuned street layer. +const TILES = { + topo: { url: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', opts: { maxZoom: 17, subdomains: 'abc' } }, + osm: { url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', opts: { maxZoom: 19 } }, + terrain: { url: 'https://server.arcgisonline.com/ArcGIS/rest/services/Elevation/World_Hillshade/MapServer/tile/{z}/{y}/{x}', opts: { maxZoom: 16 } }, + dark: null, +}; + +export default function MapView({ values, flightPlan, fp, inset = false, hud = true, mapMode, dcltr = 0, onView }) { + const elRef = useRef(null); + const mapRef = useRef(null); + const acRef = useRef(null); + const routeRef = useRef(null); + const wpLayerRef = useRef(null); + const navLayerRef = useRef(null); + const navAbortRef = useRef(null); + const baseRef = useRef(null); + const [follow, setFollow] = useState(true); + const followRef = useRef(true); + followRef.current = follow; + + const lat = num(values.lat, 47.45); + const lon = num(values.lon, -122.31); + const track = num(values.track); + const gs = num(values.groundspeed) * 1.94384; // m/s -> kt + const base = mapMode?.base || 'topo'; + const dcltrRef = useRef(dcltr); + dcltrRef.current = dcltr; + + // Swap the base tile layer (and report it via the container's dark class). + const applyBase = (map, name) => { + if (baseRef.current) { map.removeLayer(baseRef.current); baseRef.current = null; } + const def = TILES[name]; + if (def) baseRef.current = L.tileLayer(def.url, def.opts).addTo(map); + if (baseRef.current) baseRef.current.bringToBack(); + elRef.current?.classList.toggle('dark', name === 'dark'); + }; + + // Report the current range (centre→top edge, in NM) for the G1000 range box. + const reportView = (map) => { + if (!onView) return; + const c = map.getCenter(), n = L.latLng(map.getBounds().getNorth(), c.lng); + onView({ rangeNm: map.distance(c, n) / 1852 }); + }; + + // create map once + useEffect(() => { + const map = L.map(elRef.current, { zoomControl: !inset, attributionControl: false, dragging: !inset, scrollWheelZoom: !inset }) + .setView([lat, lon], inset ? 10 : 9); + applyBase(map, base); + + navLayerRef.current = L.layerGroup().addTo(map); // real airports/navaids/fixes + routeRef.current = L.layerGroup().addTo(map); // flight-plan legs (white + magenta active) + wpLayerRef.current = L.layerGroup().addTo(map); + + // Pull X-Plane's own nav data for the current view and draw it as G1000-style + // vector symbology (cyan airports, green VOR hexagons, NDB dot-rings, fixes). + const refreshNav = async () => { + const layer = navLayerRef.current; + if (!layer) return; + const z = map.getZoom(); + if (z < 6 || dcltrRef.current > 0) { layer.clearLayers(); return; } + const types = z >= 10 ? 'apt,vor,ndb,fix' : z >= 8 ? 'apt,vor,ndb' : 'apt'; + const b = map.getBounds(); + const url = `/api/nav/bbox?s=${b.getSouth()}&w=${b.getWest()}&n=${b.getNorth()}&e=${b.getEast()}&types=${types}&limit=${z >= 10 ? 500 : 250}`; + try { + navAbortRef.current?.abort(); + navAbortRef.current = new AbortController(); + const res = await fetch(url, { signal: navAbortRef.current.signal }); + if (!res.ok) return; + const feats = await res.json(); + layer.clearLayers(); + const labels = z >= 8; + for (const f of feats) navSymbol(f, labels).addTo(layer); + } catch { /* aborted or offline — leave as is */ } + }; + map.on('moveend', () => { refreshNav(); reportView(map); }); + map.on('zoomend', () => reportView(map)); + setTimeout(() => { refreshNav(); reportView(map); }, 300); + + const icon = L.divIcon({ className: 'ac-divicon', html: PLANE_SVG, iconSize: [34, 34], iconAnchor: [17, 17] }); + acRef.current = L.marker([lat, lon], { icon, interactive: false, zIndexOffset: 1000 }).addTo(map); + + // tap the map to drop a user waypoint (full map only) + if (!inset && fp) map.on('click', (e) => fp.addLatLon(+e.latlng.lat.toFixed(5), +e.latlng.lng.toFixed(5))); + if (!inset) map.on('dragstart', () => setFollow(false)); + + mapRef.current = map; + // leaflet needs a nudge once its container has real size + setTimeout(() => map.invalidateSize(), 200); + return () => { map.remove(); mapRef.current = null; }; + }, []); // eslint-disable-line + + // swap base layer when the MFD changes map mode + useEffect(() => { + const map = mapRef.current; + if (map) applyBase(map, base); + }, [base]); // eslint-disable-line + + // declutter: hide nav symbology, or repopulate it, when the level changes + useEffect(() => { + const map = mapRef.current; + if (!map) return; + if (dcltr > 0) navLayerRef.current?.clearLayers(); + else map.fire('moveend'); // triggers refreshNav to redraw symbols + }, [dcltr]); // eslint-disable-line + + // update aircraft position + heading + useEffect(() => { + const ac = acRef.current, map = mapRef.current; + if (!ac || !map) return; + ac.setLatLng([lat, lon]); + const el = ac.getElement()?.querySelector('svg'); + if (el) el.style.transform = `rotate(${track}deg)`; + if (followRef.current) map.panTo([lat, lon], { animate: true, duration: 0.5 }); + }, [lat, lon, track]); + + // redraw route + waypoints when the plan changes. Like the real G1000, the + // active leg (to waypoint `activeLeg`) is magenta; all other legs are white. + useEffect(() => { + const route = routeRef.current, layer = wpLayerRef.current; + if (!route || !layer) return; + route.clearLayers(); + layer.clearLayers(); + const wps = flightPlan?.waypoints || []; + const active = Math.max(1, Math.min(wps.length - 1, flightPlan?.activeLeg ?? 1)); + for (let i = 1; i < wps.length; i++) { + const seg = [[wps[i - 1].lat, wps[i - 1].lon], [wps[i].lat, wps[i].lon]]; + const isActive = i === active; + L.polyline(seg, { color: isActive ? '#ff20ff' : '#ffffff', weight: isActive ? 4 : 2.5, opacity: 0.95 }).addTo(route); + } + wps.forEach((w, i) => { + const isActiveWp = i === active; // the waypoint the active leg flies to + L.circleMarker([w.lat, w.lon], { + radius: 6, color: '#fff', weight: 2, + fillColor: isActiveWp ? '#ff20ff' : '#0a0a0a', fillOpacity: 1, + }) + .bindTooltip(`${i + 1}. ${w.id}`, { permanent: true, direction: 'right', className: 'wp-label' }) + .addTo(layer); + }); + }, [flightPlan]); + + if (inset) { + return ( +
+
+
+ ); + } + return ( +
+
+ {hud && ( + <> +
+
GS{Math.round(gs)} kt
+
TRK{String(Math.round(track) % 360).padStart(3, '0')}°
+
POS{lat.toFixed(3)}, {lon.toFixed(3)}
+ {num(values.gpsDistNm) > 0 && ( +
→WPT{num(values.gpsDistNm).toFixed(1)} nm
+ )} +
+ +
Tippe auf die Karte, um einen Wegpunkt hinzuzufügen
+ + )} +
+ ); +} diff --git a/web/src/components/Nearest.jsx b/web/src/components/Nearest.jsx new file mode 100644 index 0000000..08cd4e8 --- /dev/null +++ b/web/src/components/Nearest.jsx @@ -0,0 +1,77 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { num } from '../api/useXplane.js'; + +// The G1000 "Nearest" window. On the PFD it pops up over the right side when you +// press the NRST softkey; it lists the closest airports / VORs / NDBs to the +// aircraft with bearing + distance, straight from X-Plane's own nav data +// (/api/nav/nearest). Tabs switch the feature type, like turning the FMS knob +// through the NRST page group on the real unit. +const TABS = [ + { id: 'apt', label: 'APT' }, + { id: 'vor', label: 'VOR' }, + { id: 'ndb', label: 'NDB' }, +]; + +// VOR freq comes in 10 kHz units (11630 → 116.30); NDB in kHz (e.g. 350). +const freqStr = (f, type) => { + const n = num(f); + if (!n) return ''; + return type === 'vor' ? (n / 100).toFixed(2) : String(n); +}; + +export default function Nearest({ values, onClose }) { + const [type, setType] = useState('apt'); + const [rows, setRows] = useState([]); + const lastRef = useRef(null); + const lat = num(values.lat), lon = num(values.lon); + + useEffect(() => { + let abort = new AbortController(); + let timer; + const load = async () => { + if (!isFinite(lat) || !isFinite(lon) || (lat === 0 && lon === 0)) return; + try { + const r = await fetch(`/api/nav/nearest?lat=${lat}&lon=${lon}&type=${type}&count=9`, { signal: abort.signal }); + if (r.ok) setRows(await r.json()); + } catch { /* aborted / offline */ } + }; + load(); + // Refresh as the aircraft moves (cheap server scan). + timer = setInterval(load, 5000); + return () => { abort.abort(); clearInterval(timer); }; + }, [type, Math.round(lat * 50), Math.round(lon * 50)]); // re-key on ~1nm moves + + return ( +
+
+ NEAREST +
+ {TABS.map((t) => ( + + ))} +
+ {onClose && } +
+
+ {type === 'apt' ? 'IDENT' : 'IDENT'} + BRG + DIS + {type === 'apt' ? 'ELEV' : 'FREQ'} +
+
+ {rows.length === 0 &&
— no data —
} + {rows.map((f, i) => ( +
+ {f.id} + {String(num(f.brg)).padStart(3, '0')}° + {num(f.dist).toFixed(1)}nm + + {type === 'apt' ? `${Math.round(num(f.elev))}ft` : freqStr(f.freq, type)} + + {f.name && {f.name}} +
+ ))} +
+
+ ); +} diff --git a/web/src/components/PFD.jsx b/web/src/components/PFD.jsx new file mode 100644 index 0000000..72c4354 --- /dev/null +++ b/web/src/components/PFD.jsx @@ -0,0 +1,589 @@ +import React, { useRef, useState, useLayoutEffect, Suspense, lazy } from 'react'; +import { num } from '../api/useXplane.js'; +import MapView from './MapView.jsx'; +import Nearest from './Nearest.jsx'; +import TimerRef from './TimerRef.jsx'; +// Lazy-load the heavy WebGL terrain engine only when the PFD is shown. +const SVT = lazy(() => import('./SVT.jsx')); + +// Garmin G1000 (GDU 1040) PFD as used by the default Cessna 172. Every field is +// driven by the same X-Plane datarefs the in-sim G1000 uses, so values match. +const W = 1000; +const H = 780; +const PITCH_PX = 9; + +const arr0 = (v, d = 0) => (Array.isArray(v) ? num(v[0], d) : num(v, d)); +const navF = (v) => (num(v) / 100).toFixed(2); // NAV: 11170 -> 111.70 +const comF = (v) => (num(v) / 100).toFixed(3); // COM: 11810 -> 118.100 + +// Great-circle bearing + distance (nm) from aircraft to a point. +const D2R = Math.PI / 180, R2D = 180 / Math.PI, R_NM = 3440.065; +function brgDist(la1, lo1, la2, lo2) { + const dLat = (la2 - la1) * D2R, dLon = (lo2 - lo1) * D2R; + const a = Math.sin(dLat / 2) ** 2 + Math.cos(la1 * D2R) * Math.cos(la2 * D2R) * Math.sin(dLon / 2) ** 2; + const dist = 2 * R_NM * Math.asin(Math.min(1, Math.sqrt(a))); + const y = Math.sin(dLon) * Math.cos(la2 * D2R); + const x = Math.cos(la1 * D2R) * Math.sin(la2 * D2R) - Math.sin(la1 * D2R) * Math.cos(la2 * D2R) * Math.cos(dLon); + const brg = (Math.atan2(y, x) * R2D + 360) % 360; + return { brg, dist }; +} +// GPS guidance to the active flight-plan leg, computed from our own plan. +function activeNav(V, fp) { + const wps = fp?.waypoints || []; + if (wps.length < 1) return null; + const ai = Math.max(1, Math.min(wps.length - 1, fp?.activeLeg ?? 1)); + const wp = wps[ai]; + const lat = num(V.lat), lon = num(V.lon); + if (!wp || (!lat && !lon)) return null; + const { brg, dist } = brgDist(lat, lon, wp.lat, wp.lon); + const prev = wps[ai - 1]; + const dtk = prev ? brgDist(prev.lat, prev.lon, wp.lat, wp.lon).brg : brg; + const gs = num(V.groundspeed) * 1.94384; + const ete = gs > 20 ? (dist / gs) * 3600 : null; // seconds + // Cross-track deviation from the prev→wp leg, for the GPS CDI (dots; full + // scale 2 nm enroute = 1 nm/dot). + = right of course → CDI bar deflects left. + let def = 0, xtk = 0; + if (prev) { + const leg = brgDist(prev.lat, prev.lon, lat, lon); // prev → aircraft + xtk = Math.asin(Math.sin(leg.dist / R_NM) * Math.sin((leg.brg - dtk) * D2R)) * R_NM; + def = Math.max(-2.5, Math.min(2.5, -xtk / 1.0)); + } + return { id: wp.id, brg, dist, dtk, ete, xtk, def }; +} +function fmtEte(s) { + if (s == null) return '--:--'; + const m = Math.round(s / 60); + return `${Math.floor(m / 60)}:${String(m % 60).padStart(2, '0')}`; +} +// VNAV: nearest downstream waypoint with a lower altitude constraint, and the +// vertical speed required to meet it at the current groundspeed. +function vnavInfo(V, fp) { + const wps = fp?.waypoints || []; + const ai = Math.max(1, Math.min(wps.length - 1, fp?.activeLeg ?? 1)); + const alt = num(V.altitude); + const lat = num(V.lat), lon = num(V.lon); + const gs = num(V.groundspeed) * 1.94384; + if (gs < 40 || (!lat && !lon)) return null; + let cum = 0, prevLat = lat, prevLon = lon; + for (let i = ai; i < wps.length; i++) { + cum += brgDist(prevLat, prevLon, wps[i].lat, wps[i].lon).dist; + prevLat = wps[i].lat; prevLon = wps[i].lon; + const tgt = num(wps[i].alt); + if (tgt > 0 && tgt < alt - 50) { + const tMin = (cum / gs) * 60; + const vsReq = tMin > 0 ? (tgt - alt) / tMin : 0; + return { wptId: wps[i].id, tgtAlt: tgt, dist: cum, vsReq }; + } + } + return null; +} + +// Attitude SYMBOLOGY clip (pitch ladder, roll arc, FD) — only the upper region, +// so the ladder doesn't bleed into the tapes/HSI. +const ATT = { x: W / 2 - 290, y: 270 - 175, w: 580, h: 385 }; +// The synthetic terrain fills the WHOLE display below the radio bar, exactly +// like the real G1000 — the tapes and HSI sit translucently on top of it. +const SVT_BOX = { x: 0, y: 74, w: W, h: H - 74 }; +// The INSET moving map sits in the bottom-left corner (toggled by INSET softkey). +const INSET_BOX = { x: 6, y: 556, w: 300, h: 172 }; + +export default function PFD({ values: V, svt = true, inset = false, insetMode, nrst = false, onCloseNrst, tmr = false, onCloseTmr, flightPlan, fp }) { + const wrapRef = useRef(null); + const svgRef = useRef(null); + const [box, setBox] = useState(null); + const [insetBox, setInsetBox] = useState(null); + + // Map SVG-space regions to on-screen pixels, accounting for the SVG's + // letterboxing (xMidYMid meet) — used for both the SVT canvas and the inset. + useLayoutEffect(() => { + const measure = () => { + const svg = svgRef.current, wrap = wrapRef.current; + if (!svg || !wrap) return; + const r = svg.getBoundingClientRect(), wr = wrap.getBoundingClientRect(); + const scale = Math.min(r.width / W, r.height / H); + const offX = (r.width - W * scale) / 2 + (r.left - wr.left); + const offY = (r.height - H * scale) / 2 + (r.top - wr.top); + const map = (b) => ({ left: offX + b.x * scale, top: offY + b.y * scale, width: b.w * scale, height: b.h * scale }); + setBox(map(SVT_BOX)); + setInsetBox(map(INSET_BOX)); + }; + measure(); + const ro = new ResizeObserver(measure); + if (svgRef.current) ro.observe(svgRef.current); + window.addEventListener('resize', measure); + return () => { ro.disconnect(); window.removeEventListener('resize', measure); }; + }, []); + + const nav = activeNav(V, flightPlan); + const vnav = vnavInfo(V, flightPlan); + + return ( +
+ {svt && box && ( +
+ }> +
+ )} + {inset && insetBox && ( +
+ +
+ )} + + + + + + + + + + {!svt && } + + {nav && } + {vnav && } + + + + + + + + + {nrst && } + {tmr && } +
+ ); +} + +/* ---------------- top NAV/COM radio bar ---------------- */ +// Matches the XPLANE 1000: NAV cyan (active boxed), COM green active / +// cyan-boxed standby, a centre flight-plan cell with DIS/BRG, ⇄ swap arrows. +const SWAP = '⇔'; +function RadioBar({ V }) { + const swap = (x, y) => {SWAP}; + return ( + + + {/* cell dividers */} + {[330, 560, 690].map((x) => )} + + + {/* NAV1 / NAV2 (left) */} + NAV1 + + {navF(V.nav1)} + {swap(176, 28)} + {navF(V.nav1Sb)} + NAV2 + {navF(V.nav2)} + {swap(176, 60)} + {navF(V.nav2Sb)} + + {/* centre: active leg + DIS/BRG */} + {'→'} + + + DIS + {V.gpsDistNm != null ? num(V.gpsDistNm).toFixed(1) : '_._'} + NM + BRG + + {/* COM1 / COM2 (right) */} + {comF(V.com1)} + {swap(848, 28)} + + {comF(V.com1Sb)} + COM1 + {comF(V.com2)} + {swap(848, 60)} + {comF(V.com2Sb)} + COM2 + + ); +} + +/* ---------------- attitude + flight director ---------------- */ +function Attitude({ V, svt }) { + const pitch = num(V.pitch), roll = num(V.roll), slip = num(V.slip); + const fdP = num(V.fdPitch), fdR = num(V.fdRoll); + const cx = W / 2, cy = 270; + const off = pitch * PITCH_PX; + + return ( + + + + + + + + {/* sky/ground only when SVT is off — otherwise the 3D terrain shows */} + {!svt && } + {!svt && } + {!svt && } + {pitchLadder(cx, cy)} + + + {/* flight director command bars (magenta) */} + + + + + {rollArc(cx, cy, roll, slip)} + {/* fixed aircraft reference (yellow) */} + + + + + {/* flight path marker (green) — track/AOA based; offset approximated */} + {(() => { + const fpx = Math.max(-120, Math.min(120, (num(V.track) - num(V.heading)) * 6)); + return ( + + + + + + + ); + })()} + {!svt && } + + ); +} + +function pitchLadder(cx, cy) { + const m = []; + for (let d = -90; d <= 90; d += 2.5) { + if (d === 0) continue; + const y = cy - d * PITCH_PX; + const ten = d % 10 === 0, five = d % 5 === 0; + const half = ten ? 70 : five ? 40 : 22; + m.push(); + if (ten) m.push( + + {Math.abs(d)} + {Math.abs(d)} + + ); + } + return {m}; +} + +function rollArc(cx, cy, roll, slip) { + const r = 165; + const ticks = [-60, -45, -30, -20, -10, 0, 10, 20, 30, 45, 60]; + return ( + + {ticks.map((t) => { + const a = (t - 90) * (Math.PI / 180); + const big = t % 30 === 0 || t === 0; + const r2 = r - (big ? 18 : 11); + return ; + })} + + + + + + + ); +} + +/* ---------------- airspeed tape ---------------- */ +// V-speed reference marks for the C172 (KIAS), shown below the tape like the +// XPLANE 1000: Vy=74 (Y), Vx=62 (X), best glide=68 (G). +const VSPEEDS = [{ s: 74, l: 'Y' }, { s: 62, l: 'X' }, { s: 68, l: 'G' }]; +function AirspeedTape({ V }) { + const ias = num(V.airspeed), tas = num(V.tas), spdBug = num(V.apSpdBug); + const x = 60, top = 95, h = 350, cy = top + h / 2, px = 3.6; + const W2 = 84, sx = x + W2 - 7; // colour strip at the right inner edge + const ticks = []; + const lo = Math.floor((ias - 50) / 10) * 10; + for (let s = lo; s <= ias + 50; s += 10) { + if (s < 0) continue; + const y = cy + (ias - s) * px; + ticks.push( + {s}); + } + const yOf = (s) => Math.max(top, Math.min(top + h, cy + (ias - s) * px)); + const band = (a, b, color) => ; + const bugY = Math.max(top, Math.min(top + h, cy + (ias - spdBug) * px)); + const valid = ias >= 20; + return ( + + + {/* V-speed colour strip (white flap arc, green normal, yellow caution, red Vne) */} + {band(33, 85, '#e8e8e8')} + {band(48, 129, '#16c116')} + {band(129, 163, '#e0d000')} + + {ticks} + {/* selected-airspeed bug (cyan) */} + + {/* current-speed readout box (points right toward the tape) */} + + {valid ? Math.round(ias) : '- - -'} + {/* V-speed reference list below the tape */} + {VSPEEDS.map((v, i) => ( + + {v.s} + + {v.l} + + ))} + {/* TAS box at the very bottom */} + + TAS + {Math.round(tas)} + + ); +} + +/* ---------------- altitude tape + VSI + baro ---------------- */ +function AltitudeTape({ V }) { + const alt = num(V.altitude), vs = num(V.vspeed), altBug = num(V.apAltBug), baro = num(V.baro, 29.92); + const x = W - 70 - 84, W2 = 84, top = 95, h = 350, cy = top + h / 2, px = 0.42; + const ticks = []; + const lo = Math.floor((alt - 420) / 100) * 100; + for (let a = lo; a <= alt + 420; a += 100) { + const y = cy + (alt - a) * px; + ticks.push( + {a}); + } + const bugY = Math.max(top, Math.min(top + h, cy + (alt - altBug) * px)); + // rolling readout: leading hundreds (static) + a two-digit drum that *rolls* + // through 20-ft steps, so you always see the value you're between — exactly + // like the mechanical tens drum on the real GDU 1040. + const hi = Math.floor(alt / 100); + const STEP = 20, ROW = 25; // drum increment + row height + const base = Math.floor(alt / STEP) * STEP; // nearest 20 ft at/below current + const frac = (alt - base) / STEP; // 0..1 position between rows + const selStr = altBug > 0 ? String(Math.round(altBug)) : '- - - - -'; + // drum geometry + const drumX = x + W2 + 4, drumW = 26, drumCx = drumX + drumW / 2; + return ( + + {/* selected altitude (cyan) above the tape */} + + {selStr} + + {ticks} + {/* selected-altitude bug (cyan) on the tape */} + + {/* current-altitude readout (points left toward the tape): static hundreds + + a rolling tens/units drum that scrolls through 20-ft steps, so two + values are visible at once with the pointer between them (GDU 1040). */} + + + {hi} + + {[-1, 0, 1, 2].map((k) => { + const v = base + k * STEP; + const s = String(((v % 100) + 100) % 100).padStart(2, '0'); + return {s}; + })} + + {/* baro */} + + {baro.toFixed(2)} IN + {/* VSI to the right */} + + + ); +} +function VSI({ x, cy, h, vs, bug }) { + const max = 2000, top = cy - h / 2 + 10, bot = cy + h / 2 - 10; + const yOf = (v) => cy - (Math.max(-max, Math.min(max, v)) / max) * (h / 2 - 10); + return ( + + + {[2000, 1000, 0, -1000, -2000].map((v) => ( + + + {v !== 0 && {Math.abs(v) / 1000}} + + ))} + {[500, 1500, -500, -1500].map((v) => )} + {bug !== 0 && } + + {Math.abs(vs) >= 100 ? Math.round(vs / 10) * 10 : ''} + + ); +} + +/* ---------------- HSI compass rose ---------------- */ +function HSI({ V, nav }) { + const hdg = ((num(V.heading) % 360) + 360) % 360; + const bug = num(V.apHdgBug); + // With an active flight-plan leg the CDI follows OUR GPS guidance (desired + // track + cross-track); otherwise it mirrors the sim's nav source. + const crs = nav ? nav.dtk : num(V.obsCrs, 360); + const def = nav ? nav.def : num(V.hsiDef); + const toFrom = nav ? 1 : num(V.hsiToFrom); + const cx = W / 2, cy = 630, r = 130; + + const ticks = []; + for (let d = 0; d < 360; d += 5) { + const a = ((d - hdg - 90) * Math.PI) / 180; + const big = d % 30 === 0; + const r2 = r - (big ? 18 : 10); + ticks.push(); + if (big) { + const lr = r - 36, la = a; + const lbl = d === 0 ? 'N' : d === 90 ? 'E' : d === 180 ? 'S' : d === 270 ? 'W' : d / 10; + ticks.push({lbl}); + } + } + const bugA = bug - hdg, crsA = crs - hdg; + const defPx = Math.max(-2, Math.min(2, def)) * 26; + + return ( + + + {ticks} + {/* lubber line + heading box */} + + + {String(Math.round(hdg) % 360).padStart(3, '0')} + {/* heading bug (cyan) */} + + + + {/* GPS source label */} + GPS + ENR + {/* course pointer + CDI (magenta = GPS source) */} + + + + + {/* CDI deviation bar */} + + {[-2, -1, 1, 2].map((d) => )} + {toFrom > 0 && } + + {/* cyan bearing pointer to the active flight-plan waypoint (BRG) */} + {nav && ( + + + + + + )} + + + ); +} + +/* ---------------- VNAV box (descent target + required vertical speed) ---------------- */ +function VnavBox({ vnav }) { + const vs = Math.round(vnav.vsReq / 10) * 10; + return ( + + + VNV + {vnav.tgtAlt}FT + @{vnav.wptId} + VS + {vs >= 0 ? '+' : ''}{vs} + + ); +} + +/* ---------------- glideslope (vertical deviation) for ILS approaches ---------------- */ +// Localizer freqs: 108.10–111.95 MHz with an odd 100-kHz digit → an ILS (has GS). +function isILS(navHz) { + const f = num(navHz) / 100; + return f >= 108.1 && f <= 111.95 && Math.floor(f * 10) % 2 === 1; +} +function GlideSlope({ V }) { + if (!isILS(V.nav1)) return null; + const cx = 792, cy = 280, h = 120, step = h / 2.5; // ±2.5 dots + // +vdef = above glideslope → diamond rides high → "fly down". + const def = Math.max(-2.5, Math.min(2.5, num(V.gsDef))); + const dy = cy - def * step; + return ( + + + GS + + + {[-2, -1, 1, 2].map((d) => ( + + ))} + + + ); +} + +/* ---------------- GPS nav status block (top, when a leg is active) ---------------- */ +function NavStatus({ nav }) { + return ( + + + {nav.id} + DTK + {String(Math.round(nav.dtk)).padStart(3, '0')}° + DIS + {nav.dist.toFixed(1)}nm + ETE + {fmtEte(nav.ete)} + + ); +} + +/* ---------------- HDG/CRS boxes flanking the HSI ---------------- */ +function HdgCrsBoxes({ V, nav }) { + const hdgSel = String(Math.round(num(V.apHdgBug)) % 360).padStart(3, '0'); + // In GPS mode (active leg) the CRS field shows the desired track. + const crsVal = nav ? nav.dtk : num(V.obsCrs, 360); + const crs = String(Math.round(crsVal) % 360 || 360).padStart(3, '0'); + return ( + + + HDG + {hdgSel}° + + CRS + {crs}° + + ); +} + +/* ---------------- bottom data line: OAT / ISA / XPDR / LCL ---------------- */ +function DataStrip({ V }) { + const oatC = num(V.oat); + const oatF = Math.round(oatC * 9 / 5 + 32); + const stdC = 15 - 1.98 * (num(V.altitude) / 1000); // ISA temp at altitude + const isaF = Math.round((oatC - stdC) * 9 / 5); + const xpdr = String(num(V.xpdrCode, 1200)).padStart(4, '0'); + const mode = ['OFF', 'STBY', 'ON', 'ALT', 'TEST'][num(V.xpdrMode)] || 'ALT'; + const now = new Date(); + const lcl = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`; + return ( + + + {/* OAT + ISA (left) */} + + OAT {oatF}°F + + ISA {isaF >= 0 ? '+' : ''}{isaF}°F + {/* XPDR + LCL (right) — code/mode in green text, like the real GDU */} + XPDR + {xpdr}{mode} + LCL {lcl} + + ); +} diff --git a/web/src/components/Proc.jsx b/web/src/components/Proc.jsx new file mode 100644 index 0000000..b373f7b --- /dev/null +++ b/web/src/components/Proc.jsx @@ -0,0 +1,116 @@ +import React, { useEffect, useState } from 'react'; +import { num } from '../api/useXplane.js'; + +// G1000 PROC dialog. Pick a destination/airport, a category (Departure / Arrival +// / Approach), then a procedure + transition; LOAD inserts the procedure's leg +// fixes into the active flight plan. Procedures come from X-Plane's own CIFP data +// via /api/nav/procs and /api/nav/proc (resolved to coordinates server-side). +const CATS = [ + { id: 'approach', label: 'APPROACH', key: 'approaches', t: 'approach' }, + { id: 'arrival', label: 'ARRIVAL', key: 'stars', t: 'star' }, + { id: 'departure', label: 'DEPARTURE', key: 'sids', t: 'sid' }, +]; + +export default function Proc({ xp, onClose }) { + const { flightPlan, fp, values } = xp; + // Default airport: the plan's destination if it's an airport, else blank. + const wps = flightPlan?.waypoints || []; + const destGuess = [...wps].reverse().find((w) => w.type === 'APT')?.id || ''; + const [icao, setIcao] = useState(destGuess); + const [query, setQuery] = useState(destGuess); + const [procs, setProcs] = useState(null); + const [err, setErr] = useState(''); + const [cat, setCat] = useState('approach'); + const [selProc, setSelProc] = useState(null); // { name, transitions } + const [selTrans, setSelTrans] = useState(''); + const [legs, setLegs] = useState([]); + + // Fetch the procedure summary whenever the airport changes. + useEffect(() => { + const id = icao.trim().toUpperCase(); + if (id.length < 3) { setProcs(null); return; } + let alive = true; + setErr(''); setProcs(null); setSelProc(null); setSelTrans(''); setLegs([]); + fetch(`/api/nav/procs?icao=${id}`).then((r) => r.ok ? r.json() : Promise.reject(r.status)) + .then((d) => { if (alive) setProcs(d); }) + .catch(() => { if (alive) setErr(`keine Prozeduren für ${id}`); }); + return () => { alive = false; }; + }, [icao]); + + // Preview the resolved legs when a procedure+transition is chosen. + useEffect(() => { + if (!procs || !selProc) { setLegs([]); return; } + const c = CATS.find((c) => c.id === cat); + let alive = true; + const t = encodeURIComponent(selTrans || ''); + fetch(`/api/nav/proc?icao=${procs.icao}&type=${c.t}&name=${encodeURIComponent(selProc.name)}&trans=${t}`) + .then((r) => r.ok ? r.json() : []).then((d) => { if (alive) setLegs(d); }); + return () => { alive = false; }; + }, [procs, cat, selProc, selTrans]); + + const catList = procs ? (procs[CATS.find((c) => c.id === cat).key] || []) : []; + + const load = () => { + if (!legs.length) return; + const existing = wps.slice(); + // Departures go to the front, arrivals/approaches to the end. + const merged = cat === 'departure' ? [...legs, ...existing] : [...existing, ...legs]; + fp.set({ name: 'ACTIVE', waypoints: merged, activeLeg: cat === 'departure' ? 1 : existing.length || 1 }); + onClose(); + }; + + return ( +
+
e.stopPropagation()}> +
PROCEDURES
+
+
+ + setQuery(e.target.value.toUpperCase())} + onKeyDown={(e) => e.key === 'Enter' && setIcao(query)} + placeholder="ICAO (z.B. KSEA)" autoCapitalize="characters" autoCorrect="off" spellCheck="false" /> + +
+ {err &&
{err}
} + +
+ {CATS.map((c) => ( + + ))} +
+ +
+
+
{procs ? `${catList.length}` : '—'} PROC
+ {catList.map((p) => ( + + ))} + {procs && catList.length === 0 &&
keine
} +
+
+
TRANS
+ {selProc?.transitions.map((t) => ( + + ))} + {selProc && selProc.transitions.length === 0 &&
} +
+
+
{legs.length} FIXES
+ {legs.map((l, i) => ( +
+ {l.id}{l.alt ? {l.alt}ft : null} +
+ ))} +
+
+
+
+ + +
+
+
+ ); +} diff --git a/web/src/components/SVT.jsx b/web/src/components/SVT.jsx new file mode 100644 index 0000000..0108799 --- /dev/null +++ b/web/src/components/SVT.jsx @@ -0,0 +1,177 @@ +import React, { useEffect, useRef } from 'react'; +import maplibregl from 'maplibre-gl'; +import 'maplibre-gl/dist/maplibre-gl.css'; +import { num } from '../api/useXplane.js'; + +// Synthetic Vision background: real-world 3D terrain (elevation tiles) rendered +// in WebGL, with the camera placed at the aircraft and oriented by heading and +// pitch. Bank (roll) is applied as a CSS rotation of the whole canvas. This is +// the SVT *concept* using real-world DEM data — not X-Plane's own scenery. +// +// Free public elevation tiles: AWS "terrarium" (no API key needed). +const STYLE = { + version: 8, + glyphs: 'https://fonts.openmaptiles.org/{fontstack}/{range}.pbf', // for runway-number labels + sources: { + dem: { + type: 'raster-dem', + tiles: ['https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png'], + encoding: 'terrarium', + tileSize: 256, + maxzoom: 11, // coarser cap = far fewer tiles to fetch + attribution: 'Elevation: Mapzen/AWS', + }, + }, + layers: [ + // background shows above the horizon = the sky + { id: 'bg', type: 'background', paint: { 'background-color': '#4a93da' } }, + { + id: 'relief', + type: 'color-relief', + source: 'dem', + paint: { + 'color-relief-color': [ + 'interpolate', ['linear'], ['elevation'], + -50, '#3d6ea5', 0, '#2e6b3a', 300, '#5a8f3c', 800, '#9aa84a', + 1500, '#b08f4e', 2500, '#8d6b4a', 3500, '#b9b0a6', 4500, '#ffffff', + ], + }, + }, + { id: 'hill', type: 'hillshade', source: 'dem', paint: { 'hillshade-exaggeration': 0.55 } }, + ], + terrain: { source: 'dem', exaggeration: 1.3 }, +}; + +// Build runway surfaces (+ threshold number labels) from the bridge's runway +// list. Each runway becomes a ground-draped quad plus two rotated number tags. +function runwayGeoJSON(list) { + const feats = []; + for (const r of list) { + const midLat = (r.la1 + r.la2) / 2; + const mLat = 111320, mLon = 111320 * Math.cos((midLat * Math.PI) / 180); + const dx = (r.lo2 - r.lo1) * mLon, dy = (r.la2 - r.la1) * mLat; + const len = Math.hypot(dx, dy) || 1; + const hw = (r.w || 30) / 2; + const dLon = ((-dy / len) * hw) / mLon, dLat = ((dx / len) * hw) / mLat; + const c1 = [r.lo1 + dLon, r.la1 + dLat], c2 = [r.lo2 + dLon, r.la2 + dLat]; + const c3 = [r.lo2 - dLon, r.la2 - dLat], c4 = [r.lo1 - dLon, r.la1 - dLat]; + feats.push({ type: 'Feature', geometry: { type: 'Polygon', coordinates: [[c1, c2, c3, c4, c1]] }, properties: {} }); + const brg = (Math.atan2(dx, dy) * 180 / Math.PI + 360) % 360; + feats.push({ type: 'Feature', geometry: { type: 'Point', coordinates: [r.lo1, r.la1] }, properties: { num: r.n1, rot: brg } }); + feats.push({ type: 'Feature', geometry: { type: 'Point', coordinates: [r.lo2, r.la2] }, properties: { num: r.n2, rot: (brg + 180) % 360 } }); + } + return { type: 'FeatureCollection', features: feats }; +} + +export default function SVT({ values }) { + const elRef = useRef(null); + const mapRef = useRef(null); + const dataRef = useRef(values); + dataRef.current = values; + + useEffect(() => { + let map; + try { + map = new maplibregl.Map({ + container: elRef.current, + style: STYLE, + center: [num(values.lon, -122.31), num(values.lat, 47.45)], + zoom: 11.5, + pitch: 72, + bearing: num(values.heading), + maxPitch: 76, // lower max pitch = nearer horizon = less distant terrain + pixelRatio: 1, // don't render at 2× on retina — big perf/bandwidth win + renderWorldCopies: false, + maxTileCacheSize: 40, + attributionControl: false, + interactive: false, + preserveDrawingBuffer: true, + fadeDuration: 0, + }); + mapRef.current = map; + } catch (e) { + // WebGL unavailable → the CSS gradient fallback stays visible. + console.warn('SVT: WebGL init failed', e?.message); + return; + } + + // Runways from X-Plane's nav data, draped on the terrain with their numbers. + let rwyTimer; + const addRunways = () => { + if (map.getSource('runways')) return; + map.addSource('runways', { type: 'geojson', data: { type: 'FeatureCollection', features: [] } }); + map.addLayer({ id: 'rwy-fill', type: 'fill', source: 'runways', filter: ['==', ['geometry-type'], 'Polygon'], paint: { 'fill-color': '#33373b', 'fill-opacity': 0.9 } }); + map.addLayer({ id: 'rwy-line', type: 'line', source: 'runways', filter: ['==', ['geometry-type'], 'Polygon'], paint: { 'line-color': '#e8edf2', 'line-width': 1.6 } }); + map.addLayer({ + id: 'rwy-num', type: 'symbol', source: 'runways', filter: ['==', ['geometry-type'], 'Point'], + layout: { + 'text-field': ['get', 'num'], 'text-font': ['Open Sans Bold'], 'text-size': 15, + 'text-rotate': ['get', 'rot'], 'text-rotation-alignment': 'map', 'text-keep-upright': false, + 'text-allow-overlap': true, 'text-ignore-placement': true, + }, + paint: { 'text-color': '#fff', 'text-halo-color': '#000', 'text-halo-width': 1.4 }, + }); + let last = null; + const refresh = async () => { + const v = dataRef.current, lat = num(v.lat), lon = num(v.lon); + if (!isFinite(lat) || !isFinite(lon)) return; + if (last && Math.abs(last[0] - lat) < 0.02 && Math.abs(last[1] - lon) < 0.02) return; + last = [lat, lon]; + try { + const res = await fetch(`/api/nav/runways?lat=${lat}&lon=${lon}&radius=15`); + if (!res.ok) return; + map.getSource('runways')?.setData(runwayGeoJSON(await res.json())); + } catch { /* offline */ } + }; + refresh(); + rwyTimer = setInterval(refresh, 4000); + }; + + // Terrain awareness (TAWS): recolour the relief relative to aircraft + // altitude — terrain within 1000 ft below = yellow, within 100 ft below or + // above = red, otherwise normal. Stops are in metres (terrarium elevation). + let lastBandM = null; + const updateTerrainAwareness = (altFt) => { + const altM = altFt * 0.3048; + if (lastBandM != null && Math.abs(altM - lastBandM) < 12) return; + lastBandM = altM; + const yellowLo = altM - 305, redLo = altM - 30; // 1000 ft / 100 ft below + const s = []; // [elevation, color] pairs, strictly increasing inputs + const push = (e, c) => { if (!s.length || e > s[s.length - 2]) s.push(e, c); }; + push(-150, '#2f6a3c'); push(150, '#4f8a3e'); push(900, '#9a8a4a'); + push(yellowLo - 1, '#7d6a3a'); + push(yellowLo, '#e6c200'); push(redLo - 1, '#e6c200'); + push(redLo, '#e03030'); push(redLo + 4000, '#ff2a2a'); + try { map.setPaintProperty('relief', 'color-relief-color', ['interpolate', ['linear'], ['elevation'], ...s]); } catch { /* not ready */ } + }; + + let raf; + const tick = () => { + const v = dataRef.current; + // Keep the view close: higher zoom floor + capped pitch bounds the area. + const zoom = Math.max(10.5, Math.min(12.5, 12.5 - num(v.altitude) / 3500)); + try { + map.jumpTo({ + center: [num(v.lon, -122.31), num(v.lat, 47.45)], + bearing: num(v.heading), + pitch: Math.max(58, Math.min(76, 72 + num(v.pitch))), + zoom, + }); + updateTerrainAwareness(num(v.altitude, 5500)); + } catch { /* style not ready yet */ } + raf = requestAnimationFrame(tick); + }; + map.on('load', () => { addRunways(); raf = requestAnimationFrame(tick); }); + + return () => { cancelAnimationFrame(raf); clearInterval(rwyTimer); map.remove(); mapRef.current = null; }; + }, []); // eslint-disable-line + + // Bank: rotate the whole terrain canvas opposite to aircraft roll; scale up so + // the corners stay covered while rotated. + const roll = num(values.roll); + return ( +
+
+
+ ); +} diff --git a/web/src/components/TimerRef.jsx b/web/src/components/TimerRef.jsx new file mode 100644 index 0000000..da0ea70 --- /dev/null +++ b/web/src/components/TimerRef.jsx @@ -0,0 +1,90 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { num } from '../api/useXplane.js'; + +// G1000 TMR/REF window (PFD). The real unit shows a generic timer plus the +// reference V-speeds and barometric minimums. This implements the timer +// (count-up or count-down with START/STOP/RESET) and the V-speed / minimums +// references with simple on/off bugs. Self-contained — no sim dependency. +const VSPEEDS = [ + { key: 'vr', label: 'Vr', def: 55 }, + { key: 'vx', label: 'Vx', def: 62 }, + { key: 'vy', label: 'Vy', def: 74 }, + { key: 'vg', label: 'Vg', def: 68 }, // best glide +]; + +function fmt(sec) { + const s = Math.max(0, Math.floor(sec)); + const h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), ss = s % 60; + const pad = (n) => String(n).padStart(2, '0'); + return h > 0 ? `${pad(h)}:${pad(m)}:${pad(ss)}` : `${pad(m)}:${pad(ss)}`; +} + +export default function TimerRef({ values, onClose }) { + const [dir, setDir] = useState('up'); // 'up' | 'dn' + const [running, setRunning] = useState(false); + const [elapsed, setElapsed] = useState(0); // seconds + const [target, setTarget] = useState(300); // count-down start (s) + const [vbugs, setVbugs] = useState({}); // key -> bool (shown on tape, future) + const [minsOn, setMinsOn] = useState(false); + const [mins, setMins] = useState(500); // baro minimums (ft) + const tickRef = useRef(null); + + useEffect(() => { + if (!running) return; + const t0 = Date.now() - elapsed * 1000; + tickRef.current = setInterval(() => setElapsed((Date.now() - t0) / 1000), 250); + return () => clearInterval(tickRef.current); + }, [running]); // eslint-disable-line + + const shown = dir === 'dn' ? Math.max(0, target - elapsed) : elapsed; + const alt = num(values.altitude); + const belowMins = minsOn && alt > 0 && alt <= mins; + + const reset = () => { setRunning(false); setElapsed(0); }; + + return ( +
+
+ TIMER / REFERENCES + {onClose && } +
+
+
{fmt(shown)}
+
+ + +
+
+ + +
+ {dir === 'dn' && ( +
+ + + {fmt(target)} + +
+ )} + +
REFERENCES — V-SPEEDS
+
+ {VSPEEDS.map((v) => ( + + ))} +
+ +
+ + + {mins} FT + +
+ {belowMins &&
MINIMUMS
} +
+
+ ); +} diff --git a/web/src/components/VFR.jsx b/web/src/components/VFR.jsx new file mode 100644 index 0000000..36bc079 --- /dev/null +++ b/web/src/components/VFR.jsx @@ -0,0 +1,304 @@ +import React from 'react'; +import { num } from '../api/useXplane.js'; + +// Classic analog "six-pack" VFR panel: airspeed, attitude, altimeter, turn +// coordinator, heading indicator, vertical speed — round steam gauges driven by +// the same X-Plane datarefs. For steam/VFR aircraft (and just because it looks +// great). Each gauge is a self-contained SVG on a dark instrument panel. + +const arr0 = (v, d = 0) => (Array.isArray(v) ? num(v[0], d) : num(v, d)); +const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v)); +// point on a dial: ang in degrees, 0 = up (12 o'clock), clockwise positive. +const pt = (cx, cy, r, ang) => { + const a = (ang - 90) * Math.PI / 180; + return [cx + r * Math.cos(a), cy + r * Math.sin(a)]; +}; + +function Bezel({ title, children }) { + return ( +
+ + + + + {children} + + {title} +
+ ); +} + +const Needle = ({ ang, len = 70, w = 4, color = '#fff', tail = 14 }) => ( + + + +); + +// generic tick ring +function ticks(min, max, a0, a1, step, big = 1, r = 84, lab) { + const out = []; + let i = 0; + for (let v = min; v <= max + 1e-6; v += step, i++) { + const ang = a0 + ((v - min) / (max - min)) * (a1 - a0); + const isBig = i % big === 0; + const [x1, y1] = pt(100, 100, r, ang); + const [x2, y2] = pt(100, 100, r - (isBig ? 12 : 7), ang); + out.push(); + if (lab && isBig) { + const [lx, ly] = pt(100, 100, r - 24, ang); + out.push({lab(v)}); + } + } + return out; +} + +/* ---------- Airspeed ---------- */ +function ASI({ V }) { + const kt = num(V.airspeed); + const A0 = -150, A1 = 150, MIN = 0, MAX = 200; + const ang = A0 + (clamp(kt, MIN, MAX) - MIN) / (MAX - MIN) * (A1 - A0); + const arc = (lo, hi, color, rr, wdt) => { + const [x1, y1] = pt(100, 100, rr, A0 + (lo / MAX) * (A1 - A0)); + const [x2, y2] = pt(100, 100, rr, A0 + (hi / MAX) * (A1 - A0)); + const large = ((hi - lo) / MAX) * 300 > 180 ? 1 : 0; + return ; + }; + return ( + + {arc(33, 85, '#fff', 70, 4)} {/* white flap arc */} + {arc(48, 129, '#21d04a', 78, 5)} {/* green normal */} + {arc(129, 163, '#e6c200', 78, 5)}{/* yellow caution */} + {(() => { const [x, y] = pt(100, 100, 78, A0 + (163 / MAX) * (A1 - A0)); const [x2, y2] = pt(100, 100, 70, A0 + (163 / MAX) * (A1 - A0)); return ; })()} + {ticks(0, 200, A0, A1, 10, 2, 84, (v) => (v % 20 === 0 && v >= 40 ? v : ''))} + KT + + + + ); +} + +/* ---------- Attitude ---------- */ +function AI({ V }) { + const pitch = num(V.pitch), roll = num(V.roll); + const PPD = 2.0; // px per degree pitch + const off = clamp(pitch, -25, 25) * PPD; + return ( + + + + + + + + + + + {[-20, -10, 10, 20].map((d) => ( + + + {d % 20 === 0 && {Math.abs(d)}} + + ))} + + + {/* bank arc + pointer */} + + {[-60, -30, -20, -10, 0, 10, 20, 30, 60].map((b) => { const [x1, y1] = pt(100, 100, 84, b); const [x2, y2] = pt(100, 100, 78, b); return ; })} + + + + {/* fixed aircraft reference */} + + + + + ); +} + +/* ---------- Altimeter (3-pointer) ---------- */ +function ALT({ V }) { + const alt = num(V.altitude), baro = num(V.baro, 29.92); + const a100 = (alt % 1000) / 1000 * 360; + const a1000 = (alt % 10000) / 10000 * 360; + const a10000 = (alt % 100000) / 100000 * 360; + return ( + + {ticks(0, 1000, 0, 360, 100, 1, 84, (v) => (v < 1000 ? v / 100 : ''))} + {ticks(0, 1000, 0, 360, 20, 5, 84)} + + {baro.toFixed(2)} + {/* 10000 ft thin pointer */} + + {/* 1000 ft short fat */} + + {/* 100 ft long */} + + + + ); +} + +/* ---------- Turn coordinator ---------- */ +function TC({ V }) { + const roll = num(V.roll), slip = num(V.slip); + const bank = clamp(roll, -30, 30); // little-plane bank (approx turn rate) + const ballX = 100 + clamp(slip, -8, 8) * 3.0; + return ( + + {/* standard-rate marks */} + {[-25, 25].map((b) => { const [x1, y1] = pt(100, 100, 80, b); const [x2, y2] = pt(100, 100, 66, b); return ; })} + L + R + {/* little airplane */} + + + + + + 2 MIN + {/* inclinometer (slip ball) */} + + + + + ); +} + +/* ---------- Heading indicator ---------- */ +function HI({ V }) { + const hdg = ((num(V.heading) % 360) + 360) % 360; + const card = []; + for (let d = 0; d < 360; d += 5) { + const big = d % 30 === 0; + const [x1, y1] = pt(100, 100, 84, d); + const [x2, y2] = pt(100, 100, 84 - (big ? 12 : 7), d); + card.push(); + if (big) { + const [lx, ly] = pt(100, 100, 62, d); + const lbl = d === 0 ? 'N' : d === 90 ? 'E' : d === 180 ? 'S' : d === 270 ? 'W' : d / 10; + card.push({lbl}); + } + } + return ( + + {card} + {/* fixed aircraft */} + + + + + ); +} + +/* ---------- Vertical speed ---------- */ +function VSI({ V }) { + const vs = clamp(num(V.vspeed), -2000, 2000); + // 0 at 9 o'clock (270°), climb sweeps up (toward 0/up), descent down. + const ang = 270 + (vs / 2000) * 160; // -2000→110°, 0→270°, +2000→430°(=70°) + return ( + + {ticks(-2000, 2000, 110, 430, 500, 1, 84, (v) => Math.abs(v) / 1000)} + {ticks(-2000, 2000, 110, 430, 100, 5, 84)} + FPM x1000 + 0 + + + + ); +} + +/* ---------- small gauges for the engine/fuel cluster ---------- */ +const KG_GAL = 2.72; + +function SmallBezel({ title, children }) { + return ( +
+ + + + {children} + + {title} +
+ ); +} + +// dual half-dial gauge: left needle (lower-left sweep) + right needle (lower-right) +function Dual({ title, l, r }) { + const sg = (v, min, max, a0, a1) => a0 + (clamp(v, min, max) - min) / (max - min) * (a1 - a0); + const sp = (cx, cy, rr, ang) => { const a = (ang - 90) * Math.PI / 180; return [cx + rr * Math.cos(a), cy + rr * Math.sin(a)]; }; + const band = (lo, hi, min, max, a0, a1, color) => { + const [x1, y1] = sp(60, 60, 46, sg(lo, min, max, a0, a1)); + const [x2, y2] = sp(60, 60, 46, sg(hi, min, max, a0, a1)); + return ; + }; + const La = sg(l.value, l.min, l.max, -150, -20), Ra = sg(r.value, r.min, r.max, 20, 150); + return ( + + {l.green && band(l.green[0], l.green[1], l.min, l.max, -150, -20, '#21d04a')} + {r.green && band(r.green[0], r.green[1], r.min, r.max, 20, 150, '#21d04a')} + {l.tag} + {r.tag} + + + + + ); +} + +/* ---------- tachometer ---------- */ +function Tach({ V }) { + const rpm = arr0(V.engRpm); + const A0 = -150, A1 = 150; + const ang = A0 + clamp(rpm, 0, 3500) / 3500 * (A1 - A0); + return ( + + {ticks(0, 3500, A0, A1, 500, 1, 84, (v) => v / 100)} + {(() => { const [x1, y1] = pt(100, 100, 84, A0 + 2700 / 3500 * (A1 - A0)); const [x2, y2] = pt(100, 100, 72, A0 + 2700 / 3500 * (A1 - A0)); return ; })()} + {(() => { const [x1, y1] = pt(100, 100, 80, A0 + 2100 / 3500 * (A1 - A0)); const [x2, y2] = pt(100, 100, 80, A0 + 2600 / 3500 * (A1 - A0)); return ; })()} + RPM x100 + {Math.round(rpm)} + + + + ); +} + +/* ---------- digital OAT / Volts plate ---------- */ +function Clock({ V }) { + const oatC = num(V.oat), oatF = Math.round(oatC * 9 / 5 + 32); + const volts = arr0(V.volts, 28); + return ( +
+
{oatF}°FO.A.T.
+
{volts.toFixed(1)}VOLT
+
+ ); +} + +export default function VFR({ values: V }) { + const fuelL = arr0(V.fuelQty, 0) / KG_GAL, fuelR = (Array.isArray(V.fuelQty) ? num(V.fuelQty[1]) : 0) / KG_GAL; + const oilF = arr0(V.oilTemp) * 9 / 5 + 32, oilP = arr0(V.oilPress); + const egtF = arr0(V.egt) * 9 / 5 + 32, ffGph = (arr0(V.fuelFlow) * 3600) / KG_GAL; + const amps = arr0(V.amps); + return ( +
+
+
+ + + + + +
+
+
+ + +
+
+
+
+
+ ); +} diff --git a/web/src/main.jsx b/web/src/main.jsx new file mode 100644 index 0000000..0857bd6 --- /dev/null +++ b/web/src/main.jsx @@ -0,0 +1,6 @@ +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import App from './App.jsx'; +import './styles.css'; + +createRoot(document.getElementById('root')).render(); diff --git a/web/src/styles.css b/web/src/styles.css new file mode 100644 index 0000000..c71de41 --- /dev/null +++ b/web/src/styles.css @@ -0,0 +1,491 @@ +:root { + --bg: #0a0a0a; + --panel: #141414; + --accent: #00e676; + --amber: #ffcc00; + /* App chrome (everything that is NOT a G1000 instrument): same clean + macOS-dark look as the desktop launcher. */ + --ui-font: 'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', system-ui, sans-serif; + --c-bg: #1c1c1e; + --c-surface: #2c2c2e; + --c-fill: #3a3a3c; + --c-line: #48484a; + --c-line-soft: #38383a; + --c-txt: #ffffff; + --c-txt2: #ebebf5; + --c-mut: #8e8e93; + --c-green: #30d158; + --c-amber: #ffd60a; + --c-red: #ff453a; + color-scheme: dark; +} + +* { box-sizing: border-box; margin: 0; padding: 0; } +html, body, #root { height: 100%; } +body { + background: var(--bg); + color: #eee; + font-family: -apple-system, system-ui, "Segoe UI", monospace; + overscroll-behavior: none; + -webkit-user-select: none; + user-select: none; + touch-action: manipulation; +} + +.app { display: flex; flex-direction: row; height: 100vh; height: 100dvh; } + +/* collapsible left nav rail — macOS-dark app chrome (Inter) */ +.sidebar { + display: flex; flex-direction: column; gap: 8px; + background: var(--c-bg); border-right: 1px solid var(--c-line-soft); + font-family: var(--ui-font); + width: 58px; flex: 0 0 58px; transition: width .18s ease, flex-basis .18s ease; + padding: 10px 8px; + padding-top: max(10px, env(safe-area-inset-top)); + padding-left: max(8px, env(safe-area-inset-left)); +} +.app.nav-wide .sidebar { width: 176px; flex-basis: 176px; } + +.sb-top { + display: flex; align-items: center; justify-content: space-between; gap: 6px; + background: var(--c-surface); color: var(--c-txt); + border: 1px solid var(--c-line-soft); border-radius: 10px; + padding: 9px 10px; cursor: pointer; font-family: inherit; min-height: 38px; +} +.sb-top:hover { background: #34343a; } +.brand { font-weight: 700; font-size: 17px; letter-spacing: .3px; white-space: nowrap; } +.brand span { color: var(--c-green); font-weight: 500; } +.sb-chev { color: var(--c-mut); font-size: 12px; } +.app.nav-narrow .brand span { display: none; } +.app.nav-narrow .sb-chev { display: none; } +.app.nav-narrow .sb-top { justify-content: center; padding: 9px 0; } + +.snav { display: flex; flex-direction: column; gap: 5px; flex: 1; margin-top: 4px; } +.snav-i { + display: flex; align-items: center; gap: 13px; + background: transparent; color: var(--c-mut); + border: 1px solid transparent; border-radius: 10px; + padding: 10px 11px; font-size: 14px; font-weight: 500; font-family: inherit; + cursor: pointer; width: 100%; text-align: left; overflow: hidden; + transition: background .12s, color .12s; +} +.snav-i:hover { background: var(--c-surface); color: var(--c-txt2); } +.snav-i.active { background: rgba(48,209,88,.16); color: var(--c-green); border-color: rgba(48,209,88,.35); } +.snav-ic { flex: 0 0 22px; } +.snav-lbl { white-space: nowrap; } +.app.nav-narrow .snav-lbl { display: none; } +.app.nav-narrow .snav-i { justify-content: center; padding: 10px 0; gap: 0; } + +.sb-conn { display: flex; align-items: center; gap: 11px; padding: 9px 11px; font-size: 11px; font-weight: 600; letter-spacing: .8px; color: var(--c-mut); } +.sb-conn .dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 9px; background: var(--c-mut); } +.sb-conn.ok .dot { background: var(--c-green); box-shadow: 0 0 8px var(--c-green); } +.sb-conn.warn .dot { background: var(--c-amber); } +.sb-conn.bad .dot { background: var(--c-red); } +.app.nav-narrow .sb-conn { justify-content: center; padding: 9px 0; } + +/* main screen */ +.screen { flex: 1; display: flex; align-items: center; justify-content: center; padding: 10px; overflow: hidden; min-width: 0; } + +/* VFR analog panel (C172 steam gauges on a metal panel) */ +.vfr-panel { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; + background: linear-gradient(150deg, #44474d 0%, #303338 40%, #232529 100%); + overflow: auto; padding: 18px; } +.vfr-layout { display: flex; align-items: center; gap: clamp(14px, 3vw, 40px); } +.vfr-cluster { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px 14px; align-content: center; max-width: 270px; } +.vfr-cluster .vfr-clock { grid-column: 1 / -1; } +.vfr-main { display: flex; flex-direction: column; align-items: center; gap: clamp(10px, 2vw, 26px); } +.vfr-grid { display: grid; grid-template-columns: repeat(3, minmax(140px, 215px)); gap: clamp(10px, 2.2vw, 26px); } +.vfr-tach { width: clamp(130px, 16vw, 180px); } +.vfr-gauge, .vfr-sg { display: flex; flex-direction: column; align-items: center; gap: 6px; } +.vfr-gauge svg, .vfr-sg svg { width: 100%; height: auto; filter: drop-shadow(0 4px 12px rgba(0,0,0,.55)); } +.vfr-name, .vfr-sname { font-family: var(--ui-font); letter-spacing: 1.2px; color: #c9d0d7; font-weight: 600; } +.vfr-name { font-size: 11px; } .vfr-sname { font-size: 9px; } +.vfr-clock { background: #0c0d0f; border: 1px solid #2a2f36; border-radius: 6px; padding: 8px 10px; display: flex; flex-direction: column; gap: 4px; } +.vc-row { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; } +.vc-row b { font-family: 'Saira Condensed', monospace; color: #46e0c0; font-size: 18px; } +.vc-row span { color: #7d8893; font-size: 9px; letter-spacing: 1px; } + +/* Garmin-like condensed type on every PFD/MFD readout (CSS overrides the + monospace presentation attributes inside the SVG). */ +.g1000 text, .g1000 tspan { font-family: 'Saira Condensed', 'Saira Semi Condensed', sans-serif; font-weight: 600; } + +/* PFD */ +.pfd, .g1000 { width: 100%; height: 100%; max-height: 100%; display: block; } +.pfd-wrap { position: relative; width: 100%; height: 100%; } +.pfd-wrap .g1000 { position: relative; z-index: 1; } +/* SVT (synthetic vision) terrain behind the attitude window */ +.svt-pos { position: absolute; z-index: 0; overflow: hidden; } +.svt-fallback { + width: 100%; height: 100%; overflow: hidden; + background: linear-gradient(#1f86d6 0%, #6fb2e6 49%, #7a5230 51%, #4a2d12 100%); +} +/* INSET moving map, bottom-left corner of the PFD (toggled by INSET softkey) */ +.pfd-inset { position: absolute; z-index: 2; overflow: hidden; border: 2px solid #c8d0d8; box-shadow: 0 0 0 1px #000; } +.pfd-inset .mapwrap, .pfd-inset .leaflet-host { width: 100%; height: 100%; } +.mapwrap.inset .leaflet-control-container { display: none; } +/* NRST (nearest) window — pops over the right side of the PFD */ +.nrst-window { + position: absolute; z-index: 4; top: 9%; right: 1.5%; width: 41%; max-width: 440px; + background: rgba(8, 10, 12, 0.94); border: 1px solid #4a5560; border-radius: 3px; + color: #fff; font-family: 'Roboto Mono', monospace; box-shadow: 0 4px 18px rgba(0,0,0,0.6); +} +.nrst-head { display: flex; align-items: center; gap: 8px; padding: 5px 8px; background: #11161b; border-bottom: 1px solid #2c343c; } +.nrst-title { color: #39d3c0; font-size: 13px; font-weight: bold; letter-spacing: 1px; } +.nrst-tabs { display: flex; gap: 3px; margin-left: auto; } +.nrst-tabs button { background: #1c242c; color: #9fb0bd; border: 1px solid #2c343c; border-radius: 2px; font: inherit; font-size: 11px; padding: 2px 9px; cursor: pointer; } +.nrst-tabs button.on { background: #0c9; color: #04201c; border-color: #0c9; font-weight: bold; } +.nrst-x { background: none; border: none; color: #9fb0bd; cursor: pointer; font-size: 14px; padding: 0 2px; } +.nrst-cols, .nrst-row { display: grid; grid-template-columns: 1.3fr 0.8fr 1fr 1.1fr; align-items: baseline; padding: 2px 8px; column-gap: 4px; } +.nrst-cols { color: #6f808d; font-size: 10px; border-bottom: 1px solid #222; padding-bottom: 4px; } +.nrst-row { font-size: 14px; border-bottom: 1px solid #161b20; } +.nrst-row .c-id { color: #0ff; font-weight: bold; } +.nrst-row .c-brg, .nrst-row .c-dis { color: #fff; text-align: right; } +.nrst-row .c-dis u { color: #6f808d; font-size: 9px; text-decoration: none; margin-left: 1px; } +.nrst-row .c-xtra { color: #39d3c0; text-align: right; } +.nrst-row .c-name { grid-column: 1 / -1; color: #8b9aa6; font-size: 10px; margin-top: -1px; } +.nrst-list { max-height: 62vh; overflow-y: auto; } +.nrst-empty { color: #6f808d; text-align: center; padding: 12px; font-size: 12px; } +/* XPDR squawk-entry readout above the softkey keypad */ +.squawk-entry { text-align: center; color: #9fb0bd; font-family: 'Roboto Mono', monospace; font-size: 13px; letter-spacing: 1px; padding: 3px 0; } +.squawk-entry b { color: #19ff19; font-size: 18px; letter-spacing: 5px; margin-left: 6px; } +/* TMR/REF window — left side of the PFD */ +.tmr-window { + position: absolute; z-index: 4; top: 9%; left: 1.5%; width: 30%; max-width: 320px; + background: rgba(8, 10, 12, 0.94); border: 1px solid #4a5560; border-radius: 3px; + color: #fff; font-family: 'Roboto Mono', monospace; box-shadow: 0 4px 18px rgba(0,0,0,0.6); +} +.tmr-body { padding: 8px 10px; } +.tmr-clock { font-size: 34px; font-weight: bold; text-align: center; color: #fff; letter-spacing: 2px; } +.tmr-dir { display: flex; gap: 4px; justify-content: center; margin: 4px 0; } +.tmr-dir button { background: #1c242c; color: #9fb0bd; border: 1px solid #2c343c; font: inherit; font-size: 11px; padding: 2px 12px; cursor: pointer; } +.tmr-dir button.on { background: #0c9; color: #04201c; font-weight: bold; } +.tmr-ctl { display: flex; gap: 6px; margin: 6px 0; } +.tmr-ctl .fbtn { flex: 1; } +.tmr-target { display: flex; align-items: center; gap: 6px; justify-content: center; color: #cfd6dd; font-size: 13px; } +.tmr-target label { color: #6f808d; font-size: 10px; } +.tmr-target button { background: #1c242c; color: #fff; border: 1px solid #2c343c; width: 24px; cursor: pointer; } +.tmr-sec { color: #39d3c0; font-size: 10px; margin: 8px 0 4px; border-top: 1px solid #222; padding-top: 6px; } +.tmr-vspeeds { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; } +.tmr-vspeeds button { display: flex; align-items: baseline; gap: 5px; background: #141a20; border: 1px solid #222b33; color: #cfd6dd; font: inherit; padding: 4px 6px; cursor: pointer; } +.tmr-vspeeds button.on { border-color: #0c9; background: #0a1f1b; } +.tmr-vspeeds button i { color: #0a8; font-style: normal; } .tmr-vspeeds button b { color: #fff; margin-left: auto; } .tmr-vspeeds button u { color: #6f808d; font-size: 9px; text-decoration: none; } +.tmr-mins { display: flex; align-items: center; gap: 6px; margin-top: 8px; } +.tmr-mins button:first-child { background: #1c242c; color: #9fb0bd; border: 1px solid #2c343c; font: inherit; font-size: 11px; padding: 3px 8px; cursor: pointer; } +.tmr-mins button:first-child.on { background: #0c9; color: #04201c; font-weight: bold; } +.tmr-mins > button:not(:first-child) { background: #1c242c; color: #fff; border: 1px solid #2c343c; width: 24px; cursor: pointer; } +.tmr-mins span { color: #fff; margin-left: auto; } .tmr-mins span.alert { color: #ffd24a; font-weight: bold; } +.tmr-minalert { margin-top: 6px; text-align: center; background: #ffd24a; color: #1a1400; font-weight: bold; padding: 3px; border-radius: 2px; letter-spacing: 2px; } +/* Modal dialogs (Direct-To, …) */ +.dlg-backdrop { position: fixed; inset: 0; z-index: 20; background: rgba(0,0,0,0.55); display: flex; align-items: center; justify-content: center; } +.dlg { background: #0c1015; border: 1px solid #3a4651; border-radius: 5px; min-width: 320px; color: #fff; font-family: 'Roboto Mono', monospace; box-shadow: 0 8px 30px rgba(0,0,0,0.7); } +.dlg-head { background: #11161b; padding: 8px 12px; border-bottom: 1px solid #2c343c; color: #fff; font-weight: bold; letter-spacing: 1px; border-radius: 5px 5px 0 0; } +.dto-arrow { color: #e040fb; margin-right: 8px; } +.dto-body { padding: 12px; } +.dto-lbl { color: #6f808d; font-size: 11px; display: block; margin-bottom: 4px; } +.dto-input { width: 100%; box-sizing: border-box; background: #05080b; border: 1px solid #2c343c; color: #0ff; font: inherit; font-size: 20px; letter-spacing: 3px; padding: 6px 10px; text-transform: uppercase; } +.dto-hits { display: flex; flex-direction: column; gap: 3px; margin-top: 6px; } +.dto-hits button { display: flex; align-items: baseline; gap: 8px; background: #141a20; border: 1px solid #222b33; color: #cfd6dd; font: inherit; padding: 5px 8px; cursor: pointer; text-align: left; } +.dto-hits button.on { border-color: #0c9; background: #0a1f1b; } +.dto-hits button b { color: #0ff; } .dto-hits button i { color: #0a8; font-style: normal; font-size: 11px; } .dto-hits button span { color: #6f808d; font-size: 11px; margin-left: auto; } +.dto-sel { display: flex; align-items: baseline; gap: 10px; margin-top: 10px; padding-top: 8px; border-top: 1px solid #222; } +.dto-sel .dto-id { color: #0ff; font-size: 20px; font-weight: bold; } +.dto-sel .dto-type { color: #0a8; font-size: 11px; } +.dto-sel .dto-vec { color: #e040fb; margin-left: auto; font-weight: bold; } +.dlg-actions { display: flex; gap: 8px; padding: 10px 12px; border-top: 1px solid #2c343c; } +.dlg-actions .fbtn { flex: 1; } +/* PROC dialog */ +.dlg.proc { width: 640px; max-width: 92vw; } +.proc-body { padding: 12px; } +.proc-apt { display: flex; align-items: center; gap: 8px; } +.proc-apt label { color: #6f808d; font-size: 11px; } +.proc-apt input { flex: 1; background: #05080b; border: 1px solid #2c343c; color: #0ff; font: inherit; font-size: 18px; letter-spacing: 2px; padding: 5px 10px; text-transform: uppercase; } +.proc-apt .fbtn { flex: 0 0 auto; } +.proc-err { color: #ffae42; font-size: 12px; margin-top: 6px; } +.proc-tabs { display: flex; gap: 4px; margin: 10px 0 6px; } +.proc-tabs button { flex: 1; background: #1c242c; color: #9fb0bd; border: 1px solid #2c343c; font: inherit; font-size: 12px; padding: 5px; cursor: pointer; } +.proc-tabs button.on { background: #0c9; color: #04201c; font-weight: bold; border-color: #0c9; } +.proc-cols { display: grid; grid-template-columns: 1fr 1fr 1.4fr; gap: 6px; height: 300px; } +.proc-list, .proc-preview { background: #05080b; border: 1px solid #1c242c; overflow-y: auto; display: flex; flex-direction: column; } +.proc-coltitle { position: sticky; top: 0; background: #11161b; color: #6f808d; font-size: 10px; padding: 4px 8px; border-bottom: 1px solid #222; } +.proc-list button { background: none; border: none; border-bottom: 1px solid #11161b; color: #cfd6dd; font: inherit; font-size: 14px; text-align: left; padding: 6px 8px; cursor: pointer; } +.proc-list button:hover { background: #11161b; } +.proc-list button.on { background: #0a1f1b; color: #0ff; font-weight: bold; } +.proc-empty { color: #6f808d; font-size: 11px; padding: 8px; } +.proc-leg { display: flex; align-items: baseline; gap: 8px; padding: 5px 8px; border-bottom: 1px solid #11161b; font-size: 13px; } +.proc-leg b { color: #0ff; } .proc-leg u { color: #39d3c0; font-size: 10px; text-decoration: none; margin-left: auto; } +/* G1000 vector nav symbology drawn from X-Plane's own nav data */ +.nav-divicon { background: none; border: none; } +.nav-sym { position: relative; width: 18px; height: 18px; } +.nav-lbl { position: absolute; left: 19px; top: 1px; font: 700 11px/1 monospace; white-space: nowrap; + text-shadow: 0 0 2px #000, 0 0 2px #000, 1px 1px 1px #000; } +/* Bank pivots about the aircraft reference (attitude centre), which sits ~28% + down the full-screen terrain box — so terrain roll tracks the attitude. */ +.svt-canvas { width: 100%; height: 100%; transform-origin: 50% 28%; } +.svt-canvas .maplibregl-canvas { width: 100% !important; height: 100% !important; } + +/* ---- GDU-1040 bezel ---- */ +.bezel { + width: 100%; height: 100%; display: flex; align-items: stretch; gap: 0; + background: linear-gradient(150deg, #3a3c40, #202123 55%, #2c2d30); + border-radius: 18px; padding: 12px; box-shadow: inset 0 1px 0 #4a4c50, 0 8px 30px #000; + font-family: 'Saira Semi Condensed', sans-serif; +} +.bezel-core { flex: 1; display: flex; flex-direction: column; min-width: 0; } +.bezel-title { text-align: center; color: #c9ced3; font-size: 14px; font-weight: 700; letter-spacing: 3px; padding: 2px 0 6px; } +.bezel-screen { + flex: 1; background: #000; border-radius: 6px; overflow: hidden; position: relative; + border: 2px solid #0a0a0a; box-shadow: inset 0 0 18px #000, inset 0 0 2px #1a3a5a; + display: flex; min-height: 0; +} +.bezel-screen > * { width: 100%; height: 100%; } +.softkeys { display: grid; grid-template-columns: repeat(12, 1fr); gap: 6px; padding: 8px 2px 2px; } +.softkey { + height: 30px; display: flex; align-items: center; justify-content: center; + background: linear-gradient(#202224, #131416); border: 1px solid #000; border-top: 1px solid #45474b; + border-radius: 4px; color: #cfd6dc; font-size: 12px; font-weight: 600; letter-spacing: .3px; + box-shadow: 0 1px 2px #000; cursor: pointer; font-family: inherit; +} +.softkey:not(.empty):hover { background: linear-gradient(#2a2c2f, #1a1b1e); border-top-color: #5a5d61; } +.softkey:not(.empty):active { background: #0d0e10; box-shadow: inset 0 1px 3px #000; } +.softkey.empty { color: transparent; cursor: default; } +.softkey.on { background: #e8edf2; color: #0a0c0e; border-top-color: #fff; font-weight: 800; } +.softkey.caution { color: #1a1b1e; background: linear-gradient(#ffd23a, #e0b400); border-top-color: #fff2a8; font-weight: 800; } + +.bezel-knobs { display: flex; flex-direction: column; align-items: center; justify-content: space-around; padding: 4px 6px; gap: 6px; } +.bezel-knobs.left { width: 88px; } .bezel-knobs.right { width: 100px; } +.knob-wrap { display: flex; flex-direction: column; align-items: center; gap: 2px; position: relative; } +.knob-lbl { color: #d2d7dc; font-size: 12px; font-weight: 800; letter-spacing: 1px; } +.knob-sub { color: #8b9197; font-size: 8.5px; font-weight: 600; letter-spacing: .3px; text-align: center; } +.knob-extra { position: absolute; right: -10px; top: 6px; width: 20px; height: 16px; background: #1a1b1e; border: 1px solid #000; border-radius: 3px; color: #cfd6dc; font-size: 11px; text-align: center; line-height: 16px; } +.knob.outer { + width: 50px; height: 50px; border-radius: 50%; display: flex; align-items: center; justify-content: center; position: relative; + background: radial-gradient(circle at 35% 30%, #55585d, #2a2c2f 70%); box-shadow: 0 2px 5px #000, inset 0 1px 0 #6a6d72; +} +.knob-wrap.big .knob.outer { width: 58px; height: 58px; } +.knob.inner { width: 26px; height: 26px; border-radius: 50%; background: radial-gradient(circle at 35% 30%, #44474b, #1c1e20); box-shadow: inset 0 1px 0 #5a5d61; } +.knob.joy .joy-cross { position: absolute; color: #6a6d72; font-size: 22px; font-weight: 700; pointer-events: none; } +.knob.outer { cursor: pointer; border: none; padding: 0; } +.knob.outer:active { box-shadow: 0 1px 2px #000, inset 0 2px 4px #000; } + +/* concentric knob + its rotation arrows */ +.knob-cluster { position: relative; display: flex; align-items: center; justify-content: center; padding: 14px; } +.knob-arrow { + position: absolute; width: 16px; height: 16px; padding: 0; line-height: 1; + background: #1a1b1e; border: 1px solid #000; border-radius: 3px; color: #b9c0c6; + font-size: 11px; font-weight: 800; cursor: pointer; display: flex; align-items: center; justify-content: center; +} +.knob-arrow:hover { background: #2a2c2f; color: #fff; } +.knob-arrow:active { background: #000; } +.knob-arrow.left { left: -2px; } .knob-arrow.right { right: -2px; } +.knob-arrow.top { top: -2px; } .knob-arrow.bottom { bottom: -2px; } + +.pan-pad { display: grid; grid-template-columns: repeat(2, 14px); gap: 2px; margin-top: 3px; } +.pan-pad button { + width: 14px; height: 12px; padding: 0; background: #1a1b1e; border: 1px solid #000; + border-radius: 2px; color: #b9c0c6; font-size: 7px; cursor: pointer; +} +.pan-pad button:active { background: #000; } + +.bezel-btn { + background: linear-gradient(#26282b, #16171a); border: 1px solid #000; border-top: 1px solid #3e4044; + border-radius: 5px; color: #cfd6dc; font-size: 11px; font-weight: 700; text-align: center; + padding: 6px 4px; min-width: 40px; line-height: 1.1; cursor: pointer; font-family: inherit; +} +.bezel-btn:hover { background: linear-gradient(#303236, #1c1d20); border-top-color: #55585d; } +.bezel-btn:active { background: #0d0e10; box-shadow: inset 0 1px 3px #000; } +.bezel-btn.sm { font-size: 10px; padding: 5px 3px; min-width: 0; } +.bezel-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; width: 100%; } + +/* autopilot mode controller (MFD left bezel) */ +.ap-controller { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; width: 100%; } +.ap-key { + background: linear-gradient(#26282b, #131416); border: 1px solid #000; border-top: 1px solid #3e4044; + border-radius: 4px; color: #d6dbe0; font-size: 11px; font-weight: 700; letter-spacing: .2px; + padding: 7px 2px; line-height: 1; font-family: 'Saira Semi Condensed', sans-serif; +} +.ap-key:active { transform: scale(0.95); } +.ap-key.on { background: #0a8f3c; color: #fff; border-color: #0c0; box-shadow: 0 0 8px rgba(0,200,80,.6); } + +/* G1000 MFD: top NAV/COM bar, engine strip (EIS) left, moving map right */ +.mfd-g1000 { display: flex; flex-direction: column; width: 100%; height: 100%; background: #000; } +.mfd-topbar { width: 100%; height: auto; flex-shrink: 0; display: block; border-bottom: 1px solid #3a3a3a; } +.mfd-body { flex: 1; display: flex; min-height: 0; } +.eis-svg { width: 178px; flex-shrink: 0; height: 100%; background: #0a0a0a; border-right: 1px solid #222; } +.mfd-map { flex: 1; position: relative; min-width: 0; } +.leaflet-host.dark { background: #000; } +/* G1000 chrome over the map */ +.map-chrome { position: absolute; inset: 0; pointer-events: none; z-index: 650; } +.map-rose { position: absolute; left: 50%; top: 50%; width: min(74%, 380px); height: min(74%, 380px); transform: translate(-50%, -50%); } +.mc-tr { position: absolute; right: 6px; top: 6px; display: flex; gap: 6px; align-items: center; + font: 600 12px/1 monospace; color: #fff; background: #000a; padding: 4px 6px; } +.mc-tr span { color: #cfe3ff; } +.mc-range { position: absolute; right: 6px; bottom: 36px; font: 700 14px/1 monospace; color: #0ff; + background: #000; border: 1px solid #555; padding: 4px 8px; } +.mc-mode { position: absolute; right: 6px; bottom: 6px; display: flex; align-items: center; gap: 3px; + font: 600 12px/1 monospace; color: #0ff; background: #000a; padding: 4px 6px; } +.mc-mode em { width: 8px; height: 8px; border: 1px solid #0ff; display: inline-block; } +.mc-mode em.on { background: #0ff; } + +/* Autopilot — GMC-710-style AFCS mode controller (app chrome look) */ +.afcs { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; + background: radial-gradient(120% 100% at 50% 0%, #1f2227, #0c0d0f); padding: 20px; font-family: var(--ui-font); } +.afcs-unit { width: min(880px, 100%); background: linear-gradient(#202329, #15171b); + border: 1px solid #34383f; border-radius: 16px; padding: 16px; box-shadow: 0 14px 40px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.04); display: flex; flex-direction: column; gap: 14px; } + +.afcs-ann { display: flex; align-items: center; gap: 10px; background: #07080a; border: 1px solid #2a2f36; + border-radius: 10px; padding: 10px 14px; font-family: 'Saira Semi Condensed', var(--ui-font); } +.ann { color: #4a525b; font-size: 17px; font-weight: 700; letter-spacing: 1px; } +.ann.on { color: #2ee06a; text-shadow: 0 0 10px rgba(46,224,106,.5); } +.ann.mode { color: #2ee06a; text-shadow: 0 0 10px rgba(46,224,106,.5); font-size: 18px; } +.ann-sep { width: 1px; height: 18px; background: #2a2f36; } +.ann-gap { flex: 1; } +.ann.val { color: #fff; font-size: 18px; } .ann.val i { color: #7d8893; font-style: normal; font-size: 11px; margin-left: 2px; } + +.afcs-keys { display: grid; grid-template-columns: repeat(10, 1fr); gap: 8px; } +.apk { background: linear-gradient(#2b2f36, #1c2026); color: #cdd4db; border: 1px solid #3a3f47; + border-radius: 9px; padding: 14px 4px; font-family: var(--ui-font); font-size: 14px; font-weight: 700; + letter-spacing: .5px; cursor: pointer; transition: all .12s; } +.apk:hover { border-color: #4a525b; } +.apk:active { transform: translateY(1px); } +.apk.on { background: linear-gradient(#1f8f47, #146b34); color: #fff; border-color: #2ee06a; + box-shadow: 0 0 16px rgba(46,224,106,.45), inset 0 1px 0 rgba(255,255,255,.15); } +.apk.sm { padding: 9px 12px; font-size: 12px; } + +.afcs-sels { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; } +.apsel { background: #07080a; border: 1px solid #2a2f36; border-radius: 12px; padding: 10px; text-align: center; } +.apsel-lbl { color: #2ee06a; font-size: 12px; font-weight: 700; letter-spacing: 1.5px; } +.apsel-val { font-family: 'Saira Condensed', monospace; font-size: 34px; font-weight: 700; color: #fff; line-height: 1.1; margin: 2px 0 6px; } +.apsel-val span { font-size: 14px; color: #7d8893; margin-left: 3px; } +.apsel-knob { display: flex; align-items: center; justify-content: center; gap: 10px; } +.apsel-knob button { width: 46px; height: 40px; background: linear-gradient(#2b2f36, #1c2026); color: #cdd4db; + border: 1px solid #3a3f47; border-radius: 8px; font-size: 20px; cursor: pointer; } +.apsel-knob button:active { background: #146b34; color: #fff; } +.knobdot { width: 30px; height: 30px; border-radius: 50%; background: radial-gradient(circle at 35% 30%, #3a3f47, #15171b); border: 1px solid #444; } + +.afcs-pitch { display: flex; align-items: center; gap: 10px; } +.afcs-pitch span { color: #7d8893; font-size: 11px; letter-spacing: 1.5px; font-weight: 600; } + +/* FMS as an X-Plane-style CDU/FMC */ +.cdu { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; + background: radial-gradient(120% 100% at 50% 0%, #1c1f24, #0b0c0e); padding: 16px; font-family: var(--ui-font); } +.cdu-unit { width: min(560px, 100%); background: linear-gradient(#23262c, #15171b); border: 1px solid #34383f; + border-radius: 18px; padding: 14px; box-shadow: 0 16px 44px rgba(0,0,0,.55); display: flex; flex-direction: column; gap: 12px; } +.cdu-screenwrap { display: flex; align-items: stretch; gap: 8px; } +.cdu-lsks { display: flex; flex-direction: column; justify-content: space-around; padding: 38px 0 30px; gap: 6px; } +.cdu-lsk { width: 18px; height: 26px; border-radius: 4px; background: linear-gradient(#3a3f47, #23262c); border: 1px solid #4a525b; cursor: pointer; } +.cdu-lsk:active { background: #146b34; } +.cdu-screen { flex: 1; background: #04140a; border: 1px solid #0b3; border-radius: 8px; padding: 10px 12px; + font-family: 'Saira Semi Condensed', monospace; color: #34e06a; min-height: 240px; + box-shadow: inset 0 0 30px rgba(0,80,30,.4); display: flex; flex-direction: column; } +.cdu-hdr { display: flex; justify-content: space-between; color: #9fffc0; font-size: 13px; letter-spacing: 1px; border-bottom: 1px solid #084d24; padding-bottom: 4px; } +.cdu-cols { display: grid; grid-template-columns: 1fr 60px 60px; color: #1f9d52; font-size: 10px; margin-top: 4px; } +.cdu-row { display: grid; grid-template-columns: 1fr 60px 60px; align-items: baseline; font-size: 17px; padding: 3px 0; border-bottom: 1px solid #06250f; } +.cdu-row.act { background: rgba(255,32,255,.12); } +.cdu-row.act .cdu-wpt, .cdu-row.act .cdu-dtk, .cdu-row.act .cdu-dist { color: #ff5bff; } +.cdu-wpt { color: #fff; font-weight: 600; } .cdu-wpt i { color: #1f9d52; font-style: normal; font-size: 11px; margin-left: 7px; } +.cdu-dtk, .cdu-dist { color: #34e06a; text-align: right; } +.cdu-add { color: #1f9d52; font-size: 14px; } .cdu-empty { color: #084d24; } +.cdu-scratch { margin-top: auto; border-top: 1px solid #084d24; padding-top: 6px; display: flex; justify-content: space-between; min-height: 22px; } +.cdu-sp { color: #fff; font-size: 16px; letter-spacing: 2px; background: #06250f; padding: 1px 8px; border-radius: 3px; min-width: 90px; } +.cdu-msg { color: #ffd24a; font-size: 13px; } .cdu-msg.ok { color: #34e06a; } + +.cdu-fn { display: grid; grid-template-columns: repeat(5, 1fr); gap: 7px; } +.cdu-pad { display: flex; flex-direction: column; gap: 7px; } +.cdu-padrow { display: grid; grid-template-columns: repeat(7, 1fr); gap: 7px; } +.cdu-padrow:nth-child(n+5) { grid-template-columns: repeat(5, 1fr); max-width: 72%; margin: 0 auto; width: 100%; } +.cdu-k { background: linear-gradient(#2b2f36, #1c2026); color: #dfe5ec; border: 1px solid #3a3f47; border-radius: 8px; + padding: 11px 4px; font-family: var(--ui-font); font-size: 14px; font-weight: 600; cursor: pointer; } +.cdu-k:hover { border-color: #4a525b; } .cdu-k:active { transform: translateY(1px); background: #146b34; color: #fff; } +.cdu-k.fn { font-size: 12px; letter-spacing: .5px; color: #9fb0bd; } +.cdu-k.fn.arm { background: #7d5a10; color: #fff; border-color: #ffd24a; } +.cdu-k.fn.exec { background: linear-gradient(#1f8f47, #146b34); color: #fff; border-color: #2ee06a; } + +/* MFD */ +.mfd { display: flex; gap: 24px; align-items: center; flex-wrap: wrap; justify-content: center; width: 100%; } +.rose { width: min(58vh, 440px); height: auto; } +.mfd-data { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } +.mfd-cell { + background: var(--panel); border: 1px solid #262626; border-radius: 12px; + padding: 14px 18px; min-width: 150px; display: flex; flex-direction: column; gap: 4px; +} +.mfd-cell .k { color: var(--accent); font-size: 13px; font-weight: 700; letter-spacing: 1px; } +.mfd-cell .v { font-size: 30px; font-weight: 800; font-family: monospace; } + +/* ---- Map ---- */ +.mapwrap { position: relative; width: 100%; height: 100%; } +.leaflet-host { position: absolute; inset: 0; background: #1a1a1a; } +.leaflet-container { font-family: monospace; } +.ac-divicon svg { transition: transform .2s linear; transform-origin: 50% 50%; filter: drop-shadow(0 0 3px #000); } +.wp-label { background: #000a; border: none; color: #ff20ff; font-weight: 700; font-family: monospace; } +.map-hud { + position: absolute; top: 10px; left: 10px; z-index: 500; + display: flex; flex-direction: column; gap: 6px; +} +.hud-cell { + background: #000c; border: 1px solid #333; border-radius: 8px; padding: 5px 10px; + display: flex; gap: 10px; align-items: baseline; min-width: 150px; +} +.hud-cell span { color: var(--accent); font-size: 11px; font-weight: 700; letter-spacing: 1px; } +.hud-cell b { font-family: monospace; font-size: 18px; margin-left: auto; } +.follow-btn { + position: absolute; right: 10px; top: 10px; z-index: 500; + background: #000c; color: #888; border: 1px solid #333; border-radius: 8px; + padding: 8px 14px; font-weight: 700; font-family: monospace; +} +.follow-btn.on { color: var(--accent); border-color: var(--accent); } +.map-hint { + position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%); z-index: 500; + background: #000a; color: #ccc; padding: 5px 12px; border-radius: 8px; font-size: 12px; +} + +/* ---- FMS (CDU style) ---- */ +.fms { + width: min(720px, 100%); height: 100%; display: flex; flex-direction: column; + background: #04140a; border: 1px solid #0a3; border-radius: 12px; overflow: hidden; + font-family: monospace; color: #29f06a; +} +.fms-head { + display: flex; justify-content: space-between; padding: 12px 16px; + background: #062; color: #d6ffe6; font-weight: 800; letter-spacing: 1px; font-size: 15px; +} +.fms-total { color: #bff8d4; } +.fms-rows { flex: 1; overflow-y: auto; padding: 6px 0; } +.fms-row { + display: grid; grid-template-columns: 34px 1fr 64px 64px 40px; align-items: center; + gap: 8px; padding: 10px 16px; border-bottom: 1px solid #0a2a18; font-size: 17px; +} +.fms-colhead { color: #0a6; font-size: 12px; letter-spacing: 1px; border-bottom: 1px solid #0a3; } +.fms-empty { padding: 24px 16px; color: #0a6; text-align: center; } +.fms-row .wid { font-weight: 800; color: #d6ffe6; } +.fms-row .wtype { font-style: normal; color: #0a8; font-size: 11px; margin-left: 8px; } +.fms-row .dtk, .fms-row .dist { color: #29f06a; } +.fms-row.orig .dist { color: #ffae42; } +.fms-row { cursor: pointer; } +.fms-row.active { background: rgba(255, 32, 255, 0.12); border-left: 3px solid #ff20ff; } +.fms-row.active .wid { color: #ff7bff; } +.fms-row.active .dtk, .fms-row.active .dist { color: #ff20ff; } +.fms-row .del { background: none; border: none; color: #c44; font-size: 18px; cursor: pointer; } +.fms-scratch { background: #021008; border-top: 2px solid #0a3; padding: 10px; } +.fms-hits { display: flex; flex-direction: column; gap: 4px; margin-bottom: 8px; } +.fms-hits button { + text-align: left; background: #08240f; border: 1px solid #0a3; border-radius: 6px; + padding: 8px 12px; color: #29f06a; font-family: monospace; +} +.fms-hits button b { color: #d6ffe6; } .fms-hits button i { color: #0a8; font-style: normal; margin: 0 8px; } +.fms-hits button span { color: #0a7; font-size: 12px; } +.fms-input { display: flex; gap: 8px; } +.fms-input input { + flex: 1; background: #000; border: 1px solid #0a5; border-radius: 8px; color: #ffae42; + font-family: monospace; font-size: 18px; padding: 12px; letter-spacing: 1px; +} +.fbtn { + background: #08240f; color: #29f06a; border: 1px solid #0a5; border-radius: 8px; + padding: 12px 16px; font-weight: 800; font-family: monospace; letter-spacing: 1px; +} +.fbtn.add { background: #0a5; color: #021008; } +.fbtn.export { background: #ffae42; color: #2a1500; border-color: #ffae42; flex: 1; } +.fbtn:disabled { opacity: .4; } +.fms-actions { display: flex; gap: 8px; margin-top: 8px; } +.fms-export { margin-top: 8px; font-size: 13px; padding: 8px; border-radius: 6px; } +.fms-export.ok { background: #06330f; color: #9f9; } +.fms-export.err { background: #330606; color: #f99; } diff --git a/web/vite.config.js b/web/vite.config.js new file mode 100644 index 0000000..d484717 --- /dev/null +++ b/web/vite.config.js @@ -0,0 +1,15 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +// During `npm run dev`, proxy the bridge WebSocket so you can develop the UI +// with hot-reload while the bridge runs on :8080. +export default defineConfig({ + plugins: [react()], + server: { + host: true, // expose dev server on the LAN too + proxy: { + '/ws': { target: 'ws://localhost:8080', ws: true }, + '/api': { target: 'http://localhost:8080' }, + }, + }, +});